mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-23 21:46:03 +03:00
Allow installation to close shell extension DLLs via the custom action. Disable reboot prompt in case of the version with this change was previously already installed.
Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
parent
7262696846
commit
c1719bc817
11 changed files with 330 additions and 4 deletions
|
@ -23,8 +23,13 @@ set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|||
|
||||
include(${CMAKE_SOURCE_DIR}/NEXTCLOUD.cmake)
|
||||
|
||||
set ( NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME "${APPLICATION_SHORTNAME}_Shxt_CntMenuHndlr_WndClass" )
|
||||
set ( NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME "${APPLICATION_SHORTNAME}_Shxt_Ovs_WndClass" )
|
||||
|
||||
# CfAPI Shell Extensions
|
||||
set( CFAPI_SHELL_EXTENSIONS_LIB_NAME CfApiShellExtensions )
|
||||
|
||||
set ( CFAPI_SHELLEXT_WINDOW_CLASS_NAME "${APPLICATION_SHORTNAME}_${CFAPI_SHELL_EXTENSIONS_LIB_NAME}_WndClass" )
|
||||
|
||||
set( CFAPI_SHELLEXT_APPID_REG "{E314A650-DCA4-416E-974E-18EA37C213EA}")
|
||||
set( CFAPI_SHELLEXT_APPID_DISPLAY_NAME "${APPLICATION_NAME} CfApi Shell Extensions" )
|
||||
|
|
|
@ -60,18 +60,33 @@
|
|||
<FileSearch Id="LegacyUninstallFileName" Name="Uninstall.exe"/>
|
||||
</RegistrySearch>
|
||||
</Property>
|
||||
|
||||
<Property Id="IS_PREV_VERSION_SHELL_EXT_CLOSE_SUPPORTED">
|
||||
<RegistrySearch Id="RegIsPrevVersionShellExtCloseSupported" Type="raw" Root="HKLM" Key="Software\$(var.AppVendor)\$(var.AppName)" Name="isShellExtCloseSupported" Win64="$(var.PlatformWin64)" />
|
||||
</Property>
|
||||
|
||||
<!-- Property to disable update checks -->
|
||||
<Property Id="SKIPAUTOUPDATE" Value="0" />
|
||||
|
||||
<!-- Quit / restart application -->
|
||||
<util:RestartResource ProcessName="$(var.AppExe)" />
|
||||
|
||||
<Property Id="WNDCLASSNAMETOCLOSE" Value="$(var.CfApiShellextWndClassName)" />
|
||||
<CustomAction Id="SetCfApiWindowClassName" Property="WNDCLASSNAMETOCLOSE" Value="$(var.CfApiShellextWndClassName)" />
|
||||
<CustomAction Id="SetNCContextMenuWindowClassName" Property="WNDCLASSNAMETOCLOSE" Value="$(var.NCContextMenuShellextWndClassName)" />
|
||||
<CustomAction Id="SetNCOverlaysWindowClassName" Property="WNDCLASSNAMETOCLOSE" Value="$(var.NCOverlaysShellextWndClassName)" />
|
||||
|
||||
<!-- Helper DLL Custom Actions -->
|
||||
<!-- Helper DLL Custom Actions -->
|
||||
<SetProperty Id="ExecNsisUninstaller" Value=""$(var.AppShortName)" "[NSIS_UNINSTALLEXE]"" Before="ExecNsisUninstaller" Sequence="execute" />
|
||||
<SetProperty Id="RemoveNavigationPaneEntries" Value=""$(var.AppName)"" Before="RemoveNavigationPaneEntries" Sequence="execute" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="SetCfApiWindowClassName" Before="InstallValidate"/>
|
||||
<Custom Action="CloseCfApiShellExtension" After="SetCfApiWindowClassName" />
|
||||
<Custom Action="SetNCContextMenuWindowClassName" After="CloseCfApiShellExtension"/>
|
||||
<Custom Action="CloseNCContextMenuShellExtension" After="SetNCContextMenuWindowClassName" />
|
||||
<Custom Action="SetNCOverlaysWindowClassName" After="CloseNCContextMenuShellExtension"/>
|
||||
<Custom Action="CloseNCOverlaysShellExtension" After="SetNCOverlaysWindowClassName" />
|
||||
<!-- Install: Remove previous NSIS installation, if detected -->
|
||||
<Custom Action="ExecNsisUninstaller" Before="ProcessComponents">NSIS_UNINSTALLEXE AND NOT Installed</Custom>
|
||||
|
||||
|
@ -80,9 +95,8 @@
|
|||
|
||||
<!-- Uninstall: Cleanup the Registry -->
|
||||
<Custom Action="RegistryCleanupCustomAction" After="RemoveFiles">(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
|
||||
|
||||
<!-- Schedule Reboot for the Shell Extensions (in silent installation mode only, or if SCHEDULE_REBOOT argument is set-->
|
||||
<ScheduleReboot After="InstallFinalize">(SCHEDULE_REBOOT=1) OR NOT (UILevel=2)</ScheduleReboot>
|
||||
<!-- Schedule Reboot for the Shell Extensions (only if SCHEDULE_REBOOT argument is set or if th version is less than 3.12.2 -->
|
||||
<ScheduleReboot After="InstallFinalize">(SCHEDULE_REBOOT=1) OR ((NOT (UILevel=2)) AND (NOT IS_PREV_VERSION_SHELL_EXT_CLOSE_SUPPORTED))</ScheduleReboot>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<!-- "Add or Remove" Programs Entries -->
|
||||
|
@ -184,6 +198,11 @@
|
|||
<RegistryValue Type="string" Name="InstallerProductCode" Value="[ProductCode]" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
<Component Id="RegistryMiscInfo" Guid="*" Win64="$(var.PlatformWin64)">
|
||||
<RegistryKey Root="HKLM" Key="Software\$(var.AppVendor)\$(var.AppName)">
|
||||
<RegistryValue Type="integer" Name="isShellExtCloseSupported" Value="1" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
|
||||
<!-- Platform bitness-dependent settings -->
|
||||
<Component Id="RegistryDefaultSettings" Guid="*" Win64="$(var.PlatformWin64)">
|
||||
|
@ -213,6 +232,7 @@
|
|||
<ComponentGroupRef Id="ClientFiles" />
|
||||
|
||||
<ComponentRef Id="RegistryVersionInfo" />
|
||||
<ComponentRef Id="RegistryMiscInfo" />
|
||||
<ComponentRef Id="RegistryDefaultSettings" />
|
||||
<ComponentRef Id="RegistryUriHandler" />
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@
|
|||
|
||||
<?define AppCommandOpenUrlScheme = "@APPLICATION_URI_HANDLER_SCHEME@" ?>
|
||||
|
||||
<?define CfApiShellextWndClassName = "@CFAPI_SHELLEXT_WINDOW_CLASS_NAME@" ?>
|
||||
<?define NCOverlaysShellextWndClassName = "@NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME@" ?>
|
||||
<?define NCContextMenuShellextWndClassName = "@NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME@" ?>
|
||||
|
||||
<!-- Custom license: To use it, also remove the "Skip the license page" stuff in the <UI> section
|
||||
and uncomment <WixVariable Id="WixUILicenseRtf"...
|
||||
<?define AppLicenseRtf = "path\License.rtf" ?>
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
*/
|
||||
|
||||
#include "NCMsiHelper.h"
|
||||
#include <MsiQuery.h>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Sets up logging for MSIs and then calls the appropriate custom action with argc/argv parameters.
|
||||
|
@ -94,6 +96,71 @@ UINT __stdcall RemoveNavigationPaneEntries(MSIHANDLE hInstall)
|
|||
return CustomActionArgcArgv(hInstall, DoRemoveNavigationPaneEntries, "RemoveNavigationPaneEntries");
|
||||
}
|
||||
|
||||
UINT LogMsiInfoMessage(MSIHANDLE hInstall, const TCHAR *format, ...)
|
||||
{
|
||||
TCHAR szFormatted[MAX_PATH];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vswprintf(szFormatted, MAX_PATH, format, args);
|
||||
va_end(args);
|
||||
|
||||
PMSIHANDLE hRecord = ::MsiCreateRecord(1);
|
||||
::MsiRecordSetString(hRecord, 0, szFormatted);
|
||||
|
||||
// we are always logging a message as info, as error will bring a popup that we don't want, just logs
|
||||
return MsiProcessMessage(hInstall, INSTALLMESSAGE_INFO, hRecord);
|
||||
}
|
||||
|
||||
UINT __stdcall CloseWindowByClassName(MSIHANDLE hInstall)
|
||||
{
|
||||
const auto windowClassPropertyName = _T("WNDCLASSNAMETOCLOSE");
|
||||
DWORD windowClassNameSize = 0;
|
||||
if (MsiGetProperty(hInstall, windowClassPropertyName, _T(""), &windowClassNameSize) != ERROR_MORE_DATA) {
|
||||
LogMsiInfoMessage(hInstall,
|
||||
_T("ERROR: Custom action CloseWindowByClassName. MsiGetProperty failed for windowClassPropertyName: %s"),
|
||||
windowClassPropertyName);
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (windowClassNameSize <= 0) {
|
||||
LogMsiInfoMessage(hInstall, _T("ERROR: Custom action CloseWindowByClassName. classNameSize is <= 0!"));
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
++windowClassNameSize;
|
||||
|
||||
std::vector<TCHAR> windowClassNameValue(windowClassNameSize, 0);
|
||||
std::vector<char> vec;
|
||||
const auto getPropertyRes = MsiGetProperty(hInstall, windowClassPropertyName, windowClassNameValue.data(), &windowClassNameSize);
|
||||
if (getPropertyRes != ERROR_SUCCESS) {
|
||||
LogMsiInfoMessage(hInstall, _T("ERROR: Custom action CloseWindowByClassName. MsiGetProperty failed for windowClassPropertyName: %s with code: %d"),
|
||||
windowClassNameValue.data(),
|
||||
getPropertyRes);
|
||||
return getPropertyRes;
|
||||
}
|
||||
|
||||
if (windowClassNameSize <= 0) {
|
||||
LogMsiInfoMessage(hInstall, _T("ERROR: Custom action CloseWindowByClassName. Final classNameSize is <= 0!"));
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
LogMsiInfoMessage(hInstall, _T("Custom action CloseWindowByClassName is running for windowClassNameValue: %s"), windowClassNameValue.data());
|
||||
|
||||
const auto windowToCloseHandle = FindWindow(windowClassNameValue.data(), NULL);
|
||||
if (windowToCloseHandle == NULL) {
|
||||
LogMsiInfoMessage(hInstall, _T("WARNING: Custom action CloseWindowByClassName. windowToCloseHandle is NULL."));
|
||||
// FindWindow will return NULL if the window is not currently running, so not an error
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
LogMsiInfoMessage(hInstall, _T("Custom action CloseWindowByClassName. Sending WM_CLOSE message to windowClassNameValue: %s"), windowClassNameValue.data());
|
||||
|
||||
SendMessage(windowToCloseHandle, WM_CLOSE, 0, 0);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* DllMain - Initialize and cleanup WiX custom action utils.
|
||||
*/
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
EXPORTS
|
||||
CloseWindowByClassName
|
||||
ExecNsisUninstaller
|
||||
RemoveNavigationPaneEntries
|
||||
|
|
|
@ -39,5 +39,24 @@
|
|||
Execute="deferred"
|
||||
Impersonate="yes" />
|
||||
|
||||
<CustomAction Id="CloseCfApiShellExtension"
|
||||
Return="ignore"
|
||||
BinaryKey="NCMsiHelper"
|
||||
DllEntry="CloseWindowByClassName"
|
||||
Execute="immediate"
|
||||
Impersonate="yes" />
|
||||
<CustomAction Id="CloseNCContextMenuShellExtension"
|
||||
Return="ignore"
|
||||
BinaryKey="NCMsiHelper"
|
||||
DllEntry="CloseWindowByClassName"
|
||||
Execute="immediate"
|
||||
Impersonate="yes" />
|
||||
<CustomAction Id="CloseNCOverlaysShellExtension"
|
||||
Return="ignore"
|
||||
BinaryKey="NCMsiHelper"
|
||||
DllEntry="CloseWindowByClassName"
|
||||
Execute="immediate"
|
||||
Impersonate="yes" />
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
|
|
@ -48,6 +48,10 @@
|
|||
|
||||
#cmakedefine BUILD_UPDATER "@BUILD_UPDATER@"
|
||||
|
||||
#cmakedefine CFAPI_SHELLEXT_WINDOW_CLASS_NAME "@CFAPI_SHELLEXT_WINDOW_CLASS_NAME@"
|
||||
#cmakedefine NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME "@NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME@"
|
||||
#cmakedefine NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME "@NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME@"
|
||||
|
||||
#cmakedefine CFAPI_SHELLEXT_APPID_REG "@CFAPI_SHELLEXT_APPID_REG@"
|
||||
#cmakedefine CFAPI_SHELLEXT_APPID_DISPLAY_NAME "@CFAPI_SHELLEXT_APPID_DISPLAY_NAME@"
|
||||
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
HINSTANCE g_hInst = nullptr;
|
||||
long g_cDllRef = 0;
|
||||
|
||||
HWND hHiddenWnd = nullptr;
|
||||
DWORD WINAPI MessageLoopThread(LPVOID lpParameter);
|
||||
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
void CreateHiddenWindowAndLaunchMessageLoop();
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
|
@ -30,6 +35,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
|||
// path of the DLL to register the component.
|
||||
g_hInst = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
CreateHiddenWindowAndLaunchMessageLoop();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
|
@ -122,3 +128,63 @@ STDAPI DllUnregisterServer(void)
|
|||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void CreateHiddenWindowAndLaunchMessageLoop()
|
||||
{
|
||||
const WNDCLASSEX hiddenWindowClass{sizeof(WNDCLASSEX),
|
||||
CS_CLASSDC,
|
||||
HiddenWndProc,
|
||||
0L,
|
||||
0L,
|
||||
GetModuleHandle(NULL),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME,
|
||||
NULL};
|
||||
|
||||
RegisterClassEx(&hiddenWindowClass);
|
||||
|
||||
hHiddenWnd = CreateWindow(hiddenWindowClass.lpszClassName,
|
||||
L"",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
hiddenWindowClass.hInstance,
|
||||
NULL);
|
||||
|
||||
ShowWindow(hHiddenWnd, SW_HIDE);
|
||||
UpdateWindow(hHiddenWnd);
|
||||
|
||||
const auto hMessageLoopThread = CreateThread(NULL, 0, MessageLoopThread, NULL, 0, NULL);
|
||||
if (hMessageLoopThread) {
|
||||
CloseHandle(hMessageLoopThread);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI MessageLoopThread(LPVOID lpParameter)
|
||||
{
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_CLOSE:
|
||||
FreeLibrary(g_hInst);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,11 @@ HINSTANCE instanceHandle = nullptr;
|
|||
|
||||
long dllReferenceCount = 0;
|
||||
|
||||
HWND hHiddenWnd = nullptr;
|
||||
DWORD WINAPI MessageLoopThread(LPVOID lpParameter);
|
||||
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
void CreateHiddenWindowAndLaunchMessageLoop();
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
|
@ -27,6 +32,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
|||
case DLL_PROCESS_ATTACH:
|
||||
instanceHandle = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
CreateHiddenWindowAndLaunchMessageLoop();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
|
@ -175,3 +181,63 @@ STDAPI DllUnregisterServer(void)
|
|||
|
||||
return hResult;
|
||||
}
|
||||
|
||||
void CreateHiddenWindowAndLaunchMessageLoop()
|
||||
{
|
||||
const WNDCLASSEX hiddenWindowClass{sizeof(WNDCLASSEX),
|
||||
CS_CLASSDC,
|
||||
HiddenWndProc,
|
||||
0L,
|
||||
0L,
|
||||
GetModuleHandle(NULL),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME,
|
||||
NULL};
|
||||
|
||||
RegisterClassEx(&hiddenWindowClass);
|
||||
|
||||
hHiddenWnd = CreateWindow(hiddenWindowClass.lpszClassName,
|
||||
L"",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
hiddenWindowClass.hInstance,
|
||||
NULL);
|
||||
|
||||
ShowWindow(hHiddenWnd, SW_HIDE);
|
||||
UpdateWindow(hHiddenWnd);
|
||||
|
||||
const auto hMessageLoopThread = CreateThread(NULL, 0, MessageLoopThread, NULL, 0, NULL);
|
||||
if (hMessageLoopThread) {
|
||||
CloseHandle(hMessageLoopThread);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI MessageLoopThread(LPVOID lpParameter)
|
||||
{
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_CLOSE:
|
||||
FreeLibrary(instanceHandle);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#define OVERLAY_GUID_SYNC L"@WIN_SHELLEXT_OVERLAY_GUID_SYNC@"
|
||||
#define OVERLAY_GUID_WARNING L"@WIN_SHELLEXT_OVERLAY_GUID_WARNING@"
|
||||
|
||||
#cmakedefine NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME L"@NCCONTEXTMENU_SHELLEXT_WINDOW_CLASS_NAME@"
|
||||
#cmakedefine NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME L"@NCOVERLAYS_SHELLEXT_WINDOW_CLASS_NAME@"
|
||||
|
||||
//
|
||||
// Preceding spaces are intended, two spaces to put us ahead of the competition :/
|
||||
//
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "customstateprovider.h"
|
||||
#include "thumbnailprovider.h"
|
||||
#include <comdef.h>
|
||||
#include <tchar.h>
|
||||
|
||||
long dllReferenceCount = 0;
|
||||
long dllObjectsCount = 0;
|
||||
|
@ -25,6 +26,11 @@ HINSTANCE instanceHandle = nullptr;
|
|||
HRESULT CustomStateProvider_CreateInstance(REFIID riid, void **ppv);
|
||||
HRESULT ThumbnailProvider_CreateInstance(REFIID riid, void **ppv);
|
||||
|
||||
HWND hHiddenWnd = nullptr;
|
||||
DWORD WINAPI MessageLoopThread(LPVOID lpParameter);
|
||||
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
void CreateHiddenWindowAndLaunchMessageLoop();
|
||||
|
||||
const VfsShellExtensions::ClassObjectInit listClassesSupported[] = {
|
||||
{&__uuidof(winrt::CfApiShellExtensions::implementation::CustomStateProvider), CustomStateProvider_CreateInstance},
|
||||
{&__uuidof(VfsShellExtensions::ThumbnailProvider), ThumbnailProvider_CreateInstance}
|
||||
|
@ -38,6 +44,8 @@ STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
|
|||
::GetModuleFileName(instanceHandle, dllFilePath, _MAX_PATH);
|
||||
winrt::CfApiShellExtensions::implementation::CustomStateProvider::setDllFilePath(dllFilePath);
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
|
||||
CreateHiddenWindowAndLaunchMessageLoop();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -73,3 +81,66 @@ HRESULT ThumbnailProvider_CreateInstance(REFIID riid, void **ppv)
|
|||
thumbnailProvider->Release();
|
||||
return hresult;
|
||||
}
|
||||
|
||||
void CreateHiddenWindowAndLaunchMessageLoop()
|
||||
{
|
||||
const WNDCLASSEX hiddenWindowClass {
|
||||
sizeof(WNDCLASSEX),
|
||||
CS_CLASSDC,
|
||||
HiddenWndProc,
|
||||
0L,
|
||||
0L,
|
||||
GetModuleHandle(NULL),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
_T(CFAPI_SHELLEXT_WINDOW_CLASS_NAME),
|
||||
NULL
|
||||
};
|
||||
|
||||
RegisterClassEx(&hiddenWindowClass);
|
||||
|
||||
hHiddenWnd = CreateWindow(
|
||||
hiddenWindowClass.lpszClassName,
|
||||
_T(""),
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
hiddenWindowClass.hInstance,
|
||||
NULL);
|
||||
|
||||
ShowWindow(hHiddenWnd, SW_HIDE);
|
||||
UpdateWindow(hHiddenWnd);
|
||||
|
||||
const auto hMessageLoopThread = CreateThread(NULL, 0, MessageLoopThread, NULL, 0, NULL);
|
||||
if (hMessageLoopThread) {
|
||||
CloseHandle(hMessageLoopThread);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI MessageLoopThread(LPVOID lpParameter)
|
||||
{
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_CLOSE:
|
||||
FreeLibrary(instanceHandle);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue