mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-23 19:49:17 +08:00
[FileExplorer]Add QoiThumbnailProvider and QoiPreviewHandler (#29735)
* [FileExplorer]QoiThumbnailProvider * Corrects code documentation * Adds QoiPreviewHandler * Corrects GUIDs * Ensure returned thumbnail image is 32bit ARGB * Updates following review comments * More updates following review comments * Updates following PR comments * Fix dark theme background in QoiPreviewHandler * Updates attribution text
This commit is contained in:
parent
9d2f9bcff2
commit
0990724e44
@ -73,6 +73,12 @@
|
||||
"PowerToys.PdfThumbnailProviderCpp.dll",
|
||||
"PowerToys.powerpreview.dll",
|
||||
"PowerToys.PreviewHandlerCommon.dll",
|
||||
"PowerToys.QoiPreviewHandler.dll",
|
||||
"PowerToys.QoiPreviewHandler.exe",
|
||||
"PowerToys.QoiPreviewHandlerCpp.dll",
|
||||
"PowerToys.QoiThumbnailProvider.dll",
|
||||
"PowerToys.QoiThumbnailProvider.exe",
|
||||
"PowerToys.QoiThumbnailProviderCpp.dll",
|
||||
"PowerToys.StlThumbnailProvider.dll",
|
||||
"PowerToys.StlThumbnailProvider.exe",
|
||||
"PowerToys.StlThumbnailProviderCpp.dll",
|
||||
|
@ -195,8 +195,10 @@ steps:
|
||||
**\UnitTests-GcodeThumbnailProvider.dll
|
||||
**\UnitTests-StlThumbnailProvider.dll
|
||||
**\UnitTests-PdfThumbnailProvider.dll
|
||||
**\UnitTests-QoiThumbnailProvider.dll
|
||||
**\Settings.UI.UnitTests.dll
|
||||
**\UnitTests-GcodePreviewHandler.dll
|
||||
**\UnitTests-QoiPreviewHandler.dll
|
||||
**\UnitTests-FancyZonesEditor.dll
|
||||
**\UnitTests-PdfPreviewHandler.dll
|
||||
**\UnitTests-PreviewHandlerCommon.dll
|
||||
|
@ -538,7 +538,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLock", "src\modules\
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLockModuleInterface", "src\modules\CropAndLock\CropAndLockModuleInterface\CropAndLockModuleInterface.vcxproj", "{3157FA75-86CF-4EE2-8F62-C43F776493C6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests-FancyZonesEditor", "src\modules\fancyzones\UnitTests-FancyZonesEditor\UnitTests-FancyZonesEditor.csproj", "{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-FancyZonesEditor", "src\modules\fancyzones\UnitTests-FancyZonesEditor\UnitTests-FancyZonesEditor.csproj", "{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvironmentVariables", "EnvironmentVariables", "{538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}"
|
||||
EndProject
|
||||
@ -546,6 +546,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvironmentVariables", "src
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EnvironmentVariablesModuleInterface", "src\modules\EnvironmentVariables\EnvironmentVariablesModuleInterface\EnvironmentVariablesModuleInterface.vcxproj", "{B9420661-B0E4-4241-ABD4-4A27A1F64250}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QoiThumbnailProviderCpp", "src\modules\previewpane\QoiThumbnailProviderCpp\QoiThumbnailProviderCpp.vcxproj", "{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QoiThumbnailProvider", "src\modules\previewpane\QoiThumbnailProvider\QoiThumbnailProvider.csproj", "{D949EC7D-48A9-4279-95D5-078E7FD1F048}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QoiPreviewHandlerCpp", "src\modules\previewpane\QoiPreviewHandlerCpp\QoiPreviewHandlerCpp.vcxproj", "{3BAF9C81-A194-4925-A035-5E24A5D1E542}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QoiPreviewHandler", "src\modules\previewpane\QoiPreviewHandler\QoiPreviewHandler.csproj", "{6B04803D-B418-4833-A67E-B0FC966636A5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-QoiPreviewHandler", "src\modules\previewpane\UnitTests-QoiPreviewHandler\UnitTests-QoiPreviewHandler.csproj", "{3940AD4D-F748-4BE4-9083-85769CD553EF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-QoiThumbnailProvider", "src\modules\previewpane\UnitTests-QoiThumbnailProvider\UnitTests-QoiThumbnailProvider.csproj", "{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@ -2352,6 +2364,78 @@ Global
|
||||
{B9420661-B0E4-4241-ABD4-4A27A1F64250}.Release|x64.Build.0 = Release|x64
|
||||
{B9420661-B0E4-4241-ABD4-4A27A1F64250}.Release|x86.ActiveCfg = Release|x64
|
||||
{B9420661-B0E4-4241-ABD4-4A27A1F64250}.Release|x86.Build.0 = Release|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Debug|x64.Build.0 = Debug|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Debug|x86.Build.0 = Debug|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Release|x64.ActiveCfg = Release|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Release|x64.Build.0 = Release|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Release|x86.ActiveCfg = Release|x64
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}.Release|x86.Build.0 = Release|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Debug|x64.Build.0 = Debug|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Debug|x86.Build.0 = Debug|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Release|x64.ActiveCfg = Release|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Release|x64.Build.0 = Release|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Release|x86.ActiveCfg = Release|x64
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048}.Release|x86.Build.0 = Release|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Debug|x64.Build.0 = Debug|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Debug|x86.Build.0 = Debug|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Release|x64.ActiveCfg = Release|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Release|x64.Build.0 = Release|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Release|x86.ActiveCfg = Release|x64
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542}.Release|x86.Build.0 = Release|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Debug|x64.Build.0 = Debug|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Debug|x86.Build.0 = Debug|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Release|x64.ActiveCfg = Release|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Release|x64.Build.0 = Release|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Release|x86.ActiveCfg = Release|x64
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5}.Release|x86.Build.0 = Release|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Debug|x64.Build.0 = Debug|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Debug|x86.Build.0 = Debug|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Release|x64.ActiveCfg = Release|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Release|x64.Build.0 = Release|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Release|x86.ActiveCfg = Release|x64
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF}.Release|x86.Build.0 = Release|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Debug|x64.Build.0 = Debug|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Debug|x86.Build.0 = Debug|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x64.ActiveCfg = Release|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x64.Build.0 = Release|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x86.ActiveCfg = Release|x64
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -2550,6 +2634,12 @@ Global
|
||||
{538ED0BB-B863-4B20-98CC-BCDF7FA0B68A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}
|
||||
{B9420661-B0E4-4241-ABD4-4A27A1F64250} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}
|
||||
{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{D949EC7D-48A9-4279-95D5-078E7FD1F048} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{3BAF9C81-A194-4925-A035-5E24A5D1E542} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{6B04803D-B418-4833-A67E-B0FC966636A5} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{3940AD4D-F748-4BE4-9083-85769CD553EF} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -402,6 +402,15 @@
|
||||
</RegistryKey>
|
||||
<File Id="Launcher_ValueGenerator_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)RunPlugins\ValueGenerator\$(var.Language)\Community.PowerToys.Run.Plugin.ValueGenerator.resources.dll" />
|
||||
</Component>
|
||||
<Component
|
||||
Id="QoiPreviewHandler_$(var.IdSafeLanguage)_Component"
|
||||
Directory="Resource$(var.IdSafeLanguage)INSTALLFOLDER"
|
||||
Guid="$(var.CompGUIDPrefix)1E">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="QoiPreviewHandler_$(var.IdSafeLanguage)_Component" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Id="QoiPreviewHandler_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)\$(var.Language)\PowerToys.QoiPreviewHandler.resources.dll" />
|
||||
</Component>
|
||||
<?undef IdSafeLanguage?>
|
||||
<?undef CompGUIDPrefix?>
|
||||
<?endforeach?>
|
||||
|
@ -1005,7 +1005,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
}
|
||||
processes.resize(bytes / sizeof(processes[0]));
|
||||
|
||||
std::array<std::wstring_view, 29> processesToTerminate = {
|
||||
std::array<std::wstring_view, 31> processesToTerminate = {
|
||||
L"PowerToys.PowerLauncher.exe",
|
||||
L"PowerToys.Settings.exe",
|
||||
L"PowerToys.Awake.exe",
|
||||
@ -1026,7 +1026,9 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
L"PowerToys.StlThumbnailProvider.exe",
|
||||
L"PowerToys.SvgThumbnailProvider.exe",
|
||||
L"PowerToys.GcodePreviewHandler.exe",
|
||||
L"PowerToys.QoiPreviewHandler.exe",
|
||||
L"PowerToys.PdfPreviewHandler.exe",
|
||||
L"PowerToys.QoiThumbnailProvider.exe",
|
||||
L"PowerToys.SvgPreviewHandler.exe",
|
||||
L"PowerToys.Peek.UI.exe",
|
||||
L"PowerToys.MouseWithoutBorders.exe",
|
||||
|
@ -152,4 +152,12 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredEnvironmentVariablesEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredQoiPreviewEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredQoiPreviewEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredQoiThumbnailsEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredQoiThumbnailsEnabledValue());
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetAllowExperimentationValue();
|
||||
static GpoRuleConfigured GetRunPluginEnabledValue(winrt::hstring const& pluginID);
|
||||
static GpoRuleConfigured GetConfiguredEnvironmentVariablesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,8 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetAllowExperimentationValue();
|
||||
static GpoRuleConfigured GetRunPluginEnabledValue(String pluginID);
|
||||
static GpoRuleConfigured GetConfiguredEnvironmentVariablesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +235,10 @@ public
|
||||
return gcnew String(CommonSharedConstants::GCODE_PREVIEW_RESIZE_EVENT);
|
||||
}
|
||||
|
||||
static String ^ QoiPreviewResizeEvent() {
|
||||
return gcnew String(CommonSharedConstants::QOI_PREVIEW_RESIZE_EVENT);
|
||||
}
|
||||
|
||||
static String ^ DevFilesPreviewResizeEvent() {
|
||||
return gcnew String(CommonSharedConstants::DEV_FILES_PREVIEW_RESIZE_EVENT);
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ namespace CommonSharedConstants
|
||||
// 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 QoiPreviewHandler
|
||||
const wchar_t QOI_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysQoiPreviewResizeEvent-579518d1-8c8b-494f-8143-04f43d761ead";
|
||||
|
||||
// Path to the event used by DevFilesPreviewHandler
|
||||
const wchar_t DEV_FILES_PREVIEW_RESIZE_EVENT[] = L"Local\\PowerToysDevFilesPreviewResizeEvent-5707a22c-2cac-4ea2-82f0-27c03ef0b5f3";
|
||||
|
||||
|
@ -27,6 +27,10 @@ struct LogSettings
|
||||
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 qoiPrevLoggerName = "QoiPrevHandler";
|
||||
inline const static std::wstring qoiPrevLogPath = L"logs\\FileExplorer_localLow\\QoiPreviewHandler\\qoi-prev-handler-log.txt";
|
||||
inline const static std::string qoiThumbLoggerName = "QoiThumbnailProvider";
|
||||
inline const static std::wstring qoiThumbLogPath = L"logs\\FileExplorer_localLow\\QoiThumbnailProvider\\qoi-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";
|
||||
|
@ -56,6 +56,8 @@ namespace powertoys_gpo {
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_WITHOUT_BORDERS = L"ConfigureEnabledUtilityMouseWithoutBorders";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_PEEK = L"ConfigureEnabledUtilityPeek";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_ENVIRONMENT_VARIABLES = L"ConfigureEnabledUtilityEnvironmentVariables";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_QOI_PREVIEW = L"ConfigureEnabledUtilityFileExplorerQOIPreview";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_QOI_THUMBNAILS = L"ConfigureEnabledUtilityFileExplorerQOIThumbnails";
|
||||
|
||||
// The registry value names for PowerToys installer and update policies.
|
||||
const std::wstring POLICY_DISABLE_PER_USER_INSTALLATION = L"PerUserInstallationDisabled";
|
||||
@ -446,4 +448,14 @@ namespace powertoys_gpo {
|
||||
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER_ALL_PLUGINS);
|
||||
}
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredQoiPreviewEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_QOI_PREVIEW);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredQoiThumbnailsEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_QOI_THUMBNAILS);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace NonLocalizable
|
||||
const static std::vector<std::wstring> ExtPDF = { L".pdf" };
|
||||
const static std::vector<std::wstring> ExtGCode = { L".gcode" };
|
||||
const static std::vector<std::wstring> ExtSTL = { L".stl" };
|
||||
const static std::vector<std::wstring> ExtQOI = { L".qoi" };
|
||||
const static std::vector<std::wstring> ExtNoNoNo = {
|
||||
L".svgz" //Monaco cannot handle this file type at all; it's a binary file.
|
||||
};
|
||||
@ -145,6 +146,19 @@ inline registry::ChangeSet getGcodePreviewHandlerChangeSet(const std::wstring in
|
||||
NonLocalizable::ExtGCode);
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getQoiPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::preview,
|
||||
perUser,
|
||||
L"{729B72CD-B72E-4FE9-BCBF-E954B33FE699}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(PowerToys.QoiPreviewHandlerCpp.dll)d").wstring(),
|
||||
L"QoiPreviewHandler",
|
||||
L"Qoi Preview Handler",
|
||||
NonLocalizable::ExtQOI);
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
@ -198,6 +212,19 @@ inline registry::ChangeSet getStlThumbnailHandlerChangeSet(const std::wstring in
|
||||
NonLocalizable::ExtSTL);
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getQoiThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::thumbnail,
|
||||
perUser,
|
||||
L"{AD856B15-D25E-4008-AFB7-AFAA55586188}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(PowerToys.QoiThumbnailProviderCpp.dll)d").wstring(),
|
||||
L"QoiThumbnailProvider",
|
||||
L"Qoi Thumbnail Provider",
|
||||
NonLocalizable::ExtQOI);
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getRegistryPreviewSetDefaultAppChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
||||
@ -245,9 +272,11 @@ inline std::vector<registry::ChangeSet> getAllOnByDefaultModulesChangeSets(const
|
||||
getMdPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getMonacoPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodePreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getQoiPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getQoiThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getRegistryPreviewChangeSet(installationDir, PER_USER) };
|
||||
}
|
||||
|
||||
@ -259,10 +288,12 @@ inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstri
|
||||
getMonacoPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getPdfPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodePreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getQoiPreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getPdfThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getQoiThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getRegistryPreviewChangeSet(installationDir, PER_USER),
|
||||
getRegistryPreviewSetDefaultAppChangeSet(installationDir, PER_USER) };
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<policyNamespaces>
|
||||
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
|
||||
</policyNamespaces>
|
||||
<resources minRequiredRevision="1.5"/><!-- Last changed with PowerToys v0.75.1 -->
|
||||
<resources minRequiredRevision="1.6"/><!-- Last changed with PowerToys v0.76.0 -->
|
||||
<supportedOn>
|
||||
<definitions>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
|
||||
@ -14,6 +14,7 @@
|
||||
<definition name="SUPPORTED_POWERTOYS_0_70_0" displayName="$(string.SUPPORTED_POWERTOYS_0_70_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_73_0" displayName="$(string.SUPPORTED_POWERTOYS_0_73_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_75_0" displayName="$(string.SUPPORTED_POWERTOYS_0_75_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_76_0" displayName="$(string.SUPPORTED_POWERTOYS_0_76_0)"/>
|
||||
</definitions>
|
||||
</supportedOn>
|
||||
<categories>
|
||||
@ -188,6 +189,26 @@
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityFileExplorerQOIPreview" class="Both" displayName="$(string.ConfigureEnabledUtilityFileExplorerQOIPreview)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityFileExplorerQOIPreview">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_76_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityFileExplorerQOIThumbnails" class="Both" displayName="$(string.ConfigureEnabledUtilityFileExplorerQOIThumbnails)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityFileExplorerQOIThumbnails">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_76_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityFileExplorerSTLThumbnails" class="Both" displayName="$(string.ConfigureEnabledUtilityFileExplorerSTLThumbnails)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityFileExplorerSTLThumbnails">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_64_0" />
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.5" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.6" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<displayName>PowerToys</displayName>
|
||||
<description>PowerToys</description>
|
||||
<resources>
|
||||
@ -16,6 +16,7 @@
|
||||
<string id="SUPPORTED_POWERTOYS_0_70_0">PowerToys version 0.70.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_73_0">PowerToys version 0.73.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_75_0">PowerToys version 0.75.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_76_0">PowerToys version 0.76.0 or later</string>
|
||||
|
||||
<string id="ConfigureGlobalUtilityEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.
|
||||
|
||||
@ -149,6 +150,8 @@ Note: Changes require a restart of PowerToys Run.
|
||||
<string id="AllowExperimentation">Allow Experimentation</string>
|
||||
<string id="PowerToysRunAllPluginsEnabledState">Configure enabled state for all plugins</string>
|
||||
<string id="PowerToysRunIndividualPluginEnabledState">Configure enabled state for individual plugins</string>
|
||||
<string id="ConfigureEnabledUtilityFileExplorerQOIPreview">QOI file preview: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFileExplorerQOIThumbnails">QOI file thumbnail: Configure enabled state</string>
|
||||
</stringTable>
|
||||
|
||||
<presentationTable>
|
||||
|
63
src/modules/previewpane/QoiPreviewHandler/Program.cs
Normal file
63
src/modules/previewpane/QoiPreviewHandler/Program.cs
Normal file
@ -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.
|
||||
|
||||
using System.Globalization;
|
||||
using System.Windows.Threading;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Qoi
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
|
||||
|
||||
private static QoiPreviewHandlerControl _previewHandlerControl;
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[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 QoiPreviewHandlerControl();
|
||||
_previewHandlerControl.SetWindow((IntPtr)hwnd, s);
|
||||
_previewHandlerControl.DoPreview(filePath);
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.QoiPreviewResizeEvent(),
|
||||
() =>
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
81
src/modules/previewpane/QoiPreviewHandler/Properties/Resource.Designer.cs
generated
Normal file
81
src/modules/previewpane/QoiPreviewHandler/Properties/Resource.Designer.cs
generated
Normal file
@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Qoi.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resource {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resource() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.PowerToys.PreviewHandler.Qoi.Properties.Resource", typeof(Resource).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This Qoi could not be previewed due to an internal error..
|
||||
/// </summary>
|
||||
internal static string QoiNotPreviewedError {
|
||||
get {
|
||||
return ResourceManager.GetString("QoiNotPreviewedError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string for an error when Gpo has the utility disabled.
|
||||
/// </summary>
|
||||
internal static string GpoDisabledErrorText {
|
||||
get {
|
||||
return ResourceManager.GetString("GpoDisabledErrorText", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="QoiNotPreviewedError" xml:space="preserve">
|
||||
<value>This Qoi could not be previewed due to an internal error.</value>
|
||||
<comment>This text is displayed if Qoi fails to preview</comment>
|
||||
</data>
|
||||
<data name="GpoDisabledErrorText" xml:space="preserve">
|
||||
<value>Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.</value>
|
||||
<comment>GPO stands for the Windows Group Policy Object feature.</comment>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,77 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AssemblyTitle>PowerToys.QoiPreviewHandler</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys QoiPreviewHandler</AssemblyDescription>
|
||||
<Description>PowerToys QoiPreviewHandler</Description>
|
||||
<DocumentationFile>..\..\..\..\$(Platform)\$(Configuration)\QoiPreviewPaneDocumentation.xml</DocumentationFile>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||
<AssemblyName>PowerToys.QoiPreviewHandler</AssemblyName>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
|
||||
<PropertyGroup Condition="'$(Platform)'=='x64'">
|
||||
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
|
||||
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{6B04803D-B418-4833-A67E-B0FC966636A5}</ProjectGuid>
|
||||
<RootNamespace>Microsoft.PowerToys.PreviewHandler.Qoi</RootNamespace>
|
||||
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="QoiPreviewHandlerControl.cs" />
|
||||
<Compile Update="Properties\Resource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
|
||||
<PropertyGroup>
|
||||
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Disable missing comment warning. WinRT/C++ libraries added won't have comments on their reflections. -->
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
<OutputType>WinExe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\common\PreviewHandlerCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resource.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,166 @@
|
||||
// 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 Common;
|
||||
using Microsoft.PowerToys.PreviewHandler.Qoi.Telemetry.Events;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using PreviewHandlerCommon.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Qoi
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of Control for Qoi Preview Handler.
|
||||
/// </summary>
|
||||
public class QoiPreviewHandlerControl : FormHandlerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Picture box control to display the Qoi thumbnail.
|
||||
/// </summary>
|
||||
private PictureBox _pictureBox;
|
||||
|
||||
/// <summary>
|
||||
/// Text box to display errors.
|
||||
/// </summary>
|
||||
private RichTextBox _textBox;
|
||||
|
||||
/// <summary>
|
||||
/// Represent if an text box info bar is added for showing message.
|
||||
/// </summary>
|
||||
private bool _infoBarAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QoiPreviewHandlerControl"/> class.
|
||||
/// </summary>
|
||||
public QoiPreviewHandlerControl()
|
||||
{
|
||||
SetBackgroundColor(Settings.BackgroundColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the preview on the Control.
|
||||
/// </summary>
|
||||
/// <param name="dataSource">Stream reference to access source file.</param>
|
||||
public override void DoPreview<T>(T dataSource)
|
||||
{
|
||||
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredQoiPreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
|
||||
{
|
||||
// GPO is disabling this utility. Show an error message instead.
|
||||
_infoBarAdded = true;
|
||||
AddTextBoxControl(Properties.Resource.GpoDisabledErrorText);
|
||||
Resize += FormResized;
|
||||
base.DoPreview(dataSource);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
if (!(dataSource is string filePath))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(dataSource)} for {nameof(QoiPreviewHandlerControl)} must be a string but was a '{typeof(T)}'");
|
||||
}
|
||||
|
||||
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
thumbnail = QoiImage.FromStream(fs);
|
||||
|
||||
_infoBarAdded = false;
|
||||
|
||||
AddPictureBoxControl(thumbnail);
|
||||
|
||||
Resize += FormResized;
|
||||
base.DoPreview(fs);
|
||||
try
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new QoiFilePreviewed());
|
||||
}
|
||||
catch
|
||||
{ // Should not crash if sending telemetry is failing. Ignore the exception.
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PreviewError(ex, dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when RichtextBox is resized.
|
||||
/// </summary>
|
||||
/// <param name="sender">Reference to resized control.</param>
|
||||
/// <param name="e">Provides data for the ContentsResized event.</param>
|
||||
private void RTBContentsResized(object sender, ContentsResizedEventArgs e)
|
||||
{
|
||||
var richTextBox = sender as RichTextBox;
|
||||
richTextBox.Height = e.NewRectangle.Height + 5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when form is resized.
|
||||
/// </summary>
|
||||
/// <param name="sender">Reference to resized control.</param>
|
||||
/// <param name="e">Provides data for the resize event.</param>
|
||||
private void FormResized(object sender, EventArgs e)
|
||||
{
|
||||
if (_infoBarAdded)
|
||||
{
|
||||
_textBox.Width = Width;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PictureBox Control to Control Collection.
|
||||
/// </summary>
|
||||
/// <param name="image">Image to display on PictureBox Control.</param>
|
||||
private void AddPictureBoxControl(Image image)
|
||||
{
|
||||
_pictureBox = new PictureBox();
|
||||
_pictureBox.BackgroundImage = image;
|
||||
_pictureBox.BackgroundImageLayout = Width >= image.Width && Height >= image.Height ? ImageLayout.Center : ImageLayout.Zoom;
|
||||
_pictureBox.Dock = DockStyle.Fill;
|
||||
Controls.Add(_pictureBox);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Text Box to display errors.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to be displayed in textbox.</param>
|
||||
private void AddTextBoxControl(string message)
|
||||
{
|
||||
_textBox = new RichTextBox();
|
||||
_textBox.Text = message;
|
||||
_textBox.BackColor = Color.LightYellow;
|
||||
_textBox.Multiline = true;
|
||||
_textBox.Dock = DockStyle.Top;
|
||||
_textBox.ReadOnly = true;
|
||||
_textBox.ContentsResized += RTBContentsResized;
|
||||
_textBox.ScrollBars = RichTextBoxScrollBars.None;
|
||||
_textBox.BorderStyle = BorderStyle.None;
|
||||
Controls.Add(_textBox);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when an error occurs during preview.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception which occurred.</param>
|
||||
/// <param name="dataSource">Stream reference to access source file.</param>
|
||||
private void PreviewError<T>(Exception exception, T dataSource)
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new QoiFilePreviewError { Message = exception.Message });
|
||||
}
|
||||
catch
|
||||
{ // Should not crash if sending telemetry is failing. Ignore the exception.
|
||||
}
|
||||
|
||||
Controls.Clear();
|
||||
_infoBarAdded = true;
|
||||
AddTextBoxControl(Properties.Resource.QoiNotPreviewedError);
|
||||
base.DoPreview(dataSource);
|
||||
}
|
||||
}
|
||||
}
|
38
src/modules/previewpane/QoiPreviewHandler/Settings.cs
Normal file
38
src/modules/previewpane/QoiPreviewHandler/Settings.cs
Normal file
@ -0,0 +1,38 @@
|
||||
// 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.Qoi
|
||||
{
|
||||
internal sealed class Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the color of the window background.
|
||||
/// Even though this is not a setting yet, it's retrieved from a "Settings" class to be aligned with other preview handlers that contain this setting.
|
||||
/// It's possible it can be converted into a setting in the future.
|
||||
/// </summary>
|
||||
public static Color BackgroundColor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GetTheme() == "dark")
|
||||
{
|
||||
return Color.FromArgb(30, 30, 30); // #1e1e1e
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the theme.
|
||||
/// </summary>
|
||||
/// <returns>Theme that should be used.</returns>
|
||||
public static string GetTheme()
|
||||
{
|
||||
return Common.UI.ThemeManager.GetWindowsBaseColor().ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// 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.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Qoi.Telemetry.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A telemetry event to be raised when an error has occurred in the preview pane.
|
||||
/// </summary>
|
||||
[EventData]
|
||||
public class QoiFilePreviewError : EventBase, IEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the error message to log as part of the telemetry event.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServicePerformance;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// 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.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Qoi.Telemetry.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A telemetry event to be raised when a Qoi file has been viewed in the preview pane.
|
||||
/// </summary>
|
||||
[EventData]
|
||||
public class QoiFilePreviewed : EventBase, IEvent
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
#include "pch.h"
|
||||
#include "ClassFactory.h"
|
||||
#include "QoiPreviewHandler.h"
|
||||
|
||||
#include <new>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
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;
|
||||
|
||||
QoiPreviewHandler* pExt = new (std::nothrow) QoiPreviewHandler();
|
||||
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;
|
||||
}
|
24
src/modules/previewpane/QoiPreviewHandlerCpp/ClassFactory.h
Normal file
24
src/modules/previewpane/QoiPreviewHandlerCpp/ClassFactory.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <Unknwn.h>
|
||||
|
||||
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;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
@ -0,0 +1,266 @@
|
||||
#include "pch.h"
|
||||
#include "QoiPreviewHandler.h"
|
||||
#include "../powerpreview/powerpreviewConstants.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <string>
|
||||
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/Themes/windows_colors.h>
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
extern long g_cDllRef;
|
||||
|
||||
QoiPreviewHandler::QoiPreviewHandler() :
|
||||
m_cRef(1), m_hwndParent(NULL), m_rcParent(), m_punkSite(NULL), m_process(NULL)
|
||||
{
|
||||
m_resizeEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::QOI_PREVIEW_RESIZE_EVENT);
|
||||
|
||||
std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
|
||||
logFilePath.append(LogSettings::qoiPrevLogPath);
|
||||
Logger::init(LogSettings::qoiPrevLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
QoiPreviewHandler::~QoiPreviewHandler()
|
||||
{
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
#pragma region IUnknown
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(QoiPreviewHandler, IPreviewHandler),
|
||||
QITABENT(QoiPreviewHandler, IInitializeWithFile),
|
||||
QITABENT(QoiPreviewHandler, IPreviewHandlerVisuals),
|
||||
QITABENT(QoiPreviewHandler, IOleWindow),
|
||||
QITABENT(QoiPreviewHandler, IObjectWithSite),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
QoiPreviewHandler::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
QoiPreviewHandler::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IInitializationWithFile
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::Initialize(LPCWSTR pszFilePath, DWORD grfMode)
|
||||
{
|
||||
m_filePath = pszFilePath;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IPreviewHandler
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::SetWindow(HWND hwnd, const RECT* prc)
|
||||
{
|
||||
if (hwnd && prc)
|
||||
{
|
||||
m_hwndParent = hwnd;
|
||||
m_rcParent = *prc;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::SetFocus()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::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 QoiPreviewHandler::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 QoiPreviewHandler::SetRect(const RECT* prc)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
if (prc != NULL)
|
||||
{
|
||||
if (!m_resizeEvent)
|
||||
{
|
||||
Logger::error(L"Failed to create resize event for QoiPreviewHandler");
|
||||
}
|
||||
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 QoiPreviewHandler");
|
||||
}
|
||||
}
|
||||
}
|
||||
m_rcParent = *prc;
|
||||
hr = S_OK;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::DoPreview()
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger::info(L"Starting QoiPreviewHandler.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.QoiPreviewHandler.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 QoiPreviewHandler.exe. Error: {}", errorMessage);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::Unload()
|
||||
{
|
||||
Logger::info(L"Unload and terminate .exe");
|
||||
|
||||
m_hwndParent = NULL;
|
||||
TerminateProcess(m_process, 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IPreviewHandlerVisuals
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::SetBackgroundColor(COLORREF color)
|
||||
{
|
||||
HBRUSH brush = CreateSolidBrush(WindowsColors::is_dark_mode() ? powerpreviewConstants::DARK_THEME_COLOR : powerpreviewConstants::LIGHT_THEME_COLOR);
|
||||
SetClassLongPtr(m_hwndParent, GCLP_HBRBACKGROUND, reinterpret_cast<LONG_PTR>(brush));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::SetFont(const LOGFONTW* plf)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::SetTextColor(COLORREF color)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IOleWindow
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::GetWindow(HWND* phwnd)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
if (phwnd)
|
||||
{
|
||||
*phwnd = m_hwndParent;
|
||||
hr = S_OK;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::ContextSensitiveHelp(BOOL fEnterMode)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IObjectWithSite
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::SetSite(IUnknown* punkSite)
|
||||
{
|
||||
if (m_punkSite)
|
||||
{
|
||||
m_punkSite->Release();
|
||||
m_punkSite = NULL;
|
||||
}
|
||||
return punkSite ? punkSite->QueryInterface(&m_punkSite) : S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QoiPreviewHandler::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
|
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <ShlObj.h>
|
||||
#include <string>
|
||||
|
||||
class QoiPreviewHandler :
|
||||
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);
|
||||
|
||||
QoiPreviewHandler();
|
||||
protected:
|
||||
~QoiPreviewHandler();
|
||||
|
||||
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;
|
||||
};
|
@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#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
|
@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{3BAF9C81-A194-4925-A035-5E24A5D1E542}</ProjectGuid>
|
||||
<RootNamespace>QoiPreviewHandlerCpp</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToys.$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>../../..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>GlobalExportFunctions.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>../../..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>GlobalExportFunctions.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ClassFactory.h" />
|
||||
<ClInclude Include="QoiPreviewHandler.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ClassFactory.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="QoiPreviewHandler.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="GlobalExportFunctions.def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="QoiPreviewHandlerCpp.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
|
||||
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ClassFactory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="QoiPreviewHandler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ClassFactory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QoiPreviewHandler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="GlobalExportFunctions.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="QoiPreviewHandlerCpp.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
73
src/modules/previewpane/QoiPreviewHandlerCpp/dllmain.cpp
Normal file
73
src/modules/previewpane/QoiPreviewHandlerCpp/dllmain.cpp
Normal file
@ -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;
|
||||
|
||||
// {729B72CD-B72E-4FE9-BCBF-E954B33FE699}
|
||||
static const GUID CLSID_QoiPreviewHandler = { 0x729b72cd, 0xb72e, 0x4fe9, { 0xbc, 0xbf, 0xe9, 0x54, 0xb3, 0x3f, 0xe6, 0x99 } };
|
||||
|
||||
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_QoiPreviewHandler, 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;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
|
||||
</packages>
|
5
src/modules/previewpane/QoiPreviewHandlerCpp/pch.cpp
Normal file
5
src/modules/previewpane/QoiPreviewHandlerCpp/pch.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
14
src/modules/previewpane/QoiPreviewHandlerCpp/pch.h
Normal file
14
src/modules/previewpane/QoiPreviewHandlerCpp/pch.h
Normal file
@ -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 <windows.h>
|
||||
|
||||
#endif //PCH_H
|
13
src/modules/previewpane/QoiPreviewHandlerCpp/resource.h
Normal file
13
src/modules/previewpane/QoiPreviewHandlerCpp/resource.h
Normal file
@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by AlwaysOnTopModuleInterface.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys Qoi Preview Handler Module"
|
||||
#define INTERNAL_NAME "PowerToys.QoiPreviewHandlerCpp"
|
||||
#define ORIGINAL_FILENAME "PowerToys.QoiPreviewHandlerCpp.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
42
src/modules/previewpane/QoiThumbnailProvider/Program.cs
Normal file
42
src/modules/previewpane/QoiThumbnailProvider/Program.cs
Normal file
@ -0,0 +1,42 @@
|
||||
// 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.Globalization;
|
||||
|
||||
namespace Microsoft.PowerToys.ThumbnailHandler.Qoi
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static QoiThumbnailProvider _thumbnailProvider;
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[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 QoiThumbnailProvider(filePath);
|
||||
Bitmap thumbnail = _thumbnailProvider.GetThumbnail(cx);
|
||||
if (thumbnail != null)
|
||||
{
|
||||
filePath = filePath.Replace(".qoi", ".bmp");
|
||||
thumbnail.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Qoi thumbnail - wrong number of args: " + args.Length.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
// 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.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using PreviewHandlerCommon.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.ThumbnailHandler.Qoi
|
||||
{
|
||||
/// <summary>
|
||||
/// Qoi Thumbnail Provider.
|
||||
/// </summary>
|
||||
public class QoiThumbnailProvider
|
||||
{
|
||||
public QoiThumbnailProvider(string filePath)
|
||||
{
|
||||
FilePath = filePath;
|
||||
Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file path to the file creating thumbnail for.
|
||||
/// </summary>
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stream object to access file.
|
||||
/// </summary>
|
||||
public Stream Stream { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum dimension (width or height) thumbnail we will generate.
|
||||
/// </summary>
|
||||
private const uint MaxThumbnailSize = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Generate thumbnail bitmap for provided Qoi stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The Stream instance for the Qoi bitmap.</param>
|
||||
/// <param name="cx">The maximum thumbnail size, in pixels.</param>
|
||||
/// <returns>A thumbnail rendered from the Qoi bitmap.</returns>
|
||||
public static Bitmap GetThumbnail(Stream stream, uint cx)
|
||||
{
|
||||
if (cx > MaxThumbnailSize || stream == null || stream.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap thumbnail = null;
|
||||
try
|
||||
{
|
||||
thumbnail = QoiImage.FromStream(stream);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// TODO: add logger
|
||||
}
|
||||
|
||||
if (thumbnail != null && (
|
||||
((thumbnail.Width != cx || thumbnail.Height > cx) && (thumbnail.Height != cx || thumbnail.Width > cx)) ||
|
||||
thumbnail.PixelFormat != PixelFormat.Format32bppArgb))
|
||||
{
|
||||
// We are not the appropriate size for caller. Resize now while
|
||||
// respecting the aspect ratio.
|
||||
float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height);
|
||||
int scaleWidth = (int)(thumbnail.Width * scale);
|
||||
int scaleHeight = (int)(thumbnail.Height * scale);
|
||||
thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight);
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resize the image with high quality to the specified width and height.
|
||||
/// </summary>
|
||||
/// <param name="image">The image to resize.</param>
|
||||
/// <param name="width">The width to resize to.</param>
|
||||
/// <param name="height">The height to resize to.</param>
|
||||
/// <returns>The resized image.</returns>
|
||||
public static Bitmap ResizeImage(Image image, int width, int height)
|
||||
{
|
||||
if (width <= 0 ||
|
||||
height <= 0 ||
|
||||
width > MaxThumbnailSize ||
|
||||
height > MaxThumbnailSize ||
|
||||
image == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap destImage = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
|
||||
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
|
||||
|
||||
using (var graphics = Graphics.FromImage(destImage))
|
||||
{
|
||||
graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
graphics.DrawImage(image, 0, 0, width, height);
|
||||
}
|
||||
|
||||
image.Dispose();
|
||||
|
||||
return destImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate thumbnail bitmap for provided Qoi file/stream.
|
||||
/// </summary>
|
||||
/// <param name="cx">Maximum thumbnail size, in pixels.</param>
|
||||
/// <returns>Generated bitmap</returns>
|
||||
public Bitmap GetThumbnail(uint cx)
|
||||
{
|
||||
if (cx == 0 || cx > MaxThumbnailSize)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredQoiThumbnailsEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
|
||||
{
|
||||
// GPO is disabling this utility.
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap thumbnail = GetThumbnail(this.Stream, cx);
|
||||
if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
|
||||
{
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ProjectGuid>{D949EC7D-48A9-4279-95D5-078E7FD1F048}</ProjectGuid>
|
||||
<RootNamespace>Microsoft.PowerToys.ThumbnailHandler.Qoi</RootNamespace>
|
||||
<AssemblyName>PowerToys.QoiThumbnailProvider</AssemblyName>
|
||||
<AssemblyTitle>PowerToys.QoiThumbnailProvider</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys QoiPreviewHandler</AssemblyDescription>
|
||||
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Description>PowerToys QoiPreviewHandler</Description>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
|
||||
<PropertyGroup Condition="'$(Platform)'=='x64'">
|
||||
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
|
||||
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
|
||||
<PropertyGroup>
|
||||
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Disable missing comment warning. WinRT/C++ libraries added won't have comments on their reflections. -->
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
<OutputType>WinExe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,84 @@
|
||||
#include "pch.h"
|
||||
#include "ClassFactory.h"
|
||||
#include "QoiThumbnailProvider.h"
|
||||
|
||||
#include <new>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
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;
|
||||
|
||||
QoiThumbnailProvider* pExt = new (std::nothrow) QoiThumbnailProvider();
|
||||
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;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <Unknwn.h>
|
||||
|
||||
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;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
@ -0,0 +1,195 @@
|
||||
#include "pch.h"
|
||||
#include "QoiThumbnailProvider.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <string>
|
||||
|
||||
#include <wil/com.h>
|
||||
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/process_path.h>
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
extern long g_cDllRef;
|
||||
|
||||
QoiThumbnailProvider::QoiThumbnailProvider() :
|
||||
m_cRef(1), m_pStream(NULL), m_process(NULL)
|
||||
{
|
||||
std::filesystem::path logFilePath(PTSettingsHelper::get_local_low_folder_location());
|
||||
logFilePath.append(LogSettings::qoiThumbLogPath);
|
||||
Logger::init(LogSettings::qoiThumbLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
QoiThumbnailProvider::~QoiThumbnailProvider()
|
||||
{
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
#pragma region IUnknown
|
||||
|
||||
IFACEMETHODIMP QoiThumbnailProvider::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(QoiThumbnailProvider, IThumbnailProvider),
|
||||
QITABENT(QoiThumbnailProvider, IInitializeWithStream),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
QoiThumbnailProvider::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
QoiThumbnailProvider::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IInitializationWithStream
|
||||
|
||||
IFACEMETHODIMP QoiThumbnailProvider::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 QoiThumbnailProvider::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"\\QoiThumbnail-Temp\\";
|
||||
if (!std::filesystem::exists(filePath))
|
||||
{
|
||||
std::filesystem::create_directories(filePath);
|
||||
}
|
||||
|
||||
std::wstring fileName = filePath + guid + L".qoi";
|
||||
|
||||
// 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();
|
||||
|
||||
m_pStream->Release();
|
||||
m_pStream = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
Logger::info(L"Start QoiThumbnailProvider.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.QoiThumbnailProvider.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";
|
||||
if (std::filesystem::exists(fileNameBmp))
|
||||
{
|
||||
*phbmp = static_cast<HBITMAP>(LoadImage(NULL, fileNameBmp.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
|
||||
*pdwAlpha = WTS_ALPHATYPE::WTSAT_ARGB;
|
||||
std::filesystem::remove(fileNameBmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"Bmp file not generated.");
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::wstring errorMessage = std::wstring{ winrt::to_hstring(e.what()) };
|
||||
Logger::error(L"Failed to start QoiThumbnailProvider.exe. Error: {}", errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Helper Functions
|
||||
|
||||
#pragma endregion
|
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <ShlObj.h>
|
||||
#include <string>
|
||||
#include <thumbcache.h>
|
||||
|
||||
class QoiThumbnailProvider :
|
||||
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);
|
||||
|
||||
// IThumbnailProvider
|
||||
IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
|
||||
|
||||
QoiThumbnailProvider();
|
||||
protected:
|
||||
~QoiThumbnailProvider();
|
||||
|
||||
private:
|
||||
// Reference count of component.
|
||||
long m_cRef;
|
||||
|
||||
// Provided during initialization.
|
||||
IStream* m_pStream;
|
||||
|
||||
HANDLE m_process;
|
||||
};
|
@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#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
|
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{CCB5E44F-84D9-4203-83C6-1C9EC9302BC7}</ProjectGuid>
|
||||
<RootNamespace>QoiThumbnailProviderCpp</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToys.$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>../../..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>GlobalExportFunctions.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;MARKDOWNPREVIEWHANDLERCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>../../..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>GlobalExportFunctions.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ClassFactory.h" />
|
||||
<ClInclude Include="QoiThumbnailProvider.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ClassFactory.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="QoiThumbnailProvider.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="GlobalExportFunctions.def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="QoiThumbnailProviderCpp.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ClassFactory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="QoiThumbnailProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ClassFactory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QoiThumbnailProvider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="GlobalExportFunctions.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="QoiThumbnailProviderCpp.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
73
src/modules/previewpane/QoiThumbnailProviderCpp/dllmain.cpp
Normal file
73
src/modules/previewpane/QoiThumbnailProviderCpp/dllmain.cpp
Normal file
@ -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;
|
||||
|
||||
// {AD856B15-D25E-4008-AFB7-AFAA55586188}
|
||||
static const GUID CLSID_QoiThumbnailProvider = { 0xad856b15, 0xd25e, 0x4008, { 0xaf, 0xb7, 0xaf, 0xaa, 0x55, 0x58, 0x61, 0x88 } };
|
||||
|
||||
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_QoiThumbnailProvider, 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;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220914.1" targetFramework="native" />
|
||||
</packages>
|
5
src/modules/previewpane/QoiThumbnailProviderCpp/pch.cpp
Normal file
5
src/modules/previewpane/QoiThumbnailProviderCpp/pch.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
15
src/modules/previewpane/QoiThumbnailProviderCpp/pch.h
Normal file
15
src/modules/previewpane/QoiThumbnailProviderCpp/pch.h
Normal file
@ -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 <windows.h>
|
||||
#include <winrt/base.h>
|
||||
|
||||
#endif //PCH_H
|
13
src/modules/previewpane/QoiThumbnailProviderCpp/resource.h
Normal file
13
src/modules/previewpane/QoiThumbnailProviderCpp/resource.h
Normal file
@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by AlwaysOnTopModuleInterface.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys Qoi Thumbnail Provider Module"
|
||||
#define INTERNAL_NAME "PowerToys.QoiThumbnailProviderCpp"
|
||||
#define ORIGINAL_FILENAME "PowerToys.QoiThumbnailProviderCpp.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
Binary file not shown.
@ -0,0 +1,92 @@
|
||||
// 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.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerToys.PreviewHandler.Qoi;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
|
||||
namespace QoiPreviewHandlerUnitTests
|
||||
{
|
||||
[STATestClass]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "new Exception() is fine in test projects.")]
|
||||
public class QoiPreviewHandlerTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void QoiPreviewHandlerControlAddsControlsToFormWhenDoPreviewIsCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var qoiPreviewHandlerControl = new QoiPreviewHandlerControl())
|
||||
{
|
||||
// Act
|
||||
var file = File.ReadAllBytes("HelperFiles/sample.qoi");
|
||||
|
||||
qoiPreviewHandlerControl.DoPreview<IStream>(GetMockStream(file));
|
||||
|
||||
var flowLayoutPanel = qoiPreviewHandlerControl.Controls[0] as FlowLayoutPanel;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, qoiPreviewHandlerControl.Controls.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void QoiPreviewHandlerControlShouldAddValidInfoBarIfQoiPreviewThrows()
|
||||
{
|
||||
// Arrange
|
||||
using (var qoiPreviewHandlerControl = new QoiPreviewHandlerControl())
|
||||
{
|
||||
var mockStream = new Mock<IStream>();
|
||||
mockStream
|
||||
.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<IntPtr>()))
|
||||
.Throws(new Exception());
|
||||
|
||||
// Act
|
||||
qoiPreviewHandlerControl.DoPreview(mockStream.Object);
|
||||
var textBox = qoiPreviewHandlerControl.Controls[0] as RichTextBox;
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(string.IsNullOrWhiteSpace(textBox.Text));
|
||||
Assert.AreEqual(1, qoiPreviewHandlerControl.Controls.Count);
|
||||
Assert.AreEqual(DockStyle.Top, textBox.Dock);
|
||||
Assert.AreEqual(Color.LightYellow, textBox.BackColor);
|
||||
Assert.IsTrue(textBox.Multiline);
|
||||
Assert.IsTrue(textBox.ReadOnly);
|
||||
Assert.AreEqual(RichTextBoxScrollBars.None, textBox.ScrollBars);
|
||||
Assert.AreEqual(BorderStyle.None, textBox.BorderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
private static IStream GetMockStream(byte[] sourceArray)
|
||||
{
|
||||
var streamMock = new Mock<IStream>();
|
||||
int bytesRead = 0;
|
||||
|
||||
streamMock
|
||||
.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<IntPtr>()))
|
||||
.Callback<byte[], int, IntPtr>((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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>UnitTests-QoiPreviewHandler</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys UnitTests-QoiPreviewHandler</AssemblyDescription>
|
||||
<AssemblyTitle>UnitTests-QoiPreviewHandler</AssemblyTitle>
|
||||
<Description>PowerToys UnitTests-QoiPreviewHandler</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{3940AD4D-F748-4BE4-9083-85769CD553EF}</ProjectGuid>
|
||||
<RootNamespace>PdfPreviewHandlerUnitTests</RootNamespace>
|
||||
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="HelperFiles\sample.qoi" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="MSTest.TestAdapter" />
|
||||
<PackageReference Include="MSTest.TestFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common\PreviewHandlerCommon.csproj" />
|
||||
<ProjectReference Include="..\QoiPreviewHandler\QoiPreviewHandler.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="HelperFiles\sample.qoi">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Compile Include="..\STATestClassAttribute.cs" Link="STATestClassAttribute.cs" />
|
||||
<Compile Include="..\STATestMethodAttribute.cs" Link="STATestMethodAttribute.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Binary file not shown.
@ -0,0 +1,61 @@
|
||||
// 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.Drawing;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.PowerToys.ThumbnailHandler.Qoi;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace QoiThumbnailProviderUnitTests
|
||||
{
|
||||
[STATestClass]
|
||||
public class QoiThumbnailProviderTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void GetThumbnailValidStreamQoi()
|
||||
{
|
||||
// Act
|
||||
var filePath = "HelperFiles/sample.qoi";
|
||||
|
||||
QoiThumbnailProvider provider = new QoiThumbnailProvider(filePath);
|
||||
|
||||
Bitmap bitmap = provider.GetThumbnail(256);
|
||||
|
||||
Assert.IsTrue(bitmap != null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetThumbnailInValidSizeQoi()
|
||||
{
|
||||
// Act
|
||||
var filePath = "HelperFiles/sample.qoi";
|
||||
|
||||
QoiThumbnailProvider provider = new QoiThumbnailProvider(filePath);
|
||||
|
||||
Bitmap bitmap = provider.GetThumbnail(0);
|
||||
|
||||
Assert.IsTrue(bitmap == null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetThumbnailToBigQoi()
|
||||
{
|
||||
// Act
|
||||
var filePath = "HelperFiles/sample.qoi";
|
||||
|
||||
QoiThumbnailProvider provider = new QoiThumbnailProvider(filePath);
|
||||
|
||||
Bitmap bitmap = provider.GetThumbnail(10001);
|
||||
|
||||
Assert.IsTrue(bitmap == null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CheckNoQoiNullStringShouldReturnNullBitmap()
|
||||
{
|
||||
Bitmap thumbnail = QoiThumbnailProvider.GetThumbnail(null, 256);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>UnitTests-QoiThumbnailProvider</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys UnitTests-QoiThumbnailProvider</AssemblyDescription>
|
||||
<AssemblyTitle>UnitTests-QoiThumbnailProvider</AssemblyTitle>
|
||||
<Description>PowerToys UnitTests-QoiThumbnailProvider</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}</ProjectGuid>
|
||||
<RootNamespace>QoiThumbnailProviderUnitTests</RootNamespace>
|
||||
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="HelperFiles\sample.qoi" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" />
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="MSTest.TestAdapter" />
|
||||
<PackageReference Include="MSTest.TestFramework" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
|
||||
<ProjectReference Include="..\QoiThumbnailProvider\QoiThumbnailProvider.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\STATestClassAttribute.cs" Link="STATestClassAttribute.cs" />
|
||||
<Compile Include="..\STATestMethodAttribute.cs" Link="STATestMethodAttribute.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="HelperFiles\sample.qoi">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -37,17 +37,27 @@ const CLSID CLSID_SHIMActivateGcodePreviewHandler = { 0x516cb24f, 0x562f, 0x422f
|
||||
// ec52dea8-7c9f-4130-a77b-1737d0418507
|
||||
const CLSID CLSID_GcodePreviewHandler = { 0xec52dea8, 0x7c9f, 0x4130, { 0xa7, 0x7b, 0x17, 0x37, 0xd0, 0x41, 0x85, 0x07 } };
|
||||
|
||||
// F498BE36-5C94-4EC9-A65A-AD1CF4C38271
|
||||
const GUID CLSID_SHIMActivateQoiPreviewHandler = { 0xf498be36, 0x5c94, 0x4ec9, { 0xa6, 0x5a, 0xad, 0x1c, 0xf4, 0xc3, 0x82, 0x71 } };
|
||||
|
||||
// 8AA07897-C30B-4543-865B-00A0E5A1B32D
|
||||
const GUID CLSID_QoiPreviewHandler = { 0x8aa07897, 0xc30b, 0x4543, { 0x86, 0x5b, 0x0, 0xa0, 0xe5, 0xa1, 0xb3, 0x2d } };
|
||||
|
||||
// BFEE99B4-B74D-4348-BCA5-E757029647FF
|
||||
const GUID CLSID_GcodeThumbnailProvider = { 0xbfee99b4, 0xb74d, 0x4348, { 0xbc, 0xa5, 0xe7, 0x57, 0x02, 0x96, 0x47, 0xff } };
|
||||
|
||||
// 8BC8AFC2-4E7C-4695-818E-8C1FFDCEA2AF
|
||||
const GUID CLSID_StlThumbnailProvider = { 0x8bc8afc2, 0x4e7c, 0x4695, { 0x81, 0x8e, 0x8c, 0x1f, 0xfd, 0xce, 0xa2, 0xaf } };
|
||||
|
||||
// 907B7E38-38ED-42E7-A276-9EF0ECABB003
|
||||
const GUID CLSID_QoiThumbnailProvider = { 0x907b7e38, 0x38ed, 0x42e7, { 0xa2, 0x76, 0x9e, 0xf0, 0xec, 0xab, 0xb0, 0x3 } };
|
||||
|
||||
// Pairs of NativeClsid vs ManagedClsid used for preview handlers.
|
||||
const std::vector<std::pair<CLSID, CLSID>> NativeToManagedClsid({
|
||||
{ CLSID_SHIMActivateMdPreviewHandler, CLSID_MdPreviewHandler },
|
||||
{ CLSID_SHIMActivatePdfPreviewHandler, CLSID_PdfPreviewHandler },
|
||||
{ CLSID_SHIMActivateGcodePreviewHandler, CLSID_GcodePreviewHandler },
|
||||
{ CLSID_SHIMActivateQoiPreviewHandler, CLSID_QoiPreviewHandler },
|
||||
{ CLSID_SHIMActivateSvgPreviewHandler, CLSID_SvgPreviewHandler },
|
||||
{ CLSID_SHIMActivateSvgThumbnailProvider, CLSID_SvgThumbnailProvider }
|
||||
});
|
||||
|
@ -192,4 +192,10 @@
|
||||
<data name="Stl_Thumbnail_Provider_Settings_Description" xml:space="preserve">
|
||||
<value>Stl Thumbnail Provider</value>
|
||||
</data>
|
||||
<data name="Prevpane_Qoi_Settings_Description" xml:space="preserve">
|
||||
<value>Qoi Previewer</value>
|
||||
</data>
|
||||
<data name="Qoi_Thumbnail_Provider_Settings_Description" xml:space="preserve">
|
||||
<value>Qoi Thumbnail Provider</value>
|
||||
</data>
|
||||
</root>
|
@ -71,6 +71,16 @@ PowerPreviewModule::PowerPreviewModule() :
|
||||
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredStlThumbnailsEnabledValue,
|
||||
.registryChanges = getStlThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
m_fileExplorerModules.push_back({ .settingName = L"qoi-previewer-toggle-setting",
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_QOI_SETTINGS_DESCRIPTION),
|
||||
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredQoiPreviewEnabledValue,
|
||||
.registryChanges = getQoiPreviewHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
m_fileExplorerModules.push_back({ .settingName = L"qoi-thumbnail-toggle-setting",
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_QOI_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
||||
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredQoiThumbnailsEnabledValue,
|
||||
.registryChanges = getQoiThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
|
@ -221,6 +221,40 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("stl-thumbnail-color-setting")]
|
||||
public StringProperty StlThumbnailColor { get; set; }
|
||||
|
||||
private bool enableQoiPreview = true;
|
||||
|
||||
[JsonPropertyName("qoi-previewer-toggle-setting")]
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool EnableQoiPreview
|
||||
{
|
||||
get => enableQoiPreview;
|
||||
set
|
||||
{
|
||||
if (value != enableQoiPreview)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
enableQoiPreview = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool enableQoiThumbnail = true;
|
||||
|
||||
[JsonPropertyName("qoi-thumbnail-toggle-setting")]
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool EnableQoiThumbnail
|
||||
{
|
||||
get => enableQoiThumbnail;
|
||||
set
|
||||
{
|
||||
if (value != enableQoiThumbnail)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
enableQoiThumbnail = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PowerPreviewProperties()
|
||||
{
|
||||
SvgBackgroundColorMode = new IntProperty(DefaultSvgBackgroundColorMode);
|
||||
|
@ -60,11 +60,13 @@ namespace ViewModelTests
|
||||
Assert.AreEqual(originalSettings.Properties.EnableMonacoPreview, viewModel.MonacoRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnablePdfPreview, viewModel.PDFRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableGcodePreview, viewModel.GCODERenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableQoiPreview, viewModel.QOIRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnablePdfThumbnail, viewModel.PDFThumbnailIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableGcodeThumbnail, viewModel.GCODEThumbnailIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableStlThumbnail, viewModel.STLThumbnailIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableQoiThumbnail, viewModel.QOIThumbnailIsEnabled);
|
||||
|
||||
// Verify that the stub file was used
|
||||
var expectedCallCount = 2; // once via the view model, and once by the test (GetSettings<T>)
|
||||
@ -161,6 +163,24 @@ namespace ViewModelTests
|
||||
viewModel.STLThumbnailIsEnabled = true;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void QOIThumbnailIsEnabledShouldPrevHandlerWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
SndModuleSettings<SndPowerPreviewSettings> snd = JsonSerializer.Deserialize<SndModuleSettings<SndPowerPreviewSettings>>(msg);
|
||||
Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnableQoiThumbnail);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// arrange
|
||||
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
|
||||
|
||||
// act
|
||||
viewModel.QOIThumbnailIsEnabled = true;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MDRenderIsEnabledShouldPrevHandlerWhenSuccessful()
|
||||
{
|
||||
@ -232,5 +252,23 @@ namespace ViewModelTests
|
||||
// act
|
||||
viewModel.GCODERenderIsEnabled = true;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void QOIRenderIsEnabledShouldPrevHandlerWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
SndModuleSettings<SndPowerPreviewSettings> snd = JsonSerializer.Deserialize<SndModuleSettings<SndPowerPreviewSettings>>(msg);
|
||||
Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnableQoiPreview);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// arrange
|
||||
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
|
||||
|
||||
// act
|
||||
viewModel.QOIRenderIsEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,18 @@
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.IsGCODERenderEnabledGpoConfigured}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.IsGCODERenderEnabledGpoConfigured}"
|
||||
Severity="Informational" />
|
||||
<controls:SettingsCard
|
||||
x:Uid="FileExplorerPreview_ToggleSwitch_Preview_QOI"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsQOIRenderEnabledGpoConfigured, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.QOIRenderIsEnabled}" />
|
||||
</controls:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="GPO_IsSettingForced"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.IsQOIRenderEnabledGpoConfigured}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.IsQOIRenderEnabledGpoConfigured}"
|
||||
Severity="Informational" />
|
||||
</custom:SettingsGroup>
|
||||
|
||||
<custom:SettingsGroup x:Uid="FileExplorerPreview_IconThumbnail_GroupSettings">
|
||||
@ -201,6 +213,19 @@
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.IsSTLThumbnailEnabledGpoConfigured}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.IsSTLThumbnailEnabledGpoConfigured}"
|
||||
Severity="Informational" />
|
||||
|
||||
<controls:SettingsCard
|
||||
x:Uid="FileExplorerPreview_ToggleSwitch_Thumbnail_QOI"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsQOIThumbnailEnabledGpoConfigured, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.QOIThumbnailIsEnabled}" />
|
||||
</controls:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="GPO_IsSettingForced"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.IsQOIThumbnailEnabledGpoConfigured}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.IsQOIThumbnailEnabledGpoConfigured}"
|
||||
Severity="Informational" />
|
||||
</custom:SettingsGroup>
|
||||
</StackPanel>
|
||||
</custom:SettingsPageControl.ModuleContent>
|
||||
@ -210,7 +235,7 @@
|
||||
</custom:SettingsPageControl.PrimaryLinks>
|
||||
<custom:SettingsPageControl.SecondaryLinks>
|
||||
<custom:PageLink Link="https://blog.aaron-junker.ch" Text="Aaron Junker's work on developer file preview" />
|
||||
<custom:PageLink Link="https://www.pedrolamas.com" Text="Pedro Lamas's work on G-Code and STL" />
|
||||
<custom:PageLink Link="https://www.pedrolamas.com" Text="Pedro Lamas's work on G-Code, STL, and QOI" />
|
||||
</custom:SettingsPageControl.SecondaryLinks>
|
||||
</custom:SettingsPageControl>
|
||||
</Page>
|
||||
|
@ -1135,6 +1135,21 @@
|
||||
<data name="FileExplorerPreview_Color_Thumbnail_STL.Header" xml:space="preserve">
|
||||
<value>Color</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Preview_QOI.Header" xml:space="preserve">
|
||||
<value>Quite Ok Image</value>
|
||||
<comment>File type, do not translate</comment>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Preview_QOI.Description" xml:space="preserve">
|
||||
<value>.qoi</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Thumbnail_QOI.Header" xml:space="preserve">
|
||||
<value>Quite OK Image</value>
|
||||
<comment>File type, do not translate</comment>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Thumbnail_QOI.Description" xml:space="preserve">
|
||||
<value>.qoi</value>
|
||||
<comment>File extension, should not be altered</comment>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Thumbnail_PDF.Header" xml:space="preserve">
|
||||
<value>Portable Document Format</value>
|
||||
<comment>File type, do not translate</comment>
|
||||
|
@ -129,6 +129,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
_gcodeRenderIsEnabled = Settings.Properties.EnableGcodePreview;
|
||||
}
|
||||
|
||||
_qoiRenderEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredQoiPreviewEnabledValue();
|
||||
if (_qoiRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _qoiRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||
{
|
||||
// Get the enabled state from GPO.
|
||||
_qoiRenderEnabledStateIsGPOConfigured = true;
|
||||
_qoiRenderIsEnabled = _qoiRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
_qoiRenderIsEnabled = Settings.Properties.EnableQoiPreview;
|
||||
}
|
||||
|
||||
_pdfThumbnailEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredPdfThumbnailsEnabledValue();
|
||||
if (_pdfThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _pdfThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||
{
|
||||
@ -166,6 +178,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
|
||||
_stlThumbnailColor = Settings.Properties.StlThumbnailColor.Value;
|
||||
|
||||
_qoiThumbnailEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredQoiThumbnailsEnabledValue();
|
||||
if (_qoiThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _qoiThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||
{
|
||||
// Get the enabled state from GPO.
|
||||
_qoiThumbnailEnabledStateIsGPOConfigured = true;
|
||||
_qoiThumbnailIsEnabled = _qoiThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
_qoiThumbnailIsEnabled = Settings.Properties.EnableQoiThumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
private GpoRuleConfigured _svgRenderEnabledGpoRuleConfiguration;
|
||||
@ -194,6 +218,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private bool _gcodeRenderEnabledStateIsGPOConfigured;
|
||||
private bool _gcodeRenderIsEnabled;
|
||||
|
||||
private GpoRuleConfigured _qoiRenderEnabledGpoRuleConfiguration;
|
||||
private bool _qoiRenderEnabledStateIsGPOConfigured;
|
||||
private bool _qoiRenderIsEnabled;
|
||||
|
||||
private GpoRuleConfigured _svgThumbnailEnabledGpoRuleConfiguration;
|
||||
private bool _svgThumbnailEnabledStateIsGPOConfigured;
|
||||
private bool _svgThumbnailIsEnabled;
|
||||
@ -211,6 +239,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private bool _stlThumbnailIsEnabled;
|
||||
private string _stlThumbnailColor;
|
||||
|
||||
private GpoRuleConfigured _qoiThumbnailEnabledGpoRuleConfiguration;
|
||||
private bool _qoiThumbnailEnabledStateIsGPOConfigured;
|
||||
private bool _qoiThumbnailIsEnabled;
|
||||
|
||||
public bool SVGRenderIsEnabled
|
||||
{
|
||||
get
|
||||
@ -616,6 +648,64 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool QOIRenderIsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _qoiRenderIsEnabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_qoiRenderEnabledStateIsGPOConfigured)
|
||||
{
|
||||
// If it's GPO configured, shouldn't be able to change this state.
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != _qoiRenderIsEnabled)
|
||||
{
|
||||
_qoiRenderIsEnabled = value;
|
||||
Settings.Properties.EnableQoiPreview = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsQOIRenderEnabledGpoConfigured
|
||||
{
|
||||
get => _qoiRenderEnabledStateIsGPOConfigured;
|
||||
}
|
||||
|
||||
public bool QOIThumbnailIsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _qoiThumbnailIsEnabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_qoiThumbnailEnabledStateIsGPOConfigured)
|
||||
{
|
||||
// If it's GPO configured, shouldn't be able to change this state.
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != _qoiThumbnailIsEnabled)
|
||||
{
|
||||
_qoiThumbnailIsEnabled = value;
|
||||
Settings.Properties.EnableQoiThumbnail = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsQOIThumbnailEnabledGpoConfigured
|
||||
{
|
||||
get => _qoiThumbnailEnabledStateIsGPOConfigured;
|
||||
}
|
||||
|
||||
public string GetSettingsSubPath()
|
||||
{
|
||||
return _settingsConfigFileFolder + "\\" + ModuleName;
|
||||
|
@ -30,6 +30,8 @@ std::vector<std::wstring> processes =
|
||||
L"PowerToys.MonacoPreviewHandler.exe",
|
||||
L"PowerToys.PdfPreviewHandler.exe",
|
||||
L"PowerToys.PdfThumbnailProvider.exe",
|
||||
L"PowerToys.QoiPreviewHandler.exe",
|
||||
L"PowerToys.QoiThumbnailProvider.exe",
|
||||
L"PowerToys.StlThumbnailProvider.exe",
|
||||
L"PowerToys.SvgPreviewHandler.exe",
|
||||
L"PowerToys.SvgThumbnailProvider.exe",
|
||||
|
@ -17,6 +17,7 @@ namespace
|
||||
{ HKEY_CLASSES_ROOT, L"AppID\\{CF142243-F059-45AF-8842-DBBE9783DB14}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{07665729-6243-4746-95b7-79579308d1b2}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{ec52dea8-7c9f-4130-a77b-1737d0418507}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{8AA07897-C30B-4543-865B-00A0E5A1B32D}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{BCC13D15-9720-4CC4-8371-EA74A274741E}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{BFEE99B4-B74D-4348-BCA5-E757029647FF}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{8BC8AFC2-4E7C-4695-818E-8C1FFDCEA2AF}" },
|
||||
@ -28,6 +29,8 @@ namespace
|
||||
{ HKEY_CLASSES_ROOT, L".md\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
|
||||
{ HKEY_CLASSES_ROOT, L".pdf\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
|
||||
{ HKEY_CLASSES_ROOT, L".pdf\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" },
|
||||
{ HKEY_CLASSES_ROOT, L".qoi\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
|
||||
{ HKEY_CLASSES_ROOT, L".qoi\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" },
|
||||
{ HKEY_CLASSES_ROOT, L".gcode\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
|
||||
{ HKEY_CLASSES_ROOT, L".gcode\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" },
|
||||
{ HKEY_CLASSES_ROOT, L".stl\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }
|
||||
@ -38,6 +41,7 @@ namespace
|
||||
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}" },
|
||||
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{07665729-6243-4746-95b7-79579308d1b2}" },
|
||||
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{ec52dea8-7c9f-4130-a77b-1737d0418507}" },
|
||||
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{8AA07897-C30B-4543-865B-00A0E5A1B32D}" },
|
||||
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"prevhost.exe" },
|
||||
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"dllhost.exe" }
|
||||
};
|
||||
|
@ -64,5 +64,7 @@ void ReportGPOValues(const std::filesystem::path& tmpDir)
|
||||
report << "getSuspendNewUpdateToastValue: " << gpo_rule_configured_to_string(powertoys_gpo::getSuspendNewUpdateToastValue()) << std::endl;
|
||||
report << "getDisablePeriodicUpdateCheckValue: " << gpo_rule_configured_to_string(powertoys_gpo::getDisablePeriodicUpdateCheckValue()) << std::endl;
|
||||
report << "getAllowExperimentationValue: " << gpo_rule_configured_to_string(powertoys_gpo::getAllowExperimentationValue()) << std::endl;
|
||||
report << "getConfiguredQoiPreviewEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredQoiPreviewEnabledValue()) << std::endl;
|
||||
report << "getConfiguredQoiThumbnailsEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredQoiThumbnailsEnabledValue()) << std::endl;
|
||||
|
||||
}
|
||||
|
@ -15,12 +15,13 @@ function PublicStaticVoidMain {
|
||||
[String] $MachineWideHandler
|
||||
}
|
||||
|
||||
[String[]]$TypesToCheck = @(".markdown", ".mdtext", ".mdtxt", ".mdown", ".mkdn", ".mdwn", ".mkd", ".md", ".svg", ".svgz", ".pdf", ".gcode", ".stl", ".txt", ".ini")
|
||||
[String[]]$TypesToCheck = @(".markdown", ".mdtext", ".mdtxt", ".mdown", ".mkdn", ".mdwn", ".mkd", ".md", ".svg", ".svgz", ".pdf", ".gcode", ".stl", ".txt", ".ini", ".qoi")
|
||||
$IPREVIEW_HANDLER_CLSID = '{8895b1c6-b41f-4c1c-a562-0d564250836f}'
|
||||
$PowerToysHandlers = @{
|
||||
'{07665729-6243-4746-95b7-79579308d1b2}' = "PowerToys PDF handler"
|
||||
'{ddee2b8a-6807-48a6-bb20-2338174ff779}' = "PowerToys SVG handler"
|
||||
'{ec52dea8-7c9f-4130-a77b-1737d0418507}' = "PowerToys GCode handler"
|
||||
'{8AA07897-C30B-4543-865B-00A0E5A1B32D}' = "PowerToys QOI handler"
|
||||
'{45769bcc-e8fd-42d0-947e-02beef77a1f5}' = "PowerToys Markdown handler"
|
||||
'{afbd5a44-2520-4ae0-9224-6cfce8fe4400}' = "PowerToys Monaco fallback handler"
|
||||
'{DC6EFB56-9CFA-464D-8880-44885D7DC193}' = "Adobe Acrobat DC"
|
||||
|
Loading…
Reference in New Issue
Block a user