diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 3acc79d4b1..1222c66e66 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -63,6 +63,7 @@ APPIDS
appium
Applets
Applicationcan
+applicationconfiguration
applicationframehost
Applist
applog
@@ -87,9 +88,11 @@ ARRAYSIZE
arsinh
artanh
Artsakh
+asd
asdf
AShortcut
ASingle
+Asn
ASSOCCHANGED
ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS
@@ -158,8 +161,8 @@ bpmf
bpp
bricelam
BRIGHTGREEN
+Brotli
Browsable
-brucelindbloom
bsd
bstr
bti
@@ -199,9 +202,8 @@ CHILDACTIVATE
CHILDWINDOW
Choibalsan
chrdavis
-chromaticities
Chrzan
-CHT
+cht
Chukotka
Chuuk
CIELAB
@@ -220,6 +222,10 @@ CLIPCHILDREN
Clipperton
CLIPSIBLINGS
clrcall
+clrcompression
+clretwrc
+clrgc
+clrjit
Cls
CLSCTX
clsid
@@ -234,6 +240,7 @@ CMock
CMONITORS
cmpgt
cmyk
+Cng
cnt
Cocklebiddy
coclass
@@ -254,13 +261,11 @@ comctl
COMDAT
comdef
comdlg
-comhost
cominterop
commandline
COMMANDTITLE
commctrl
Comoros
-companding
COMPOSITIONFULL
comsupp
comsuppw
@@ -281,6 +286,7 @@ CONTROLL
CONTROLPARENT
Controlz
copiedcolorrepresentation
+coreclr
corewebview
cortana
cotaskmem
@@ -325,12 +331,10 @@ cwd
cxfksword
CXSMICON
CXVIRTUALSCREEN
-cxxopts
cyberrex
CYSMICON
CYVIRTUALSCREEN
cziplib
-cziplob
Dac
dacl
damienleroy
@@ -346,6 +350,7 @@ davidegiacometti
Dayof
Dbg
Dbghelp
+dbgshim
DBLCLKS
DBLEPSILON
DCapture
@@ -354,6 +359,7 @@ DCOM
dcommon
dcomp
dcompi
+DCompiler
DComposition
DCR
DDevice
@@ -388,7 +394,7 @@ DESKTOPABSOLUTEEDITING
DESKTOPABSOLUTEPARSING
desktopshorcutinstalled
desktopwindowxamlsource
-DEU
+deu
devblogs
devdocs
devenum
@@ -476,12 +482,11 @@ ENABLEDPOPUP
endpointvolume
endregion
ENTERSIZEMOVE
-ENU
+enu
enumerationoptions
EOAC
epicgames
epu
-Eqn
ERASEBKGND
EREOF
EResize
@@ -490,6 +495,7 @@ ERRORLEVEL
ERRORTITLE
ESettings
esize
+esn
esrp
Eswatini
etl
@@ -533,7 +539,6 @@ Faroe
FARPROC
fdw
feimage
-ffaa
fff
fileapi
FILEEXPLORER
@@ -679,6 +684,8 @@ HOMEPATH
homljgmgpmcbpjbnjpfijnhipfkiclkd
HOOKPROC
Hostbackdropbrush
+hostfxr
+hostpolicy
hotkeycontrol
hotkeys
hotlight
@@ -750,6 +757,7 @@ IMAGERESIZEREXT
imageresizerinput
imageresizersettings
imagingdevices
+Imc
ime
imeutil
inetcpl
@@ -786,17 +794,15 @@ Intelli
interactable
Interlop
INTRESOURCE
+Intrinsics
INVALIDARG
invalidoperatioexception
-iobjectwithsitesetsite
-iolewindowcontextsensitivehelp
ipc
ipcmanager
IPlugin
IPower
-ipreview
+IPREVIEW
ipreviewhandler
-ipreviewhandlertranslateaccelerator
ipreviewhandlervisualssetfont
IProperty
IPublic
@@ -824,7 +830,7 @@ jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi
jjw
jobject
jpe
-JPN
+jpn
jpnime
JSONOf
Jsons
@@ -847,7 +853,6 @@ keyevent
KEYEVENTF
keynum
keyremaps
-keystokes
Keytool
keyup
Khakassia
@@ -906,6 +911,7 @@ lmcons
LMEM
LMENU
lnk
+LOADFROMFILE
LOADLIBRARYASDATAFILE
LOBYTE
LOCALAPPDATA
@@ -917,6 +923,7 @@ LOCATIONCHANGE
logconsole
logfile
LOGFONT
+LOGFONTW
LOGMSG
logon
LOGPIXELSX
@@ -983,6 +990,8 @@ MAPPEDTOSAMEKEY
MAPTOSAMESHORTCUT
MAPVK
Markdig
+markdownpreviewhandler
+MARKDOWNPREVIEWHANDLERCPP
Markovic
Marquesas
martinchrzan
@@ -1015,6 +1024,7 @@ Metadatas
metafile
mfapi
mfc
+mfcm
mfidl
mfobjects
mfplat
@@ -1074,8 +1084,11 @@ mru
msbuild
msc
msclr
+mscordaccore
+mscordbi
mscoree
mscorlib
+mscorrc
msdata
msedge
MSGFLT
@@ -1088,6 +1101,7 @@ MSIXCA
MSLLHOOKSTRUCT
Mso
msp
+msquic
msrc
msstore
mst
@@ -1137,6 +1151,7 @@ netcpl
netframework
netsetup
netsh
+netstandard
Neue
newcolor
newdev
@@ -1313,6 +1328,7 @@ pinvoke
pipename
Pitcairn
PKBDLLHOOKSTRUCT
+Pkcs
PKEY
plib
PLK
@@ -1413,6 +1429,7 @@ QUERYENDSESSION
queryfocus
QUERYOPEN
QUEUESYNC
+Quic
Quickime
QUNS
qwertyuiopasdfghjklzxcvbnm
@@ -1530,7 +1547,7 @@ runtimeclass
runtimeconfig
runtimeobject
runtimes
-RUS
+rus
Rutkas
RValue
rvm
@@ -1574,7 +1591,6 @@ SETFOCUS
SETFOREGROUND
SETICON
setlocal
-Setrect
SETREDRAW
SETTEXT
SETTINGCHANGE
@@ -1682,6 +1698,8 @@ srw
srwlock
sse
ssf
+Ssl
+sss
STACKFRAME
stackoverflow
stackpanel
@@ -1799,6 +1817,7 @@ THH
THICKFRAME
THISCOMPONENT
THotkey
+thumbcache
TILEDWINDOW
timedate
timediff
@@ -1873,7 +1892,7 @@ uniquifier
Uniquifies
unitconverter
unittests
-unk
+Unk
unknwn
UNLEN
Unmap
@@ -2008,7 +2027,6 @@ WINDOWPOSCHANGING
Windowsapp
WINDOWSBUILDNUMBER
Windowscodecs
-windowsdesktop
windowssearch
windowssettings
WINDOWSTYLES
@@ -2071,6 +2089,7 @@ workspaces
wox
wparam
wpf
+wpfgfx
wpftmp
wpr
wprp
diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json
index dac486b7a2..af84380a24 100644
--- a/.pipelines/ESRPSigning_core.json
+++ b/.pipelines/ESRPSigning_core.json
@@ -46,26 +46,35 @@
"modules\\FancyZones\\PowerToys.FancyZones.exe",
"modules\\FileExplorerPreview\\PowerToys.GcodePreviewHandler.dll",
- "modules\\FileExplorerPreview\\PowerToys.GcodePreviewHandler.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.GcodePreviewHandler.exe",
+ "modules\\FileExplorerPreview\\PowerToys.GcodePreviewHandlerCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.GcodeThumbnailProvider.dll",
- "modules\\FileExplorerPreview\\PowerToys.GcodeThumbnailProvider.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.GcodeThumbnailProvider.exe",
+ "modules\\FileExplorerPreview\\PowerToys.GcodeThumbnailProviderCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.ManagedTelemetry.dll",
"modules\\FileExplorerPreview\\PowerToys.MarkdownPreviewHandler.dll",
- "modules\\FileExplorerPreview\\PowerToys.MarkdownPreviewHandler.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.MarkdownPreviewHandler.exe",
+ "modules\\FileExplorerPreview\\PowerToys.MarkdownPreviewHandlerCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.MonacoPreviewHandler.dll",
- "modules\\FileExplorerPreview\\PowerToys.MonacoPreviewHandler.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.MonacoPreviewHandler.exe",
+ "modules\\FileExplorerPreview\\PowerToys.MonacoPreviewHandlerCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.PdfPreviewHandler.dll",
- "modules\\FileExplorerPreview\\PowerToys.PdfPreviewHandler.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.PdfPreviewHandler.exe",
+ "modules\\FileExplorerPreview\\PowerToys.PdfPreviewHandlerCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.PdfThumbnailProvider.dll",
- "modules\\FileExplorerPreview\\PowerToys.PdfThumbnailProvider.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.PdfThumbnailProvider.exe",
+ "modules\\FileExplorerPreview\\PowerToys.PdfThumbnailProviderCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.powerpreview.dll",
"modules\\FileExplorerPreview\\PowerToys.PreviewHandlerCommon.dll",
"modules\\FileExplorerPreview\\PowerToys.StlThumbnailProvider.dll",
- "modules\\FileExplorerPreview\\PowerToys.StlThumbnailProvider.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.StlThumbnailProvider.exe",
+ "modules\\FileExplorerPreview\\PowerToys.StlThumbnailProviderCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.SvgPreviewHandler.dll",
- "modules\\FileExplorerPreview\\PowerToys.SvgPreviewHandler.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.SvgPreviewHandler.exe",
+ "modules\\FileExplorerPreview\\PowerToys.SvgPreviewHandlerCpp.dll",
"modules\\FileExplorerPreview\\PowerToys.SvgThumbnailProvider.dll",
- "modules\\FileExplorerPreview\\PowerToys.SvgThumbnailProvider.comhost.dll",
+ "modules\\FileExplorerPreview\\PowerToys.SvgThumbnailProvider.exe",
+ "modules\\FileExplorerPreview\\PowerToys.SvgThumbnailProviderCpp.dll",
"modules\\Hosts\\PowerToys.HostsModuleInterface.dll",
"modules\\Hosts\\PowerToys.Hosts.dll",
@@ -238,6 +247,7 @@
"modules\\launcher\\Interop.Microsoft.Office.Interop.OneNote.dll",
"modules\\launcher\\hyjiacan.py4n.dll",
"Settings\\Microsoft.Graphics.Canvas.Interop.dll",
+ "Settings\\clrcompression.dll",
"Settings\\CommunityToolkit.Labs.WinUI.SettingsControls.dll",
"ColorCode.Core.dll",
"ColorCode.UWP.dll",
diff --git a/.pipelines/ci/templates/build-powertoys-ci.yml b/.pipelines/ci/templates/build-powertoys-ci.yml
index b403ecdb30..20107c8063 100644
--- a/.pipelines/ci/templates/build-powertoys-ci.yml
+++ b/.pipelines/ci/templates/build-powertoys-ci.yml
@@ -9,6 +9,7 @@ jobs:
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
+ NUGET_RESTORE_MSBUILD_ARGS: /p:Platform=${{ parameters.platform }} # Required for nuget to work due to self contained
pool:
demands: ImageOverride -equals WinDevVS17-latest
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
diff --git a/.pipelines/release.yml b/.pipelines/release.yml
index cb6b6615e4..cab7398de9 100644
--- a/.pipelines/release.yml
+++ b/.pipelines/release.yml
@@ -39,6 +39,7 @@ jobs:
${{ config }}_${{ platform }}:
BuildConfiguration: ${{ config }}
BuildPlatform: ${{ platform }}
+ NUGET_RESTORE_MSBUILD_ARGS: /p:Platform=${{ platform }} # Required for nuget to work due to self contained
displayName: Build
timeoutInMinutes: 120 # Some of the loc stuff adds quite a bit of time.
cancelTimeoutInMinutes: 1
diff --git a/.pipelines/versionAndSignCheck.ps1 b/.pipelines/versionAndSignCheck.ps1
index 0e27375355..168f7d0c25 100644
--- a/.pipelines/versionAndSignCheck.ps1
+++ b/.pipelines/versionAndSignCheck.ps1
@@ -62,7 +62,8 @@ $items | ForEach-Object {
(-not $_.Name.EndsWith("Microsoft.WindowsAppRuntime.Bootstrap.dll")) -and
(-not $_.Name.EndsWith("MRM.dll")) -and
(-not $_.Name.EndsWith("PushNotificationsLongRunningTask.ProxyStub.dll")) -and
- (-not $_.Name.EndsWith("WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll"))
+ (-not $_.Name.EndsWith("WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll")) -and
+ (-not $_.Name.EndsWith("System.Diagnostics.EventLog.Messages.dll"))
)
{
Write-Host "Version not set: " + $_.FullName
diff --git a/PowerToys.sln b/PowerToys.sln
index 1d85f27dde..7583cc9b36 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -468,6 +468,24 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPOWrapper", "src\common\GP
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPOWrapperProjection", "src\common\GPOWrapperProjection\GPOWrapperProjection.csproj", "{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MarkdownPreviewHandlerCpp", "src\modules\previewpane\MarkdownPreviewHandlerCpp\MarkdownPreviewHandlerCpp.vcxproj", "{ED9A1AC6-AEB0-4569-A6E9-E1696182B545}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GcodePreviewHandlerCpp", "src\modules\previewpane\GcodePreviewHandlerCpp\GcodePreviewHandlerCpp.vcxproj", "{5A5DD09D-723A-44D3-8F2B-293584C3D731}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MonacoPreviewHandlerCpp", "src\modules\previewpane\MonacoPreviewHandlerCpp\MonacoPreviewHandlerCpp.vcxproj", "{B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PdfPreviewHandlerCpp", "src\modules\previewpane\PdfPreviewHandlerCpp\PdfPreviewHandlerCpp.vcxproj", "{54F7C616-FD41-4E62-BFF9-015686914F4D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SvgPreviewHandlerCpp", "src\modules\previewpane\SvgPreviewHandlerCpp\SvgPreviewHandlerCpp.vcxproj", "{143F13E3-D2E3-4D83-B035-356612D99956}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GcodeThumbnailProviderCpp", "src\modules\previewpane\GcodeThumbnailProviderCpp\GcodeThumbnailProviderCpp.vcxproj", "{56CC2F10-6E41-453D-BE16-C593A5E58482}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PdfThumbnailProviderCpp", "src\modules\previewpane\PdfThumbnailProviderCpp\PdfThumbnailProviderCpp.vcxproj", "{CA5518ED-0458-4B09-8F53-4122B9888655}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StlThumbnailProviderCpp", "src\modules\previewpane\StlThumbnailProviderCpp\StlThumbnailProviderCpp.vcxproj", "{D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SvgThumbnailProviderCpp", "src\modules\previewpane\SvgThumbnailProviderCpp\SvgThumbnailProviderCpp.vcxproj", "{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -1895,6 +1913,114 @@ Global
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x64.Build.0 = Release|x64
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x86.ActiveCfg = Release|x64
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x86.Build.0 = Release|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|ARM64.Build.0 = Debug|ARM64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|x64.ActiveCfg = Debug|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|x64.Build.0 = Debug|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|x86.ActiveCfg = Debug|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|x86.Build.0 = Debug|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Release|ARM64.ActiveCfg = Release|ARM64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Release|ARM64.Build.0 = Release|ARM64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Release|x64.ActiveCfg = Release|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Release|x64.Build.0 = Release|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Release|x86.ActiveCfg = Release|x64
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Release|x86.Build.0 = Release|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Debug|ARM64.Build.0 = Debug|ARM64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Debug|x64.ActiveCfg = Debug|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Debug|x64.Build.0 = Debug|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Debug|x86.ActiveCfg = Debug|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Debug|x86.Build.0 = Debug|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Release|ARM64.ActiveCfg = Release|ARM64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Release|ARM64.Build.0 = Release|ARM64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Release|x64.ActiveCfg = Release|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Release|x64.Build.0 = Release|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Release|x86.ActiveCfg = Release|x64
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731}.Release|x86.Build.0 = Release|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Debug|ARM64.Build.0 = Debug|ARM64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Debug|x64.ActiveCfg = Debug|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Debug|x64.Build.0 = Debug|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Debug|x86.ActiveCfg = Debug|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Debug|x86.Build.0 = Debug|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Release|ARM64.Build.0 = Release|ARM64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Release|x64.ActiveCfg = Release|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Release|x64.Build.0 = Release|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Release|x86.ActiveCfg = Release|x64
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9}.Release|x86.Build.0 = Release|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Debug|x64.ActiveCfg = Debug|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Debug|x64.Build.0 = Debug|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Debug|x86.ActiveCfg = Debug|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Debug|x86.Build.0 = Debug|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Release|ARM64.Build.0 = Release|ARM64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Release|x64.ActiveCfg = Release|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Release|x64.Build.0 = Release|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Release|x86.ActiveCfg = Release|x64
+ {54F7C616-FD41-4E62-BFF9-015686914F4D}.Release|x86.Build.0 = Release|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Debug|ARM64.Build.0 = Debug|ARM64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Debug|x64.ActiveCfg = Debug|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Debug|x64.Build.0 = Debug|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Debug|x86.ActiveCfg = Debug|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Debug|x86.Build.0 = Debug|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Release|ARM64.ActiveCfg = Release|ARM64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Release|ARM64.Build.0 = Release|ARM64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Release|x64.ActiveCfg = Release|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Release|x64.Build.0 = Release|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Release|x86.ActiveCfg = Release|x64
+ {143F13E3-D2E3-4D83-B035-356612D99956}.Release|x86.Build.0 = Release|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Debug|ARM64.Build.0 = Debug|ARM64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Debug|x64.ActiveCfg = Debug|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Debug|x64.Build.0 = Debug|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Debug|x86.ActiveCfg = Debug|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Debug|x86.Build.0 = Debug|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Release|ARM64.ActiveCfg = Release|ARM64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Release|ARM64.Build.0 = Release|ARM64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Release|x64.ActiveCfg = Release|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Release|x64.Build.0 = Release|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Release|x86.ActiveCfg = Release|x64
+ {56CC2F10-6E41-453D-BE16-C593A5E58482}.Release|x86.Build.0 = Release|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Debug|ARM64.Build.0 = Debug|ARM64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Debug|x64.ActiveCfg = Debug|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Debug|x64.Build.0 = Debug|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Debug|x86.ActiveCfg = Debug|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Debug|x86.Build.0 = Debug|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Release|ARM64.Build.0 = Release|ARM64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Release|x64.ActiveCfg = Release|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Release|x64.Build.0 = Release|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Release|x86.ActiveCfg = Release|x64
+ {CA5518ED-0458-4B09-8F53-4122B9888655}.Release|x86.Build.0 = Release|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Debug|x64.ActiveCfg = Debug|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Debug|x64.Build.0 = Debug|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Debug|x86.ActiveCfg = Debug|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Debug|x86.Build.0 = Debug|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Release|ARM64.Build.0 = Release|ARM64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Release|x64.ActiveCfg = Release|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Release|x64.Build.0 = Release|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Release|x86.ActiveCfg = Release|x64
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D}.Release|x86.Build.0 = Release|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Debug|x64.ActiveCfg = Debug|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Debug|x64.Build.0 = Debug|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Debug|x86.ActiveCfg = Debug|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Debug|x86.Build.0 = Debug|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|ARM64.Build.0 = Release|ARM64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x64.ActiveCfg = Release|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x64.Build.0 = Release|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x86.ActiveCfg = Release|x64
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2056,6 +2182,15 @@ Global
{C604B37E-9D0E-4484-8778-E8B31B0E1B3A} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
{E599C30B-9DC8-4E5A-BF27-93D4CCEDE788} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97} = {1AFB6476-670D-4E80-A464-657E01DFF482}
+ {ED9A1AC6-AEB0-4569-A6E9-E1696182B545} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {5A5DD09D-723A-44D3-8F2B-293584C3D731} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {54F7C616-FD41-4E62-BFF9-015686914F4D} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {143F13E3-D2E3-4D83-B035-356612D99956} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {56CC2F10-6E41-453D-BE16-C593A5E58482} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {CA5518ED-0458-4B09-8F53-4122B9888655} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {2BBC9E33-21EC-401C-84DA-BB6590A9B2AA} = {2F305555-C296-497E-AC20-5FA1B237996A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
diff --git a/installer/PowerToysSetup/PowerToys.wxs b/installer/PowerToysSetup/PowerToys.wxs
index f3e5cfeac5..0818170273 100644
--- a/installer/PowerToysSetup/PowerToys.wxs
+++ b/installer/PowerToysSetup/PowerToys.wxs
@@ -6,21 +6,13 @@
-
-
-
-
-
-
-
-
-
+
@@ -41,7 +33,6 @@
SuppressRepair="yes" />
-
@@ -73,26 +64,6 @@
PerMachine="yes"
Vital="no">
-
-
-
-
-
+
-
+
-
+
+
+
+
+
-
+
@@ -117,7 +121,7 @@
-
+
@@ -125,9 +129,9 @@
-
+
-
+
@@ -139,7 +143,19 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
NOT Installed and CREATESCHEDULEDTASK = 1
@@ -250,6 +268,9 @@
NOT Installed
+
+ NOT Installed
+
@@ -275,6 +296,10 @@
Installed AND (REMOVE="ALL")
+
+ Installed AND (REMOVE="ALL")
+
+
+
+
+
+
+
@@ -758,6 +806,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1056,8 +1116,8 @@
-
-
+
+
@@ -1076,8 +1136,8 @@
-
-
+
+
@@ -1086,8 +1146,8 @@
-
-
+
+
@@ -1384,8 +1444,9 @@
-
-
+
+
+
@@ -2066,7 +2127,7 @@
-
+
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp
index 7434fe3af7..faa67c0931 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.cpp
+++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp
@@ -15,6 +15,8 @@
#include
#include
+#include "DepsFilesLists.h"
+
using namespace std;
HINSTANCE DLL_HANDLE = nullptr;
@@ -32,56 +34,6 @@ 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}";
-const std::vector winAppSdkFiles = {
- L"CoreMessagingXP.dll",
- L"DWriteCore.dll",
- L"DwmSceneI.dll",
- L"MRM.dll",
- L"Microsoft.DirectManipulation.dll",
- L"Microsoft.InputStateManager.dll",
- L"Microsoft.Internal.FrameworkUdk.dll",
- L"Microsoft.UI.Composition.OSSupport.dll",
- L"Microsoft.UI.Input.dll",
- L"Microsoft.UI.Windowing.Core.dll",
- L"Microsoft.UI.Xaml.Controls.dll",
- L"Microsoft.UI.Xaml.Controls.pri",
- L"Microsoft.UI.Xaml.Internal.dll",
- L"Microsoft.UI.Xaml.Phone.dll",
- L"Microsoft.Web.WebView2.Core.dll",
- L"Microsoft.Windows.AppNotifications.Projection.dll",
- L"Microsoft.Windows.ApplicationModel.Resources.dll",
- L"Microsoft.WindowsAppRuntime.Bootstrap.dll",
- L"Microsoft.Windows.PushNotifications.Projection.dll",
- L"Microsoft.Windows.System.Projection.dll",
- L"Microsoft.WindowsAppRuntime.Insights.Resource.dll",
- L"Microsoft.WindowsAppRuntime.Release.Net.dll",
- L"Microsoft.WindowsAppRuntime.dll",
- L"Microsoft.ui.xaml.dll",
- L"Microsoft.ui.xaml.resources.19h1.dll",
- L"Microsoft.ui.xaml.resources.common.dll",
- L"PushNotificationsLongRunningTask.ProxyStub.dll",
- L"WinUIEdit.dll",
- L"WindowsAppRuntime.png",
- L"WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll",
- L"dcompi.dll",
- L"dwmcorei.dll",
- L"marshal.dll",
- L"wuceffectsi.dll" };
-
-const std::vector powerToysInteropFiles = {
- L"concrt140.dll",
- L"msvcp140.dll",
- L"msvcp140_1.dll",
- L"msvcp140_2.dll",
- L"msvcp140_atomic_wait.dll",
- L"msvcp140_codecvt_ids.dll",
- L"PowerToys.Interop.dll",
- L"vcamp140.dll",
- L"vccorlib140.dll",
- L"vcomp140.dll",
- L"vcruntime140.dll",
- L"vcruntime140_1.dll" };
-
struct WcaSink : spdlog::sinks::base_sink
{
virtual void sink_it_(const spdlog::details::log_msg& msg) override
@@ -1103,6 +1055,7 @@ const std::wstring PTInteropConsumers[] =
L"modules\\PowerAccent",
L"modules\\FileLocksmith",
L"modules\\Hosts",
+ L"modules\\FileExplorerPreview",
};
UINT __stdcall CreatePTInteropHardlinksCA(MSIHANDLE hInstall)
@@ -1141,6 +1094,87 @@ LExit:
return WcaFinalize(er);
}
+UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ std::wstring installationFolder, dotnetRuntimeFilesSrcDir, colorPickerDir, powerOCRDir, launcherDir, fancyZonesDir,
+ imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir, hostsDir, fileLocksmithDir;
+
+ hr = WcaInitialize(hInstall, "CreateDotnetRuntimeHardlinksCA");
+ ExitOnFailure(hr, "Failed to initialize");
+
+ hr = getInstallFolder(hInstall, installationFolder);
+ ExitOnFailure(hr, "Failed to get installation folder");
+
+ dotnetRuntimeFilesSrcDir = installationFolder + L"dll\\dotnet\\";
+ colorPickerDir = installationFolder + L"modules\\ColorPicker\\";
+ powerOCRDir = installationFolder + L"modules\\PowerOCR\\";
+ launcherDir = installationFolder + L"modules\\launcher\\";
+ fancyZonesDir = installationFolder + L"modules\\FancyZones\\";
+ imageResizerDir = installationFolder + L"modules\\ImageResizer\\";
+ settingsDir = installationFolder + L"Settings\\";
+ awakeDir = installationFolder + L"modules\\Awake\\";
+ measureToolDir = installationFolder + L"modules\\MeasureTool\\";
+ powerAccentDir = installationFolder + L"modules\\PowerAccent\\";
+ fileExplorerAddOnsDir = installationFolder + L"modules\\FileExplorerPreview\\";
+ hostsDir = installationFolder + L"modules\\Hosts\\";
+ fileLocksmithDir = installationFolder + L"modules\\FileLocksmith\\";
+
+ for (auto file : dotnetRuntimeFiles)
+ {
+ std::error_code ec;
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (colorPickerDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerOCRDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (launcherDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fancyZonesDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (imageResizerDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (settingsDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (awakeDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (measureToolDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerAccentDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileExplorerAddOnsDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileLocksmithDir + file).c_str(), ec);
+
+ if (ec.value() != S_OK)
+ {
+ std::wstring errorMessage{ L"Error creating hard link for: " };
+ errorMessage += file;
+ errorMessage += L", error code: " + std::to_wstring(ec.value());
+ Logger::error(errorMessage);
+ er = ERROR_INSTALL_FAILURE;
+ }
+ }
+
+ for (auto file : dotnetRuntimeWPFFiles)
+ {
+ std::error_code ec;
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (awakeDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (colorPickerDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerOCRDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (launcherDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fancyZonesDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (imageResizerDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerAccentDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileExplorerAddOnsDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
+
+ if (ec.value() != S_OK)
+ {
+ std::wstring errorMessage{ L"Error creating hard link for: " };
+ errorMessage += file;
+ errorMessage += L", error code: " + std::to_wstring(ec.value());
+ Logger::error(errorMessage);
+ er = ERROR_INSTALL_FAILURE;
+ }
+ }
+
+ LExit:
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
UINT __stdcall DeleteWinAppSDKHardlinksCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
@@ -1213,6 +1247,78 @@ LExit:
return WcaFinalize(er);
}
+UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ std::wstring installationFolder, colorPickerDir, powerOCRDir, launcherDir, fancyZonesDir,
+ imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir,
+ hostsDir, fileLocksmithDir;
+
+ hr = WcaInitialize(hInstall, "DeleteDotnetRuntimeHardlinksCA");
+ ExitOnFailure(hr, "Failed to initialize");
+
+ hr = getInstallFolder(hInstall, installationFolder);
+ ExitOnFailure(hr, "Failed to get installation folder");
+
+ colorPickerDir = installationFolder + L"modules\\ColorPicker\\";
+ powerOCRDir = installationFolder + L"modules\\PowerOCR\\";
+ launcherDir = installationFolder + L"modules\\launcher\\";
+ fancyZonesDir = installationFolder + L"modules\\FancyZones\\";
+ imageResizerDir = installationFolder + L"modules\\ImageResizer\\";
+ settingsDir = installationFolder + L"Settings\\";
+ awakeDir = installationFolder + L"modules\\Awake\\";
+ measureToolDir = installationFolder + L"modules\\MeasureTool\\";
+ powerAccentDir = installationFolder + L"modules\\PowerAccent\\";
+ fileExplorerAddOnsDir = installationFolder + L"modules\\FileExplorerPreview\\";
+ hostsDir = installationFolder + L"modules\\Hosts\\";
+ fileLocksmithDir = installationFolder + L"modules\\FileLocksmith\\";
+
+ try
+ {
+ for (auto file : dotnetRuntimeFiles)
+ {
+ DeleteFile((colorPickerDir + file).c_str());
+ DeleteFile((powerOCRDir + file).c_str());
+ DeleteFile((launcherDir + file).c_str());
+ DeleteFile((fancyZonesDir + file).c_str());
+ DeleteFile((imageResizerDir + file).c_str());
+ DeleteFile((settingsDir + file).c_str());
+ DeleteFile((awakeDir + file).c_str());
+ DeleteFile((measureToolDir + file).c_str());
+ DeleteFile((powerAccentDir + file).c_str());
+ DeleteFile((fileExplorerAddOnsDir + file).c_str());
+ DeleteFile((hostsDir + file).c_str());
+ DeleteFile((fileLocksmithDir + file).c_str());
+ }
+
+ for (auto file : dotnetRuntimeWPFFiles)
+ {
+ DeleteFile((awakeDir + file).c_str());
+ DeleteFile((colorPickerDir + file).c_str());
+ DeleteFile((powerOCRDir + file).c_str());
+ DeleteFile((launcherDir + file).c_str());
+ DeleteFile((fancyZonesDir + file).c_str());
+ DeleteFile((imageResizerDir + file).c_str());
+ DeleteFile((powerAccentDir + file).c_str());
+ DeleteFile((fileExplorerAddOnsDir + file).c_str());
+ DeleteFile((hostsDir + file).c_str());
+ }
+ }
+ catch (std::exception e)
+ {
+ std::string errorMessage{ "Exception thrown while trying to delete dotnet runtime hardlinks: " };
+ errorMessage += e.what();
+ Logger::error(errorMessage);
+
+ er = ERROR_INSTALL_FAILURE;
+ }
+
+LExit:
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def
index 3a36f02f7d..27d59b2fda 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.def
+++ b/installer/PowerToysSetupCustomActions/CustomAction.def
@@ -7,6 +7,8 @@ EXPORTS
DeleteWinAppSDKHardlinksCA
CreatePTInteropHardlinksCA
DeletePTInteropHardlinksCA
+ CreateDotnetRuntimeHardlinksCA
+ DeleteDotnetRuntimeHardlinksCA
DetectPrevInstallPathCA
RemoveScheduledTasksCA
TelemetryLogInstallSuccessCA
diff --git a/installer/PowerToysSetupCustomActions/DepsFilesLists.h b/installer/PowerToysSetupCustomActions/DepsFilesLists.h
new file mode 100644
index 0000000000..de7e4e0b7d
--- /dev/null
+++ b/installer/PowerToysSetupCustomActions/DepsFilesLists.h
@@ -0,0 +1,535 @@
+#pragma once
+
+#include
+#include
+
+inline const std::vector winAppSdkFiles = {
+ L"CoreMessagingXP.dll",
+ L"DWriteCore.dll",
+ L"DwmSceneI.dll",
+ L"MRM.dll",
+ L"Microsoft.DirectManipulation.dll",
+ L"Microsoft.InputStateManager.dll",
+ L"Microsoft.Internal.FrameworkUdk.dll",
+ L"Microsoft.UI.Composition.OSSupport.dll",
+ L"Microsoft.UI.Input.dll",
+ L"Microsoft.UI.Windowing.Core.dll",
+ L"Microsoft.UI.Xaml.Controls.dll",
+ L"Microsoft.UI.Xaml.Controls.pri",
+ L"Microsoft.UI.Xaml.Internal.dll",
+ L"Microsoft.UI.Xaml.Phone.dll",
+ L"Microsoft.Web.WebView2.Core.dll",
+ L"Microsoft.Windows.AppNotifications.Projection.dll",
+ L"Microsoft.Windows.ApplicationModel.Resources.dll",
+ L"Microsoft.WindowsAppRuntime.Bootstrap.dll",
+ L"Microsoft.Windows.PushNotifications.Projection.dll",
+ L"Microsoft.Windows.System.Projection.dll",
+ L"Microsoft.WindowsAppRuntime.Insights.Resource.dll",
+ L"Microsoft.WindowsAppRuntime.Release.Net.dll",
+ L"Microsoft.WindowsAppRuntime.dll",
+ L"Microsoft.ui.xaml.dll",
+ L"Microsoft.ui.xaml.resources.19h1.dll",
+ L"Microsoft.ui.xaml.resources.common.dll",
+ L"PushNotificationsLongRunningTask.ProxyStub.dll",
+ L"WinUIEdit.dll",
+ L"WindowsAppRuntime.png",
+ L"WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll",
+ L"dcompi.dll",
+ L"dwmcorei.dll",
+ L"marshal.dll",
+ L"wuceffectsi.dll"
+};
+
+inline const std::vector powerToysInteropFiles = {
+ L"concrt140.dll",
+ L"msvcp140.dll",
+ L"msvcp140_1.dll",
+ L"msvcp140_2.dll",
+ L"msvcp140_atomic_wait.dll",
+ L"msvcp140_codecvt_ids.dll",
+ L"PowerToys.Interop.dll",
+ L"vcamp140.dll",
+ L"vccorlib140.dll",
+ L"vcomp140.dll",
+ L"vcruntime140.dll",
+ L"vcruntime140_1.dll"
+};
+
+#ifdef _M_X64
+inline const std::vector dotnetRuntimeFiles = {
+ L"clrcompression.dll",
+ L"clretwrc.dll",
+ L"clrgc.dll",
+ L"clrjit.dll",
+ L"coreclr.dll",
+ L"hostfxr.dll",
+ L"hostpolicy.dll",
+ L"Microsoft.CSharp.dll",
+ L"Microsoft.DiaSymReader.Native.amd64.dll",
+ L"Microsoft.VisualBasic.Core.dll",
+ L"Microsoft.VisualBasic.dll",
+ L"Microsoft.Win32.Primitives.dll",
+ L"Microsoft.Win32.Registry.dll",
+ L"mscordaccore.dll",
+ L"mscordbi.dll",
+ L"mscorlib.dll",
+ L"mscorrc.dll",
+ L"msquic.dll",
+ L"netstandard.dll",
+ L"System.AppContext.dll",
+ L"System.Buffers.dll",
+ L"System.CodeDom.dll",
+ L"System.Collections.Concurrent.dll",
+ L"System.Collections.dll",
+ L"System.Collections.Immutable.dll",
+ L"System.Collections.NonGeneric.dll",
+ L"System.Collections.Specialized.dll",
+ L"System.ComponentModel.Annotations.dll",
+ L"System.ComponentModel.DataAnnotations.dll",
+ L"System.ComponentModel.dll",
+ L"System.ComponentModel.EventBasedAsync.dll",
+ L"System.ComponentModel.Primitives.dll",
+ L"System.ComponentModel.TypeConverter.dll",
+ L"System.Configuration.dll",
+ L"System.Console.dll",
+ L"System.Core.dll",
+ L"System.Data.Common.dll",
+ L"System.Data.DataSetExtensions.dll",
+ L"System.Data.dll",
+ L"System.Diagnostics.Contracts.dll",
+ L"System.Diagnostics.Debug.dll",
+ L"System.Diagnostics.DiagnosticSource.dll",
+ L"System.Diagnostics.FileVersionInfo.dll",
+ L"System.Diagnostics.Process.dll",
+ L"System.Diagnostics.StackTrace.dll",
+ L"System.Diagnostics.TextWriterTraceListener.dll",
+ L"System.Diagnostics.Tools.dll",
+ L"System.Diagnostics.TraceSource.dll",
+ L"System.Diagnostics.Tracing.dll",
+ L"System.dll",
+ L"System.Drawing.dll",
+ L"System.Drawing.Primitives.dll",
+ L"System.Dynamic.Runtime.dll",
+ L"System.Formats.Asn1.dll",
+ L"System.Formats.Tar.dll",
+ L"System.Globalization.Calendars.dll",
+ L"System.Globalization.dll",
+ L"System.Globalization.Extensions.dll",
+ L"System.IO.Compression.Brotli.dll",
+ L"System.IO.Compression.dll",
+ L"System.IO.Compression.FileSystem.dll",
+ L"System.IO.Compression.Native.dll",
+ L"System.IO.Compression.ZipFile.dll",
+ L"System.IO.dll",
+ L"System.IO.FileSystem.AccessControl.dll",
+ L"System.IO.FileSystem.dll",
+ L"System.IO.FileSystem.DriveInfo.dll",
+ L"System.IO.FileSystem.Primitives.dll",
+ L"System.IO.FileSystem.Watcher.dll",
+ L"System.IO.IsolatedStorage.dll",
+ L"System.IO.MemoryMappedFiles.dll",
+ L"System.IO.Pipes.AccessControl.dll",
+ L"System.IO.Pipes.dll",
+ L"System.IO.UnmanagedMemoryStream.dll",
+ L"System.Linq.dll",
+ L"System.Linq.Expressions.dll",
+ L"System.Linq.Parallel.dll",
+ L"System.Linq.Queryable.dll",
+ L"System.Memory.dll",
+ L"System.Net.dll",
+ L"System.Net.Http.dll",
+ L"System.Net.Http.Json.dll",
+ L"System.Net.HttpListener.dll",
+ L"System.Net.Mail.dll",
+ L"System.Net.NameResolution.dll",
+ L"System.Net.NetworkInformation.dll",
+ L"System.Net.Ping.dll",
+ L"System.Net.Primitives.dll",
+ L"System.Net.Quic.dll",
+ L"System.Net.Requests.dll",
+ L"System.Net.Security.dll",
+ L"System.Net.ServicePoint.dll",
+ L"System.Net.Sockets.dll",
+ L"System.Net.WebClient.dll",
+ L"System.Net.WebHeaderCollection.dll",
+ L"System.Net.WebProxy.dll",
+ L"System.Net.WebSockets.Client.dll",
+ L"System.Net.WebSockets.dll",
+ L"System.Numerics.dll",
+ L"System.Numerics.Vectors.dll",
+ L"System.ObjectModel.dll",
+ L"System.Private.CoreLib.dll",
+ L"System.Private.DataContractSerialization.dll",
+ L"System.Private.Uri.dll",
+ L"System.Private.Xml.dll",
+ L"System.Private.Xml.Linq.dll",
+ L"System.Reflection.DispatchProxy.dll",
+ L"System.Reflection.dll",
+ L"System.Reflection.Emit.dll",
+ L"System.Reflection.Emit.ILGeneration.dll",
+ L"System.Reflection.Emit.Lightweight.dll",
+ L"System.Reflection.Extensions.dll",
+ L"System.Reflection.Metadata.dll",
+ L"System.Reflection.Primitives.dll",
+ L"System.Reflection.TypeExtensions.dll",
+ L"System.Resources.Reader.dll",
+ L"System.Resources.ResourceManager.dll",
+ L"System.Resources.Writer.dll",
+ L"System.Runtime.CompilerServices.Unsafe.dll",
+ L"System.Runtime.CompilerServices.VisualC.dll",
+ L"System.Runtime.dll",
+ L"System.Runtime.Extensions.dll",
+ L"System.Runtime.Handles.dll",
+ L"System.Runtime.InteropServices.dll",
+ L"System.Runtime.InteropServices.JavaScript.dll",
+ L"System.Runtime.InteropServices.RuntimeInformation.dll",
+ L"System.Runtime.Intrinsics.dll",
+ L"System.Runtime.Loader.dll",
+ L"System.Runtime.Numerics.dll",
+ L"System.Runtime.Serialization.dll",
+ L"System.Runtime.Serialization.Formatters.dll",
+ L"System.Runtime.Serialization.Json.dll",
+ L"System.Runtime.Serialization.Primitives.dll",
+ L"System.Runtime.Serialization.Xml.dll",
+ L"System.Security.AccessControl.dll",
+ L"System.Security.Claims.dll",
+ L"System.Security.Cryptography.dll",
+ L"System.Security.Cryptography.Algorithms.dll",
+ L"System.Security.Cryptography.Cng.dll",
+ L"System.Security.Cryptography.Csp.dll",
+ L"System.Security.Cryptography.Encoding.dll",
+ L"System.Security.Cryptography.OpenSsl.dll",
+ L"System.Security.Cryptography.Primitives.dll",
+ L"System.Security.Cryptography.X509Certificates.dll",
+ L"System.Security.dll",
+ L"System.Security.Principal.dll",
+ L"System.Security.Principal.Windows.dll",
+ L"System.Security.SecureString.dll",
+ L"System.ServiceModel.Web.dll",
+ L"System.ServiceProcess.dll",
+ L"System.Text.Encoding.CodePages.dll",
+ L"System.Text.Encoding.dll",
+ L"System.Text.Encoding.Extensions.dll",
+ L"System.Text.Encodings.Web.dll",
+ L"System.Text.RegularExpressions.dll",
+ L"System.Threading.Channels.dll",
+ L"System.Threading.dll",
+ L"System.Threading.Overlapped.dll",
+ L"System.Threading.Tasks.Dataflow.dll",
+ L"System.Threading.Tasks.dll",
+ L"System.Threading.Tasks.Extensions.dll",
+ L"System.Threading.Tasks.Parallel.dll",
+ L"System.Threading.Thread.dll",
+ L"System.Threading.ThreadPool.dll",
+ L"System.Threading.Timer.dll",
+ L"System.Transactions.dll",
+ L"System.Transactions.Local.dll",
+ L"System.ValueTuple.dll",
+ L"System.Web.dll",
+ L"System.Web.HttpUtility.dll",
+ L"System.Windows.dll",
+ L"System.Xml.dll",
+ L"System.Xml.Linq.dll",
+ L"System.Xml.ReaderWriter.dll",
+ L"System.Xml.Serialization.dll",
+ L"System.Xml.XDocument.dll",
+ L"System.Xml.XmlDocument.dll",
+ L"System.Xml.XmlSerializer.dll",
+ L"System.Xml.XPath.dll",
+ L"System.Xml.XPath.XDocument.dll" };
+
+inline const std::vector dotnetRuntimeWPFFiles = {
+ L"Accessibility.dll",
+ L"D3DCompiler_47_cor3.dll",
+ L"DirectWriteForwarder.dll",
+ L"Microsoft.VisualBasic.Forms.dll",
+ L"Microsoft.Win32.Registry.AccessControl.dll",
+ L"Microsoft.Win32.SystemEvents.dll",
+ L"PenImc_cor3.dll",
+ L"PresentationCore.dll",
+ L"PresentationFramework-SystemCore.dll",
+ L"PresentationFramework-SystemData.dll",
+ L"PresentationFramework-SystemDrawing.dll",
+ L"PresentationFramework-SystemXml.dll",
+ L"PresentationFramework-SystemXmlLinq.dll",
+ L"PresentationFramework.Aero.dll",
+ L"PresentationFramework.Aero2.dll",
+ L"PresentationFramework.AeroLite.dll",
+ L"PresentationFramework.Classic.dll",
+ L"PresentationFramework.dll",
+ L"PresentationFramework.Luna.dll",
+ L"PresentationFramework.Royale.dll",
+ L"PresentationNative_cor3.dll",
+ L"PresentationUI.dll",
+ L"ReachFramework.dll",
+ L"System.Configuration.ConfigurationManager.dll",
+ L"System.Design.dll",
+ L"System.Diagnostics.EventLog.dll",
+ L"System.Diagnostics.EventLog.Messages.dll",
+ L"System.Diagnostics.PerformanceCounter.dll",
+ L"System.DirectoryServices.dll",
+ L"System.Drawing.Common.dll",
+ L"System.Drawing.Design.dll",
+ L"System.IO.Packaging.dll",
+ L"System.Printing.dll",
+ L"System.Resources.Extensions.dll",
+ L"System.Security.Cryptography.Pkcs.dll",
+ L"System.Security.Cryptography.ProtectedData.dll",
+ L"System.Security.Cryptography.Xml.dll",
+ L"System.Security.Permissions.dll",
+ L"System.Threading.AccessControl.dll",
+ L"System.Windows.Controls.Ribbon.dll",
+ L"System.Windows.Extensions.dll",
+ L"System.Windows.Forms.Design.dll",
+ L"System.Windows.Forms.Design.Editors.dll",
+ L"System.Windows.Forms.dll",
+ L"System.Windows.Forms.Primitives.dll",
+ L"System.Windows.Input.Manipulations.dll",
+ L"System.Windows.Presentation.dll",
+ L"System.Xaml.dll",
+ L"UIAutomationClient.dll",
+ L"UIAutomationClientSideProviders.dll",
+ L"UIAutomationProvider.dll",
+ L"UIAutomationTypes.dll",
+ L"vcruntime140_cor3.dll",
+ L"WindowsFormsIntegration.dll",
+ L"wpfgfx_cor3.dll" };
+#else //ARM64
+inline const std::vector dotnetRuntimeFiles = {
+ L"clretwrc.dll",
+ L"clrgc.dll",
+ L"clrjit.dll",
+ L"coreclr.dll",
+ L"dbgshim.dll",
+ L"hostfxr.dll",
+ L"hostpolicy.dll",
+ L"Microsoft.CSharp.dll",
+ L"Microsoft.DiaSymReader.Native.arm64.dll",
+ L"Microsoft.Graphics.Canvas.dll",
+ L"Microsoft.VisualBasic.Core.dll",
+ L"Microsoft.VisualBasic.dll",
+ L"Microsoft.Win32.Primitives.dll",
+ L"Microsoft.Win32.Registry.dll",
+ L"mscordaccore.dll",
+ L"mscordbi.dll",
+ L"mscorlib.dll",
+ L"mscorrc.dll",
+ L"netstandard.dll",
+ L"System.AppContext.dll",
+ L"System.Buffers.dll",
+ L"System.Collections.Concurrent.dll",
+ L"System.Collections.dll",
+ L"System.Collections.Immutable.dll",
+ L"System.Collections.NonGeneric.dll",
+ L"System.Collections.Specialized.dll",
+ L"System.ComponentModel.Annotations.dll",
+ L"System.ComponentModel.DataAnnotations.dll",
+ L"System.ComponentModel.dll",
+ L"System.ComponentModel.EventBasedAsync.dll",
+ L"System.ComponentModel.Primitives.dll",
+ L"System.ComponentModel.TypeConverter.dll",
+ L"System.Configuration.dll",
+ L"System.Console.dll",
+ L"System.Core.dll",
+ L"System.Data.Common.dll",
+ L"System.Data.DataSetExtensions.dll",
+ L"System.Data.dll",
+ L"System.Diagnostics.Contracts.dll",
+ L"System.Diagnostics.Debug.dll",
+ L"System.Diagnostics.DiagnosticSource.dll",
+ L"System.Diagnostics.FileVersionInfo.dll",
+ L"System.Diagnostics.Process.dll",
+ L"System.Diagnostics.StackTrace.dll",
+ L"System.Diagnostics.TextWriterTraceListener.dll",
+ L"System.Diagnostics.Tools.dll",
+ L"System.Diagnostics.TraceSource.dll",
+ L"System.Diagnostics.Tracing.dll",
+ L"System.dll",
+ L"System.Drawing.dll",
+ L"System.Drawing.Primitives.dll",
+ L"System.Dynamic.Runtime.dll",
+ L"System.Formats.Asn1.dll",
+ L"System.Formats.Tar.dll",
+ L"System.Globalization.Calendars.dll",
+ L"System.Globalization.dll",
+ L"System.Globalization.Extensions.dll",
+ L"System.IO.Compression.Brotli.dll",
+ L"System.IO.Compression.dll",
+ L"System.IO.Compression.FileSystem.dll",
+ L"System.IO.Compression.Native.dll",
+ L"System.IO.Compression.ZipFile.dll",
+ L"System.IO.dll",
+ L"System.IO.FileSystem.AccessControl.dll",
+ L"System.IO.FileSystem.dll",
+ L"System.IO.FileSystem.DriveInfo.dll",
+ L"System.IO.FileSystem.Primitives.dll",
+ L"System.IO.FileSystem.Watcher.dll",
+ L"System.IO.IsolatedStorage.dll",
+ L"System.IO.MemoryMappedFiles.dll",
+ L"System.IO.Pipes.AccessControl.dll",
+ L"System.IO.Pipes.dll",
+ L"System.IO.UnmanagedMemoryStream.dll",
+ L"System.Linq.dll",
+ L"System.Linq.Expressions.dll",
+ L"System.Linq.Parallel.dll",
+ L"System.Linq.Queryable.dll",
+ L"System.Memory.dll",
+ L"System.Net.dll",
+ L"System.Net.Http.dll",
+ L"System.Net.Http.Json.dll",
+ L"System.Net.HttpListener.dll",
+ L"System.Net.Mail.dll",
+ L"System.Net.NameResolution.dll",
+ L"System.Net.NetworkInformation.dll",
+ L"System.Net.Ping.dll",
+ L"System.Net.Primitives.dll",
+ L"System.Net.Quic.dll",
+ L"System.Net.Requests.dll",
+ L"System.Net.Security.dll",
+ L"System.Net.ServicePoint.dll",
+ L"System.Net.Sockets.dll",
+ L"System.Net.WebClient.dll",
+ L"System.Net.WebHeaderCollection.dll",
+ L"System.Net.WebProxy.dll",
+ L"System.Net.WebSockets.Client.dll",
+ L"System.Net.WebSockets.dll",
+ L"System.Numerics.dll",
+ L"System.Numerics.Vectors.dll",
+ L"System.ObjectModel.dll",
+ L"System.Private.CoreLib.dll",
+ L"System.Private.DataContractSerialization.dll",
+ L"System.Private.Uri.dll",
+ L"System.Private.Xml.dll",
+ L"System.Private.Xml.Linq.dll",
+ L"System.Reflection.DispatchProxy.dll",
+ L"System.Reflection.dll",
+ L"System.Reflection.Emit.dll",
+ L"System.Reflection.Emit.ILGeneration.dll",
+ L"System.Reflection.Emit.Lightweight.dll",
+ L"System.Reflection.Extensions.dll",
+ L"System.Reflection.Metadata.dll",
+ L"System.Reflection.Primitives.dll",
+ L"System.Reflection.TypeExtensions.dll",
+ L"System.Resources.Reader.dll",
+ L"System.Resources.ResourceManager.dll",
+ L"System.Resources.Writer.dll",
+ L"System.Runtime.CompilerServices.Unsafe.dll",
+ L"System.Runtime.CompilerServices.VisualC.dll",
+ L"System.Runtime.dll",
+ L"System.Runtime.Extensions.dll",
+ L"System.Runtime.Handles.dll",
+ L"System.Runtime.InteropServices.dll",
+ L"System.Runtime.InteropServices.JavaScript.dll",
+ L"System.Runtime.InteropServices.RuntimeInformation.dll",
+ L"System.Runtime.Intrinsics.dll",
+ L"System.Runtime.Loader.dll",
+ L"System.Runtime.Numerics.dll",
+ L"System.Runtime.Serialization.dll",
+ L"System.Runtime.Serialization.Formatters.dll",
+ L"System.Runtime.Serialization.Json.dll",
+ L"System.Runtime.Serialization.Primitives.dll",
+ L"System.Runtime.Serialization.Xml.dll",
+ L"System.Security.AccessControl.dll",
+ L"System.Security.Claims.dll",
+ L"System.Security.Cryptography.dll",
+ L"System.Security.Cryptography.Algorithms.dll",
+ L"System.Security.Cryptography.Cng.dll",
+ L"System.Security.Cryptography.Csp.dll",
+ L"System.Security.Cryptography.Encoding.dll",
+ L"System.Security.Cryptography.OpenSsl.dll",
+ L"System.Security.Cryptography.Primitives.dll",
+ L"System.Security.Cryptography.X509Certificates.dll",
+ L"System.Security.dll",
+ L"System.Security.Principal.dll",
+ L"System.Security.Principal.Windows.dll",
+ L"System.Security.SecureString.dll",
+ L"System.ServiceModel.Web.dll",
+ L"System.ServiceProcess.dll",
+ L"System.Text.Encoding.CodePages.dll",
+ L"System.Text.Encoding.dll",
+ L"System.Text.Encoding.Extensions.dll",
+ L"System.Text.Encodings.Web.dll",
+ L"System.Text.Json.dll",
+ L"System.Text.RegularExpressions.dll",
+ L"System.Threading.Channels.dll",
+ L"System.Threading.dll",
+ L"System.Threading.Overlapped.dll",
+ L"System.Threading.Tasks.Dataflow.dll",
+ L"System.Threading.Tasks.dll",
+ L"System.Threading.Tasks.Extensions.dll",
+ L"System.Threading.Tasks.Parallel.dll",
+ L"System.Threading.Thread.dll",
+ L"System.Threading.ThreadPool.dll",
+ L"System.Threading.Timer.dll",
+ L"System.Transactions.dll",
+ L"System.Transactions.Local.dll",
+ L"System.ValueTuple.dll",
+ L"System.Web.dll",
+ L"System.Web.HttpUtility.dll",
+ L"System.Windows.dll",
+ L"System.Xml.dll",
+ L"System.Xml.Linq.dll",
+ L"System.Xml.ReaderWriter.dll",
+ L"System.Xml.Serialization.dll",
+ L"System.Xml.XDocument.dll",
+ L"System.Xml.XmlDocument.dll",
+ L"System.Xml.XmlSerializer.dll",
+ L"System.Xml.XPath.dll",
+ L"System.Xml.XPath.XDocument.dll" };
+
+inline const std::vector dotnetRuntimeWPFFiles = {
+ L"Accessibility.dll",
+ L"DirectWriteForwarder.dll",
+ L"Microsoft.VisualBasic.Forms.dll",
+ L"Microsoft.Win32.Registry.AccessControl.dll",
+ L"Microsoft.Win32.SystemEvents.dll",
+ L"PenImc_cor3.dll",
+ L"PresentationCore.dll",
+ L"PresentationFramework-SystemCore.dll",
+ L"PresentationFramework-SystemData.dll",
+ L"PresentationFramework-SystemDrawing.dll",
+ L"PresentationFramework-SystemXml.dll",
+ L"PresentationFramework-SystemXmlLinq.dll",
+ L"PresentationFramework.Aero.dll",
+ L"PresentationFramework.Aero2.dll",
+ L"PresentationFramework.AeroLite.dll",
+ L"PresentationFramework.Classic.dll",
+ L"PresentationFramework.dll",
+ L"PresentationFramework.Luna.dll",
+ L"PresentationFramework.Royale.dll",
+ L"PresentationNative_cor3.dll",
+ L"PresentationUI.dll",
+ L"ReachFramework.dll",
+ L"System.CodeDom.dll",
+ L"System.Configuration.ConfigurationManager.dll",
+ L"System.Design.dll",
+ L"System.Diagnostics.EventLog.dll",
+ L"System.Diagnostics.EventLog.Messages.dll",
+ L"System.Diagnostics.PerformanceCounter.dll",
+ L"System.DirectoryServices.dll",
+ L"System.Drawing.Common.dll",
+ L"System.Drawing.Design.dll",
+ L"System.IO.Packaging.dll",
+ L"System.Security.Cryptography.Pkcs.dll",
+ L"System.Security.Cryptography.ProtectedData.dll",
+ L"System.Security.Cryptography.Xml.dll",
+ L"System.Security.Permissions.dll",
+ L"System.Threading.AccessControl.dll",
+ L"System.Windows.Controls.Ribbon.dll",
+ L"System.Windows.Extensions.dll",
+ L"System.Windows.Forms.Design.dll",
+ L"System.Windows.Forms.Design.Editors.dll",
+ L"System.Windows.Forms.dll",
+ L"System.Windows.Forms.Primitives.dll",
+ L"System.Windows.Input.Manipulations.dll",
+ L"System.Windows.Presentation.dll",
+ L"System.Xaml.dll",
+ L"UIAutomationClient.dll",
+ L"UIAutomationClientSideProviders.dll",
+ L"UIAutomationProvider.dll",
+ L"UIAutomationTypes.dll",
+ L"vcruntime140_cor3.dll",
+ L"WindowsFormsIntegration.dll",
+ L"wpfgfx_cor3.dll"
+};
+#endif
diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
index 19547da5cf..985d920f58 100644
--- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
+++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
@@ -109,6 +109,7 @@
+
diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters
index 7108f08409..71e80f20f2 100644
--- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters
+++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters
@@ -14,6 +14,7 @@
+
diff --git a/src/common/interop/interop.cpp b/src/common/interop/interop.cpp
index 83f48732f8..7d5bfe099f 100644
--- a/src/common/interop/interop.cpp
+++ b/src/common/interop/interop.cpp
@@ -207,5 +207,24 @@ public
return gcnew String(CommonSharedConstants::POWERACCENT_EXIT_EVENT);
}
+ static String ^ GcodePreviewResizeEvent() {
+ return gcnew String(CommonSharedConstants::GCODE_PREVIEW_RESIZE_EVENT);
+ }
+
+ static String ^ DevFilesPreviewResizeEvent() {
+ return gcnew String(CommonSharedConstants::DEV_FILES_PREVIEW_RESIZE_EVENT);
+ }
+
+ static String ^ MarkdownPreviewResizeEvent() {
+ return gcnew String(CommonSharedConstants::MARKDOWN_PREVIEW_RESIZE_EVENT);
+ }
+
+ static String ^ PdfPreviewResizeEvent() {
+ return gcnew String(CommonSharedConstants::PDF_PREVIEW_RESIZE_EVENT);
+ }
+
+ static String ^ SvgPreviewResizeEvent() {
+ return gcnew String(CommonSharedConstants::SVG_PREVIEW_RESIZE_EVENT);
+ }
};
}
diff --git a/src/common/interop/shared_constants.h b/src/common/interop/shared_constants.h
index 7adf617047..a1116a6065 100644
--- a/src/common/interop/shared_constants.h
+++ b/src/common/interop/shared_constants.h
@@ -44,6 +44,21 @@ namespace CommonSharedConstants
// Path to the event used by PowerOCR
const wchar_t SHOW_POWEROCR_SHARED_EVENT[] = L"Local\\PowerOCREvent-dc864e06-e1af-4ecc-9078-f98bee745e3a";
+ // Path to the event used by GcodePreviewHandler
+ const wchar_t GCODE_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysGcodePreviewResizeEvent-6ff1f9bd-ccbd-4b24-a79f-40a34fb0317d";
+
+ // Path to the event used by DevFilesPreviewHandler
+ const wchar_t DEV_FILES_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysDevFilesPreviewResizeEvent-5707a22c-2cac-4ea2-82f0-27c03ef0b5f3";
+
+ // Path to the event used by MarkdownPreviewHandler
+ const wchar_t MARKDOWN_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysMarkdownPreviewResizeEvent-54c9ab69-11f3-49e9-a98f-53221cfef3ec";
+
+ // Path to the event used by MarkdownPreviewHandler
+ const wchar_t PDF_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysPdfPreviewResizeEvent-5a2f162a-f728-45fe-8bda-ef3d5e434ce7";
+
+ // Path to the event used by MarkdownPreviewHandler
+ const wchar_t SVG_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysSvgPreviewResizeEvent-0701a4fc-d5a1-4ee7-b885-f83982c62a0d";
+
// Max DWORD for key code to disable keys.
const DWORD VK_DISABLED = 0x100;
}
diff --git a/src/common/logger/logger.cpp b/src/common/logger/logger.cpp
index 7bf0e62a91..9587b97743 100644
--- a/src/common/logger/logger.cpp
+++ b/src/common/logger/logger.cpp
@@ -58,18 +58,24 @@ bool Logger::wasLogFailedShown()
void Logger::init(std::string loggerName, std::wstring logFilePath, std::wstring_view logSettingsPath)
{
auto logLevel = getLogLevel(logSettingsPath);
+ bool newLoggerCreated = false;
try
{
- auto sink = make_shared(logFilePath, 0, 0, false, LogSettings::retention);
- if (IsDebuggerPresent())
+ logger = spdlog::get(loggerName);
+ if (logger == nullptr)
{
- auto msvc_sink = make_shared();
- msvc_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%f] [%n] [t-%t] [%l] %v");
- logger = make_shared(loggerName, sinks_init_list{ sink, msvc_sink });
- }
- else
- {
- logger = make_shared(loggerName, sink);
+ auto sink = make_shared(logFilePath, 0, 0, false, LogSettings::retention);
+ if (IsDebuggerPresent())
+ {
+ auto msvc_sink = make_shared();
+ msvc_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%f] [%n] [t-%t] [%l] %v");
+ logger = make_shared(loggerName, sinks_init_list{ sink, msvc_sink });
+ }
+ else
+ {
+ logger = make_shared(loggerName, sink);
+ }
+ newLoggerCreated = true;
}
}
catch (...)
@@ -89,10 +95,14 @@ void Logger::init(std::string loggerName, std::wstring logFilePath, std::wstring
return;
}
- logger->set_level(logLevel);
- logger->set_pattern("[%Y-%m-%d %H:%M:%S.%f] [p-%P] [t-%t] [%l] %v");
- logger->flush_on(logLevel); // Auto flush on every log message.
- spdlog::register_logger(logger);
+ if (newLoggerCreated)
+ {
+ logger->set_level(logLevel);
+ logger->set_pattern("[%Y-%m-%d %H:%M:%S.%f] [p-%P] [t-%t] [%l] %v");
+ logger->flush_on(logLevel); // Auto flush on every log message.
+ spdlog::register_logger(logger);
+ }
+
logger->info("{} logger is initialized", loggerName);
}
diff --git a/src/common/logger/logger_settings.h b/src/common/logger/logger_settings.h
index e342ba410b..b424212314 100644
--- a/src/common/logger/logger_settings.h
+++ b/src/common/logger/logger_settings.h
@@ -15,6 +15,24 @@ struct LogSettings
inline const static std::wstring updateLogPath = L"UpdateLogs\\update-log.txt";
inline const static std::string fileExplorerLoggerName = "FileExplorer";
inline const static std::wstring fileExplorerLogPath = L"Logs\\file-explorer-log.txt";
+ inline const static std::string gcodePrevLoggerName = "GcodePrevHandler";
+ inline const static std::wstring gcodePrevLogPath = L"logs\\FileExplorer_localLow\\GcodePreviewHandler\\gcode-prev-handler-log.txt";
+ inline const static std::string gcodeThumbLoggerName = "GcodeThumbnailProvider";
+ inline const static std::wstring gcodeThumbLogPath = L"logs\\FileExplorer_localLow\\GcodeThumbnailProvider\\gcode-thumbnail-provider-log.txt";
+ inline const static std::string mdPrevLoggerName = "MDPrevHandler";
+ inline const static std::wstring mdPrevLogPath = L"logs\\FileExplorer_localLow\\MDPrevHandler\\md-prev-handler-log.txt";
+ inline const static std::string monacoPrevLoggerName = "MonacoPrevHandler";
+ inline const static std::wstring monacoPrevLogPath = L"logs\\FileExplorer_localLow\\MonacoPrevHandler\\monaco-prev-handler-log.txt";
+ inline const static std::string pdfPrevLoggerName = "PdfPrevHandler";
+ inline const static std::wstring pdfPrevLogPath = L"logs\\FileExplorer_localLow\\PdfPrevHandler\\pdf-prev-handler-log.txt";
+ inline const static std::string pdfThumbLoggerName = "PdfThumbnailProvider";
+ inline const static std::wstring pdfThumbLogPath = L"logs\\FileExplorer_localLow\\PdfThumbnailProvider\\pdf-thumbnail-provider-log.txt";
+ inline const static std::string stlThumbLoggerName = "StlThumbnailProvider";
+ inline const static std::wstring stlThumbLogPath = L"logs\\FileExplorer_localLow\\StlThumbnailProvider\\stl-thumbnail-provider-log.txt";
+ inline const static std::string svgPrevLoggerName = "SvgPrevHandler";
+ inline const static std::wstring svgPrevLogPath = L"logs\\FileExplorer_localLow\\SvgPrevHandler\\svg-prev-handler-log.txt";
+ inline const static std::string svgThumbLoggerName = "SvgThumbnailProvider";
+ inline const static std::wstring svgThumbLogPath = L"logs\\FileExplorer_localLow\\SvgThumbnailProvider\\svg-thumbnail-provider-log.txt";
inline const static std::string launcherLoggerName = "launcher";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.txt";
diff --git a/src/common/utils/modulesRegistry.h b/src/common/utils/modulesRegistry.h
index 7f8631ea09..62d0d35cf2 100644
--- a/src/common/utils/modulesRegistry.h
+++ b/src/common/utils/modulesRegistry.h
@@ -28,13 +28,12 @@ inline registry::ChangeSet getSvgPreviewHandlerChangeSet(const std::wstring inst
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
- L"{ddee2b8a-6807-48a6-bb20-2338174ff779}",
+ L"{FCDD4EED-41AA-492F-8A84-31A1546226E0}",
get_std_product_version(),
(fs::path{ installationDir } /
- LR"d(modules\FileExplorerPreview\PowerToys.SvgPreviewHandler.comhost.dll)d")
+ LR"d(modules\FileExplorerPreview\PowerToys.SvgPreviewHandlerCpp.dll)d")
.wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler",
+ L"SvgPreviewHandler",
L"Svg Preview Handler",
NonLocalizable::ExtSVG);
}
@@ -44,11 +43,10 @@ inline registry::ChangeSet getMdPreviewHandlerChangeSet(const std::wstring insta
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
- L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}",
+ L"{60789D87-9C3C-44AF-B18C-3DE2C2820ED3}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.MarkdownPreviewHandler.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.MarkdownPreviewHandlerCpp.dll)d").wstring(),
+ L"MarkdownPreviewHandler",
L"Markdown Preview Handler",
NonLocalizable::ExtMarkdown);
}
@@ -107,11 +105,10 @@ inline registry::ChangeSet getMonacoPreviewHandlerChangeSet(const std::wstring i
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
- L"{afbd5a44-2520-4ae0-9224-6cfce8fe4400}",
+ L"{D8034CFA-F34B-41FE-AD45-62FCBB52A6DA}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.MonacoPreviewHandler.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.PreviewHandler.Monaco.MonacoPreviewHandler",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.MonacoPreviewHandlerCpp.dll)d").wstring(),
+ L"MonacoPreviewHandler",
L"Monaco Preview Handler",
extensions);
}
@@ -121,11 +118,10 @@ inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring inst
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
- L"{07665729-6243-4746-95b7-79579308d1b2}",
+ L"{A5A41CC7-02CB-41D4-8C9B-9087040D6098}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.PdfPreviewHandler.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.PdfPreviewHandlerCpp.dll)d").wstring(),
+ L"PdfPreviewHandler",
L"Pdf Preview Handler",
NonLocalizable::ExtPDF);
}
@@ -135,11 +131,10 @@ inline registry::ChangeSet getGcodePreviewHandlerChangeSet(const std::wstring in
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
perUser,
- L"{ec52dea8-7c9f-4130-a77b-1737d0418507}",
+ L"{A0257634-8812-4CE8-AF11-FA69ACAEAFAE}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.PreviewHandler.Gcode.GcodePreviewHandler",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.GcodePreviewHandlerCpp.dll)d").wstring(),
+ L"GcodePreviewHandler",
L"G-code Preview Handler",
NonLocalizable::ExtGCode);
}
@@ -149,11 +144,10 @@ inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring in
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
perUser,
- L"{36B27788-A8BB-4698-A756-DF9F11F64F84}",
+ L"{10144713-1526-46C9-88DA-1FB52807A9FF}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.SvgThumbnailProvider.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.SvgThumbnailProviderCpp.dll)d").wstring(),
+ L"SvgThumbnailProvider",
L"Svg Thumbnail Provider",
NonLocalizable::ExtSVG,
L"Picture");
@@ -164,11 +158,10 @@ inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring in
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
perUser,
- L"{BCC13D15-9720-4CC4-8371-EA74A274741E}",
+ L"{D8BB9942-93BD-412D-87E4-33FAB214DC1A}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.PdfThumbnailProvider.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.PdfThumbnailProviderCpp.dll)d").wstring(),
+ L"PdfThumbnailProvider",
L"Pdf Thumbnail Provider",
NonLocalizable::ExtPDF);
}
@@ -178,11 +171,10 @@ inline registry::ChangeSet getGcodeThumbnailHandlerChangeSet(const std::wstring
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
perUser,
- L"{BFEE99B4-B74D-4348-BCA5-E757029647FF}",
+ L"{F2847CBE-CD03-4C83-A359-1A8052C1B9D5}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.ThumbnailHandler.Gcode.GcodeThumbnailProvider",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.GcodeThumbnailProviderCpp.dll)d").wstring(),
+ L"GcodeThumbnailProvider",
L"G-code Thumbnail Provider",
NonLocalizable::ExtGCode);
}
@@ -192,11 +184,10 @@ inline registry::ChangeSet getStlThumbnailHandlerChangeSet(const std::wstring in
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
perUser,
- L"{8BC8AFC2-4E7C-4695-818E-8C1FFDCEA2AF}",
+ L"{77257004-6F25-4521-B602-50ECC6EC62A6}",
get_std_product_version(),
- (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.StlThumbnailProvider.comhost.dll)d").wstring(),
- registry::DOTNET_COMPONENT_CATEGORY_CLSID,
- L"Microsoft.PowerToys.ThumbnailHandler.Stl.StlThumbnailProvider",
+ (fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.StlThumbnailProviderCpp.dll)d").wstring(),
+ L"StlThumbnailProvider",
L"Stl Thumbnail Provider",
NonLocalizable::ExtSTL);
}
diff --git a/src/common/utils/registry.h b/src/common/utils/registry.h
index 689b436a7b..d254457999 100644
--- a/src/common/utils/registry.h
+++ b/src/common/utils/registry.h
@@ -315,11 +315,10 @@ namespace registry
std::wstring handlerClsid,
std::wstring powertoysVersion,
std::wstring fullPathToHandler,
- std::wstring handlerCategory,
std::wstring className,
std::wstring displayName,
std::vector fileTypes,
- std::wstring fileKindType = L"" )
+ std::wstring fileKindType = L"")
{
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
@@ -331,9 +330,6 @@ namespace registry
inprocServerPath += L'\\';
inprocServerPath += L"InprocServer32";
- std::wstring implementedCategoriesPath = clsidPath + LR"d(\Implemented Categories\)d";
- implementedCategoriesPath += handlerCategory;
-
std::wstring assemblyKeyValue;
if (const auto lastDotPos = className.rfind(L'.'); lastDotPos != std::wstring::npos)
{
@@ -356,13 +352,10 @@ namespace registry
// TODO: verify that we actually need all of those
vec_t changes = { { scope, clsidPath, L"DisplayName", displayName },
{ scope, clsidPath, std::nullopt, className },
- { scope, implementedCategoriesPath, std::nullopt, L"" },
{ scope, inprocServerPath, std::nullopt, fullPathToHandler },
{ scope, inprocServerPath, L"Assembly", assemblyKeyValue },
{ scope, inprocServerPath, L"Class", className },
- { scope, inprocServerPath, L"ThreadingModel", L"Both" },
- { scope, versionPath, L"Assembly", assemblyKeyValue },
- { scope, versionPath, L"Class", className } };
+ { scope, inprocServerPath, L"ThreadingModel", L"Apartment" } };
for (const auto& fileType : fileTypes)
{
diff --git a/src/modules/FileLocksmith/FileLocksmithUI/FileLocksmithUI.csproj b/src/modules/FileLocksmith/FileLocksmithUI/FileLocksmithUI.csproj
index 1e5faa376b..b0f04a01a6 100644
--- a/src/modules/FileLocksmith/FileLocksmithUI/FileLocksmithUI.csproj
+++ b/src/modules/FileLocksmith/FileLocksmithUI/FileLocksmithUI.csproj
@@ -21,6 +21,15 @@
true
10.0.19041.0
Assets/Icon.ico
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
diff --git a/src/modules/FileLocksmith/FileLocksmithUI/Properties/PublishProfiles/InstallationPublishProfile.pubxml b/src/modules/FileLocksmith/FileLocksmithUI/Properties/PublishProfiles/InstallationPublishProfile.pubxml
index b4ac401e4e..a4a0a4c4f1 100644
--- a/src/modules/FileLocksmith/FileLocksmithUI/Properties/PublishProfiles/InstallationPublishProfile.pubxml
+++ b/src/modules/FileLocksmith/FileLocksmithUI/Properties/PublishProfiles/InstallationPublishProfile.pubxml
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net7.0-windows10.0.19041.0
$(PowerToysRoot)\$(Platform)\$(Configuration)\modules\FileLocksmith
win10-$(Platform)
- false
+ true
False
False
false
diff --git a/src/modules/Hosts/Hosts/Hosts.csproj b/src/modules/Hosts/Hosts/Hosts.csproj
index 4a065e0f28..81361152bc 100644
--- a/src/modules/Hosts/Hosts/Hosts.csproj
+++ b/src/modules/Hosts/Hosts/Hosts.csproj
@@ -20,6 +20,15 @@
PowerToys.Hosts
DISABLE_XAML_GENERATED_MAIN,TRACE
Assets/Hosts.ico
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
diff --git a/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj b/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj
index ff7c66c004..f92f7e5567 100644
--- a/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj
+++ b/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj
@@ -13,7 +13,6 @@
app.manifest
x86;x64;arm64
win10-x86;win10-x64;win10-arm64
- win10-$(Platform).pubxml
true
true
false
@@ -22,6 +21,14 @@
None
true
10.0.19041.0
+ true
+
+
+
+ win10-x64
+
+
+ win10-arm64
diff --git a/src/modules/PowerOCR/PowerOCR/PowerOCR.csproj b/src/modules/PowerOCR/PowerOCR/PowerOCR.csproj
index 57fe667ab3..bfb1a03791 100644
--- a/src/modules/PowerOCR/PowerOCR/PowerOCR.csproj
+++ b/src/modules/PowerOCR/PowerOCR/PowerOCR.csproj
@@ -10,6 +10,15 @@
enable
true
true
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
diff --git a/src/modules/awake/Awake/Awake.csproj b/src/modules/awake/Awake/Awake.csproj
index e05c2aeeb4..01da46c13a 100644
--- a/src/modules/awake/Awake/Awake.csproj
+++ b/src/modules/awake/Awake/Awake.csproj
@@ -17,6 +17,15 @@
10.0.19041.0
https://awake.den.dev
https://github.com/microsoft/powertoys
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
diff --git a/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj b/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj
index 734b1601bb..d75d01efee 100644
--- a/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj
+++ b/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj
@@ -9,7 +9,17 @@
true
true
ColorPicker.Program
+ true
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
{BA58206B-1493-4C75-BFEA-A85768A1E156}
WinExe
diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj b/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj
index ccb358c55a..fa00d92d70 100644
--- a/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj
+++ b/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj
@@ -11,9 +11,18 @@
false
false
true
- $(SolutionDir)$(Platform)\$(Configuration)\modules\FancyZones
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FancyZones
+ true
-
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
net7.0-windows10.0.19041.0
diff --git a/src/modules/imageresizer/ui/ImageResizerUI.csproj b/src/modules/imageresizer/ui/ImageResizerUI.csproj
index c8e456f417..b9fd21cc61 100644
--- a/src/modules/imageresizer/ui/ImageResizerUI.csproj
+++ b/src/modules/imageresizer/ui/ImageResizerUI.csproj
@@ -8,8 +8,17 @@
false
true
true
+ true
-
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
WinExe
diff --git a/src/modules/launcher/PowerLauncher/PowerLauncher.csproj b/src/modules/launcher/PowerLauncher/PowerLauncher.csproj
index 0bc9df1487..4c13b9eb4c 100644
--- a/src/modules/launcher/PowerLauncher/PowerLauncher.csproj
+++ b/src/modules/launcher/PowerLauncher/PowerLauncher.csproj
@@ -19,8 +19,16 @@
PowerToys.PowerLauncher
..\..\..\..\$(Platform)\$(Configuration)\modules\launcher\
true
+ true
+
+
+ win10-x64
+
+
+ win10-arm64
+
DEBUG;TRACE
diff --git a/src/modules/launcher/PowerLauncher/Properties/PublishProfiles/InstallationPublishProfile.pubxml b/src/modules/launcher/PowerLauncher/Properties/PublishProfiles/InstallationPublishProfile.pubxml
index acfc5cdd38..0c628c50af 100644
--- a/src/modules/launcher/PowerLauncher/Properties/PublishProfiles/InstallationPublishProfile.pubxml
+++ b/src/modules/launcher/PowerLauncher/Properties/PublishProfiles/InstallationPublishProfile.pubxml
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net7.0-windows10.0.19041.0
$(PowerToysRoot)\$(Platform)\$(Configuration)\modules\launcher
win-$(Platform)
- false
+ true
False
False
false
diff --git a/src/modules/poweraccent/PowerAccent.Core/PowerAccent.Core.csproj b/src/modules/poweraccent/PowerAccent.Core/PowerAccent.Core.csproj
index 338a68c9c3..a622b1d653 100644
--- a/src/modules/poweraccent/PowerAccent.Core/PowerAccent.Core.csproj
+++ b/src/modules/poweraccent/PowerAccent.Core/PowerAccent.Core.csproj
@@ -7,8 +7,18 @@
disable
True
true
- true
+ true
+ true
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
PowerToys.GPOWrapper;PowerToys.PowerAccentKeyboardService
$(OutDir)
diff --git a/src/modules/poweraccent/PowerAccent.UI/PowerAccent.UI.csproj b/src/modules/poweraccent/PowerAccent.UI/PowerAccent.UI.csproj
index 18db1b36e4..cc01326236 100644
--- a/src/modules/poweraccent/PowerAccent.UI/PowerAccent.UI.csproj
+++ b/src/modules/poweraccent/PowerAccent.UI/PowerAccent.UI.csproj
@@ -10,10 +10,19 @@
icon.ico
PowerToys.PowerAccent
True
- PowerAccent.UI.Program
- $(SolutionDir)$(Platform)\$(Configuration)\modules\PowerAccent
- false
- false
+ PowerAccent.UI.Program
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\PowerAccent
+ false
+ false
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
diff --git a/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.cs b/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.cs
deleted file mode 100644
index 168855a589..0000000000
--- a/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using Common;
-using Microsoft.PowerToys.Telemetry;
-
-namespace Microsoft.PowerToys.PreviewHandler.Gcode
-{
- ///
- /// Extends for Gcode Preview Handler.
- ///
- [Guid("ec52dea8-7c9f-4130-a77b-1737d0418507")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class GcodePreviewHandler : StreamBasedPreviewHandler, IDisposable
- {
- private GcodePreviewHandlerControl _gcodePreviewControl;
- private bool disposedValue;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public GcodePreviewHandler()
- {
- Initialize();
- }
-
- ///
- public override void DoPreview()
- {
- _gcodePreviewControl.DoPreview(Stream);
- }
-
- ///
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- PowerToysTelemetry.Log.WriteEvent(new Telemetry.Events.GcodeFileHandlerLoaded());
- _gcodePreviewControl = new GcodePreviewHandlerControl();
-
- return _gcodePreviewControl;
- }
-
- ///
- /// Disposes objects
- ///
- /// Is Disposing
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- _gcodePreviewControl.Dispose();
- }
-
- disposedValue = true;
- }
- }
-
- ///
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.csproj b/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.csproj
index c61b95e07d..954f426d4e 100644
--- a/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.csproj
+++ b/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.csproj
@@ -1,5 +1,6 @@
+ enable
true
PowerToys.GcodePreviewHandler
PowerToys GcodePreviewHandler
@@ -11,13 +12,21 @@
true
true
PowerToys.GcodePreviewHandler
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
{805306FF-A562-4415-8DEF-E493BDC45918}
Microsoft.PowerToys.PreviewHandler.Gcode
net7.0-windows10.0.19041.0
- true
@@ -40,6 +49,7 @@
$(NoWarn);1591
+ WinExe
@@ -48,7 +58,9 @@
+
+
diff --git a/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandlerControl.cs b/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandlerControl.cs
index 63e83480e9..ed1c2621b0 100644
--- a/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandlerControl.cs
+++ b/src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandlerControl.cs
@@ -46,52 +46,50 @@ namespace Microsoft.PowerToys.PreviewHandler.Gcode
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredGcodePreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility. Show an error message instead.
- InvokeOnControlThread(() =>
- {
- _infoBarAdded = true;
- AddTextBoxControl(Properties.Resource.GpoDisabledErrorText);
- Resize += FormResized;
- base.DoPreview(dataSource);
- });
+ _infoBarAdded = true;
+ AddTextBoxControl(Properties.Resource.GpoDisabledErrorText);
+ Resize += FormResized;
+ base.DoPreview(dataSource);
return;
}
- InvokeOnControlThread(() =>
+ try
{
- try
+ Bitmap thumbnail = null;
+
+ if (!(dataSource is string filePath))
{
- Bitmap thumbnail = null;
-
- using (var stream = new ReadonlyStream(dataSource as IStream))
- {
- using (var reader = new StreamReader(stream))
- {
- thumbnail = GetThumbnail(reader);
- }
- }
-
- _infoBarAdded = false;
-
- if (thumbnail == null)
- {
- _infoBarAdded = true;
- AddTextBoxControl(Properties.Resource.GcodeWithoutEmbeddedThumbnails);
- }
- else
- {
- AddPictureBoxControl(thumbnail);
- }
-
- Resize += FormResized;
- base.DoPreview(dataSource);
- PowerToysTelemetry.Log.WriteEvent(new GcodeFilePreviewed());
+ throw new ArgumentException($"{nameof(dataSource)} for {nameof(GcodePreviewHandlerControl)} must be a string but was a '{typeof(T)}'");
}
- catch (Exception ex)
+
+ FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+
+ using (var reader = new StreamReader(fs))
{
- PreviewError(ex, dataSource);
+ thumbnail = GetThumbnail(reader);
}
- });
+
+ _infoBarAdded = false;
+
+ if (thumbnail == null)
+ {
+ _infoBarAdded = true;
+ AddTextBoxControl(Properties.Resource.GcodeWithoutEmbeddedThumbnails);
+ }
+ else
+ {
+ AddPictureBoxControl(thumbnail);
+ }
+
+ Resize += FormResized;
+ base.DoPreview(fs);
+ PowerToysTelemetry.Log.WriteEvent(new GcodeFilePreviewed());
+ }
+ catch (Exception ex)
+ {
+ PreviewError(ex, dataSource);
+ }
}
///
diff --git a/src/modules/previewpane/GcodePreviewHandler/Program.cs b/src/modules/previewpane/GcodePreviewHandler/Program.cs
new file mode 100644
index 0000000000..ec9194fcd2
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandler/Program.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.PreviewHandler.Gcode
+{
+ using System.Globalization;
+ using System.Windows.Threading;
+ using Common.UI;
+ using interop;
+
+ internal static class Program
+ {
+ private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
+
+ private static GcodePreviewHandlerControl _previewHandlerControl;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 6)
+ {
+ string filePath = args[0];
+ int hwnd = Convert.ToInt32(args[1], 16);
+
+ Rectangle s = default(Rectangle);
+ int left = Convert.ToInt32(args[2], 10);
+ int right = Convert.ToInt32(args[3], 10);
+ int top = Convert.ToInt32(args[4], 10);
+ int bottom = Convert.ToInt32(args[5], 10);
+
+ _previewHandlerControl = new GcodePreviewHandlerControl();
+ _previewHandlerControl.SetWindow((IntPtr)hwnd, s);
+ _previewHandlerControl.DoPreview(filePath);
+
+ NativeEventWaiter.WaitForEventLoop(
+ Constants.GcodePreviewResizeEvent(),
+ () =>
+ {
+ Rectangle s = default(Rectangle);
+ _previewHandlerControl.SetRect(s);
+ },
+ Dispatcher.CurrentDispatcher,
+ _tokenSource.Token);
+ }
+ else
+ {
+ MessageBox.Show("Wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ Application.Run();
+ }
+ }
+}
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/ClassFactory.cpp b/src/modules/previewpane/GcodePreviewHandlerCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..28524635f4
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "GcodePreviewHandler.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ GcodePreviewHandler* pExt = new (std::nothrow) GcodePreviewHandler();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/ClassFactory.h b/src/modules/previewpane/GcodePreviewHandlerCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp
new file mode 100644
index 0000000000..8903d9908c
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp
@@ -0,0 +1,262 @@
+#include "pch.h"
+#include "GcodePreviewHandler.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+GcodePreviewHandler::GcodePreviewHandler() :
+ m_cRef(1), m_hwndParent(NULL), m_rcParent(), m_punkSite(NULL), m_process(NULL)
+{
+ m_resizeEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::GCODE_PREVIEW_RESIZE_EVENT);
+
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::gcodePrevLogPath);
+ Logger::init(LogSettings::gcodePrevLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+GcodePreviewHandler::~GcodePreviewHandler()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP GcodePreviewHandler::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(GcodePreviewHandler, IPreviewHandler),
+ QITABENT(GcodePreviewHandler, IInitializeWithFile),
+ QITABENT(GcodePreviewHandler, IPreviewHandlerVisuals),
+ QITABENT(GcodePreviewHandler, IOleWindow),
+ QITABENT(GcodePreviewHandler, IObjectWithSite),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+GcodePreviewHandler::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+GcodePreviewHandler::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithFile
+
+IFACEMETHODIMP GcodePreviewHandler::Initialize(LPCWSTR pszFilePath, DWORD grfMode)
+{
+ m_filePath = pszFilePath;
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandler
+
+IFACEMETHODIMP GcodePreviewHandler::SetWindow(HWND hwnd, const RECT* prc)
+{
+ if (hwnd && prc)
+ {
+ m_hwndParent = hwnd;
+ m_rcParent = *prc;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::SetFocus()
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::QueryFocus(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = ::GetFocus();
+ if (*phwnd)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ return hr;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::TranslateAccelerator(MSG* pmsg)
+{
+ HRESULT hr = S_FALSE;
+ IPreviewHandlerFrame* pFrame = NULL;
+ if (m_punkSite && SUCCEEDED(m_punkSite->QueryInterface(&pFrame)))
+ {
+ hr = pFrame->TranslateAccelerator(pmsg);
+
+ pFrame->Release();
+ }
+ return hr;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::SetRect(const RECT* prc)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (prc != NULL)
+ {
+ if (!m_resizeEvent)
+ {
+ Logger::error(L"Failed to create resize event for GcodePreviewHandler");
+ }
+ else
+ {
+ if (m_rcParent.right != prc->right || m_rcParent.left != prc->left || m_rcParent.top != prc->top || m_rcParent.bottom != prc->bottom)
+ {
+ if (!SetEvent(m_resizeEvent))
+ {
+ Logger::error(L"Failed to signal resize event for GcodePreviewHandler");
+ }
+ }
+ }
+ m_rcParent = *prc;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::DoPreview()
+{
+ try
+ {
+ Logger::info(L"Starting GcodePreviewHandler.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + m_filePath + L"\"" };
+ cmdLine += L" ";
+ std::wostringstream ss;
+ ss << std::hex << m_hwndParent;
+
+ cmdLine += ss.str();
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.left);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.right);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.top);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.bottom);
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.GcodePreviewHandler.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start GcodePreviewHandler.exe. Error: {}", errorMessage);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::Unload()
+{
+ Logger::info(L"Unload and terminate .exe");
+
+ m_hwndParent = NULL;
+ TerminateProcess(m_process, 0);
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandlerVisuals
+
+IFACEMETHODIMP GcodePreviewHandler::SetBackgroundColor(COLORREF color)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::SetFont(const LOGFONTW* plf)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::SetTextColor(COLORREF color)
+{
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IOleWindow
+
+IFACEMETHODIMP GcodePreviewHandler::GetWindow(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = m_hwndParent;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+#pragma endregion
+
+#pragma region IObjectWithSite
+
+IFACEMETHODIMP GcodePreviewHandler::SetSite(IUnknown* punkSite)
+{
+ if (m_punkSite)
+ {
+ m_punkSite->Release();
+ m_punkSite = NULL;
+ }
+ return punkSite ? punkSite->QueryInterface(&m_punkSite) : S_OK;
+}
+
+IFACEMETHODIMP GcodePreviewHandler::GetSite(REFIID riid, void** ppv)
+{
+ *ppv = NULL;
+ return m_punkSite ? m_punkSite->QueryInterface(riid, ppv) : E_FAIL;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.h b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.h
new file mode 100644
index 0000000000..715bb44922
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class GcodePreviewHandler :
+ public IInitializeWithFile,
+ public IPreviewHandler,
+ public IPreviewHandlerVisuals,
+ public IOleWindow,
+ public IObjectWithSite
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithFile
+ IFACEMETHODIMP Initialize(LPCWSTR pszFilePath, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP SetWindow(HWND hwnd, const RECT* prc);
+ IFACEMETHODIMP SetFocus();
+ IFACEMETHODIMP QueryFocus(HWND* phwnd);
+ IFACEMETHODIMP TranslateAccelerator(MSG* pmsg);
+ IFACEMETHODIMP SetRect(const RECT* prc);
+ IFACEMETHODIMP DoPreview();
+ IFACEMETHODIMP Unload();
+
+ // IPreviewHandlerVisuals
+ IFACEMETHODIMP SetBackgroundColor(COLORREF color);
+ IFACEMETHODIMP SetFont(const LOGFONTW* plf);
+ IFACEMETHODIMP SetTextColor(COLORREF color);
+
+ // IOleWindow
+ IFACEMETHODIMP GetWindow(HWND* phwnd);
+ IFACEMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
+
+ // IObjectWithSite
+ IFACEMETHODIMP SetSite(IUnknown* punkSite);
+ IFACEMETHODIMP GetSite(REFIID riid, void** ppv);
+
+ GcodePreviewHandler();
+protected:
+ ~GcodePreviewHandler();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ std::wstring m_filePath;
+
+ // Parent window that hosts the previewer window.
+ // Note: do NOT DestroyWindow this.
+ HWND m_hwndParent;
+ // Bounding rect of the parent window.
+ RECT m_rcParent;
+
+ // Site pointer from host, used to get IPreviewHandlerFrame.
+ IUnknown* m_punkSite;
+
+ HANDLE m_process;
+ HANDLE m_resizeEvent;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.rc b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj
new file mode 100644
index 0000000000..df0afaaaf9
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj
@@ -0,0 +1,119 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {5a5dd09d-723a-44d3-8f2b-293584c3d731}
+ GcodePreviewHandlerCpp
+ 10.0.19041.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj.filters b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj.filters
new file mode 100644
index 0000000000..5c278e0fbb
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj.filters
@@ -0,0 +1,56 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GlobalExportFunctions.def b/src/modules/previewpane/GcodePreviewHandlerCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/dllmain.cpp b/src/modules/previewpane/GcodePreviewHandlerCpp/dllmain.cpp
new file mode 100644
index 0000000000..259403f0c8
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {A0257634-8812-4CE8-AF11-FA69ACAEAFAE}
+static const GUID CLSID_GcodePreviewHandler = { 0xa0257634, 0x8812, 0x4ce8, { 0xaf, 0x11, 0xfa, 0x69, 0xac, 0xae, 0xaf, 0xae } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_GcodePreviewHandler, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/packages.config b/src/modules/previewpane/GcodePreviewHandlerCpp/packages.config
new file mode 100644
index 0000000000..48319b8c95
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/pch.cpp b/src/modules/previewpane/GcodePreviewHandlerCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/pch.h b/src/modules/previewpane/GcodePreviewHandlerCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/resource.h b/src/modules/previewpane/GcodePreviewHandlerCpp/resource.h
new file mode 100644
index 0000000000..b7fc0664a7
--- /dev/null
+++ b/src/modules/previewpane/GcodePreviewHandlerCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Gcode Preview Handler Module"
+#define INTERNAL_NAME "PowerToys.GcodePreviewHandlerCpp"
+#define ORIGINAL_FILENAME "PowerToys.GcodePreviewHandlerCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.cs b/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.cs
index 2a52a53dbe..09a3c98c27 100644
--- a/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.cs
+++ b/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.cs
@@ -1,32 +1,31 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections.Generic;
-using System.Drawing;
using System.Drawing.Drawing2D;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
using System.Text;
-using Common.ComInterlop;
-using Common.Utilities;
namespace Microsoft.PowerToys.ThumbnailHandler.Gcode
{
///
/// G-code Thumbnail Provider.
///
- [Guid("BFEE99B4-B74D-4348-BCA5-E757029647FF")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class GcodeThumbnailProvider : IInitializeWithStream, IThumbnailProvider
+ public class GcodeThumbnailProvider
{
+ public GcodeThumbnailProvider(string filePath)
+ {
+ FilePath = filePath;
+ Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+ }
+
+ ///
+ /// Gets the file path to the file creating thumbnail for.
+ ///
+ public string FilePath { get; private set; }
+
///
/// Gets the stream object to access file.
///
- public IStream Stream { get; private set; }
+ public Stream Stream { get; private set; }
///
/// The maximum dimension (width or height) thumbnail we will generate.
@@ -140,44 +139,36 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Gcode
return destImage;
}
- ///
- public void Initialize(IStream pstream, uint grfMode)
+ ///
+ /// Generate thumbnail bitmap for provided Gcode file/stream.
+ ///
+ /// Maximum thumbnail size, in pixels.
+ /// Generated bitmap
+ public Bitmap GetThumbnail(uint cx)
{
- // Ignore the grfMode always use read mode to access the file.
- this.Stream = pstream;
- }
-
- ///
- public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha)
- {
- phbmp = IntPtr.Zero;
- pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN;
-
if (cx == 0 || cx > MaxThumbnailSize)
{
- return;
+ return null;
}
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredGcodeThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility.
- return;
+ return null;
}
- using (var stream = new ReadonlyStream(this.Stream as IStream))
+ using (var reader = new StreamReader(this.Stream))
{
- using (var reader = new StreamReader(stream))
+ using (Bitmap thumbnail = GetThumbnail(reader, cx))
{
- using (Bitmap thumbnail = GetThumbnail(reader, cx))
+ if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
{
- if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
- {
- phbmp = thumbnail.GetHbitmap(Color.Transparent);
- pdwAlpha = WTS_ALPHATYPE.WTSAT_ARGB;
- }
+ return (Bitmap)thumbnail.Clone();
}
}
}
+
+ return null;
}
}
}
diff --git a/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.csproj b/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.csproj
index e3653ff114..11c1c3f3c9 100644
--- a/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.csproj
+++ b/src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.csproj
@@ -1,5 +1,6 @@
+ enable
true
{809AA252-E17A-4FA2-B0A1-0450976B763F}
Microsoft.PowerToys.ThumbnailHandler.Gcode
@@ -7,13 +8,21 @@
PowerToys.GcodeThumbnailProvider
PowerToys GcodePreviewHandler
net7.0-windows10.0.19041.0
- true
true
PowerToys GcodePreviewHandler
$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
false
false
true
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
@@ -27,6 +36,7 @@
$(NoWarn);1591
+ WinExe
diff --git a/src/modules/previewpane/GcodeThumbnailProvider/Program.cs b/src/modules/previewpane/GcodeThumbnailProvider/Program.cs
new file mode 100644
index 0000000000..84bfd5dcaf
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProvider/Program.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.ThumbnailHandler.Gcode
+{
+ using System.Globalization;
+
+ internal static class Program
+ {
+ private static GcodeThumbnailProvider _thumbnailProvider;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 2)
+ {
+ string filePath = args[0];
+ uint cx = Convert.ToUInt32(args[1], 10);
+
+ _thumbnailProvider = new GcodeThumbnailProvider(filePath);
+ Bitmap thumbnail = _thumbnailProvider.GetThumbnail(cx);
+ filePath = filePath.Replace(".gcode", ".bmp");
+ thumbnail.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
+ }
+ else
+ {
+ MessageBox.Show("Gcode thumbnail - wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/ClassFactory.cpp b/src/modules/previewpane/GcodeThumbnailProviderCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..33e8c037c6
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "GcodeThumbnailProvider.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ GcodeThumbnailProvider* pExt = new (std::nothrow) GcodeThumbnailProvider();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/ClassFactory.h b/src/modules/previewpane/GcodeThumbnailProviderCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProvider.cpp b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProvider.cpp
new file mode 100644
index 0000000000..7f16288d46
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProvider.cpp
@@ -0,0 +1,185 @@
+#include "pch.h"
+#include "GcodeThumbnailProvider.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+GcodeThumbnailProvider::GcodeThumbnailProvider() :
+ m_cRef(1), m_pStream(NULL), m_process(NULL)
+{
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::gcodeThumbLogPath);
+ Logger::init(LogSettings::gcodeThumbLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+GcodeThumbnailProvider::~GcodeThumbnailProvider()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP GcodeThumbnailProvider::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(GcodeThumbnailProvider, IThumbnailProvider),
+ QITABENT(GcodeThumbnailProvider, IInitializeWithStream),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+GcodeThumbnailProvider::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+GcodeThumbnailProvider::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithStream
+
+IFACEMETHODIMP GcodeThumbnailProvider::Initialize(IStream* pStream, DWORD grfMode)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (pStream)
+ {
+ // Initialize can be called more than once, so release existing valid
+ // m_pStream.
+ if (m_pStream)
+ {
+ m_pStream->Release();
+ m_pStream = NULL;
+ }
+
+ m_pStream = pStream;
+ m_pStream->AddRef();
+ hr = S_OK;
+ }
+ return hr;
+}
+
+#pragma endregion
+
+#pragma region IThumbnailProvider
+
+IFACEMETHODIMP GcodeThumbnailProvider::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
+{
+ // Read stream into the buffer
+ char buffer[4096];
+ ULONG cbRead;
+
+ Logger::trace(L"Begin");
+
+ GUID guid;
+ if (CoCreateGuid(&guid) == S_OK)
+ {
+ wil::unique_cotaskmem_string guidString;
+ if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
+ {
+ Logger::info(L"Read stream and save to tmp file.");
+
+ // {CLSID} -> CLSID
+ std::wstring guid = std::wstring(guidString.get()).substr(1, std::wstring(guidString.get()).size() - 2);
+ std::wstring filePath = PTSettingsHelper::get_local_low_folder_location() + L"\\GCodeThumbnail-Temp\\";
+ if (!std::filesystem::exists(filePath))
+ {
+ std::filesystem::create_directories(filePath);
+ }
+
+ std::wstring fileName = filePath + guid + L".gcode";
+
+ // Write data to tmp file
+ std::fstream file;
+ file.open(fileName, std::ios_base::out | std::ios_base::binary);
+
+ if (!file.is_open())
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ auto result = m_pStream->Read(buffer, 4096, &cbRead);
+
+ file.write(buffer, cbRead);
+ if (result == S_FALSE)
+ {
+ break;
+ }
+ }
+ file.close();
+
+
+ try
+ {
+ Logger::info(L"Start GcodeThumbnailProvider.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + fileName + L"\"" };
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(cx);
+
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.GcodeThumbnailProvider.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ WaitForSingleObject(m_process, INFINITE);
+ std::filesystem::remove(fileName);
+
+ std::wstring fileNameBmp = filePath + guid + L".bmp";
+ *phbmp = (HBITMAP)LoadImage(NULL, fileNameBmp.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
+ *pdwAlpha = WTS_ALPHATYPE::WTSAT_ARGB;
+
+ std::filesystem::remove(fileNameBmp);
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start GcodeThumbnailProvider.exe. Error: {}", errorMessage);
+ }
+ }
+ }
+
+
+ return S_OK;
+}
+
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProvider.h b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProvider.h
new file mode 100644
index 0000000000..8662de66e6
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProvider.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class GcodeThumbnailProvider :
+ public IInitializeWithStream,
+ public IThumbnailProvider
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithStream
+ IFACEMETHODIMP Initialize(IStream* pstream, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
+
+ GcodeThumbnailProvider();
+protected:
+ ~GcodeThumbnailProvider();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ IStream* m_pStream;
+
+ HANDLE m_process;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.rc b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj
new file mode 100644
index 0000000000..59a2db3c48
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj
@@ -0,0 +1,121 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {56cc2f10-6e41-453d-be16-c593a5e58482}
+ GcodeThumbnailProviderCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj.filters b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj.filters
new file mode 100644
index 0000000000..08004c2ea6
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj.filters
@@ -0,0 +1,59 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/GlobalExportFunctions.def b/src/modules/previewpane/GcodeThumbnailProviderCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/dllmain.cpp b/src/modules/previewpane/GcodeThumbnailProviderCpp/dllmain.cpp
new file mode 100644
index 0000000000..34fde4073e
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {F2847CBE-CD03-4C83-A359-1A8052C1B9D5}
+static const GUID CLSID_GcodeThumbnailProvider = { 0xf2847cbe, 0xcd03, 0x4c83, { 0xa3, 0x59, 0x1a, 0x80, 0x52, 0xc1, 0xb9, 0xd5 } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_GcodeThumbnailProvider, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/packages.config b/src/modules/previewpane/GcodeThumbnailProviderCpp/packages.config
new file mode 100644
index 0000000000..c92dd4bf0c
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/pch.cpp b/src/modules/previewpane/GcodeThumbnailProviderCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/pch.h b/src/modules/previewpane/GcodeThumbnailProviderCpp/pch.h
new file mode 100644
index 0000000000..8a0d004247
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/pch.h
@@ -0,0 +1,15 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/GcodeThumbnailProviderCpp/resource.h b/src/modules/previewpane/GcodeThumbnailProviderCpp/resource.h
new file mode 100644
index 0000000000..87f19fc75e
--- /dev/null
+++ b/src/modules/previewpane/GcodeThumbnailProviderCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Gcode Thumbnail Provider Module"
+#define INTERNAL_NAME "PowerToys.GcodeThumbnailProviderCpp"
+#define ORIGINAL_FILENAME "PowerToys.GcodeThumbnailProviderCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.cs b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.cs
deleted file mode 100644
index 83fa419c89..0000000000
--- a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using Common;
-using Microsoft.PowerToys.Telemetry;
-
-namespace Microsoft.PowerToys.PreviewHandler.Markdown
-{
- ///
- /// Implementation of preview handler for markdown files.
- ///
- [Guid("45769bcc-e8fd-42d0-947e-02beef77a1f5")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class MarkdownPreviewHandler : FileBasedPreviewHandler, IDisposable
- {
- private MarkdownPreviewHandlerControl _markdownPreviewHandlerControl;
- private bool disposedValue;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public MarkdownPreviewHandler()
- {
- Initialize();
- }
-
- ///
- public override void DoPreview()
- {
- _markdownPreviewHandlerControl.DoPreview(FilePath);
- }
-
- ///
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- PowerToysTelemetry.Log.WriteEvent(new Telemetry.Events.MarkdownFileHandlerLoaded());
- _markdownPreviewHandlerControl = new MarkdownPreviewHandlerControl();
-
- return _markdownPreviewHandlerControl;
- }
-
- ///
- /// Disposes objects
- ///
- /// Is Disposing
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- _markdownPreviewHandlerControl.Dispose();
- }
-
- disposedValue = true;
- }
- }
-
- ///
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj
index 59455ae34e..5c90e75c57 100644
--- a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj
+++ b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj
@@ -1,5 +1,6 @@
+ enable
true
PowerToys.MarkdownPreviewHandler
PowerToys MarkdownPreviewHandler
@@ -12,12 +13,20 @@
true
win10-x64;win10-arm64
net7.0-windows10.0.19041.0
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}
Microsoft.PowerToys.PreviewHandler.Markdown
- true
PowerToys.MarkdownPreviewHandler
@@ -46,6 +55,7 @@
$(NoWarn);1591
+ WinExe
@@ -58,6 +68,7 @@
+
diff --git a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs
index cc0a1b9420..0129fa5319 100644
--- a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs
+++ b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs
@@ -133,14 +133,11 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredMarkdownPreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility. Show an error message instead.
- InvokeOnControlThread(() =>
- {
- _infoBarDisplayed = true;
- _infoBar = GetTextBoxControl(Resources.GpoDisabledErrorText);
- Resize += FormResized;
- Controls.Add(_infoBar);
- base.DoPreview(dataSource);
- });
+ _infoBarDisplayed = true;
+ _infoBar = GetTextBoxControl(Resources.GpoDisabledErrorText);
+ Resize += FormResized;
+ Controls.Add(_infoBar);
+ base.DoPreview(dataSource);
return;
}
@@ -153,7 +150,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
{
if (!(dataSource is string filePath))
{
- throw new ArgumentException($"{nameof(dataSource)} for {nameof(MarkdownPreviewHandler)} must be a string but was a '{typeof(T)}'");
+ throw new ArgumentException($"{nameof(dataSource)} for {nameof(MarkdownPreviewHandlerControl)} must be a string but was a '{typeof(T)}'");
}
string fileText = File.ReadAllText(filePath);
@@ -174,80 +171,74 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
Dock = DockStyle.Fill,
};
- InvokeOnControlThread(() =>
- {
- var webView2Options = new CoreWebView2EnvironmentOptions("--block-new-web-contents");
- ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
+ var webView2Options = new CoreWebView2EnvironmentOptions("--block-new-web-contents");
+ ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
webView2EnvironmentAwaiter = CoreWebView2Environment
.CreateAsync(userDataFolder: _webView2UserDataFolder, options: webView2Options)
.ConfigureAwait(true).GetAwaiter();
- webView2EnvironmentAwaiter.OnCompleted(() =>
+ webView2EnvironmentAwaiter.OnCompleted(async () =>
+ {
+ try
{
- InvokeOnControlThread(async () =>
+ _webView2Environment = webView2EnvironmentAwaiter.GetResult();
+ await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
+ _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny);
+ _browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
+ _browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
+ _browser.CoreWebView2.Settings.AreDevToolsEnabled = false;
+ _browser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
+ _browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
+ _browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
+ _browser.CoreWebView2.Settings.IsScriptEnabled = false;
+ _browser.CoreWebView2.Settings.IsWebMessageEnabled = false;
+
+ // Don't load any resources.
+ _browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
+ _browser.CoreWebView2.WebResourceRequested += (object sender, CoreWebView2WebResourceRequestedEventArgs e) =>
{
- try
+ // Show local file we've saved with the markdown contents. Block all else.
+ if (new Uri(e.Request.Uri) != _localFileURI)
{
- _webView2Environment = webView2EnvironmentAwaiter.GetResult();
- await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
- _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny);
- _browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
- _browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
- _browser.CoreWebView2.Settings.AreDevToolsEnabled = false;
- _browser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
- _browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
- _browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
- _browser.CoreWebView2.Settings.IsScriptEnabled = false;
- _browser.CoreWebView2.Settings.IsWebMessageEnabled = false;
-
- // Don't load any resources.
- _browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
- _browser.CoreWebView2.WebResourceRequested += (object sender, CoreWebView2WebResourceRequestedEventArgs e) =>
- {
- // Show local file we've saved with the markdown contents. Block all else.
- if (new Uri(e.Request.Uri) != _localFileURI)
- {
- e.Response = _browser.CoreWebView2.Environment.CreateWebResourceResponse(null, 403, "Forbidden", null);
- }
- };
-
- // WebView2.NavigateToString() limitation
- // See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks
- // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes
- if (markdownHTML.Length > 1_500_000)
- {
- string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html";
- File.WriteAllText(filename, markdownHTML);
- _localFileURI = new Uri(filename);
- _browser.Source = _localFileURI;
- }
- else
- {
- _browser.NavigateToString(markdownHTML);
- }
-
- Controls.Add(_browser);
-
- _browser.NavigationStarting += async (object sender, CoreWebView2NavigationStartingEventArgs args) =>
- {
- if (args.Uri != null && args.Uri != _localFileURI?.ToString() && args.IsUserInitiated)
- {
- args.Cancel = true;
- await Launcher.LaunchUriAsync(new Uri(args.Uri));
- }
- };
-
- if (_infoBarDisplayed)
- {
- _infoBar = GetTextBoxControl(Resources.BlockedImageInfoText);
- Resize += FormResized;
- Controls.Add(_infoBar);
- }
+ e.Response = _browser.CoreWebView2.Environment.CreateWebResourceResponse(null, 403, "Forbidden", null);
}
- catch (NullReferenceException)
+ };
+
+ // WebView2.NavigateToString() limitation
+ // See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks
+ // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes
+ if (markdownHTML.Length > 1_500_000)
+ {
+ string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html";
+ File.WriteAllText(filename, markdownHTML);
+ _localFileURI = new Uri(filename);
+ _browser.Source = _localFileURI;
+ }
+ else
+ {
+ _browser.NavigateToString(markdownHTML);
+ }
+
+ Controls.Add(_browser);
+
+ _browser.NavigationStarting += async (object sender, CoreWebView2NavigationStartingEventArgs args) =>
+ {
+ if (args.Uri != null && args.Uri != _localFileURI?.ToString() && args.IsUserInitiated)
{
+ args.Cancel = true;
+ await Launcher.LaunchUriAsync(new Uri(args.Uri));
}
- });
- });
+ };
+
+ if (_infoBarDisplayed)
+ {
+ _infoBar = GetTextBoxControl(Resources.BlockedImageInfoText);
+ Resize += FormResized;
+ Controls.Add(_infoBar);
+ }
+ }
+ catch (NullReferenceException)
+ {
+ }
});
PowerToysTelemetry.Log.WriteEvent(new MarkdownFilePreviewed());
@@ -256,14 +247,11 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
{
PowerToysTelemetry.Log.WriteEvent(new MarkdownFilePreviewError { Message = ex.Message });
- InvokeOnControlThread(() =>
- {
- Controls.Clear();
- _infoBarDisplayed = true;
- _infoBar = GetTextBoxControl(Resources.MarkdownNotPreviewedError);
- Resize += FormResized;
- Controls.Add(_infoBar);
- });
+ Controls.Clear();
+ _infoBarDisplayed = true;
+ _infoBar = GetTextBoxControl(Resources.MarkdownNotPreviewedError);
+ Resize += FormResized;
+ Controls.Add(_infoBar);
}
finally
{
diff --git a/src/modules/previewpane/MarkdownPreviewHandler/Program.cs b/src/modules/previewpane/MarkdownPreviewHandler/Program.cs
new file mode 100644
index 0000000000..32bd6ac7fa
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandler/Program.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.PreviewHandler.Markdown
+{
+ using System.Globalization;
+ using System.Windows.Threading;
+ using Common.UI;
+ using interop;
+
+ internal static class Program
+ {
+ private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
+
+ private static MarkdownPreviewHandlerControl _previewHandlerControl;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 6)
+ {
+ string filePath = args[0];
+ int hwnd = Convert.ToInt32(args[1], 16);
+
+ Rectangle s = default(Rectangle);
+ int left = Convert.ToInt32(args[2], 10);
+ int right = Convert.ToInt32(args[3], 10);
+ int top = Convert.ToInt32(args[4], 10);
+ int bottom = Convert.ToInt32(args[5], 10);
+
+ _previewHandlerControl = new MarkdownPreviewHandlerControl();
+ _previewHandlerControl.SetWindow((IntPtr)hwnd, s);
+ _previewHandlerControl.DoPreview(filePath);
+
+ NativeEventWaiter.WaitForEventLoop(
+ Constants.MarkdownPreviewResizeEvent(),
+ () =>
+ {
+ Rectangle s = default(Rectangle);
+ _previewHandlerControl.SetRect(s);
+ },
+ Dispatcher.CurrentDispatcher,
+ _tokenSource.Token);
+ }
+ else
+ {
+ MessageBox.Show("Wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ Application.Run();
+ }
+ }
+}
diff --git a/src/modules/previewpane/MarkdownPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml b/src/modules/previewpane/MarkdownPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
index 74181a551d..d8a1a0ab2d 100644
--- a/src/modules/previewpane/MarkdownPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
+++ b/src/modules/previewpane/MarkdownPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net7.0-windows10.0.19041.0
$(PowerToysRoot)\$(Platform)\$(Configuration)\modules\FileExplorerPreview
win10-$(Platform)
- false
+ true
False
False
false
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/ClassFactory.cpp b/src/modules/previewpane/MarkdownPreviewHandlerCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..fcf04c6d1f
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "MarkdownPreviewHandler.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ MarkdownPreviewHandler* pExt = new (std::nothrow) MarkdownPreviewHandler();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/ClassFactory.h b/src/modules/previewpane/MarkdownPreviewHandlerCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/GlobalExportFunctions.def b/src/modules/previewpane/MarkdownPreviewHandlerCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp
new file mode 100644
index 0000000000..3a0210ff3a
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp
@@ -0,0 +1,263 @@
+#include "pch.h"
+#include "MarkdownPreviewHandler.h"
+#include "Generated Files/resource.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+MarkdownPreviewHandler::MarkdownPreviewHandler() :
+ m_cRef(1), m_hwndParent(NULL), m_rcParent(), m_punkSite(NULL), m_process(NULL)
+{
+ m_resizeEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::MARKDOWN_PREVIEW_RESIZE_EVENT);
+
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::mdPrevLogPath);
+ Logger::init(LogSettings::mdPrevLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+MarkdownPreviewHandler::~MarkdownPreviewHandler()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP MarkdownPreviewHandler::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(MarkdownPreviewHandler, IPreviewHandler),
+ QITABENT(MarkdownPreviewHandler, IInitializeWithFile),
+ QITABENT(MarkdownPreviewHandler, IPreviewHandlerVisuals),
+ QITABENT(MarkdownPreviewHandler, IOleWindow),
+ QITABENT(MarkdownPreviewHandler, IObjectWithSite),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+MarkdownPreviewHandler::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+MarkdownPreviewHandler::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithFile
+
+IFACEMETHODIMP MarkdownPreviewHandler::Initialize(LPCWSTR pszFilePath, DWORD grfMode)
+{
+ m_filePath = pszFilePath;
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandler
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetWindow(HWND hwnd, const RECT* prc)
+{
+ if (hwnd && prc)
+ {
+ m_hwndParent = hwnd;
+ m_rcParent = *prc;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetFocus()
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::QueryFocus(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = ::GetFocus();
+ if (*phwnd)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::TranslateAccelerator(MSG* pmsg)
+{
+ HRESULT hr = S_FALSE;
+ IPreviewHandlerFrame* pFrame = NULL;
+ if (m_punkSite && SUCCEEDED(m_punkSite->QueryInterface(&pFrame)))
+ {
+ hr = pFrame->TranslateAccelerator(pmsg);
+
+ pFrame->Release();
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetRect(const RECT* prc)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (prc != NULL)
+ {
+ if (!m_resizeEvent)
+ {
+ Logger::error(L"Failed to create resize event for MDPreviewHandler");
+ }
+ else
+ {
+ if (m_rcParent.right != prc->right || m_rcParent.left != prc->left || m_rcParent.top != prc->top || m_rcParent.bottom != prc->bottom)
+ {
+ if (!SetEvent(m_resizeEvent))
+ {
+ Logger::error(L"Failed to signal resize event for MDPreviewHandler");
+ }
+ }
+ }
+ m_rcParent = *prc;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::DoPreview()
+{
+ try
+ {
+ Logger::info(L"Starting MarkdownPreviewHandler.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + m_filePath + L"\"" };
+ cmdLine += L" ";
+ std::wostringstream ss;
+ ss << std::hex << m_hwndParent;
+
+ cmdLine += ss.str();
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.left);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.right);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.top);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.bottom);
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.MarkdownPreviewHandler.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start MarkdownPreviewHandler.exe. Error: {}", errorMessage);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::Unload()
+
+{
+ Logger::info(L"Unload and terminate .exe");
+
+ TerminateProcess(m_process, 0);
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandlerVisuals
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetBackgroundColor(COLORREF color)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetFont(const LOGFONTW* plf)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetTextColor(COLORREF color)
+{
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IOleWindow
+
+IFACEMETHODIMP MarkdownPreviewHandler::GetWindow(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = m_hwndParent;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+#pragma endregion
+
+#pragma region IObjectWithSite
+
+IFACEMETHODIMP MarkdownPreviewHandler::SetSite(IUnknown* punkSite)
+{
+ if (m_punkSite)
+ {
+ m_punkSite->Release();
+ m_punkSite = NULL;
+ }
+ return punkSite ? punkSite->QueryInterface(&m_punkSite) : S_OK;
+}
+
+IFACEMETHODIMP MarkdownPreviewHandler::GetSite(REFIID riid, void** ppv)
+{
+ *ppv = NULL;
+ return m_punkSite ? m_punkSite->QueryInterface(riid, ppv) : E_FAIL;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.h b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.h
new file mode 100644
index 0000000000..c12e6a1e9b
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class MarkdownPreviewHandler :
+ public IInitializeWithFile,
+ public IPreviewHandler,
+ public IPreviewHandlerVisuals,
+ public IOleWindow,
+ public IObjectWithSite
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithFile
+ IFACEMETHODIMP Initialize(LPCWSTR pszFilePath, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP SetWindow(HWND hwnd, const RECT* prc);
+ IFACEMETHODIMP SetFocus();
+ IFACEMETHODIMP QueryFocus(HWND* phwnd);
+ IFACEMETHODIMP TranslateAccelerator(MSG* pmsg);
+ IFACEMETHODIMP SetRect(const RECT* prc);
+ IFACEMETHODIMP DoPreview();
+ IFACEMETHODIMP Unload();
+
+ // IPreviewHandlerVisuals
+ IFACEMETHODIMP SetBackgroundColor(COLORREF color);
+ IFACEMETHODIMP SetFont(const LOGFONTW* plf);
+ IFACEMETHODIMP SetTextColor(COLORREF color);
+
+ // IOleWindow
+ IFACEMETHODIMP GetWindow(HWND* phwnd);
+ IFACEMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
+
+ // IObjectWithSite
+ IFACEMETHODIMP SetSite(IUnknown* punkSite);
+ IFACEMETHODIMP GetSite(REFIID riid, void** ppv);
+
+ MarkdownPreviewHandler();
+protected:
+ ~MarkdownPreviewHandler();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ std::wstring m_filePath;
+
+ // Parent window that hosts the previewer window.
+ // Note: do NOT DestroyWindow this.
+ HWND m_hwndParent;
+ // Bounding rect of the parent window.
+ RECT m_rcParent;
+
+ // Site pointer from host, used to get IPreviewHandlerFrame.
+ IUnknown* m_punkSite;
+
+ HANDLE m_process;
+ HANDLE m_resizeEvent;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj
new file mode 100644
index 0000000000..6866ce4f77
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+ 16.0
+ Win32Proj
+ {ed9a1ac6-aeb0-4569-a6e9-e1696182b545}
+ MarkdownPreviewHandlerCpp
+ 10.0.19041.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+ true
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj.filters b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj.filters
new file mode 100644
index 0000000000..331ad3cb42
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj.filters
@@ -0,0 +1,65 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/Resources.resx b/src/modules/previewpane/MarkdownPreviewHandlerCpp/Resources.resx
new file mode 100644
index 0000000000..7a845ea7a2
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/Resources.resx
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/dllmain.cpp b/src/modules/previewpane/MarkdownPreviewHandlerCpp/dllmain.cpp
new file mode 100644
index 0000000000..ef29b3ccc3
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/dllmain.cpp
@@ -0,0 +1,74 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {60789D87-9C3C-44AF-B18C-3DE2C2820ED3}
+static const GUID CLSID_MarkdownPreviewHandler = { 0x60789d87, 0x9c3c, 0x44af, { 0xb1, 0x8c, 0x3d, 0xe2, 0xc2, 0x82, 0xe, 0xd3 } };
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_MarkdownPreviewHandler, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/markdownpreviewhandler.base.rc b/src/modules/previewpane/MarkdownPreviewHandlerCpp/markdownpreviewhandler.base.rc
new file mode 100644
index 0000000000..ec61be69d7
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/markdownpreviewhandler.base.rc
@@ -0,0 +1,46 @@
+#include
+#include "resource.h"
+#include "../../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/packages.config b/src/modules/previewpane/MarkdownPreviewHandlerCpp/packages.config
new file mode 100644
index 0000000000..48319b8c95
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/pch.cpp b/src/modules/previewpane/MarkdownPreviewHandlerCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/pch.h b/src/modules/previewpane/MarkdownPreviewHandlerCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/resource.base.h b/src/modules/previewpane/MarkdownPreviewHandlerCpp/resource.base.h
new file mode 100644
index 0000000000..bf58c9ddb2
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/resource.base.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by powerpreview.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Markdown Preview Handler"
+#define INTERNAL_NAME "PowerToys.MarkdownPreviewHandler"
+#define ORIGINAL_FILENAME "PowerToys.MarkdownPreviewHandlerCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/resource.h b/src/modules/previewpane/MarkdownPreviewHandlerCpp/resource.h
new file mode 100644
index 0000000000..750d292358
--- /dev/null
+++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by markdownpreviewhandler.base.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs
deleted file mode 100644
index 0445c2af1a..0000000000
--- a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace Microsoft.PowerToys.PreviewHandler.Monaco
-{
- using System;
- using System.Runtime.InteropServices;
- using Common;
-
- ///
- /// Implementation of preview handler for files with source code.
- ///
- [Guid("afbd5a44-2520-4ae0-9224-6cfce8fe4400")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class MonacoPreviewHandler : FileBasedPreviewHandler, IDisposable
- {
- private MonacoPreviewHandlerControl _monacoPreviewHandlerControl;
- private bool _disposedValue;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public MonacoPreviewHandler()
- {
- this.Initialize();
- }
-
- ///
- [STAThread]
- public override void DoPreview()
- {
- _monacoPreviewHandlerControl.DoPreview(FilePath);
- }
-
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- _monacoPreviewHandlerControl = new MonacoPreviewHandlerControl();
-
- return _monacoPreviewHandlerControl;
- }
-
- ///
- /// Disposes objects
- ///
- /// Is Disposing
- [STAThread]
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- _monacoPreviewHandlerControl.Dispose();
- }
-
- _disposedValue = true;
- this.Unload();
- }
- }
-
- ///
- [STAThread]
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.csproj b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.csproj
index 4115158951..b54e276b29 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.csproj
+++ b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.csproj
@@ -1,5 +1,7 @@
+ enable
+ true
PowerToys.MonacoPreviewHandler
PowerToys MonacoPreviewHandler
PowerToys MonacoPreviewHandler
@@ -9,14 +11,22 @@
true
true
win10-x64;win10-arm64
+ true
-
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
Microsoft.PowerToys.PreviewHandler.Monaco
net7.0-windows10.0.19041.0
- true
PowerToys.MonacoPreviewHandler
@@ -35,6 +45,7 @@
$(NoWarn);1591
+ WinExe
diff --git a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs
index 81e962aeed..bd76aacc0e 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs
+++ b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs
@@ -107,13 +107,10 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredMonacoPreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility. Show an error message instead.
- InvokeOnControlThread(() =>
- {
- _infoBarAdded = true;
- AddTextBoxControl(Properties.Resources.GpoDisabledErrorText);
- Resize += FormResized;
- base.DoPreview(dataSource);
- });
+ _infoBarAdded = true;
+ AddTextBoxControl(Properties.Resources.GpoDisabledErrorText);
+ Resize += FormResized;
+ base.DoPreview(dataSource);
return;
}
@@ -132,7 +129,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
// Checks if dataSource is a string
if (!(dataSource is string filePath))
{
- throw new ArgumentException($"{nameof(dataSource)} for {nameof(MonacoPreviewHandler)} must be a string but was a '{typeof(T)}'");
+ throw new ArgumentException($"{nameof(dataSource)} for {nameof(MonacoPreviewHandlerControl)} must be a string but was a '{typeof(T)}'");
}
// Check if the file is too big.
@@ -145,103 +142,94 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
try
{
- InvokeOnControlThread(() =>
+ Logger.LogInfo("Create WebView2 environment");
+ ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
+ webView2EnvironmentAwaiter = CoreWebView2Environment
+ .CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
+ "\\AppData\\LocalLow\\Microsoft\\PowerToys\\MonacoPreview-Temp")
+ .ConfigureAwait(true).GetAwaiter();
+ webView2EnvironmentAwaiter.OnCompleted(async () =>
{
- Logger.LogInfo("Create WebView2 environment");
- ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
- webView2EnvironmentAwaiter = CoreWebView2Environment
- .CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
- "\\AppData\\LocalLow\\Microsoft\\PowerToys\\MonacoPreview-Temp")
- .ConfigureAwait(true).GetAwaiter();
- webView2EnvironmentAwaiter.OnCompleted(() =>
+ _loadingBar.Value = 60;
+ this.Update();
+ try
{
- _loadingBar.Value = 60;
- this.Update();
- InvokeOnControlThread(async () =>
+ if (CoreWebView2Environment.GetAvailableBrowserVersionString() == null)
{
- try
- {
- if (CoreWebView2Environment.GetAvailableBrowserVersionString() == null)
- {
- throw new WebView2RuntimeNotFoundException();
- }
+ throw new WebView2RuntimeNotFoundException();
+ }
- _webView2Environment = webView2EnvironmentAwaiter.GetResult();
+ _webView2Environment = webView2EnvironmentAwaiter.GetResult();
- _loadingBar.Value = 70;
- this.Update();
+ _loadingBar.Value = 70;
+ this.Update();
- // Initialize WebView
- try
- {
- await _webView.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
+ // Initialize WebView
+ try
+ {
+ await _webView.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
- // Wait until html is loaded
- initializeIndexFileAndSelectedFileTask.Wait();
+ // Wait until html is loaded
+ initializeIndexFileAndSelectedFileTask.Wait();
- _webView.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, Settings.AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
+ _webView.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, Settings.AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
- Logger.LogInfo("Navigates to string of HTML file");
+ Logger.LogInfo("Navigates to string of HTML file");
- _webView.NavigateToString(_html);
- _webView.NavigationCompleted += WebView2Init;
- _webView.Height = this.Height;
- _webView.Width = this.Width;
- Controls.Add(_webView);
- _webView.SendToBack();
- _loadingBar.Value = 100;
- this.Update();
- }
- catch (NullReferenceException e)
- {
- Logger.LogError("NullReferenceException catched. Skipping exception.", e);
- }
- }
- catch (WebView2RuntimeNotFoundException e)
- {
- Logger.LogWarning("WebView2 was not found:");
- Logger.LogWarning(e.Message);
- Controls.Remove(_loading);
- Controls.Remove(_loadingBar);
- Controls.Remove(_loadingBackground);
+ _webView.NavigateToString(_html);
+ _webView.NavigationCompleted += WebView2Init;
+ _webView.Height = this.Height;
+ _webView.Width = this.Width;
+ Controls.Add(_webView);
+ _webView.SendToBack();
+ _loadingBar.Value = 100;
+ this.Update();
+ }
+ catch (NullReferenceException e)
+ {
+ Logger.LogError("NullReferenceException catched. Skipping exception.", e);
+ }
+ }
+ catch (WebView2RuntimeNotFoundException e)
+ {
+ Logger.LogWarning("WebView2 was not found:");
+ Logger.LogWarning(e.Message);
+ Controls.Remove(_loading);
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
- // WebView2 not installed message
- Label errorMessage = new Label();
- errorMessage.Text = Resources.WebView2_Not_Installed_Message;
- errorMessage.Width = TextRenderer.MeasureText(Resources.WebView2_Not_Installed_Message, errorMessage.Font).Width + 10;
- errorMessage.Height = TextRenderer.MeasureText(Resources.WebView2_Not_Installed_Message, errorMessage.Font).Height;
- Controls.Add(errorMessage);
+ // WebView2 not installed message
+ Label errorMessage = new Label();
+ errorMessage.Text = Resources.WebView2_Not_Installed_Message;
+ errorMessage.Width = TextRenderer.MeasureText(Resources.WebView2_Not_Installed_Message, errorMessage.Font).Width + 10;
+ errorMessage.Height = TextRenderer.MeasureText(Resources.WebView2_Not_Installed_Message, errorMessage.Font).Height;
+ Controls.Add(errorMessage);
- // Download Link
- Label downloadLink = new LinkLabel();
- downloadLink.Text = Resources.Download_WebView2;
- downloadLink.Click += DownloadLink_Click;
- downloadLink.Top = TextRenderer.MeasureText(Resources.WebView2_Not_Installed_Message, errorMessage.Font).Height + 10;
- downloadLink.Width = TextRenderer.MeasureText(Resources.Download_WebView2, errorMessage.Font).Width + 10;
- downloadLink.Height = TextRenderer.MeasureText(Resources.Download_WebView2, errorMessage.Font).Height;
- Controls.Add(downloadLink);
- }
- });
- });
+ // Download Link
+ Label downloadLink = new LinkLabel();
+ downloadLink.Text = Resources.Download_WebView2;
+ downloadLink.Click += DownloadLink_Click;
+ downloadLink.Top = TextRenderer.MeasureText(Resources.WebView2_Not_Installed_Message, errorMessage.Font).Height + 10;
+ downloadLink.Width = TextRenderer.MeasureText(Resources.Download_WebView2, errorMessage.Font).Width + 10;
+ downloadLink.Height = TextRenderer.MeasureText(Resources.Download_WebView2, errorMessage.Font).Height;
+ Controls.Add(downloadLink);
+ }
});
}
catch (Exception e)
{
- InvokeOnControlThread(() =>
- {
- Controls.Remove(_loading);
- Controls.Remove(_loadingBar);
- Controls.Remove(_loadingBackground);
- Label text = new Label();
- text.Text = Resources.Exception_Occurred;
- text.Text += e.Message;
- text.Text += "\n" + e.Source;
- text.Text += "\n" + e.StackTrace;
- text.Width = 500;
- text.Height = 10000;
- Controls.Add(text);
- Logger.LogError(e.Message);
- });
+ Controls.Remove(_loading);
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
+ Label text = new Label();
+ text.Text = Resources.Exception_Occurred;
+ text.Text += e.Message;
+ text.Text += "\n" + e.Source;
+ text.Text += "\n" + e.StackTrace;
+ text.Width = 500;
+ text.Height = 10000;
+ Controls.Add(text);
+ Logger.LogError(e.Message);
}
this.Resize += FormResize;
@@ -249,18 +237,16 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
else
{
Logger.LogInfo("File is too big to display. Showing error message");
- InvokeOnControlThread(() =>
- {
- Controls.Remove(_loading);
- _loadingBar.Dispose();
- Controls.Remove(_loadingBar);
- Controls.Remove(_loadingBackground);
- Label errorMessage = new Label();
- errorMessage.Text = Resources.Max_File_Size_Error.Replace("%1", (_settings.MaxFileSize / 1000).ToString(CultureInfo.CurrentCulture), StringComparison.InvariantCulture);
- errorMessage.Width = 500;
- errorMessage.Height = 50;
- Controls.Add(errorMessage);
- });
+
+ Controls.Remove(_loading);
+ _loadingBar.Dispose();
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
+ Label errorMessage = new Label();
+ errorMessage.Text = Resources.Max_File_Size_Error.Replace("%1", (_settings.MaxFileSize / 1000).ToString(CultureInfo.CurrentCulture), StringComparison.InvariantCulture);
+ errorMessage.Width = 500;
+ errorMessage.Height = 50;
+ Controls.Add(errorMessage);
}
}
@@ -350,46 +336,41 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
private void SetBackground()
{
Logger.LogTrace();
- InvokeOnControlThread(() =>
- {
- this.BackColor = Settings.BackgroundColor;
- });
+ this.BackColor = Settings.BackgroundColor;
}
private void InitializeLoadingScreen()
{
Logger.LogTrace();
- InvokeOnControlThread(() =>
- {
- _loadingBackground = new Label();
- _loadingBackground.BackColor = Settings.BackgroundColor;
- _loadingBackground.Width = this.Width;
- _loadingBackground.Height = this.Height;
- Controls.Add(_loadingBackground);
- _loadingBackground.BringToFront();
+ _loadingBackground = new Label();
+ _loadingBackground.BackColor = Settings.BackgroundColor;
+ _loadingBackground.Width = this.Width;
+ _loadingBackground.Height = this.Height;
+ Controls.Add(_loadingBackground);
+ _loadingBackground.BringToFront();
- _loadingBar = new ProgressBar();
- _loadingBar.Width = this.Width - 10;
- _loadingBar.Location = new Point(5, this.Height / 2);
- _loadingBar.Maximum = 100;
- _loadingBar.Value = 10;
- Controls.Add(_loadingBar);
+ _loadingBar = new ProgressBar();
+ _loadingBar.Width = this.Width - 10;
+ _loadingBar.Location = new Point(5, this.Height / 2);
+ _loadingBar.Maximum = 100;
+ _loadingBar.Value = 10;
+ Controls.Add(_loadingBar);
- _loading = new Label();
- _loading.Text = Resources.Loading_Screen_Message;
- _loading.Width = this.Width;
- _loading.Height = 45;
- _loading.Location = new Point(0, _loadingBar.Location.Y - _loading.Height);
- _loading.TextAlign = ContentAlignment.TopCenter;
- _loading.Font = new Font("MS Sans Serif", 16, FontStyle.Bold);
- _loading.ForeColor = Settings.TextColor;
- Controls.Add(_loading);
+ _loading = new Label();
+ _loading.Text = Resources.Loading_Screen_Message;
+ _loading.Width = this.Width;
+ _loading.Height = 45;
+ _loading.Location = new Point(0, _loadingBar.Location.Y - _loading.Height);
+ _loading.TextAlign = ContentAlignment.TopCenter;
+ _loading.Font = new Font("MS Sans Serif", 16, FontStyle.Bold);
+ _loading.ForeColor = Settings.TextColor;
+ Controls.Add(_loading);
- _loading.BringToFront();
- _loadingBar.BringToFront();
+ _loading.BringToFront();
+ _loadingBar.BringToFront();
+
+ this.Update();
- this.Update();
- });
Logger.LogInfo("Loading screen initialized");
}
diff --git a/src/modules/previewpane/MonacoPreviewHandler/Program.cs b/src/modules/previewpane/MonacoPreviewHandler/Program.cs
new file mode 100644
index 0000000000..c5d00f2725
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandler/Program.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.PreviewHandler.Monaco
+{
+ using System.Globalization;
+ using System.Windows.Threading;
+ using Common.UI;
+ using interop;
+
+ internal static class Program
+ {
+ private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
+
+ private static MonacoPreviewHandlerControl _previewHandlerControl;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 6)
+ {
+ string filePath = args[0];
+ int hwnd = Convert.ToInt32(args[1], 16);
+
+ Rectangle s = default(Rectangle);
+ int left = Convert.ToInt32(args[2], 10);
+ int right = Convert.ToInt32(args[3], 10);
+ int top = Convert.ToInt32(args[4], 10);
+ int bottom = Convert.ToInt32(args[5], 10);
+
+ _previewHandlerControl = new MonacoPreviewHandlerControl();
+ _previewHandlerControl.SetWindow((IntPtr)hwnd, s);
+ _previewHandlerControl.DoPreview(filePath);
+
+ NativeEventWaiter.WaitForEventLoop(
+ Constants.DevFilesPreviewResizeEvent(),
+ () =>
+ {
+ Rectangle s = default(Rectangle);
+ _previewHandlerControl.SetRect(s);
+ },
+ Dispatcher.CurrentDispatcher,
+ _tokenSource.Token);
+ }
+ else
+ {
+ MessageBox.Show("Wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ Application.Run();
+ }
+ }
+}
diff --git a/src/modules/previewpane/MonacoPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml b/src/modules/previewpane/MonacoPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
index 74181a551d..d8a1a0ab2d 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
+++ b/src/modules/previewpane/MonacoPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net7.0-windows10.0.19041.0
$(PowerToysRoot)\$(Platform)\$(Configuration)\modules\FileExplorerPreview
win10-$(Platform)
- false
+ true
False
False
false
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/ClassFactory.cpp b/src/modules/previewpane/MonacoPreviewHandlerCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..6aafa46a6e
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "MonacoPreviewHandler.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ MonacoPreviewHandler* pExt = new (std::nothrow) MonacoPreviewHandler();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/ClassFactory.h b/src/modules/previewpane/MonacoPreviewHandlerCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/GlobalExportFunctions.def b/src/modules/previewpane/MonacoPreviewHandlerCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp
new file mode 100644
index 0000000000..740769c5dd
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp
@@ -0,0 +1,262 @@
+#include "pch.h"
+#include "MonacoPreviewHandler.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+MonacoPreviewHandler::MonacoPreviewHandler() :
+ m_cRef(1), m_hwndParent(NULL), m_rcParent(), m_punkSite(NULL), m_process(NULL)
+{
+ m_resizeEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::DEV_FILES_PREVIEW_RESIZE_EVENT);
+
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::monacoPrevLogPath);
+ Logger::init(LogSettings::monacoPrevLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+MonacoPreviewHandler::~MonacoPreviewHandler()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP MonacoPreviewHandler::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(MonacoPreviewHandler, IPreviewHandler),
+ QITABENT(MonacoPreviewHandler, IInitializeWithFile),
+ QITABENT(MonacoPreviewHandler, IPreviewHandlerVisuals),
+ QITABENT(MonacoPreviewHandler, IOleWindow),
+ QITABENT(MonacoPreviewHandler, IObjectWithSite),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+MonacoPreviewHandler::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+MonacoPreviewHandler::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithFile
+
+IFACEMETHODIMP MonacoPreviewHandler::Initialize(LPCWSTR pszFilePath, DWORD grfMode)
+{
+ m_filePath = pszFilePath;
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandler
+
+IFACEMETHODIMP MonacoPreviewHandler::SetWindow(HWND hwnd, const RECT* prc)
+{
+ if (hwnd && prc)
+ {
+ m_hwndParent = hwnd;
+ m_rcParent = *prc;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::SetFocus()
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::QueryFocus(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = ::GetFocus();
+ if (*phwnd)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::TranslateAccelerator(MSG* pmsg)
+{
+ HRESULT hr = S_FALSE;
+ IPreviewHandlerFrame* pFrame = NULL;
+ if (m_punkSite && SUCCEEDED(m_punkSite->QueryInterface(&pFrame)))
+ {
+ hr = pFrame->TranslateAccelerator(pmsg);
+
+ pFrame->Release();
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::SetRect(const RECT* prc)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (prc != NULL)
+ {
+ if (!m_resizeEvent)
+ {
+ Logger::error(L"Failed to create resize event for MonacoPreviewHandler");
+ }
+ else
+ {
+ if (m_rcParent.right != prc->right || m_rcParent.left != prc->left || m_rcParent.top != prc->top || m_rcParent.bottom != prc->bottom)
+ {
+ if (!SetEvent(m_resizeEvent))
+ {
+ Logger::error(L"Failed to signal resize event for MonacoPreviewHandler");
+ }
+ }
+ }
+ m_rcParent = *prc;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::DoPreview()
+{
+ try
+ {
+ Logger::info(L"Starting MonacoPreviewHandler.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + m_filePath + L"\"" };
+ cmdLine += L" ";
+ std::wostringstream ss;
+ ss << std::hex << m_hwndParent;
+
+ cmdLine += ss.str();
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.left);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.right);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.top);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.bottom);
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.MonacoPreviewHandler.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start MonacoPreviewHandler.exe. Error: {}", errorMessage);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::Unload()
+{
+ Logger::info(L"Unload and terminate .exe");
+
+ m_hwndParent = NULL;
+ TerminateProcess(m_process, 0);
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandlerVisuals
+
+IFACEMETHODIMP MonacoPreviewHandler::SetBackgroundColor(COLORREF color)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::SetFont(const LOGFONTW* plf)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::SetTextColor(COLORREF color)
+{
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IOleWindow
+
+IFACEMETHODIMP MonacoPreviewHandler::GetWindow(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = m_hwndParent;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+#pragma endregion
+
+#pragma region IObjectWithSite
+
+IFACEMETHODIMP MonacoPreviewHandler::SetSite(IUnknown* punkSite)
+{
+ if (m_punkSite)
+ {
+ m_punkSite->Release();
+ m_punkSite = NULL;
+ }
+ return punkSite ? punkSite->QueryInterface(&m_punkSite) : S_OK;
+}
+
+IFACEMETHODIMP MonacoPreviewHandler::GetSite(REFIID riid, void** ppv)
+{
+ *ppv = NULL;
+ return m_punkSite ? m_punkSite->QueryInterface(riid, ppv) : E_FAIL;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.h b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.h
new file mode 100644
index 0000000000..20b7ac1fba
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class MonacoPreviewHandler :
+ public IInitializeWithFile,
+ public IPreviewHandler,
+ public IPreviewHandlerVisuals,
+ public IOleWindow,
+ public IObjectWithSite
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithFile
+ IFACEMETHODIMP Initialize(LPCWSTR pszFilePath, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP SetWindow(HWND hwnd, const RECT* prc);
+ IFACEMETHODIMP SetFocus();
+ IFACEMETHODIMP QueryFocus(HWND* phwnd);
+ IFACEMETHODIMP TranslateAccelerator(MSG* pmsg);
+ IFACEMETHODIMP SetRect(const RECT* prc);
+ IFACEMETHODIMP DoPreview();
+ IFACEMETHODIMP Unload();
+
+ // IPreviewHandlerVisuals
+ IFACEMETHODIMP SetBackgroundColor(COLORREF color);
+ IFACEMETHODIMP SetFont(const LOGFONTW* plf);
+ IFACEMETHODIMP SetTextColor(COLORREF color);
+
+ // IOleWindow
+ IFACEMETHODIMP GetWindow(HWND* phwnd);
+ IFACEMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
+
+ // IObjectWithSite
+ IFACEMETHODIMP SetSite(IUnknown* punkSite);
+ IFACEMETHODIMP GetSite(REFIID riid, void** ppv);
+
+ MonacoPreviewHandler();
+protected:
+ ~MonacoPreviewHandler();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ std::wstring m_filePath;
+
+ // Parent window that hosts the previewer window.
+ // Note: do NOT DestroyWindow this.
+ HWND m_hwndParent;
+ // Bounding rect of the parent window.
+ RECT m_rcParent;
+
+ // Site pointer from host, used to get IPreviewHandlerFrame.
+ IUnknown* m_punkSite;
+
+ HANDLE m_process;
+
+ HANDLE m_resizeEvent;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.rc b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj
new file mode 100644
index 0000000000..41098d30e4
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj
@@ -0,0 +1,119 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {b3e869c4-8210-4ebd-a621-ff4c4afcbfa9}
+ MonacoPreviewHandlerCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj.filters b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj.filters
new file mode 100644
index 0000000000..911f755363
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj.filters
@@ -0,0 +1,56 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/dllmain.cpp b/src/modules/previewpane/MonacoPreviewHandlerCpp/dllmain.cpp
new file mode 100644
index 0000000000..11a7a5fb11
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {D8034CFA-F34B-41FE-AD45-62FCBB52A6DA}
+static const GUID CLSID_MonacoPreviewHandler = { 0xd8034cfa, 0xf34b, 0x41fe, { 0xad, 0x45, 0x62, 0xfc, 0xbb, 0x52, 0xa6, 0xda } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_MonacoPreviewHandler, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/packages.config b/src/modules/previewpane/MonacoPreviewHandlerCpp/packages.config
new file mode 100644
index 0000000000..48319b8c95
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/pch.cpp b/src/modules/previewpane/MonacoPreviewHandlerCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/pch.h b/src/modules/previewpane/MonacoPreviewHandlerCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/resource.h b/src/modules/previewpane/MonacoPreviewHandlerCpp/resource.h
new file mode 100644
index 0000000000..278191cab1
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Dev Files Preview Handler Module"
+#define INTERNAL_NAME "PowerToys.MonacoPreviewHandlerCpp"
+#define ORIGINAL_FILENAME "PowerToys.MonacoPreviewHandlerCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.cs b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.cs
deleted file mode 100644
index 8c91030447..0000000000
--- a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using Common;
-using Microsoft.PowerToys.Telemetry;
-
-namespace Microsoft.PowerToys.PreviewHandler.Pdf
-{
- ///
- /// Implementation of preview handler for pdf files.
- ///
- [Guid("07665729-6243-4746-95b7-79579308d1b2")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class PdfPreviewHandler : StreamBasedPreviewHandler, IDisposable
- {
- private PdfPreviewHandlerControl _pdfPreviewHandlerControl;
- private bool _disposedValue;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public PdfPreviewHandler()
- {
- Initialize();
- }
-
- ///
- public override void DoPreview()
- {
- _pdfPreviewHandlerControl.DoPreview(Stream);
- }
-
- ///
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- PowerToysTelemetry.Log.WriteEvent(new Telemetry.Events.PdfFileHandlerLoaded());
- _pdfPreviewHandlerControl = new PdfPreviewHandlerControl();
-
- return _pdfPreviewHandlerControl;
- }
-
- ///
- /// Disposes objects
- ///
- /// Is Disposing
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- _pdfPreviewHandlerControl.Dispose();
- }
-
- _disposedValue = true;
- }
- }
-
- ///
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj
index c24a2385cf..9624934c81 100644
--- a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj
+++ b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj
@@ -1,5 +1,7 @@
+ enable
+ true
true
PowerToys.PdfPreviewHandler
PowerToys PdfPreviewHandler
@@ -10,13 +12,21 @@
false
true
true
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
{69E1EE8D-143A-4060-9129-4658ACF14AAF}
Microsoft.PowerToys.PreviewHandler.Pdf
net7.0-windows10.0.19041.0
- true
PowerToys.PdfPreviewHandler
@@ -40,6 +50,7 @@
$(NoWarn);1591
+ WinExe
@@ -48,7 +59,9 @@
+
+
diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs
index e59a976793..ed1e94ee19 100644
--- a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs
+++ b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs
@@ -55,12 +55,9 @@ namespace Microsoft.PowerToys.PreviewHandler.Pdf
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredPdfPreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility. Show an error message instead.
- InvokeOnControlThread(() =>
- {
- _infoBar = GetTextBoxControl(Resources.GpoDisabledErrorText);
- Controls.Add(_infoBar);
- base.DoPreview(dataSource);
- });
+ _infoBar = GetTextBoxControl(Resources.GpoDisabledErrorText);
+ Controls.Add(_infoBar);
+ base.DoPreview(dataSource);
return;
}
@@ -69,7 +66,12 @@ namespace Microsoft.PowerToys.PreviewHandler.Pdf
try
{
- using (var dataStream = new ReadonlyStream(dataSource as IStream))
+ if (!(dataSource is string filePath))
+ {
+ throw new ArgumentException($"{nameof(dataSource)} for {nameof(PdfPreviewHandlerControl)} must be a string but was a '{typeof(T)}'");
+ }
+
+ using (var dataStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
var memStream = new MemoryStream();
dataStream.CopyTo(memStream);
@@ -82,77 +84,71 @@ namespace Microsoft.PowerToys.PreviewHandler.Pdf
if (pdf.PageCount > 0)
{
- InvokeOnControlThread(() =>
+ _flowLayoutPanel = new FlowLayoutPanel
{
- _flowLayoutPanel = new FlowLayoutPanel
- {
- AutoScroll = true,
- AutoSize = true,
- Dock = DockStyle.Fill,
- FlowDirection = FlowDirection.TopDown,
- WrapContents = false,
- };
- _flowLayoutPanel.Resize += FlowLayoutPanel_Resize;
+ AutoScroll = true,
+ AutoSize = true,
+ Dock = DockStyle.Fill,
+ FlowDirection = FlowDirection.TopDown,
+ WrapContents = false,
+ };
+ _flowLayoutPanel.Resize += FlowLayoutPanel_Resize;
- // Only show first 10 pages.
- for (uint i = 0; i < pdf.PageCount && i < 10; i++)
+ // Only show first 10 pages.
+ for (uint i = 0; i < pdf.PageCount && i < 10; i++)
+ {
+ using (var page = pdf.GetPage(i))
{
- using (var page = pdf.GetPage(i))
+ var image = PageToImage(page);
+
+ var picturePanel = new Panel()
{
- var image = PageToImage(page);
-
- var picturePanel = new Panel()
- {
- Name = "picturePanel",
- Margin = new Padding(6, 6, 6, 0),
- Size = CalculateSize(image),
- BorderStyle = BorderStyle.FixedSingle,
- };
-
- var picture = new PictureBox
- {
- Dock = DockStyle.Fill,
- Image = image,
- SizeMode = PictureBoxSizeMode.Zoom,
- };
-
- picturePanel.Controls.Add(picture);
- _flowLayoutPanel.Controls.Add(picturePanel);
- }
- }
-
- if (pdf.PageCount > 10)
- {
- var messageBox = new RichTextBox
- {
- Name = "messageBox",
- Text = Resources.PdfMorePagesMessage,
- BackColor = Color.LightYellow,
- Dock = DockStyle.Fill,
- Multiline = true,
- ReadOnly = true,
- ScrollBars = RichTextBoxScrollBars.None,
- BorderStyle = BorderStyle.None,
+ Name = "picturePanel",
+ Margin = new Padding(6, 6, 6, 0),
+ Size = CalculateSize(image),
+ BorderStyle = BorderStyle.FixedSingle,
};
- messageBox.ContentsResized += RTBContentsResized;
- _flowLayoutPanel.Controls.Add(messageBox);
+ var picture = new PictureBox
+ {
+ Dock = DockStyle.Fill,
+ Image = image,
+ SizeMode = PictureBoxSizeMode.Zoom,
+ };
+
+ picturePanel.Controls.Add(picture);
+ _flowLayoutPanel.Controls.Add(picturePanel);
}
+ }
- Controls.Add(_flowLayoutPanel);
- });
+ if (pdf.PageCount > 10)
+ {
+ var messageBox = new RichTextBox
+ {
+ Name = "messageBox",
+ Text = Resources.PdfMorePagesMessage,
+ BackColor = Color.LightYellow,
+ Dock = DockStyle.Fill,
+ Multiline = true,
+ ReadOnly = true,
+ ScrollBars = RichTextBoxScrollBars.None,
+ BorderStyle = BorderStyle.None,
+ };
+ messageBox.ContentsResized += RTBContentsResized;
+
+ _flowLayoutPanel.Controls.Add(messageBox);
+ }
+
+ Controls.Add(_flowLayoutPanel);
}
}
catch (Exception ex)
{
if (ex.Message.Contains("Unable to update the password. The value provided as the current password is incorrect.", StringComparison.Ordinal))
{
- InvokeOnControlThread(() =>
- {
- Controls.Clear();
- _infoBar = GetTextBoxControl(Resources.PdfPasswordProtectedError);
- Controls.Add(_infoBar);
- });
+ Controls.Clear();
+ _infoBar = GetTextBoxControl(Resources.PdfPasswordProtectedError);
+ Controls.Add(_infoBar);
}
else
{
@@ -171,12 +167,9 @@ namespace Microsoft.PowerToys.PreviewHandler.Pdf
{
PowerToysTelemetry.Log.WriteEvent(new PdfFilePreviewError { Message = ex.Message });
- InvokeOnControlThread(() =>
- {
- Controls.Clear();
- _infoBar = GetTextBoxControl(Resources.PdfNotPreviewedError);
- Controls.Add(_infoBar);
- });
+ Controls.Clear();
+ _infoBar = GetTextBoxControl(Resources.PdfNotPreviewedError);
+ Controls.Add(_infoBar);
}
finally
{
diff --git a/src/modules/previewpane/PdfPreviewHandler/Program.cs b/src/modules/previewpane/PdfPreviewHandler/Program.cs
new file mode 100644
index 0000000000..8dadc8205e
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/Program.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf
+{
+ using System.Globalization;
+ using System.Windows.Threading;
+ using Common.UI;
+ using interop;
+
+ internal static class Program
+ {
+ private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
+
+ private static PdfPreviewHandlerControl _previewHandlerControl;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 6)
+ {
+ string filePath = args[0];
+ int hwnd = Convert.ToInt32(args[1], 16);
+
+ Rectangle s = default(Rectangle);
+ int left = Convert.ToInt32(args[2], 10);
+ int right = Convert.ToInt32(args[3], 10);
+ int top = Convert.ToInt32(args[4], 10);
+ int bottom = Convert.ToInt32(args[5], 10);
+
+ _previewHandlerControl = new PdfPreviewHandlerControl();
+ _previewHandlerControl.SetWindow((IntPtr)hwnd, s);
+ _previewHandlerControl.DoPreview(filePath);
+
+ NativeEventWaiter.WaitForEventLoop(
+ Constants.PdfPreviewResizeEvent(),
+ () =>
+ {
+ Rectangle s = default(Rectangle);
+ _previewHandlerControl.SetRect(s);
+ },
+ Dispatcher.CurrentDispatcher,
+ _tokenSource.Token);
+ }
+ else
+ {
+ MessageBox.Show("Wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ Application.Run();
+ }
+ }
+}
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/ClassFactory.cpp b/src/modules/previewpane/PdfPreviewHandlerCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..21291c90a1
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "PdfPreviewHandler.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ PdfPreviewHandler* pExt = new (std::nothrow) PdfPreviewHandler();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/ClassFactory.h b/src/modules/previewpane/PdfPreviewHandlerCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/GlobalExportFunctions.def b/src/modules/previewpane/PdfPreviewHandlerCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp
new file mode 100644
index 0000000000..8ff6e50af6
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp
@@ -0,0 +1,261 @@
+#include "pch.h"
+#include "PdfPreviewHandler.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+PdfPreviewHandler::PdfPreviewHandler() :
+ m_cRef(1), m_hwndParent(NULL), m_rcParent(), m_punkSite(NULL), m_process(NULL)
+{
+ m_resizeEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::PDF_PREVIEW_RESIZE_EVENT);
+
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::pdfPrevLogPath);
+ Logger::init(LogSettings::pdfPrevLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+PdfPreviewHandler::~PdfPreviewHandler()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP PdfPreviewHandler::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(PdfPreviewHandler, IPreviewHandler),
+ QITABENT(PdfPreviewHandler, IInitializeWithFile),
+ QITABENT(PdfPreviewHandler, IPreviewHandlerVisuals),
+ QITABENT(PdfPreviewHandler, IOleWindow),
+ QITABENT(PdfPreviewHandler, IObjectWithSite),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+PdfPreviewHandler::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+PdfPreviewHandler::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithFile
+
+IFACEMETHODIMP PdfPreviewHandler::Initialize(LPCWSTR pszFilePath, DWORD grfMode)
+{
+ m_filePath = pszFilePath;
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandler
+
+IFACEMETHODIMP PdfPreviewHandler::SetWindow(HWND hwnd, const RECT* prc)
+{
+ if (hwnd && prc)
+ {
+ m_hwndParent = hwnd;
+ m_rcParent = *prc;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::SetFocus()
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::QueryFocus(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = ::GetFocus();
+ if (*phwnd)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ return hr;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::TranslateAccelerator(MSG* pmsg)
+{
+ HRESULT hr = S_FALSE;
+ IPreviewHandlerFrame* pFrame = NULL;
+ if (m_punkSite && SUCCEEDED(m_punkSite->QueryInterface(&pFrame)))
+ {
+ hr = pFrame->TranslateAccelerator(pmsg);
+
+ pFrame->Release();
+ }
+ return hr;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::SetRect(const RECT* prc)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (prc != NULL)
+ {
+ if (!m_resizeEvent)
+ {
+ Logger::error(L"Failed to create resize event for PdfPreviewHandler");
+ }
+ else
+ {
+ if (m_rcParent.right != prc->right || m_rcParent.left != prc->left || m_rcParent.top != prc->top || m_rcParent.bottom != prc->bottom)
+ {
+ if (!SetEvent(m_resizeEvent))
+ {
+ Logger::error(L"Failed to signal resize event for PdfPreviewHandler");
+ }
+ }
+ }
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::DoPreview()
+{
+ try
+ {
+ Logger::info(L"Starting PdfPreviewHandler.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + m_filePath + L"\"" };
+ cmdLine += L" ";
+ std::wostringstream ss;
+ ss << std::hex << m_hwndParent;
+
+ cmdLine += ss.str();
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.left);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.right);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.top);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.bottom);
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.PdfPreviewHandler.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start PdfPreviewHandler.exe. Error: {}", errorMessage);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::Unload()
+{
+ Logger::info(L"Unload and terminate .exe");
+
+ m_hwndParent = NULL;
+ TerminateProcess(m_process, 0);
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandlerVisuals
+
+IFACEMETHODIMP PdfPreviewHandler::SetBackgroundColor(COLORREF color)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::SetFont(const LOGFONTW* plf)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::SetTextColor(COLORREF color)
+{
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IOleWindow
+
+IFACEMETHODIMP PdfPreviewHandler::GetWindow(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = m_hwndParent;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+#pragma endregion
+
+#pragma region IObjectWithSite
+
+IFACEMETHODIMP PdfPreviewHandler::SetSite(IUnknown* punkSite)
+{
+ if (m_punkSite)
+ {
+ m_punkSite->Release();
+ m_punkSite = NULL;
+ }
+ return punkSite ? punkSite->QueryInterface(&m_punkSite) : S_OK;
+}
+
+IFACEMETHODIMP PdfPreviewHandler::GetSite(REFIID riid, void** ppv)
+{
+ *ppv = NULL;
+ return m_punkSite ? m_punkSite->QueryInterface(riid, ppv) : E_FAIL;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.h b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.h
new file mode 100644
index 0000000000..66ebf68ee4
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class PdfPreviewHandler :
+ public IInitializeWithFile,
+ public IPreviewHandler,
+ public IPreviewHandlerVisuals,
+ public IOleWindow,
+ public IObjectWithSite
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithFile
+ IFACEMETHODIMP Initialize(LPCWSTR pszFilePath, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP SetWindow(HWND hwnd, const RECT* prc);
+ IFACEMETHODIMP SetFocus();
+ IFACEMETHODIMP QueryFocus(HWND* phwnd);
+ IFACEMETHODIMP TranslateAccelerator(MSG* pmsg);
+ IFACEMETHODIMP SetRect(const RECT* prc);
+ IFACEMETHODIMP DoPreview();
+ IFACEMETHODIMP Unload();
+
+ // IPreviewHandlerVisuals
+ IFACEMETHODIMP SetBackgroundColor(COLORREF color);
+ IFACEMETHODIMP SetFont(const LOGFONTW* plf);
+ IFACEMETHODIMP SetTextColor(COLORREF color);
+
+ // IOleWindow
+ IFACEMETHODIMP GetWindow(HWND* phwnd);
+ IFACEMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
+
+ // IObjectWithSite
+ IFACEMETHODIMP SetSite(IUnknown* punkSite);
+ IFACEMETHODIMP GetSite(REFIID riid, void** ppv);
+
+ PdfPreviewHandler();
+protected:
+ ~PdfPreviewHandler();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ std::wstring m_filePath;
+
+ // Parent window that hosts the previewer window.
+ // Note: do NOT DestroyWindow this.
+ HWND m_hwndParent;
+ // Bounding rect of the parent window.
+ RECT m_rcParent;
+
+ // Site pointer from host, used to get IPreviewHandlerFrame.
+ IUnknown* m_punkSite;
+
+ HANDLE m_process;
+ HANDLE m_resizeEvent;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.rc b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj
new file mode 100644
index 0000000000..2eca59b53a
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj
@@ -0,0 +1,119 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {54f7c616-fd41-4e62-bff9-015686914f4d}
+ PdfPreviewHandlerCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj.filters b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj.filters
new file mode 100644
index 0000000000..ba7aa21bca
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj.filters
@@ -0,0 +1,56 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/dllmain.cpp b/src/modules/previewpane/PdfPreviewHandlerCpp/dllmain.cpp
new file mode 100644
index 0000000000..9df21544f7
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {A5A41CC7-02CB-41D4-8C9B-9087040D6098}
+static const GUID CLSID_PdfPreviewHandler = { 0xa5a41cc7, 0x2cb, 0x41d4, { 0x8c, 0x9b, 0x90, 0x87, 0x4, 0xd, 0x60, 0x98 } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_PdfPreviewHandler, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/packages.config b/src/modules/previewpane/PdfPreviewHandlerCpp/packages.config
new file mode 100644
index 0000000000..48319b8c95
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/pch.cpp b/src/modules/previewpane/PdfPreviewHandlerCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/pch.h b/src/modules/previewpane/PdfPreviewHandlerCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/resource.h b/src/modules/previewpane/PdfPreviewHandlerCpp/resource.h
new file mode 100644
index 0000000000..50e5cfb9e2
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandlerCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Pdf Preview Handler Module"
+#define INTERNAL_NAME "PowerToys.PdfPreviewHandlerCpp"
+#define ORIGINAL_FILENAME "PowerToys.PdfPreviewHandlerCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs
index a38d6813b5..0852369f96 100644
--- a/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs
+++ b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs
@@ -16,49 +16,50 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Pdf
///
/// PDF Thumbnail Provider.
///
- [Guid("BCC13D15-9720-4CC4-8371-EA74A274741E")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class PdfThumbnailProvider : IInitializeWithStream, IThumbnailProvider
+ public class PdfThumbnailProvider
{
+ public PdfThumbnailProvider(string filePath)
+ {
+ FilePath = filePath;
+ Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+ }
+
+ ///
+ /// Gets the file path to the file creating thumbnail for.
+ ///
+ public string FilePath { get; private set; }
+
///
/// Gets the stream object to access file.
///
- public IStream Stream { get; private set; }
+ public Stream Stream { get; private set; }
///
/// The maximum dimension (width or height) thumbnail we will generate.
///
private const uint MaxThumbnailSize = 10000;
- ///
- public void Initialize(IStream pstream, uint grfMode)
+ ///
+ /// Generate thumbnail bitmap for provided Pdf file/stream.
+ ///
+ /// Maximum thumbnail size, in pixels.
+ /// Generated bitmap
+ public Bitmap GetThumbnail(uint cx)
{
- // Ignore the grfMode always use read mode to access the file.
- this.Stream = pstream;
- }
-
- ///
- public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha)
- {
- phbmp = IntPtr.Zero;
- pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN;
-
if (cx == 0 || cx > MaxThumbnailSize)
{
- return;
+ return null;
}
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredPdfThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility.
- return;
+ return null;
}
- using var dataStream = new ReadonlyStream(this.Stream as IStream);
using var memStream = new MemoryStream();
- dataStream.CopyTo(memStream);
+ this.Stream.CopyTo(memStream);
memStream.Position = 0;
// AsRandomAccessStream() extension method from System.Runtime.WindowsRuntime
@@ -72,9 +73,10 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Pdf
using Bitmap thumbnail = new Bitmap(image);
- phbmp = thumbnail.GetHbitmap();
- pdwAlpha = WTS_ALPHATYPE.WTSAT_RGB;
+ return (Bitmap)thumbnail.Clone();
}
+
+ return null;
}
///
diff --git a/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj
index b206356328..af28de12f8 100644
--- a/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj
+++ b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj
@@ -1,5 +1,6 @@
+ enable
true
{11491FD8-F921-48BF-880C-7FEA185B80A1}
Microsoft.PowerToys.ThumbnailHandler.Pdf
@@ -7,13 +8,21 @@
PowerToys.PdfThumbnailProvider
PowerToys PdfPreviewHandler
net7.0-windows10.0.19041.0
- true
true
PowerToys PdfPreviewHandler
$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
false
false
true
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
@@ -26,6 +35,7 @@
$(NoWarn);1591
+ WinExe
diff --git a/src/modules/previewpane/PdfThumbnailProvider/Program.cs b/src/modules/previewpane/PdfThumbnailProvider/Program.cs
new file mode 100644
index 0000000000..0efbd0189e
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProvider/Program.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.ThumbnailHandler.Pdf
+{
+ using System.Globalization;
+
+ internal static class Program
+ {
+ private static PdfThumbnailProvider _thumbnailProvider;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 2)
+ {
+ string filePath = args[0];
+ uint cx = Convert.ToUInt32(args[1], 10);
+
+ _thumbnailProvider = new PdfThumbnailProvider(filePath);
+ Bitmap thumbnail = _thumbnailProvider.GetThumbnail(cx);
+ filePath = filePath.Replace(".pdf", ".bmp");
+ thumbnail.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
+ }
+ else
+ {
+ MessageBox.Show("Gcode thumbnail - wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/ClassFactory.cpp b/src/modules/previewpane/PdfThumbnailProviderCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..4d9bd3a565
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "PdfThumbnailProvider.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ PdfThumbnailProvider* pExt = new (std::nothrow) PdfThumbnailProvider();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/ClassFactory.h b/src/modules/previewpane/PdfThumbnailProviderCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/GlobalExportFunctions.def b/src/modules/previewpane/PdfThumbnailProviderCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProvider.cpp b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProvider.cpp
new file mode 100644
index 0000000000..312512a454
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProvider.cpp
@@ -0,0 +1,181 @@
+#include "pch.h"
+#include "PdfThumbnailProvider.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+PdfThumbnailProvider::PdfThumbnailProvider() :
+ m_cRef(1), m_pStream(NULL), m_process(NULL)
+{
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::pdfThumbLogPath);
+ Logger::init(LogSettings::pdfThumbLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+PdfThumbnailProvider::~PdfThumbnailProvider()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP PdfThumbnailProvider::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(PdfThumbnailProvider, IThumbnailProvider),
+ QITABENT(PdfThumbnailProvider, IInitializeWithStream),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+PdfThumbnailProvider::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+PdfThumbnailProvider::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithStream
+
+IFACEMETHODIMP PdfThumbnailProvider::Initialize(IStream* pStream, DWORD grfMode)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (pStream)
+ {
+ // Initialize can be called more than once, so release existing valid
+ // m_pStream.
+ if (m_pStream)
+ {
+ m_pStream->Release();
+ m_pStream = NULL;
+ }
+
+ m_pStream = pStream;
+ m_pStream->AddRef();
+ hr = S_OK;
+ }
+ return hr;
+}
+
+#pragma endregion
+
+#pragma region IThumbnailProvider
+
+IFACEMETHODIMP PdfThumbnailProvider::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
+{
+ // Read stream into the buffer
+ char buffer[4096];
+ ULONG cbRead;
+
+ Logger::trace(L"Begin");
+
+ GUID guid;
+ if (CoCreateGuid(&guid) == S_OK)
+ {
+ wil::unique_cotaskmem_string guidString;
+ if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
+ {
+ Logger::info(L"Read stream and save to tmp file.");
+
+ // {CLSID} -> CLSID
+ std::wstring guid = std::wstring(guidString.get()).substr(1, std::wstring(guidString.get()).size() - 2);
+ std::wstring filePath = PTSettingsHelper::get_local_low_folder_location() + L"\\PdfThumbnail-Temp\\";
+ if (!std::filesystem::exists(filePath))
+ {
+ std::filesystem::create_directories(filePath);
+ }
+
+ std::wstring fileName = filePath + guid + L".pdf";
+
+ // Write data to tmp file
+ std::fstream file;
+ file.open(fileName, std::ios_base::out | std::ios_base::binary);
+
+ if (!file.is_open())
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ auto result = m_pStream->Read(buffer, 4096, &cbRead);
+
+ file.write(buffer, cbRead);
+ if (result == S_FALSE)
+ {
+ break;
+ }
+ }
+ file.close();
+
+ try
+ {
+ Logger::info(L"Start PdfThumbnailProvider.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + fileName + L"\"" };
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(cx);
+
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.PdfThumbnailProvider.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ WaitForSingleObject(m_process, INFINITE);
+ std::filesystem::remove(fileName);
+
+ std::wstring fileNameBmp = filePath + guid + L".bmp";
+ *phbmp = (HBITMAP)LoadImage(NULL, fileNameBmp.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
+ *pdwAlpha = WTS_ALPHATYPE::WTSAT_ARGB;
+
+ std::filesystem::remove(fileNameBmp);
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start PdfThumbnailProvider.exe. Error: {}", errorMessage);
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProvider.h b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProvider.h
new file mode 100644
index 0000000000..9ae9b43445
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProvider.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class PdfThumbnailProvider :
+ public IInitializeWithStream,
+ public IThumbnailProvider
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithStream
+ IFACEMETHODIMP Initialize(IStream* pstream, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
+
+ PdfThumbnailProvider();
+protected:
+ ~PdfThumbnailProvider();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ IStream* m_pStream;
+
+ HANDLE m_process;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.rc b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj
new file mode 100644
index 0000000000..7690364542
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj
@@ -0,0 +1,121 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {ca5518ed-0458-4b09-8f53-4122b9888655}
+ PdfThumbnailProviderCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj.filters b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj.filters
new file mode 100644
index 0000000000..25a0d0a880
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj.filters
@@ -0,0 +1,59 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/dllmain.cpp b/src/modules/previewpane/PdfThumbnailProviderCpp/dllmain.cpp
new file mode 100644
index 0000000000..e08a9c6adf
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {D8BB9942-93BD-412D-87E4-33FAB214DC1A}
+static const GUID CLSID_PdfThumbnailProvider = { 0xd8bb9942, 0x93bd, 0x412d, { 0x87, 0xe4, 0x33, 0xfa, 0xb2, 0x14, 0xdc, 0x1a } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_PdfThumbnailProvider, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/packages.config b/src/modules/previewpane/PdfThumbnailProviderCpp/packages.config
new file mode 100644
index 0000000000..c92dd4bf0c
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/pch.cpp b/src/modules/previewpane/PdfThumbnailProviderCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/pch.h b/src/modules/previewpane/PdfThumbnailProviderCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/PdfThumbnailProviderCpp/resource.h b/src/modules/previewpane/PdfThumbnailProviderCpp/resource.h
new file mode 100644
index 0000000000..209bddb345
--- /dev/null
+++ b/src/modules/previewpane/PdfThumbnailProviderCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Pdf Thumbnail Provider Module"
+#define INTERNAL_NAME "PowerToys.PdfThumbnailProviderCpp"
+#define ORIGINAL_FILENAME "PowerToys.PdfThumbnailProviderCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/README.md b/src/modules/previewpane/README.md
index 383548bd4f..10653a4811 100644
--- a/src/modules/previewpane/README.md
+++ b/src/modules/previewpane/README.md
@@ -6,122 +6,14 @@
## Developing
-We have already done most of the development work in the [PreviewHandlerCommon](./common/cominterop/IPreviewHandler.cs) common project. To add a preview for the file type of .xyz:
-
-- Add a new .NET project in the preview pane folder.
-- Add a reference to the `PreviewHandlerCommon` common project.
-- Create your preview handler class and extend the FileBasedPreviewHandler class. See an example below:
-
-```csharp
-using System;
-using System.Runtime.InteropServices;
-using Common;
-
-namespace XYZPreviewHandler
-{
- ///
- /// Implementation of preview handler for .xyz files.
- /// GUID = CLSID / CLASS ID.
- ///
- [Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class XYZPreviewHandler : FileBasedPreviewHandler
- {
- private XYZPreviewHandlerControl xyzPreviewHandlerControl;
-
- /// Call your rendering method here.
- public override void DoPreview()
- {
- this.xyzPreviewHandlerControl.DoPreview(this.FilePath);
- }
-
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- this.xyzPreviewHandlerControl = new xyzPreviewHandlerControl();
- return this.xyzPreviewHandlerControl;
- }
- }
-}
-```
-
-Create a separate Preview Handler Control class and extend the `FormHandlerControl` Class.
-
-```csharp
-using Common;
-
-namespace XYZPreviewHandler
-{
- public class XYZPreviewHandlerControl : FormHandlerControl
- {
- public XYZPreviewHandlerControl()
- {
- // ... do your initializations here.
- }
-
- public override void DoPreview(T dataSource)
- {
- // ... add your preview rendering code here.
- }
- }
-}
-```
-
-#### Integrate the Preview Handler into PowerToys Settings:
-
-Navigate to the [powerpreview](../previewpane/powerpreview/powerpreview.h) project and edit the `powerpreview.h` file. Add the following Settings Object instance to `m_previewHandlers` settings objects array in the constructor initialization:
-
-```cpp
-// XYZ Preview Handler Settings Object.
-FileExplorerPreviewSettings(
- false,
- L"<--YOUR_TOGGLE_CONTROL_ID-->",
- L"<--A description of your preview handler-->",
- L"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx", // your preview handler CLSID.
- L"<--A display name for your preview handler-->")
-```
+- Add new C++ DLL project in the preview pane folder. This DLL is actual preview handler, i.e. implements IPreviewHandler/IThumbnailProvider interface.
+- Add new .NET EXE project in the preview pane folder. This EXE is being spawned by C++ DLL to generate preview/thumbnail.
## Installation
### MSI (Recommended)
-To add a new Previewer update the `Product.wxs` file in `PowerToysSetup` similar to existing Previewer to register the Preview Handler. More details about registration of Preview Handlers can be [found here.](https://learn.microsoft.com/windows/win32/shell/how-to-register-a-preview-handler)
-
-```xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
+To add a new Previewer update the `Product.wxs` file in `PowerToysSetup` similar to existing Previewer to register the Preview Handler. More details about registration of Preview Handlers can be [found here.](https://learn.microsoft.com/windows/win32/shell/how-to-register-a-preview-handler) - implemented in [modulesRegistry.h](../../common/utils/modulesRegistry.h).
### Directly registering/unregistering DLL's
**[Important] This method of registering Preview Handler DLL's is not recommended. It could lead to registry corruption.**
diff --git a/src/modules/previewpane/StlThumbnailProvider/Program.cs b/src/modules/previewpane/StlThumbnailProvider/Program.cs
new file mode 100644
index 0000000000..79e77c8913
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProvider/Program.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.ThumbnailHandler.Stl
+{
+ using System.Globalization;
+
+ internal static class Program
+ {
+ private static StlThumbnailProvider _thumbnailProvider;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 2)
+ {
+ string filePath = args[0];
+ uint cx = Convert.ToUInt32(args[1], 10);
+
+ _thumbnailProvider = new StlThumbnailProvider(filePath);
+ Bitmap thumbnail = _thumbnailProvider.GetThumbnail(cx);
+ filePath = filePath.Replace(".stl", ".bmp");
+ thumbnail.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
+ }
+ else
+ {
+ MessageBox.Show("Gcode thumbnail - wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.cs b/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.cs
index c944d7936b..c7d4ebdd14 100644
--- a/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.cs
+++ b/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.cs
@@ -1,33 +1,40 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.IO;
-using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
-using Common.ComInterlop;
using Common.Utilities;
using HelixToolkit.Wpf;
using Microsoft.PowerToys.Settings.UI.Library;
using Bitmap = System.Drawing.Bitmap;
+using Color = System.Windows.Media.Color;
+using ColorConverter = System.Windows.Media.ColorConverter;
namespace Microsoft.PowerToys.ThumbnailHandler.Stl
{
///
/// Stl Thumbnail Provider.
///
- [Guid("8BC8AFC2-4E7C-4695-818E-8C1FFDCEA2AF")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class StlThumbnailProvider : IInitializeWithStream, IThumbnailProvider
+ public class StlThumbnailProvider
{
+ public StlThumbnailProvider(string filePath)
+ {
+ FilePath = filePath;
+ Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+ }
+
+ ///
+ /// Gets the file path to the file creating thumbnail for.
+ ///
+ public string FilePath { get; private set; }
+
///
/// Gets the stream object to access file.
///
- public IStream Stream { get; private set; }
+ public Stream Stream { get; private set; }
///
/// The maximum dimension (width or height) thumbnail we will generate.
@@ -63,7 +70,7 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Stl
var viewport = new System.Windows.Controls.Viewport3D();
- viewport.Measure(new Size(cx, cx));
+ viewport.Measure(new System.Windows.Size(cx, cx));
viewport.Arrange(new Rect(0, 0, cx, cx));
var modelVisual = new ModelVisual3D()
@@ -105,48 +112,40 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Stl
return thumbnail;
}
- ///
- public void Initialize(IStream pstream, uint grfMode)
+ ///
+ /// Generate thumbnail bitmap for provided Gcode file/stream.
+ ///
+ /// Maximum thumbnail size, in pixels.
+ /// Generated bitmap
+ public Bitmap GetThumbnail(uint cx)
{
- // Ignore the grfMode always use read mode to access the file.
- this.Stream = pstream;
- }
-
- ///
- public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha)
- {
- phbmp = IntPtr.Zero;
- pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN;
-
if (cx == 0 || cx > MaxThumbnailSize)
{
- return;
+ return null;
}
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredStlThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility.
- return;
+ return null;
}
- using (var stream = new ReadonlyStream(this.Stream as IStream))
+ using (var memStream = new MemoryStream())
{
- using (var memStream = new MemoryStream())
+ this.Stream.CopyTo(memStream);
+
+ memStream.Position = 0;
+
+ using (Bitmap thumbnail = GetThumbnail(memStream, cx))
{
- stream.CopyTo(memStream);
-
- memStream.Position = 0;
-
- using (Bitmap thumbnail = GetThumbnail(memStream, cx))
+ if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
{
- if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
- {
- phbmp = thumbnail.GetHbitmap(System.Drawing.Color.Transparent);
- pdwAlpha = WTS_ALPHATYPE.WTSAT_ARGB;
- }
+ return (Bitmap)thumbnail.Clone();
}
}
}
+
+ return null;
}
///
diff --git a/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.csproj b/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.csproj
index ebfd1c81fd..016716c50a 100644
--- a/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.csproj
+++ b/src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.csproj
@@ -1,5 +1,6 @@
+ enable
true
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}
Microsoft.PowerToys.ThumbnailHandler.Stl
@@ -7,7 +8,6 @@
PowerToys.StlThumbnailProvider
PowerToys StlPreviewHandler
net7.0-windows10.0.19041.0
- true
true
PowerToys StlPreviewHandler
$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
@@ -15,6 +15,15 @@
false
true
true
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
@@ -27,6 +36,7 @@
$(NoWarn);1591
+ WinExe
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/ClassFactory.cpp b/src/modules/previewpane/StlThumbnailProviderCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..653a126aa6
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "StlThumbnailProvider.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ StlThumbnailProvider* pExt = new (std::nothrow) StlThumbnailProvider();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/ClassFactory.h b/src/modules/previewpane/StlThumbnailProviderCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/GlobalExportFunctions.def b/src/modules/previewpane/StlThumbnailProviderCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProvider.cpp b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProvider.cpp
new file mode 100644
index 0000000000..eada9c4b06
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProvider.cpp
@@ -0,0 +1,181 @@
+#include "pch.h"
+#include "StlThumbnailProvider.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+StlThumbnailProvider::StlThumbnailProvider() :
+ m_cRef(1), m_pStream(NULL), m_process(NULL)
+{
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::stlThumbLogPath);
+ Logger::init(LogSettings::stlThumbLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+StlThumbnailProvider::~StlThumbnailProvider()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP StlThumbnailProvider::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(StlThumbnailProvider, IThumbnailProvider),
+ QITABENT(StlThumbnailProvider, IInitializeWithStream),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+StlThumbnailProvider::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+StlThumbnailProvider::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithStream
+
+IFACEMETHODIMP StlThumbnailProvider::Initialize(IStream* pStream, DWORD grfMode)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (pStream)
+ {
+ // Initialize can be called more than once, so release existing valid
+ // m_pStream.
+ if (m_pStream)
+ {
+ m_pStream->Release();
+ m_pStream = NULL;
+ }
+
+ m_pStream = pStream;
+ m_pStream->AddRef();
+ hr = S_OK;
+ }
+ return hr;
+}
+
+#pragma endregion
+
+#pragma region IThumbnailProvider
+
+IFACEMETHODIMP StlThumbnailProvider::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
+{
+ // Read stream into the buffer
+ char buffer[4096];
+ ULONG cbRead;
+
+ Logger::trace(L"Begin");
+
+ GUID guid;
+ if (CoCreateGuid(&guid) == S_OK)
+ {
+ wil::unique_cotaskmem_string guidString;
+ if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
+ {
+ Logger::info(L"Read stream and save to tmp file.");
+
+ // {CLSID} -> CLSID
+ std::wstring guid = std::wstring(guidString.get()).substr(1, std::wstring(guidString.get()).size() - 2);
+ std::wstring filePath = PTSettingsHelper::get_local_low_folder_location() + L"\\StlThumbnail-Temp\\";
+ if (!std::filesystem::exists(filePath))
+ {
+ std::filesystem::create_directories(filePath);
+ }
+
+ std::wstring fileName = filePath + guid + L".stl";
+
+ // Write data to tmp file
+ std::fstream file;
+ file.open(fileName, std::ios_base::out | std::ios_base::binary);
+
+ if (!file.is_open())
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ auto result = m_pStream->Read(buffer, 4096, &cbRead);
+
+ file.write(buffer, cbRead);
+ if (result == S_FALSE)
+ {
+ break;
+ }
+ }
+ file.close();
+
+ try
+ {
+ Logger::info(L"Start StlThumbnailProvider.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + fileName + L"\"" };
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(cx);
+
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.StlThumbnailProvider.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ WaitForSingleObject(m_process, INFINITE);
+ std::filesystem::remove(fileName);
+
+ std::wstring fileNameBmp = filePath + guid + L".bmp";
+ *phbmp = (HBITMAP)LoadImage(NULL, fileNameBmp.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
+ *pdwAlpha = WTS_ALPHATYPE::WTSAT_ARGB;
+
+ std::filesystem::remove(fileNameBmp);
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start StlThumbnailProvider.exe. Error: {}", errorMessage);
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProvider.h b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProvider.h
new file mode 100644
index 0000000000..ea97d69c82
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProvider.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class StlThumbnailProvider :
+ public IInitializeWithStream,
+ public IThumbnailProvider
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithStream
+ IFACEMETHODIMP Initialize(IStream* pstream, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
+
+ StlThumbnailProvider();
+protected:
+ ~StlThumbnailProvider();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ IStream* m_pStream;
+
+ HANDLE m_process;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.rc b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj
new file mode 100644
index 0000000000..1d8956cb9f
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj
@@ -0,0 +1,121 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {d6dcc3ae-18c0-488a-b978-baa9e3cff09d}
+ StlThumbnailProviderCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj.filters b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj.filters
new file mode 100644
index 0000000000..a787045e5e
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj.filters
@@ -0,0 +1,59 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/dllmain.cpp b/src/modules/previewpane/StlThumbnailProviderCpp/dllmain.cpp
new file mode 100644
index 0000000000..e97a163a42
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {77257004-6F25-4521-B602-50ECC6EC62A6}
+static const GUID CLSID_StlThumbnailProvider = { 0x77257004, 0x6f25, 0x4521, { 0xb6, 0x2, 0x50, 0xec, 0xc6, 0xec, 0x62, 0xa6 } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_StlThumbnailProvider, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/packages.config b/src/modules/previewpane/StlThumbnailProviderCpp/packages.config
new file mode 100644
index 0000000000..c92dd4bf0c
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/pch.cpp b/src/modules/previewpane/StlThumbnailProviderCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/pch.h b/src/modules/previewpane/StlThumbnailProviderCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/StlThumbnailProviderCpp/resource.h b/src/modules/previewpane/StlThumbnailProviderCpp/resource.h
new file mode 100644
index 0000000000..9d8a12e219
--- /dev/null
+++ b/src/modules/previewpane/StlThumbnailProviderCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Stl Thumbnail Provider Module"
+#define INTERNAL_NAME "PowerToys.StlThumbnailProviderCpp"
+#define ORIGINAL_FILENAME "PowerToys.StlThumbnailProviderCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/SvgPreviewHandler/Program.cs b/src/modules/previewpane/SvgPreviewHandler/Program.cs
new file mode 100644
index 0000000000..f9c013b354
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandler/Program.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.PreviewHandler.Svg
+{
+ using System.Globalization;
+ using System.Windows.Threading;
+ using Common.UI;
+ using interop;
+
+ internal static class Program
+ {
+ private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
+
+ private static SvgPreviewControl _previewHandlerControl;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 6)
+ {
+ string filePath = args[0];
+ int hwnd = Convert.ToInt32(args[1], 16);
+
+ Rectangle s = default(Rectangle);
+ int left = Convert.ToInt32(args[2], 10);
+ int right = Convert.ToInt32(args[3], 10);
+ int top = Convert.ToInt32(args[4], 10);
+ int bottom = Convert.ToInt32(args[5], 10);
+
+ _previewHandlerControl = new SvgPreviewControl();
+ _previewHandlerControl.SetWindow((IntPtr)hwnd, s);
+ _previewHandlerControl.DoPreview(filePath);
+
+ NativeEventWaiter.WaitForEventLoop(
+ Constants.SvgPreviewResizeEvent(),
+ () =>
+ {
+ Rectangle s = default(Rectangle);
+ _previewHandlerControl.SetRect(s);
+ },
+ Dispatcher.CurrentDispatcher,
+ _tokenSource.Token);
+ }
+ else
+ {
+ MessageBox.Show("Wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ Application.Run();
+ }
+ }
+}
diff --git a/src/modules/previewpane/SvgPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml b/src/modules/previewpane/SvgPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
index 74181a551d..d8a1a0ab2d 100644
--- a/src/modules/previewpane/SvgPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
+++ b/src/modules/previewpane/SvgPreviewHandler/Properties/PublishProfiles/InstallationPublishProfile.pubxml
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net7.0-windows10.0.19041.0
$(PowerToysRoot)\$(Platform)\$(Configuration)\modules\FileExplorerPreview
win10-$(Platform)
- false
+ true
False
False
false
diff --git a/src/modules/previewpane/SvgPreviewHandler/SvgPreviewControl.cs b/src/modules/previewpane/SvgPreviewHandler/SvgPreviewControl.cs
index cb0152f170..907dde51aa 100644
--- a/src/modules/previewpane/SvgPreviewHandler/SvgPreviewControl.cs
+++ b/src/modules/previewpane/SvgPreviewHandler/SvgPreviewControl.cs
@@ -2,16 +2,10 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Drawing;
-using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices.ComTypes;
-using System.Windows.Forms;
using Common;
using Common.Utilities;
-using Microsoft.PowerToys.PreviewHandler.Svg.Properties;
using Microsoft.PowerToys.PreviewHandler.Svg.Telemetry.Events;
using Microsoft.PowerToys.Telemetry;
using Microsoft.Web.WebView2.Core;
@@ -86,13 +80,10 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredSvgPreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility. Show an error message instead.
- InvokeOnControlThread(() =>
- {
- _infoBarAdded = true;
- AddTextBoxControl(Properties.Resource.GpoDisabledErrorText);
- Resize += FormResized;
- base.DoPreview(dataSource);
- });
+ _infoBarAdded = true;
+ AddTextBoxControl(Properties.Resource.GpoDisabledErrorText);
+ Resize += FormResized;
+ base.DoPreview(dataSource);
return;
}
@@ -104,7 +95,12 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
try
{
- using (var stream = new ReadonlyStream(dataSource as IStream))
+ if (!(dataSource is string filePath))
+ {
+ throw new ArgumentException($"{nameof(dataSource)} for {nameof(SvgPreviewControl)} must be a string but was a '{typeof(T)}'");
+ }
+
+ using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (var reader = new StreamReader(stream))
{
@@ -133,29 +129,26 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
PowerToysTelemetry.Log.WriteEvent(new SvgFilePreviewError { Message = ex.Message });
}
- InvokeOnControlThread(() =>
+ try
{
- try
- {
- _infoBarAdded = false;
+ _infoBarAdded = false;
- // Add a info bar on top of the Preview if any blocked element is present.
- if (blocked)
- {
- _infoBarAdded = true;
- AddTextBoxControl(Properties.Resource.BlockedElementInfoText);
- }
-
- AddWebViewControl(svgData);
- Resize += FormResized;
- base.DoPreview(dataSource);
- PowerToysTelemetry.Log.WriteEvent(new SvgFilePreviewed());
- }
- catch (Exception ex)
+ // Add a info bar on top of the Preview if any blocked element is present.
+ if (blocked)
{
- PreviewError(ex, dataSource);
+ _infoBarAdded = true;
+ AddTextBoxControl(Properties.Resource.BlockedElementInfoText);
}
- });
+
+ AddWebViewControl(svgData);
+ Resize += FormResized;
+ base.DoPreview(dataSource);
+ PowerToysTelemetry.Log.WriteEvent(new SvgFilePreviewed());
+ }
+ catch (Exception ex)
+ {
+ PreviewError(ex, dataSource);
+ }
}
///
@@ -207,49 +200,46 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
webView2EnvironmentAwaiter = CoreWebView2Environment
.CreateAsync(userDataFolder: _webView2UserDataFolder, options: webView2Options)
.ConfigureAwait(true).GetAwaiter();
- webView2EnvironmentAwaiter.OnCompleted(() =>
+ webView2EnvironmentAwaiter.OnCompleted(async () =>
{
- InvokeOnControlThread(async () =>
+ try
{
- try
+ _webView2Environment = webView2EnvironmentAwaiter.GetResult();
+ await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
+ _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny);
+ _browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
+ _browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
+ _browser.CoreWebView2.Settings.AreDevToolsEnabled = false;
+ _browser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
+ _browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
+ _browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
+ _browser.CoreWebView2.Settings.IsScriptEnabled = false;
+ _browser.CoreWebView2.Settings.IsWebMessageEnabled = false;
+
+ // Don't load any resources.
+ _browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
+ _browser.CoreWebView2.WebResourceRequested += CoreWebView2_BlockExternalResources;
+
+ // WebView2.NavigateToString() limitation
+ // See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks
+ // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes
+ if (svgData.Length > 1_500_000)
{
- _webView2Environment = webView2EnvironmentAwaiter.GetResult();
- await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
- _browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny);
- _browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
- _browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
- _browser.CoreWebView2.Settings.AreDevToolsEnabled = false;
- _browser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
- _browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
- _browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
- _browser.CoreWebView2.Settings.IsScriptEnabled = false;
- _browser.CoreWebView2.Settings.IsWebMessageEnabled = false;
-
- // Don't load any resources.
- _browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
- _browser.CoreWebView2.WebResourceRequested += CoreWebView2_BlockExternalResources;
-
- // WebView2.NavigateToString() limitation
- // See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks
- // While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes
- if (svgData.Length > 1_500_000)
- {
- string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html";
- File.WriteAllText(filename, svgData);
- _localFileURI = new Uri(filename);
- _browser.Source = _localFileURI;
- }
- else
- {
- _browser.NavigateToString(svgData);
- }
-
- Controls.Add(_browser);
+ string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html";
+ File.WriteAllText(filename, svgData);
+ _localFileURI = new Uri(filename);
+ _browser.Source = _localFileURI;
}
- catch (Exception)
+ else
{
+ _browser.NavigateToString(svgData);
}
- });
+
+ Controls.Add(_browser);
+ }
+ catch (Exception)
+ {
+ }
});
}
diff --git a/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.cs b/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.cs
deleted file mode 100644
index 2061b03184..0000000000
--- a/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using Common;
-using Microsoft.PowerToys.Telemetry;
-
-namespace Microsoft.PowerToys.PreviewHandler.Svg
-{
- ///
- /// Extends for Svg Preview Handler.
- ///
- [Guid("ddee2b8a-6807-48a6-bb20-2338174ff779")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class SvgPreviewHandler : StreamBasedPreviewHandler, IDisposable
- {
- private SvgPreviewControl _svgPreviewControl;
- private bool disposedValue;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SvgPreviewHandler()
- {
- Initialize();
- }
-
- ///
- public override void DoPreview()
- {
- _svgPreviewControl.DoPreview(Stream);
- }
-
- ///
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- PowerToysTelemetry.Log.WriteEvent(new Telemetry.Events.SvgFileHandlerLoaded());
- _svgPreviewControl = new SvgPreviewControl();
-
- return _svgPreviewControl;
- }
-
- ///
- /// Disposes objects
- ///
- /// Is Disposing
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- _svgPreviewControl.Dispose();
- }
-
- disposedValue = true;
- }
- }
-
- ///
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj b/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj
index a328991454..0bf93c0376 100644
--- a/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj
+++ b/src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj
@@ -1,5 +1,7 @@
+ enable
+ true
true
PowerToys.SvgPreviewHandler
PowerToys SvgPreviewHandler
@@ -12,12 +14,20 @@
true
win10-x64;win10-arm64
net7.0-windows10.0.19041.0
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
{DA425894-6E13-404F-8DCB-78584EC0557A}
Microsoft.PowerToys.PreviewHandler.Svg
- true
PowerToys.SvgPreviewHandler
@@ -41,10 +51,13 @@
$(NoWarn);1591
+ WinExe
+
+
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/ClassFactory.cpp b/src/modules/previewpane/SvgPreviewHandlerCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..9e5a4691e4
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "SvgPreviewHandler.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ SvgPreviewHandler* pExt = new (std::nothrow) SvgPreviewHandler();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/ClassFactory.h b/src/modules/previewpane/SvgPreviewHandlerCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/GlobalExportFunctions.def b/src/modules/previewpane/SvgPreviewHandlerCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp
new file mode 100644
index 0000000000..21841329a0
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp
@@ -0,0 +1,258 @@
+#include "pch.h"
+#include "SvgPreviewHandler.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+SvgPreviewHandler::SvgPreviewHandler() :
+ m_cRef(1), m_hwndParent(NULL), m_rcParent(), m_punkSite(NULL), m_process(NULL)
+{
+ m_resizeEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::SVG_PREVIEW_RESIZE_EVENT);
+
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::svgPrevLogPath);
+ Logger::init(LogSettings::svgPrevLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+SvgPreviewHandler::~SvgPreviewHandler()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP SvgPreviewHandler::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(SvgPreviewHandler, IPreviewHandler),
+ QITABENT(SvgPreviewHandler, IInitializeWithFile),
+ QITABENT(SvgPreviewHandler, IPreviewHandlerVisuals),
+ QITABENT(SvgPreviewHandler, IOleWindow),
+ QITABENT(SvgPreviewHandler, IObjectWithSite),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+SvgPreviewHandler::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+SvgPreviewHandler::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithFile
+
+IFACEMETHODIMP SvgPreviewHandler::Initialize(LPCWSTR pszFilePath, DWORD grfMode)
+{
+ m_filePath = pszFilePath;
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandler
+
+IFACEMETHODIMP SvgPreviewHandler::SetWindow(HWND hwnd, const RECT* prc)
+{
+ if (hwnd && prc)
+ {
+ m_hwndParent = hwnd;
+ m_rcParent = *prc;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::SetFocus()
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::QueryFocus(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = ::GetFocus();
+ if (*phwnd)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ return hr;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::TranslateAccelerator(MSG* pmsg)
+{
+ HRESULT hr = S_FALSE;
+ IPreviewHandlerFrame* pFrame = NULL;
+ if (m_punkSite && SUCCEEDED(m_punkSite->QueryInterface(&pFrame)))
+ {
+ hr = pFrame->TranslateAccelerator(pmsg);
+
+ pFrame->Release();
+ }
+ return hr;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::SetRect(const RECT* prc)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (prc != NULL)
+ {
+ if (!m_resizeEvent)
+ {
+ Logger::error(L"Failed to create resize event for SvgPreviewHandler");
+ }
+ else
+ {
+ if (m_rcParent.right != prc->right || m_rcParent.left != prc->left || m_rcParent.top != prc->top || m_rcParent.bottom != prc->bottom)
+ {
+ if (!SetEvent(m_resizeEvent))
+ {
+ Logger::error(L"Failed to signal resize event for SvgPreviewHandler");
+ }
+ }
+ }
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::DoPreview()
+{
+ try
+ {
+ Logger::info(L"Starting SvgPreviewHandler.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + m_filePath + L"\"" };
+ cmdLine += L" ";
+ std::wostringstream ss;
+ ss << std::hex << m_hwndParent;
+
+ cmdLine += ss.str();
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.left);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.right);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.top);
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(m_rcParent.bottom);
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.SvgPreviewHandler.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start SvgPreviewHandler.exe. Error: {}", errorMessage);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::Unload()
+{
+ TerminateProcess(m_process, 0);
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IPreviewHandlerVisuals
+
+IFACEMETHODIMP SvgPreviewHandler::SetBackgroundColor(COLORREF color)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::SetFont(const LOGFONTW* plf)
+{
+ return S_OK;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::SetTextColor(COLORREF color)
+{
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region IOleWindow
+
+IFACEMETHODIMP SvgPreviewHandler::GetWindow(HWND* phwnd)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (phwnd)
+ {
+ *phwnd = m_hwndParent;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+#pragma endregion
+
+#pragma region IObjectWithSite
+
+IFACEMETHODIMP SvgPreviewHandler::SetSite(IUnknown* punkSite)
+{
+ if (m_punkSite)
+ {
+ m_punkSite->Release();
+ m_punkSite = NULL;
+ }
+ return punkSite ? punkSite->QueryInterface(&m_punkSite) : S_OK;
+}
+
+IFACEMETHODIMP SvgPreviewHandler::GetSite(REFIID riid, void** ppv)
+{
+ *ppv = NULL;
+ return m_punkSite ? m_punkSite->QueryInterface(riid, ppv) : E_FAIL;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.h b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.h
new file mode 100644
index 0000000000..c1c20e8ad0
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class SvgPreviewHandler :
+ public IInitializeWithFile,
+ public IPreviewHandler,
+ public IPreviewHandlerVisuals,
+ public IOleWindow,
+ public IObjectWithSite
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithFile
+ IFACEMETHODIMP Initialize(LPCWSTR pszFilePath, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP SetWindow(HWND hwnd, const RECT* prc);
+ IFACEMETHODIMP SetFocus();
+ IFACEMETHODIMP QueryFocus(HWND* phwnd);
+ IFACEMETHODIMP TranslateAccelerator(MSG* pmsg);
+ IFACEMETHODIMP SetRect(const RECT* prc);
+ IFACEMETHODIMP DoPreview();
+ IFACEMETHODIMP Unload();
+
+ // IPreviewHandlerVisuals
+ IFACEMETHODIMP SetBackgroundColor(COLORREF color);
+ IFACEMETHODIMP SetFont(const LOGFONTW* plf);
+ IFACEMETHODIMP SetTextColor(COLORREF color);
+
+ // IOleWindow
+ IFACEMETHODIMP GetWindow(HWND* phwnd);
+ IFACEMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
+
+ // IObjectWithSite
+ IFACEMETHODIMP SetSite(IUnknown* punkSite);
+ IFACEMETHODIMP GetSite(REFIID riid, void** ppv);
+
+ SvgPreviewHandler();
+protected:
+ ~SvgPreviewHandler();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ std::wstring m_filePath;
+
+ // Parent window that hosts the previewer window.
+ // Note: do NOT DestroyWindow this.
+ HWND m_hwndParent;
+ // Bounding rect of the parent window.
+ RECT m_rcParent;
+
+ // Site pointer from host, used to get IPreviewHandlerFrame.
+ IUnknown* m_punkSite;
+
+ HANDLE m_process;
+ HANDLE m_resizeEvent;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.rc b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj
new file mode 100644
index 0000000000..0bf8d3967f
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj
@@ -0,0 +1,119 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {143f13e3-d2e3-4d83-b035-356612d99956}
+ SvgPreviewHandlerCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj.filters b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj.filters
new file mode 100644
index 0000000000..e3ccce0bed
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj.filters
@@ -0,0 +1,56 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/dllmain.cpp b/src/modules/previewpane/SvgPreviewHandlerCpp/dllmain.cpp
new file mode 100644
index 0000000000..28871d2fe8
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {FCDD4EED-41AA-492F-8A84-31A1546226E0}
+static const GUID CLSID_SvgPreviewHandler = { 0xfcdd4eed, 0x41aa, 0x492f, { 0x8a, 0x84, 0x31, 0xa1, 0x54, 0x62, 0x26, 0xe0 } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_SvgPreviewHandler, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/packages.config b/src/modules/previewpane/SvgPreviewHandlerCpp/packages.config
new file mode 100644
index 0000000000..48319b8c95
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/pch.cpp b/src/modules/previewpane/SvgPreviewHandlerCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/pch.h b/src/modules/previewpane/SvgPreviewHandlerCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/resource.h b/src/modules/previewpane/SvgPreviewHandlerCpp/resource.h
new file mode 100644
index 0000000000..76fe6194dd
--- /dev/null
+++ b/src/modules/previewpane/SvgPreviewHandlerCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Svg Preview Handler Module"
+#define INTERNAL_NAME "PowerToys.SvgPreviewHandlerCpp"
+#define ORIGINAL_FILENAME "PowerToys.SvgPreviewHandlerCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/SvgThumbnailProvider/Program.cs b/src/modules/previewpane/SvgThumbnailProvider/Program.cs
new file mode 100644
index 0000000000..18df99e29f
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProvider/Program.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.PowerToys.ThumbnailHandler.Svg
+{
+ using System.Globalization;
+
+ internal static class Program
+ {
+ private static SvgThumbnailProvider _thumbnailProvider;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ ApplicationConfiguration.Initialize();
+ if (args != null)
+ {
+ if (args.Length == 2)
+ {
+ string filePath = args[0];
+ uint cx = Convert.ToUInt32(args[1], 10);
+
+ _thumbnailProvider = new SvgThumbnailProvider(filePath);
+ Bitmap thumbnail = _thumbnailProvider.GetThumbnail(cx);
+ filePath = filePath.Replace(".svg", ".bmp");
+ thumbnail.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
+ }
+ else
+ {
+ MessageBox.Show("Gcode thumbnail - wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/previewpane/SvgThumbnailProvider/Properties/PublishProfiles/InstallationPublishProfile.pubxml b/src/modules/previewpane/SvgThumbnailProvider/Properties/PublishProfiles/InstallationPublishProfile.pubxml
index 74181a551d..d8a1a0ab2d 100644
--- a/src/modules/previewpane/SvgThumbnailProvider/Properties/PublishProfiles/InstallationPublishProfile.pubxml
+++ b/src/modules/previewpane/SvgThumbnailProvider/Properties/PublishProfiles/InstallationPublishProfile.pubxml
@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net7.0-windows10.0.19041.0
$(PowerToysRoot)\$(Platform)\$(Configuration)\modules\FileExplorerPreview
win10-$(Platform)
- false
+ true
False
False
false
diff --git a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs
index 64a13d93fd..f8b8964be7 100644
--- a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs
+++ b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs
@@ -1,17 +1,10 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
-using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
-using System.Windows.Forms;
-using Common.ComInterlop;
using Common.Utilities;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
@@ -21,15 +14,26 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
///
/// SVG Thumbnail Provider.
///
- [Guid("36B27788-A8BB-4698-A756-DF9F11F64F84")]
- [ClassInterface(ClassInterfaceType.None)]
- [ComVisible(true)]
- public class SvgThumbnailProvider : IInitializeWithStream, IThumbnailProvider, IDisposable
+ public class SvgThumbnailProvider : IDisposable
{
+ public SvgThumbnailProvider(string filePath)
+ {
+ FilePath = filePath;
+ if (FilePath != null && File.Exists(FilePath))
+ {
+ Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+ }
+ }
+
+ ///
+ /// Gets the file path to the file creating thumbnail for.
+ ///
+ public string FilePath { get; private set; }
+
///
/// Gets the stream object to access file.
///
- public IStream Stream { get; private set; }
+ public Stream Stream { get; private set; }
///
/// The maximum dimension (width or height) thumbnail we will generate.
@@ -254,47 +258,38 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
return destImage;
}
- ///
- public void Initialize(IStream pstream, uint grfMode)
+ ///
+ /// Generate thumbnail bitmap for provided Gcode file/stream.
+ ///
+ /// Maximum thumbnail size, in pixels.
+ /// Generated bitmap
+ public Bitmap GetThumbnail(uint cx)
{
- // Ignore the grfMode always use read mode to access the file.
- this.Stream = pstream;
- }
-
- ///
- public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha)
- {
- phbmp = IntPtr.Zero;
- pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN;
-
if (cx == 0 || cx > MaxThumbnailSize)
{
- return;
+ return null;
}
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredSvgThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// GPO is disabling this utility.
- return;
+ return null;
}
string svgData = null;
- using (var stream = new ReadonlyStream(this.Stream as IStream))
+ using (var reader = new StreamReader(this.Stream))
{
- using (var reader = new StreamReader(stream))
+ svgData = reader.ReadToEnd();
+ try
+ {
+ // Fixes #17527 - Inkscape v1.1 swapped order of default and svg namespaces in svg file (default first, svg after).
+ // That resulted in parser being unable to parse it correctly and instead of svg, text was previewed.
+ // MS Edge and Firefox also couldn't preview svg files with mentioned order of namespaces definitions.
+ svgData = SvgPreviewHandlerHelper.SwapNamespaces(svgData);
+ svgData = SvgPreviewHandlerHelper.AddStyleSVG(svgData);
+ }
+ catch (Exception)
{
- svgData = reader.ReadToEnd();
- try
- {
- // Fixes #17527 - Inkscape v1.1 swapped order of default and svg namespaces in svg file (default first, svg after).
- // That resulted in parser being unable to parse it correctly and instead of svg, text was previewed.
- // MS Edge and Firefox also couldn't preview svg files with mentioned order of namespaces definitions.
- svgData = SvgPreviewHandlerHelper.SwapNamespaces(svgData);
- svgData = SvgPreviewHandlerHelper.AddStyleSVG(svgData);
- }
- catch (Exception)
- {
- }
}
}
@@ -304,11 +299,12 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
{
if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
{
- phbmp = thumbnail.GetHbitmap();
- pdwAlpha = WTS_ALPHATYPE.WTSAT_RGB;
+ return (Bitmap)thumbnail.Clone();
}
}
}
+
+ return null;
}
public void Dispose()
diff --git a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj
index ac78934152..d3f3a9cb98 100644
--- a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj
+++ b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj
@@ -1,5 +1,6 @@
+ enable
true
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}
Microsoft.PowerToys.ThumbnailHandler.Svg
@@ -7,7 +8,6 @@
PowerToys.SvgThumbnailProvider
PowerToys SvgPreviewHandler
net7.0-windows10.0.19041.0
- true
true
PowerToys SvgPreviewHandler
..\..\..\..\$(Platform)\$(Configuration)\modules\FileExplorerPreview\
@@ -16,6 +16,15 @@
false
true
win10-x64;win10-arm64
+ true
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
@@ -29,6 +38,7 @@
$(NoWarn);1591
+ WinExe
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/ClassFactory.cpp b/src/modules/previewpane/SvgThumbnailProviderCpp/ClassFactory.cpp
new file mode 100644
index 0000000000..bf8dc9250d
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/ClassFactory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+#include "ClassFactory.h"
+#include "SvgThumbnailProvider.h"
+
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() :
+ m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+//
+// IUnknown
+//
+
+IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(ClassFactory, IClassFactory),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG) ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//
+// IClassFactory
+//
+
+IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ if (pUnkOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ SvgThumbnailProvider* pExt = new (std::nothrow) SvgThumbnailProvider();
+ if (pExt)
+ {
+ hr = pExt->QueryInterface(riid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/ClassFactory.h b/src/modules/previewpane/SvgThumbnailProviderCpp/ClassFactory.h
new file mode 100644
index 0000000000..b393c3916e
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/ClassFactory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class ClassFactory : public IClassFactory
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv);
+ IFACEMETHODIMP LockServer(BOOL fLock);
+
+ ClassFactory();
+
+protected:
+ ~ClassFactory();
+
+private:
+ long m_cRef;
+};
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/GlobalExportFunctions.def b/src/modules/previewpane/SvgThumbnailProviderCpp/GlobalExportFunctions.def
new file mode 100644
index 0000000000..76fc66cac3
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/GlobalExportFunctions.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProvider.cpp b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProvider.cpp
new file mode 100644
index 0000000000..0f42b32f3b
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProvider.cpp
@@ -0,0 +1,181 @@
+#include "pch.h"
+#include "SvgThumbnailProvider.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+SvgThumbnailProvider::SvgThumbnailProvider() :
+ m_cRef(1), m_pStream(NULL), m_process(NULL)
+{
+ std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
+ logFilePath.append(LogSettings::svgThumbLogPath);
+ Logger::init(LogSettings::svgThumbLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ InterlockedIncrement(&g_cDllRef);
+}
+
+SvgThumbnailProvider::~SvgThumbnailProvider()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+#pragma region IUnknown
+
+IFACEMETHODIMP SvgThumbnailProvider::QueryInterface(REFIID riid, void** ppv)
+{
+ static const QITAB qit[] = {
+ QITABENT(SvgThumbnailProvider, IThumbnailProvider),
+ QITABENT(SvgThumbnailProvider, IInitializeWithStream),
+ { 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+}
+
+IFACEMETHODIMP_(ULONG)
+SvgThumbnailProvider::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+IFACEMETHODIMP_(ULONG)
+SvgThumbnailProvider::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+#pragma endregion
+
+#pragma region IInitializationWithStream
+
+IFACEMETHODIMP SvgThumbnailProvider::Initialize(IStream* pStream, DWORD grfMode)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (pStream)
+ {
+ // Initialize can be called more than once, so release existing valid
+ // m_pStream.
+ if (m_pStream)
+ {
+ m_pStream->Release();
+ m_pStream = NULL;
+ }
+
+ m_pStream = pStream;
+ m_pStream->AddRef();
+ hr = S_OK;
+ }
+ return hr;
+}
+
+#pragma endregion
+
+#pragma region IThumbnailProvider
+
+IFACEMETHODIMP SvgThumbnailProvider::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
+{
+ // Read stream into the buffer
+ char buffer[4096];
+ ULONG cbRead;
+
+ Logger::trace(L"Begin");
+
+ GUID guid;
+ if (CoCreateGuid(&guid) == S_OK)
+ {
+ wil::unique_cotaskmem_string guidString;
+ if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
+ {
+ Logger::info(L"Read stream and save to tmp file.");
+
+ // {CLSID} -> CLSID
+ std::wstring guid = std::wstring(guidString.get()).substr(1, std::wstring(guidString.get()).size() - 2);
+ std::wstring filePath = PTSettingsHelper::get_local_low_folder_location() + L"\\SvgThumbnailPreview-Temp\\";
+ if (!std::filesystem::exists(filePath))
+ {
+ std::filesystem::create_directories(filePath);
+ }
+
+ std::wstring fileName = filePath + guid + L".svg";
+
+ // Write data to tmp file
+ std::fstream file;
+ file.open(fileName, std::ios_base::out | std::ios_base::binary);
+
+ if (!file.is_open())
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ auto result = m_pStream->Read(buffer, 4096, &cbRead);
+
+ file.write(buffer, cbRead);
+ if (result == S_FALSE)
+ {
+ break;
+ }
+ }
+ file.close();
+
+ try
+ {
+ Logger::info(L"Start SvgThumbnailProvider.exe");
+
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring cmdLine{ L"\"" + fileName + L"\"" };
+ cmdLine += L" ";
+ cmdLine += std::to_wstring(cx);
+
+ std::wstring appPath = get_module_folderpath(g_hInst) + L"\\PowerToys.SvgThumbnailProvider.exe";
+
+ SHELLEXECUTEINFO sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = appPath.c_str();
+ sei.lpParameters = cmdLine.c_str();
+ sei.nShow = SW_SHOWDEFAULT;
+ ShellExecuteEx(&sei);
+ m_process = sei.hProcess;
+ WaitForSingleObject(m_process, INFINITE);
+ std::filesystem::remove(fileName);
+
+ std::wstring fileNameBmp = filePath + guid + L".bmp";
+ *phbmp = (HBITMAP)LoadImage(NULL, fileNameBmp.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
+ *pdwAlpha = WTS_ALPHATYPE::WTSAT_ARGB;
+
+ std::filesystem::remove(fileNameBmp);
+ }
+ catch (std::exception& e)
+ {
+ std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
+ Logger::error(L"Failed to start SvgThumbnailProvider.exe. Error: {}", errorMessage);
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+#pragma endregion
+
+#pragma region Helper Functions
+
+#pragma endregion
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProvider.h b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProvider.h
new file mode 100644
index 0000000000..3c8a7f1b9c
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProvider.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+#include
+
+class SvgThumbnailProvider :
+ public IInitializeWithStream,
+ public IThumbnailProvider
+{
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IInitializeWithStream
+ IFACEMETHODIMP Initialize(IStream* pstream, DWORD grfMode);
+
+ // IPreviewHandler
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
+
+ SvgThumbnailProvider();
+protected:
+ ~SvgThumbnailProvider();
+
+private:
+ // Reference count of component.
+ long m_cRef;
+
+ // Provided during initialization.
+ IStream* m_pStream;
+
+ HANDLE m_process;
+};
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.rc b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.rc
new file mode 100644
index 0000000000..5fa3c8b90d
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj
new file mode 100644
index 0000000000..060e178785
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj
@@ -0,0 +1,121 @@
+
+
+
+
+ 16.0
+ Win32Proj
+ {2bbc9e33-21ec-401c-84da-bb6590a9b2aa}
+ SvgThumbnailProviderCpp
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+
+
+ PowerToys.$(ProjectName)
+
+
+
+ Level3
+ true
+ _DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ ../../..
+
+
+ Windows
+ true
+ true
+ true
+ false
+ GlobalExportFunctions.def
+ Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj.filters b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj.filters
new file mode 100644
index 0000000000..67f21bfdc2
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj.filters
@@ -0,0 +1,59 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Resource Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/dllmain.cpp b/src/modules/previewpane/SvgThumbnailProviderCpp/dllmain.cpp
new file mode 100644
index 0000000000..69748f2ce9
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/dllmain.cpp
@@ -0,0 +1,73 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+#include "ClassFactory.h"
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// {10144713-1526-46C9-88DA-1FB52807A9FF}
+static const GUID CLSID_SvgThumbnailProvider = { 0x10144713, 0x1526, 0x46c9, { 0x88, 0xda, 0x1f, 0xb5, 0x28, 0x7, 0xa9, 0xff } };
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst = hModule;
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+//
+// FUNCTION: DllGetClassObject
+//
+// PURPOSE: Create the class factory and query to the specific interface.
+//
+// PARAMETERS:
+// * rclsid - The CLSID that will associate the correct data and code.
+// * riid - A reference to the identifier of the interface that the caller
+// is to use to communicate with the class object.
+// * ppv - The address of a pointer variable that receives the interface
+// pointer requested in riid. Upon successful return, *ppv contains the
+// requested interface pointer. If an error occurs, the interface pointer
+// is NULL.
+//
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if (IsEqualCLSID(CLSID_SvgThumbnailProvider, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+
+ ClassFactory* pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: DllCanUnloadNow
+//
+// PURPOSE: Check if we can unload the component from the memory.
+//
+// NOTE: The component can be unloaded from the memory when its reference
+// count is zero (i.e. nobody is still using the component).
+//
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/packages.config b/src/modules/previewpane/SvgThumbnailProviderCpp/packages.config
new file mode 100644
index 0000000000..c92dd4bf0c
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/pch.cpp b/src/modules/previewpane/SvgThumbnailProviderCpp/pch.cpp
new file mode 100644
index 0000000000..64b7eef6d6
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/pch.cpp
@@ -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.
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/pch.h b/src/modules/previewpane/SvgThumbnailProviderCpp/pch.h
new file mode 100644
index 0000000000..125ddcdf24
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/pch.h
@@ -0,0 +1,14 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#endif //PCH_H
diff --git a/src/modules/previewpane/SvgThumbnailProviderCpp/resource.h b/src/modules/previewpane/SvgThumbnailProviderCpp/resource.h
new file mode 100644
index 0000000000..9c56b472ed
--- /dev/null
+++ b/src/modules/previewpane/SvgThumbnailProviderCpp/resource.h
@@ -0,0 +1,13 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by AlwaysOnTopModuleInterface.rc
+
+//////////////////////////////
+// Non-localizable
+
+#define FILE_DESCRIPTION "PowerToys Svg Thumbnail Provider Module"
+#define INTERNAL_NAME "PowerToys.SvgThumbnailProviderCpp"
+#define ORIGINAL_FILENAME "PowerToys.SvgThumbnailProviderCpp.dll"
+
+// Non-localizable
+//////////////////////////////
diff --git a/src/modules/previewpane/UnitTests-GcodeThumbnailProvider/GcodeThumbnailProviderTests.cs b/src/modules/previewpane/UnitTests-GcodeThumbnailProvider/GcodeThumbnailProviderTests.cs
index 5bce85ff7d..38f0829e74 100644
--- a/src/modules/previewpane/UnitTests-GcodeThumbnailProvider/GcodeThumbnailProviderTests.cs
+++ b/src/modules/previewpane/UnitTests-GcodeThumbnailProvider/GcodeThumbnailProviderTests.cs
@@ -22,48 +22,39 @@ namespace GcodeThumbnailProviderUnitTests
public void GetThumbnailValidStreamGcode()
{
// Act
- var file = File.ReadAllBytes("HelperFiles/sample.gcode");
+ var filePath = "HelperFiles/sample.gcode";
- GcodeThumbnailProvider provider = new GcodeThumbnailProvider();
+ GcodeThumbnailProvider provider = new GcodeThumbnailProvider(filePath);
- provider.Initialize(GetMockStream(file), 0);
+ Bitmap bitmap = provider.GetThumbnail(256);
- provider.GetThumbnail(256, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
-
- Assert.IsTrue(bitmap != IntPtr.Zero);
- Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_ARGB);
+ Assert.IsTrue(bitmap != null);
}
[TestMethod]
public void GetThumbnailInValidSizeGcode()
{
// Act
- var file = File.ReadAllBytes("HelperFiles/sample.gcode");
+ var filePath = "HelperFiles/sample.gcode";
- GcodeThumbnailProvider provider = new GcodeThumbnailProvider();
+ GcodeThumbnailProvider provider = new GcodeThumbnailProvider(filePath);
- provider.Initialize(GetMockStream(file), 0);
+ Bitmap bitmap = provider.GetThumbnail(0);
- provider.GetThumbnail(0, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
-
- Assert.IsTrue(bitmap == IntPtr.Zero);
- Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN);
+ Assert.IsTrue(bitmap == null);
}
[TestMethod]
public void GetThumbnailToBigGcode()
{
// Act
- var file = File.ReadAllBytes("HelperFiles/sample.gcode");
+ var filePath = "HelperFiles/sample.gcode";
- GcodeThumbnailProvider provider = new GcodeThumbnailProvider();
+ GcodeThumbnailProvider provider = new GcodeThumbnailProvider(filePath);
- provider.Initialize(GetMockStream(file), 0);
+ Bitmap bitmap = provider.GetThumbnail(10001);
- provider.GetThumbnail(10001, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
-
- Assert.IsTrue(bitmap == IntPtr.Zero);
- Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN);
+ Assert.IsTrue(bitmap == null);
}
[TestMethod]
@@ -82,30 +73,5 @@ namespace GcodeThumbnailProviderUnitTests
Bitmap thumbnail = GcodeThumbnailProvider.GetThumbnail(null, 256);
Assert.IsTrue(thumbnail == null);
}
-
- private static IStream GetMockStream(byte[] sourceArray)
- {
- var streamMock = new Mock();
- int bytesRead = 0;
-
- streamMock
- .Setup(x => x.Read(It.IsAny(), It.IsAny(), It.IsAny()))
- .Callback((buffer, countToRead, bytesReadPtr) =>
- {
- int actualCountToRead = Math.Min(sourceArray.Length - bytesRead, countToRead);
- if (actualCountToRead > 0)
- {
- Array.Copy(sourceArray, bytesRead, buffer, 0, actualCountToRead);
- Marshal.WriteInt32(bytesReadPtr, actualCountToRead);
- bytesRead += actualCountToRead;
- }
- else
- {
- Marshal.WriteInt32(bytesReadPtr, 0);
- }
- });
-
- return streamMock.Object;
- }
}
}
diff --git a/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs
index 969943c03d..a406c89ff5 100644
--- a/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs
+++ b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
@@ -21,73 +22,39 @@ namespace PdfThumbnailProviderUnitTests
public void GetThumbnailValidStreamPDF()
{
// Act
- var file = File.ReadAllBytes("HelperFiles/sample.pdf");
+ var filePath = "HelperFiles/sample.pdf";
- PdfThumbnailProvider provider = new PdfThumbnailProvider();
+ PdfThumbnailProvider provider = new PdfThumbnailProvider(filePath);
- provider.Initialize(GetMockStream(file), 0);
+ Bitmap bitmap = provider.GetThumbnail(256);
- provider.GetThumbnail(256, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
-
- Assert.IsTrue(bitmap != IntPtr.Zero);
- Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_RGB);
+ Assert.IsTrue(bitmap != null);
}
[TestMethod]
public void GetThumbnailInValidSizePDF()
{
// Act
- var file = File.ReadAllBytes("HelperFiles/sample.pdf");
+ var filePath = "HelperFiles/sample.pdf";
- PdfThumbnailProvider provider = new PdfThumbnailProvider();
+ PdfThumbnailProvider provider = new PdfThumbnailProvider(filePath);
- provider.Initialize(GetMockStream(file), 0);
+ Bitmap bitmap = provider.GetThumbnail(0);
- provider.GetThumbnail(0, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
-
- Assert.IsTrue(bitmap == IntPtr.Zero);
- Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN);
+ Assert.IsTrue(bitmap == null);
}
[TestMethod]
public void GetThumbnailToBigPDF()
{
// Act
- var file = File.ReadAllBytes("HelperFiles/sample.pdf");
+ var filePath = "HelperFiles/sample.pdf";
- PdfThumbnailProvider provider = new PdfThumbnailProvider();
+ PdfThumbnailProvider provider = new PdfThumbnailProvider(filePath);
- provider.Initialize(GetMockStream(file), 0);
+ Bitmap bitmap = provider.GetThumbnail(10001);
- provider.GetThumbnail(10001, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
-
- Assert.IsTrue(bitmap == IntPtr.Zero);
- Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN);
- }
-
- private static IStream GetMockStream(byte[] sourceArray)
- {
- var streamMock = new Mock();
- int bytesRead = 0;
-
- streamMock
- .Setup(x => x.Read(It.IsAny(), It.IsAny(), It.IsAny()))
- .Callback((buffer, countToRead, bytesReadPtr) =>
- {
- int actualCountToRead = Math.Min(sourceArray.Length - bytesRead, countToRead);
- if (actualCountToRead > 0)
- {
- Array.Copy(sourceArray, bytesRead, buffer, 0, actualCountToRead);
- Marshal.WriteInt32(bytesReadPtr, actualCountToRead);
- bytesRead += actualCountToRead;
- }
- else
- {
- Marshal.WriteInt32(bytesReadPtr, 0);
- }
- });
-
- return streamMock.Object;
+ Assert.IsTrue(bitmap == null);
}
}
}
diff --git a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FileBasedPreviewHandlerTests.cs b/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FileBasedPreviewHandlerTests.cs
deleted file mode 100644
index 12a854ee49..0000000000
--- a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FileBasedPreviewHandlerTests.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-
-namespace PreviewHandlerCommonUnitTests
-{
- [TestClass]
- public class FileBasedPreviewHandlerTests
- {
- internal class TestFileBasedPreviewHandler : FileBasedPreviewHandler
- {
- public override void DoPreview()
- {
- throw new NotImplementedException();
- }
-
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- return new Mock().Object;
- }
- }
-
- [DataTestMethod]
- [DataRow(0U)]
- [DataRow(1U)]
- public void FileBasedPreviewHandlerShouldSetFilePathWhenInitializeCalled(uint grfMode)
- {
- // Arrange
- var fileBasedPreviewHandler = new TestFileBasedPreviewHandler();
- var filePath = "C:\\valid-path";
-
- // Act
- fileBasedPreviewHandler.Initialize(filePath, grfMode);
-
- // Assert
- Assert.AreEqual(filePath, fileBasedPreviewHandler.FilePath);
- }
- }
-}
diff --git a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FormHandlerControlTests.cs b/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FormHandlerControlTests.cs
index 0f645ec430..b1fd46d5bc 100644
--- a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FormHandlerControlTests.cs
+++ b/src/modules/previewpane/UnitTests-PreviewHandlerCommon/FormHandlerControlTests.cs
@@ -97,22 +97,6 @@ namespace PreviewHandlerCommonUnitTests
}
}
- [TestMethod]
- public void FormHandlerControlShouldUpdateBoundsWhenSetRectCalled()
- {
- // Arrange
- using (var testFormHandlerControl = new TestFormControl())
- {
- var bounds = new Rectangle(2, 2, 4, 4);
-
- // Act
- testFormHandlerControl.SetRect(bounds);
-
- // Assert
- Assert.AreEqual(bounds, testFormHandlerControl.Bounds);
- }
- }
-
[TestMethod]
public void FormHandlerControlShouldSetTextColorWhenSetTextColorCalled()
{
diff --git a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/PreviewHandlerBaseTests.cs b/src/modules/previewpane/UnitTests-PreviewHandlerCommon/PreviewHandlerBaseTests.cs
deleted file mode 100644
index 63dc505c5a..0000000000
--- a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/PreviewHandlerBaseTests.cs
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using Common;
-using Common.ComInterlop;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-
-namespace PreviewHandlerCommonUnitTests
-{
- [TestClass]
- public class PreviewHandlerBaseTests
- {
- private static IPreviewHandlerControl previewHandlerControl;
-
- internal class TestPreviewHandler : PreviewHandlerBase
- {
- public TestPreviewHandler()
- {
- Initialize();
- }
-
- public override void DoPreview()
- {
- throw new NotImplementedException();
- }
-
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- return GetMockPreviewHandlerControl();
- }
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlSetWindowWhenSetWindowCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
- var handle = new IntPtr(5);
- var bounds = GetRectangle(2, 2, 4, 4);
-
- var actualHandle = IntPtr.Zero;
- var actualBounds = Rectangle.Empty;
- mockPreviewControl
- .Setup(_ => _.SetWindow(It.IsAny(), It.IsAny()))
- .Callback((hwnd, rect) =>
- {
- actualHandle = hwnd;
- actualBounds = rect;
- });
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
-
- // Act
- testPreviewHandler.SetWindow(handle, ref bounds);
-
- // Assert
- Assert.AreEqual(actualHandle, handle);
- Assert.AreEqual(actualBounds, bounds.ToRectangle());
- mockPreviewControl.Verify(_ => _.SetWindow(It.IsAny(), It.IsAny()), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlSetrectWhenSetRectCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
- var bounds = GetRectangle(2, 2, 4, 4);
-
- var actualBounds = Rectangle.Empty;
- mockPreviewControl
- .Setup(_ => _.SetRect(It.IsAny()))
- .Callback((rect) =>
- {
- actualBounds = rect;
- });
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
-
- // Act
- testPreviewHandler.SetRect(ref bounds);
-
- // Assert
- Assert.AreEqual(actualBounds, bounds.ToRectangle());
- mockPreviewControl.Verify(_ => _.SetRect(It.IsAny()), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlUnloadWhenUnloadCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
-
- // Act
- testPreviewHandler.Unload();
-
- // Assert
- mockPreviewControl.Verify(_ => _.Unload(), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlSetBackgroundColorWhenSetBackgroundColorCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- var color = default(COLORREF);
-
- // Act
- testPreviewHandler.SetBackgroundColor(color);
-
- // Assert
- mockPreviewControl.Verify(_ => _.SetBackgroundColor(It.Is(c => (c == color.Color))), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlSetTextColorWhenSetTextColorCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- var color = default(COLORREF);
-
- // Act
- testPreviewHandler.SetTextColor(color);
-
- // Assert
- mockPreviewControl.Verify(_ => _.SetTextColor(It.Is(c => (c == color.Color))), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlSetFontWhenSetFontCalled()
- {
- // Arrange
- Font actualFont = null;
- var mockPreviewControl = new Mock();
- mockPreviewControl
- .Setup(x => x.SetFont(It.IsAny()))
- .Callback((font) =>
- {
- actualFont = font;
- });
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- var logFont = GetLogFont();
-
- // Act
- testPreviewHandler.SetFont(ref logFont);
-
- // Assert
- mockPreviewControl.Verify(_ => _.SetFont(It.IsAny()), Times.Once);
- Assert.AreEqual(Font.FromLogFont(logFont), actualFont);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldCallPreviewControlSetFocusWhenSetFocusCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
-
- // Act
- testPreviewHandler.SetFocus();
-
- // Assert
- mockPreviewControl.Verify(_ => _.SetFocus(), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldSetHandleOnQueryFocusWhenPreviewControlsReturnValidHandle()
- {
- // Arrange
- var hwnd = new IntPtr(5);
- var mockPreviewControl = new Mock();
- mockPreviewControl.Setup(x => x.QueryFocus(out hwnd));
- var actualHwnd = IntPtr.Zero;
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
-
- // Act
- testPreviewHandler.QueryFocus(out actualHwnd);
-
- // Assert
- Assert.AreEqual(actualHwnd, hwnd);
- mockPreviewControl.Verify(_ => _.QueryFocus(out hwnd), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldThrowOnQueryFocusWhenPreviewControlsReturnNotValidHandle()
- {
- // Arrange
- var hwnd = IntPtr.Zero;
- var mockPreviewControl = new Mock();
- mockPreviewControl.Setup(x => x.QueryFocus(out hwnd));
- var actualHwnd = IntPtr.Zero;
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- Win32Exception exception = null;
-
- // Act
- try
- {
- testPreviewHandler.QueryFocus(out actualHwnd);
- }
- catch (Win32Exception ex)
- {
- exception = ex;
- }
-
- // Assert
- Assert.IsNotNull(exception);
- mockPreviewControl.Verify(_ => _.QueryFocus(out hwnd), Times.Once);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldDirectKeyStrokesToIPreviewHandlerFrameIfIPreviewHandlerFrameIsSet()
- {
- // Arrange
- var mockPreviewControl = new Mock();
- var mockPreviewHandlerFrame = new Mock();
- var msg = default(MSG);
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- testPreviewHandler.SetSite(mockPreviewHandlerFrame.Object);
-
- // Act
- testPreviewHandler.TranslateAccelerator(ref msg);
-
- // Assert
- mockPreviewHandlerFrame.Verify(_ => _.TranslateAccelerator(ref msg), Times.Once);
- }
-
- [DataTestMethod]
- [DataRow(0U)]
- [DataRow(1U)]
- public void PreviewHandlerBaseShouldReturnIPreviewHandlerFrameResponseIfIPreviewHandlerFrameIsSet(uint resultCode)
- {
- // Arrange
- var mockPreviewControl = new Mock();
- var mockPreviewHandlerFrame = new Mock();
- var msg = default(MSG);
- mockPreviewHandlerFrame
- .Setup(x => x.TranslateAccelerator(ref msg))
- .Returns(resultCode);
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- testPreviewHandler.SetSite(mockPreviewHandlerFrame.Object);
-
- // Act
- var actualResultCode = testPreviewHandler.TranslateAccelerator(ref msg);
-
- // Assert
- Assert.AreEqual(resultCode, actualResultCode);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldReturnUintFalseIfIPreviewHandlerFrameIsNotSet()
- {
- // Arrange
- var mockPreviewControl = new Mock();
- var msg = default(MSG);
- uint sFalse = 1;
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
-
- // Act
- var result = testPreviewHandler.TranslateAccelerator(ref msg);
-
- // Assert
- Assert.AreEqual(result, sFalse);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldReturnPreviewControlHandleIfGetWindowCalled()
- {
- // Arrange
- var previewControlHandle = new IntPtr(5);
- var mockPreviewControl = new Mock();
- mockPreviewControl.Setup(x => x.GetWindowHandle())
- .Returns(previewControlHandle);
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- var hwndReceived = IntPtr.Zero;
-
- // Act
- testPreviewHandler.GetWindow(out hwndReceived);
-
- // Assert
- Assert.AreEqual(hwndReceived, previewControlHandle);
- }
-
- [DataTestMethod]
- [DataRow(true)]
- [DataRow(false)]
- public void PreviewHandlerBaseShouldThrowNotImplementedExceptionIfContextSensitiveHelpCalled(bool fEnterMode)
- {
- // Arrange
- var mockPreviewControl = new Mock();
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- NotImplementedException exception = null;
-
- // Act
- try
- {
- testPreviewHandler.ContextSensitiveHelp(fEnterMode);
- }
- catch (NotImplementedException ex)
- {
- exception = ex;
- }
-
- // Assert
- Assert.IsNotNull(exception);
- }
-
- [TestMethod]
- public void PreviewHandlerBaseShouldReturnSiteWhenGetSiteCalled()
- {
- // Arrange
- var mockPreviewControl = new Mock();
-
- previewHandlerControl = mockPreviewControl.Object;
- var testPreviewHandler = new TestPreviewHandler();
- var site = new Mock().Object;
- testPreviewHandler.SetSite(site);
- var riid = Guid.Empty;
-
- // Act
- testPreviewHandler.GetSite(ref riid, out object actualSite);
-
- // Assert
- Assert.AreEqual(actualSite, site);
- }
-
- private static LOGFONT GetLogFont()
- {
- return new LOGFONT
- {
- LfHeight = 12,
- LfWidth = 0,
- LfEscapement = 0,
- LfWeight = 400, // FW_NORMAL
- LfItalic = Convert.ToByte(false),
- LfUnderline = Convert.ToByte(false),
- LfStrikeOut = Convert.ToByte(0),
- LfCharSet = Convert.ToByte(0), // ANSI_CHARSET
- LfOutPrecision = Convert.ToByte(0), // OUT_DEFAULT_PRECIS
- LfClipPrecision = Convert.ToByte(0),
- LfQuality = Convert.ToByte(0),
- LfPitchAndFamily = Convert.ToByte(0),
- LfFaceName = "valid-font",
- };
- }
-
- private static RECT GetRectangle(int left, int top, int right, int bottom)
- {
- return new RECT
- {
- Left = left,
- Top = top,
- Right = right,
- Bottom = bottom,
- };
- }
-
- private static IPreviewHandlerControl GetMockPreviewHandlerControl()
- {
- return previewHandlerControl;
- }
- }
-}
diff --git a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/StreamBasedPreviewHandlerTests.cs b/src/modules/previewpane/UnitTests-PreviewHandlerCommon/StreamBasedPreviewHandlerTests.cs
deleted file mode 100644
index 583947be21..0000000000
--- a/src/modules/previewpane/UnitTests-PreviewHandlerCommon/StreamBasedPreviewHandlerTests.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices.ComTypes;
-using Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-
-namespace PreviewHandlerCommonUnitTests
-{
- [TestClass]
- public class StreamBasedPreviewHandlerTests
- {
- internal class TestStreamBasedPreviewHandler : StreamBasedPreviewHandler
- {
- public override void DoPreview()
- {
- throw new NotImplementedException();
- }
-
- protected override IPreviewHandlerControl CreatePreviewHandlerControl()
- {
- return new Mock