diff --git a/.pipelines/pipeline.user.windows.yml b/.pipelines/pipeline.user.windows.yml
index c851d2f1a..21a982792 100644
--- a/.pipelines/pipeline.user.windows.yml
+++ b/.pipelines/pipeline.user.windows.yml
@@ -116,6 +116,11 @@ build:
- 'modules\Microsoft.Launcher.dll'
- 'modules\PowerRename\PowerRenameExt.dll'
- 'modules\ShortcutGuide\ShortcutGuide.dll'
+ - 'modules\VideoConference\VideoConferenceModule.dll'
+ - 'modules\VideoConference\VideoConferenceVirtualDriver\VideoConferenceVirtualDriver.dll'
+ - 'modules\VideoConference\VideoConferenceVirtualDriver\VideoConferenceCustomMediaSource.dll'
+ - 'modules\VideoConference\VideoConferenceVirtualDriver\videoconferencevirtualdriver.cat'
+ - 'modules\VideoConference\VideoConferenceVirtualDriver\VideoConferenceVirtualDriver.inf'
- 'Notifications.dll'
- 'os-detection.dll'
- 'PowerToys.exe'
diff --git a/.pipelines/restore.cmd b/.pipelines/restore.cmd
index fd630aea5..22eb393aa 100644
--- a/.pipelines/restore.cmd
+++ b/.pipelines/restore.cmd
@@ -1,3 +1,12 @@
cd /D "%~dp0"
nuget restore ../PowerToys.sln || exit /b 1
+
+powershell.exe -Command "Invoke-WebRequest -OutFile %tmp%\wdksetup.exe https://go.microsoft.com/fwlink/p/?linkid=2085767"
+%tmp%\wdksetup.exe /q
+
+copy "C:\Program Files (x86)\Windows Kits\10\Vsix\VS2019\WDK.vsix" %tmp%\wdkvsix.zip
+powershell Expand-Archive %tmp%\wdkvsix.zip -DestinationPath %tmp%\wdkvsix -Force
+
+robocopy /e %tmp%\wdkvsix\$MSBuild\Microsoft\VC\v160 "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160" || IF %ERRORLEVEL% LEQ 7 EXIT 0
+robocopy /e %tmp%\wdkvsix\$VCTargets "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCTargets" || IF %ERRORLEVEL% LEQ 7 EXIT 0
diff --git a/PowerToys.sln b/PowerToys.sln
index 7812aa19d..4e13c7705 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -265,6 +265,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Uri.UnitTe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Settings.UI.UnitTests", "src\core\Microsoft.PowerToys.Settings.UI.UnitTests\Microsoft.PowerToys.Settings.UI.UnitTests.csproj", "{0F85E674-34AE-443D-954C-8321EB8B93B1}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{05BE6150-D5B3-48F0-AEB9-C44096950C6D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceCustomMediaSource", "src\modules\videoconference\VideoConferenceCustomMediaSource\VideoConferenceCustomMediaSource.vcxproj", "{43AD9BF7-E765-48FE-9826-71A8F2CB12DD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceModule", "src\modules\videoconference\VideoConferenceModule\Video Conference.vcxproj", "{FD2CAFFC-D682-4ED9-A06B-5FC88AE0A193}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceShared", "src\modules\videoconference\VideoConferenceShared\VideoConferenceShared.vcxproj", "{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceVirtualDriver", "src\modules\videoconference\VideoConferenceVirtualDriver\VideoConferenceVirtualDriver.vcxproj", "{3098C6BF-E96E-4793-A70E-FB09B741580A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -531,6 +544,24 @@ Global
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.Build.0 = Debug|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.ActiveCfg = Release|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.Build.0 = Release|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Debug|x64.ActiveCfg = Debug|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Debug|x64.Build.0 = Debug|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Release|x64.ActiveCfg = Release|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Release|x64.Build.0 = Release|x64
+ {FD2CAFFC-D682-4ED9-A06B-5FC88AE0A193}.Debug|x64.ActiveCfg = Debug|x64
+ {FD2CAFFC-D682-4ED9-A06B-5FC88AE0A193}.Debug|x64.Build.0 = Debug|x64
+ {FD2CAFFC-D682-4ED9-A06B-5FC88AE0A193}.Release|x64.ActiveCfg = Release|x64
+ {FD2CAFFC-D682-4ED9-A06B-5FC88AE0A193}.Release|x64.Build.0 = Release|x64
+ {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.ActiveCfg = Debug|x64
+ {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.Build.0 = Debug|x64
+ {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64
+ {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64
+ {3098C6BF-E96E-4793-A70E-FB09B741580A}.Debug|x64.ActiveCfg = Debug|x64
+ {3098C6BF-E96E-4793-A70E-FB09B741580A}.Debug|x64.Build.0 = Debug|x64
+ {3098C6BF-E96E-4793-A70E-FB09B741580A}.Debug|x64.Deploy.0 = Debug|x64
+ {3098C6BF-E96E-4793-A70E-FB09B741580A}.Release|x64.ActiveCfg = Release|x64
+ {3098C6BF-E96E-4793-A70E-FB09B741580A}.Release|x64.Build.0 = Release|x64
+ {3098C6BF-E96E-4793-A70E-FB09B741580A}.Release|x64.Deploy.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -607,6 +638,11 @@ Global
{03276A39-D4E9-417C-8FFD-200B0EE5E871} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{B81FB7B6-D30E-428F-908A-41422EFC1172} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0F85E674-34AE-443D-954C-8321EB8B93B1} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
+ {05BE6150-D5B3-48F0-AEB9-C44096950C6D} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD} = {05BE6150-D5B3-48F0-AEB9-C44096950C6D}
+ {FD2CAFFC-D682-4ED9-A06B-5FC88AE0A193} = {05BE6150-D5B3-48F0-AEB9-C44096950C6D}
+ {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {05BE6150-D5B3-48F0-AEB9-C44096950C6D}
+ {3098C6BF-E96E-4793-A70E-FB09B741580A} = {05BE6150-D5B3-48F0-AEB9-C44096950C6D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
diff --git a/installer/PowerToysSetup/PowerToysSetup.wixproj b/installer/PowerToysSetup/PowerToysSetup.wixproj
index 8c5ad9d3d..7f3bc6951 100644
--- a/installer/PowerToysSetup/PowerToysSetup.wixproj
+++ b/installer/PowerToysSetup/PowerToysSetup.wixproj
@@ -2,8 +2,9 @@
+
- Version=$(Version);
+ Version=$(Version);HasWDK=$(HasWDK)
Release
diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs
index dee4bedd4..c0279b9c3 100644
--- a/installer/PowerToysSetup/Product.wxs
+++ b/installer/PowerToysSetup/Product.wxs
@@ -9,6 +9,7 @@
+
@@ -87,6 +88,20 @@
NOT Installed and CREATESCHEDULEDTASK = 1
+
+
+
+ NOT Installed
+
+
+
+ NOT Installed
+
+
+
+ Installed
+
+
@@ -204,6 +219,44 @@
DllEntry="DetectPrevInstallPathCA"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -240,6 +293,11 @@
+
+
+
+
+
@@ -612,6 +670,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -793,6 +881,10 @@
+
+
+
+
diff --git a/installer/PowerToysSetup/publish.cmd b/installer/PowerToysSetup/publish.cmd
index b52cdc0bb..5b766039b 100644
--- a/installer/PowerToysSetup/publish.cmd
+++ b/installer/PowerToysSetup/publish.cmd
@@ -31,7 +31,6 @@ echo ^ >> !settingsPublishProfile!
rem In case of Release we should not use Debug CRT in VCRT forwarders
msbuild !PTRoot!\src\core\Microsoft.PowerToys.Settings.UI.Runner\Microsoft.PowerToys.Settings.UI.Runner.csproj -t:Publish -p:Configuration="Release" -p:Platform="x64" -p:AppxBundle=Never -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=!settingsProfileFileName!
-
rem Publish Launcher
SET launcherProfileFolderName=!PTRoot!\src\modules\launcher\PowerLauncher\Properties\PublishProfiles\
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp
index 99d915d55..96993a74f 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.cpp
+++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp
@@ -3,6 +3,11 @@
#include
#include "../../src/common/updating/updating.h"
+#include
+
+#include
+
+#pragma comment (lib, "crypt32.lib")
using namespace std;
@@ -16,6 +21,7 @@ TRACELOGGING_DEFINE_PROVIDER(
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
+static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
// Creates a Scheduled Task to run at logon for the current user.
@@ -564,6 +570,8 @@ LExit:
return WcaFinalize(er);
}
+
+
UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
@@ -662,6 +670,165 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
return WcaFinalize(er);
}
+UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall)
+{
+#ifdef CIBuild // On pipeline we are using microsoft certification
+ WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
+ return WcaFinalize(ERROR_SUCCESS);
+#else
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ LPWSTR certificatePath = NULL;
+ HCERTSTORE hCertStore = NULL;
+ HANDLE hfile = NULL;
+ DWORD size = INVALID_FILE_SIZE;
+
+ hr = WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
+ ExitOnFailure(hr, "Failed to initialize", hr);
+
+ hr = WcaGetProperty(L"CustomActionData", &certificatePath);
+ ExitOnFailure(hr, "Failed to get install preperty", hr);
+
+ hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"AuthRoot");
+ if (!hCertStore)
+ {
+ hr = GetLastError();
+ ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
+ }
+
+ hfile = CreateFile(certificatePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hfile == INVALID_HANDLE_VALUE)
+ {
+ hr = GetLastError();
+ ExitOnFailure(hr, "Certificate file open failed", hr);
+ }
+
+ size = GetFileSize(hfile, NULL);
+ if (size == INVALID_FILE_SIZE)
+ {
+ hr = GetLastError();
+ ExitOnFailure(hr, "Certificate file size not valid", hr);
+ }
+
+ char* pFileContent = (char*)malloc(size);
+
+ DWORD sizeread;
+ if (!ReadFile(hfile, pFileContent, size, &sizeread, NULL))
+ {
+ hr = GetLastError();
+ ExitOnFailure(hr, "Certificate file read failed", hr);
+ }
+
+ if (!CertAddEncodedCertificateToStore(hCertStore,
+ X509_ASN_ENCODING,
+ (const BYTE*)pFileContent,
+ size,
+ CERT_STORE_ADD_ALWAYS,
+ NULL))
+ {
+ hr = GetLastError();
+ ExitOnFailure(hr, "Adding certificate failed", hr);
+ }
+
+ free(pFileContent);
+
+LExit:
+ ReleaseStr(certificatePath);
+ if (hCertStore)
+ {
+ CertCloseStore(hCertStore, 0);
+ }
+ if (hfile)
+ {
+ CloseHandle(hfile);
+ }
+
+ if (!SUCCEEDED(hr))
+ {
+ PMSIHANDLE hRecord = MsiCreateRecord(0);
+ MsiRecordSetString(hRecord, 0, TEXT("Failed to add certificate to store"));
+ MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
+ }
+
+
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+#endif
+}
+
+
+UINT __stdcall InstallVirtualCameraDriverCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ hr = WcaInitialize(hInstall, "InstallVirtualCameraDriverCA");
+ ExitOnFailure(hr, "Failed to initialize");
+
+ LPWSTR driverPath = NULL;
+
+ hr = WcaGetProperty(L"CustomActionData", &driverPath);
+ ExitOnFailure(hr, "Failed to get install preperty");
+
+ BOOL requiresReboot;
+ DiInstallDriverW(GetConsoleWindow(), driverPath, DIIRFLAG_FORCE_INF, &requiresReboot);
+
+ hr = GetLastError();
+ ExitOnFailure(hr, "Failed to install driver");
+
+LExit:
+
+ if (!SUCCEEDED(hr))
+ {
+ PMSIHANDLE hRecord = MsiCreateRecord(0);
+ MsiRecordSetString(hRecord, 0, TEXT("Failed to install virtual camera driver"));
+ MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
+ }
+
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
+UINT __stdcall UninstallVirtualCameraDriverCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ hr = WcaInitialize(hInstall, "UninstallVirtualCameraDriverCA");
+ ExitOnFailure(hr, "Failed to initialize");
+
+ LPWSTR driverPath = NULL;
+
+ hr = WcaGetProperty(L"CustomActionData", &driverPath);
+ ExitOnFailure(hr, "Failed to get uninstall preperty");
+
+ BOOL requiresReboot;
+ DiUninstallDriverW(GetConsoleWindow(), driverPath, 0, &requiresReboot);
+
+ switch (GetLastError())
+ {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_INVALID_FLAGS:
+ case ERROR_IN_WOW64:
+ {
+ hr = GetLastError();
+ ExitOnFailure(hr, "Failed to uninstall driver");
+ break;
+ }
+ }
+
+LExit:
+
+ if (!SUCCEEDED(hr))
+ {
+ PMSIHANDLE hRecord = MsiCreateRecord(0);
+ MsiRecordSetString(hRecord, 0, TEXT("Filed to iminstall virtual camera driver"));
+ MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
+ }
+
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
// DllMain - Initialize and cleanup WiX custom action utils.
extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID)
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def
index 3e8a2ab72..0f90c2e4d 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.def
+++ b/installer/PowerToysSetupCustomActions/CustomAction.def
@@ -12,4 +12,7 @@ EXPORTS
TelemetryLogUninstallFailCA
TelemetryLogRepairCancelCA
TelemetryLogRepairFailCA
- TerminateProcessesCA
\ No newline at end of file
+ TerminateProcessesCA
+ CertifyVirtualCameraDriverCA
+ InstallVirtualCameraDriverCA
+ UninstallVirtualCameraDriverCA
diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
index e0a23ec46..fbec536dd 100644
--- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
+++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
@@ -60,7 +60,7 @@
true
- Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;..\..\$(PlatformShortName)\$(Configuration)\common.lib;..\..\$(PlatformShortName)\$(Configuration)\updating.lib;%(AdditionalDependencies)
+ Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;Newdev.lib;..\..\$(PlatformShortName)\$(Configuration)\common.lib;..\..\$(PlatformShortName)\$(Configuration)\updating.lib;%(AdditionalDependencies)
$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)
CustomAction.def
true
@@ -81,8 +81,11 @@
stdcpplatest
true
+
+ /DCIBuild
+
- Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;..\..\$(PlatformShortName)\$(Configuration)\common.lib;..\..\$(PlatformShortName)\$(Configuration)\updating.lib;%(AdditionalDependencies)
+ Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;Newdev.lib;..\..\$(PlatformShortName)\$(Configuration)\common.lib;..\..\$(PlatformShortName)\$(Configuration)\updating.lib;%(AdditionalDependencies)
$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)
CustomAction.def
true
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index 97a46b404..41e78013b 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -132,6 +132,7 @@
+
@@ -141,6 +142,7 @@
+
@@ -171,6 +173,7 @@
+
@@ -185,6 +188,7 @@
+
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index c9abbe7cb..b1d35cdce 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -141,6 +141,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
@@ -222,8 +228,14 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
-
\ No newline at end of file
+
diff --git a/src/common/monitors.cpp b/src/common/monitors.cpp
index 1ad10aaff..e96b065bf 100644
--- a/src/common/monitors.cpp
+++ b/src/common/monitors.cpp
@@ -72,3 +72,23 @@ MonitorInfo MonitorInfo::GetPrimaryMonitor()
EnumDisplayMonitors(NULL, NULL, GetPrimaryDisplayEnumCb, reinterpret_cast(&primary));
return primary;
}
+
+MonitorInfo MonitorInfo::GetFromWindow(HWND hwnd)
+{
+ auto monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+ return GetFromHandle(monitor);
+}
+
+MonitorInfo MonitorInfo::GetFromPoint(POINT p)
+{
+ auto monitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST);
+ return GetFromHandle(monitor);
+}
+
+MonitorInfo MonitorInfo::GetFromHandle(HMONITOR monitor)
+{
+ MONITORINFOEX monitor_info;
+ monitor_info.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(monitor, &monitor_info);
+ return MonitorInfo(monitor, monitor_info.rcWork);
+}
diff --git a/src/common/monitors.h b/src/common/monitors.h
index 7771e843d..6af6de74a 100644
--- a/src/common/monitors.h
+++ b/src/common/monitors.h
@@ -33,6 +33,9 @@ struct MonitorInfo : ScreenSize
// Returns monitor rects ordered from left to right
static std::vector GetMonitors(bool includeNonWorkingArea);
static MonitorInfo GetPrimaryMonitor();
+ static MonitorInfo GetFromWindow(HWND hwnd);
+ static MonitorInfo GetFromPoint(POINT p);
+ static MonitorInfo GetFromHandle(HMONITOR monitor);
};
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs);
diff --git a/src/common/naming.cpp b/src/common/naming.cpp
new file mode 100644
index 000000000..70d2af9b1
--- /dev/null
+++ b/src/common/naming.cpp
@@ -0,0 +1,20 @@
+#include "pch.h"
+#include "naming.h"
+
+#include "user.h"
+
+std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted)
+{
+ static const std::optional username = ObtainActiveUserName();
+ std::wstring result = L"Global\\";
+ if (restricted)
+ {
+ result += L"Restricted\\";
+ }
+ if (username)
+ {
+ result += *username;
+ }
+ result += name;
+ return result;
+}
diff --git a/src/common/naming.h b/src/common/naming.h
new file mode 100644
index 000000000..8d127b062
--- /dev/null
+++ b/src/common/naming.h
@@ -0,0 +1,5 @@
+#pragma once
+#include
+#include
+
+std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);
\ No newline at end of file
diff --git a/src/common/settings_helpers.h b/src/common/settings_helpers.h
index 754ab0237..1b9b21192 100644
--- a/src/common/settings_helpers.h
+++ b/src/common/settings_helpers.h
@@ -7,6 +7,7 @@
namespace PTSettingsHelper
{
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
+ std::wstring get_module_save_file_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location();
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings);
diff --git a/src/common/settings_objects.h b/src/common/settings_objects.h
index 52f654b96..f3cc37493 100644
--- a/src/common/settings_objects.h
+++ b/src/common/settings_objects.h
@@ -202,7 +202,7 @@ namespace PowerToysSettings
if (output_bytes == 1 && output[0] >= 'a' && output[0] <= 'z')
{
// Make Latin letters keys capital, as it looks better
- output[0] = toupper(output[0]);
+ output[0] = static_cast(toupper(output[0]));
}
return output.data();
}
diff --git a/src/common/timeutil.h b/src/common/timeutil.h
index 348eb7ab9..cd1a101da 100644
--- a/src/common/timeutil.h
+++ b/src/common/timeutil.h
@@ -26,6 +26,13 @@ namespace timeutil
return std::nullopt;
}
}
+ inline time_t from_filetime(const FILETIME& ft)
+ {
+ ULARGE_INTEGER ull;
+ ull.LowPart = ft.dwLowDateTime;
+ ull.HighPart = ft.dwHighDateTime;
+ return ull.QuadPart / 10000000ULL - 11644473600ULL;
+ }
inline std::time_t now()
{
diff --git a/src/common/user.cpp b/src/common/user.cpp
new file mode 100644
index 000000000..1e3f1d56d
--- /dev/null
+++ b/src/common/user.cpp
@@ -0,0 +1,20 @@
+#include "pch.h"
+#include "user.h"
+
+#include
+
+std::optional ObtainActiveUserName()
+{
+ const DWORD sessionId = WTSGetActiveConsoleSessionId();
+ WCHAR* pUserName;
+ DWORD _ = 0;
+
+ if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &pUserName, &_))
+ {
+ return std::nullopt;
+ }
+ WTSGetActiveConsoleSessionId();
+ std::wstring result{ pUserName };
+ WTSFreeMemory(pUserName);
+ return result;
+}
diff --git a/src/common/user.h b/src/common/user.h
new file mode 100644
index 000000000..dcbefec38
--- /dev/null
+++ b/src/common/user.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include
+#include
+#include
+
+std::optional ObtainActiveUserName();
+
+std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);
\ No newline at end of file
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/EnabledModules.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/EnabledModules.cs
index 835b9a726..db2c112a7 100644
--- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/EnabledModules.cs
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/EnabledModules.cs
@@ -80,6 +80,22 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
}
}
+ private bool videoConference = true;
+
+ [JsonPropertyName("Video Conference")]
+ public bool VideoConference
+ {
+ get => this.videoConference;
+ set
+ {
+ if (this.videoConference != value)
+ {
+ LogTelemetryEvent(value);
+ this.videoConference = value;
+ }
+ }
+ }
+
private bool powerRename = true;
public bool PowerRename
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/SettingsUtils.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/SettingsUtils.cs
index abc6c1cd9..f70c5fdb8 100644
--- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/SettingsUtils.cs
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/SettingsUtils.cs
@@ -56,6 +56,22 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
return JsonSerializer.Deserialize(jsonSettingsString);
}
+ public static T GetOrCreateSettings(string powertoy = DefaultModuleName, string fileName = DefaultFileName)
+ where T : new()
+ {
+ try
+ {
+ var jsonSettingsString = File.ReadAllText(GetSettingsPath(powertoy, fileName));
+ return JsonSerializer.Deserialize(jsonSettingsString);
+ }
+ catch
+ {
+ var settings = new T();
+ SaveSettings(JsonSerializer.Serialize(settings), powertoy, fileName);
+ return settings;
+ }
+ }
+
// Save settings to a json file.
public static void SaveSettings(string jsonSettings, string powertoy = DefaultModuleName, string fileName = DefaultFileName)
{
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/SndVideoConferenceSettings.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/SndVideoConferenceSettings.cs
new file mode 100644
index 000000000..166835ac8
--- /dev/null
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/SndVideoConferenceSettings.cs
@@ -0,0 +1,28 @@
+// 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.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.PowerToys.Settings.UI.Lib
+{
+ public class SndVideoConferenceSettings
+ {
+ [JsonPropertyName("Video Conference")]
+ public VideoConferenceSettings VideoConference { get; set; }
+
+ public SndVideoConferenceSettings(VideoConferenceSettings settings)
+ {
+ this.VideoConference = settings;
+ }
+
+ public string ToJsonString()
+ {
+ return JsonSerializer.Serialize(this);
+ }
+ }
+}
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/StringProperty.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/StringProperty.cs
index 6165d7544..fb44f2479 100644
--- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/StringProperty.cs
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/StringProperty.cs
@@ -29,5 +29,10 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{
return JsonSerializer.Serialize(this);
}
+
+ public static implicit operator StringProperty(string v)
+ {
+ return new StringProperty(v);
+ }
}
}
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceConfigProperties.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceConfigProperties.cs
new file mode 100644
index 000000000..49eff76b4
--- /dev/null
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceConfigProperties.cs
@@ -0,0 +1,85 @@
+// 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.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.PowerToys.Settings.UI.Lib
+{
+ public class VideoConferenceConfigProperties
+ {
+ public VideoConferenceConfigProperties()
+ {
+ this.MuteCameraAndMicrophoneHotkey = new KeyboardKeysProperty(
+ new HotkeySettings()
+ {
+ Win = true,
+ Ctrl = false,
+ Alt = false,
+ Shift = false,
+ Key = "N",
+ Code = 78,
+ });
+
+ this.MuteMicrophoneHotkey = new KeyboardKeysProperty(
+ new HotkeySettings()
+ {
+ Win = true,
+ Ctrl = false,
+ Alt = false,
+ Shift = true,
+ Key = "A",
+ Code = 65,
+ });
+
+ this.MuteCameraHotkey = new KeyboardKeysProperty(
+ new HotkeySettings()
+ {
+ Win = true,
+ Ctrl = false,
+ Alt = false,
+ Shift = true,
+ Key = "O",
+ Code = 79,
+ });
+
+ Theme = new StringProperty("light");
+
+ this.HideOverlayWhenUnmuted = new BoolProperty(true);
+ }
+
+ [JsonPropertyName("mute_camera_and_microphone_hotkey")]
+ public KeyboardKeysProperty MuteCameraAndMicrophoneHotkey { get; set; }
+
+ [JsonPropertyName("mute_microphone_hotkey")]
+ public KeyboardKeysProperty MuteMicrophoneHotkey { get; set; }
+
+ [JsonPropertyName("mute_camera_hotkey")]
+ public KeyboardKeysProperty MuteCameraHotkey { get; set; }
+
+ [JsonPropertyName("selected_camera")]
+ public StringProperty SelectedCamera { get; set; } = string.Empty;
+
+ [JsonPropertyName("overlay_position")]
+ public StringProperty OverlayPosition { get; set; } = "Top right corner";
+
+ [JsonPropertyName("overlay_monitor")]
+ public StringProperty OverlayMonitor { get; set; } = "Main monitor";
+
+ [JsonPropertyName("camera_overlay_image_path")]
+ public StringProperty CameraOverlayImagePath { get; set; } = string.Empty;
+
+ [JsonPropertyName("theme")]
+ public StringProperty Theme { get; set; }
+
+ [JsonPropertyName("hide_overlay_when_unmuted")]
+ public BoolProperty HideOverlayWhenUnmuted { get; set; }
+
+ // converts the current to a json string.
+ public string ToJsonString()
+ {
+ return JsonSerializer.Serialize(this);
+ }
+ }
+}
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceSettings.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceSettings.cs
new file mode 100644
index 000000000..ff434176b
--- /dev/null
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceSettings.cs
@@ -0,0 +1,36 @@
+// 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.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.PowerToys.Settings.UI.Lib
+{
+ public class VideoConferenceSettings
+ {
+ public VideoConferenceSettings()
+ {
+ this.Version = "1.0";
+ this.Name = "Video Conference";
+ this.Properties = new VideoConferenceConfigProperties();
+ }
+
+ [JsonPropertyName("version")]
+ public string Version { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("properties")]
+ public VideoConferenceConfigProperties Properties { get; set; }
+
+ public string ToJsonString()
+ {
+ return JsonSerializer.Serialize(this);
+ }
+ }
+}
diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceSettingsIPCMessage.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceSettingsIPCMessage.cs
new file mode 100644
index 000000000..a188e5ce3
--- /dev/null
+++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/VideoConferenceSettingsIPCMessage.cs
@@ -0,0 +1,29 @@
+// 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.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.PowerToys.Settings.UI.Lib
+{
+ public class VideoConferenceSettingsIPCMessage
+ {
+ [JsonPropertyName("powertoys")]
+ public SndVideoConferenceSettings Powertoys { get; set; }
+
+ public VideoConferenceSettingsIPCMessage()
+ {
+ }
+
+ public VideoConferenceSettingsIPCMessage(SndVideoConferenceSettings settings)
+ {
+ this.Powertoys = settings;
+ }
+
+ public string ToJsonString()
+ {
+ return JsonSerializer.Serialize(this);
+ }
+ }
+}
diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj b/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj
index 051bec93f..c965f16e1 100644
--- a/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj
+++ b/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj
@@ -111,6 +111,7 @@
+
ColorPickerPage.xaml
@@ -141,6 +142,9 @@
ShortcutGuidePage.xaml
+
+ VideoConference.xaml
+
@@ -182,7 +186,7 @@
6.1.0
- 6.1.1
+ 6.1.2
2.5.0-prerelease.200708003
@@ -275,6 +279,10 @@
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
@@ -298,12 +306,6 @@
false
false
-
- 8.0
-
-
- 8.0
-