mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
common: refactor common library pt2 (#8588)
- remove common lib - split settings, remove common-md - move ipc interop/kb_layout to interop - rename core -> settings, settings -> old_settings - os-detect header-only; interop -> PowerToysInterop - split notifications, move single-use headers where they're used - winstore lib - rename com utils - rename Updating and Telemetry projects - rename core -> settings-ui and remove examples folder - rename settings-ui folder + consisent common/version include
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardHook.h"
|
||||
#include <exception>
|
||||
#include <msclr\marshal.h>
|
||||
#include <msclr\marshal_cppstd.h>
|
||||
#include <msclr/marshal.h>
|
||||
#include <msclr/marshal_cppstd.h>
|
||||
#include <common/debug_control.h>
|
||||
#include <common/common.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
using namespace interop;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
|
||||
@@ -1,117 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToysInterop</AssemblyTitle>
|
||||
<AssemblyCompany>Microsoft Corp.</AssemblyCompany>
|
||||
<AssemblyCopyright>Copyright (C) 2019 Microsoft Corp.</AssemblyCopyright>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{F055103B-F80B-4D0C-BF48-057C55620033}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>PowerToysInterop</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToysInterop</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||
<AdditionalOptions>/Zc:twoPhase- </AdditionalOptions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<AssemblyVersionFiles Include="Generated Files\AssemblyInfo.cpp" />
|
||||
</ItemGroup>
|
||||
<Target Name="GenerateAssemblyInfo" BeforeTargets="PrepareForBuild">
|
||||
<ItemGroup>
|
||||
<HeaderLines Include="#include <pch.h> " />
|
||||
<HeaderLines Include="using namespace System%3b" />
|
||||
<HeaderLines Include="using namespace System::Reflection%3b" />
|
||||
<HeaderLines Include="using namespace System::Runtime::CompilerServices%3b" />
|
||||
<HeaderLines Include="using namespace System::Runtime::InteropServices%3b" />
|
||||
<HeaderLines Include="using namespace System::Security::Permissions%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyTitleAttribute(L"$(AssemblyTitle)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyDescriptionAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyConfigurationAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyCompanyAttribute("$(AssemblyCompany)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyCopyrightAttribute("$(AssemblyCopyright)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyProductAttribute("$(AssemblyTitle)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyTrademarkAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyCultureAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyVersionAttribute("$(Version).0")]%3b" />
|
||||
<HeaderLines Include="[assembly: ComVisible(false)]%3b" />
|
||||
<HeaderLines Include="[assembly:CLSCompliantAttribute(true)]%3b" />
|
||||
</ItemGroup>
|
||||
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HotkeyManager.h" />
|
||||
<ClInclude Include="interop.h" />
|
||||
<ClInclude Include="KeyboardHook.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp" />
|
||||
<ClCompile Include="HotkeyManager.cpp" />
|
||||
<ClCompile Include="interop.cpp" />
|
||||
<ClCompile Include="KeyboardHook.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="interop.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common-md-flag\common-md-flag.vcxproj">
|
||||
<Project>{985b3f2f-ceed-4c0a-a249-69257e719145}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToysInterop</AssemblyTitle>
|
||||
<AssemblyCompany>Microsoft Corp.</AssemblyCompany>
|
||||
<AssemblyCopyright>Copyright (C) 2019 Microsoft Corp.</AssemblyCopyright>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{F055103B-F80B-4D0C-BF48-057C55620033}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>PowerToysInterop</RootNamespace>
|
||||
<ProjectName>PowerToysInterop</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToysInterop</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||
<AdditionalOptions>/Zc:twoPhase- </AdditionalOptions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<AssemblyVersionFiles Include="Generated Files\AssemblyInfo.cpp" />
|
||||
</ItemGroup>
|
||||
<Target Name="GenerateAssemblyInfo" BeforeTargets="PrepareForBuild">
|
||||
<ItemGroup>
|
||||
<HeaderLines Include="#include "../pch.h"" />
|
||||
<HeaderLines Include="using namespace System%3b" />
|
||||
<HeaderLines Include="using namespace System::Reflection%3b" />
|
||||
<HeaderLines Include="using namespace System::Runtime::CompilerServices%3b" />
|
||||
<HeaderLines Include="using namespace System::Runtime::InteropServices%3b" />
|
||||
<HeaderLines Include="using namespace System::Security::Permissions%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyTitleAttribute(L"$(AssemblyTitle)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyDescriptionAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyConfigurationAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyCompanyAttribute("$(AssemblyCompany)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyCopyrightAttribute("$(AssemblyCopyright)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyProductAttribute("$(AssemblyTitle)")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyTrademarkAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyCultureAttribute("")]%3b" />
|
||||
<HeaderLines Include="[assembly: AssemblyVersionAttribute("$(Version).0")]%3b" />
|
||||
<HeaderLines Include="[assembly: ComVisible(false)]%3b" />
|
||||
<HeaderLines Include="[assembly:CLSCompliantAttribute(true)]%3b" />
|
||||
</ItemGroup>
|
||||
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HotkeyManager.h" />
|
||||
<ClInclude Include="interop.h" />
|
||||
<ClInclude Include="KeyboardHook.h" />
|
||||
<ClInclude Include="os-detect.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp" />
|
||||
<ClCompile Include="HotkeyManager.cpp" />
|
||||
<ClCompile Include="interop.cpp" />
|
||||
<ClCompile Include="KeyboardHook.cpp" />
|
||||
<ClCompile Include="keyboard_layout.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
</ClCompile>
|
||||
<ClCompile Include="two_way_pipe_message_ipc.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="interop.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,56 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="interop.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardHook.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HotkeyManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="interop.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardHook.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HotkeyManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="interop.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="interop.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardHook.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HotkeyManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="os-detect.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="interop.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardHook.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HotkeyManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="two_way_pipe_message_ipc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="keyboard_layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="interop.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
54
src/common/interop/async_message_queue.h
Normal file
54
src/common/interop/async_message_queue.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <string>
|
||||
|
||||
class AsyncMessageQueue
|
||||
{
|
||||
private:
|
||||
std::mutex queue_mutex;
|
||||
std::queue<std::wstring> message_queue;
|
||||
std::condition_variable message_ready;
|
||||
bool interrupted = false;
|
||||
|
||||
//Disable copy
|
||||
AsyncMessageQueue(const AsyncMessageQueue&);
|
||||
AsyncMessageQueue& operator=(const AsyncMessageQueue&);
|
||||
|
||||
public:
|
||||
AsyncMessageQueue()
|
||||
{
|
||||
}
|
||||
void queue_message(std::wstring message)
|
||||
{
|
||||
this->queue_mutex.lock();
|
||||
this->message_queue.push(message);
|
||||
this->queue_mutex.unlock();
|
||||
this->message_ready.notify_one();
|
||||
}
|
||||
std::wstring pop_message()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
while (message_queue.empty() && !this->interrupted)
|
||||
{
|
||||
this->message_ready.wait(lock);
|
||||
}
|
||||
if (this->interrupted)
|
||||
{
|
||||
//Just returns a empty string if the queue was interrupted.
|
||||
return std::wstring(L"");
|
||||
}
|
||||
std::wstring message = this->message_queue.front();
|
||||
this->message_queue.pop();
|
||||
return message;
|
||||
}
|
||||
void interrupt()
|
||||
{
|
||||
this->queue_mutex.lock();
|
||||
this->interrupted = true;
|
||||
this->queue_mutex.unlock();
|
||||
this->message_ready.notify_all();
|
||||
}
|
||||
};
|
||||
82
src/common/interop/interop-tests/InteropTests.cs
Normal file
82
src/common/interop/interop-tests/InteropTests.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using interop;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Microsoft.Interop.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class InteropTests : IDisposable
|
||||
{
|
||||
private const string ServerSidePipe = "\\\\.\\pipe\\serverside";
|
||||
private const string ClientSidePipe = "\\\\.\\pipe\\clientside";
|
||||
|
||||
internal TwoWayPipeMessageIPCManaged ClientPipe { get; set; }
|
||||
|
||||
private bool disposedValue;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
ClientPipe = new TwoWayPipeMessageIPCManaged(ClientSidePipe, ServerSidePipe, null);
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
ClientPipe.End();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSend()
|
||||
{
|
||||
var testString = "This string is a test\n";
|
||||
using (var reset = new AutoResetEvent(false))
|
||||
{
|
||||
using (var serverPipe = new TwoWayPipeMessageIPCManaged(
|
||||
ServerSidePipe,
|
||||
ClientSidePipe,
|
||||
(string msg) =>
|
||||
{
|
||||
Assert.AreEqual(testString, msg);
|
||||
reset.Set();
|
||||
}))
|
||||
{
|
||||
serverPipe.Start();
|
||||
ClientPipe.Start();
|
||||
|
||||
ClientPipe.Send(testString);
|
||||
reset.WaitOne();
|
||||
|
||||
serverPipe.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ClientPipe.Dispose();
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyTitle>interop-tests</AssemblyTitle>
|
||||
<Company>Microsoft Corp.</Company>
|
||||
<Copyright>Copyright (C) 2020 Microsoft Corp.</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Microsoft.Interop.Tests</RootNamespace>
|
||||
<AssemblyName>Microsoft.Interop.Tests</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
|
||||
<Version>3.3.0</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
<Version>1.1.118</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs">
|
||||
<Link>GlobalSuppressions.cs</Link>
|
||||
</Compile>
|
||||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PowerToysInterop.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <msclr\marshal.h>
|
||||
#include <msclr\marshal_cppstd.h>
|
||||
#include <msclr/marshal.h>
|
||||
#include <msclr/marshal_cppstd.h>
|
||||
#include <functional>
|
||||
#include "..\keyboard_layout.h"
|
||||
#include "..\two_way_pipe_message_ipc.h"
|
||||
#include "..\common.h"
|
||||
#include "..\shared_constants.h"
|
||||
#include "..\os-detect.h"
|
||||
#include "keyboard_layout.h"
|
||||
#include "two_way_pipe_message_ipc.h"
|
||||
#include "shared_constants.h"
|
||||
#include "../utils/os-detect.h"
|
||||
|
||||
#include <common/version/version.h>
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
@@ -56,7 +57,7 @@ public
|
||||
{
|
||||
_wrapperCallback = gcnew InternalReadCallback(this, &TwoWayPipeMessageIPCManaged::ReadCallbackHelper);
|
||||
_callback = callback;
|
||||
|
||||
|
||||
TwoWayPipeMessageIPC::callback_function cb = nullptr;
|
||||
if (callback != nullptr)
|
||||
{
|
||||
@@ -107,12 +108,11 @@ public
|
||||
}
|
||||
};
|
||||
|
||||
public
|
||||
public
|
||||
ref class CommonManaged
|
||||
{
|
||||
public:
|
||||
static String^ GetProductVersion()
|
||||
{
|
||||
static String ^ GetProductVersion() {
|
||||
return gcnew String(get_product_version().c_str());
|
||||
}
|
||||
|
||||
@@ -122,14 +122,13 @@ public
|
||||
}
|
||||
};
|
||||
|
||||
public
|
||||
public
|
||||
ref class Constants
|
||||
{
|
||||
public:
|
||||
literal int VK_WIN_BOTH = CommonSharedConstants::VK_WIN_BOTH;
|
||||
|
||||
static String^ PowerLauncherSharedEvent()
|
||||
{
|
||||
|
||||
static String ^ PowerLauncherSharedEvent() {
|
||||
return gcnew String(CommonSharedConstants::POWER_LAUNCHER_SHARED_EVENT);
|
||||
}
|
||||
};
|
||||
|
||||
Binary file not shown.
332
src/common/interop/keyboard_layout.cpp
Normal file
332
src/common/interop/keyboard_layout.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
#include "pch.h"
|
||||
#include "keyboard_layout_impl.h"
|
||||
#include "shared_constants.h"
|
||||
|
||||
LayoutMap::LayoutMap() :
|
||||
impl(new LayoutMap::LayoutMapImpl())
|
||||
{
|
||||
}
|
||||
|
||||
LayoutMap::~LayoutMap()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
void LayoutMap::UpdateLayout()
|
||||
{
|
||||
impl->UpdateLayout();
|
||||
}
|
||||
|
||||
std::wstring LayoutMap::GetKeyName(DWORD key)
|
||||
{
|
||||
return impl->GetKeyName(key);
|
||||
}
|
||||
|
||||
std::vector<DWORD> LayoutMap::GetKeyCodeList(const bool isShortcut)
|
||||
{
|
||||
return impl->GetKeyCodeList(isShortcut);
|
||||
}
|
||||
|
||||
std::vector<std::pair<DWORD, std::wstring>> LayoutMap::GetKeyNameList(const bool isShortcut)
|
||||
{
|
||||
return impl->GetKeyNameList(isShortcut);
|
||||
}
|
||||
|
||||
// Function to return the unicode string name of the key
|
||||
std::wstring LayoutMap::LayoutMapImpl::GetKeyName(DWORD key)
|
||||
{
|
||||
std::wstring result = L"Undefined";
|
||||
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
|
||||
UpdateLayout();
|
||||
|
||||
auto it = keyboardLayoutMap.find(key);
|
||||
if (it != keyboardLayoutMap.end())
|
||||
{
|
||||
result = it->second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool mapKeycodeToUnicode(const int vCode, HKL layout, const BYTE* keyState, std::array<wchar_t, 3>& outBuffer)
|
||||
{
|
||||
// Get the scan code from the virtual key code
|
||||
const UINT scanCode = MapVirtualKeyExW(vCode, MAPVK_VK_TO_VSC, layout);
|
||||
// Get the unicode representation from the virtual key code and scan code pair
|
||||
const int result = ToUnicodeEx(vCode, scanCode, keyState, outBuffer.data(), (int)outBuffer.size(), 0, layout);
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
// Update Keyboard layout according to input locale identifier
|
||||
void LayoutMap::LayoutMapImpl::UpdateLayout()
|
||||
{
|
||||
// Get keyboard layout for current thread
|
||||
const HKL layout = GetKeyboardLayout(0);
|
||||
if (layout == previousLayout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
previousLayout = layout;
|
||||
if (!isKeyCodeListGenerated)
|
||||
{
|
||||
unicodeKeys.clear();
|
||||
unknownKeys.clear();
|
||||
}
|
||||
|
||||
std::array<BYTE, 256> btKeys = { 0 };
|
||||
// Only set the Caps Lock key to on for the key names in uppercase
|
||||
btKeys[VK_CAPITAL] = 1;
|
||||
|
||||
// Iterate over all the virtual key codes. virtual key 0 is not used
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
std::array<wchar_t, 3> szBuffer = { 0 };
|
||||
if (mapKeycodeToUnicode(i, layout, btKeys.data(), szBuffer))
|
||||
{
|
||||
keyboardLayoutMap[i] = szBuffer.data();
|
||||
if (!isKeyCodeListGenerated)
|
||||
{
|
||||
unicodeKeys[i] = szBuffer.data();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store the virtual key code as string
|
||||
std::wstring vk = L"VK ";
|
||||
vk += std::to_wstring(i);
|
||||
keyboardLayoutMap[i] = vk;
|
||||
if (!isKeyCodeListGenerated)
|
||||
{
|
||||
unknownKeys[i] = vk;
|
||||
}
|
||||
}
|
||||
|
||||
// Override special key names like Shift, Ctrl etc because they don't have unicode mappings and key names like Enter, Space as they appear as "\r", " "
|
||||
// To do: localization
|
||||
keyboardLayoutMap[VK_CANCEL] = L"Break";
|
||||
keyboardLayoutMap[VK_BACK] = L"Backspace";
|
||||
keyboardLayoutMap[VK_TAB] = L"Tab";
|
||||
keyboardLayoutMap[VK_CLEAR] = L"Clear";
|
||||
keyboardLayoutMap[VK_RETURN] = L"Enter";
|
||||
keyboardLayoutMap[VK_SHIFT] = L"Shift";
|
||||
keyboardLayoutMap[VK_CONTROL] = L"Ctrl";
|
||||
keyboardLayoutMap[VK_MENU] = L"Alt";
|
||||
keyboardLayoutMap[VK_PAUSE] = L"Pause";
|
||||
keyboardLayoutMap[VK_CAPITAL] = L"Caps Lock";
|
||||
keyboardLayoutMap[VK_ESCAPE] = L"Esc";
|
||||
keyboardLayoutMap[VK_SPACE] = L"Space";
|
||||
keyboardLayoutMap[VK_PRIOR] = L"PgUp";
|
||||
keyboardLayoutMap[VK_NEXT] = L"PgDn";
|
||||
keyboardLayoutMap[VK_END] = L"End";
|
||||
keyboardLayoutMap[VK_HOME] = L"Home";
|
||||
keyboardLayoutMap[VK_LEFT] = L"Left";
|
||||
keyboardLayoutMap[VK_UP] = L"Up";
|
||||
keyboardLayoutMap[VK_RIGHT] = L"Right";
|
||||
keyboardLayoutMap[VK_DOWN] = L"Down";
|
||||
keyboardLayoutMap[VK_SELECT] = L"Select";
|
||||
keyboardLayoutMap[VK_PRINT] = L"Print";
|
||||
keyboardLayoutMap[VK_EXECUTE] = L"Execute";
|
||||
keyboardLayoutMap[VK_SNAPSHOT] = L"Print Screen";
|
||||
keyboardLayoutMap[VK_INSERT] = L"Insert";
|
||||
keyboardLayoutMap[VK_DELETE] = L"Delete";
|
||||
keyboardLayoutMap[VK_HELP] = L"Help";
|
||||
keyboardLayoutMap[VK_LWIN] = L"Win (Left)";
|
||||
keyboardLayoutMap[VK_RWIN] = L"Win (Right)";
|
||||
keyboardLayoutMap[VK_APPS] = L"Apps/Menu";
|
||||
keyboardLayoutMap[VK_SLEEP] = L"Sleep";
|
||||
keyboardLayoutMap[VK_NUMPAD0] = L"NumPad 0";
|
||||
keyboardLayoutMap[VK_NUMPAD1] = L"NumPad 1";
|
||||
keyboardLayoutMap[VK_NUMPAD2] = L"NumPad 2";
|
||||
keyboardLayoutMap[VK_NUMPAD3] = L"NumPad 3";
|
||||
keyboardLayoutMap[VK_NUMPAD4] = L"NumPad 4";
|
||||
keyboardLayoutMap[VK_NUMPAD5] = L"NumPad 5";
|
||||
keyboardLayoutMap[VK_NUMPAD6] = L"NumPad 6";
|
||||
keyboardLayoutMap[VK_NUMPAD7] = L"NumPad 7";
|
||||
keyboardLayoutMap[VK_NUMPAD8] = L"NumPad 8";
|
||||
keyboardLayoutMap[VK_NUMPAD9] = L"NumPad 9";
|
||||
keyboardLayoutMap[VK_SEPARATOR] = L"Separator";
|
||||
keyboardLayoutMap[VK_F1] = L"F1";
|
||||
keyboardLayoutMap[VK_F2] = L"F2";
|
||||
keyboardLayoutMap[VK_F3] = L"F3";
|
||||
keyboardLayoutMap[VK_F4] = L"F4";
|
||||
keyboardLayoutMap[VK_F5] = L"F5";
|
||||
keyboardLayoutMap[VK_F6] = L"F6";
|
||||
keyboardLayoutMap[VK_F7] = L"F7";
|
||||
keyboardLayoutMap[VK_F8] = L"F8";
|
||||
keyboardLayoutMap[VK_F9] = L"F9";
|
||||
keyboardLayoutMap[VK_F10] = L"F10";
|
||||
keyboardLayoutMap[VK_F11] = L"F11";
|
||||
keyboardLayoutMap[VK_F12] = L"F12";
|
||||
keyboardLayoutMap[VK_F13] = L"F13";
|
||||
keyboardLayoutMap[VK_F14] = L"F14";
|
||||
keyboardLayoutMap[VK_F15] = L"F15";
|
||||
keyboardLayoutMap[VK_F16] = L"F16";
|
||||
keyboardLayoutMap[VK_F17] = L"F17";
|
||||
keyboardLayoutMap[VK_F18] = L"F18";
|
||||
keyboardLayoutMap[VK_F19] = L"F19";
|
||||
keyboardLayoutMap[VK_F20] = L"F20";
|
||||
keyboardLayoutMap[VK_F21] = L"F21";
|
||||
keyboardLayoutMap[VK_F22] = L"F22";
|
||||
keyboardLayoutMap[VK_F23] = L"F23";
|
||||
keyboardLayoutMap[VK_F24] = L"F24";
|
||||
keyboardLayoutMap[VK_NUMLOCK] = L"Num Lock";
|
||||
keyboardLayoutMap[VK_SCROLL] = L"Scroll Lock";
|
||||
keyboardLayoutMap[VK_LSHIFT] = L"Shift (Left)";
|
||||
keyboardLayoutMap[VK_RSHIFT] = L"Shift (Right)";
|
||||
keyboardLayoutMap[VK_LCONTROL] = L"Ctrl (Left)";
|
||||
keyboardLayoutMap[VK_RCONTROL] = L"Ctrl (Right)";
|
||||
keyboardLayoutMap[VK_LMENU] = L"Alt (Left)";
|
||||
keyboardLayoutMap[VK_RMENU] = L"Alt (Right)";
|
||||
keyboardLayoutMap[VK_BROWSER_BACK] = L"Browser Back";
|
||||
keyboardLayoutMap[VK_BROWSER_FORWARD] = L"Browser Forward";
|
||||
keyboardLayoutMap[VK_BROWSER_REFRESH] = L"Browser Refresh";
|
||||
keyboardLayoutMap[VK_BROWSER_STOP] = L"Browser Stop";
|
||||
keyboardLayoutMap[VK_BROWSER_SEARCH] = L"Browser Search";
|
||||
keyboardLayoutMap[VK_BROWSER_FAVORITES] = L"Browser Favorites";
|
||||
keyboardLayoutMap[VK_BROWSER_HOME] = L"Browser Home";
|
||||
keyboardLayoutMap[VK_VOLUME_MUTE] = L"Volume Mute";
|
||||
keyboardLayoutMap[VK_VOLUME_DOWN] = L"Volume Down";
|
||||
keyboardLayoutMap[VK_VOLUME_UP] = L"Volume Up";
|
||||
keyboardLayoutMap[VK_MEDIA_NEXT_TRACK] = L"Next Track";
|
||||
keyboardLayoutMap[VK_MEDIA_PREV_TRACK] = L"Previous Track";
|
||||
keyboardLayoutMap[VK_MEDIA_STOP] = L"Stop Media";
|
||||
keyboardLayoutMap[VK_MEDIA_PLAY_PAUSE] = L"Play/Pause Media";
|
||||
keyboardLayoutMap[VK_LAUNCH_MAIL] = L"Start Mail";
|
||||
keyboardLayoutMap[VK_LAUNCH_MEDIA_SELECT] = L"Select Media";
|
||||
keyboardLayoutMap[VK_LAUNCH_APP1] = L"Start App 1";
|
||||
keyboardLayoutMap[VK_LAUNCH_APP2] = L"Start App 2";
|
||||
keyboardLayoutMap[VK_PACKET] = L"Packet";
|
||||
keyboardLayoutMap[VK_ATTN] = L"Attn";
|
||||
keyboardLayoutMap[VK_CRSEL] = L"CrSel";
|
||||
keyboardLayoutMap[VK_EXSEL] = L"ExSel";
|
||||
keyboardLayoutMap[VK_EREOF] = L"Erase EOF";
|
||||
keyboardLayoutMap[VK_PLAY] = L"Play";
|
||||
keyboardLayoutMap[VK_ZOOM] = L"Zoom";
|
||||
keyboardLayoutMap[VK_PA1] = L"PA1";
|
||||
keyboardLayoutMap[VK_OEM_CLEAR] = L"Clear";
|
||||
keyboardLayoutMap[0xFF] = L"Undefined";
|
||||
keyboardLayoutMap[CommonSharedConstants::VK_WIN_BOTH] = L"Win";
|
||||
keyboardLayoutMap[VK_KANA] = L"IME Kana";
|
||||
keyboardLayoutMap[VK_HANGEUL] = L"IME Hangeul";
|
||||
keyboardLayoutMap[VK_HANGUL] = L"IME Hangul";
|
||||
keyboardLayoutMap[VK_JUNJA] = L"IME Junja";
|
||||
keyboardLayoutMap[VK_FINAL] = L"IME Final";
|
||||
keyboardLayoutMap[VK_HANJA] = L"IME Hanja";
|
||||
keyboardLayoutMap[VK_KANJI] = L"IME Kanji";
|
||||
keyboardLayoutMap[VK_CONVERT] = L"IME Convert";
|
||||
keyboardLayoutMap[VK_NONCONVERT] = L"IME Non-Convert";
|
||||
keyboardLayoutMap[VK_ACCEPT] = L"IME Kana";
|
||||
keyboardLayoutMap[VK_MODECHANGE] = L"IME Mode Change";
|
||||
keyboardLayoutMap[CommonSharedConstants::VK_DISABLED] = L"Disable";
|
||||
}
|
||||
|
||||
// Function to return the list of key codes in the order for the drop down. It creates it if it doesn't exist
|
||||
std::vector<DWORD> LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcut)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
|
||||
UpdateLayout();
|
||||
std::vector<DWORD> keyCodes;
|
||||
if (!isKeyCodeListGenerated)
|
||||
{
|
||||
// Add character keys
|
||||
for (auto& it : unicodeKeys)
|
||||
{
|
||||
// If it was not renamed with a special name
|
||||
if (it.second == keyboardLayoutMap[it.first])
|
||||
{
|
||||
keyCodes.push_back(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
// Add modifier keys in alphabetical order
|
||||
keyCodes.push_back(VK_MENU);
|
||||
keyCodes.push_back(VK_LMENU);
|
||||
keyCodes.push_back(VK_RMENU);
|
||||
keyCodes.push_back(VK_CONTROL);
|
||||
keyCodes.push_back(VK_LCONTROL);
|
||||
keyCodes.push_back(VK_RCONTROL);
|
||||
keyCodes.push_back(VK_SHIFT);
|
||||
keyCodes.push_back(VK_LSHIFT);
|
||||
keyCodes.push_back(VK_RSHIFT);
|
||||
keyCodes.push_back(CommonSharedConstants::VK_WIN_BOTH);
|
||||
keyCodes.push_back(VK_LWIN);
|
||||
keyCodes.push_back(VK_RWIN);
|
||||
|
||||
// Add all other special keys
|
||||
std::vector<DWORD> specialKeys;
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
// If it is not already been added (i.e. it was either a modifier or had a unicode representation)
|
||||
if (std::find(keyCodes.begin(), keyCodes.end(), i) == keyCodes.end())
|
||||
{
|
||||
// If it is any other key but it is not named as VK #
|
||||
auto it = unknownKeys.find(i);
|
||||
if (it == unknownKeys.end())
|
||||
{
|
||||
specialKeys.push_back(i);
|
||||
}
|
||||
else if (unknownKeys[i] != keyboardLayoutMap[i])
|
||||
{
|
||||
specialKeys.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the special keys in alphabetical order
|
||||
std::sort(specialKeys.begin(), specialKeys.end(), [&](const DWORD& lhs, const DWORD& rhs) {
|
||||
return keyboardLayoutMap[lhs] < keyboardLayoutMap[rhs];
|
||||
});
|
||||
for (int i = 0; i < specialKeys.size(); i++)
|
||||
{
|
||||
keyCodes.push_back(specialKeys[i]);
|
||||
}
|
||||
|
||||
// Add unknown keys
|
||||
for (auto& it : unknownKeys)
|
||||
{
|
||||
// If it was not renamed with a special name
|
||||
if (it.second == keyboardLayoutMap[it.first])
|
||||
{
|
||||
keyCodes.push_back(it.first);
|
||||
}
|
||||
}
|
||||
keyCodeList = keyCodes;
|
||||
isKeyCodeListGenerated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyCodes = keyCodeList;
|
||||
}
|
||||
|
||||
// If it is a key list for the shortcut control then we add a "None" key at the start
|
||||
if (isShortcut)
|
||||
{
|
||||
keyCodes.insert(keyCodes.begin(), 0);
|
||||
}
|
||||
|
||||
return keyCodes;
|
||||
}
|
||||
|
||||
std::vector<std::pair<DWORD, std::wstring>> LayoutMap::LayoutMapImpl::GetKeyNameList(const bool isShortcut)
|
||||
{
|
||||
std::vector<std::pair<DWORD, std::wstring>> keyNames;
|
||||
std::vector<DWORD> keyCodes = GetKeyCodeList(isShortcut);
|
||||
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
|
||||
// If it is a key list for the shortcut control then we add a "None" key at the start
|
||||
if (isShortcut)
|
||||
{
|
||||
keyNames.push_back({ 0, L"None" });
|
||||
for (int i = 1; i < keyCodes.size(); i++)
|
||||
{
|
||||
keyNames.push_back({ keyCodes[i], keyboardLayoutMap[keyCodes[i]] });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < keyCodes.size(); i++)
|
||||
{
|
||||
keyNames.push_back({ keyCodes[i], keyboardLayoutMap[keyCodes[i]] });
|
||||
}
|
||||
}
|
||||
|
||||
return keyNames;
|
||||
}
|
||||
20
src/common/interop/keyboard_layout.h
Normal file
20
src/common/interop/keyboard_layout.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <Windows.h>
|
||||
|
||||
class LayoutMap
|
||||
{
|
||||
public:
|
||||
LayoutMap();
|
||||
~LayoutMap();
|
||||
void UpdateLayout();
|
||||
std::wstring GetKeyName(DWORD key);
|
||||
std::vector<DWORD> GetKeyCodeList(const bool isShortcut = false);
|
||||
std::vector<std::pair<DWORD, std::wstring>> GetKeyNameList(const bool isShortcut = false);
|
||||
|
||||
private:
|
||||
class LayoutMapImpl;
|
||||
LayoutMapImpl* impl;
|
||||
};
|
||||
51
src/common/interop/keyboard_layout_impl.h
Normal file
51
src/common/interop/keyboard_layout_impl.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "keyboard_layout.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
|
||||
using namespace winrt;
|
||||
|
||||
// Wrapper class to handle keyboard layout
|
||||
class LayoutMap::LayoutMapImpl
|
||||
{
|
||||
private:
|
||||
// Stores mappings for all the virtual key codes to the name of the key
|
||||
std::mutex keyboardLayoutMap_mutex;
|
||||
|
||||
// Stores the previous layout
|
||||
HKL previousLayout = 0;
|
||||
|
||||
// Stores the keys which have a unicode representation
|
||||
std::map<DWORD, std::wstring> unicodeKeys;
|
||||
|
||||
// Stores the keys which do not have a name
|
||||
std::map<DWORD, std::wstring> unknownKeys;
|
||||
|
||||
// Stores true if the fixed ordering key code list has already been set
|
||||
bool isKeyCodeListGenerated = false;
|
||||
|
||||
// Stores a fixed order key code list for the drop down menus. It is kept fixed to change in ordering due to languages
|
||||
std::vector<DWORD> keyCodeList;
|
||||
|
||||
public:
|
||||
std::map<DWORD, std::wstring> keyboardLayoutMap;
|
||||
|
||||
// Update Keyboard layout according to input locale identifier
|
||||
void UpdateLayout();
|
||||
|
||||
LayoutMapImpl()
|
||||
{
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
// Function to return the unicode string name of the key
|
||||
std::wstring GetKeyName(DWORD key);
|
||||
|
||||
// Function to return the list of key codes in the order for the drop down. It creates it if it doesn't exist
|
||||
std::vector<DWORD> GetKeyCodeList(const bool isShortcut);
|
||||
|
||||
// Function to return the list of key name pairs in the order for the drop down based on the key codes
|
||||
std::vector<std::pair<DWORD, std::wstring>> GetKeyNameList(const bool isShortcut);
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
||||
18
src/common/interop/shared_constants.h
Normal file
18
src/common/interop/shared_constants.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace CommonSharedConstants
|
||||
{
|
||||
// Flag that can be set on an input event so that it is ignored by Keyboard Manager
|
||||
const uintptr_t KEYBOARDMANAGER_INJECTED_FLAG = 0x1;
|
||||
|
||||
// Fake key code to represent VK_WIN.
|
||||
inline const int VK_WIN_BOTH = 0x104;
|
||||
|
||||
// Path to the event used by PowerLauncher
|
||||
const wchar_t POWER_LAUNCHER_SHARED_EVENT[] = L"Local\\PowerToysRunInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab";
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const int VK_DISABLED = 0x100;
|
||||
}
|
||||
499
src/common/interop/two_way_pipe_message_ipc.cpp
Normal file
499
src/common/interop/two_way_pipe_message_ipc.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
#include "pch.h"
|
||||
#include "two_way_pipe_message_ipc_impl.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
|
||||
TwoWayPipeMessageIPC::TwoWayPipeMessageIPC(
|
||||
std::wstring _input_pipe_name,
|
||||
std::wstring _output_pipe_name,
|
||||
callback_function p_func) :
|
||||
impl(new TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl(
|
||||
_input_pipe_name,
|
||||
_output_pipe_name,
|
||||
p_func))
|
||||
{
|
||||
}
|
||||
|
||||
TwoWayPipeMessageIPC::~TwoWayPipeMessageIPC()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::send(std::wstring msg)
|
||||
{
|
||||
impl->send(msg);
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::start(HANDLE _restricted_pipe_token)
|
||||
{
|
||||
impl->start(_restricted_pipe_token);
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::end()
|
||||
{
|
||||
impl->end();
|
||||
}
|
||||
|
||||
TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::TwoWayPipeMessageIPCImpl(
|
||||
std::wstring _input_pipe_name,
|
||||
std::wstring _output_pipe_name,
|
||||
callback_function p_func)
|
||||
{
|
||||
input_pipe_name = _input_pipe_name;
|
||||
output_pipe_name = _output_pipe_name;
|
||||
dispatch_inc_message_function = p_func;
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::send(std::wstring msg)
|
||||
{
|
||||
output_queue.queue_message(msg);
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::start(HANDLE _restricted_pipe_token)
|
||||
{
|
||||
output_queue_thread = std::thread(&TwoWayPipeMessageIPCImpl::consume_output_queue_thread, this);
|
||||
input_queue_thread = std::thread(&TwoWayPipeMessageIPCImpl::consume_input_queue_thread, this);
|
||||
input_pipe_thread = std::thread(&TwoWayPipeMessageIPCImpl::start_named_pipe_server, this, _restricted_pipe_token);
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::end()
|
||||
{
|
||||
closed = true;
|
||||
input_queue.interrupt();
|
||||
input_queue_thread.join();
|
||||
output_queue.interrupt();
|
||||
output_queue_thread.join();
|
||||
pipe_connect_handle_mutex.lock();
|
||||
if (current_connect_pipe_handle != NULL)
|
||||
{
|
||||
//Cancels the Pipe currently waiting for a connection.
|
||||
CancelIoEx(current_connect_pipe_handle, NULL);
|
||||
}
|
||||
pipe_connect_handle_mutex.unlock();
|
||||
input_pipe_thread.join();
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::send_pipe_message(std::wstring message)
|
||||
{
|
||||
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-client
|
||||
HANDLE output_pipe_handle;
|
||||
const wchar_t* message_send = message.c_str();
|
||||
BOOL fSuccess = FALSE;
|
||||
DWORD cbToWrite, cbWritten, dwMode;
|
||||
const wchar_t* lpszPipename = output_pipe_name.c_str();
|
||||
|
||||
// Try to open a named pipe; wait for it, if necessary.
|
||||
|
||||
while (1)
|
||||
{
|
||||
output_pipe_handle = CreateFile(
|
||||
lpszPipename, // pipe name
|
||||
GENERIC_READ | // read and write access
|
||||
GENERIC_WRITE,
|
||||
0, // no sharing
|
||||
NULL, // default security attributes
|
||||
OPEN_EXISTING, // opens existing pipe
|
||||
0, // default attributes
|
||||
NULL); // no template file
|
||||
|
||||
// Break if the pipe handle is valid.
|
||||
|
||||
if (output_pipe_handle != INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
// Exit if an error other than ERROR_PIPE_BUSY occurs.
|
||||
DWORD curr_error = 0;
|
||||
if ((curr_error = GetLastError()) != ERROR_PIPE_BUSY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// All pipe instances are busy, so wait for 20 seconds.
|
||||
|
||||
if (!WaitNamedPipe(lpszPipename, 20000))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
dwMode = PIPE_READMODE_MESSAGE;
|
||||
fSuccess = SetNamedPipeHandleState(
|
||||
output_pipe_handle, // pipe handle
|
||||
&dwMode, // new pipe mode
|
||||
NULL, // don't set maximum bytes
|
||||
NULL); // don't set maximum time
|
||||
if (!fSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a message to the pipe server.
|
||||
|
||||
cbToWrite = (lstrlen(message_send)) * sizeof(WCHAR); // no need to send final '\0'. Pipe is in message mode.
|
||||
|
||||
fSuccess = WriteFile(
|
||||
output_pipe_handle, // pipe handle
|
||||
message_send, // message
|
||||
cbToWrite, // message length
|
||||
&cbWritten, // bytes written
|
||||
NULL); // not overlapped
|
||||
if (!fSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CloseHandle(output_pipe_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::consume_output_queue_thread()
|
||||
{
|
||||
while (!closed)
|
||||
{
|
||||
std::wstring message = output_queue.pop_message();
|
||||
if (message.length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
send_pipe_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::GetLogonSID(HANDLE hToken, PSID* ppsid)
|
||||
{
|
||||
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
|
||||
BOOL bSuccess = FALSE;
|
||||
DWORD dwIndex;
|
||||
DWORD dwLength = 0;
|
||||
PTOKEN_GROUPS ptg = NULL;
|
||||
|
||||
// Verify the parameter passed in is not NULL.
|
||||
if (NULL == ppsid)
|
||||
goto Cleanup;
|
||||
|
||||
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
|
||||
|
||||
if (!GetTokenInformation(
|
||||
hToken, // handle to the access token
|
||||
TokenGroups, // get information about the token's groups
|
||||
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
|
||||
0, // size of buffer
|
||||
&dwLength // receives required buffer size
|
||||
))
|
||||
{
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
goto Cleanup;
|
||||
|
||||
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
dwLength);
|
||||
|
||||
if (ptg == NULL)
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Get the token group information from the access token.
|
||||
|
||||
if (!GetTokenInformation(
|
||||
hToken, // handle to the access token
|
||||
TokenGroups, // get information about the token's groups
|
||||
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
|
||||
dwLength, // size of buffer
|
||||
&dwLength // receives required buffer size
|
||||
))
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Loop through the groups to find the logon SID.
|
||||
|
||||
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
|
||||
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
|
||||
{
|
||||
// Found the logon SID; make a copy of it.
|
||||
|
||||
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
|
||||
*ppsid = (PSID)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
dwLength);
|
||||
if (*ppsid == NULL)
|
||||
goto Cleanup;
|
||||
if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
|
||||
goto Cleanup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bSuccess = TRUE;
|
||||
|
||||
Cleanup:
|
||||
|
||||
// Free the buffer for the token groups.
|
||||
|
||||
if (ptg != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
VOID TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::FreeLogonSID(PSID* ppsid)
|
||||
{
|
||||
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
|
||||
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
|
||||
}
|
||||
|
||||
int TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::change_pipe_security_allow_restricted_token(HANDLE handle, HANDLE token)
|
||||
{
|
||||
PACL old_dacl, new_dacl;
|
||||
PSECURITY_DESCRIPTOR sd;
|
||||
EXPLICIT_ACCESS ea;
|
||||
PSID user_restricted;
|
||||
int error;
|
||||
|
||||
if (!GetLogonSID(token, &user_restricted))
|
||||
{
|
||||
error = 5; // No access error.
|
||||
goto Ldone;
|
||||
}
|
||||
|
||||
if (GetSecurityInfo(handle,
|
||||
SE_KERNEL_OBJECT,
|
||||
DACL_SECURITY_INFORMATION,
|
||||
NULL,
|
||||
NULL,
|
||||
&old_dacl,
|
||||
NULL,
|
||||
&sd))
|
||||
{
|
||||
error = GetLastError();
|
||||
goto Lclean_sid;
|
||||
}
|
||||
|
||||
memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
|
||||
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
|
||||
ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||
ea.grfAccessPermissions |= SYNCHRONIZE;
|
||||
ea.grfAccessMode = SET_ACCESS;
|
||||
ea.grfInheritance = NO_INHERITANCE;
|
||||
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||||
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
|
||||
ea.Trustee.ptstrName = (LPTSTR)user_restricted;
|
||||
|
||||
if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl))
|
||||
{
|
||||
error = GetLastError();
|
||||
goto Lclean_sd;
|
||||
}
|
||||
|
||||
if (SetSecurityInfo(handle,
|
||||
SE_KERNEL_OBJECT,
|
||||
DACL_SECURITY_INFORMATION,
|
||||
NULL,
|
||||
NULL,
|
||||
new_dacl,
|
||||
NULL))
|
||||
{
|
||||
error = GetLastError();
|
||||
goto Lclean_dacl;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
Lclean_dacl:
|
||||
LocalFree((HLOCAL)new_dacl);
|
||||
Lclean_sd:
|
||||
LocalFree((HLOCAL)sd);
|
||||
Lclean_sid:
|
||||
FreeLogonSID(&user_restricted);
|
||||
Ldone:
|
||||
return error;
|
||||
}
|
||||
|
||||
HANDLE TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::create_medium_integrity_token()
|
||||
{
|
||||
HANDLE restricted_token_handle;
|
||||
SAFER_LEVEL_HANDLE level_handle = NULL;
|
||||
DWORD sid_size = SECURITY_MAX_SID_SIZE;
|
||||
BYTE medium_sid[SECURITY_MAX_SID_SIZE];
|
||||
if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &level_handle, NULL))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!SaferComputeTokenFromLevel(level_handle, NULL, &restricted_token_handle, 0, NULL))
|
||||
{
|
||||
SaferCloseLevel(level_handle);
|
||||
return NULL;
|
||||
}
|
||||
SaferCloseLevel(level_handle);
|
||||
|
||||
if (!CreateWellKnownSid(WinMediumLabelSid, nullptr, medium_sid, &sid_size))
|
||||
{
|
||||
CloseHandle(restricted_token_handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TOKEN_MANDATORY_LABEL integrity_level = { 0 };
|
||||
integrity_level.Label.Attributes = SE_GROUP_INTEGRITY;
|
||||
integrity_level.Label.Sid = reinterpret_cast<PSID>(medium_sid);
|
||||
|
||||
if (!SetTokenInformation(restricted_token_handle, TokenIntegrityLevel, &integrity_level, sizeof(integrity_level)))
|
||||
{
|
||||
CloseHandle(restricted_token_handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return restricted_token_handle;
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::handle_pipe_connection(HANDLE input_pipe_handle)
|
||||
{
|
||||
//Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
|
||||
HANDLE hHeap = GetProcessHeap();
|
||||
uint8_t* pchRequest = (uint8_t*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(uint8_t));
|
||||
|
||||
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
|
||||
BOOL fSuccess = FALSE;
|
||||
|
||||
// Do some extra error checking since the app will keep running even if this thread fails.
|
||||
std::list<std::vector<uint8_t>> message_parts;
|
||||
|
||||
if (input_pipe_handle == NULL)
|
||||
{
|
||||
if (pchRequest != NULL)
|
||||
HeapFree(hHeap, 0, pchRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pchRequest == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop until done reading
|
||||
do
|
||||
{
|
||||
// Read client requests from the pipe. This simplistic code only allows messages
|
||||
// up to BUFSIZE characters in length.
|
||||
ZeroMemory(pchRequest, BUFSIZE * sizeof(uint8_t));
|
||||
fSuccess = ReadFile(
|
||||
input_pipe_handle, // handle to pipe
|
||||
pchRequest, // buffer to receive data
|
||||
BUFSIZE * sizeof(uint8_t), // size of buffer
|
||||
&cbBytesRead, // number of bytes read
|
||||
NULL); // not overlapped I/O
|
||||
|
||||
if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::vector<uint8_t> part_vector;
|
||||
part_vector.reserve(cbBytesRead);
|
||||
std::copy(pchRequest, pchRequest + cbBytesRead, std::back_inserter(part_vector));
|
||||
message_parts.push_back(part_vector);
|
||||
} while (!fSuccess);
|
||||
|
||||
if (fSuccess)
|
||||
{
|
||||
// Reconstruct the total_message.
|
||||
std::vector<uint8_t> reconstructed_message;
|
||||
size_t total_size = 0;
|
||||
for (auto& part_vector : message_parts)
|
||||
{
|
||||
total_size += part_vector.size();
|
||||
}
|
||||
reconstructed_message.reserve(total_size);
|
||||
for (auto& part_vector : message_parts)
|
||||
{
|
||||
std::move(part_vector.begin(), part_vector.end(), std::back_inserter(reconstructed_message));
|
||||
}
|
||||
std::wstring unicode_msg;
|
||||
unicode_msg.assign(reinterpret_cast<std::wstring::const_pointer>(reconstructed_message.data()), reconstructed_message.size() / sizeof(std::wstring::value_type));
|
||||
input_queue.queue_message(unicode_msg);
|
||||
}
|
||||
|
||||
// Flush the pipe to allow the client to read the pipe's contents
|
||||
// before disconnecting. Then disconnect the pipe, and close the
|
||||
// handle to this pipe instance.
|
||||
|
||||
FlushFileBuffers(input_pipe_handle);
|
||||
DisconnectNamedPipe(input_pipe_handle);
|
||||
CloseHandle(input_pipe_handle);
|
||||
|
||||
HeapFree(hHeap, 0, pchRequest);
|
||||
|
||||
printf("InstanceThread exiting.\n");
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::start_named_pipe_server(HANDLE token)
|
||||
{
|
||||
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
|
||||
const wchar_t* pipe_name = input_pipe_name.c_str();
|
||||
BOOL connected = FALSE;
|
||||
HANDLE connect_pipe_handle = INVALID_HANDLE_VALUE;
|
||||
while (!closed)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(pipe_connect_handle_mutex);
|
||||
connect_pipe_handle = CreateNamedPipe(
|
||||
pipe_name,
|
||||
PIPE_ACCESS_DUPLEX |
|
||||
WRITE_DAC,
|
||||
PIPE_TYPE_MESSAGE |
|
||||
PIPE_READMODE_MESSAGE |
|
||||
PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
BUFSIZE,
|
||||
BUFSIZE,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (connect_pipe_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (token != NULL)
|
||||
{
|
||||
int err = change_pipe_security_allow_restricted_token(connect_pipe_handle, token);
|
||||
}
|
||||
current_connect_pipe_handle = connect_pipe_handle;
|
||||
}
|
||||
connected = ConnectNamedPipe(connect_pipe_handle, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
|
||||
{
|
||||
std::unique_lock lock(pipe_connect_handle_mutex);
|
||||
current_connect_pipe_handle = NULL;
|
||||
}
|
||||
if (connected)
|
||||
{
|
||||
std::thread(&TwoWayPipeMessageIPCImpl::handle_pipe_connection, this, connect_pipe_handle).detach();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Client could not connect.
|
||||
CloseHandle(connect_pipe_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl::consume_input_queue_thread()
|
||||
{
|
||||
while (!closed)
|
||||
{
|
||||
outgoing_message = L"";
|
||||
std::wstring message = input_queue.pop_message();
|
||||
if (message.length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if callback method exists first before trying to call it.
|
||||
// otherwise just store the response message in a variable.
|
||||
if (dispatch_inc_message_function != nullptr)
|
||||
{
|
||||
dispatch_inc_message_function(message);
|
||||
}
|
||||
outgoing_message = message;
|
||||
}
|
||||
}
|
||||
18
src/common/interop/two_way_pipe_message_ipc.h
Normal file
18
src/common/interop/two_way_pipe_message_ipc.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
class TwoWayPipeMessageIPC
|
||||
{
|
||||
public:
|
||||
typedef void (*callback_function)(const std::wstring&);
|
||||
TwoWayPipeMessageIPC(
|
||||
std::wstring _input_pipe_name,
|
||||
std::wstring _output_pipe_name,
|
||||
callback_function p_func);
|
||||
~TwoWayPipeMessageIPC();
|
||||
void send(std::wstring msg);
|
||||
void start(HANDLE _restricted_pipe_token);
|
||||
void end();
|
||||
|
||||
private:
|
||||
class TwoWayPipeMessageIPCImpl;
|
||||
TwoWayPipeMessageIPCImpl* impl;
|
||||
};
|
||||
43
src/common/interop/two_way_pipe_message_ipc_impl.h
Normal file
43
src/common/interop/two_way_pipe_message_ipc_impl.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include "async_message_queue.h"
|
||||
#include <WinSafer.h>
|
||||
#include <accctrl.h>
|
||||
#include <aclapi.h>
|
||||
#include <list>
|
||||
#include "two_way_pipe_message_ipc.h"
|
||||
|
||||
class TwoWayPipeMessageIPC::TwoWayPipeMessageIPCImpl
|
||||
{
|
||||
public:
|
||||
void send(std::wstring msg);
|
||||
TwoWayPipeMessageIPCImpl(std::wstring _input_pipe_name, std::wstring _output_pipe_name, callback_function p_func);
|
||||
void start(HANDLE _restricted_pipe_token);
|
||||
void end();
|
||||
|
||||
private:
|
||||
AsyncMessageQueue input_queue;
|
||||
AsyncMessageQueue output_queue;
|
||||
std::wstring output_pipe_name;
|
||||
std::wstring input_pipe_name;
|
||||
std::thread input_queue_thread;
|
||||
std::thread output_queue_thread;
|
||||
std::thread input_pipe_thread;
|
||||
std::mutex pipe_connect_handle_mutex; // For manipulating the current_connect_pipe
|
||||
std::wstring outgoing_message; // Store the updated json settings.
|
||||
|
||||
HANDLE current_connect_pipe_handle = NULL;
|
||||
bool closed = false;
|
||||
TwoWayPipeMessageIPC::callback_function dispatch_inc_message_function;
|
||||
const DWORD BUFSIZE = 1024;
|
||||
|
||||
void send_pipe_message(std::wstring message);
|
||||
void consume_output_queue_thread();
|
||||
BOOL GetLogonSID(HANDLE hToken, PSID* ppsid);
|
||||
VOID FreeLogonSID(PSID* ppsid);
|
||||
int change_pipe_security_allow_restricted_token(HANDLE handle, HANDLE token);
|
||||
HANDLE create_medium_integrity_token();
|
||||
void handle_pipe_connection(HANDLE input_pipe_handle);
|
||||
void start_named_pipe_server(HANDLE token);
|
||||
void consume_input_queue_thread();
|
||||
};
|
||||
Reference in New Issue
Block a user