Add new VideoConference module for muting mic/cam (#11798)

* add new VideoConference module for muting mic/cam

Co-authored-by: PrzemyslawTusinski <61138537+PrzemyslawTusinski@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
Andrey Nekrasov 2021-06-29 13:06:12 +03:00 committed by GitHub
parent e450669663
commit 4e23832d52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
116 changed files with 7425 additions and 81 deletions

View File

@ -46,6 +46,7 @@ Aissue
akamaihd akamaihd
ALarger ALarger
alekhyareddy alekhyareddy
alignas
ALIGNLEFT ALIGNLEFT
ALLAPPS ALLAPPS
Alloc Alloc
@ -142,9 +143,11 @@ autoplay
Autorun Autorun
AUTOSIZECOLUMNS AUTOSIZECOLUMNS
autoupdate autoupdate
awakeversion
AValid AValid
avialable
awakeversion
AWAYMODE AWAYMODE
AYUV
azurecr azurecr
azurewebsites azurewebsites
backend backend
@ -185,6 +188,7 @@ bms
BNumber BNumber
Bokm Bokm
BOKMAL BOKMAL
boolalpha
Bools Bools
bootstrapper bootstrapper
Bopomofo Bopomofo
@ -213,6 +217,7 @@ BValue
bytearray bytearray
callbackptr callbackptr
callhistory callhistory
Camer
Cangjie Cangjie
cangjieime cangjieime
CANRENAME CANRENAME
@ -285,6 +290,7 @@ CMock
CMONITORS CMONITORS
cmyk cmyk
cnt cnt
coc
coclass coclass
codebase codebase
codecvt codecvt
@ -293,9 +299,10 @@ codereview
Codespaces Codespaces
COINIT COINIT
colorconv colorconv
colorfilter
colorhistory colorhistory
colorhistorylimit colorhistorylimit
colorfilter COLORKEY
colorpicker colorpicker
COLORREF COLORREF
colorscheme colorscheme
@ -429,6 +436,7 @@ dcomp
DComposition DComposition
ddd ddd
ddee ddee
ddf
Deact Deact
declspec declspec
decltype decltype
@ -472,11 +480,14 @@ devenum
deviceencryption deviceencryption
devicemanagenent devicemanagenent
DEVMON DEVMON
devpkey
DEVSOURCE
DFactory DFactory
DHCP DHCP
Dialpad Dialpad
diffing diffing
difftime difftime
DIIRFLAG
dimm dimm
directaccess directaccess
dirname dirname
@ -489,6 +500,7 @@ Displayandhidethedesktop
DISPLAYCHANGE DISPLAYCHANGE
displayname displayname
divyan divyan
djsoref
DLACTIVEXCTLS DLACTIVEXCTLS
DLCONTROL DLCONTROL
dlg dlg
@ -501,9 +513,10 @@ dllexport
dllhost dllhost
dllmain dllmain
DNLEN DNLEN
docsmsft
Dns Dns
docsmsft
doctype doctype
dogancelik
domainlexicon domainlexicon
DONTVALIDATEPATH DONTVALIDATEPATH
dotnet dotnet
@ -531,7 +544,11 @@ dupenv
dutil dutil
DVASPECT DVASPECT
DVASPECTINFO DVASPECTINFO
DVH
DVHD
DVR DVR
DVSD
DVSL
DVTARGETDEVICE DVTARGETDEVICE
DWindow DWindow
DWINRT DWINRT
@ -550,6 +567,8 @@ dword
dworigin dworigin
dwrite dwrite
dxgi dxgi
dxgiformat
dxguid
dynamiclock dynamiclock
EABF EABF
EAC EAC
@ -602,6 +621,7 @@ efa
efgh efgh
EFile EFile
egistry egistry
elif
elseif elseif
emailandaccounts emailandaccounts
Emoji Emoji
@ -610,6 +630,7 @@ ENABLEDPOPUP
endforeach endforeach
endif endif
endl endl
endpointvolume
endregion endregion
Enque Enque
ENTERSIZEMOVE ENTERSIZEMOVE
@ -662,7 +683,7 @@ exlist
EXPCMDFLAGS EXPCMDFLAGS
EXPCMDSTATE EXPCMDSTATE
explr explr
Expr expr
exsb exsb
EXSEL EXSEL
exstyle exstyle
@ -679,6 +700,7 @@ FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR FANCYZONESEDITOR
Farbraum Farbraum
FARPROC FARPROC
fdw
feimage feimage
ffcd ffcd
FFDDDDDD FFDDDDDD
@ -690,13 +712,16 @@ FILEFLAGS
FILEFLAGSMASK FILEFLAGSMASK
FILEOP FILEOP
FILEOS FILEOS
filepath
FILESUBTYPE FILESUBTYPE
FILESYSPATH FILESYSPATH
filesystem filesystem
FILETIME FILETIME
FILETYPE FILETYPE
FILEVERSION FILEVERSION
Filtergraph
Filterkeyboard Filterkeyboard
Filterx
finalizer finalizer
findfast findfast
findmydevice findmydevice
@ -705,6 +730,7 @@ FIXEDFILEINFO
FLASHZONES FLASHZONES
FLASHZONESONQUICKSWITCH FLASHZONESONQUICKSWITCH
Fle Fle
flt
fluentui fluentui
flyout flyout
fmtlib fmtlib
@ -726,6 +752,7 @@ FTYPE
FULLNAME FULLNAME
fullscreen fullscreen
func func
Functiondiscoverykeys
fwlink fwlink
fwrite fwrite
fxcop fxcop
@ -736,6 +763,7 @@ Gamebar
gamedvr gamedvr
gamemode gamemode
GBs GBs
GCLP
gcnew gcnew
gdi gdi
gdiplus gdiplus
@ -778,8 +806,10 @@ Hashset
hbitmap hbitmap
hbmp hbmp
hbr hbr
HBRBACKGROUND
HBRUSH HBRUSH
hcblack hcblack
HCERTSTORE
hcwhite hcwhite
hdc hdc
HDF HDF
@ -791,6 +821,8 @@ hdrop
HDS HDS
HEB HEB
helptext helptext
HEVC
hfile
HGLOBAL HGLOBAL
hhk hhk
HHmmss HHmmss
@ -865,11 +897,13 @@ IApp
IApplication IApplication
IAppx IAppx
IAsync IAsync
IAudio
IAuto IAuto
IBackground IBackground
IBase IBase
IBeam IBeam
IBind IBind
ICapture
icase icase
iccex iccex
ICEBLUE ICEBLUE
@ -922,9 +956,11 @@ IFancy
ifdef ifdef
IFeatures IFeatures
IFile IFile
IFilter
ifndef ifndef
IFolder IFolder
ifstream ifstream
IGraph
iid iid
IImage IImage
Iindex Iindex
@ -944,8 +980,11 @@ imagingdevices
IMain IMain
IMarkdown IMarkdown
ime ime
IMedia
IMem
imeutil imeutil
img img
iminstall
IMoniker IMoniker
IMonitor IMonitor
IMouse IMouse
@ -1002,6 +1041,7 @@ IObject
iobjectwithsitesetsite iobjectwithsitesetsite
IOle IOle
iolewindowcontextsensitivehelp iolewindowcontextsensitivehelp
iomanip
iostream iostream
IPackage IPackage
IPath IPath
@ -1023,6 +1063,7 @@ IProperty
IPublic IPublic
IQuery IQuery
IRead IRead
IReference
IReflect IReflect
IRegistered IRegistered
IRegistration IRegistration
@ -1055,6 +1096,7 @@ ith
IThrottled IThrottled
IThumbnail IThumbnail
ITrigger ITrigger
itsme
IUI IUI
IUnknown IUnknown
IUri IUri
@ -1065,9 +1107,11 @@ IVector
IView IView
IVirtual IVirtual
IWeb IWeb
IXml IWIC
IWindows IWindows
IXml
ixx ixx
IYUV
IZone IZone
IZoom IZoom
JArray JArray
@ -1116,17 +1160,17 @@ Keytool
keyup keyup
KILLFOCUS KILLFOCUS
Knownfolders Knownfolders
KSPROPERTY
Kybd Kybd
LAlt LAlt
Lambson Lambson
lamotile lamotile
langword langword
langword
Lastdevice Lastdevice
LASTEXITCODE LASTEXITCODE
Laute
launchfaceenrollment launchfaceenrollment
launchfingerprintenrollment launchfingerprintenrollment
Laute
laute laute
laviusmotileng laviusmotileng
LAYOUTRTL LAYOUTRTL
@ -1140,9 +1184,11 @@ Lclean
LCONTROL LCONTROL
LCtrl LCtrl
Ldone Ldone
ldx
LEFTSCROLLBAR LEFTSCROLLBAR
lego lego
len len
LEQ
LError LError
Lessthan Lessthan
LEVELID LEVELID
@ -1166,6 +1212,7 @@ LINQTo
Linux Linux
listbox listbox
listview listview
lld
llkhf llkhf
Llvm Llvm
lmcons lmcons
@ -1246,6 +1293,7 @@ MAINICON
Mainwindow Mainwindow
majortype majortype
makeappx makeappx
makecab
MAKEINTRESOURCE MAKEINTRESOURCE
MAKEINTRESOURCEW MAKEINTRESOURCEW
MAKELPARAM MAKELPARAM
@ -1264,6 +1312,7 @@ MATCHMODE
MAXIMIZEBOX MAXIMIZEBOX
MAXSHORTCUTSIZE MAXSHORTCUTSIZE
maxversiontested maxversiontested
MBs
MBUTTON MBUTTON
MBUTTONDBLCLK MBUTTONDBLCLK
MBUTTONDOWN MBUTTONDOWN
@ -1273,7 +1322,7 @@ MDICHILD
MDL MDL
mdpreviewhandler mdpreviewhandler
MEDIASUBTYPE MEDIASUBTYPE
MEDIATYPE mediatype
Melman Melman
memcpy memcpy
memset memset
@ -1285,8 +1334,17 @@ messageboxes
METACHARSET METACHARSET
metadata metadata
metafile metafile
mfapi
mfc mfc
mfcribbon mfcribbon
mfidl
mfobjects
mfplat
mfreadwrite
Mfsensorgroup
mftransform
mfuuid
mic
microsoft microsoft
Midl Midl
mii mii
@ -1299,10 +1357,12 @@ miniz
minlevel minlevel
MINMAXINFO MINMAXINFO
Miracast Miracast
mirophone
MJPG MJPG
mkdir mkdir
Mlcfg Mlcfg
MLogo MLogo
mmdeviceapi
MMI MMI
Mmsys Mmsys
mobilehotspot mobilehotspot
@ -1369,6 +1429,7 @@ mutex
mutexes mutexes
muxc muxc
mvvm mvvm
myfile
MYICON MYICON
NAMECHANGE NAMECHANGE
nameof nameof
@ -1412,6 +1473,7 @@ netsh
netstandard netstandard
Neue Neue
newcolor newcolor
newdev
newitem newitem
newpath newpath
newrow newrow
@ -1421,6 +1483,7 @@ niels
nielslaute nielslaute
NIF NIF
nightlight nightlight
nitroin
NLD NLD
nlog nlog
NLSTEXT NLSTEXT
@ -1438,6 +1501,7 @@ nodoc
noexcept noexcept
NOFRAMES NOFRAMES
NOINHERITLAYOUT NOINHERITLAYOUT
NOINTERFACE
NOLINKINFO NOLINKINFO
NOMINMAX NOMINMAX
NOMOVE NOMOVE
@ -1521,6 +1585,7 @@ OPTIMIZEFORINVOKE
optin optin
optionalfeatures optionalfeatures
OPTIONSGROUP OPTIONSGROUP
ORAW
ORPHANEDDIALOGTITLE ORPHANEDDIALOGTITLE
oss oss
ostr ostr
@ -1532,6 +1597,7 @@ otheroptions
otherusers otherusers
OUTOFCONTEXT OUTOFCONTEXT
OUTOFMEMORY OUTOFMEMORY
outpin
Outptr Outptr
outputtype outputtype
outro outro
@ -1553,6 +1619,7 @@ PARENTRELATIVEPARSING
parray parray
PARTIALCONFIRMATIONDIALOGTITLE PARTIALCONFIRMATIONDIALOGTITLE
pathcch pathcch
PAUDIO
pbc pbc
Pbgra Pbgra
pcb pcb
@ -1593,6 +1660,7 @@ Pipelinhttps
pipename pipename
pitem pitem
PKBDLLHOOKSTRUCT PKBDLLHOOKSTRUCT
PKEY
placeholders placeholders
plib plib
PLK PLK
@ -1611,6 +1679,7 @@ popd
popup popup
POPUPWINDOW POPUPWINDOW
posix posix
Postion
powerappscds powerappscds
powercfg powercfg
powerlauncher powerlauncher
@ -1626,6 +1695,7 @@ powertoyswiki
Powrprof Powrprof
ppenum ppenum
ppidl ppidl
ppmt
pprm pprm
pproc pproc
ppsi ppsi
@ -1643,11 +1713,13 @@ Prefixer
Preinstalled Preinstalled
preload preload
PREMULTIPLIED PREMULTIPLIED
preperty
prevhost prevhost
previewer previewer
PREVIEWGROUP PREVIEWGROUP
PREVIEWHANDLERFRAMEINFO PREVIEWHANDLERFRAMEINFO
previewpane previewpane
previouscamera
PREVIOUSVERSIONSINSTALLED PREVIOUSVERSIONSINSTALLED
prevpane prevpane
prgms prgms
@ -1664,6 +1736,7 @@ PROGRAMFILES
progressbar progressbar
Proj Proj
projectname projectname
PROPBAG
propkey propkey
propvarutil propvarutil
prpui prpui
@ -1676,6 +1749,7 @@ psfgao
Psr Psr
psrm psrm
psrree psrree
pstr
pstream pstream
pstrm pstrm
psz psz
@ -1693,6 +1767,7 @@ PVOID
pwa pwa
pwcs pwcs
PWSTR PWSTR
pwsz
pwtd pwtd
qianlifeng qianlifeng
qit qit
@ -1738,20 +1813,27 @@ rectp
rects rects
recyclebin recyclebin
redirectedfrom redirectedfrom
reencode
reencoded
refactor refactor
refactoring refactoring
REFCLSID REFCLSID
refcount refcount
REFGUID
REFIID REFIID
REGCLS REGCLS
regedit regedit
regex regex
REGFILTER
REGFILTERPINS
regionformatting regionformatting
regionlanguage regionlanguage
REGISTERCLASSFAILED REGISTERCLASSFAILED
Registery Registery
registrypath registrypath
regkey regkey
REGPINTYPES
regsvr
reimplementing reimplementing
reloadable reloadable
Remapper Remapper
@ -1803,13 +1885,14 @@ RKey
RMENU RMENU
RNumber RNumber
roadmap roadmap
robocopy
Roboto Roboto
roslyn roslyn
royvou royvou
Rpc Rpc
RRF RRF
rshift
RSHIFT RSHIFT
rshift
Rsp Rsp
rst rst
Rstrtmgr Rstrtmgr
@ -1859,6 +1942,7 @@ SEARCHFOR
SEARCHREPLACEGROUP SEARCHREPLACEGROUP
searchterm searchterm
Secur Secur
seekg
Segoe Segoe
Sekan Sekan
SENDCHANGE SENDCHANGE
@ -1904,8 +1988,8 @@ Shl
shldisp shldisp
shlobj shlobj
shlwapi shlwapi
shmem
shobjidl shobjidl
shortsplit
SHORTCUTATLEAST SHORTCUTATLEAST
shortcutcontrol shortcutcontrol
Shortcutguide Shortcutguide
@ -1917,6 +2001,7 @@ SHORTCUTSTARTWITHMODIFIER
Shortcuttool Shortcuttool
shortdate shortdate
SHORTPATH SHORTPATH
shortsplit
showcolorname showcolorname
SHOWDEFAULT SHOWDEFAULT
SHOWELEVATIONPROMPT SHOWELEVATIONPROMPT
@ -1945,6 +2030,7 @@ SIZENESW
SIZENS SIZENS
SIZENWSE SIZENWSE
sizeof sizeof
sizeread
SIZEWE SIZEWE
sketchapp sketchapp
SKIPOWNPROCESS SKIPOWNPROCESS
@ -1974,6 +2060,7 @@ spesi
splitwstring splitwstring
sppd sppd
sppre sppre
sprintf
spsi spsi
spsia spsia
spsrif spsrif
@ -2031,6 +2118,7 @@ storagesense
stoul stoul
stoull stoull
strcmp strcmp
streampos
strftime strftime
Stringified Stringified
Stringify Stringify
@ -2057,8 +2145,8 @@ surfacehub
sut sut
SVE SVE
svg svg
SVGIO
SVGIn SVGIn
SVGIO
svgpreviewhandler svgpreviewhandler
SWC SWC
SWFO SWFO
@ -2068,6 +2156,7 @@ swprintf
SWRESTORE SWRESTORE
SYMED SYMED
SYMOPT SYMOPT
SYNCMFT
SYNCPAINT SYNCPAINT
sys sys
SYSCHAR SYSCHAR
@ -2083,9 +2172,9 @@ syslog
SYSMENU SYSMENU
systemd systemd
SYSTEMTIME SYSTEMTIME
Tadele
sz sz
tabletmode tabletmode
Tadele
tadele tadele
Tahoma Tahoma
talenthrcore talenthrcore
@ -2111,6 +2200,7 @@ tchar
tcscpy tcscpy
TCustom TCustom
TDevice TDevice
tellg
Templated Templated
templatenamespace templatenamespace
Temporarilypeekatthedesktop Temporarilypeekatthedesktop
@ -2132,8 +2222,8 @@ THISCOMPONENT
thre thre
tif tif
TILEDWINDOW TILEDWINDOW
timediff
timedate timedate
timediff
Timeline Timeline
TIMERID TIMERID
timeunion timeunion
@ -2143,6 +2233,7 @@ TLayout
tlb tlb
tlbimp tlbimp
tmp tmp
TMPVAR
TNP TNP
todo todo
toggleswitch toggleswitch
@ -2161,12 +2252,15 @@ towlower
towupper towupper
tracelogging tracelogging
traies traies
transcoded
transparrent
TRAYMOUSEMESSAGE TRAYMOUSEMESSAGE
TRK TRK
trl trl
trueplay trueplay
truetype truetype
trunc trunc
tspan
TStr TStr
tsx tsx
TYMED TYMED
@ -2192,8 +2286,10 @@ UIPI
UIs UIs
UITo UITo
ULARGE ULARGE
ulazy
ULLONG ULLONG
ulong ulong
ULONGLONG
umd umd
unchecks unchecks
uncomment uncomment
@ -2222,6 +2318,7 @@ unknwn
UNLEN UNLEN
unlicense unlicense
Unmap Unmap
unmute
UNORM UNORM
unregister unregister
unregistering unregistering
@ -2256,16 +2353,20 @@ uuidof
uwp uwp
UWPUI UWPUI
uxtheme uxtheme
UYVY
validmodulename validmodulename
vcamp vcamp
vccorlib vccorlib
vcdl
VCINSTALLDIR VCINSTALLDIR
vcm
vcomp vcomp
vcredist vcredist
VCRT VCRT
vcruntime vcruntime
vcvars vcvars
vcxproj vcxproj
vdi
VDId VDId
vec vec
VERBSONLY VERBSONLY
@ -2275,10 +2376,14 @@ VERSIONINFO
Versioning Versioning
VFT VFT
vid vid
VIDCAP
videoconference
videoconferencevirtualdriver
VIDEOINFOHEADER VIDEOINFOHEADER
videoplayback videoplayback
viewbox viewbox
viewmodel viewmodel
vih
virtualization virtualization
visiblecolorformats visiblecolorformats
Visibletrue Visibletrue
@ -2298,6 +2403,7 @@ VSCBD
vscode vscode
VSCROLL VSCROLL
vse vse
vsix
vsonline vsonline
vstemplate vstemplate
VSTHRD VSTHRD
@ -2320,6 +2426,9 @@ wcscpy
wcslen wcslen
wcsncmp wcsncmp
wcsnicmp wcsnicmp
WDK
wdksetup
wdkvsix
wdp wdp
wdupenv wdupenv
We'd We'd
@ -2346,6 +2455,8 @@ wikipedia
wil wil
wildcards wildcards
winapi winapi
wincodec
Wincodecsdk
wincolor wincolor
windef windef
windevbuildagents windevbuildagents
@ -2401,6 +2512,7 @@ WMKEYUP
wmp wmp
WMSYSKEYDOWN WMSYSKEYDOWN
WMSYSKEYUP WMSYSKEYUP
WMV
wnd wnd
WNDCLASS WNDCLASS
WNDCLASSEX WNDCLASSEX
@ -2431,9 +2543,11 @@ wstringstream
wsz wsz
wtoi wtoi
WTS WTS
wtsapi
WTSAT WTSAT
wu wu
wubi wubi
WVC
Wwan Wwan
www www
wxs wxs
@ -2448,6 +2562,7 @@ XBUTTON
XBUTTONDBLCLK XBUTTONDBLCLK
XBUTTONDOWN XBUTTONDOWN
XBUTTONUP XBUTTONUP
xcopy
XDiff XDiff
XDocument XDocument
XElement XElement
@ -2479,7 +2594,10 @@ yourinfo
YourUserName YourUserName
YStr YStr
YUY YUY
yuyoyuppe
YUYV YUYV
YVU
YVYU
ZEROINIT ZEROINIT
ZIndex ZIndex
zipfolder zipfolder
@ -2491,9 +2609,3 @@ ZONESETCHANGE
Zoneszonabletester Zoneszonabletester
Zoomusingmagnifier Zoomusingmagnifier
zzz zzz
coc
djsoref
dogancelik
itsme
nitroin
ulazy

View File

@ -7,3 +7,5 @@ set SolutionDir=%cd%
popd popd
SET IsPipeline=1 SET IsPipeline=1
call msbuild ../tools/BugReportTool/BugReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1 call msbuild ../tools/BugReportTool/BugReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1
call msbuild ../tools/WebcamReportTool/WebcamReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1

View File

@ -61,6 +61,11 @@ build:
- 'x64/**/*.pdb' - 'x64/**/*.pdb'
exclude: exclude:
- 'x64/Release/obj/**/*.pdb' - 'x64/Release/obj/**/*.pdb'
# TODO(yuyoyuppe): uncomment when VCM should be enabled
#- from: 'x86/Release'
# to: 'Build_Output'
# include:
# - 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
- from: 'x64/Release' - from: 'x64/Release'
to: 'Build_Output' to: 'Build_Output'
include: include:
@ -159,6 +164,9 @@ build:
- 'modules\PowerRename\PowerRenameExt.dll' - 'modules\PowerRename\PowerRenameExt.dll'
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe' - 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll' - 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
# TODO(yuyoyuppe): uncomment when VCM should be enabled
#- 'modules\VideoConference\VideoConferenceModule.dll'
#- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
- 'Settings\ManagedTelemetry.dll' - 'Settings\ManagedTelemetry.dll'
- 'Settings\Microsoft.PowerToys.Settings.UI.exe' - 'Settings\Microsoft.PowerToys.Settings.UI.exe'
- 'Settings\Microsoft.PowerToys.Settings.UI.Lib.dll' - 'Settings\Microsoft.PowerToys.Settings.UI.Lib.dll'
@ -177,6 +185,7 @@ build:
to: 'Build_Output' to: 'Build_Output'
include: include:
- 'BugReportTool\BugReportTool.exe' - 'BugReportTool\BugReportTool.exe'
- 'WebcamReportTool\WebcamReportTool.exe'
signing_options: signing_options:
sign_inline: true # This does signing a soon as this command completes sign_inline: true # This does signing a soon as this command completes
- !!buildcommand - !!buildcommand
@ -237,4 +246,3 @@ static_analysis_options:
files_to_scan: files_to_scan:
- exclude: - exclude:
- '**/*.lcl' - '**/*.lcl'

View File

@ -1,3 +1,4 @@
cd /D "%~dp0" cd /D "%~dp0"
nuget restore ../tools/BugReportTool/BugReportTool.sln || exit /b 1 nuget restore ../tools/BugReportTool/BugReportTool.sln || exit /b 1
nuget restore ../tools/WebcamReportTool/WebcamReportTool.sln || exit /b 1

View File

@ -1,3 +1,12 @@
cd /D "%~dp0" cd /D "%~dp0"
nuget restore ../PowerToys.sln || exit /b 1 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

View File

@ -75,7 +75,7 @@
<!-- Props that are constant for both Debug and Release configurations --> <!-- Props that are constant for both Debug and Release configurations -->
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<PlatformToolset>v142</PlatformToolset> <PlatformToolset Condition="'$(OverridePlatformToolset)'!='True'">v142</PlatformToolset>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir> <IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>Spectre</SpectreMitigation> <SpectreMitigation>Spectre</SpectreMitigation>

View File

@ -333,7 +333,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plu
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter.UnitTest", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest.csproj", "{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter.UnitTest", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest.csproj", "{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}"
EndProject EndProject
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shortcutguide", "shortcutguide", "{106CBECA-0701-4FC3-838C-9DF816A19AE2}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shortcutguide", "shortcutguide", "{106CBECA-0701-4FC3-838C-9DF816A19AE2}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}"
@ -342,376 +341,597 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\module
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesModuleInterface", "src\modules\fancyzones\FancyZonesModuleInterface\FancyZonesModuleInterface.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesModuleInterface", "src\modules\fancyzones\FancyZonesModuleInterface\FancyZonesModuleInterface.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{390AE700-B55F-4202-91EA-A822EB75B9BD}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Update", "src\Update\PowerToys.Update.vcxproj", "{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Update", "src\Update\PowerToys.Update.vcxproj", "{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsSettings", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsSettings", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}"
EndProject 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}") = "VideoConferenceModule", "src\modules\videoconference\VideoConferenceModule\Video Conference.vcxproj", "{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter", "src\modules\videoconference\VideoConferenceProxyFilter\VideoConferenceProxyFilter.vcxproj", "{AC2857B4-103D-4D6D-9740-926EBF785042}"
ProjectSection(ProjectDependencies) = postProject
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64 Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.ActiveCfg = Debug|x64 {9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.ActiveCfg = Debug|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64 {9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x86.ActiveCfg = Debug|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64 {9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64 {9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x86.ActiveCfg = Release|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64 {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64 {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x86.ActiveCfg = Debug|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64 {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.Build.0 = Release|x64 {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.Build.0 = Release|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x86.ActiveCfg = Release|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.ActiveCfg = Debug|x64 {9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.ActiveCfg = Debug|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.Build.0 = Debug|x64 {9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.Build.0 = Debug|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x86.ActiveCfg = Debug|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.ActiveCfg = Release|x64 {9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.ActiveCfg = Release|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.Build.0 = Release|x64 {9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.Build.0 = Release|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x86.ActiveCfg = Release|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.ActiveCfg = Debug|x64 {1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.ActiveCfg = Debug|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.Build.0 = Debug|x64 {1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.Build.0 = Debug|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x86.ActiveCfg = Debug|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64 {1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.Build.0 = Release|x64 {1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.Build.0 = Release|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x86.ActiveCfg = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64 {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64 {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x86.ActiveCfg = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64 {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64 {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x86.ActiveCfg = Release|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.ActiveCfg = Debug|x64 {B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.ActiveCfg = Debug|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.Build.0 = Debug|x64 {B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.Build.0 = Debug|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x86.ActiveCfg = Debug|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.ActiveCfg = Release|x64 {B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.ActiveCfg = Release|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.Build.0 = Release|x64 {B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.Build.0 = Release|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x86.ActiveCfg = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.ActiveCfg = Debug|x64 {51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.ActiveCfg = Debug|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.Build.0 = Debug|x64 {51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.Build.0 = Debug|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x86.ActiveCfg = Debug|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64 {51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64 {51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x86.ActiveCfg = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64 {0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64 {0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x86.ActiveCfg = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64 {0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64 {0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x86.ActiveCfg = Release|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64 {A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64 {A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x86.ActiveCfg = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.ActiveCfg = Release|x64 {A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.ActiveCfg = Release|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.Build.0 = Release|x64 {A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.Build.0 = Release|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x86.ActiveCfg = Release|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.ActiveCfg = Debug|x64 {2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.ActiveCfg = Debug|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.Build.0 = Debug|x64 {2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.Build.0 = Debug|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x86.ActiveCfg = Debug|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.ActiveCfg = Release|x64 {2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.ActiveCfg = Release|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.Build.0 = Release|x64 {2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.Build.0 = Release|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x86.ActiveCfg = Release|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.ActiveCfg = Debug|x64 {64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.ActiveCfg = Debug|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.Build.0 = Debug|x64 {64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.Build.0 = Debug|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x86.ActiveCfg = Debug|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64 {64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64 {64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x86.ActiveCfg = Release|x64
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.ActiveCfg = Debug|x64 {0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.ActiveCfg = Debug|x64
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.Build.0 = Debug|x64
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x86.ActiveCfg = Debug|x64
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.ActiveCfg = Release|x64 {0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.ActiveCfg = Release|x64
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.Build.0 = Release|x64
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x86.ActiveCfg = Release|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.ActiveCfg = Debug|x64 {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.ActiveCfg = Debug|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.Build.0 = Debug|x64 {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.Build.0 = Debug|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x86.ActiveCfg = Debug|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.ActiveCfg = Release|x64 {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.ActiveCfg = Release|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.Build.0 = Release|x64 {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.Build.0 = Release|x64
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x86.ActiveCfg = Release|x64
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.ActiveCfg = Debug|x64 {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.ActiveCfg = Debug|x64
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.Build.0 = Debug|x64 {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.Build.0 = Debug|x64
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x86.ActiveCfg = Debug|x64
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.ActiveCfg = Release|x64 {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.ActiveCfg = Release|x64
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.Build.0 = Release|x64 {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.Build.0 = Release|x64
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x86.ActiveCfg = Release|x64
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.ActiveCfg = Debug|x64 {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.ActiveCfg = Debug|x64
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.Build.0 = Debug|x64 {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.Build.0 = Debug|x64
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x86.ActiveCfg = Debug|x64
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.ActiveCfg = Release|x64 {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.ActiveCfg = Release|x64
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.Build.0 = Release|x64 {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.Build.0 = Release|x64
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x86.ActiveCfg = Release|x64
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.ActiveCfg = Debug|x64 {E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.ActiveCfg = Debug|x64
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.Build.0 = Debug|x64 {E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.Build.0 = Debug|x64
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x86.ActiveCfg = Debug|x64
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.ActiveCfg = Release|x64 {E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.ActiveCfg = Release|x64
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.Build.0 = Release|x64 {E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.Build.0 = Release|x64
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x86.ActiveCfg = Release|x64
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.ActiveCfg = Debug|x64 {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.ActiveCfg = Debug|x64
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.Build.0 = Debug|x64 {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.Build.0 = Debug|x64
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x86.ActiveCfg = Debug|x64
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.ActiveCfg = Release|x64 {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.ActiveCfg = Release|x64
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.Build.0 = Release|x64 {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.Build.0 = Release|x64
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x86.ActiveCfg = Release|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.ActiveCfg = Debug|x64 {17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.ActiveCfg = Debug|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.Build.0 = Debug|x64 {17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.Build.0 = Debug|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x86.ActiveCfg = Debug|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.ActiveCfg = Release|x64 {17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.ActiveCfg = Release|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.Build.0 = Release|x64 {17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.Build.0 = Release|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x86.ActiveCfg = Release|x64
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.ActiveCfg = Debug|x64 {8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.ActiveCfg = Debug|x64
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.Build.0 = Debug|x64 {8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.Build.0 = Debug|x64
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x86.ActiveCfg = Debug|x64
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.ActiveCfg = Release|x64 {8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.ActiveCfg = Release|x64
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.Build.0 = Release|x64 {8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.Build.0 = Release|x64
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x86.ActiveCfg = Release|x64
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.ActiveCfg = Debug|x64 {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.ActiveCfg = Debug|x64
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.Build.0 = Debug|x64 {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.Build.0 = Debug|x64
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x86.ActiveCfg = Debug|x64
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.ActiveCfg = Release|x64 {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.ActiveCfg = Release|x64
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.Build.0 = Release|x64 {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.Build.0 = Release|x64
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.ActiveCfg = Release|x64
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.ActiveCfg = Debug|x64 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.ActiveCfg = Debug|x64
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.Build.0 = Debug|x64 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.Build.0 = Debug|x64
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x86.ActiveCfg = Debug|x64
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.ActiveCfg = Release|x64 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.ActiveCfg = Release|x64
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.Build.0 = Release|x64 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.Build.0 = Release|x64
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x86.ActiveCfg = Release|x64
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.ActiveCfg = Debug|x64 {FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.ActiveCfg = Debug|x64
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.Build.0 = Debug|x64 {FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.Build.0 = Debug|x64
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x86.ActiveCfg = Debug|x64
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.ActiveCfg = Release|x64 {FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.ActiveCfg = Release|x64
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.Build.0 = Release|x64 {FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.Build.0 = Release|x64
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x86.ActiveCfg = Release|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.ActiveCfg = Debug|x64 {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.ActiveCfg = Debug|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|x64 {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.ActiveCfg = Debug|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|x64 {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|x64 {59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.ActiveCfg = Release|x64
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.ActiveCfg = Debug|x64 {4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.ActiveCfg = Debug|x64
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.Build.0 = Debug|x64 {4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.Build.0 = Debug|x64
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x86.ActiveCfg = Debug|x64
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.ActiveCfg = Release|x64 {4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.ActiveCfg = Release|x64
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.Build.0 = Release|x64 {4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.Build.0 = Release|x64
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x86.ActiveCfg = Release|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.ActiveCfg = Debug|x64 {74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.ActiveCfg = Debug|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.Build.0 = Debug|x64 {74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.Build.0 = Debug|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x86.ActiveCfg = Debug|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.ActiveCfg = Release|x64 {74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.ActiveCfg = Release|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.Build.0 = Release|x64 {74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.Build.0 = Release|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x86.ActiveCfg = Release|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.ActiveCfg = Debug|x64 {FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.ActiveCfg = Debug|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.Build.0 = Debug|x64 {FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.Build.0 = Debug|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x86.ActiveCfg = Debug|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.ActiveCfg = Release|x64 {FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.ActiveCfg = Release|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.Build.0 = Release|x64 {FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.Build.0 = Release|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x86.ActiveCfg = Release|x64
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.ActiveCfg = Debug|x64 {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.ActiveCfg = Debug|x64
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.Build.0 = Debug|x64 {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.Build.0 = Debug|x64
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x86.ActiveCfg = Debug|x64
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.ActiveCfg = Release|x64 {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.ActiveCfg = Release|x64
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.Build.0 = Release|x64 {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.Build.0 = Release|x64
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x86.ActiveCfg = Release|x64
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.ActiveCfg = Debug|x64 {F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.ActiveCfg = Debug|x64
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.Build.0 = Debug|x64 {F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.Build.0 = Debug|x64
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x86.ActiveCfg = Debug|x64
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.ActiveCfg = Release|x64 {F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.ActiveCfg = Release|x64
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.Build.0 = Release|x64 {F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.Build.0 = Release|x64
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x86.ActiveCfg = Release|x64
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.ActiveCfg = Debug|x64 {E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.ActiveCfg = Debug|x64
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.Build.0 = Debug|x64 {E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.Build.0 = Debug|x64
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x86.ActiveCfg = Debug|x64
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.ActiveCfg = Release|x64 {E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.ActiveCfg = Release|x64
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.Build.0 = Release|x64 {E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.Build.0 = Release|x64
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x86.ActiveCfg = Release|x64
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.ActiveCfg = Debug|x64 {F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.ActiveCfg = Debug|x64
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.Build.0 = Debug|x64 {F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.Build.0 = Debug|x64
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x86.ActiveCfg = Debug|x64
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.ActiveCfg = Release|x64 {F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.ActiveCfg = Release|x64
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.Build.0 = Release|x64 {F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.Build.0 = Release|x64
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x86.ActiveCfg = Release|x64
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.ActiveCfg = Debug|x64 {AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.ActiveCfg = Debug|x64
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.Build.0 = Debug|x64 {AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.Build.0 = Debug|x64
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x86.ActiveCfg = Debug|x64
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.ActiveCfg = Release|x64 {AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.ActiveCfg = Release|x64
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.Build.0 = Release|x64 {AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.Build.0 = Release|x64
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x86.ActiveCfg = Release|x64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.ActiveCfg = Debug|x64 {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.ActiveCfg = Debug|x64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.Build.0 = Debug|x64 {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.Build.0 = Debug|x64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x86.ActiveCfg = Debug|x64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.ActiveCfg = Release|x64 {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.ActiveCfg = Release|x64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.Build.0 = Release|x64 {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.Build.0 = Release|x64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x86.ActiveCfg = Release|x64
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.ActiveCfg = Debug|x64 {A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.ActiveCfg = Debug|x64
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.Build.0 = Debug|x64 {A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.Build.0 = Debug|x64
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x86.ActiveCfg = Debug|x64
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.ActiveCfg = Release|x64 {A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.ActiveCfg = Release|x64
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.Build.0 = Release|x64 {A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.Build.0 = Release|x64
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x86.ActiveCfg = Release|x64
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.ActiveCfg = Debug|x64 {DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.ActiveCfg = Debug|x64
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.Build.0 = Debug|x64 {DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.Build.0 = Debug|x64
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x86.ActiveCfg = Debug|x64
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.ActiveCfg = Release|x64 {DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.ActiveCfg = Release|x64
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.Build.0 = Release|x64 {DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.Build.0 = Release|x64
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x86.ActiveCfg = Release|x64
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.ActiveCfg = Debug|x64 {060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.ActiveCfg = Debug|x64
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.Build.0 = Debug|x64 {060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.Build.0 = Debug|x64
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x86.ActiveCfg = Debug|x64
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.ActiveCfg = Release|x64 {060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.ActiveCfg = Release|x64
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.Build.0 = Release|x64 {060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.Build.0 = Release|x64
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x86.ActiveCfg = Release|x64
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.ActiveCfg = Debug|x64 {748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.ActiveCfg = Debug|x64
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.Build.0 = Debug|x64 {748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.Build.0 = Debug|x64
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x86.ActiveCfg = Debug|x64
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.ActiveCfg = Release|x64 {748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.ActiveCfg = Release|x64
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.Build.0 = Release|x64 {748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.Build.0 = Release|x64
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x86.ActiveCfg = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.ActiveCfg = Debug|x64 {217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.ActiveCfg = Debug|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.Build.0 = Debug|x64 {217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.Build.0 = Debug|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x86.ActiveCfg = Debug|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64 {217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64 {217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x86.ActiveCfg = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64 {47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64 {47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x86.ActiveCfg = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64 {47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64 {47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x86.ActiveCfg = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64 {A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64 {A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Build.0 = Debug|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Deploy.0 = Debug|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.ActiveCfg = Release|x64 {A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.ActiveCfg = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.Build.0 = Release|x64 {A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.Build.0 = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.ActiveCfg = Release|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.Build.0 = Release|Win32
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.Deploy.0 = Release|Win32
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.ActiveCfg = Debug|x64 {B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.ActiveCfg = Debug|x64
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.Build.0 = Debug|x64 {B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.Build.0 = Debug|x64
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x86.ActiveCfg = Debug|x64
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.ActiveCfg = Release|x64 {B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.ActiveCfg = Release|x64
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.Build.0 = Release|x64 {B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.Build.0 = Release|x64
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x86.ActiveCfg = Release|x64
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.Build.0 = Debug|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.Build.0 = Debug|x64
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x86.ActiveCfg = Debug|x64
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.ActiveCfg = Release|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.ActiveCfg = Release|x64
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.ActiveCfg = Release|x64
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.ActiveCfg = Debug|x64 {787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.ActiveCfg = Debug|x64
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.Build.0 = Debug|x64 {787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.Build.0 = Debug|x64
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x86.ActiveCfg = Debug|x64
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.ActiveCfg = Release|x64 {787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.ActiveCfg = Release|x64
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.Build.0 = Release|x64 {787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.Build.0 = Release|x64
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x86.ActiveCfg = Release|x64
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.ActiveCfg = Debug|x64 {08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.ActiveCfg = Debug|x64
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.Build.0 = Debug|x64 {08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.Build.0 = Debug|x64
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x86.ActiveCfg = Debug|x64
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.ActiveCfg = Release|x64 {08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.ActiveCfg = Release|x64
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.Build.0 = Release|x64 {08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.Build.0 = Release|x64
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x86.ActiveCfg = Release|x64
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.ActiveCfg = Debug|x64 {5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.ActiveCfg = Debug|x64
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.Build.0 = Debug|x64 {5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.Build.0 = Debug|x64
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x86.ActiveCfg = Debug|x64
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.ActiveCfg = Release|x64 {5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.ActiveCfg = Release|x64
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.Build.0 = Release|x64 {5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.Build.0 = Release|x64
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x86.ActiveCfg = Release|x64
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.ActiveCfg = Debug|x64 {4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.ActiveCfg = Debug|x64
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.Build.0 = Debug|x64 {4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.Build.0 = Debug|x64
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x86.ActiveCfg = Debug|x64
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.ActiveCfg = Release|x64 {4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.ActiveCfg = Release|x64
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.Build.0 = Release|x64 {4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.Build.0 = Release|x64
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x86.ActiveCfg = Release|x64
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.ActiveCfg = Debug|x64 {42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.ActiveCfg = Debug|x64
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.Build.0 = Debug|x64 {42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.Build.0 = Debug|x64
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x86.ActiveCfg = Debug|x64
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.ActiveCfg = Release|x64 {42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.ActiveCfg = Release|x64
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.Build.0 = Release|x64 {42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.Build.0 = Release|x64
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x86.ActiveCfg = Release|x64
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.ActiveCfg = Debug|x64 {1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.ActiveCfg = Debug|x64
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.Build.0 = Debug|x64 {1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.Build.0 = Debug|x64
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x86.ActiveCfg = Debug|x64
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.ActiveCfg = Release|x64 {1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.ActiveCfg = Release|x64
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.Build.0 = Release|x64 {1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.Build.0 = Release|x64
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x86.ActiveCfg = Release|x64
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.ActiveCfg = Debug|x64 {8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.ActiveCfg = Debug|x64
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.Build.0 = Debug|x64 {8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.Build.0 = Debug|x64
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x86.ActiveCfg = Debug|x64
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.ActiveCfg = Release|x64 {8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.ActiveCfg = Release|x64
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.Build.0 = Release|x64 {8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.Build.0 = Release|x64
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x86.ActiveCfg = Release|x64
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.ActiveCfg = Debug|x64 {655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.ActiveCfg = Debug|x64
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.Build.0 = Debug|x64 {655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.Build.0 = Debug|x64
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x86.ActiveCfg = Debug|x64
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.ActiveCfg = Release|x64 {655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.ActiveCfg = Release|x64
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.Build.0 = Release|x64 {655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.Build.0 = Release|x64
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x86.ActiveCfg = Release|x64
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.ActiveCfg = Debug|x64 {BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.ActiveCfg = Debug|x64
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64 {BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x86.ActiveCfg = Debug|x64
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64 {BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64 {BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x86.ActiveCfg = Release|x64
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.ActiveCfg = Debug|x64 {03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.ActiveCfg = Debug|x64
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.Build.0 = Debug|x64 {03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.Build.0 = Debug|x64
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x86.ActiveCfg = Debug|x64
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.ActiveCfg = Release|x64 {03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.ActiveCfg = Release|x64
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.Build.0 = Release|x64 {03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.Build.0 = Release|x64
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x86.ActiveCfg = Release|x64
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.ActiveCfg = Debug|x64 {B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.ActiveCfg = Debug|x64
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.Build.0 = Debug|x64 {B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.Build.0 = Debug|x64
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x86.ActiveCfg = Debug|x64
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.ActiveCfg = Release|x64 {B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.ActiveCfg = Release|x64
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.Build.0 = Release|x64 {B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.Build.0 = Release|x64
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x86.ActiveCfg = Release|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.ActiveCfg = Debug|x64 {0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.ActiveCfg = Debug|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.Build.0 = Debug|x64 {0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.Build.0 = Debug|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x86.ActiveCfg = Debug|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.ActiveCfg = Release|x64 {0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.ActiveCfg = Release|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.Build.0 = Release|x64 {0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.Build.0 = Release|x64
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x86.ActiveCfg = Release|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.ActiveCfg = Debug|x64 {632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.ActiveCfg = Debug|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.Build.0 = Debug|x64 {632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.Build.0 = Debug|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x86.ActiveCfg = Debug|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.ActiveCfg = Release|x64 {632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.ActiveCfg = Release|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.Build.0 = Release|x64 {632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.Build.0 = Release|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x86.ActiveCfg = Release|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.ActiveCfg = Debug|x64 {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.ActiveCfg = Debug|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.Build.0 = Debug|x64 {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.Build.0 = Debug|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x86.ActiveCfg = Debug|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.ActiveCfg = Release|x64 {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.ActiveCfg = Release|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.Build.0 = Release|x64 {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.Build.0 = Release|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x86.ActiveCfg = Release|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.ActiveCfg = Debug|x64 {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.ActiveCfg = Debug|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.Build.0 = Debug|x64 {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.Build.0 = Debug|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x86.ActiveCfg = Debug|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.ActiveCfg = Release|x64 {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.ActiveCfg = Release|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.Build.0 = Release|x64 {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.Build.0 = Release|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x86.ActiveCfg = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x86.ActiveCfg = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x86.ActiveCfg = Release|x64
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.ActiveCfg = Debug|x64 {FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.ActiveCfg = Debug|x64
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.Build.0 = Debug|x64 {FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.Build.0 = Debug|x64
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x86.ActiveCfg = Debug|x64
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.ActiveCfg = Release|x64 {FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.ActiveCfg = Release|x64
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.Build.0 = Release|x64 {FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.Build.0 = Release|x64
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x86.ActiveCfg = Release|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.ActiveCfg = Debug|x64 {DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.ActiveCfg = Debug|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.Build.0 = Debug|x64 {DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.Build.0 = Debug|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x86.ActiveCfg = Debug|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.ActiveCfg = Release|x64 {DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.ActiveCfg = Release|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.Build.0 = Release|x64 {DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.Build.0 = Release|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x86.ActiveCfg = Release|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.ActiveCfg = Debug|x64 {0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.ActiveCfg = Debug|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.Build.0 = Debug|x64 {0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.Build.0 = Debug|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x86.ActiveCfg = Debug|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.ActiveCfg = Release|x64 {0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.ActiveCfg = Release|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.Build.0 = Release|x64 {0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.Build.0 = Release|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x86.ActiveCfg = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64 {D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64 {D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x86.ActiveCfg = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64 {D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64 {D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x86.ActiveCfg = Release|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.ActiveCfg = Debug|x64 {6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.ActiveCfg = Debug|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.Build.0 = Debug|x64 {6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.Build.0 = Debug|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x86.ActiveCfg = Debug|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.ActiveCfg = Release|x64 {6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.ActiveCfg = Release|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.Build.0 = Release|x64 {6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.Build.0 = Release|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x86.ActiveCfg = Release|x64
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.ActiveCfg = Debug|x64 {58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.ActiveCfg = Debug|x64
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.Build.0 = Debug|x64 {58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.Build.0 = Debug|x64
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x86.ActiveCfg = Debug|x64
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.ActiveCfg = Release|x64 {58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.ActiveCfg = Release|x64
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.Build.0 = Release|x64 {58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.Build.0 = Release|x64
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x86.ActiveCfg = Release|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.ActiveCfg = Debug|x64 {1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.ActiveCfg = Debug|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.Build.0 = Debug|x64 {1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.Build.0 = Debug|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x86.ActiveCfg = Debug|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.ActiveCfg = Release|x64 {1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.ActiveCfg = Release|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.Build.0 = Release|x64 {1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.Build.0 = Release|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x86.ActiveCfg = Release|x64
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.ActiveCfg = Debug|x64 {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.ActiveCfg = Debug|x64
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.Build.0 = Debug|x64 {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.Build.0 = Debug|x64
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x86.ActiveCfg = Debug|x64
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.ActiveCfg = Release|x64 {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.ActiveCfg = Release|x64
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.Build.0 = Release|x64 {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.Build.0 = Release|x64
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x86.ActiveCfg = Release|x64
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.ActiveCfg = Debug|x64 {0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.ActiveCfg = Debug|x64
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.Build.0 = Debug|x64 {0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.Build.0 = Debug|x64
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x86.ActiveCfg = Debug|x64
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.ActiveCfg = Release|x64 {0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.ActiveCfg = Release|x64
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.Build.0 = Release|x64 {0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.Build.0 = Release|x64
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x86.ActiveCfg = Release|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.ActiveCfg = Debug|x64 {CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.ActiveCfg = Debug|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.Build.0 = Debug|x64 {CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.Build.0 = Debug|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x86.ActiveCfg = Debug|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.ActiveCfg = Release|x64 {CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.ActiveCfg = Release|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.Build.0 = Release|x64 {CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.Build.0 = Release|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x86.ActiveCfg = Release|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.ActiveCfg = Debug|x64 {7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.ActiveCfg = Debug|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.Build.0 = Debug|x64 {7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.Build.0 = Debug|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x86.ActiveCfg = Debug|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.ActiveCfg = Release|x64 {7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.ActiveCfg = Release|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.Build.0 = Release|x64 {7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.Build.0 = Release|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x86.ActiveCfg = Release|x64
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.ActiveCfg = Debug|x64 {CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.ActiveCfg = Debug|x64
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.Build.0 = Debug|x64 {CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.Build.0 = Debug|x64
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x86.ActiveCfg = Debug|x64
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.ActiveCfg = Release|x64 {CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.ActiveCfg = Release|x64
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.Build.0 = Release|x64 {CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.Build.0 = Release|x64
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x86.ActiveCfg = Release|x64
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.ActiveCfg = Debug|x64 {98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.ActiveCfg = Debug|x64
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.Build.0 = Debug|x64 {98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.Build.0 = Debug|x64
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x86.ActiveCfg = Debug|x64
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.ActiveCfg = Release|x64 {98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.ActiveCfg = Release|x64
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.Build.0 = Release|x64 {98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.Build.0 = Release|x64
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x86.ActiveCfg = Release|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.ActiveCfg = Debug|x64 {C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.ActiveCfg = Debug|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.Build.0 = Debug|x64 {C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.Build.0 = Debug|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x86.ActiveCfg = Debug|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.ActiveCfg = Release|x64 {C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.ActiveCfg = Release|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.Build.0 = Release|x64 {C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.Build.0 = Release|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x86.ActiveCfg = Release|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.ActiveCfg = Debug|x64 {4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.ActiveCfg = Debug|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.Build.0 = Debug|x64 {4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.Build.0 = Debug|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x86.ActiveCfg = Debug|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.ActiveCfg = Release|x64 {4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.ActiveCfg = Release|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.Build.0 = Release|x64 {4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.Build.0 = Release|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x86.ActiveCfg = Release|x64
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.ActiveCfg = Debug|x64 {0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.ActiveCfg = Debug|x64
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.Build.0 = Debug|x64 {0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.Build.0 = Debug|x64
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x86.ActiveCfg = Debug|x64
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.ActiveCfg = Release|x64 {0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.ActiveCfg = Release|x64
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.Build.0 = Release|x64 {0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.Build.0 = Release|x64
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x86.ActiveCfg = Release|x64
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.ActiveCfg = Debug|x64 {6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.ActiveCfg = Debug|x64
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.Build.0 = Debug|x64 {6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.Build.0 = Debug|x64
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x86.ActiveCfg = Debug|x64
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.ActiveCfg = Release|x64 {6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.ActiveCfg = Release|x64
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.Build.0 = Release|x64 {6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.Build.0 = Release|x64
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x86.ActiveCfg = Release|x64
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.ActiveCfg = Debug|x64 {BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.ActiveCfg = Debug|x64
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.Build.0 = Debug|x64 {BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.Build.0 = Debug|x64
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x86.ActiveCfg = Debug|x64
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.ActiveCfg = Release|x64 {BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.ActiveCfg = Release|x64
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.Build.0 = Release|x64 {BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.Build.0 = Release|x64
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x86.ActiveCfg = Release|x64
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.ActiveCfg = Debug|x64 {E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.ActiveCfg = Debug|x64
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.Build.0 = Debug|x64 {E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.Build.0 = Debug|x64
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x86.ActiveCfg = Debug|x64
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.ActiveCfg = Release|x64 {E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.ActiveCfg = Release|x64
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.Build.0 = Release|x64 {E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.Build.0 = Release|x64
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x86.ActiveCfg = Release|x64
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.ActiveCfg = Debug|x64 {7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.ActiveCfg = Debug|x64
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.Build.0 = Debug|x64 {7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.Build.0 = Debug|x64
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x86.ActiveCfg = Debug|x64
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.ActiveCfg = Release|x64 {7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.ActiveCfg = Release|x64
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.Build.0 = Release|x64 {7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.Build.0 = Release|x64
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x86.ActiveCfg = Release|x64
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.ActiveCfg = Debug|x64 {8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.ActiveCfg = Debug|x64
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.Build.0 = Debug|x64 {8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.Build.0 = Debug|x64
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x86.ActiveCfg = Debug|x64
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.ActiveCfg = Release|x64 {8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.ActiveCfg = Release|x64
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.Build.0 = Release|x64 {8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.Build.0 = Release|x64
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x86.ActiveCfg = Release|x64
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.ActiveCfg = Debug|x64 {23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.ActiveCfg = Debug|x64
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.Build.0 = Debug|x64 {23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.Build.0 = Debug|x64
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x86.ActiveCfg = Debug|x64
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.ActiveCfg = Release|x64 {23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.ActiveCfg = Release|x64
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.Build.0 = Release|x64 {23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.Build.0 = Release|x64
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x86.ActiveCfg = Release|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.ActiveCfg = Debug|x64 {62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.ActiveCfg = Debug|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64 {62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x86.ActiveCfg = Debug|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64 {62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64 {62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64 {62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x86.ActiveCfg = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64 {5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64 {5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x86.ActiveCfg = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64 {5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64 {5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64 {5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x86.ActiveCfg = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64 {D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64 {D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x86.ActiveCfg = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64 {D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64 {D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x86.ActiveCfg = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x86.ActiveCfg = Debug|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x86.ActiveCfg = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x86.ActiveCfg = Debug|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x86.ActiveCfg = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64 {2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64 {2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x86.ActiveCfg = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64 {2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.Build.0 = Release|x64 {2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.Build.0 = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x86.ActiveCfg = Release|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.ActiveCfg = Debug|x64 {2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.ActiveCfg = Debug|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64 {2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x86.ActiveCfg = Debug|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64 {2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64 {2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x86.ActiveCfg = Release|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.ActiveCfg = Debug|x64 {48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.ActiveCfg = Debug|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.Build.0 = Debug|x64 {48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.Build.0 = Debug|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x86.ActiveCfg = Debug|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.ActiveCfg = Release|x64 {48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.ActiveCfg = Release|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.Build.0 = Release|x64 {48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.Build.0 = Release|x64
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Debug|x64.ActiveCfg = Debug|x64 {48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x86.ActiveCfg = Release|x64
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Debug|x64.Build.0 = Debug|x64 {FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x64.ActiveCfg = Debug|x64
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Release|x64.ActiveCfg = Release|x64 {FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x64.Build.0 = Debug|x64
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Release|x64.Build.0 = Release|x64 {FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x86.ActiveCfg = Debug|x64
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x64.ActiveCfg = Release|x64
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x64.Build.0 = Release|x64
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x86.ActiveCfg = Release|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.ActiveCfg = Debug|x64 {44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.ActiveCfg = Debug|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.Build.0 = Debug|x64 {44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.Build.0 = Debug|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x86.ActiveCfg = Debug|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.ActiveCfg = Release|x64 {44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.ActiveCfg = Release|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.Build.0 = Release|x64 {44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.Build.0 = Release|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x86.ActiveCfg = Release|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.ActiveCfg = Debug|x64 {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.ActiveCfg = Debug|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.Build.0 = Debug|x64 {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.Build.0 = Debug|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x86.ActiveCfg = Debug|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|x64 {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|x64 {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.ActiveCfg = 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}.Debug|x86.ActiveCfg = Debug|Win32
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.Build.0 = Debug|Win32
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.ActiveCfg = Release|Win32
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.Build.0 = Release|Win32
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.ActiveCfg = Debug|x64
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.Build.0 = Debug|x64
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x86.ActiveCfg = Debug|x64
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.ActiveCfg = Release|x64
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.Build.0 = Release|x64
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x86.ActiveCfg = Release|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.ActiveCfg = Debug|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.Build.0 = Debug|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.ActiveCfg = Debug|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.Build.0 = Debug|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.ActiveCfg = Release|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.ActiveCfg = Release|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -809,16 +1029,20 @@ Global
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65} {23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65} {62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882} {5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882} {D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2} {2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
{2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2} {2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
{48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} {48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{390AE700-B55F-4202-91EA-A822EB75B9BD} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} {FF1D7936-842A-4BBB-8BEA-E9FE796DE700} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93} {5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
{AC2857B4-103D-4D6D-9740-926EBF785042} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@ -66,7 +66,12 @@ Various tools used by PowerToys. Includes the Visual Studio 2019 project templat
2. Visual Studio Community/Professional/Enterprise 2019 2. Visual Studio Community/Professional/Enterprise 2019
3. Once you've cloned and started the `PowerToys.sln`, in the solution explorer, if you see a dialog that says `install extra components`, click `install` 3. Once you've cloned and started the `PowerToys.sln`, in the solution explorer, if you see a dialog that says `install extra components`, click `install`
### Compile source code **Optional step:**<br/>
4. to build the Video Conference module, install the [WDK version 1903](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads) ([direct download link](https://go.microsoft.com/fwlink/?linkid=2085767))<br />
During the installation, make sure that, when prompted, the `Install Windows Driver Kit Visual Studio extension` option is checked.
### Compiling Source Code
- Open `PowerToys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`. - Open `PowerToys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
- The PowerToys binaries will be in your repo under `x64\Release\`. - The PowerToys binaries will be in your repo under `x64\Release\`.

View File

@ -3,7 +3,7 @@
<Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" /> <Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" />
<Import Project="..\..\src\Version.props" /> <Import Project="..\..\src\Version.props" />
<PropertyGroup> <PropertyGroup>
<DefineConstants>Version=$(Version);</DefineConstants> <DefineConstants>Version=$(Version)</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
@ -74,7 +74,6 @@
</Target> </Target>
<PropertyGroup> <PropertyGroup>
<PreBuildEvent>IF NOT DEFINED IsPipeline ( <PreBuildEvent>IF NOT DEFINED IsPipeline (
call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0 call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
SET PTRoot=..\..\..\.. SET PTRoot=..\..\..\..
call "..\..\publish.cmd" call "..\..\publish.cmd"

View File

@ -8,9 +8,11 @@
<?define KeyboardManagerProjectName="KeyboardManager"?> <?define KeyboardManagerProjectName="KeyboardManager"?>
<?define PowerRenameProjectName="PowerRename"?> <?define PowerRenameProjectName="PowerRename"?>
<?define ColorPickerProjectName="ColorPicker"?> <?define ColorPickerProjectName="ColorPicker"?>
<?define VideoConferenceProjectName="VideoConference"?>
<?define AwakeProjectName="Awake"?> <?define AwakeProjectName="Awake"?>
<?define RepoDir="$(var.ProjectDir)..\..\" ?> <?define RepoDir="$(var.ProjectDir)..\..\" ?>
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?> <?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
<?define ShortcutGuideExecutable=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuide?> <?define ShortcutGuideExecutable=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuide?>
<?define ShortcutGuideModuleInterface=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuideModuleInterface?> <?define ShortcutGuideModuleInterface=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuideModuleInterface?>
@ -218,6 +220,10 @@
</Directory> </Directory>
<Directory Id="ShortcutGuideModuleInterfaceInstallFolder" Name="ShortcutGuideModuleInterface"/> <Directory Id="ShortcutGuideModuleInterfaceInstallFolder" Name="ShortcutGuideModuleInterface"/>
</Directory> </Directory>
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
<!-- <Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
<Directory Id="VideoConferenceIconsFolder" Name="Icons" />
</Directory> -->
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" /> <Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" /> <Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
<Directory Id="AwakeInstallFolder" Name="$(var.AwakeProjectName)"> <Directory Id="AwakeInstallFolder" Name="$(var.AwakeProjectName)">
@ -442,6 +448,9 @@
<Component Id="BugReportTool_exe" Guid="0F8E3E9F-2E86-4660-A3BF-AE4DD431B93C" Win64="yes"> <Component Id="BugReportTool_exe" Guid="0F8E3E9F-2E86-4660-A3BF-AE4DD431B93C" Win64="yes">
<File Source="$(var.BinX64Dir)BugReportTool\BugReportTool.exe" Id="BugReportTool.exe" KeyPath="yes" Checksum="yes" /> <File Source="$(var.BinX64Dir)BugReportTool\BugReportTool.exe" Id="BugReportTool.exe" KeyPath="yes" Checksum="yes" />
</Component> </Component>
<Component Id="WebcamReportTool_exe" Guid="B6005DAC-8C26-4865-91B3-99F098422C13" Win64="yes">
<File Source="$(var.BinX64Dir)WebcamReportTool\WebcamReportTool.exe" Id="WebcamReportTool.exe" Checksum="yes" />
</Component>
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\"> <DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
@ -637,6 +646,37 @@
</Component> </Component>
</DirectoryRef> </DirectoryRef>
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
<!-- <DirectoryRef Id="VideoConferenceInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\">
<Component Id="Module_VideoConference" Guid="5996527a-40fc-432e-b3ac-abc0b4bd3887" Win64="yes">
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
<File SelfRegCost="1" Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x64.dll" KeyPath="yes">
<Class Id="{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}" Context="InprocServer32" ThreadingModel="apartment" Description="PowerToys VideoConference Mute" />
</File>
<File SelfRegCost="1" Source="$(var.BinX32Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x86.dll">
<Class Id="{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}" Context="InprocServer32" ThreadingModel="apartment" Description="PowerToys VideoConference Mute" />
</File>
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceModule.dll" />
</Component>
</DirectoryRef>
<DirectoryRef Id="VideoConferenceIconsFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons">
<Component Id="Module_VideoConferenceIcons" Guid="5996527a-40fc-432e-b34c-abc0b4bd3887" Win64="yes">
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-NotInUse Dark.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-NotInUse Light.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-Off Dark.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-Off Light.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-On Dark.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-On Light.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-NotInUse Dark.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-NotInUse Light.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-Off Light.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-Off Dark.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Dark.png" />
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Light.png" />
</Component>
</DirectoryRef> -->
<DirectoryRef Id="ShortcutGuideExecutableInstallFolder" FileSource="$(var.ShortcutGuideExecutable)"> <DirectoryRef Id="ShortcutGuideExecutableInstallFolder" FileSource="$(var.ShortcutGuideExecutable)">
<Component Id="Module_ShortcutGuideExecutable" Guid="DA6E5710-F1DF-44EB-A316-300FA39544E9" Win64="yes"> <Component Id="Module_ShortcutGuideExecutable" Guid="DA6E5710-F1DF-44EB-A316-300FA39544E9" Win64="yes">
<File Source="$(var.ShortcutGuideExecutable)\PowerToys.ShortcutGuide.exe" KeyPath="yes" /> <File Source="$(var.ShortcutGuideExecutable)\PowerToys.ShortcutGuide.exe" KeyPath="yes" />
@ -751,7 +791,7 @@
<File Source="$(var.BinX64Dir)Settings\PowerToys.Settings.exe"/> <File Source="$(var.BinX64Dir)Settings\PowerToys.Settings.exe"/>
<File Source="$(var.BinX64Dir)Settings\Microsoft.PowerToys.Settings.UI.exe"/> <File Source="$(var.BinX64Dir)Settings\Microsoft.PowerToys.Settings.UI.exe"/>
<!-- dll --> <!-- dll -->
<?foreach File in concrt140_app.dll;Microsoft.Bcl.AsyncInterfaces.dll;System.IO.Abstractions.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToys.Settings.dll;Microsoft.Toolkit.dll;Microsoft.Toolkit.Uwp.dll;Microsoft.Toolkit.Uwp.UI.dll;Microsoft.Toolkit.Win32.UI.XamlHost.dll;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.Controls.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.UI.Xaml.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;PowerToysInterop.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;ManagedTelemetry.dll;ManagedCommon.dll;ColorCode.Core.dll;ColorCode.UWP.dll;Microsoft.Graphics.Canvas.winmd;Microsoft.Toolkit.Parsers.dll;Microsoft.Toolkit.Uwp.UI.Animations.dll;Microsoft.Toolkit.Uwp.UI.Controls.dll?> <?foreach File in concrt140_app.dll;Microsoft.Bcl.AsyncInterfaces.dll;System.IO.Abstractions.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToys.Settings.dll;Microsoft.Toolkit.dll;Microsoft.Toolkit.Uwp.dll;Microsoft.Toolkit.Uwp.UI.dll;Microsoft.Toolkit.Win32.UI.XamlHost.dll;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.Controls.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.UI.Xaml.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;PowerToysInterop.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;ManagedTelemetry.dll;ManagedCommon.dll;ColorCode.Core.dll;ColorCode.UWP.dll;Microsoft.Graphics.Canvas.winmd;Microsoft.Toolkit.Parsers.dll;Microsoft.Toolkit.Uwp.UI.Animations.dll;Microsoft.Toolkit.Uwp.UI.Controls.dll;System.Deployment.dll;System.Windows.Forms.dll;System.Runtime.Serialization.Formatters.Soap.dll?>
<File Id="SettingsV2_$(var.File)" Source="$(var.BinX64Dir)Settings\$(var.File)" /> <File Id="SettingsV2_$(var.File)" Source="$(var.BinX64Dir)Settings\$(var.File)" />
<?endforeach?> <?endforeach?>
<!-- json --> <!-- json -->
@ -791,7 +831,7 @@
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules"> <DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes"> <Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png?> <?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" /> <File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
<?endforeach?> <?endforeach?>
</Component> </Component>
@ -882,6 +922,9 @@
<ComponentRef Id="ShortcutGuideSvgs" /> <ComponentRef Id="ShortcutGuideSvgs" />
<ComponentRef Id="Module_ShortcutGuideModuleInterface" /> <ComponentRef Id="Module_ShortcutGuideModuleInterface" />
<ComponentRef Id="Module_ShortcutGuideExecutable" /> <ComponentRef Id="Module_ShortcutGuideExecutable" />
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
<!-- <ComponentRef Id="Module_VideoConference" />
<ComponentRef Id="Module_VideoConferenceIcons" /> -->
<ComponentRef Id="Module_FancyZones" /> <ComponentRef Id="Module_FancyZones" />
<ComponentRef Id="DesktopShortcut" /> <ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="Module_PowerRename" /> <ComponentRef Id="Module_PowerRename" />
@ -911,6 +954,7 @@
</ComponentGroup> </ComponentGroup>
<ComponentGroup Id="ToolComponents" Directory="ToolsFolder"> <ComponentGroup Id="ToolComponents" Directory="ToolsFolder">
<ComponentRef Id="BugReportTool_exe" /> <ComponentRef Id="BugReportTool_exe" />
<ComponentRef Id="WebcamReportTool_exe" />
</ComponentGroup> </ComponentGroup>
</Fragment> </Fragment>

View File

@ -18,6 +18,7 @@ TRACELOGGING_DEFINE_PROVIDER(
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0' const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
const DWORD USERNAME_LEN = UNLEN + 1; // 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}"; 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. // Creates a Scheduled Task to run at logon for the current user.
@ -596,6 +597,165 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
return WcaFinalize(er); 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 = nullptr;
HCERTSTORE hCertStore = nullptr;
HANDLE hfile = nullptr;
DWORD size = INVALID_FILE_SIZE;
char * pFileContent = nullptr;
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, 0, 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, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hfile == INVALID_HANDLE_VALUE)
{
hr = GetLastError();
ExitOnFailure(hr, "Certificate file open failed", hr);
}
size = GetFileSize(hfile, nullptr);
if (size == INVALID_FILE_SIZE)
{
hr = GetLastError();
ExitOnFailure(hr, "Certificate file size not valid", hr);
}
pFileContent = (char*)malloc(size);
DWORD sizeread;
if (!ReadFile(hfile, pFileContent, size, &sizeread, nullptr))
{
hr = GetLastError();
ExitOnFailure(hr, "Certificate file read failed", hr);
}
if (!CertAddEncodedCertificateToStore(hCertStore,
X509_ASN_ENCODING,
(const BYTE*)pFileContent,
size,
CERT_STORE_ADD_ALWAYS,
nullptr))
{
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;
LPWSTR driverPath = nullptr;
hr = WcaInitialize(hInstall, "InstallVirtualCameraDriverCA");
ExitOnFailure(hr, "Failed to initialize");
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;
LPWSTR driverPath = nullptr;
hr = WcaInitialize(hInstall, "UninstallVirtualCameraDriverCA");
ExitOnFailure(hr, "Failed to initialize");
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);
}
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall) UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
{ {

View File

@ -13,3 +13,7 @@ EXPORTS
TelemetryLogRepairCancelCA TelemetryLogRepairCancelCA
TelemetryLogRepairFailCA TelemetryLogRepairFailCA
TerminateProcessesCA TerminateProcessesCA
TerminateProcessesCA
CertifyVirtualCameraDriverCA
InstallVirtualCameraDriverCA
UninstallVirtualCameraDriverCA

View File

@ -56,7 +56,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;..\..\$(PlatformShortName)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;..\..\$(PlatformShortName)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Newdev.lib;Crypt32.lib;msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

View File

@ -4,6 +4,7 @@
#define DPSAPI_VERSION 1 #define DPSAPI_VERSION 1
// Windows Header Files: // Windows Header Files:
#include <windows.h> #include <windows.h>
#include <newdev.h>
#include <strsafe.h> #include <strsafe.h>
#include <msiquery.h> #include <msiquery.h>
#include <Msi.h> #include <Msi.h>

View File

@ -1,6 +1,13 @@
#pragma once #pragma once
#include "pch.h" #define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <thread>
#include <optional>
#include <string>
#include <functional>
class FileWatcher class FileWatcher
{ {

View File

@ -28,10 +28,12 @@
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
<ClInclude Include="settings_helpers.h" /> <ClInclude Include="settings_helpers.h" />
<ClInclude Include="settings_objects.h" /> <ClInclude Include="settings_objects.h" />
<ClInclude Include="FileWatcher.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="settings_helpers.cpp" /> <ClCompile Include="settings_helpers.cpp" />
<ClCompile Include="settings_objects.cpp" /> <ClCompile Include="settings_objects.cpp" />
<ClCompile Include="FileWatcher.cpp" />
<ClCompile Include="pch.cpp"> <ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
</ClCompile> </ClCompile>

View File

@ -8,6 +8,7 @@ namespace PTSettingsHelper
{ {
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json"; constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
std::wstring get_powertoys_general_save_file_location();
std::wstring get_module_save_file_location(std::wstring_view powertoy_key); std::wstring get_module_save_file_location(std::wstring_view powertoy_key);
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name); std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location(); std::wstring get_root_save_folder_location();

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <TraceLoggingProvider.h> #include "TraceLoggingProvider.h"
#include <TraceLoggingDefines.h> #include "TraceLoggingDefines.h"
TRACELOGGING_DECLARE_PROVIDER(g_hProvider); TRACELOGGING_DECLARE_PROVIDER(g_hProvider);

View File

@ -47,6 +47,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<PreprocessorDefinitions>PowerToysInterop;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<OmitDefaultLibName>false</OmitDefaultLibName> <OmitDefaultLibName>false</OmitDefaultLibName>
@ -54,7 +55,7 @@
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Mf.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@ -83,6 +84,8 @@
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" /> <WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
</Target> </Target>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h" />
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h" />
<ClInclude Include="HotkeyManager.h" /> <ClInclude Include="HotkeyManager.h" />
<ClInclude Include="KeyboardHook.h" /> <ClInclude Include="KeyboardHook.h" />
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
@ -90,6 +93,12 @@
<ClInclude Include="shared_constants.h" /> <ClInclude Include="shared_constants.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.cpp">
<CompileAsManaged>false</CompileAsManaged>
</ClCompile>
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.cpp">
<CompileAsManaged>false</CompileAsManaged>
</ClCompile>
<ClCompile Include="Generated Files\AssemblyInfo.cpp" /> <ClCompile Include="Generated Files\AssemblyInfo.cpp" />
<ClCompile Include="HotkeyManager.cpp" /> <ClCompile Include="HotkeyManager.cpp" />
<ClCompile Include="interop.cpp" /> <ClCompile Include="interop.cpp" />
@ -109,6 +118,12 @@
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200902.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200902.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

View File

@ -27,6 +27,12 @@
<ClInclude Include="resource.h"> <ClInclude Include="resource.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shared_constants.h"> <ClInclude Include="shared_constants.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -50,6 +56,12 @@
<ClCompile Include="keyboard_layout.cpp"> <ClCompile Include="keyboard_layout.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="interop.rc"> <ResourceCompile Include="interop.rc">

View File

@ -13,12 +13,17 @@
// Therefore the simplest way is to compile these functions as native using the pragmas below. // Therefore the simplest way is to compile these functions as native using the pragmas below.
#pragma managed(push, off) #pragma managed(push, off)
#include "../utils/os-detect.h" #include "../utils/os-detect.h"
// TODO: move to a separate library in common
#include "../../modules/videoconference/VideoConferenceShared/MicrophoneDevice.h"
#include "../../modules/videoconference/VideoConferenceShared/VideoCaptureDeviceList.h"
#pragma managed(pop) #pragma managed(pop)
#include <common/version/version.h> #include <common/version/version.h>
using namespace System; using namespace System;
using namespace System::Runtime::InteropServices; using namespace System::Runtime::InteropServices;
using System::Collections::Generic::List;
// https://docs.microsoft.com/en-us/cpp/dotnet/how-to-wrap-native-class-for-use-by-csharp?view=vs-2019 // https://docs.microsoft.com/en-us/cpp/dotnet/how-to-wrap-native-class-for-use-by-csharp?view=vs-2019
namespace interop namespace interop
@ -122,6 +127,32 @@ public
static String ^ GetProductVersion() { static String ^ GetProductVersion() {
return gcnew String(get_product_version().c_str()); return gcnew String(get_product_version().c_str());
} }
static List<String ^> ^ GetAllActiveMicrophoneDeviceNames() {
auto names = gcnew List<String ^>();
for (const auto& device : MicrophoneDevice::getAllActive())
{
names->Add(gcnew String(device.name().data()));
}
return names;
}
static List<String ^> ^
GetAllVideoCaptureDeviceNames() {
auto names = gcnew List<String ^>();
VideoCaptureDeviceList vcdl;
vcdl.EnumerateDevices();
for (UINT32 i = 0; i < vcdl.Count(); ++i)
{
auto name = gcnew String(vcdl.GetDeviceName(i).data());
if (name != L"PowerToys VideoConference Mute")
{
names->Add(name);
}
}
return names;
}
}; };
public public

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200902.2" targetFramework="native" />
</packages>

View File

@ -7,13 +7,13 @@
#include <common/utils/resources.h> #include <common/utils/resources.h>
#include <common/utils/winapi_error.h> #include <common/utils/winapi_error.h>
#include <common/utils/window.h> #include <common/utils/window.h>
#include <common/SettingsAPI/FileWatcher.h>
#include "FancyZones.h" #include "FancyZones.h"
#include "FancyZonesLib/Settings.h" #include "FancyZonesLib/Settings.h"
#include "FancyZonesLib/ZoneWindow.h" #include "FancyZonesLib/ZoneWindow.h"
#include "FancyZonesLib/FancyZonesData.h" #include "FancyZonesLib/FancyZonesData.h"
#include "FancyZonesLib/ZoneSet.h" #include "FancyZonesLib/ZoneSet.h"
#include "FancyZonesLib/FileWatcher.h"
#include "FancyZonesLib/WindowMoveHandler.h" #include "FancyZonesLib/WindowMoveHandler.h"
#include "FancyZonesLib/FancyZonesWinHookEventIDs.h" #include "FancyZonesLib/FancyZonesWinHookEventIDs.h"
#include "FancyZonesLib/util.h" #include "FancyZonesLib/util.h"

View File

@ -41,7 +41,6 @@
<ClInclude Include="FancyZones.h" /> <ClInclude Include="FancyZones.h" />
<ClInclude Include="FancyZonesDataTypes.h" /> <ClInclude Include="FancyZonesDataTypes.h" />
<ClInclude Include="FancyZonesWinHookEventIDs.h" /> <ClInclude Include="FancyZonesWinHookEventIDs.h" />
<ClInclude Include="FileWatcher.h" />
<ClInclude Include="GenericKeyHook.h" /> <ClInclude Include="GenericKeyHook.h" />
<ClInclude Include="FancyZonesData.h" /> <ClInclude Include="FancyZonesData.h" />
<ClInclude Include="JsonHelpers.h" /> <ClInclude Include="JsonHelpers.h" />
@ -67,7 +66,6 @@
<ClCompile Include="FancyZonesDataTypes.cpp" /> <ClCompile Include="FancyZonesDataTypes.cpp" />
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" /> <ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
<ClCompile Include="FancyZonesData.cpp" /> <ClCompile Include="FancyZonesData.cpp" />
<ClCompile Include="FileWatcher.cpp" />
<ClCompile Include="JsonHelpers.cpp" /> <ClCompile Include="JsonHelpers.cpp" />
<ClCompile Include="MonitorWorkAreaHandler.cpp" /> <ClCompile Include="MonitorWorkAreaHandler.cpp" />
<ClCompile Include="OnThreadExecutor.cpp" /> <ClCompile Include="OnThreadExecutor.cpp" />

View File

@ -78,9 +78,6 @@
<ClInclude Include="ZoneWindowDrawing.h"> <ClInclude Include="ZoneWindowDrawing.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FileWatcher.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CallTracer.h"> <ClInclude Include="CallTracer.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -140,9 +137,6 @@
<ClCompile Include="OnThreadExecutor.cpp"> <ClCompile Include="OnThreadExecutor.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FileWatcher.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CallTracer.cpp"> <ClCompile Include="CallTracer.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-Off-Disabled">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="Off-Disabled" clip-path="url(#clip-Off-Disabled)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#1f1f1f">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#585858" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
<path id="Camera_disabled_icon" data-name="Camera disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#585858"/>
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)" fill="#fff"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-Off-Disabled_Light">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="Off-Disabled_Light" data-name="Off-Disabled Light" clip-path="url(#clip-Off-Disabled_Light)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#f1f1f1">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#c1c1c1" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
<path id="Camera_disabled_icon" data-name="Camera disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#c1c1c1"/>
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-Off-Off_Dark">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="Off-Off_Dark" data-name="Off-Off Dark" clip-path="url(#clip-Off-Off_Dark)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#1f1f1f">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)" fill="#fff"/>
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)" fill="#fff"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-Off-Off_Light">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="Off-Off_Light" data-name="Off-Off Light" clip-path="url(#clip-Off-Off_Light)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#f1f1f1">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)"/>
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-Off-On_Dark">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="Off-On_Dark" data-name="Off-On Dark" clip-path="url(#clip-Off-On_Dark)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#1f1f1f">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)" fill="#fff"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-Off-On_Light">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="Off-On_Light" data-name="Off-On Light" clip-path="url(#clip-Off-On_Light)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#f1f1f1">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-On-Disabled">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="On-Disabled" clip-path="url(#clip-On-Disabled)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#1f1f1f">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#1f1f1f"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#585858" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
<path id="Camer_disabled_icon" data-name="Camer disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#585858"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-On-Disabled_Light">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="On-Disabled_Light" data-name="On-Disabled Light" clip-path="url(#clip-On-Disabled_Light)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#f1f1f1">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#c1c1c1" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
<path id="Camer_disabled_icon" data-name="Camer disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#c1c1c1"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-On-Off_Dark">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="On-Off_Dark" data-name="On-Off Dark" clip-path="url(#clip-On-Off_Dark)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#1f1f1f">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)" fill="#fff"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-On-Off_Light">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="On-Off_Light" data-name="On-Off Light" clip-path="url(#clip-On-Off_Light)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#f1f1f1">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-On-On_Dark">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="On-On_Dark" data-name="On-On Dark" clip-path="url(#clip-On-On_Dark)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#1f1f1f">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)" fill="#fff"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
<defs>
<clipPath id="clip-On-On_Light">
<rect width="322" height="44"/>
</clipPath>
</defs>
<g id="On-On_Light" data-name="On-On Light" clip-path="url(#clip-On-On_Light)">
<rect width="322" height="44" fill="#f1f1f1"/>
<g id="Background" fill="#f1f1f1">
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
</g>
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)"/>
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,14 @@
# Video Conference Mute
# Introduction
The Video Conference Mute module allows muting microphone and/or web camera video stream during video calls or other activity.
# Usage
If you'd like to mute your web camera, please select "PowerToys VideoConference Mute" device in your web camera-using app, then restart it.
During a video call, you can use default shortcuts to mute microphone, web camera or both. You'll see a toolbar indicating corresponding mute statuses.
# Options
You can tweak the toolbar position on the screen as well as set web camera overlay image during muting.
# Backlog

View File

@ -0,0 +1,335 @@
#include "pch.h"
#include "Toolbar.h"
#include <windowsx.h>
#include <common/Themes/windows_colors.h>
#include "Logging.h"
#include "VideoConferenceModule.h"
Toolbar* toolbar = nullptr;
const int REFRESH_RATE = 100;
const int OVERLAY_SHOW_TIME = 500;
const int BORDER_OFFSET = 12;
Toolbar::Toolbar()
{
toolbar = this;
darkImages.camOnMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-On Dark.png");
darkImages.camOffMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-Off Dark.png");
darkImages.camOnMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-On Dark.png");
darkImages.camOffMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-Off Dark.png");
darkImages.camUnusedMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-NotInUse Dark.png");
darkImages.camUnusedMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-NotInUse Dark.png");
lightImages.camOnMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-On Light.png");
lightImages.camOffMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-Off Light.png");
lightImages.camOnMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-On Light.png");
lightImages.camOffMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-Off Light.png");
lightImages.camUnusedMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-NotInUse Light.png");
lightImages.camUnusedMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-NotInUse Light.png");
}
void Toolbar::scheduleModuleSettingsUpdate()
{
moduleSettingsUpdateScheduled = true;
}
void Toolbar::scheduleGeneralSettingsUpdate()
{
generalSettingsUpdateScheduled = true;
}
LRESULT Toolbar::WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DESTROY:
return 0;
case WM_LBUTTONDOWN:
{
int x = GET_X_LPARAM(lparam);
int y = GET_Y_LPARAM(lparam);
if (x < 322 / 2)
{
VideoConferenceModule::reverseMicrophoneMute();
}
else
{
VideoConferenceModule::reverseVirtualCameraMuteState();
}
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
case WM_CREATE:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
Gdiplus::Graphics graphic(hdc);
ToolbarImages* themeImages = &toolbar->darkImages;
if (toolbar->theme == L"light" || (toolbar->theme == L"system" && !WindowsColors::is_dark_mode()))
{
themeImages = &toolbar->lightImages;
}
else
{
themeImages = &toolbar->darkImages;
}
Gdiplus::Image* toolbarImage = nullptr;
if (!toolbar->cameraInUse)
{
if (toolbar->microphoneMuted)
{
toolbarImage = themeImages->camUnusedMicOff;
}
else
{
toolbarImage = themeImages->camUnusedMicOn;
}
}
else if (toolbar->microphoneMuted)
{
if (toolbar->cameraMuted)
{
toolbarImage = themeImages->camOffMicOff;
}
else
{
toolbarImage = themeImages->camOnMicOff;
}
}
else
{
if (toolbar->cameraMuted)
{
toolbarImage = themeImages->camOffMicOn;
}
else
{
toolbarImage = themeImages->camOnMicOn;
}
}
graphic.DrawImage(toolbarImage, 0, 0, toolbarImage->GetWidth(), toolbarImage->GetHeight());
EndPaint(hwnd, &ps);
break;
}
case WM_TIMER:
{
if (toolbar->generalSettingsUpdateScheduled)
{
instance->onGeneralSettingsChanged();
toolbar->generalSettingsUpdateScheduled = false;
}
if (toolbar->moduleSettingsUpdateScheduled)
{
instance->onModuleSettingsChanged();
toolbar->moduleSettingsUpdateScheduled = false;
}
toolbar->cameraInUse = VideoConferenceModule::getVirtualCameraInUse();
InvalidateRect(hwnd, NULL, NULL);
using namespace std::chrono;
const auto nowMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
const bool showOverlayTimeout = nowMillis - toolbar->lastTimeCamOrMicMuteStateChanged > OVERLAY_SHOW_TIME;
static bool previousShow = false;
bool show = false;
if (toolbar->cameraInUse)
{
show = toolbar->HideToolbarWhenUnmuted ? toolbar->microphoneMuted || toolbar->cameraMuted : true;
}
else if (toolbar->previouscameraInUse)
{
VideoConferenceModule::unmuteAll();
}
else
{
show = toolbar->microphoneMuted;
}
show = show || !showOverlayTimeout;
if (show)
{
ShowWindow(hwnd, SW_SHOW);
}
else
{
ShowWindow(hwnd, SW_HIDE);
}
if (previousShow != show)
{
previousShow = show;
LOG(show ? "Toolbar visibility changed to shown" : "Toolbar visibility changed to hidden");
}
KillTimer(hwnd, toolbar->nTimerId);
toolbar->previouscameraInUse = toolbar->cameraInUse;
break;
}
default:
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
toolbar->nTimerId = SetTimer(hwnd, 101, REFRESH_RATE, nullptr);
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
void Toolbar::show(std::wstring position, std::wstring monitorString)
{
for (auto& hwnd : hwnds)
{
PostMessageW(hwnd, WM_CLOSE, 0, 0);
}
hwnds.clear();
int overlayWidth = darkImages.camOffMicOff->GetWidth();
int overlayHeight = darkImages.camOffMicOff->GetHeight();
// Register the window class
LPCWSTR CLASS_NAME = L"MuteNotificationWindowClass";
WNDCLASS wc{};
wc.hInstance = GetModuleHandleW(nullptr);
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpfnWndProc = WindowProcessMessages;
RegisterClassW(&wc);
// Create the window
DWORD dwExtStyle = 0;
DWORD dwStyle = WS_POPUPWINDOW;
std::vector<MonitorInfo> monitorInfos;
if (monitorString == L"All monitors")
{
monitorInfos = MonitorInfo::GetMonitors(false);
}
else //"Main monitor" or non-present
{
monitorInfos.push_back(MonitorInfo::GetPrimaryMonitor());
}
for (auto& monitorInfo : monitorInfos)
{
int positionX = 0;
int positionY = 0;
if (position == L"Top left corner")
{
positionX = monitorInfo.left() + BORDER_OFFSET;
positionY = monitorInfo.top() + BORDER_OFFSET;
}
else if (position == L"Top center")
{
positionX = monitorInfo.middle().x - overlayWidth / 2;
positionY = monitorInfo.top() + BORDER_OFFSET;
}
else if (position == L"Bottom left corner")
{
positionX = monitorInfo.left() + BORDER_OFFSET;
positionY = monitorInfo.bottom() - overlayHeight - BORDER_OFFSET;
}
else if (position == L"Bottom center")
{
positionX = monitorInfo.middle().x - overlayWidth / 2;
positionY = monitorInfo.bottom() - overlayHeight - BORDER_OFFSET;
}
else if (position == L"Bottom right corner")
{
positionX = monitorInfo.right() - overlayWidth - BORDER_OFFSET;
positionY = monitorInfo.bottom() - overlayHeight - BORDER_OFFSET;
}
else //"Top right corner" or non-present
{
positionX = monitorInfo.right() - overlayWidth - BORDER_OFFSET;
positionY = monitorInfo.top() + BORDER_OFFSET;
}
HWND hwnd;
hwnd = CreateWindowExW(
WS_EX_TOOLWINDOW | WS_EX_LAYERED,
CLASS_NAME,
CLASS_NAME,
WS_POPUP,
positionX,
positionY,
overlayWidth,
overlayHeight,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr);
auto transparrentColorKey = RGB(0, 0, 255);
HBRUSH brush = CreateSolidBrush(transparrentColorKey);
SetClassLongPtr(hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
SetLayeredWindowAttributes(hwnd, transparrentColorKey, 0, LWA_COLORKEY);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
hwnds.push_back(hwnd);
}
}
void Toolbar::hide()
{
for (auto& hwnd : hwnds)
{
PostMessage(hwnd, WM_CLOSE, 0, 0);
}
hwnds.clear();
}
bool Toolbar::getCameraMute()
{
return cameraMuted;
}
void Toolbar::setCameraMute(bool mute)
{
if (mute != cameraMuted)
{
lastTimeCamOrMicMuteStateChanged = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
cameraMuted = mute;
}
bool Toolbar::getMicrophoneMute()
{
return microphoneMuted;
}
void Toolbar::setMicrophoneMute(bool mute)
{
if (mute != microphoneMuted)
{
lastTimeCamOrMicMuteStateChanged = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
microphoneMuted = mute;
}
void Toolbar::setHideToolbarWhenUnmuted(bool hide)
{
HideToolbarWhenUnmuted = hide;
}
void Toolbar::setTheme(std::wstring theme)
{
Toolbar::theme = theme;
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <Windows.h>
#include <gdiplus.h>
#include <atomic>
#include <common/Display/monitors.h>
struct ToolbarImages
{
Gdiplus::Image* camOnMicOn = nullptr;
Gdiplus::Image* camOffMicOn = nullptr;
Gdiplus::Image* camOnMicOff = nullptr;
Gdiplus::Image* camOffMicOff = nullptr;
Gdiplus::Image* camUnusedMicOn = nullptr;
Gdiplus::Image* camUnusedMicOff = nullptr;
};
class Toolbar
{
public:
Toolbar();
void scheduleModuleSettingsUpdate();
void scheduleGeneralSettingsUpdate();
void show(std::wstring position, std::wstring monitorString);
void hide();
bool getCameraMute();
void setCameraMute(bool mute);
bool getMicrophoneMute();
void setMicrophoneMute(bool mute);
void setTheme(std::wstring theme);
void setHideToolbarWhenUnmuted(bool hide);
private:
static LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
// Window callback can't be non-static so this members can't as well
std::vector<HWND> hwnds;
ToolbarImages darkImages;
ToolbarImages lightImages;
bool cameraMuted = false;
bool cameraInUse = false;
bool previouscameraInUse = false;
bool microphoneMuted = false;
std::wstring theme = L"system";
bool HideToolbarWhenUnmuted = true;
uint64_t lastTimeCamOrMicMuteStateChanged;
std::atomic_bool moduleSettingsUpdateScheduled = false;
std::atomic_bool generalSettingsUpdateScheduled = false;
UINT_PTR nTimerId;
};

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="keyboard_state.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="shortcut_guide.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="target_state.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="overlay_window.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="keyboard_state.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shortcut_guide.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="target_state.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="overlay_window.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{2c7c97f7-0d87-4230-a4b2-baf2cfc35d58}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{aa4b6713-589d-42ef-804d-3a045833f83f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="shortcut_guide.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>overlaywindow</RootNamespace>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<ProjectName>VideoConferenceModule</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>Spectre</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
</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 Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;OVERLAYWINDOW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\;..\..\;..\VideoConferenceShared\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>mfplat.lib;mf.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;gdiplus.lib;dwmapi.lib;uxtheme.lib;shcore.lib;Wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /I "$(ProjectDir)Icons\*" "$(OutDir)Icons"
xcopy /y /I "$(ProjectDir)black.bmp*" "$(OutDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;OVERLAYWINDOW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\..\;..\..\;..\VideoConferenceShared\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>mfplat.lib;mf.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;gdiplus.lib;dwmapi.lib;uxtheme.lib;shcore.lib;Wtsapi32.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /I "$(ProjectDir)Icons\*" "$(OutDir)Icons"
xcopy /y /I "$(ProjectDir)black.bmp*" "$(OutDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="Toolbar.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="VideoConferenceModule.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="trace.cpp" />
<ClCompile Include="Toolbar.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="VideoConferenceModule.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VideoConferenceShared\VideoConferenceShared.vcxproj">
<Project>{459e0768-7ebd-4c41-bba1-6db3b3815e0a}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Icons\Off-NotInUse Dark.svg" />
<None Include="Icons\Off-NotInUse Light.svg" />
<None Include="Icons\Off-Off Dark.svg" />
<None Include="Icons\Off-Off Light.svg" />
<None Include="Icons\Off-On Dark.svg" />
<None Include="Icons\Off-On Light.svg" />
<None Include="Icons\On-NotInUse Dark.svg" />
<None Include="Icons\On-NotInUse Light.svg" />
<None Include="Icons\On-Off Dark.svg" />
<None Include="Icons\On-Off Light.svg" />
<None Include="Icons\On-On Dark.svg" />
<None Include="Icons\On-On Light.svg" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Image Include="black.bmp" />
<Image Include="Icons\Off-NotInUse Dark.png" />
<Image Include="Icons\Off-NotInUse Light.png" />
<Image Include="Icons\Off-Off Dark.png" />
<Image Include="Icons\Off-Off Light.png" />
<Image Include="Icons\Off-On Dark.png" />
<Image Include="Icons\Off-On Light.png" />
<Image Include="Icons\On-NotInUse Dark.png" />
<Image Include="Icons\On-NotInUse Light.png" />
<Image Include="Icons\On-Off Dark.png" />
<Image Include="Icons\On-Off Light.png" />
<Image Include="Icons\On-On Dark.png" />
<Image Include="Icons\On-On Light.png" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="Toolbar.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="VideoConferenceModule.cpp" />
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="Toolbar.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="VideoConferenceModule.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<Image Include="black.bmp" />
<Image Include="Icons\Off-NotInUse Dark.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\Off-NotInUse Light.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\Off-Off Dark.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\Off-Off Light.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\Off-On Dark.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\Off-On Light.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\On-NotInUse Dark.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\On-NotInUse Light.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\On-Off Dark.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\On-Off Light.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\On-On Dark.png">
<Filter>Icons</Filter>
</Image>
<Image Include="Icons\On-On Light.png">
<Filter>Icons</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Icons\Off-NotInUse Dark.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\Off-NotInUse Light.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\Off-Off Dark.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\Off-Off Light.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\Off-On Dark.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\Off-On Light.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\On-NotInUse Dark.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\On-NotInUse Light.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\On-Off Dark.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\On-Off Light.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\On-On Dark.svg">
<Filter>Icons</Filter>
</None>
<None Include="Icons\On-On Light.svg">
<Filter>Icons</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Filter Include="Icons">
<UniqueIdentifier>{735361e2-82fa-4034-b9c9-cd6aa099eaa5}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -0,0 +1,568 @@
#include "pch.h"
#include "VideoConferenceModule.h"
#include <WinUser.h>
#include <gdiplus.h>
#include <shellapi.h>
#include <filesystem>
#include <common/debug_control.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/elevation.h>
#include <common/utils/process_path.h>
#include <CameraStateUpdateChannels.h>
#include "logging.h"
#include "trace.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
VideoConferenceModule* instance = nullptr;
VideoConferenceSettings VideoConferenceModule::settings;
Toolbar VideoConferenceModule::toolbar;
HHOOK VideoConferenceModule::hook_handle;
IAudioEndpointVolume* endpointVolume = NULL;
bool VideoConferenceModule::isKeyPressed(unsigned int keyCode)
{
return (GetKeyState(keyCode) & 0x8000);
}
namespace fs = std::filesystem;
bool VideoConferenceModule::isHotkeyPressed(DWORD code, PowerToysSettings::HotkeyObject& hotkey)
{
return code == hotkey.get_code() &&
isKeyPressed(VK_SHIFT) == hotkey.shift_pressed() &&
isKeyPressed(VK_CONTROL) == hotkey.ctrl_pressed() &&
isKeyPressed(VK_LWIN) == hotkey.win_pressed() &&
(isKeyPressed(VK_LMENU)) == hotkey.alt_pressed();
}
void VideoConferenceModule::reverseMicrophoneMute()
{
bool muted = false;
for (auto& controlledMic : instance->_controlledMicrophones)
{
const bool was_muted = controlledMic.muted();
controlledMic.toggle_muted();
muted = muted || !was_muted;
}
if (muted)
{
Trace::MicrophoneMuted();
}
toolbar.setMicrophoneMute(muted);
}
bool VideoConferenceModule::getMicrophoneMuteState()
{
return instance->_microphoneTrackedInUI ? instance->_microphoneTrackedInUI->muted() : false;
}
void VideoConferenceModule::reverseVirtualCameraMuteState()
{
bool muted = false;
if (!instance->_settingsUpdateChannel.has_value())
{
return;
}
instance->_settingsUpdateChannel->access([&muted](auto settingsMemory) {
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
settings->useOverlayImage = !settings->useOverlayImage;
muted = settings->useOverlayImage;
});
if (muted)
{
Trace::CameraMuted();
}
toolbar.setCameraMute(muted);
}
bool VideoConferenceModule::getVirtualCameraMuteState()
{
bool disabled = false;
if (!instance->_settingsUpdateChannel.has_value())
{
return disabled;
}
instance->_settingsUpdateChannel->access([&disabled](auto settingsMemory) {
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
disabled = settings->useOverlayImage;
});
return disabled;
}
bool VideoConferenceModule::getVirtualCameraInUse()
{
if (!instance->_settingsUpdateChannel.has_value())
{
return false;
}
bool inUse = false;
instance->_settingsUpdateChannel->access([&inUse](auto settingsMemory) {
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
inUse = settings->cameraInUse;
});
return inUse;
}
LRESULT CALLBACK VideoConferenceModule::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
KBDLLHOOKSTRUCT* kbd = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
if (isHotkeyPressed(kbd->vkCode, settings.cameraAndMicrophoneMuteHotkey))
{
const bool cameraInUse = getVirtualCameraInUse();
const bool microphoneIsMuted = getMicrophoneMuteState();
const bool cameraIsMuted = cameraInUse && getVirtualCameraMuteState();
if (cameraInUse)
{
// we're likely on a video call, so we must mute the unmuted cam/mic or reverse the mute state
// of everything, if cam and mic mute states are the same
if (microphoneIsMuted == cameraIsMuted)
{
reverseMicrophoneMute();
reverseVirtualCameraMuteState();
}
else if (cameraIsMuted)
{
reverseMicrophoneMute();
}
else if (microphoneIsMuted)
{
reverseVirtualCameraMuteState();
}
}
else
{
// if the camera is not in use, we just mute/unmute the mic
reverseMicrophoneMute();
}
return 1;
}
else if (isHotkeyPressed(kbd->vkCode, settings.microphoneMuteHotkey))
{
reverseMicrophoneMute();
return 1;
}
else if (isHotkeyPressed(kbd->vkCode, settings.cameraMuteHotkey))
{
reverseVirtualCameraMuteState();
return 1;
}
}
}
return CallNextHookEx(hook_handle, nCode, wParam, lParam);
}
void VideoConferenceModule::onGeneralSettingsChanged()
{
auto settings = PTSettingsHelper::load_general_settings();
bool enabled = false;
try
{
if (json::has(settings, L"enabled"))
{
for (const auto& mod : settings.GetNamedObject(L"enabled"))
{
const auto value = mod.Value();
if (value.ValueType() != json::JsonValueType::Boolean)
{
continue;
}
if (mod.Key() == get_key())
{
enabled = value.GetBoolean();
break;
}
}
}
}
catch (...)
{
LOG("Couldn't get enabled state");
}
if (enabled)
{
enable();
}
else
{
disable();
}
}
void VideoConferenceModule::onModuleSettingsChanged()
{
try
{
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
//Trace::SettingsChanged(pressTime.value, overlayOpacity.value, theme.value);
if (_enabled)
{
if (const auto val = values.get_json(L"mute_camera_and_microphone_hotkey"))
{
settings.cameraAndMicrophoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
}
if (const auto val = values.get_json(L"mute_microphone_hotkey"))
{
settings.microphoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
}
if (const auto val = values.get_json(L"mute_camera_hotkey"))
{
settings.cameraMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
}
if (const auto val = values.get_string_value(L"toolbar_position"))
{
settings.toolbarPositionString = val.value();
}
if (const auto val = values.get_string_value(L"toolbar_monitor"))
{
settings.toolbarMonitorString = val.value();
}
if (const auto val = values.get_string_value(L"selected_camera"); val && val != settings.selectedCamera)
{
settings.selectedCamera = val.value();
sendSourceCameraNameUpdate();
}
if (const auto val = values.get_string_value(L"camera_overlay_image_path"); val && val != settings.imageOverlayPath)
{
settings.imageOverlayPath = val.value();
sendOverlayImageUpdate();
}
if (const auto val = values.get_bool_value(L"hide_toolbar_when_unmuted"))
{
toolbar.setHideToolbarWhenUnmuted(val.value());
}
const auto selectedMic = values.get_string_value(L"selected_mic");
if (selectedMic && selectedMic != settings.selectedMicrophone)
{
settings.selectedMicrophone = *selectedMic;
updateControlledMicrophones(settings.selectedMicrophone);
}
toolbar.show(settings.toolbarPositionString, settings.toolbarMonitorString);
}
}
catch (...)
{
LOG("onModuleSettingsChanged encountered an exception");
}
}
VideoConferenceModule::VideoConferenceModule() :
_generalSettingsWatcher{ PTSettingsHelper::get_powertoys_general_save_file_location(), [this] {
toolbar.scheduleGeneralSettingsUpdate();
} },
_moduleSettingsWatcher{ PTSettingsHelper::get_module_save_file_location(get_key()), [this] { toolbar.scheduleModuleSettingsUpdate(); } }
{
init_settings();
_settingsUpdateChannel =
SerializedSharedMemory::create(CameraSettingsUpdateChannel::endpoint(), sizeof(CameraSettingsUpdateChannel), false);
if (_settingsUpdateChannel)
{
_settingsUpdateChannel->access([](auto memory) {
auto updatesChannel = new (memory._data) CameraSettingsUpdateChannel{};
});
}
sendSourceCameraNameUpdate();
sendOverlayImageUpdate();
}
inline VideoConferenceModule::~VideoConferenceModule()
{
instance->unmuteAll();
toolbar.hide();
}
const wchar_t* VideoConferenceModule::get_name()
{
return L"Video Conference";
}
const wchar_t* VideoConferenceModule::get_key()
{
return L"Video Conference";
}
bool VideoConferenceModule::get_config(wchar_t* buffer, int* buffer_size)
{
return true;
}
void VideoConferenceModule::set_config(const wchar_t* config)
{
try
{
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
values.save_to_settings_file();
}
catch (...)
{
LOG("VideoConferenceModule::set_config: exception during saving new settings values");
}
}
void VideoConferenceModule::init_settings()
{
try
{
PowerToysSettings::PowerToyValues powerToysSettings = PowerToysSettings::PowerToyValues::load_from_settings_file(L"Video Conference");
if (const auto val = powerToysSettings.get_json(L"mute_camera_and_microphone_hotkey"))
{
settings.cameraAndMicrophoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
}
if (const auto val = powerToysSettings.get_json(L"mute_microphone_hotkey"))
{
settings.microphoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
}
if (const auto val = powerToysSettings.get_json(L"mute_camera_hotkey"))
{
settings.cameraMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
}
if (const auto val = powerToysSettings.get_string_value(L"toolbar_position"))
{
settings.toolbarPositionString = val.value();
}
if (const auto val = powerToysSettings.get_string_value(L"toolbar_monitor"))
{
settings.toolbarMonitorString = val.value();
}
if (const auto val = powerToysSettings.get_string_value(L"selected_camera"))
{
settings.selectedCamera = val.value();
}
if (const auto val = powerToysSettings.get_string_value(L"camera_overlay_image_path"))
{
settings.imageOverlayPath = val.value();
}
if (const auto val = powerToysSettings.get_bool_value(L"hide_toolbar_when_unmuted"))
{
toolbar.setHideToolbarWhenUnmuted(val.value());
}
if (const auto val = powerToysSettings.get_string_value(L"selected_mic"); val && *val != settings.selectedMicrophone)
{
settings.selectedMicrophone = *val;
updateControlledMicrophones(settings.selectedMicrophone);
}
}
catch (std::exception&)
{
// Error while loading from the settings file. Just let default values stay as they are.
}
try
{
auto loaded = PTSettingsHelper::load_general_settings();
std::wstring settings_theme{ static_cast<std::wstring_view>(loaded.GetNamedString(L"theme", L"system")) };
if (settings_theme != L"dark" && settings_theme != L"light")
{
settings_theme = L"system";
}
toolbar.setTheme(settings_theme);
}
catch (...)
{
}
}
void VideoConferenceModule::updateControlledMicrophones(const std::wstring_view new_mic)
{
for (auto& controlledMic : _controlledMicrophones)
{
controlledMic.set_muted(false);
}
_controlledMicrophones.clear();
_microphoneTrackedInUI = nullptr;
auto allMics = MicrophoneDevice::getAllActive();
if (new_mic == L"[All]")
{
_controlledMicrophones = std::move(allMics);
if (auto defaultMic = MicrophoneDevice::getDefault())
{
for (auto& controlledMic : _controlledMicrophones)
{
if (controlledMic.id() == defaultMic->id())
{
_microphoneTrackedInUI = &controlledMic;
break;
}
}
}
}
else
{
for (auto& controlledMic : allMics)
{
if (controlledMic.name() == new_mic)
{
_controlledMicrophones.emplace_back(std::move(controlledMic));
_microphoneTrackedInUI = &_controlledMicrophones[0];
break;
}
}
}
if (_microphoneTrackedInUI)
{
_microphoneTrackedInUI->set_mute_changed_callback([&](const bool muted) {
toolbar.setMicrophoneMute(muted);
});
toolbar.setMicrophoneMute(_microphoneTrackedInUI->muted());
}
}
void toggleProxyCamRegistration(const bool enable)
{
if (!is_process_elevated())
{
return;
}
auto vcmRoot = fs::path{ get_module_folderpath() } / "modules";
vcmRoot /= "VideoConference";
std::array<fs::path, 2> proxyFilters = { vcmRoot / "VideoConferenceProxyFilter_x64.dll", vcmRoot / "VideoConferenceProxyFilter_x86.dll" };
for (const auto filter : proxyFilters)
{
std::wstring params{ L"/s " };
if (!enable)
{
params += L"/u ";
}
params += '"';
params += filter;
params += '"';
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
sei.lpFile = L"regsvr32";
sei.lpParameters = params.c_str();
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
}
}
void VideoConferenceModule::enable()
{
if (!_enabled)
{
toggleProxyCamRegistration(true);
toolbar.setMicrophoneMute(getMicrophoneMuteState());
toolbar.setCameraMute(getVirtualCameraMuteState());
toolbar.show(settings.toolbarPositionString, settings.toolbarMonitorString);
_enabled = true;
#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED)
if (IsDebuggerPresent())
{
return;
}
#endif
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
}
}
void VideoConferenceModule::unmuteAll()
{
if (getVirtualCameraMuteState())
{
reverseVirtualCameraMuteState();
}
if (getMicrophoneMuteState())
{
reverseMicrophoneMute();
}
}
void VideoConferenceModule::disable()
{
if (_enabled)
{
toggleProxyCamRegistration(false);
if (hook_handle)
{
bool success = UnhookWindowsHookEx(hook_handle);
if (success)
{
hook_handle = nullptr;
}
}
instance->unmuteAll();
toolbar.hide();
_enabled = false;
}
}
bool VideoConferenceModule::is_enabled()
{
return _enabled;
}
void VideoConferenceModule::destroy()
{
delete this;
instance = nullptr;
}
void VideoConferenceModule::sendSourceCameraNameUpdate()
{
if (!_settingsUpdateChannel.has_value() || settings.selectedCamera.empty())
{
return;
}
_settingsUpdateChannel->access([](auto memory) {
auto updatesChannel = reinterpret_cast<CameraSettingsUpdateChannel*>(memory._data);
updatesChannel->sourceCameraName.emplace();
std::copy(begin(settings.selectedCamera), end(settings.selectedCamera), begin(*updatesChannel->sourceCameraName));
});
}
void VideoConferenceModule::sendOverlayImageUpdate()
{
if (!_settingsUpdateChannel.has_value())
{
return;
}
_imageOverlayChannel.reset();
wchar_t powertoysDirectory[MAX_PATH + 1];
DWORD length = GetModuleFileNameW(nullptr, powertoysDirectory, MAX_PATH);
PathRemoveFileSpecW(powertoysDirectory);
std::wstring blankImagePath(powertoysDirectory);
blankImagePath += L"\\modules\\VideoConference\\black.bmp";
_imageOverlayChannel = SerializedSharedMemory::create_readonly(CameraOverlayImageChannel::endpoint(),
settings.imageOverlayPath != L"" ? settings.imageOverlayPath : blankImagePath);
const auto imageSize = static_cast<uint32_t>(_imageOverlayChannel->size());
_settingsUpdateChannel->access([imageSize](auto memory) {
auto updatesChannel = reinterpret_cast<CameraSettingsUpdateChannel*>(memory._data);
updatesChannel->overlayImageSize.emplace(imageSize);
updatesChannel->newOverlayImagePosted = true;
});
}

View File

@ -0,0 +1,86 @@
#pragma once
#include <common/SettingsAPI/FileWatcher.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <interface/powertoy_module_interface.h>
#include <common/SettingsAPI/settings_objects.h>
#include <MicrophoneDevice.h>
#include "Toolbar.h"
#include <SerializedSharedMemory.h>
extern class VideoConferenceModule* instance;
struct VideoConferenceSettings
{
PowerToysSettings::HotkeyObject cameraAndMicrophoneMuteHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, 78);
PowerToysSettings::HotkeyObject microphoneMuteHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, true, 65);
PowerToysSettings::HotkeyObject cameraMuteHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, true, 79);
std::wstring toolbarPositionString;
std::wstring toolbarMonitorString;
std::wstring selectedCamera;
std::wstring imageOverlayPath;
std::wstring selectedMicrophone;
};
class VideoConferenceModule : public PowertoyModuleIface
{
public:
VideoConferenceModule();
~VideoConferenceModule();
virtual const wchar_t* get_name() override;
virtual bool get_config(wchar_t* buffer, int* buffer_size) override;
virtual void set_config(const wchar_t* config) override;
virtual void enable() override;
virtual void disable() override;
virtual bool is_enabled() override;
virtual void destroy() override;
virtual const wchar_t * get_key() override;
void sendSourceCameraNameUpdate();
void sendOverlayImageUpdate();
static void unmuteAll();
static void reverseMicrophoneMute();
static bool getMicrophoneMuteState();
static void reverseVirtualCameraMuteState();
static bool getVirtualCameraMuteState();
static bool getVirtualCameraInUse();
void onGeneralSettingsChanged();
void onModuleSettingsChanged();
private:
void init_settings();
void updateControlledMicrophones(const std::wstring_view new_mic);
// all callback methods and used by callback have to be static
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
static bool isKeyPressed(unsigned int keyCode);
static bool isHotkeyPressed(DWORD code, PowerToysSettings::HotkeyObject& hotkey);
static HHOOK hook_handle;
bool _enabled = false;
std::vector<MicrophoneDevice> _controlledMicrophones;
MicrophoneDevice* _microphoneTrackedInUI = nullptr;
std::optional<SerializedSharedMemory> _imageOverlayChannel;
std::optional<SerializedSharedMemory> _settingsUpdateChannel;
FileWatcher _generalSettingsWatcher;
FileWatcher _moduleSettingsWatcher;
static VideoConferenceSettings settings;
static Toolbar toolbar;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

View File

@ -0,0 +1,35 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include "trace.h"
#include "VideoConferenceModule.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
if (!instance)
{
instance = new VideoConferenceModule();
return instance;
}
else
{
return nullptr;
}
}

View File

@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" />
</packages>

View File

@ -0,0 +1,5 @@
// 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.

View File

@ -0,0 +1,24 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Unknwn.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <wil/resource.h>
#include <wil/com.h>
#include <string_view>
#include <optional>
#include <iostream>
#include <fstream>
#include <vector>
#include <functional>
#include <algorithm>
#include <Shobjidl.h>
#include <Shlwapi.h>
#include <common/Telemetry/ProjectTelemetry.h>

View File

@ -0,0 +1,57 @@
#include "pch.h"
#include "trace.h"
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider() noexcept
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider() noexcept
{
TraceLoggingUnregister(g_hProvider);
}
void Trace::SettingsChanged(const struct VideoConferenceSettings& settings) noexcept
{
bool CustomOverlayImage = (settings.imageOverlayPath.length() > 0);
TraceLoggingWrite(
g_hProvider,
"VideoConference_SettingsChanged",
TraceLoggingWideString(settings.toolbarPositionString.c_str(), "ToolbarPosition"),
TraceLoggingWideString(settings.toolbarMonitorString.c_str(), "ToolbarMonitorSelection"),
TraceLoggingBool(CustomOverlayImage, "CustomImageOverlayUsed"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
void Trace::MicrophoneMuted() noexcept
{
TraceLoggingWrite(
g_hProvider,
"VideoConference_MicrophoneMuted",
TraceLoggingBoolean(true, "MicrophoneMuted"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
void Trace::CameraMuted() noexcept
{
TraceLoggingWrite(
g_hProvider,
"VideoConference_CameraMuted",
TraceLoggingBoolean(true, "CameraMuted"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "VideoConferenceModule.h"
class Trace
{
public:
static void RegisterProvider() noexcept;
static void UnregisterProvider() noexcept;
static void SettingsChanged(const struct VideoConferenceSettings &settings) noexcept;
static void MicrophoneMuted() noexcept;
static void CameraMuted() noexcept;
};

View File

@ -0,0 +1,118 @@
#include "DirectShowUtils.h"
#include <algorithm>
unique_media_type_ptr CopyMediaType(const AM_MEDIA_TYPE* source)
{
unique_media_type_ptr target{ static_cast<AM_MEDIA_TYPE*>(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))) };
*target = *source;
if (source->cbFormat)
{
target->pbFormat = static_cast<BYTE*>(CoTaskMemAlloc(source->cbFormat));
std::copy(source->pbFormat, source->pbFormat + source->cbFormat, target->pbFormat);
}
if (target->pUnk)
{
target->pUnk->AddRef();
}
return target;
}
wil::com_ptr_nothrow<IMemAllocator> GetPinAllocator(wil::com_ptr_nothrow<IPin>& inputPin)
{
if (!inputPin)
{
return nullptr;
}
wil::com_ptr_nothrow<IMemAllocator> allocator;
if (auto memInput = inputPin.try_query<IMemInputPin>(); memInput)
{
memInput->GetAllocator(&allocator);
return allocator;
}
return nullptr;
}
unique_media_type_ptr CopyMediaType(const unique_media_type_ptr& source)
{
return CopyMediaType(source.get());
}
void MyFreeMediaType(AM_MEDIA_TYPE& mt)
{
if (mt.cbFormat != 0)
{
CoTaskMemFree(mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = nullptr;
}
if (mt.pUnk != nullptr)
{
mt.pUnk->Release();
mt.pUnk = nullptr;
}
}
void MyDeleteMediaType(AM_MEDIA_TYPE* pmt)
{
if (!pmt)
{
return;
}
MyFreeMediaType(*pmt);
CoTaskMemFree(const_cast<AM_MEDIA_TYPE*>(pmt));
}
HRESULT MediaTypeEnumerator::Next(ULONG cObjects, AM_MEDIA_TYPE** outObjects, ULONG* pcFetched)
{
if (!outObjects)
{
return E_POINTER;
}
ULONG fetched = 0;
ULONG toFetch = cObjects;
while (toFetch-- && _pos < _objects.size())
{
auto copy = CopyMediaType(_objects[_pos++]);
outObjects[fetched++] = copy.release();
}
if (pcFetched)
{
*pcFetched = fetched;
}
return fetched == cObjects ? S_OK : S_FALSE;
}
HRESULT MediaTypeEnumerator::Skip(ULONG cObjects)
{
_pos += cObjects;
return _pos < _objects.size() ? S_OK : S_FALSE;
}
HRESULT MediaTypeEnumerator::Reset()
{
_pos = 0;
return S_OK;
}
HRESULT MediaTypeEnumerator::Clone(IEnumMediaTypes** ppEnum)
{
auto cloned = winrt::make_self<MediaTypeEnumerator>();
cloned->_objects.resize(_objects.size());
for (size_t i = 0; i < _objects.size(); ++i)
{
cloned->_objects[i] = CopyMediaType(_objects[i]);
}
cloned->_pos = _pos;
cloned.as<IEnumMediaTypes>().copy_to(ppEnum);
return S_OK;
}

View File

@ -0,0 +1,88 @@
#pragma once
#include <initguid.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dshow.h>
#include <wil/com.h>
#include <winrt/Windows.Foundation.h>
#include <vector>
#include "Logging.h"
void MyDeleteMediaType(AM_MEDIA_TYPE* pmt);
using unique_media_type_ptr =
wistd::unique_ptr<AM_MEDIA_TYPE, wil::function_deleter<decltype(&MyDeleteMediaType), MyDeleteMediaType>>;
unique_media_type_ptr CopyMediaType(const unique_media_type_ptr& source);
unique_media_type_ptr CopyMediaType(const AM_MEDIA_TYPE* source);
template<typename ObjectInterface, typename EnumeratorInterface>
struct ObjectEnumerator : public winrt::implements<ObjectEnumerator<ObjectInterface, EnumeratorInterface>, EnumeratorInterface>
{
std::vector<wil::com_ptr_nothrow<ObjectInterface>> _objects;
ULONG _pos = 0;
HRESULT STDMETHODCALLTYPE Next(ULONG cObjects, ObjectInterface** outObjects, ULONG* pcFetched) override
{
if (!outObjects)
{
return E_POINTER;
}
ULONG fetched = 0;
ULONG toFetch = cObjects;
while (toFetch-- && _pos < _objects.size())
{
_objects[_pos++].copy_to(&outObjects[fetched++]);
}
if (pcFetched)
{
*pcFetched = fetched;
}
return fetched == cObjects ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE Skip(ULONG cObjects) override
{
_pos += cObjects;
return _pos < _objects.size() ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE Reset() override
{
_pos = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Clone(EnumeratorInterface** ppEnum) override
{
auto cloned = winrt::make_self<ObjectEnumerator>();
cloned->_objects = _objects;
cloned->_pos = _pos;
cloned.as<EnumeratorInterface>().copy_to(ppEnum);
return S_OK;
}
virtual ~ObjectEnumerator() = default;
};
struct MediaTypeEnumerator : public winrt::implements<MediaTypeEnumerator, IEnumMediaTypes>
{
std::vector<unique_media_type_ptr> _objects;
ULONG _pos = 0;
HRESULT STDMETHODCALLTYPE Next(ULONG cObjects, AM_MEDIA_TYPE** outObjects, ULONG* pcFetched) override;
HRESULT STDMETHODCALLTYPE Skip(ULONG cObjects) override;
HRESULT STDMETHODCALLTYPE Reset() override;
HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes** ppEnum) override;
virtual ~MediaTypeEnumerator() = default;
};
wil::com_ptr_nothrow<IMemAllocator> GetPinAllocator(wil::com_ptr_nothrow<IPin>& inputPin);

View File

@ -0,0 +1,425 @@
#include <initguid.h>
#include <dxgiformat.h>
#include <assert.h>
#include <winrt/base.h>
#pragma warning(push)
#pragma warning(disable : 4005)
#include <wincodec.h>
#pragma warning(pop)
#include <memory>
#include <mfapi.h>
#include <shcore.h>
#include <algorithm>
#include <wil/resource.h>
#include <wil/com.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mftransform.h>
#include <dshow.h>
#include <Wincodecsdk.h>
#include <shlwapi.h>
#include "Logging.h"
IWICImagingFactory* _GetWIC() noexcept
{
static IWICImagingFactory* s_Factory = nullptr;
if (s_Factory)
{
return s_Factory;
}
OK_OR_BAIL(CoCreateInstance(
CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), (LPVOID*)&s_Factory));
return s_Factory;
}
bool ReencodeJPGImage(BYTE* imageBuf, const DWORD imageSize, DWORD& reencodedSize)
{
auto pWIC = _GetWIC();
wil::com_ptr_nothrow<IStream> imageStream = SHCreateMemStream(imageBuf, imageSize);
if (!imageStream)
{
return false;
}
// Decode jpg into bitmap
wil::com_ptr_nothrow<IWICBitmapDecoder> bitmapDecoder;
OK_OR_BAIL(pWIC->CreateDecoderFromStream(imageStream.get(), nullptr, WICDecodeMetadataCacheOnLoad, &bitmapDecoder));
wil::com_ptr_nothrow<IWICBitmapFrameDecode> decodedFrame;
OK_OR_BAIL(bitmapDecoder->GetFrame(0, &decodedFrame));
wil::com_ptr_nothrow<IWICBitmapSource> bitmap;
bitmap.attach(decodedFrame.detach());
UINT width = 0, height = 0;
OK_OR_BAIL(bitmap->GetSize(&width, &height));
// Initialize jpg encoder
wil::com_ptr_nothrow<IWICBitmapEncoder> encoder;
OK_OR_BAIL(pWIC->CreateEncoder(GUID_ContainerFormatJpeg, nullptr, &encoder));
wil::com_ptr_nothrow<IStream> outputStream;
OK_OR_BAIL(CreateStreamOnHGlobal(nullptr, true, &outputStream));
OK_OR_BAIL(encoder->Initialize(outputStream.get(), WICBitmapEncoderNoCache));
wil::com_ptr_nothrow<IWICBitmapFrameEncode> encodedFrame;
wil::com_ptr_nothrow<IPropertyBag2> encoderOptions;
OK_OR_BAIL(encoder->CreateNewFrame(&encodedFrame, &encoderOptions));
ULONG nProperties = 0;
OK_OR_BAIL(encoderOptions->CountProperties(&nProperties));
for (ULONG propIdx = 0; propIdx < nProperties; ++propIdx)
{
PROPBAG2 propBag{};
ULONG _;
OK_OR_BAIL(encoderOptions->GetPropertyInfo(propIdx, 1, &propBag, &_));
if (propBag.pstrName == std::wstring_view{ L"ImageQuality" })
{
wil::unique_variant variant;
variant.vt = VT_R4;
variant.fltVal = 0.1f;
OK_OR_BAIL(encoderOptions->Write(1, &propBag, &variant));
LOG("Successfully set jpg compression quality");
// skip the rest of the properties
propIdx = nProperties;
}
CoTaskMemFree(propBag.pstrName);
}
OK_OR_BAIL(encodedFrame->Initialize(encoderOptions.get()));
WICPixelFormatGUID intermediateFormat = GUID_WICPixelFormat24bppRGB;
OK_OR_BAIL(encodedFrame->SetPixelFormat(&intermediateFormat));
OK_OR_BAIL(encodedFrame->SetSize(width, height));
// Commit the image encoding
OK_OR_BAIL(encodedFrame->WriteSource(bitmap.get(), nullptr));
OK_OR_BAIL(encodedFrame->Commit());
OK_OR_BAIL(encoder->Commit());
STATSTG intermediateStreamStat{};
OK_OR_BAIL(outputStream->Stat(&intermediateStreamStat, STATFLAG_NONAME));
const ULONGLONG jpgStreamSize = intermediateStreamStat.cbSize.QuadPart;
HGLOBAL streamMemoryHandle{};
OK_OR_BAIL(GetHGlobalFromStream(outputStream.get(), &streamMemoryHandle));
auto jpgStreamMemory = static_cast<uint8_t*>(GlobalLock(streamMemoryHandle));
std::copy(jpgStreamMemory, jpgStreamMemory + jpgStreamSize, imageBuf);
auto unlockJpgStreamMemory = wil::scope_exit([jpgStreamMemory] { GlobalUnlock(jpgStreamMemory); });
reencodedSize = (DWORD)jpgStreamSize;
return true;
}
wil::com_ptr_nothrow<IWICBitmapSource> LoadAsRGB24BitmapWithSize(IWICImagingFactory* pWIC,
wil::com_ptr_nothrow<IStream> image,
const UINT targetWidth,
const UINT targetHeight)
{
wil::com_ptr_nothrow<IWICBitmapSource> bitmap;
// Initialize image bitmap decoder from filename and get the image frame
wil::com_ptr_nothrow<IWICBitmapDecoder> bitmapDecoder;
OK_OR_BAIL(pWIC->CreateDecoderFromStream(image.get(), nullptr, WICDecodeMetadataCacheOnLoad, &bitmapDecoder));
wil::com_ptr_nothrow<IWICBitmapFrameDecode> decodedFrame;
OK_OR_BAIL(bitmapDecoder->GetFrame(0, &decodedFrame));
UINT imageWidth = 0, imageHeight = 0;
OK_OR_BAIL(decodedFrame->GetSize(&imageWidth, &imageHeight));
// Scale the image if required
if (targetWidth != imageWidth || targetHeight != imageHeight)
{
wil::com_ptr_nothrow<IWICBitmapScaler> scaler;
OK_OR_BAIL(pWIC->CreateBitmapScaler(&scaler));
OK_OR_BAIL(
scaler->Initialize(decodedFrame.get(), targetWidth, targetHeight, WICBitmapInterpolationModeHighQualityCubic));
bitmap.attach(scaler.detach());
}
else
{
bitmap.attach(decodedFrame.detach());
}
WICPixelFormatGUID pixelFormat{};
OK_OR_BAIL(bitmap->GetPixelFormat(&pixelFormat));
const auto targetPixelFormat = GUID_WICPixelFormat24bppBGR;
if (pixelFormat != targetPixelFormat)
{
wil::com_ptr_nothrow<IWICBitmapSource> convertedBitmap;
if (SUCCEEDED(WICConvertBitmapSource(targetPixelFormat, bitmap.get(), &convertedBitmap)))
{
return convertedBitmap;
}
}
return bitmap;
}
wil::com_ptr_nothrow<IStream> EncodeBitmapToContainer(IWICImagingFactory* pWIC,
wil::com_ptr_nothrow<IWICBitmapSource> bitmap,
const GUID& containerGUID,
const UINT width,
const UINT height,
const float quality)
{
wil::com_ptr_nothrow<IWICBitmapEncoder> encoder;
pWIC->CreateEncoder(containerGUID, nullptr, &encoder);
if (!encoder)
{
return nullptr;
}
// Prepare the encoder output memory stream and encoding params
wil::com_ptr_nothrow<IStream> encodedBitmap;
OK_OR_BAIL(CreateStreamOnHGlobal(nullptr, true, &encodedBitmap));
OK_OR_BAIL(encoder->Initialize(encodedBitmap.get(), WICBitmapEncoderNoCache));
wil::com_ptr_nothrow<IWICBitmapFrameEncode> encodedFrame;
wil::com_ptr_nothrow<IPropertyBag2> encoderOptions;
OK_OR_BAIL(encoder->CreateNewFrame(&encodedFrame, &encoderOptions));
ULONG nProperties = 0;
OK_OR_BAIL(encoderOptions->CountProperties(&nProperties));
for (ULONG propIdx = 0; propIdx < nProperties; ++propIdx)
{
PROPBAG2 propBag{};
ULONG _;
OK_OR_BAIL(encoderOptions->GetPropertyInfo(propIdx, 1, &propBag, &_));
if (propBag.pstrName == std::wstring_view{ L"ImageQuality" })
{
wil::unique_variant variant;
variant.vt = VT_R4;
variant.fltVal = quality;
OK_OR_BAIL(encoderOptions->Write(1, &propBag, &variant));
LOG("Successfully set jpg compression quality");
// skip the rest of the properties
propIdx = nProperties;
}
CoTaskMemFree(propBag.pstrName);
}
OK_OR_BAIL(encodedFrame->Initialize(encoderOptions.get()));
WICPixelFormatGUID intermediateFormat = GUID_WICPixelFormat24bppRGB;
OK_OR_BAIL(encodedFrame->SetPixelFormat(&intermediateFormat));
OK_OR_BAIL(encodedFrame->SetSize(width, height));
// Commit the image encoding
OK_OR_BAIL(encodedFrame->WriteSource(bitmap.get(), nullptr));
OK_OR_BAIL(encodedFrame->Commit());
OK_OR_BAIL(encoder->Commit());
return encodedBitmap;
}
IMFSample* ConvertIMFVideoSample(const MFT_REGISTER_TYPE_INFO& inputType,
IMFMediaType* outputMediaType,
const wil::com_ptr_nothrow<IMFSample>& inputSample,
const UINT width,
const UINT height)
{
IMFActivate** ppVDActivate = nullptr;
UINT32 count = 0;
MFT_REGISTER_TYPE_INFO outputType = { MFMediaType_Video, {} };
outputMediaType->GetGUID(MF_MT_SUBTYPE, &outputType.guidSubtype);
const std::array<GUID, 3> transformerCategories = {
MFT_CATEGORY_VIDEO_PROCESSOR, MFT_CATEGORY_VIDEO_DECODER, MFT_CATEGORY_VIDEO_ENCODER
};
for (const auto& transformerCategory : transformerCategories)
{
OK_OR_BAIL(MFTEnumEx(transformerCategory, MFT_ENUM_FLAG_SYNCMFT, &inputType, &outputType, &ppVDActivate, &count));
if (count != 0)
{
break;
}
}
wil::com_ptr_nothrow<IMFTransform> videoTransformer;
bool videoDecoderActivated = false;
for (UINT32 i = 0; i < count; ++i)
{
if (!videoDecoderActivated && !FAILED(ppVDActivate[i]->ActivateObject(IID_PPV_ARGS(&videoTransformer))))
{
videoDecoderActivated = true;
}
ppVDActivate[i]->Release();
}
if (count)
{
CoTaskMemFree(ppVDActivate);
}
if (!videoDecoderActivated)
{
LOG("No converter avialable for the selected format");
return nullptr;
}
auto shutdownVideoDecoder = wil::scope_exit([&videoTransformer] { MFShutdownObject(videoTransformer.get()); });
// Set input/output types for the decoder
wil::com_ptr_nothrow<IMFMediaType> intermediateFrameMediaType;
OK_OR_BAIL(MFCreateMediaType(&intermediateFrameMediaType));
intermediateFrameMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
intermediateFrameMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24);
intermediateFrameMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
intermediateFrameMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
OK_OR_BAIL(MFSetAttributeSize(intermediateFrameMediaType.get(), MF_MT_FRAME_SIZE, width, height));
OK_OR_BAIL(MFSetAttributeRatio(intermediateFrameMediaType.get(), MF_MT_PIXEL_ASPECT_RATIO, width, height));
OK_OR_BAIL(videoTransformer->SetInputType(0, intermediateFrameMediaType.get(), 0));
OK_OR_BAIL(videoTransformer->SetOutputType(0, outputMediaType, 0));
// Process the input sample
OK_OR_BAIL(videoTransformer->ProcessInput(0, inputSample.get(), 0));
// Check whether we need to allocate output sample and buffer ourselves
MFT_OUTPUT_STREAM_INFO outputStreamInfo{};
OK_OR_BAIL(videoTransformer->GetOutputStreamInfo(0, &outputStreamInfo));
const bool onlyProvidesSamples = outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
const bool canProvideSamples = outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES;
const bool mustAllocateSample =
(!onlyProvidesSamples && !canProvideSamples) ||
(!onlyProvidesSamples && (outputStreamInfo.dwFlags & MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER));
MFT_OUTPUT_DATA_BUFFER outputSamples{};
IMFSample* outputSample = nullptr;
// If so, do the allocation
if (mustAllocateSample)
{
OK_OR_BAIL(MFCreateSample(&outputSample));
OK_OR_BAIL(outputSample->SetSampleDuration(333333));
OK_OR_BAIL(outputSample->SetSampleTime(1));
OK_OR_BAIL(outputSample->SetUINT32(MF_MT_VIDEO_ROTATION, MFVideoRotationFormat::MFVideoRotationFormat_0));
IMFMediaBuffer* outputMediaBuffer = nullptr;
OK_OR_BAIL(
MFCreateAlignedMemoryBuffer(outputStreamInfo.cbSize, outputStreamInfo.cbAlignment - 1, &outputMediaBuffer));
OK_OR_BAIL(outputMediaBuffer->SetCurrentLength(outputStreamInfo.cbSize));
OK_OR_BAIL(outputSample->AddBuffer(outputMediaBuffer));
outputSamples.pSample = outputSample;
}
// Finally, produce the output sample
DWORD processStatus = 0;
if (failed(videoTransformer->ProcessOutput(0, 1, &outputSamples, &processStatus)))
{
LOG("Failed to convert image frame");
}
if (outputSamples.pEvents)
{
outputSamples.pEvents->Release();
}
return outputSamples.pSample;
}
wil::com_ptr_nothrow<IMFSample> LoadImageAsSample(wil::com_ptr_nothrow<IStream> imageStream,
IMFMediaType* sampleMediaType,
const float quality) noexcept
{
UINT targetWidth = 0;
UINT targetHeight = 0;
OK_OR_BAIL(MFGetAttributeSize(sampleMediaType, MF_MT_FRAME_SIZE, &targetWidth, &targetHeight));
MFT_REGISTER_TYPE_INFO outputType = { MFMediaType_Video, {} };
OK_OR_BAIL(sampleMediaType->GetGUID(MF_MT_SUBTYPE, &outputType.guidSubtype));
IWICImagingFactory* pWIC = _GetWIC();
if (!pWIC)
{
LOG("Failed to create IWICImagingFactory");
return nullptr;
}
if (!imageStream)
{
return nullptr;
}
const auto srcImageBitmap = LoadAsRGB24BitmapWithSize(pWIC, imageStream, targetWidth, targetHeight);
if (!srcImageBitmap)
{
return nullptr;
}
// First, let's create a sample containing RGB24 bitmap
IMFSample* outputSample = nullptr;
OK_OR_BAIL(MFCreateSample(&outputSample));
OK_OR_BAIL(outputSample->SetUINT32(MF_MT_VIDEO_ROTATION, MFVideoRotationFormat::MFVideoRotationFormat_0));
OK_OR_BAIL(outputSample->SetSampleDuration(333333));
OK_OR_BAIL(outputSample->SetSampleTime(1));
IMFMediaBuffer* outputMediaBuffer = nullptr;
const DWORD nPixelBytes = targetWidth * targetHeight * 3;
OK_OR_BAIL(MFCreateAlignedMemoryBuffer(nPixelBytes, MF_64_BYTE_ALIGNMENT, &outputMediaBuffer));
const UINT stride = 3 * targetWidth;
DWORD max_length = 0, current_length = 0;
BYTE* sampleBufferMemory = nullptr;
OK_OR_BAIL(outputMediaBuffer->Lock(&sampleBufferMemory, &max_length, &current_length));
OK_OR_BAIL(srcImageBitmap->CopyPixels(nullptr, stride, nPixelBytes, sampleBufferMemory));
OK_OR_BAIL(outputMediaBuffer->Unlock());
OK_OR_BAIL(outputMediaBuffer->SetCurrentLength(nPixelBytes));
OK_OR_BAIL(outputSample->AddBuffer(outputMediaBuffer));
if (outputType.guidSubtype == MFVideoFormat_RGB24)
{
return outputSample;
}
// Special case for mjpg, since we need to use jpg container for it instead of supplying raw pixels
if (outputType.guidSubtype == MFVideoFormat_MJPG)
{
// Use an intermediate jpg container sample which will be transcoded to the target format
wil::com_ptr_nothrow<IStream> jpgStream =
EncodeBitmapToContainer(pWIC, srcImageBitmap, GUID_ContainerFormatJpeg, targetWidth, targetHeight, quality);
// Obtain stream size and lock its memory pointer
STATSTG intermediateStreamStat{};
OK_OR_BAIL(jpgStream->Stat(&intermediateStreamStat, STATFLAG_NONAME));
const ULONGLONG jpgStreamSize = intermediateStreamStat.cbSize.QuadPart;
HGLOBAL streamMemoryHandle{};
OK_OR_BAIL(GetHGlobalFromStream(jpgStream.get(), &streamMemoryHandle));
auto jpgStreamMemory = static_cast<uint8_t*>(GlobalLock(streamMemoryHandle));
auto unlockJpgStreamMemory = wil::scope_exit([jpgStreamMemory] { GlobalUnlock(jpgStreamMemory); });
// Create a sample from the input image buffer
wil::com_ptr_nothrow<IMFSample> jpgSample;
OK_OR_BAIL(MFCreateSample(&jpgSample));
OK_OR_BAIL(jpgSample->SetUINT32(MF_MT_VIDEO_ROTATION, MFVideoRotationFormat::MFVideoRotationFormat_0));
IMFMediaBuffer* inputMediaBuffer = nullptr;
OK_OR_BAIL(MFCreateAlignedMemoryBuffer(static_cast<DWORD>(jpgStreamSize), MF_64_BYTE_ALIGNMENT, &inputMediaBuffer));
BYTE* inputBuf = nullptr;
OK_OR_BAIL(inputMediaBuffer->Lock(&inputBuf, &max_length, &current_length));
if (max_length < jpgStreamSize)
{
return nullptr;
}
std::copy(jpgStreamMemory, jpgStreamMemory + jpgStreamSize, inputBuf);
unlockJpgStreamMemory.reset();
OK_OR_BAIL(inputMediaBuffer->Unlock());
OK_OR_BAIL(inputMediaBuffer->SetCurrentLength(static_cast<DWORD>(jpgStreamSize)));
OK_OR_BAIL(jpgSample->AddBuffer(inputMediaBuffer));
return jpgSample;
}
// Now we are ready to convert it to the requested media type
MFT_REGISTER_TYPE_INFO intermediateType = { MFMediaType_Video, MFVideoFormat_RGB24 };
// But if no conversion is needed, just return the input sample
return ConvertIMFVideoSample(intermediateType, sampleMediaType, outputSample, targetWidth, targetHeight);
}

View File

@ -0,0 +1,634 @@
#include "Logging.h"
#include "VideoCaptureDevice.h"
#include <wil/resource.h>
#include <cguid.h>
struct VideoCaptureReceiverFilter : winrt::implements<VideoCaptureReceiverFilter, IBaseFilter, IAMFilterMiscFlags>
{
FILTER_STATE _state = State_Stopped;
IFilterGraph* _graph = nullptr;
wil::com_ptr_nothrow<IPin> _videoReceiverPin;
ULONG STDMETHODCALLTYPE GetMiscFlags() override { return AM_FILTER_MISC_FLAGS_IS_RENDERER; }
HRESULT STDMETHODCALLTYPE GetClassID(CLSID*) override { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE Stop() override
{
_state = State_Stopped;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Pause() override
{
_state = State_Paused;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME) override
{
_state = State_Running;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetState(DWORD, FILTER_STATE* outState) override
{
*outState = _state;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock** outRefClock) override
{
*outRefClock = nullptr;
return NOERROR;
}
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock*) override { return S_OK; }
HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins** ppEnum) override
{
auto enumerator = winrt::make_self<ObjectEnumerator<IPin, IEnumPins>>();
enumerator->_objects.emplace_back(_videoReceiverPin);
*ppEnum = enumerator.detach();
return S_OK;
}
HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR, IPin**) override { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR) override
{
_graph = pGraph;
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO* pInfo) override
{
std::copy(std::begin(NAME), std::end(NAME), pInfo->achName);
if (_graph)
{
pInfo->pGraph = _graph;
_graph->AddRef();
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR* pVendorInfo) override
{
auto info = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(VENDOR)));
std::copy(std::begin(VENDOR), std::end(VENDOR), info);
*pVendorInfo = info;
return S_OK;
}
virtual ~VideoCaptureReceiverFilter() = default;
constexpr static inline wchar_t NAME[] = L"PowerToysVCMCaptureFilter";
constexpr static inline wchar_t VENDOR[] = L"Microsoft Corporation";
};
struct VideoCaptureReceiverPin : winrt::implements<VideoCaptureReceiverPin, IPin, IMemInputPin>
{
VideoCaptureReceiverFilter* _owningFilter = nullptr;
unique_media_type_ptr _expectedMediaType;
wil::com_ptr_nothrow<IPin> _captureInputPin;
unique_media_type_ptr _inputCaptureMediaType;
std::atomic_bool _flushing = false;
VideoCaptureDevice::callback_t _frameCallback;
wil::com_ptr_nothrow<IMemAllocator> _allocator;
VideoCaptureReceiverPin(unique_media_type_ptr mediaType, VideoCaptureReceiverFilter* filter) :
_expectedMediaType{ std::move(mediaType) }, _owningFilter{ filter }
{
}
HRESULT STDMETHODCALLTYPE Connect(IPin*, const AM_MEDIA_TYPE* pmt) override
{
if (_owningFilter->_state == State_Running)
{
return VFW_E_NOT_STOPPED;
}
if (_captureInputPin)
{
return VFW_E_ALREADY_CONNECTED;
}
if (!pmt || pmt->majortype == GUID_NULL)
{
return S_OK;
}
if (pmt->majortype != _expectedMediaType->majortype || pmt->subtype != _expectedMediaType->subtype)
{
return S_FALSE;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) override
{
if (!pConnector || !pmt)
{
return E_POINTER;
}
if (_captureInputPin)
{
return VFW_E_ALREADY_CONNECTED;
}
if (_owningFilter->_state != State_Stopped)
{
return VFW_E_NOT_STOPPED;
}
if (QueryAccept(pmt) != S_OK)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
_captureInputPin = pConnector;
_inputCaptureMediaType = CopyMediaType(pmt);
return S_OK;
}
HRESULT STDMETHODCALLTYPE Disconnect() override
{
_allocator.reset();
_captureInputPin.reset();
_inputCaptureMediaType.reset();
return S_OK;
}
HRESULT STDMETHODCALLTYPE ConnectedTo(IPin** pPin) override
{
if (!_captureInputPin)
{
return VFW_E_NOT_CONNECTED;
}
_captureInputPin.copy_to(pPin);
return S_OK;
}
HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE* pmt) override
{
if (!pmt)
{
return E_POINTER;
}
if (!_inputCaptureMediaType)
{
return VFW_E_NOT_CONNECTED;
}
*pmt = *CopyMediaType(_inputCaptureMediaType).release();
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO* pInfo) override
{
if (!pInfo)
{
return E_POINTER;
}
pInfo->pFilter = _owningFilter;
if (_owningFilter)
{
_owningFilter->AddRef();
}
pInfo->dir = PINDIR_INPUT;
std::copy(std::begin(NAME), std::end(NAME), pInfo->achName);
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION* pPinDir) override
{
if (!pPinDir)
{
return E_POINTER;
}
*pPinDir = PINDIR_INPUT;
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryId(LPWSTR* lpId) override
{
if (!lpId)
{
return E_POINTER;
}
*lpId = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(NAME)));
std::copy(std::begin(NAME), std::end(NAME), *lpId);
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE* pmt) override
{
if (!pmt)
{
return E_POINTER;
}
if (pmt->majortype != _expectedMediaType->majortype || pmt->subtype != _expectedMediaType->subtype)
{
return S_FALSE;
}
if (_captureInputPin)
{
_inputCaptureMediaType.reset(const_cast<AM_MEDIA_TYPE*>(pmt));
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes** ppEnum) override
{
if (!ppEnum)
{
return E_POINTER;
}
auto enumerator = winrt::make_self<MediaTypeEnumerator>();
enumerator->_objects.emplace_back(CopyMediaType(_expectedMediaType));
*ppEnum = enumerator.detach();
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin**, ULONG*) override { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE EndOfStream() override { return S_OK; }
HRESULT STDMETHODCALLTYPE BeginFlush() override
{
_flushing = true;
return S_OK;
}
HRESULT STDMETHODCALLTYPE EndFlush() override
{
_flushing = false;
return S_OK;
}
HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME, REFERENCE_TIME, double) override { return S_OK; }
HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator** allocator) override
{
VERBOSE_LOG;
if (!_allocator)
{
return VFW_E_NO_ALLOCATOR;
}
_allocator.copy_to(allocator);
return S_OK;
}
HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator* allocator, BOOL readOnly) override
{
VERBOSE_LOG;
LOG(readOnly ? "Allocator READONLY: true" : "Allocator READONLY: false");
_allocator = allocator;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES*) override { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE Receive(IMediaSample* pSample) override
{
if (_flushing)
{
return S_FALSE;
}
if (!pSample)
{
return E_POINTER;
}
if (pSample && _frameCallback)
{
_frameCallback(pSample);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample** pSamples, long nSamples, long* nSamplesProcessed) override
{
if (!pSamples && nSamples)
{
return E_POINTER;
}
if (_flushing)
{
return S_FALSE;
}
for (long i = 0; i < nSamples; i++)
{
Receive(pSamples[i]);
}
*nSamplesProcessed = nSamples;
return S_OK;
}
HRESULT STDMETHODCALLTYPE ReceiveCanBlock() override { return S_FALSE; }
virtual ~VideoCaptureReceiverPin() = default;
constexpr static inline wchar_t NAME[] = L"PowerToysVCMCapturePin";
};
constexpr long MINIMAL_FPS_ALLOWED = 29;
const char* GetMediaSubTypeString(const GUID& guid)
{
if (guid == MEDIASUBTYPE_RGB24)
{
return "MEDIASUBTYPE_RGB24";
}
if (guid == MEDIASUBTYPE_YUY2)
{
return "MEDIASUBTYPE_YUY2";
}
if (guid == MEDIASUBTYPE_MJPG)
{
return "MEDIASUBTYPE_MJPG";
}
if (guid == MEDIASUBTYPE_NV12)
{
return "MEDIASUBTYPE_NV12";
}
return "MEDIASUBTYPE_UNKNOWN";
}
std::optional<VideoStreamFormat> SelectBestMediaType(wil::com_ptr_nothrow<IPin>& pin)
{
VERBOSE_LOG;
wil::com_ptr_nothrow<IEnumMediaTypes> mediaTypeEnum;
if (pin->EnumMediaTypes(&mediaTypeEnum); !mediaTypeEnum)
{
return std::nullopt;
}
ULONG _ = 0;
VideoStreamFormat bestFormat;
unique_media_type_ptr mt;
while (mediaTypeEnum->Next(1, wil::out_param(mt), &_) == S_OK)
{
if (mt->majortype != MEDIATYPE_Video)
{
continue;
}
auto format = reinterpret_cast<VIDEOINFOHEADER*>(mt->pbFormat);
if (!format || !format->AvgTimePerFrame)
{
LOG("VideoInfoHeader not found");
continue;
}
const auto formatAvgFPS = 10000000LL / format->AvgTimePerFrame;
if (format->AvgTimePerFrame > bestFormat.avgFrameTime || formatAvgFPS < MINIMAL_FPS_ALLOWED)
{
continue;
}
if (format->bmiHeader.biWidth < bestFormat.width || format->bmiHeader.biHeight < bestFormat.height)
{
continue;
}
if (mt->subtype != MEDIASUBTYPE_YUY2 && mt->subtype != MEDIASUBTYPE_MJPG && mt->subtype != MEDIASUBTYPE_RGB24)
{
OLECHAR* guidString;
StringFromCLSID(mt->subtype, &guidString);
LOG("Skipping mediatype due to unsupported subtype: ");
LOG(guidString);
::CoTaskMemFree(guidString);
continue;
}
bestFormat.avgFrameTime = format->AvgTimePerFrame;
bestFormat.width = format->bmiHeader.biWidth;
bestFormat.height = format->bmiHeader.biHeight;
bestFormat.mediaType = std::move(mt);
}
if (!bestFormat.mediaType)
{
LOG(L"Couldn't select a suitable media format");
return std::nullopt;
}
char selectedFormat[512]{};
sprintf_s(selectedFormat, "Selected media format: %s %ldx%ld %lld fps", GetMediaSubTypeString(bestFormat.mediaType->subtype), bestFormat.width, bestFormat.height, 10000000LL / bestFormat.avgFrameTime);
LOG(selectedFormat);
return std::move(bestFormat);
}
std::vector<VideoCaptureDeviceInfo> VideoCaptureDevice::ListAll()
{
std::vector<VideoCaptureDeviceInfo> devices;
auto enumeratorFactory = wil::CoCreateInstanceNoThrow<ICreateDevEnum>(CLSID_SystemDeviceEnum);
if (!enumeratorFactory)
{
LOG("Couldn't create devenum factory");
return devices;
}
wil::com_ptr_nothrow<IEnumMoniker> enumMoniker;
enumeratorFactory->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enumMoniker, CDEF_DEVMON_PNP_DEVICE);
if (!enumMoniker)
{
LOG("Couldn't create class enumerator");
return devices;
}
ULONG _ = 0;
wil::com_ptr_nothrow<IMoniker> moniker;
while (enumMoniker->Next(1, &moniker, &_) == S_OK)
{
LOG("Inspecting moniker");
VideoCaptureDeviceInfo deviceInfo;
wil::com_ptr_nothrow<IPropertyBag> propertyData;
moniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, reinterpret_cast<void**>(&propertyData));
if (!propertyData)
{
LOG("BindToStorage failed");
continue;
}
wil::unique_variant propVal;
propVal.vt = VT_BSTR;
if (FAILED(propertyData->Read(L"FriendlyName", &propVal, nullptr)))
{
LOG("Couldn't obtain FriendlyName property");
continue;
}
deviceInfo.friendlyName = { propVal.bstrVal, SysStringLen(propVal.bstrVal) };
LOG(deviceInfo.friendlyName);
propVal.reset();
propVal.vt = VT_BSTR;
if (FAILED(propertyData->Read(L"DevicePath", &propVal, nullptr)))
{
LOG("Couldn't obtain DevicePath property");
continue;
}
deviceInfo.devicePath = { propVal.bstrVal, SysStringLen(propVal.bstrVal) };
wil::com_ptr_nothrow<IBaseFilter> filter;
moniker->BindToObject(nullptr, nullptr, IID_IBaseFilter, reinterpret_cast<void**>(&filter));
if (!filter)
{
LOG("Couldn't BindToObject");
continue;
}
wil::com_ptr_nothrow<IEnumPins> pinsEnum;
if (FAILED(filter->EnumPins(&pinsEnum)))
{
LOG("BindToObject EnumPins");
continue;
}
wil::com_ptr_nothrow<IPin> pin;
while (pinsEnum->Next(1, &pin, &_) == S_OK)
{
LOG("Inspecting pin");
// Skip pins which do not belong to capture category
GUID category{};
DWORD __;
if (auto props = pin.try_copy<IKsPropertySet>();
!props ||
FAILED(props->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, nullptr, 0, &category, sizeof(GUID), &__)) ||
category != PIN_CATEGORY_CAPTURE)
{
continue;
}
// Skip non-output pins
if (PIN_DIRECTION direction = {}; FAILED(pin->QueryDirection(&direction)) || direction != PINDIR_OUTPUT)
{
continue;
}
LOG("Found a pin of suitable category and direction, selecting format");
auto bestFormat = SelectBestMediaType(pin);
if (!bestFormat)
{
continue;
}
deviceInfo.captureOutputPin = std::move(pin);
deviceInfo.bestFormat = std::move(bestFormat.value());
deviceInfo.captureOutputFilter = std::move(filter);
devices.emplace_back(std::move(deviceInfo));
}
}
return devices;
}
std::optional<VideoCaptureDevice> VideoCaptureDevice::Create(VideoCaptureDeviceInfo&& vdi, callback_t callback)
{
VERBOSE_LOG;
VideoCaptureDevice result;
result._graph = wil::CoCreateInstanceNoThrow<IGraphBuilder>(CLSID_FilterGraph);
result._builder = wil::CoCreateInstanceNoThrow<ICaptureGraphBuilder2>(CLSID_CaptureGraphBuilder2);
if (!result._graph || !result._builder)
{
return std::nullopt;
}
if (FAILED(result._builder->SetFiltergraph(result._graph.get())))
{
return std::nullopt;
}
result._control = result._graph.try_query<IMediaControl>();
if (!result._control)
{
return std::nullopt;
}
auto pinConfig = vdi.captureOutputPin.try_query<IAMStreamConfig>();
if (!pinConfig)
{
return std::nullopt;
}
if (FAILED(pinConfig->SetFormat(vdi.bestFormat.mediaType.get())))
{
return std::nullopt;
}
auto captureInputFilter = winrt::make_self<VideoCaptureReceiverFilter>();
auto receiverPin = winrt::make_self<VideoCaptureReceiverPin>(std::move(vdi.bestFormat.mediaType), captureInputFilter.get());
receiverPin->_frameCallback = std::move(callback);
captureInputFilter->_videoReceiverPin.attach(receiverPin.get());
auto detachReceiverPin = wil::scope_exit([&receiverPin]() { receiverPin.detach(); });
if (FAILED(result._graph->AddFilter(captureInputFilter.get(), nullptr)))
{
return std::nullopt;
}
if (FAILED(result._graph->AddFilter(vdi.captureOutputFilter.get(), nullptr)))
{
return std::nullopt;
}
if (FAILED(result._graph->ConnectDirect(vdi.captureOutputPin.get(), captureInputFilter->_videoReceiverPin.get(), nullptr)))
{
return std::nullopt;
}
result._allocator = receiverPin->_allocator;
return std::make_optional(std::move(result));
}
bool VideoCaptureDevice::StartCapture()
{
VERBOSE_LOG;
return SUCCEEDED(_control->Run());
}
bool VideoCaptureDevice::StopCapture()
{
VERBOSE_LOG;
return SUCCEEDED(_control->Stop());
}
VideoCaptureDevice::~VideoCaptureDevice()
{
StopCapture();
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <initguid.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dshow.h>
#include <wil/com.h>
#include <functional>
#include <vector>
#include <string>
#include <optional>
#include "DirectShowUtils.h"
struct VideoStreamFormat
{
long width = 0;
long height = 0;
REFERENCE_TIME avgFrameTime = std::numeric_limits<REFERENCE_TIME>::max();
unique_media_type_ptr mediaType;
VideoStreamFormat() = default;
VideoStreamFormat(const VideoStreamFormat&) = delete;
VideoStreamFormat& operator=(const VideoStreamFormat&) = delete;
VideoStreamFormat(VideoStreamFormat&&) = default;
VideoStreamFormat& operator=(VideoStreamFormat&&) = default;
};
struct VideoCaptureDeviceInfo
{
std::wstring friendlyName;
std::wstring devicePath;
wil::com_ptr_nothrow<IPin> captureOutputPin;
wil::com_ptr_nothrow<IBaseFilter> captureOutputFilter;
VideoStreamFormat bestFormat;
};
class VideoCaptureDevice final
{
public:
wil::com_ptr_nothrow<IMemAllocator> _allocator;
using callback_t = std::function<void(IMediaSample*)>;
static std::vector<VideoCaptureDeviceInfo> ListAll();
static std::optional<VideoCaptureDevice> Create(VideoCaptureDeviceInfo&& vdi, callback_t callback);
bool StartCapture();
bool StopCapture();
~VideoCaptureDevice();
private:
wil::com_ptr_nothrow<IGraphBuilder> _graph;
wil::com_ptr_nothrow<ICaptureGraphBuilder2> _builder;
wil::com_ptr_nothrow<IMediaControl> _control;
callback_t _callback;
};

View File

@ -0,0 +1,919 @@
#include "VideoCaptureProxyFilter.h"
#include "VideoCaptureDevice.h"
#include <mfidl.h>
#include <Shlwapi.h>
#include <mfapi.h>
#include <fstream>
constexpr static inline wchar_t FILTER_NAME[] = L"PowerToysVCMProxyFilter";
constexpr static inline wchar_t PIN_NAME[] = L"PowerToysVCMProxyPIN";
constexpr static inline wchar_t VENDOR[] = L"Microsoft Corporation";
namespace
{
constexpr float initialJpgQuality = 0.5f;
constexpr std::array<unsigned char, 3> overlayColor = { 0, 0, 0 };
// clang-format off
unsigned char bmpPixelData[58] = {
0x42, 0x4D, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, overlayColor[0], overlayColor[1], overlayColor[2], 0x00
};
// clang-format on
}
wil::com_ptr_nothrow<IMemAllocator> VideoCaptureProxyPin::FindAllocator()
{
auto allocator = GetPinAllocator(_connectedInputPin);
if (!allocator && _owningFilter->_captureDevice)
{
allocator = _owningFilter->_captureDevice->_allocator;
}
return allocator;
}
wil::com_ptr_nothrow<IMFSample> LoadImageAsSample(wil::com_ptr_nothrow<IStream> imageStream,
IMFMediaType* sampleMediaType,
const float quality) noexcept;
bool ReencodeJPGImage(BYTE* imageBuf, const DWORD imageSize, DWORD& reencodedSize);
HRESULT VideoCaptureProxyPin::Connect(IPin* pReceivePin, const AM_MEDIA_TYPE*)
{
if (!pReceivePin)
{
LOG("VideoCaptureProxyPin::Connect FAILED pReceivePin");
return E_POINTER;
}
if (_owningFilter->_state == State_Running)
{
LOG("VideoCaptureProxyPin::Connect FAILED _owningFilter->_state");
return VFW_E_NOT_STOPPED;
}
if (_connectedInputPin)
{
LOG("VideoCaptureProxyPin::Connect FAILED _connectedInputPin");
return VFW_E_ALREADY_CONNECTED;
}
if (FAILED(pReceivePin->ReceiveConnection(this, _mediaFormat.get())))
{
LOG("VideoCaptureProxyPin::Connect FAILED pReceivePin->ReceiveConnection");
return E_POINTER;
}
_connectedInputPin = pReceivePin;
auto memInput = _connectedInputPin.try_query<IMemInputPin>();
if (!memInput)
{
LOG("VideoCaptureProxyPin::Connect FAILED _connectedInputPin.try_query");
return VFW_E_NO_TRANSPORT;
}
auto allocator = FindAllocator();
if (allocator == nullptr)
{
LOG("VideoCaptureProxyPin::Connect FAILED FindAllocator");
return VFW_E_NO_TRANSPORT;
}
if (FAILED(memInput->NotifyAllocator(allocator.get(), false)))
{
LOG("VideoCaptureProxyPin::Connect FAILED memInput->NotifyAllocator");
return VFW_E_NO_TRANSPORT;
}
return S_OK;
}
HRESULT VideoCaptureProxyPin::ReceiveConnection(IPin*, const AM_MEDIA_TYPE*)
{
return S_OK;
}
HRESULT VideoCaptureProxyPin::Disconnect(void)
{
if (!_connectedInputPin)
{
LOG("VideoCaptureProxyPin::Disconnect FAILED _connectedInputPin");
return S_FALSE;
}
_connectedInputPin.reset();
return S_OK;
}
HRESULT VideoCaptureProxyPin::ConnectedTo(IPin** pPin)
{
if (!_connectedInputPin)
{
*pPin = nullptr;
return VFW_E_NOT_CONNECTED;
}
_connectedInputPin.try_copy_to(pPin);
return S_OK;
}
HRESULT VideoCaptureProxyPin::ConnectionMediaType(AM_MEDIA_TYPE* pmt)
{
if (!_connectedInputPin)
{
LOG("VideoCaptureProxyPin::ConnectionMediaType FAILED _connectedInputPin");
return VFW_E_NOT_CONNECTED;
}
*pmt = *CopyMediaType(_mediaFormat).release();
return S_OK;
}
HRESULT VideoCaptureProxyPin::QueryPinInfo(PIN_INFO* pInfo)
{
if (!pInfo)
{
LOG("VideoCaptureProxyPin::QueryPinInfo FAILED pInfo");
return E_POINTER;
}
pInfo->pFilter = _owningFilter;
if (_owningFilter)
{
_owningFilter->AddRef();
}
if (_mediaFormat->majortype == MEDIATYPE_Video)
{
std::copy(std::begin(PIN_NAME), std::end(PIN_NAME), pInfo->achName);
}
pInfo->dir = PINDIR_OUTPUT;
return S_OK;
}
HRESULT VideoCaptureProxyPin::QueryDirection(PIN_DIRECTION* pPinDir)
{
if (!pPinDir)
{
LOG("VideoCaptureProxyPin::QueryDirection FAILED pPinDir");
return E_POINTER;
}
*pPinDir = PINDIR_OUTPUT;
return S_OK;
}
HRESULT VideoCaptureProxyPin::QueryId(LPWSTR* Id)
{
if (!Id)
{
LOG("VideoCaptureProxyPin::QueryId FAILED Id");
return E_POINTER;
}
*Id = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(PIN_NAME)));
std::copy(std::begin(PIN_NAME), std::end(PIN_NAME), *Id);
return S_OK;
}
HRESULT VideoCaptureProxyPin::QueryAccept(const AM_MEDIA_TYPE*)
{
return S_OK;
}
HRESULT VideoCaptureProxyPin::EnumMediaTypes(IEnumMediaTypes** ppEnum)
{
if (!ppEnum)
{
LOG("VideoCaptureProxyPin::EnumMediaTypes FAILED ppEnum");
return E_POINTER;
}
auto enumerator = winrt::make_self<MediaTypeEnumerator>();
enumerator->_objects.emplace_back(CopyMediaType(_mediaFormat));
*ppEnum = enumerator.detach();
return S_OK;
}
HRESULT VideoCaptureProxyPin::QueryInternalConnections(IPin**, ULONG*)
{
return E_NOTIMPL;
}
HRESULT VideoCaptureProxyPin::EndOfStream(void)
{
return S_OK;
}
HRESULT VideoCaptureProxyPin::BeginFlush(void)
{
_flushing = true;
return S_OK;
}
HRESULT VideoCaptureProxyPin::EndFlush(void)
{
_flushing = false;
return S_OK;
}
HRESULT VideoCaptureProxyPin::NewSegment(REFERENCE_TIME, REFERENCE_TIME, double)
{
return S_OK;
}
HRESULT VideoCaptureProxyPin::SetFormat(AM_MEDIA_TYPE* pmt)
{
if (pmt == nullptr)
{
return S_OK;
}
_mediaFormat = CopyMediaType(pmt);
return S_OK;
}
HRESULT VideoCaptureProxyPin::GetFormat(AM_MEDIA_TYPE** ppmt)
{
if (!ppmt)
{
LOG("VideoCaptureProxyPin::GetFormat FAILED ppmt");
return E_POINTER;
}
*ppmt = CopyMediaType(_mediaFormat).release();
return S_OK;
}
HRESULT VideoCaptureProxyPin::GetNumberOfCapabilities(int* piCount, int* piSize)
{
if (!piCount || !piSize)
{
LOG("VideoCaptureProxyPin::GetNumberOfCapabilities FAILED piCount || piSize");
return E_POINTER;
}
*piCount = 1;
*piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
return S_OK;
}
HRESULT VideoCaptureProxyPin::GetStreamCaps(int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC)
{
if (!ppmt || !pSCC)
{
LOG("VideoCaptureProxyPin::GetStreamCaps FAILED ppmt || pSCC");
return E_POINTER;
}
if (iIndex != 0)
{
LOG("VideoCaptureProxyPin::GetStreamCaps FAILED iIndex");
return S_FALSE;
}
VIDEOINFOHEADER* vih = reinterpret_cast<decltype(vih)>(_mediaFormat->pbFormat);
VIDEO_STREAM_CONFIG_CAPS caps{};
caps.guid = FORMAT_VideoInfo;
caps.MinFrameInterval = vih->AvgTimePerFrame;
caps.MaxFrameInterval = vih->AvgTimePerFrame;
caps.MinOutputSize.cx = vih->bmiHeader.biWidth;
caps.MinOutputSize.cy = vih->bmiHeader.biHeight;
caps.MaxOutputSize = caps.MinOutputSize;
caps.InputSize = caps.MinOutputSize;
caps.MinCroppingSize = caps.MinOutputSize;
caps.MaxCroppingSize = caps.MinOutputSize;
caps.CropGranularityX = vih->bmiHeader.biWidth;
caps.CropGranularityY = vih->bmiHeader.biHeight;
caps.MinBitsPerSecond = vih->dwBitRate;
caps.MaxBitsPerSecond = caps.MinBitsPerSecond;
*ppmt = CopyMediaType(_mediaFormat).release();
const auto caps_begin = reinterpret_cast<const char*>(&caps);
std::copy(caps_begin, caps_begin + sizeof(caps), pSCC);
return S_OK;
}
HRESULT VideoCaptureProxyPin::Set(REFGUID, DWORD, LPVOID, DWORD, LPVOID, DWORD)
{
return E_NOTIMPL;
}
HRESULT VideoCaptureProxyPin::Get(
REFGUID guidPropSet,
DWORD dwPropID,
LPVOID,
DWORD,
LPVOID pPropData,
DWORD cbPropData,
DWORD* pcbReturned)
{
if (guidPropSet != AMPROPSETID_Pin)
{
LOG("VideoCaptureProxyPin::Get FAILED guidPropSet");
return E_PROP_SET_UNSUPPORTED;
}
if (dwPropID != AMPROPERTY_PIN_CATEGORY)
{
LOG("VideoCaptureProxyPin::Get FAILED dwPropID");
return E_PROP_ID_UNSUPPORTED;
}
if (!pPropData)
{
LOG("VideoCaptureProxyPin::Get FAILED pPropData || pcbReturned");
return E_POINTER;
}
if (pcbReturned)
{
*pcbReturned = sizeof(GUID);
}
if (cbPropData < sizeof(GUID))
{
LOG("VideoCaptureProxyPin::Get FAILED cbPropData");
return E_UNEXPECTED;
}
*(GUID*)pPropData = PIN_CATEGORY_CAPTURE;
LOG("VideoCaptureProxyPin::Get SUCCESS");
return S_OK;
}
HRESULT VideoCaptureProxyPin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport)
{
if (guidPropSet != AMPROPSETID_Pin)
{
LOG("VideoCaptureProxyPin::QuerySupported FAILED guidPropSet");
return E_PROP_SET_UNSUPPORTED;
}
if (dwPropID != AMPROPERTY_PIN_CATEGORY)
{
LOG("VideoCaptureProxyPin::QuerySupported FAILED dwPropID");
return E_PROP_ID_UNSUPPORTED;
}
if (pTypeSupport)
{
*pTypeSupport = KSPROPERTY_SUPPORT_GET;
}
return S_OK;
}
long GetImageSize(wil::com_ptr_nothrow<IMFSample>& image)
{
if (!image)
{
return 0;
}
DWORD imageSize = 0;
wil::com_ptr_nothrow<IMFMediaBuffer> imageBuf;
OK_OR_BAIL(image->GetBufferByIndex(0, &imageBuf));
OK_OR_BAIL(imageBuf->GetCurrentLength(&imageSize));
return imageSize;
}
void ReencodeFrame(IMediaSample* frame)
{
BYTE* frameData = nullptr;
frame->GetPointer(&frameData);
if (!frameData)
{
LOG("VideoCaptureProxyPin::ReencodeFrame FAILED frameData");
return;
}
const DWORD frameSize = frame->GetSize();
DWORD reencodedSize = 0;
if (!ReencodeJPGImage(frameData, frameSize, reencodedSize))
{
LOG("VideoCaptureProxyPin::ReencodeJPGImage FAILED");
return;
}
frame->SetActualDataLength(reencodedSize);
}
bool OverwriteFrame(IMediaSample* frame, wil::com_ptr_nothrow<IMFSample>& image)
{
if (!image)
{
return false;
}
BYTE* frameData = nullptr;
frame->GetPointer(&frameData);
if (!frameData)
{
LOG("VideoCaptureProxyPin::OverwriteFrame FAILED frameData");
return false;
}
wil::com_ptr_nothrow<IMFMediaBuffer> imageBuf;
const DWORD frameSize = frame->GetSize();
image->GetBufferByIndex(0, &imageBuf);
if (!imageBuf)
{
LOG("VideoCaptureProxyPin::OverwriteFrame FAILED imageBuf");
return false;
}
BYTE* imageData = nullptr;
DWORD _ = 0, imageSize = 0;
imageBuf->Lock(&imageData, &_, &imageSize);
if (!imageData)
{
LOG("VideoCaptureProxyPin::OverwriteFrame FAILED imageData");
return false;
}
if (imageSize > frameSize && failed(frame->SetActualDataLength(imageSize)))
{
char buf[512]{};
sprintf_s(buf, "VideoCaptureProxyPin::OverwriteFrame FAILED overlay image size %lu is larger than frame size %lu", imageSize, frameSize);
LOG(buf);
imageBuf->Unlock();
return false;
}
std::copy(imageData, imageData + imageSize, frameData);
imageBuf->Unlock();
frame->SetActualDataLength(imageSize);
return true;
}
//#define DEBUG_FRAME_DATA
//#define DEBUG_OVERWRITE_FRAME
//#define DEBUG_REENCODE_JPG_DATA
#if defined(DEBUG_OVERWRITE_FRAME)
void DebugOverwriteFrame(IMediaSample* frame, std::string_view filepath)
{
std::ifstream file{ filepath.data(), std::ios::binary };
std::streampos fileSize = 0;
fileSize = file.tellg();
file.seekg(0, std::ios::end);
fileSize = file.tellg() - fileSize;
BYTE* frameData = nullptr;
if (!frame)
{
LOG("null frame provided");
return;
}
frame->GetPointer(&frameData);
const DWORD frameSize = frame->GetSize();
if (fileSize > frameSize || !frameData)
{
LOG("frame can't be filled with data");
return;
}
file.read((char*)frameData, fileSize);
frame->SetActualDataLength((long)fileSize);
LOG("DebugOverwriteFrame success");
}
#endif
#if defined(DEBUG_FRAME_DATA)
#include <filesystem>
namespace fs = std::filesystem;
void DumpSample(IMediaSample* frame, const std::string_view filename)
{
BYTE* data = nullptr;
frame->GetPointer(&data);
if (!data)
{
LOG("Couldn't get sample pointer");
return;
}
const long nBytes = frame->GetActualDataLength();
std::ofstream file{ fs::temp_directory_path() / filename, std::ios::binary };
file.write((const char*)data, nBytes);
}
#endif
VideoCaptureProxyFilter::VideoCaptureProxyFilter() :
_worker_thread{
std::thread{
[this]() {
using namespace std::chrono_literals;
const auto uninitializedSleepInterval = 15ms;
std::vector<float> lowerJpgQualityModes = { 0.1f, 0.25f };
while (!_shutdown_request)
{
std::unique_lock<std::mutex> lock{ _worker_mutex };
_worker_cv.wait(lock, [this] { return _pending_frame != nullptr || _shutdown_request; });
if (!_outPin || !_outPin->_connectedInputPin)
{
lock.unlock();
std::this_thread::sleep_for(uninitializedSleepInterval);
continue;
}
auto input = _outPin->_connectedInputPin.try_query<IMemInputPin>();
if (!input)
{
continue;
}
IMediaSample* sample = _pending_frame;
if (!sample)
{
continue;
}
#if defined(DEBUG_FRAME_DATA)
static bool realFrameSaved = false;
if (!realFrameSaved)
{
DumpSample(sample, "PowerToysVCMRealFrame.binary");
realFrameSaved = true;
}
#endif
auto newSettings = SyncCurrentSettings();
if (newSettings.webcamDisabled)
{
#if !defined(DEBUG_OVERWRITE_FRAME)
bool overwritten = OverwriteFrame(_pending_frame, _overlayImage ? _overlayImage : _blankImage);
while (!overwritten && _overlayImage)
{
_overlayImage.reset();
newSettings = SyncCurrentSettings();
if (!lowerJpgQualityModes.empty() && newSettings.overlayImage)
{
const float quality = lowerJpgQualityModes.back();
lowerJpgQualityModes.pop_back();
char buf[512]{};
sprintf_s(buf, "Reload overlay image with quality %f", quality);
LOG(buf);
_overlayImage = LoadImageAsSample(newSettings.overlayImage, _targetMediaType.get(), quality);
overwritten = OverwriteFrame(_pending_frame, _overlayImage);
}
else
{
LOG("Couldn't overwrite frame with image with all available quality modes.");
}
}
#if defined(DEBUG_FRAME_DATA)
static bool overlayFrameSaved = false;
if (!overlayFrameSaved && _overlayImage && overwritten)
{
DumpSample(sample, "PowerToysVCMOverlayImageFrame.binary");
overlayFrameSaved = true;
}
#endif
if (!overwritten && !_overlayImage)
{
OverwriteFrame(_pending_frame, _blankImage);
}
#else
DebugOverwriteFrame(_pending_frame, "R:\\frame.data");
#endif
}
#if defined(DEBUG_REENCODE_JPG_DATA)
else
{
GUID subtype{};
_targetMediaType->GetGUID(MF_MT_SUBTYPE, &subtype);
if (subtype == MFVideoFormat_MJPG)
{
ReencodeFrame(_pending_frame);
}
}
#endif
_pending_frame = nullptr;
input->Receive(sample);
sample->Release();
}
} }
}
{
}
HRESULT VideoCaptureProxyFilter::Stop(void)
{
if (_state != State_Stopped && _captureDevice)
{
_captureDevice->StopCapture();
}
_state = State_Stopped;
return S_OK;
}
HRESULT VideoCaptureProxyFilter::Pause(void)
{
if (_state == State_Stopped)
{
std::unique_lock<std::mutex> lock{ _worker_mutex };
if (!_outPin)
{
LOG("VideoCaptureProxyPin::Pause FAILED _outPin");
return VFW_E_NO_TRANSPORT;
}
auto allocator = _outPin->FindAllocator();
if (!allocator)
{
LOG("VideoCaptureProxyPin::Pause FAILED allocator");
return VFW_E_NO_TRANSPORT;
}
allocator->Commit();
}
_state = State_Paused;
return S_OK;
}
HRESULT VideoCaptureProxyFilter::Run(REFERENCE_TIME)
{
_state = State_Running;
if (_captureDevice)
{
_captureDevice->StartCapture();
}
return S_OK;
}
HRESULT VideoCaptureProxyFilter::GetState(DWORD, FILTER_STATE* State)
{
*State = _state;
return S_OK;
}
HRESULT VideoCaptureProxyFilter::SetSyncSource(IReferenceClock* pClock)
{
_clock = pClock;
return S_OK;
}
HRESULT VideoCaptureProxyFilter::GetSyncSource(IReferenceClock** pClock)
{
if (!pClock)
{
return E_POINTER;
}
_clock.try_copy_to(pClock);
return S_OK;
}
GUID MapDShowSubtypeToMFT(const GUID& dshowSubtype)
{
if (dshowSubtype == MEDIASUBTYPE_YUY2)
{
return MFVideoFormat_YUY2;
}
else if (dshowSubtype == MEDIASUBTYPE_MJPG)
{
return MFVideoFormat_MJPG;
}
else if (dshowSubtype == MEDIASUBTYPE_RGB24)
{
return MFVideoFormat_RGB24;
}
else
{
LOG("MapDShowSubtypeToMFT: Unsupported media type format provided!");
return MFVideoFormat_MJPG;
}
}
HRESULT VideoCaptureProxyFilter::EnumPins(IEnumPins** ppEnum)
{
if (!ppEnum)
{
LOG("VideoCaptureProxyFilter::EnumPins null arg provided");
return E_POINTER;
}
std::unique_lock<std::mutex> lock{ _worker_mutex };
// We cannot initialize capture device and outpin during VideoCaptureProxyFilter ctor
// since that results in a deadlock -> initializing now.
if (!_outPin)
{
LOG("VideoCaptureProxyFilter::EnumPins started pin initialization");
const auto newSettings = SyncCurrentSettings();
std::vector<VideoCaptureDeviceInfo> webcams;
webcams = VideoCaptureDevice::ListAll();
if (webcams.empty())
{
LOG("VideoCaptureProxyFilter::EnumPins no physical webcams found");
return E_FAIL;
}
std::optional<size_t> selectedCamIdx;
for (size_t i = 0; i < size(webcams); ++i)
{
if (newSettings.newCameraName == webcams[i].friendlyName)
{
selectedCamIdx = i;
LOG("VideoCaptureProxyFilter::EnumPins webcam selected using settings");
break;
}
}
if (!selectedCamIdx)
{
for (size_t i = 0; i < size(webcams); ++i)
{
if (newSettings.newCameraName != CAMERA_NAME)
{
LOG("VideoCaptureProxyFilter::EnumPins webcam selected using first fit");
selectedCamIdx = i;
break;
}
}
}
if (!selectedCamIdx)
{
LOG("VideoCaptureProxyFilter::EnumPins FAILED webcam couldn't be selected");
return E_FAIL;
}
auto& webcam = webcams[*selectedCamIdx];
auto pin = winrt::make_self<VideoCaptureProxyPin>();
pin->_mediaFormat = CopyMediaType(webcam.bestFormat.mediaType);
pin->_owningFilter = this;
_outPin.attach(pin.detach());
auto frameCallback = [this](IMediaSample* sample) {
std::unique_lock<std::mutex> lock{ _worker_mutex };
sample->AddRef();
_pending_frame = sample;
_worker_cv.notify_one();
};
_targetMediaType.reset();
MFCreateMediaType(&_targetMediaType);
_targetMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
_targetMediaType->SetGUID(MF_MT_SUBTYPE, MapDShowSubtypeToMFT(webcam.bestFormat.mediaType->subtype));
_targetMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
_targetMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
MFSetAttributeSize(
_targetMediaType.get(), MF_MT_FRAME_SIZE, webcam.bestFormat.width, webcam.bestFormat.height);
MFSetAttributeRatio(_targetMediaType.get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
_captureDevice = VideoCaptureDevice::Create(std::move(webcam), std::move(frameCallback));
if (_captureDevice)
{
if (!_blankImage)
{
wil::com_ptr_nothrow<IStream> blackBMPImage = SHCreateMemStream(bmpPixelData, sizeof(bmpPixelData));
_blankImage = LoadImageAsSample(blackBMPImage, _targetMediaType.get(), initialJpgQuality);
}
_overlayImage = LoadImageAsSample(newSettings.overlayImage, _targetMediaType.get(), initialJpgQuality);
LOG("VideoCaptureProxyFilter::EnumPins capture device created successfully");
}
else
{
LOG("VideoCaptureProxyFilter::EnumPins FAILED couldn't create capture device");
}
}
auto enumerator = winrt::make_self<ObjectEnumerator<IPin, IEnumPins>>();
enumerator->_objects.emplace_back(_outPin);
*ppEnum = enumerator.detach();
return S_OK;
}
HRESULT VideoCaptureProxyFilter::FindPin(LPCWSTR, IPin**)
{
return E_NOTIMPL;
}
HRESULT VideoCaptureProxyFilter::QueryFilterInfo(FILTER_INFO* pInfo)
{
if (!pInfo)
{
LOG("VideoCaptureProxyPin::QueryFilterInfo FAILED pInfo");
return E_POINTER;
}
VERBOSE_LOG;
std::copy(std::begin(FILTER_NAME), std::end(FILTER_NAME), pInfo->achName);
pInfo->pGraph = _graph;
if (_graph)
{
_graph->AddRef();
}
return S_OK;
}
HRESULT VideoCaptureProxyFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR)
{
_graph = pGraph;
return S_OK;
}
HRESULT VideoCaptureProxyFilter::QueryVendorInfo(LPWSTR* pVendorInfo)
{
auto info = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(VENDOR)));
std::copy(std::begin(VENDOR), std::end(VENDOR), info);
*pVendorInfo = info;
return S_OK;
}
HRESULT VideoCaptureProxyFilter::GetClassID(CLSID*)
{
return E_NOTIMPL;
}
ULONG VideoCaptureProxyFilter::GetMiscFlags(void)
{
return AM_FILTER_MISC_FLAGS_IS_SOURCE;
}
VideoCaptureProxyFilter::~VideoCaptureProxyFilter()
{
VERBOSE_LOG;
_shutdown_request = true;
_worker_cv.notify_one();
_worker_thread.join();
}
VideoCaptureProxyFilter::SyncedSettings VideoCaptureProxyFilter::SyncCurrentSettings()
{
SyncedSettings result;
if (!_settingsUpdateChannel.has_value())
{
_settingsUpdateChannel = SerializedSharedMemory::open(CameraSettingsUpdateChannel::endpoint(), sizeof(CameraSettingsUpdateChannel), false);
}
if (!_settingsUpdateChannel)
{
return result;
}
_settingsUpdateChannel->access([this, &result](auto settingsMemory) {
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
bool cameraNameUpdated = false;
result.webcamDisabled = settings->useOverlayImage;
settings->cameraInUse = true;
if (settings->sourceCameraName.has_value())
{
std::wstring_view newCameraNameView{ settings->sourceCameraName->data() };
if (!_currentSourceCameraName.has_value() || *_currentSourceCameraName != newCameraNameView)
{
cameraNameUpdated = true;
result.newCameraName = newCameraNameView;
}
}
if (!settings->overlayImageSize.has_value())
{
return;
}
if (settings->newOverlayImagePosted || !_overlayImage)
{
auto imageChannel =
SerializedSharedMemory::open(CameraOverlayImageChannel::endpoint(), *settings->overlayImageSize, true);
if (!imageChannel)
{
return;
}
imageChannel->access([this, settings, &result](auto imageMemory) {
result.overlayImage = SHCreateMemStream(imageMemory._data, static_cast<UINT>(imageMemory._size));
if (!result.overlayImage)
{
return;
}
settings->newOverlayImagePosted = false;
});
}
});
return result;
}

View File

@ -0,0 +1,120 @@
#pragma once
#include <initguid.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dshow.h>
#include <winrt/base.h>
#include <wil/resource.h>
#include <wil/com.h>
#include <CameraStateUpdateChannels.h>
#include <SerializedSharedMemory.h>
#include "VideoCaptureDevice.h"
#include <mutex>
#include <condition_variable>
struct VideoCaptureProxyPin;
struct IMFSample;
struct IMFMediaType;
inline const wchar_t CAMERA_NAME[] = L"PowerToys VideoConference Mute";
struct VideoCaptureProxyFilter : winrt::implements<VideoCaptureProxyFilter, IBaseFilter, IAMFilterMiscFlags>
{
// BLOCK START: member accessed concurrently
wil::com_ptr_nothrow<VideoCaptureProxyPin> _outPin;
IMediaSample* _pending_frame = nullptr;
std::atomic_bool _shutdown_request = false;
std::optional<SerializedSharedMemory> _settingsUpdateChannel;
std::optional<std::wstring> _currentSourceCameraName;
wil::com_ptr_nothrow<IMFSample> _blankImage;
wil::com_ptr_nothrow<IMFSample> _overlayImage;
wil::com_ptr_nothrow<IMFMediaType> _targetMediaType;
// BLOCK END: member accessed concurrently
std::mutex _worker_mutex;
std::condition_variable _worker_cv;
FILTER_STATE _state = State_Stopped;
wil::com_ptr_nothrow<IReferenceClock> _clock;
IFilterGraph* _graph = nullptr;
std::optional<VideoCaptureDevice> _captureDevice;
std::thread _worker_thread;
VideoCaptureProxyFilter();
~VideoCaptureProxyFilter();
struct SyncedSettings
{
bool webcamDisabled = false;
std::wstring newCameraName;
wil::com_ptr_nothrow<IStream> overlayImage;
};
SyncedSettings SyncCurrentSettings();
HRESULT STDMETHODCALLTYPE Stop(void) override;
HRESULT STDMETHODCALLTYPE Pause(void) override;
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart) override;
HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State) override;
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock* pClock) override;
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock** pClock) override;
HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins** ppEnum) override;
HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin** ppPin) override;
HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO* pInfo) override;
HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName) override;
HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR* pVendorInfo) override;
HRESULT STDMETHODCALLTYPE GetClassID(CLSID* pClassID) override;
ULONG STDMETHODCALLTYPE GetMiscFlags(void) override;
};
struct VideoCaptureProxyPin : winrt::implements<VideoCaptureProxyPin, IPin, IAMStreamConfig, IKsPropertySet>
{
VideoCaptureProxyFilter* _owningFilter = nullptr;
wil::com_ptr_nothrow<IPin> _connectedInputPin;
unique_media_type_ptr _mediaFormat;
std::atomic_bool _flushing = false;
HRESULT STDMETHODCALLTYPE Connect(IPin* pReceivePin, const AM_MEDIA_TYPE* pmt) override;
HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) override;
HRESULT STDMETHODCALLTYPE Disconnect(void) override;
HRESULT STDMETHODCALLTYPE ConnectedTo(IPin** pPin) override;
HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE* pmt) override;
HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO* pInfo) override;
HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION* pPinDir) override;
HRESULT STDMETHODCALLTYPE QueryId(LPWSTR* Id) override;
HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE* pmt) override;
HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes** ppEnum) override;
HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin** apPin, ULONG* nPin) override;
HRESULT STDMETHODCALLTYPE EndOfStream(void) override;
HRESULT STDMETHODCALLTYPE BeginFlush(void) override;
HRESULT STDMETHODCALLTYPE EndFlush(void) override;
HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) override;
HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE* pmt) override;
HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE** ppmt) override;
HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int* piCount, int* piSize) override;
HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC) override;
HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData) override;
HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData,
DWORD* pcbReturned) override;
HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport) override;
wil::com_ptr_nothrow<IMemAllocator> FindAllocator();
};

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{AC2857B4-103D-4D6D-9740-926EBF785042}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>VideoConferenceProxyFilter</RootNamespace>
<ProjectName>VideoConferenceProxyFilter</ProjectName>
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)\src\;$(ProjectDir)..\..\..\</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\src\;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
<Lib>
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
</Lib>
<PreBuildEvent Condition="'$(Platform)'=='x64'">
<Command>call "$(ProjectDir)build_vcm_x86.cmd"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<PropertyGroup Condition="'$(Platform)'!='Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
<TargetName>VideoConferenceProxyFilter_x64</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'">
<OutDir>..\..\..\..\x86\$(Configuration)\modules\VideoConference\</OutDir>
<TargetName>VideoConferenceProxyFilter_x86</TargetName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\VideoConferenceShared\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MultiThreaded</RuntimeLibrary>
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>$(OutDir)VideoConferenceShared.lib;mfplat.lib;Mfsensorgroup.lib;OneCoreUAP.lib;Mf.lib;Shlwapi.lib;Strmiids.lib;%(AdditionalDependencies);</AdditionalDependencies>
<ModuleDefinitionFile>module.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="DirectShowUtils.h" />
<ClInclude Include="VideoCaptureDevice.h" />
<ClInclude Include="VideoCaptureProxyFilter.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="DirectShowUtils.cpp" />
<ClCompile Include="VideoCaptureDevice.cpp" />
<ClCompile Include="VideoCaptureProxyFilter.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="ImageLoading.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="module.def" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VideoConferenceShared\VideoConferenceShared.vcxproj">
<Project>{459e0768-7ebd-4c41-bba1-6db3b3815e0a}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,41 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30907.101
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter", "VideoConferenceProxyFilter.vcxproj", "{AC2857B4-103D-4D6D-9740-926EBF785042}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceShared", "..\VideoConferenceShared\VideoConferenceShared.vcxproj", "{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|Win32.ActiveCfg = Debug|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|Win32.Build.0 = Debug|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.ActiveCfg = Debug|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.Build.0 = Debug|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|Win32.ActiveCfg = Release|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|Win32.Build.0 = Release|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.ActiveCfg = Release|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|Win32.ActiveCfg = Debug|Win32
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|Win32.Build.0 = Debug|Win32
{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|Win32.ActiveCfg = Release|Win32
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|Win32.Build.0 = Release|Win32
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0E41348C-22CB-45A4-8A16-8D7BEA070BB2}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,3 @@
msbuild VideoConferenceProxyFilterx86.sln -p:Configuration="Release" -p:Platform="Win32"
exit 0

View File

@ -0,0 +1,242 @@
#include "VideoCaptureProxyFilter.h"
#include <winrt/base.h>
#include <wil/registry.h>
#include <cguid.h>
namespace
{
#if defined(_WIN64)
class __declspec(uuid("{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}")) GUID_DECL_POWERTOYS_VCM;
#elif defined(_WIN32)
class __declspec(uuid("{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}")) GUID_DECL_POWERTOYS_VCM;
#endif
const GUID CLSID_POWERTOYS_VCM = __uuidof(GUID_DECL_POWERTOYS_VCM);
const REGPINTYPES MEDIA_TYPES = { &MEDIATYPE_Video, &MEDIASUBTYPE_MJPG };
const wchar_t FILTER_NAME[] = L"Output";
const REGFILTERPINS PINS_REGISTRATION = {
(wchar_t*)FILTER_NAME,
false,
true,
false,
false,
&CLSID_NULL,
nullptr,
1,
&MEDIA_TYPES
};
HINSTANCE DLLInstance{};
}
struct __declspec(uuid("9DCAF869-9C13-4BDF-BD0D-3592C5579DD6")) VideoCaptureProxyFilterFactory : winrt::implements<VideoCaptureProxyFilterFactory, IClassFactory>
{
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown*, REFIID riid, void** ppvObject) noexcept override
{
try
{
return winrt::make<VideoCaptureProxyFilter>()->QueryInterface(riid, ppvObject);
}
catch (...)
{
return winrt::to_hresult();
}
}
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) noexcept override
{
if (fLock)
{
++winrt::get_module_lock();
}
else
{
--winrt::get_module_lock();
}
return S_OK;
}
};
HRESULT STDMETHODCALLTYPE DllCanUnloadNow()
{
if (winrt::get_module_lock())
{
return S_FALSE;
}
winrt::clear_factory_cache();
return S_OK;
}
HRESULT STDMETHODCALLTYPE DllGetClassObject(GUID const& clsid, GUID const& iid, void** result)
{
if (!result)
{
return E_POINTER;
}
if (iid != IID_IClassFactory && iid != IID_IUnknown)
{
return E_NOINTERFACE;
}
if (clsid != CLSID_POWERTOYS_VCM)
{
return E_INVALIDARG;
}
try
{
*result = nullptr;
auto factory = winrt::make<VideoCaptureProxyFilterFactory>();
factory->AddRef();
*result = static_cast<void*>(factory.get());
return S_OK;
}
catch (...)
{
return winrt::to_hresult();
}
}
std::wstring RegistryPath()
{
std::wstring registryPath;
registryPath.resize(CHARS_IN_GUID, L'\0');
StringFromGUID2(CLSID_POWERTOYS_VCM, registryPath.data(), CHARS_IN_GUID);
registryPath.resize(registryPath.size() - 1);
registryPath = L"CLSID\\" + registryPath;
return registryPath;
}
bool RegisterServer()
{
std::wstring dllPath;
dllPath.resize(MAX_PATH, L'\0');
if (auto length = GetModuleFileNameW(DLLInstance, dllPath.data(), MAX_PATH); length != 0)
{
dllPath.resize(length);
}
else
{
return false;
}
wil::unique_hkey key;
wil::unique_hkey subkey;
const auto registryPath = RegistryPath();
if (RegCreateKeyW(HKEY_CLASSES_ROOT, registryPath.c_str(), &key))
{
return false;
}
if (RegSetValueW(key.get(), nullptr, REG_SZ, CAMERA_NAME, sizeof(CAMERA_NAME)))
{
return false;
}
if (RegCreateKeyW(key.get(), L"InprocServer32", &subkey))
{
return false;
}
if (RegSetValueW(subkey.get(), nullptr, REG_SZ, dllPath.c_str(), static_cast<DWORD>((dllPath.length() + 1) * sizeof(wchar_t))))
{
return false;
}
const wchar_t THREADING_MODEL[] = L"Both";
RegSetValueExW(subkey.get(), L"ThreadingModel", 0, REG_SZ, (const BYTE*)THREADING_MODEL, sizeof(THREADING_MODEL));
return true;
}
bool UnregisterServer()
{
const auto registryPath = RegistryPath();
return !RegDeleteTreeW(HKEY_CLASSES_ROOT, registryPath.c_str());
}
bool RegisterFilter()
{
auto filterMapper = wil::CoCreateInstanceNoThrow<IFilterMapper2>(CLSID_FilterMapper2);
if (!filterMapper)
{
return false;
}
REGFILTER2 regFilter{ .dwVersion = 1, .dwMerit = MERIT_DO_NOT_USE, .cPins = 1, .rgPins = &PINS_REGISTRATION };
wil::com_ptr_nothrow<IMoniker> moniker;
return SUCCEEDED(filterMapper->RegisterFilter(
CLSID_POWERTOYS_VCM, CAMERA_NAME, &moniker, &CLSID_VideoInputDeviceCategory, nullptr, &regFilter));
}
bool UnregisterFilter()
{
auto filterMapper = wil::CoCreateInstanceNoThrow<IFilterMapper2>(CLSID_FilterMapper2);
if (!filterMapper)
{
return false;
}
return SUCCEEDED(filterMapper->UnregisterFilter(&CLSID_VideoInputDeviceCategory, nullptr, CLSID_POWERTOYS_VCM));
}
HRESULT STDMETHODCALLTYPE DllRegisterServer()
{
if (!RegisterServer())
{
UnregisterServer();
return E_FAIL;
}
auto COMContext = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);
if (!RegisterFilter())
{
UnregisterFilter();
UnregisterServer();
return E_FAIL;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE DllUnregisterServer()
{
auto COMContext = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);
UnregisterFilter();
UnregisterServer();
return S_OK;
}
HRESULT STDMETHODCALLTYPE DllInstall(BOOL install, LPCWSTR)
{
if (install)
{
return DllRegisterServer();
}
else
{
return DllUnregisterServer();
}
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
DLLInstance = hinstDLL;
}
return true;
}

View File

@ -0,0 +1,7 @@
EXPORTS
DllMain PRIVATE
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
DllInstall PRIVATE

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" />
</packages>

View File

@ -0,0 +1,15 @@
#include "CameraStateUpdateChannels.h"
#include "naming.h"
std::wstring_view CameraOverlayImageChannel::endpoint()
{
static const std::wstring endpoint = ObtainStableGlobalNameForKernelObject(L"PowerToysVideoConferenceCameraOverlayImageChannelSharedMemory", true);
return endpoint;
}
std::wstring_view CameraSettingsUpdateChannel::endpoint()
{
static const std::wstring endpoint = ObtainStableGlobalNameForKernelObject(L"PowerToysVideoConferenceSettingsChannelSharedMemory", true);
return endpoint;
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <optional>
#include <string_view>
#include <array>
struct alignas(16) CameraSettingsUpdateChannel
{
bool useOverlayImage = false;
bool cameraInUse = false;
std::optional<uint32_t> overlayImageSize;
std::optional<std::array<wchar_t, 256>> sourceCameraName;
bool newOverlayImagePosted = false;
static std::wstring_view endpoint();
};
namespace CameraOverlayImageChannel
{
std::wstring_view endpoint();
}

View File

@ -0,0 +1,203 @@
#include "Logging.h"
#include <iostream>
#include <fstream>
#include <mutex>
#include <iomanip>
#include <chrono>
#include <filesystem>
#include <mfapi.h>
#pragma warning(disable : 4127)
static std::mutex logMutex;
constexpr inline size_t maxLogSizeMegabytes = 10;
constexpr inline bool alwaysLogVerbose = true;
void LogToFile(std::wstring what, const bool verbose)
{
std::error_code _;
const auto tempPath = std::filesystem::temp_directory_path(_);
if (verbose)
{
const bool verboseIndicatorFilePresent = std::filesystem::exists(tempPath / L"PowerToysVideoConferenceVerbose.flag", _);
if (!alwaysLogVerbose && !verboseIndicatorFilePresent)
{
return;
}
}
time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm tm;
localtime_s(&tm, &now);
char prefix[64];
const auto pid = GetCurrentProcessId();
const auto iter = prefix + sprintf_s(prefix, "[%ld]", pid);
std::strftime(iter, sizeof(prefix) - (prefix - iter), "[%d.%m %H:%M:%S] ", &tm);
std::lock_guard lock{ logMutex };
std::wstring logFilePath = tempPath;
#if defined(_WIN64)
logFilePath += L"\\PowerToysVideoConference_x64.log";
#elif defined(_WIN32)
logFilePath += L"\\PowerToysVideoConference_x86.log";
#endif
size_t logSizeMBs = 0;
try
{
logSizeMBs = static_cast<size_t>(std::filesystem::file_size(logFilePath) >> 20);
}
catch (...)
{
}
if (logSizeMBs > maxLogSizeMegabytes)
{
std::error_code __;
// Truncate the log file to zero
std::filesystem::resize_file(logFilePath, 0, __);
}
std::wofstream myfile;
myfile.open(logFilePath, std::fstream::app);
static const auto newLaunch = [&] {
myfile << prefix << "\n\n<<<NEW SESSION>>";
return 0;
}();
myfile << prefix << what << "\n";
myfile.close();
}
void LogToFile(std::string what, const bool verbose)
{
std::wstring native{ begin(what), end(what) };
LogToFile(std::move(native), verbose);
}
std::string toMediaTypeString(GUID subtype)
{
if (subtype == MFVideoFormat_YUY2)
return "MFVideoFormat_YUY2";
else if (subtype == MFVideoFormat_RGB32)
return "MFVideoFormat_RGB32";
else if (subtype == MFVideoFormat_RGB24)
return "MFVideoFormat_RGB24";
else if (subtype == MFVideoFormat_ARGB32)
return "MFVideoFormat_ARGB32";
else if (subtype == MFVideoFormat_RGB555)
return "MFVideoFormat_RGB555";
else if (subtype == MFVideoFormat_RGB565)
return "MFVideoFormat_RGB565";
else if (subtype == MFVideoFormat_RGB8)
return "MFVideoFormat_RGB8";
else if (subtype == MFVideoFormat_L8)
return "MFVideoFormat_L8";
else if (subtype == MFVideoFormat_L16)
return "MFVideoFormat_L16";
else if (subtype == MFVideoFormat_D16)
return "MFVideoFormat_D16";
else if (subtype == MFVideoFormat_AYUV)
return "MFVideoFormat_AYUV";
else if (subtype == MFVideoFormat_YUY2)
return "MFVideoFormat_YUY2";
else if (subtype == MFVideoFormat_YVYU)
return "MFVideoFormat_YVYU";
else if (subtype == MFVideoFormat_YVU9)
return "MFVideoFormat_YVU9";
else if (subtype == MFVideoFormat_UYVY)
return "MFVideoFormat_UYVY";
else if (subtype == MFVideoFormat_NV11)
return "MFVideoFormat_NV11";
else if (subtype == MFVideoFormat_NV12)
return "MFVideoFormat_NV12";
else if (subtype == MFVideoFormat_YV12)
return "MFVideoFormat_YV12";
else if (subtype == MFVideoFormat_I420)
return "MFVideoFormat_I420";
else if (subtype == MFVideoFormat_IYUV)
return "MFVideoFormat_IYUV";
else if (subtype == MFVideoFormat_Y210)
return "MFVideoFormat_Y210";
else if (subtype == MFVideoFormat_Y216)
return "MFVideoFormat_Y216";
else if (subtype == MFVideoFormat_Y410)
return "MFVideoFormat_Y410";
else if (subtype == MFVideoFormat_Y416)
return "MFVideoFormat_Y416";
else if (subtype == MFVideoFormat_Y41P)
return "MFVideoFormat_Y41P";
else if (subtype == MFVideoFormat_Y41T)
return "MFVideoFormat_Y41T";
else if (subtype == MFVideoFormat_Y42T)
return "MFVideoFormat_Y42T";
else if (subtype == MFVideoFormat_P210)
return "MFVideoFormat_P210";
else if (subtype == MFVideoFormat_P216)
return "MFVideoFormat_P216";
else if (subtype == MFVideoFormat_P010)
return "MFVideoFormat_P010";
else if (subtype == MFVideoFormat_P016)
return "MFVideoFormat_P016";
else if (subtype == MFVideoFormat_v210)
return "MFVideoFormat_v210";
else if (subtype == MFVideoFormat_v216)
return "MFVideoFormat_v216";
else if (subtype == MFVideoFormat_v410)
return "MFVideoFormat_v410";
else if (subtype == MFVideoFormat_MP43)
return "MFVideoFormat_MP43";
else if (subtype == MFVideoFormat_MP4S)
return "MFVideoFormat_MP4S";
else if (subtype == MFVideoFormat_M4S2)
return "MFVideoFormat_M4S2";
else if (subtype == MFVideoFormat_MP4V)
return "MFVideoFormat_MP4V";
else if (subtype == MFVideoFormat_WMV1)
return "MFVideoFormat_WMV1";
else if (subtype == MFVideoFormat_WMV2)
return "MFVideoFormat_WMV2";
else if (subtype == MFVideoFormat_WMV3)
return "MFVideoFormat_WMV3";
else if (subtype == MFVideoFormat_WVC1)
return "MFVideoFormat_WVC1";
else if (subtype == MFVideoFormat_MSS1)
return "MFVideoFormat_MSS1";
else if (subtype == MFVideoFormat_MSS2)
return "MFVideoFormat_MSS2";
else if (subtype == MFVideoFormat_MPG1)
return "MFVideoFormat_MPG1";
else if (subtype == MFVideoFormat_DVSL)
return "MFVideoFormat_DVSL";
else if (subtype == MFVideoFormat_DVSD)
return "MFVideoFormat_DVSD";
else if (subtype == MFVideoFormat_DVHD)
return "MFVideoFormat_DVHD";
else if (subtype == MFVideoFormat_DV25)
return "MFVideoFormat_DV25";
else if (subtype == MFVideoFormat_DV50)
return "MFVideoFormat_DV50";
else if (subtype == MFVideoFormat_DVH1)
return "MFVideoFormat_DVH1";
else if (subtype == MFVideoFormat_DVC)
return "MFVideoFormat_DVC";
else if (subtype == MFVideoFormat_H264)
return "MFVideoFormat_H264";
else if (subtype == MFVideoFormat_H265)
return "MFVideoFormat_H265";
else if (subtype == MFVideoFormat_MJPG)
return "MFVideoFormat_MJPG";
else if (subtype == MFVideoFormat_420O)
return "MFVideoFormat_420O";
else if (subtype == MFVideoFormat_HEVC)
return "MFVideoFormat_HEVC";
else if (subtype == MFVideoFormat_HEVC_ES)
return "MFVideoFormat_HEVC_ES";
else if (subtype == MFVideoFormat_VP80)
return "MFVideoFormat_VP80";
else if (subtype == MFVideoFormat_VP90)
return "MFVideoFormat_VP90";
else if (subtype == MFVideoFormat_ORAW)
return "MFVideoFormat_ORAW";
else
return "Other VideoFormat";
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <string>
#include <guiddef.h>
#include <system_error>
#include <wil/com.h>
#include <Windows.h>
void LogToFile(std::string what, const bool verbose = false);
void LogToFile(std::wstring what, const bool verbose = false);
std::string toMediaTypeString(GUID subtype);
#define RETURN_IF_FAILED_WITH_LOGGING(val) \
hr = (val); \
if (FAILED(hr)) \
{ \
LogToFile(std::string(__FUNCTION__ "() ") + #val + ": " + std::system_category().message(hr)); \
return hr; \
}
#define RETURN_NULLPTR_IF_FAILED_WITH_LOGGING(val) \
hr = val; \
if (FAILED(hr)) \
{ \
LogToFile(std::string(__FUNCTION__ "() ") + #val + ": " + std::system_category().message(hr)); \
return nullptr; \
}
#define VERBOSE_LOG \
std::string functionNameTMPVAR = __FUNCTION__; \
LogToFile(std::string(functionNameTMPVAR + " enter"), true); \
auto verboseLogOnScopeEnd = wil::scope_exit([&] { \
LogToFile(std::string(functionNameTMPVAR + " exit"), true); \
});
#if defined(PowerToysInterop)
#undef LOG
#define LOG(...)
#else
#define LOG(str) LogToFile(str, false);
#endif
inline bool failed(HRESULT hr)
{
return hr != S_OK;
}
inline bool failed(bool val)
{
return val == false;
}
template<typename T>
inline bool failed(wil::com_ptr_nothrow<T>& ptr)
{
return ptr == nullptr;
}
#define OK_OR_BAIL(expr) \
if (failed(expr)) \
return {};

View File

@ -0,0 +1,152 @@
#include "MicrophoneDevice.h"
#include "Logging.h"
#include <Functiondiscoverykeys_devpkey.h>
MicrophoneDevice::MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint) :
_device{ std::move(device) },
_endpoint{ std::move(endpoint) }
{
if (!_device || !_endpoint)
{
throw std::logic_error("MicrophoneDevice was initialized with null objects");
}
_device->GetId(&_id);
wil::com_ptr_nothrow<IPropertyStore> props;
_device->OpenPropertyStore(
STGM_READ, &props);
if (props)
{
props->GetValue(PKEY_Device_FriendlyName, &_friendly_name);
}
else
{
LOG("MicrophoneDevice::MicrophoneDevice couldn't open property store");
}
}
MicrophoneDevice::~MicrophoneDevice()
{
if (_notifier)
{
_endpoint->UnregisterControlChangeNotify(_notifier.get());
}
}
bool MicrophoneDevice::active() const noexcept
{
DWORD state = 0;
_device->GetState(&state);
return state == DEVICE_STATE_ACTIVE;
}
void MicrophoneDevice::set_muted(const bool muted) noexcept
{
_endpoint->SetMute(muted, nullptr);
}
bool MicrophoneDevice::muted() const noexcept
{
BOOL muted = FALSE;
_endpoint->GetMute(&muted);
return muted;
}
void MicrophoneDevice::toggle_muted() noexcept
{
set_muted(!muted());
}
std::wstring_view MicrophoneDevice::id() const noexcept
{
return _id ? _id.get() : FALLBACK_ID;
}
std::wstring_view MicrophoneDevice::name() const noexcept
{
return _friendly_name.pwszVal ? _friendly_name.pwszVal : FALLBACK_NAME;
}
void MicrophoneDevice::set_mute_changed_callback(mute_changed_cb_t callback) noexcept
{
_mute_changed_callback = std::move(callback);
_notifier = winrt::make<VolumeNotifier>(this);
_endpoint->RegisterControlChangeNotify(_notifier.get());
}
std::optional<MicrophoneDevice> MicrophoneDevice::getDefault()
{
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
if (!deviceEnumerator)
{
LOG("MicrophoneDevice::getDefault MMDeviceEnumerator returned null");
return std::nullopt;
}
wil::com_ptr_nothrow<IMMDevice> captureDevice;
deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &captureDevice);
if (!captureDevice)
{
LOG("MicrophoneDevice::getDefault captureDevice is null");
return std::nullopt;
}
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
captureDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(&microphoneEndpoint));
if (!microphoneEndpoint)
{
LOG("MicrophoneDevice::getDefault captureDevice is null");
return std::nullopt;
}
return std::make_optional<MicrophoneDevice>(std::move(captureDevice), std::move(microphoneEndpoint));
}
std::vector<MicrophoneDevice> MicrophoneDevice::getAllActive()
{
std::vector<MicrophoneDevice> microphoneDevices;
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
if (!deviceEnumerator)
{
LOG("MicrophoneDevice::getAllActive MMDeviceEnumerator returned null");
return microphoneDevices;
}
wil::com_ptr_nothrow<IMMDeviceCollection> captureDevices;
deviceEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &captureDevices);
if (!captureDevices)
{
LOG("MicrophoneDevice::getAllActive EnumAudioEndpoints returned null");
return microphoneDevices;
}
UINT nDevices = 0;
captureDevices->GetCount(&nDevices);
microphoneDevices.reserve(nDevices);
for (UINT i = 0; i < nDevices; ++i)
{
wil::com_ptr_nothrow<IMMDevice> device;
captureDevices->Item(i, &device);
if (!device)
{
continue;
}
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(&microphoneEndpoint));
if (!microphoneEndpoint)
{
continue;
}
microphoneDevices.emplace_back(std::move(device), std::move(microphoneEndpoint));
}
return microphoneDevices;
}
MicrophoneDevice::VolumeNotifier::VolumeNotifier(MicrophoneDevice* subscribedDevice) :
_subscribedDevice{ subscribedDevice }
{
}
HRESULT __stdcall MicrophoneDevice::VolumeNotifier::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data)
{
_subscribedDevice->_mute_changed_callback(data->bMuted);
return S_OK;
}

View File

@ -0,0 +1,65 @@
#pragma once
#define NOMINMAX
#include <Windows.h>
#include <Unknwn.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <wil/resource.h>
#include <wil/com.h>
#include <string_view>
#include <optional>
#include <vector>
#include <functional>
#include <Mmdeviceapi.h>
#include <Endpointvolume.h>
class MicrophoneDevice
{
public:
using mute_changed_cb_t = std::function<void(bool muted)>;
private:
friend struct VolumeNotifier;
struct VolumeNotifier : winrt::implements<VolumeNotifier, IAudioEndpointVolumeCallback>
{
MicrophoneDevice* _subscribedDevice = nullptr;
VolumeNotifier(MicrophoneDevice* subscribedDevice);
virtual HRESULT __stdcall OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data) override;
};
wil::unique_cotaskmem_string _id;
wil::unique_prop_variant _friendly_name;
mute_changed_cb_t _mute_changed_callback;
winrt::com_ptr<IAudioEndpointVolumeCallback> _notifier;
wil::com_ptr_nothrow<IAudioEndpointVolume> _endpoint;
wil::com_ptr_nothrow<IMMDevice> _device;
constexpr static inline std::wstring_view FALLBACK_NAME = L"Unknown device";
constexpr static inline std::wstring_view FALLBACK_ID = L"UNKNOWN_ID";
public:
MicrophoneDevice(MicrophoneDevice&&) noexcept = default;
MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint);
~MicrophoneDevice();
bool active() const noexcept;
void set_muted(const bool muted) noexcept;
bool muted() const noexcept;
void toggle_muted() noexcept;
std::wstring_view id() const noexcept;
std::wstring_view name() const noexcept;
void set_mute_changed_callback(mute_changed_cb_t callback) noexcept;
static std::optional<MicrophoneDevice> getDefault();
static std::vector<MicrophoneDevice> getAllActive();
};

View File

@ -0,0 +1,188 @@
#include "SerializedSharedMemory.h"
inline char* SerializedSharedMemory::lock_flag_addr() noexcept
{
return reinterpret_cast<char*>(_memory._data + _memory._size);
}
inline void SerializedSharedMemory::lock() noexcept
{
if (_read_only)
{
return;
}
while (LOCKED == _InterlockedCompareExchange8(lock_flag_addr(), LOCKED, !LOCKED))
{
while (*lock_flag_addr() == LOCKED)
{
_mm_pause();
}
}
}
inline void SerializedSharedMemory::unlock() noexcept
{
if (_read_only)
{
return;
}
_InterlockedExchange8(lock_flag_addr(), !LOCKED);
}
SerializedSharedMemory::SerializedSharedMemory(std::array<wil::unique_handle, 2> handles,
memory_t memory,
const bool readonly) noexcept
:
_handles{ std::move(handles) }, _memory{ std::move(memory) }, _read_only(readonly)
{
}
SerializedSharedMemory::~SerializedSharedMemory() noexcept
{
if (_memory._data)
{
UnmapViewOfFile(_memory._data);
}
}
SerializedSharedMemory::SerializedSharedMemory(SerializedSharedMemory&& rhs) noexcept
{
*this = std::move(rhs);
}
SerializedSharedMemory& SerializedSharedMemory::operator=(SerializedSharedMemory&& rhs) noexcept
{
_handles = {};
_handles.swap(rhs._handles);
_memory = std::move(rhs._memory);
rhs._memory = {};
_read_only = rhs._read_only;
rhs._read_only = true;
return *this;
}
std::optional<SerializedSharedMemory> SerializedSharedMemory::create(const std::wstring_view object_name,
const size_t size,
const bool read_only,
SECURITY_ATTRIBUTES* maybe_attributes) noexcept
{
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa = { sizeof SECURITY_ATTRIBUTES };
if (!maybe_attributes)
{
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = false;
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) ||
!SetSecurityDescriptorDacl(&sd, true, nullptr, false))
{
return std::nullopt;
}
}
// We need an extra byte for locking if it's not readonly
const ULARGE_INTEGER UISize{ .QuadPart = size + !read_only };
wil::unique_handle hMapFile{ CreateFileMappingW(INVALID_HANDLE_VALUE,
maybe_attributes ? maybe_attributes : &sa,
read_only ? PAGE_READONLY : PAGE_READWRITE,
UISize.HighPart,
UISize.LowPart,
object_name.data()) };
if (!hMapFile)
{
return std::nullopt;
}
auto shmem = static_cast<uint8_t*>(
MapViewOfFile(hMapFile.get(), read_only ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, static_cast<SIZE_T>(UISize.QuadPart)));
if (!shmem)
{
return std::nullopt;
}
std::array<wil::unique_handle, 2> handles = { std::move(hMapFile), {} };
return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, size }, read_only };
}
std::optional<SerializedSharedMemory> SerializedSharedMemory::open(const std::wstring_view object_name,
const size_t size,
const bool read_only) noexcept
{
wil::unique_handle hMapFile{ OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, object_name.data()) };
if (!hMapFile)
{
return std::nullopt;
}
auto shmem = static_cast<uint8_t*>(
MapViewOfFile(hMapFile.get(), read_only ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size + !read_only));
if (!shmem)
{
return std::nullopt;
}
std::array<wil::unique_handle, 2> handles = { std::move(hMapFile), {} };
return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, size }, read_only };
}
std::optional<SerializedSharedMemory> SerializedSharedMemory::create_readonly(
const std::wstring_view object_name,
const std::wstring_view file_path,
SECURITY_ATTRIBUTES* maybe_attributes) noexcept
{
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa = { sizeof SECURITY_ATTRIBUTES };
if (!maybe_attributes)
{
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = false;
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) ||
!SetSecurityDescriptorDacl(&sd, true, nullptr, false))
{
return std::nullopt;
}
}
wil::unique_handle hFile{ CreateFileW(file_path.data(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
maybe_attributes ? maybe_attributes : &sa,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr) };
if (!hFile)
{
return std::nullopt;
}
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(hFile.get(), &fileSize))
{
return std::nullopt;
}
wil::unique_handle hMapFile{ CreateFileMappingW(hFile.get(),
maybe_attributes ? maybe_attributes : &sa,
PAGE_READONLY,
fileSize.HighPart,
fileSize.LowPart,
object_name.data()) };
if (!hMapFile)
{
return std::nullopt;
}
auto shmem = static_cast<uint8_t*>(MapViewOfFile(nullptr, FILE_MAP_READ, 0, 0, static_cast<size_t>(fileSize.QuadPart)));
if (shmem)
{
return std::nullopt;
}
std::array<wil::unique_handle, 2> handles = { std::move(hMapFile), std::move(hFile) };
return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, static_cast<size_t>(fileSize.QuadPart) }, true };
}
void SerializedSharedMemory::access(std::function<void(memory_t)> access_routine) noexcept
{
lock();
access_routine(_memory);
unlock();
}

View File

@ -0,0 +1,54 @@
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <string>
#include <optional>
#include <wil/resource.h>
#include <functional>
#include <array>
// Wrapper class allowing sharing readonly/writable memory with a serialized access via atomic locking.
// Note that it doesn't protect against a 3rd party concurrently modifying physical file contents.
class SerializedSharedMemory
{
public:
struct memory_t
{
uint8_t * _data = nullptr;
size_t _size = 0;
};
static std::optional<SerializedSharedMemory> create(const std::wstring_view object_name,
const size_t size,
const bool read_only,
SECURITY_ATTRIBUTES* maybe_attributes = nullptr) noexcept;
static std::optional<SerializedSharedMemory> create_readonly(
const std::wstring_view object_name,
const std::wstring_view file_path,
SECURITY_ATTRIBUTES* maybe_attributes = nullptr) noexcept;
static std::optional<SerializedSharedMemory> open(const std::wstring_view object_name,
const size_t size,
const bool read_only) noexcept;
void access(std::function<void(memory_t)> access_routine) noexcept;
inline size_t size() const noexcept { return _memory._size; }
~SerializedSharedMemory() noexcept;
SerializedSharedMemory(SerializedSharedMemory&&) noexcept;
SerializedSharedMemory& operator=(SerializedSharedMemory&&) noexcept;
private:
std::array<wil::unique_handle, 2> _handles;
memory_t _memory;
bool _read_only = true;
constexpr static inline int64_t LOCKED = 1;
char* lock_flag_addr() noexcept;
void lock() noexcept;
void unlock() noexcept;
SerializedSharedMemory(std::array<wil::unique_handle, 2> handles, memory_t memory, const bool readonly) noexcept;
};

View File

@ -0,0 +1,100 @@
#include "VideoCaptureDeviceList.h"
#include "Logging.h"
#include <mfapi.h>
#include <Mfidl.h>
#include <wil/resource.h>
#include <wil/com.h>
void VideoCaptureDeviceList::Clear()
{
for (UINT32 i = 0; i < m_numberDevices; i++)
{
CoTaskMemFree(m_deviceFriendlyNames[i]);
if (m_ppDevices[i])
{
m_ppDevices[i]->Release();
}
}
CoTaskMemFree(m_ppDevices);
m_ppDevices = nullptr;
if (m_deviceFriendlyNames)
{
delete[] m_deviceFriendlyNames;
}
m_deviceFriendlyNames = nullptr;
m_numberDevices = 0;
}
HRESULT VideoCaptureDeviceList::EnumerateDevices()
{
HRESULT hr = S_OK;
wil::com_ptr<IMFAttributes> pAttributes;
Clear();
// Initialize an attribute store. We will use this to
// specify the enumeration parameters.
hr = MFCreateAttributes(&pAttributes, 1);
// Ask for source type = video capture devices
if (SUCCEEDED(hr))
{
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
}
else
{
LOG("VideoCaptureDeviceList::EnumerateDevices(): Couldn't MFCreateAttributes");
}
// Enumerate devices.
if (SUCCEEDED(hr))
{
hr = MFEnumDeviceSources(pAttributes.get(), &m_ppDevices, &m_numberDevices);
}
else
{
LOG("VideoCaptureDeviceList::EnumerateDevices(): Couldn't SetGUID");
}
if (FAILED(hr))
{
LOG("VideoCaptureDeviceList::EnumerateDevices(): MFEnumDeviceSources failed");
return hr;
}
m_deviceFriendlyNames = new (std::nothrow) wchar_t*[m_numberDevices];
for (UINT32 i = 0; i < m_numberDevices; i++)
{
UINT32 nameLength = 0;
m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &m_deviceFriendlyNames[i], &nameLength);
}
return hr;
}
HRESULT VideoCaptureDeviceList::GetDevice(UINT32 index, IMFActivate** ppActivate)
{
if (index >= Count())
{
return E_INVALIDARG;
}
*ppActivate = m_ppDevices[index];
(*ppActivate)->AddRef();
return S_OK;
}
std::wstring_view VideoCaptureDeviceList::GetDeviceName(UINT32 index)
{
if (index >= Count())
{
return {};
}
return m_deviceFriendlyNames[index];
}

View File

@ -0,0 +1,33 @@
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <mfobjects.h>
#include <string_view>
class VideoCaptureDeviceList
{
UINT32 m_numberDevices;
// TODO: use wil
IMFActivate** m_ppDevices = nullptr;
wchar_t** m_deviceFriendlyNames = nullptr;
public:
VideoCaptureDeviceList() :
m_ppDevices(NULL), m_numberDevices(0)
{
}
~VideoCaptureDeviceList()
{
Clear();
}
UINT32 Count() const { return m_numberDevices; }
void Clear();
HRESULT EnumerateDevices();
HRESULT GetDevice(UINT32 index, IMFActivate** ppActivate);
std::wstring_view GetDeviceName(UINT32 index);
};

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>mfplat.lib;Mfsensorgroup.lib;OneCoreUAP.lib;Mf.lib;Shlwapi.lib;Strmiids.lib;%(AdditionalDependencies);</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{459e0768-7ebd-4c41-bba1-6db3b3815e0a}</ProjectGuid>
<RootNamespace>VideoConferenceShared</RootNamespace>
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Platform)'!='Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'">
<OutDir>..\..\..\..\x86\$(Configuration)\modules\VideoConference\</OutDir>
<IntDir>..\..\..\..\x86\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalIncludeDirectories>$(SolutionDir)\src\;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalIncludeDirectories>$(SolutionDir)\src\;</AdditionalIncludeDirectories>
<DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CameraStateUpdateChannels.cpp" />
<ClCompile Include="Logging.cpp" />
<ClCompile Include="SerializedSharedMemory.cpp" />
<ClCompile Include="naming.cpp" />
<ClCompile Include="username.cpp" />
<ClCompile Include="MicrophoneDevice.cpp" />
<ClCompile Include="VideoCaptureDeviceList.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CameraStateUpdateChannels.h" />
<ClInclude Include="Logging.h" />
<ClInclude Include="SerializedSharedMemory.h" />
<ClInclude Include="naming.h" />
<ClInclude Include="MicrophoneDevice.h" />
<ClInclude Include="VideoCaptureDeviceList.h" />
<ClInclude Include="username.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,19 @@
#include "naming.h"
#include "username.h"
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted)
{
static const std::optional<std::wstring> username = ObtainActiveUserName();
std::wstring result = L"Global\\";
if (restricted)
{
result += L"Restricted\\";
}
if (username)
{
result += *username;
}
result += name;
return result;
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string_view>
#include <string>
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
</packages>

View File

@ -0,0 +1,20 @@
#include "username.h"
#include <Windows.h>
#include <wtsapi32.h>
std::optional<std::wstring> 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;
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <optional>
#include <string>
#include <string_view>
std::optional<std::wstring> ObtainActiveUserName();
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);

View File

@ -0,0 +1,20 @@
; Disable default limits
.option EXPLICIT
.set CabinetFileCountThreshold=0
.set FolderFileCountThreshold=0
.set FolderSizeThreshold=0
.set MaxCabinetSize=0
.set MaxDiskFileCount=0
.set MaxDiskSize=0
.set GenerateInf=ON
.set Compress=OFF
.set Cabinet=ON
.set CabinetNameTemplate=driver.cab
.set DestinationDir=cab_output
.set DiskDirectoryTemplate=driver
VideoConferenceCustomMediaSource.dll
videoconferencevirtualdriver.cat
VideoConferenceVirtualDriver.dll
VideoConferenceVirtualDriver.inf

View File

@ -20,6 +20,7 @@
#include <common/updating/updateState.h> #include <common/updating/updateState.h>
#include <common/utils/appMutex.h> #include <common/utils/appMutex.h>
#include <common/utils/elevation.h> #include <common/utils/elevation.h>
#include <common/utils/os-detect.h>
#include <common/utils/processApi.h> #include <common/utils/processApi.h>
#include <common/utils/resources.h> #include <common/utils/resources.h>
@ -43,6 +44,7 @@
#include <common/utils/winapi_error.h> #include <common/utils/winapi_error.h>
#include <common/utils/window.h> #include <common/utils/window.h>
#include <common/version/version.h> #include <common/version/version.h>
#include <gdiplus.h>
namespace namespace
{ {
@ -130,7 +132,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
chdir_current_executable(); chdir_current_executable();
// Load Powertoys DLLs // Load Powertoys DLLs
const std::array<std::wstring_view, 9> knownModules = { std::vector<std::wstring_view> knownModules = {
L"modules/FancyZones/FancyZonesModuleInterface.dll", L"modules/FancyZones/FancyZonesModuleInterface.dll",
L"modules/FileExplorerPreview/powerpreview.dll", L"modules/FileExplorerPreview/powerpreview.dll",
L"modules/ImageResizer/ImageResizerExt.dll", L"modules/ImageResizer/ImageResizerExt.dll",
@ -140,6 +142,8 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.dll", L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.dll",
L"modules/ColorPicker/ColorPicker.dll", L"modules/ColorPicker/ColorPicker.dll",
L"modules/Awake/AwakeModuleInterface.dll", L"modules/Awake/AwakeModuleInterface.dll",
// TODO(yuyoyuppe): uncomment when VCM should be enabled
//L"modules/VideoConference/VideoConferenceModule.dll"
}; };
for (const auto& moduleSubdir : knownModules) for (const auto& moduleSubdir : knownModules)
@ -264,6 +268,10 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ {
Gdiplus::GdiplusStartupInput gpStartupInput;
ULONG_PTR gpToken;
GdiplusStartup(&gpToken, &gpStartupInput, NULL);
winrt::init_apartment(); winrt::init_apartment();
const wchar_t* securityDescriptor = const wchar_t* securityDescriptor =
L"O:BA" // Owner: Builtin (local) administrator L"O:BA" // Owner: Builtin (local) administrator

View File

@ -38,7 +38,7 @@
<Link> <Link>
<UACExecutionLevel>AsInvoker</UACExecutionLevel> <UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>Shcore.lib;Msi.lib;WindowsApp.lib;taskschd.lib;Rstrtmgr.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Shcore.lib;gdiplus.lib;Msi.lib;WindowsApp.lib;taskschd.lib;Rstrtmgr.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Manifest> <Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness> <EnableDpiAwareness>false</EnableDpiAwareness>

View File

@ -80,6 +80,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
} }
} }
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; private bool powerRename = true;
public bool PowerRename public bool PowerRename

View File

@ -58,4 +58,11 @@
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" /> <ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" /> <ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms">
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.Forms.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

Some files were not shown because too many files have changed in this diff Show More