Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8eb932588 | ||
|
|
ca8bf4356d | ||
|
|
616249e4d0 | ||
|
|
e540e7a2ef | ||
|
|
e0160fd1bc | ||
|
|
14cb58e8a5 | ||
|
|
369551d1f5 | ||
|
|
208430576f | ||
|
|
1534c2a0a3 | ||
|
|
0e68101223 | ||
|
|
696b6d7de0 | ||
|
|
1653d463e7 | ||
|
|
f0e29f7c87 | ||
|
|
417a0c1de4 | ||
|
|
2599489962 | ||
|
|
55a3062e98 | ||
|
|
8318c20eb0 | ||
|
|
81e2bbd80e | ||
|
|
f282958284 | ||
|
|
34b8ae5721 | ||
|
|
76e92f8026 | ||
|
|
2843ab7837 | ||
|
|
46e8501544 | ||
|
|
772f13fcc9 | ||
|
|
5d5cac4f53 | ||
|
|
3acc94fc4c | ||
|
|
b2088adbb5 | ||
|
|
4e8d87cf3d | ||
|
|
56325d164c | ||
|
|
503d175ffd | ||
|
|
d684411cd2 | ||
|
|
05c0ce4e0c | ||
|
|
0372dd451c | ||
|
|
7f02208008 | ||
|
|
b067a91253 | ||
|
|
501ae98873 | ||
|
|
850f79630e | ||
|
|
9f33aa7f2b | ||
|
|
f08c0e0869 | ||
|
|
ce7c8b60e1 | ||
|
|
67da4f4e69 | ||
|
|
8252461236 | ||
|
|
bbdc530b00 | ||
|
|
4859fa3336 | ||
|
|
46e91337f0 | ||
|
|
009c0662c1 | ||
|
|
eebffb1571 | ||
|
|
6dfd97c43f | ||
|
|
724673c1ce | ||
|
|
b9b107d1bc | ||
|
|
9cdf485795 |
115
.github/actions/spell-check/expect.txt
vendored
@@ -37,6 +37,7 @@ akamaihd
|
||||
ALarger
|
||||
alekhyareddy
|
||||
alertsolid
|
||||
alignas
|
||||
ALIGNLEFT
|
||||
ALLAPPS
|
||||
Alloc
|
||||
@@ -127,6 +128,8 @@ Autorun
|
||||
AUTOSIZECOLUMNS
|
||||
autoupdate
|
||||
AValid
|
||||
avialable
|
||||
AYUV
|
||||
azurecr
|
||||
azurewebsites
|
||||
backend
|
||||
@@ -166,6 +169,7 @@ bms
|
||||
BNumber
|
||||
Bokm
|
||||
BOKMAL
|
||||
boolalpha
|
||||
Bools
|
||||
bootstrapper
|
||||
BOTTOMALIGN
|
||||
@@ -191,6 +195,7 @@ buildtransitive
|
||||
BValue
|
||||
bytearray
|
||||
callbackptr
|
||||
Camer
|
||||
CANRENAME
|
||||
Captureascreenshot
|
||||
CAPTURECHANGED
|
||||
@@ -269,6 +274,7 @@ codereview
|
||||
Codespaces
|
||||
COINIT
|
||||
colorconv
|
||||
COLORKEY
|
||||
colorpicker
|
||||
colorpickerref
|
||||
COLORREF
|
||||
@@ -400,6 +406,7 @@ dcomp
|
||||
DComposition
|
||||
ddd
|
||||
ddee
|
||||
ddf
|
||||
Deact
|
||||
declspec
|
||||
decltype
|
||||
@@ -439,11 +446,14 @@ devblogs
|
||||
devdocs
|
||||
devenum
|
||||
DEVMON
|
||||
devpkey
|
||||
DEVSOURCE
|
||||
df
|
||||
DFactory
|
||||
Dialpad
|
||||
diffing
|
||||
difftime
|
||||
DIIRFLAG
|
||||
dimm
|
||||
dirname
|
||||
dirs
|
||||
@@ -499,6 +509,10 @@ dupenv
|
||||
dutil
|
||||
DVASPECT
|
||||
DVASPECTINFO
|
||||
DVH
|
||||
DVHD
|
||||
DVSD
|
||||
DVSL
|
||||
DVTARGETDEVICE
|
||||
dw
|
||||
DWindow
|
||||
@@ -518,6 +532,8 @@ dword
|
||||
dworigin
|
||||
dwrite
|
||||
dxgi
|
||||
dxgiformat
|
||||
dxguid
|
||||
EABF
|
||||
EAC
|
||||
EACB
|
||||
@@ -621,6 +637,7 @@ EFFE
|
||||
efgh
|
||||
EFile
|
||||
egistry
|
||||
elif
|
||||
ELogo
|
||||
elseif
|
||||
Emoji
|
||||
@@ -629,6 +646,7 @@ ENABLEDPOPUP
|
||||
endforeach
|
||||
endif
|
||||
endl
|
||||
endpointvolume
|
||||
endregion
|
||||
Enque
|
||||
ENTERSIZEMOVE
|
||||
@@ -681,7 +699,7 @@ exlist
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
explr
|
||||
Expr
|
||||
expr
|
||||
exsb
|
||||
EXSEL
|
||||
exstyle
|
||||
@@ -698,6 +716,7 @@ Farbraum
|
||||
FARPROC
|
||||
Favicon
|
||||
fd
|
||||
fdw
|
||||
feimage
|
||||
ffcd
|
||||
FFDDDDDD
|
||||
@@ -715,13 +734,16 @@ filesystem
|
||||
FILETIME
|
||||
FILETYPE
|
||||
FILEVERSION
|
||||
Filtergraph
|
||||
Filterkeyboard
|
||||
Filterx
|
||||
finalizer
|
||||
findstr
|
||||
FIXEDFILEINFO
|
||||
FLASHZONES
|
||||
FLASHZONESONQUICKSWITCH
|
||||
Fle
|
||||
flt
|
||||
fluentui
|
||||
flyout
|
||||
fmtlib
|
||||
@@ -744,6 +766,7 @@ FTYPE
|
||||
FULLNAME
|
||||
fullscreen
|
||||
func
|
||||
Functiondiscoverykeys
|
||||
fwlink
|
||||
fwrite
|
||||
fx
|
||||
@@ -753,6 +776,7 @@ GAC
|
||||
gacutil
|
||||
Gamebar
|
||||
GBs
|
||||
GCLP
|
||||
gcnew
|
||||
gdi
|
||||
gdiplus
|
||||
@@ -795,9 +819,11 @@ hashcode
|
||||
hbitmap
|
||||
hbmp
|
||||
hbr
|
||||
HBRBACKGROUND
|
||||
HBRUSH
|
||||
hc
|
||||
hcblack
|
||||
HCERTSTORE
|
||||
hcwhite
|
||||
hdc
|
||||
HDF
|
||||
@@ -809,7 +835,9 @@ hdrop
|
||||
HDS
|
||||
HEB
|
||||
helptext
|
||||
HGLOBAL
|
||||
HEVC
|
||||
hfile
|
||||
hglobal
|
||||
hh
|
||||
hhk
|
||||
HHmmss
|
||||
@@ -883,11 +911,13 @@ IApp
|
||||
IApplication
|
||||
IAppx
|
||||
IAsync
|
||||
IAudio
|
||||
IAuto
|
||||
IBackground
|
||||
IBase
|
||||
IBeam
|
||||
IBind
|
||||
ICapture
|
||||
icase
|
||||
iccex
|
||||
ICEBLUE
|
||||
@@ -940,9 +970,11 @@ IFancy
|
||||
ifdef
|
||||
IFeatures
|
||||
IFile
|
||||
IFilter
|
||||
ifndef
|
||||
IFolder
|
||||
ifstream
|
||||
IGraph
|
||||
IIcon
|
||||
iid
|
||||
IImage
|
||||
@@ -961,8 +993,11 @@ IMAGERESIZEREXT
|
||||
IMain
|
||||
IMarkdown
|
||||
ime
|
||||
IMedia
|
||||
IMem
|
||||
imeutil
|
||||
img
|
||||
iminstall
|
||||
IMoniker
|
||||
IMonitor
|
||||
IMouse
|
||||
@@ -1019,6 +1054,7 @@ IObject
|
||||
iobjectwithsitesetsite
|
||||
IOle
|
||||
iolewindowcontextsensitivehelp
|
||||
iomanip
|
||||
iostream
|
||||
ip
|
||||
IPackage
|
||||
@@ -1040,6 +1076,7 @@ IProperty
|
||||
IPublic
|
||||
IQuery
|
||||
IRead
|
||||
IReference
|
||||
IReflect
|
||||
IRegistered
|
||||
IRegistration
|
||||
@@ -1082,7 +1119,9 @@ IVector
|
||||
IView
|
||||
IVirtual
|
||||
IWeb
|
||||
IWIC
|
||||
ixx
|
||||
IYUV
|
||||
IZone
|
||||
IZoom
|
||||
JArray
|
||||
@@ -1129,6 +1168,7 @@ keyup
|
||||
Kf
|
||||
KILLFOCUS
|
||||
Knownfolders
|
||||
KSPROPERTY
|
||||
Kybd
|
||||
LAlt
|
||||
lambson
|
||||
@@ -1148,9 +1188,11 @@ Lclean
|
||||
LCONTROL
|
||||
LCtrl
|
||||
Ldone
|
||||
ldx
|
||||
LEFTSCROLLBAR
|
||||
lego
|
||||
len
|
||||
LEQ
|
||||
LError
|
||||
Lessthan
|
||||
LEVELID
|
||||
@@ -1173,6 +1215,7 @@ LINQTo
|
||||
Linux
|
||||
listbox
|
||||
listview
|
||||
lld
|
||||
llkhf
|
||||
LLogo
|
||||
Llvm
|
||||
@@ -1253,6 +1296,7 @@ MAINICON
|
||||
Mainwindow
|
||||
majortype
|
||||
makeappx
|
||||
makecab
|
||||
MAKEINTRESOURCE
|
||||
MAKEINTRESOURCEW
|
||||
MAKELPARAM
|
||||
@@ -1270,6 +1314,7 @@ MATCHMODE
|
||||
MAXIMIZEBOX
|
||||
MAXSHORTCUTSIZE
|
||||
maxversiontested
|
||||
MBs
|
||||
MBUTTON
|
||||
MBUTTONDBLCLK
|
||||
MBUTTONDOWN
|
||||
@@ -1279,7 +1324,7 @@ MDICHILD
|
||||
MDL
|
||||
mdpreviewhandler
|
||||
MEDIASUBTYPE
|
||||
MEDIATYPE
|
||||
mediatype
|
||||
Melman
|
||||
memcpy
|
||||
memset
|
||||
@@ -1292,8 +1337,17 @@ messageboxes
|
||||
METACHARSET
|
||||
metadata
|
||||
metafile
|
||||
mfapi
|
||||
mfc
|
||||
mfcribbon
|
||||
mfidl
|
||||
mfobjects
|
||||
mfplat
|
||||
mfreadwrite
|
||||
Mfsensorgroup
|
||||
mftransform
|
||||
mfuuid
|
||||
mic
|
||||
microsoft
|
||||
Midl
|
||||
mii
|
||||
@@ -1306,9 +1360,10 @@ miniz
|
||||
MINMAXINFO
|
||||
Miracast
|
||||
mixin
|
||||
MJPG
|
||||
mjpg
|
||||
mkdir
|
||||
MLogo
|
||||
mmdeviceapi
|
||||
MMI
|
||||
mockapi
|
||||
MODECHANGE
|
||||
@@ -1372,6 +1427,7 @@ mutex
|
||||
mutexes
|
||||
muxc
|
||||
mvvm
|
||||
myfile
|
||||
MYICON
|
||||
myuri
|
||||
NAMECHANGE
|
||||
@@ -1409,6 +1465,7 @@ netsh
|
||||
netstandard
|
||||
Neue
|
||||
newcolor
|
||||
newdev
|
||||
newitem
|
||||
newpath
|
||||
newrow
|
||||
@@ -1433,6 +1490,7 @@ nodoc
|
||||
noexcept
|
||||
NOFRAMES
|
||||
NOINHERITLAYOUT
|
||||
NOINTERFACE
|
||||
NOLINKINFO
|
||||
NOMINMAX
|
||||
NOMOVE
|
||||
@@ -1520,6 +1578,7 @@ Openthe
|
||||
openxmlformats
|
||||
OPTIMIZEFORINVOKE
|
||||
OPTIONSGROUP
|
||||
ORAW
|
||||
ORPHANEDDIALOGTITLE
|
||||
oss
|
||||
ostr
|
||||
@@ -1530,6 +1589,7 @@ osx
|
||||
otating
|
||||
OUTOFCONTEXT
|
||||
OUTOFMEMORY
|
||||
outpin
|
||||
Outptr
|
||||
outro
|
||||
OVERLAPPEDWINDOW
|
||||
@@ -1550,6 +1610,7 @@ PARENTRELATIVEPARSING
|
||||
parray
|
||||
PARTIALCONFIRMATIONDIALOGTITLE
|
||||
pathcch
|
||||
PAUDIO
|
||||
pb
|
||||
pbc
|
||||
Pbgra
|
||||
@@ -1589,6 +1650,7 @@ Pipelinhttps
|
||||
pipename
|
||||
pitem
|
||||
PKBDLLHOOKSTRUCT
|
||||
PKEY
|
||||
placeholders
|
||||
plib
|
||||
PLK
|
||||
@@ -1610,6 +1672,7 @@ popd
|
||||
popup
|
||||
POPUPWINDOW
|
||||
posix
|
||||
Postion
|
||||
powerappscds
|
||||
powerlauncher
|
||||
powerpreview
|
||||
@@ -1622,6 +1685,7 @@ powertoyssetup
|
||||
Powrprof
|
||||
ppenum
|
||||
ppidl
|
||||
ppmt
|
||||
pprm
|
||||
pproc
|
||||
ppsi
|
||||
@@ -1638,11 +1702,13 @@ precomp
|
||||
Preinstalled
|
||||
preload
|
||||
PREMULTIPLIED
|
||||
preperty
|
||||
prevhost
|
||||
previewer
|
||||
PREVIEWGROUP
|
||||
PREVIEWHANDLERFRAMEINFO
|
||||
previewpane
|
||||
previouscamera
|
||||
PREVIOUSVERSIONSINSTALLED
|
||||
prevpane
|
||||
prgms
|
||||
@@ -1659,6 +1725,7 @@ PROGRAMFILES
|
||||
progressbar
|
||||
Proj
|
||||
projectname
|
||||
PROPBAG
|
||||
propkey
|
||||
propvarutil
|
||||
Prt
|
||||
@@ -1670,6 +1737,7 @@ psfgao
|
||||
Psr
|
||||
psrm
|
||||
psrree
|
||||
pstr
|
||||
pstream
|
||||
pstrm
|
||||
psz
|
||||
@@ -1689,6 +1757,7 @@ pw
|
||||
pwa
|
||||
pwcs
|
||||
PWSTR
|
||||
pwsz
|
||||
pwtd
|
||||
px
|
||||
Qand
|
||||
@@ -1734,13 +1803,18 @@ refactor
|
||||
refactoring
|
||||
REFCLSID
|
||||
refcount
|
||||
REFGUID
|
||||
REFIID
|
||||
REGCLS
|
||||
regedit
|
||||
regex
|
||||
REGFILTER
|
||||
REGFILTERPINS
|
||||
REGISTERCLASSFAILED
|
||||
registrypath
|
||||
regkey
|
||||
REGPINTYPES
|
||||
regsvr
|
||||
reimplementing
|
||||
reloadable
|
||||
Remapper
|
||||
@@ -1791,12 +1865,12 @@ RKey
|
||||
RMENU
|
||||
RNumber
|
||||
roadmap
|
||||
robocopy
|
||||
Roboto
|
||||
roslyn
|
||||
royvou
|
||||
rpc
|
||||
RRF
|
||||
RSHIFT
|
||||
rshift
|
||||
Rsp
|
||||
rst
|
||||
@@ -1890,6 +1964,7 @@ Shl
|
||||
shldisp
|
||||
shlobj
|
||||
shlwapi
|
||||
shmem
|
||||
shobjidl
|
||||
SHORTCUTATLEAST
|
||||
shortcutcontrol
|
||||
@@ -1927,6 +2002,7 @@ SIZENESW
|
||||
SIZENS
|
||||
SIZENWSE
|
||||
sizeof
|
||||
sizeread
|
||||
SIZEWE
|
||||
sketchapp
|
||||
SKIPOWNPROCESS
|
||||
@@ -1952,6 +2028,7 @@ spesi
|
||||
spinbuttonref
|
||||
splitwstring
|
||||
spoprod
|
||||
sprintf
|
||||
spsi
|
||||
spsia
|
||||
spsrif
|
||||
@@ -2044,6 +2121,7 @@ swprintf
|
||||
SYMED
|
||||
Symlink
|
||||
SYMOPT
|
||||
SYNCMFT
|
||||
SYNCPAINT
|
||||
sys
|
||||
SYSCHAR
|
||||
@@ -2116,6 +2194,7 @@ TLayout
|
||||
tlb
|
||||
tlbimp
|
||||
tmp
|
||||
TMPVAR
|
||||
TNP
|
||||
todo
|
||||
toggleleft
|
||||
@@ -2136,12 +2215,15 @@ towlower
|
||||
towupper
|
||||
tracelogging
|
||||
traies
|
||||
transcoded
|
||||
transparrent
|
||||
TRAYMOUSEMESSAGE
|
||||
TRK
|
||||
trl
|
||||
truetype
|
||||
trunc
|
||||
tslint
|
||||
tspan
|
||||
TStr
|
||||
tsx
|
||||
tt
|
||||
@@ -2176,6 +2258,7 @@ ul
|
||||
ULARGE
|
||||
ULLONG
|
||||
ulong
|
||||
ULONGLONG
|
||||
umd
|
||||
unchecks
|
||||
uncomment
|
||||
@@ -2203,6 +2286,7 @@ unknwn
|
||||
UNLEN
|
||||
unlicense
|
||||
Unmap
|
||||
unmute
|
||||
UNORM
|
||||
Unpublish
|
||||
unregister
|
||||
@@ -2239,16 +2323,20 @@ uv
|
||||
uwp
|
||||
UWPUI
|
||||
uxtheme
|
||||
UYVY
|
||||
validmodulename
|
||||
vcamp
|
||||
vccorlib
|
||||
vcdl
|
||||
VCINSTALLDIR
|
||||
vcm
|
||||
vcomp
|
||||
vcredist
|
||||
VCRT
|
||||
vcruntime
|
||||
vcvars
|
||||
vcxproj
|
||||
vdi
|
||||
VDId
|
||||
vec
|
||||
VERBSONLY
|
||||
@@ -2259,9 +2347,13 @@ Versioning
|
||||
VFT
|
||||
vh
|
||||
vid
|
||||
VIDCAP
|
||||
videoconference
|
||||
videoconferencevirtualdriver
|
||||
VIDEOINFOHEADER
|
||||
viewbox
|
||||
viewmodel
|
||||
vih
|
||||
virtualization
|
||||
Visibletrue
|
||||
Visio
|
||||
@@ -2280,6 +2372,7 @@ VSCBD
|
||||
vscode
|
||||
VSCROLL
|
||||
vse
|
||||
vsix
|
||||
vsonline
|
||||
vstemplate
|
||||
VSTHRD
|
||||
@@ -2305,6 +2398,9 @@ wcscpy
|
||||
wcslen
|
||||
wcsncmp
|
||||
wcsnicmp
|
||||
WDK
|
||||
wdksetup
|
||||
wdkvsix
|
||||
wdp
|
||||
wdupenv
|
||||
weakme
|
||||
@@ -2329,6 +2425,8 @@ wikipedia
|
||||
wil
|
||||
wildcards
|
||||
winapi
|
||||
wincodec
|
||||
Wincodecsdk
|
||||
wincolor
|
||||
windef
|
||||
windevbuildagents
|
||||
@@ -2377,6 +2475,7 @@ wmonk
|
||||
wmp
|
||||
WMSYSKEYDOWN
|
||||
WMSYSKEYUP
|
||||
WMV
|
||||
wnd
|
||||
WNDCLASS
|
||||
WNDCLASSEX
|
||||
@@ -2406,8 +2505,10 @@ wstring
|
||||
wstringstream
|
||||
wsz
|
||||
WTS
|
||||
wtsapi
|
||||
WTSAT
|
||||
wu
|
||||
WVC
|
||||
Wwan
|
||||
www
|
||||
wxs
|
||||
@@ -2421,7 +2522,7 @@ XBUTTON
|
||||
XBUTTONDBLCLK
|
||||
XBUTTONDOWN
|
||||
XBUTTONUP
|
||||
XCOPY
|
||||
xcopy
|
||||
XDiff
|
||||
XDocument
|
||||
XElement
|
||||
@@ -2454,6 +2555,8 @@ YOffset
|
||||
YStr
|
||||
YUY
|
||||
YUYV
|
||||
YVU
|
||||
YVYU
|
||||
yy
|
||||
Zc
|
||||
ZEROINIT
|
||||
|
||||
@@ -7,3 +7,5 @@ set SolutionDir=%cd%
|
||||
popd
|
||||
SET IsPipeline=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
|
||||
|
||||
|
||||
@@ -61,11 +61,14 @@ build:
|
||||
- 'x64/**/*.pdb'
|
||||
exclude:
|
||||
- 'x64/Release/obj/**/*.pdb'
|
||||
- from: 'x86/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'action_runner.exe'
|
||||
- 'BugReportTool\BugReportTool.exe'
|
||||
- 'modules\ColorPicker\ColorPicker.dll'
|
||||
- 'modules\ColorPicker\ColorPickerUI.dll'
|
||||
- 'modules\ColorPicker\ColorPickerUI.exe'
|
||||
@@ -146,6 +149,8 @@ build:
|
||||
- 'modules\Microsoft.Launcher.dll'
|
||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||
- 'modules\ShortcutGuide\ShortcutGuide.dll'
|
||||
- 'modules\VideoConference\VideoConferenceModule.dll'
|
||||
- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
|
||||
- 'Notifications.dll'
|
||||
- 'os-detection.dll'
|
||||
- 'PowerToys.exe'
|
||||
@@ -168,6 +173,7 @@ build:
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'BugReportTool\BugReportTool.exe'
|
||||
- 'WebcamReportTool\WebcamReportTool.exe'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
- !!buildcommand
|
||||
@@ -228,4 +234,3 @@ static_analysis_options:
|
||||
files_to_scan:
|
||||
- exclude:
|
||||
- '**/*.lcl'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
nuget restore ../tools/BugReportTool/BugReportTool.sln || exit /b 1
|
||||
nuget restore ../tools/WebcamReportTool/WebcamReportTool.sln || exit /b 1
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
nuget restore ../PowerToys.sln || exit /b 1
|
||||
|
||||
powershell.exe -Command "Invoke-WebRequest -OutFile %tmp%\wdksetup.exe https://go.microsoft.com/fwlink/p/?linkid=2085767"
|
||||
%tmp%\wdksetup.exe /q
|
||||
|
||||
copy "C:\Program Files (x86)\Windows Kits\10\Vsix\VS2019\WDK.vsix" %tmp%\wdkvsix.zip
|
||||
powershell Expand-Archive %tmp%\wdkvsix.zip -DestinationPath %tmp%\wdkvsix -Force
|
||||
|
||||
robocopy /e %tmp%\wdkvsix\$MSBuild\Microsoft\VC\v160 "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160" || IF %ERRORLEVEL% LEQ 7 EXIT 0
|
||||
robocopy /e %tmp%\wdkvsix\$VCTargets "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCTargets" || IF %ERRORLEVEL% LEQ 7 EXIT 0
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
<!-- Props that are constant for both Debug and Release configurations -->
|
||||
<PropertyGroup Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(OverridePlatformToolset)'!='True'">v142</PlatformToolset>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
|
||||
203
PowerToys.sln
@@ -310,332 +310,531 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerToys.Settings", "src\settings-ui\PowerToys.Settings\PowerToys.Settings.csproj", "{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.Build.0 = Release|x64
|
||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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.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.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.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.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.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.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.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.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.Build.0 = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x86.ActiveCfg = Release|x64
|
||||
{EAF23649-EF6E-478B-980E-81FAD96CCA2A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EAF23649-EF6E-478B-980E-81FAD96CCA2A}.Debug|x64.Build.0 = Debug|x64
|
||||
{EAF23649-EF6E-478B-980E-81FAD96CCA2A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{EAF23649-EF6E-478B-980E-81FAD96CCA2A}.Release|x64.ActiveCfg = Release|x64
|
||||
{EAF23649-EF6E-478B-980E-81FAD96CCA2A}.Release|x64.Build.0 = Release|x64
|
||||
{EAF23649-EF6E-478B-980E-81FAD96CCA2A}.Release|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|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.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.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.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.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.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.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.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.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.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.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.Build.0 = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|x64
|
||||
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x64.Build.0 = Debug|x64
|
||||
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x64.ActiveCfg = Release|x64
|
||||
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x64.Build.0 = Release|x64
|
||||
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x64.Build.0 = Debug|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Release|x64.ActiveCfg = Release|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Release|x64.Build.0 = Release|x64
|
||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Release|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|x86.ActiveCfg = Release|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|x86.ActiveCfg = Debug|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|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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -731,6 +930,10 @@ Global
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{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
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
@@ -66,7 +66,12 @@ Various tools used by PowerToys. Includes the Visual Studio 2019 project templat
|
||||
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`
|
||||
|
||||
### 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`.
|
||||
- The PowerToys binaries will be in your repo under `x64\Release\`.
|
||||
|
||||
@@ -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="..\..\src\Version.props" />
|
||||
<PropertyGroup>
|
||||
<DefineConstants>Version=$(Version);</DefineConstants>
|
||||
<DefineConstants>Version=$(Version)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
@@ -74,7 +74,6 @@
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>IF NOT DEFINED IsPipeline (
|
||||
|
||||
call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
SET PTRoot=..\..\..\..
|
||||
call "..\..\publish.cmd"
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
<?define PowerRenameProjectName="PowerRename"?>
|
||||
<?define ShortcutGuideProjectName="ShortcutGuide"?>
|
||||
<?define ColorPickerProjectName="ColorPicker"?>
|
||||
<?define VideoConferenceProjectName="VideoConference"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
|
||||
|
||||
<Product Id="*"
|
||||
Name="PowerToys (Preview)"
|
||||
@@ -210,6 +212,9 @@
|
||||
<Directory Id="ImageResizerInstallFolder" Name="$(var.ImageResizerProjectName)" />
|
||||
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)"/>
|
||||
<Directory Id="ShortcutGuideInstallFolder" Name="$(var.ShortcutGuideProjectName)"/>
|
||||
<Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
|
||||
<Directory Id="VideoConferenceIconsFolder" Name="Icons" />
|
||||
</Directory>
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)" />
|
||||
@@ -398,6 +403,9 @@
|
||||
<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" />
|
||||
</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 Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
||||
@@ -589,6 +597,36 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<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="KeyboardManagerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\">
|
||||
<Component Id="Module_KeyboardManager" Guid="9279BD82-786F-4F0B-8E49-DB484EE34C9B" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManager.dll" />
|
||||
@@ -597,7 +635,7 @@
|
||||
|
||||
<DirectoryRef Id="ColorPickerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)">
|
||||
<Component Id="Module_ColorPicker" Guid="8A52A69E-37B2-4BEA-9D73-77763066052F" Win64="yes">
|
||||
<?foreach File in ColorPicker.dll;System.IO.Abstractions.dll;ColorPickerUI.exe;ColorPickerUI.dll;ColorPickerUI.deps.json;ColorPickerUI.runtimeconfig.json;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToysInterop.dll;System.Text.Json.dll;ManagedTelemetry.dll;ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.ComponentModel.Composition.dll;Microsoft.PowerToys.Common.UI.dll?>
|
||||
<?foreach File in ColorPicker.dll;System.IO.Abstractions.dll;ColorPickerUI.exe;ColorPickerUI.dll;ColorPickerUI.deps.json;ColorPickerUI.runtimeconfig.json;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToysInterop.dll;System.Text.Json.dll;ManagedTelemetry.dll;ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.ComponentModel.Composition.dll;Microsoft.PowerToys.Common.UI.dll;System.Deployment.dll;System.Runtime.Serialization.Formatters.Soap.dll;System.Windows.Forms.dll?>
|
||||
<File Id="ColorPickerFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
@@ -648,7 +686,7 @@
|
||||
<File Source="$(var.BinX64Dir)Settings\PowerToys.Settings.exe"/>
|
||||
<File Source="$(var.BinX64Dir)Settings\Microsoft.PowerToys.Settings.UI.exe"/>
|
||||
<!-- 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?>
|
||||
<?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;System.Deployment.dll;System.Windows.Forms.dll;System.Runtime.Serialization.Formatters.Soap.dll?>
|
||||
<File Id="SettingsV2_$(var.File)" Source="$(var.BinX64Dir)Settings\$(var.File)" />
|
||||
<?endforeach?>
|
||||
<!-- json -->
|
||||
@@ -688,7 +726,7 @@
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
|
||||
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<File Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
@@ -794,6 +832,8 @@
|
||||
<ComponentRef Id="vcredist_dlls" />
|
||||
<ComponentRef Id="PowerToysSvgs" />
|
||||
<ComponentRef Id="Module_ShortcutGuide" />
|
||||
<ComponentRef Id="Module_VideoConference" />
|
||||
<ComponentRef Id="Module_VideoConferenceIcons" />
|
||||
<ComponentRef Id="Module_FancyZones" />
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
<ComponentRef Id="Module_PowerRename" />
|
||||
@@ -822,6 +862,7 @@
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="ToolComponents" Directory="ToolsFolder">
|
||||
<ComponentRef Id="BugReportTool_exe" />
|
||||
<ComponentRef Id="WebcamReportTool_exe" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ TRACELOGGING_DEFINE_PROVIDER(
|
||||
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
|
||||
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
|
||||
|
||||
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
|
||||
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
|
||||
|
||||
// Creates a Scheduled Task to run at logon for the current user.
|
||||
@@ -595,6 +596,165 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
#ifdef CIBuild // On pipeline we are using microsoft certification
|
||||
WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
|
||||
return WcaFinalize(ERROR_SUCCESS);
|
||||
#else
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR certificatePath = 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)
|
||||
{
|
||||
|
||||
@@ -12,4 +12,8 @@ EXPORTS
|
||||
TelemetryLogUninstallFailCA
|
||||
TelemetryLogRepairCancelCA
|
||||
TelemetryLogRepairFailCA
|
||||
TerminateProcessesCA
|
||||
TerminateProcessesCA
|
||||
TerminateProcessesCA
|
||||
CertifyVirtualCameraDriverCA
|
||||
InstallVirtualCameraDriverCA
|
||||
UninstallVirtualCameraDriverCA
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<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;winstore.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Crypt32.lib;msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;Newdev.lib;ApplicationUpdate.lib;Notifications.lib;winstore.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define DPSAPI_VERSION 1
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <newdev.h>
|
||||
#include <strsafe.h>
|
||||
#include <msiquery.h>
|
||||
#include <Msi.h>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
#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
|
||||
{
|
||||
@@ -28,10 +28,12 @@
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="settings_helpers.h" />
|
||||
<ClInclude Include="settings_objects.h" />
|
||||
<ClInclude Include="FileWatcher.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="settings_helpers.cpp" />
|
||||
<ClCompile Include="settings_objects.cpp" />
|
||||
<ClCompile Include="FileWatcher.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace PTSettingsHelper
|
||||
{
|
||||
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_folder_location(std::wstring_view powertoy_name);
|
||||
std::wstring get_root_save_folder_location();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <TraceLoggingDefines.h>
|
||||
#include "TraceLoggingProvider.h"
|
||||
#include "TraceLoggingDefines.h"
|
||||
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>PowerToysInterop;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||
@@ -54,7 +55,7 @@
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Mf.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -83,12 +84,20 @@
|
||||
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h" />
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h" />
|
||||
<ClInclude Include="HotkeyManager.h" />
|
||||
<ClInclude Include="KeyboardHook.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</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="HotkeyManager.cpp" />
|
||||
<ClCompile Include="interop.cpp" />
|
||||
@@ -108,6 +117,12 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</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" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="interop.cpp">
|
||||
@@ -47,6 +53,12 @@
|
||||
<ClCompile Include="keyboard_layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</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>
|
||||
<ResourceCompile Include="interop.rc">
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
// Therefore the simplest way is to compile these functions as native using the pragmas below.
|
||||
#pragma managed(push, off)
|
||||
#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)
|
||||
|
||||
#include <common/version/version.h>
|
||||
|
||||
|
||||
using namespace System;
|
||||
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
|
||||
namespace interop
|
||||
@@ -127,6 +132,31 @@ public
|
||||
{
|
||||
return UseNewSettings();
|
||||
}
|
||||
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
|
||||
|
||||
4
src/common/interop/packages.config
Normal 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>
|
||||
@@ -29,7 +29,7 @@ namespace updating
|
||||
std::future<bool> try_autoupdate(const bool download_updates_automatically, const notifications::strings&);
|
||||
std::filesystem::path get_pending_updates_path();
|
||||
std::future<std::wstring> download_update(const notifications::strings&);
|
||||
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const notifications::strings& strings, const bool prerelease = false);
|
||||
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const notifications::strings& strings, const bool prerelease = true);
|
||||
|
||||
// non-localized
|
||||
constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN = L"powertoyssetup";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <common/display/dpi_aware.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/window.h>
|
||||
|
||||
@@ -10,7 +11,6 @@
|
||||
#include "lib/ZoneWindow.h"
|
||||
#include "lib/FancyZonesData.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "lib/FileWatcher.h"
|
||||
#include "lib/WindowMoveHandler.h"
|
||||
#include "lib/FancyZonesWinHookEventIDs.h"
|
||||
#include "lib/util.h"
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="FancyZonesDataTypes.h" />
|
||||
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
|
||||
<ClInclude Include="FileWatcher.h" />
|
||||
<ClInclude Include="GenericKeyHook.h" />
|
||||
<ClInclude Include="FancyZonesData.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
@@ -67,7 +66,6 @@
|
||||
<ClCompile Include="FancyZonesDataTypes.cpp" />
|
||||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
|
||||
<ClCompile Include="FancyZonesData.cpp" />
|
||||
<ClCompile Include="FileWatcher.cpp" />
|
||||
<ClCompile Include="JsonHelpers.cpp" />
|
||||
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
|
||||
<ClCompile Include="OnThreadExecutor.cpp" />
|
||||
@@ -90,6 +88,9 @@
|
||||
<ProjectReference Include="..\..\..\common\notifications\notifications.vcxproj">
|
||||
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ResourceCompile Include="Generated Files/fancyzones.rc" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Resources.resx" />
|
||||
|
||||
@@ -78,9 +78,6 @@
|
||||
<ClInclude Include="ZoneWindowDrawing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FileWatcher.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CallTracer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -140,9 +137,6 @@
|
||||
<ClCompile Include="OnThreadExecutor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileWatcher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CallTracer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.8 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.7 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.8 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.4 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.6 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.2 KiB |
@@ -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 |
|
After Width: | Height: | Size: 3.2 KiB |
@@ -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 |
26
src/modules/videoconference/VideoConferenceModule/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Windows Key Shortcut Guide
|
||||
|
||||
# Introduction
|
||||
The Windows Key Shortcut Guide shows common keyboard shortcuts that use the Windows key.
|
||||
|
||||
# Usage
|
||||
Press and hold the keyboard Windows key for about 1 second, an overlay appears showing keyboard shortcuts that use the Windows Key:
|
||||
- Shortcuts for changing the position of the active window.
|
||||
- Common Windows shortcuts.
|
||||
- Taskbar shortcuts.
|
||||
|
||||
Releasing the Windows key will make the overlay disappear. If the shortcut guide was visible for less than a second, the start menu will appear after the shortcut guide is dismissed.
|
||||
|
||||

|
||||
|
||||
Windows key keyboard shortcuts can be used while the guide is being shown and the result of those shortcuts (active window moved, arrow shortcut behavior changes, etc) will be displayed in the guide.
|
||||
|
||||
# Options
|
||||
These configurations can be edited from the PowerToys Settings screen:
|
||||
- "How long to press the Windows key before showing the Shortcut Guide (ms)" - How many milliseconds to press the Windows key before the Shortcut Guide is shown.
|
||||
- "Opacity of the Shortcut Guide's overlay background (%)" - Changing this setting controls the opacity of the Shortcut Guide's overlay background, occluding the work environment beneath the Shortcut Guide to different degrees.
|
||||
|
||||

|
||||
|
||||
# Backlog
|
||||
The backlog for the utility can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/ShortcutGuideBacklog.md) and the source code is [here](https://github.com/Microsoft/PowerToys/tree/master/src/modules/shortcut_guide).
|
||||
335
src/modules/videoconference/VideoConferenceModule/Toolbar.cpp
Normal 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;
|
||||
}
|
||||
61
src/modules/videoconference/VideoConferenceModule/Toolbar.h
Normal 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;
|
||||
};
|
||||
@@ -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>
|
||||
@@ -0,0 +1,182 @@
|
||||
<?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" />
|
||||
<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>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="Toolbar.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="VideoConferenceModule.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>
|
||||
@@ -0,0 +1,566 @@
|
||||
#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());
|
||||
}
|
||||
if (const auto val = values.get_string_value(L"selected_mic"))
|
||||
{
|
||||
settings.selectedMicrophone = *val;
|
||||
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;
|
||||
});
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
BIN
src/modules/videoconference/VideoConferenceModule/black.bmp
Normal file
|
After Width: | Height: | Size: 822 B |
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
@@ -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>
|
||||
@@ -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.
|
||||
24
src/modules/videoconference/VideoConferenceModule/pch.h
Normal 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>
|
||||
57
src/modules/videoconference/VideoConferenceModule/trace.cpp
Normal 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));
|
||||
}
|
||||
12
src/modules/videoconference/VideoConferenceModule/trace.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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, ¤t_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, ¤t_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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
msbuild VideoConferenceProxyFilterx86.sln -p:Configuration="Release" -p:Platform="Win32"
|
||||
|
||||
exit 0
|
||||
@@ -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, ®Filter));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
EXPORTS
|
||||
DllMain PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
DllInstall PRIVATE
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
203
src/modules/videoconference/VideoConferenceShared/Logging.cpp
Normal 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";
|
||||
}
|
||||
62
src/modules/videoconference/VideoConferenceShared/Logging.h
Normal 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 {};
|
||||
@@ -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*>(µphoneEndpoint));
|
||||
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*>(µphoneEndpoint));
|
||||
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;
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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>
|
||||
19
src/modules/videoconference/VideoConferenceShared/naming.cpp
Normal 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;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
20
src/modules/videoconference/make_cab.ddf
Normal 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
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <common/updating/updating.h>
|
||||
#include <common/utils/appMutex.h>
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/os-detect.h>
|
||||
#include <common/utils/processApi.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/winstore/winstore.h>
|
||||
@@ -44,6 +45,8 @@
|
||||
#include <common/utils/window.h>
|
||||
#include <common/version/version.h>
|
||||
|
||||
#include <gdiplus.h>
|
||||
|
||||
extern updating::notifications::strings Strings;
|
||||
|
||||
namespace
|
||||
@@ -148,7 +151,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
||||
chdir_current_executable();
|
||||
// Load Powertoys DLLs
|
||||
|
||||
const std::array<std::wstring_view, 8> knownModules = {
|
||||
std::vector<std::wstring_view> knownModules = {
|
||||
L"modules/FancyZones/fancyzones.dll",
|
||||
L"modules/FileExplorerPreview/powerpreview.dll",
|
||||
L"modules/ImageResizer/ImageResizerExt.dll",
|
||||
@@ -158,6 +161,10 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
||||
L"modules/ShortcutGuide/ShortcutGuide.dll",
|
||||
L"modules/ColorPicker/ColorPicker.dll",
|
||||
};
|
||||
if (Is19H1OrHigher())
|
||||
{
|
||||
knownModules.emplace_back(L"modules/VideoConference/VideoConferenceModule.dll");
|
||||
}
|
||||
|
||||
for (const auto& moduleSubdir : knownModules)
|
||||
{
|
||||
@@ -319,6 +326,10 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
Gdiplus::GdiplusStartupInput gpStartupInput;
|
||||
ULONG_PTR gpToken;
|
||||
GdiplusStartup(&gpToken, &gpStartupInput, NULL);
|
||||
|
||||
winrt::init_apartment();
|
||||
const wchar_t* securityDescriptor =
|
||||
L"O:BA" // Owner: Builtin (local) administrator
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<Link>
|
||||
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
|
||||
<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>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>false</EnableDpiAwareness>
|
||||
|
||||
@@ -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;
|
||||
|
||||
public bool PowerRename
|
||||
|
||||