From cd96a949e8ff4f60edf93cc7686c488fd0ba0b13 Mon Sep 17 00:00:00 2001 From: Valentin Radu Date: Mon, 28 Mar 2022 20:36:17 +0300 Subject: [PATCH] File Explorer: Classic drive groupings do not require a restart --- ExplorerPatcher/dllmain.c | 49 +++++++++++++++++----------------- ExplorerPatcher/settings.reg | 2 +- ExplorerPatcher/settings10.reg | 2 +- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index a00af05..7554c8d 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -7942,7 +7942,7 @@ HINSTANCE explorer_ShellExecuteW( #pragma region "Classic Drive Grouping" - +#ifdef _WIN64 const struct { DWORD dwDescriptionId; UINT uResourceId; } driveCategoryMap[] = { { SHDID_FS_DIRECTORY, 9338 }, //shell32 { SHDID_COMPUTER_SHAREDDOCS, 9338 }, //shell32 @@ -8168,7 +8168,7 @@ HRESULT(STDMETHODCALLTYPE *shell32_DriveTypeCategorizer_CreateInstanceFunc)(IUnk HRESULT shell32_DriveTypeCategorizer_CreateInstanceHook(IUnknown* pUnkOuter, REFIID riid, void** ppvObject) { - if (IsEqualIID(riid, &IID_ICategorizer)) + if (bUseClassicDriveGrouping && IsEqualIID(riid, &IID_ICategorizer)) { EPCategorizer* epCategorizer = (EPCategorizer*) malloc(sizeof(EPCategorizer)); epCategorizer->categorizer = &EPCategorizer_categorizerVtbl; @@ -8200,6 +8200,7 @@ HRESULT ExplorerFrame_CoCreateInstanceHook(REFCLSID rclsid, LPUNKNOWN pUnkOuter, } return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); } +#endif #pragma endregion @@ -9830,6 +9831,7 @@ DWORD Inject(BOOL bIsExplorer) hShell32 = GetModuleHandleW(L"shell32.dll"); if (hShell32) { + // Patch ribbon to handle redirects to classic CPLs HRESULT(*SHELL32_Create_IEnumUICommand)(IUnknown*, int*, int, IUnknown**) = GetProcAddress(hShell32, (LPCSTR)0x2E8); if (SHELL32_Create_IEnumUICommand) { @@ -9862,35 +9864,32 @@ DWORD Inject(BOOL bIsExplorer) } } - if (bUseClassicDriveGrouping) + // Allow clasic drive groupings in This PC + HRESULT(*SHELL32_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv) = GetProcAddress(hShell32, "DllGetClassObject"); + if (SHELL32_DllGetClassObject) { - HRESULT(*SHELL32_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv) = GetProcAddress(hShell32, "DllGetClassObject"); + IClassFactory* pClassFactory = NULL; + SHELL32_DllGetClassObject(&CLSID_DriveTypeCategorizer, &IID_IClassFactory, &pClassFactory); - if (SHELL32_DllGetClassObject) + if (pClassFactory) { - IClassFactory* pClassFactory; - SHELL32_DllGetClassObject(&CLSID_DriveTypeCategorizer, &IID_IClassFactory, &pClassFactory); - - if (pClassFactory) - { - //DllGetClassObject hands out a unique "factory entry" data structure for each type of CLSID, containing a pointer to an IClassFactoryVtbl as well as some other members including - //the _true_ create instance function that should be called (in this instance, shell32!CDriveTypeCategorizer_CreateInstance). When the IClassFactory::CreateInstance method is called, - //shell32!ECFCreateInstance will cast the IClassFactory* passed to it back into a factory entry, and then invoke the pfnCreateInstance function defined in that entry directly. - //Thus, rather than hooking the shared shell32!ECFCreateInstance function found on the IClassFactoryVtbl* shared by all class objects returned by shell32!DllGetClassObject, we get the real - //CreateInstance function that will be called and hook that instead - Shell32ClassFactoryEntry* pClassFactoryEntry = (Shell32ClassFactoryEntry*)pClassFactory; + //DllGetClassObject hands out a unique "factory entry" data structure for each type of CLSID, containing a pointer to an IClassFactoryVtbl as well as some other members including + //the _true_ create instance function that should be called (in this instance, shell32!CDriveTypeCategorizer_CreateInstance). When the IClassFactory::CreateInstance method is called, + //shell32!ECFCreateInstance will cast the IClassFactory* passed to it back into a factory entry, and then invoke the pfnCreateInstance function defined in that entry directly. + //Thus, rather than hooking the shared shell32!ECFCreateInstance function found on the IClassFactoryVtbl* shared by all class objects returned by shell32!DllGetClassObject, we get the real + //CreateInstance function that will be called and hook that instead + Shell32ClassFactoryEntry* pClassFactoryEntry = (Shell32ClassFactoryEntry*)pClassFactory; - DWORD flOldProtect = 0; + DWORD flOldProtect = 0; - if (VirtualProtect(pClassFactoryEntry, sizeof(Shell32ClassFactoryEntry), PAGE_EXECUTE_READWRITE, &flOldProtect)) - { - shell32_DriveTypeCategorizer_CreateInstanceFunc = pClassFactoryEntry->pfnCreateInstance; - pClassFactoryEntry->pfnCreateInstance = shell32_DriveTypeCategorizer_CreateInstanceHook; - VirtualProtect(pClassFactoryEntry, sizeof(Shell32ClassFactoryEntry), flOldProtect, &flOldProtect); - } - - pClassFactory->lpVtbl->Release(pClassFactory); + if (VirtualProtect(pClassFactoryEntry, sizeof(Shell32ClassFactoryEntry), PAGE_EXECUTE_READWRITE, &flOldProtect)) + { + shell32_DriveTypeCategorizer_CreateInstanceFunc = pClassFactoryEntry->pfnCreateInstance; + pClassFactoryEntry->pfnCreateInstance = shell32_DriveTypeCategorizer_CreateInstanceHook; + VirtualProtect(pClassFactoryEntry, sizeof(Shell32ClassFactoryEntry), flOldProtect, &flOldProtect); } + + pClassFactory->lpVtbl->Release(pClassFactory); } } } diff --git a/ExplorerPatcher/settings.reg b/ExplorerPatcher/settings.reg index 992716d..59f3d34 100644 --- a/ExplorerPatcher/settings.reg +++ b/ExplorerPatcher/settings.reg @@ -162,7 +162,7 @@ ;d Disable the Windows 11 context menu * @="" [HKEY_CURRENT_USER\Software\ExplorerPatcher] -;b Use classic drive groupings in This PC * +;b Use classic drive groupings in This PC "UseClassicDriveGrouping"=dword:00000000 [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;c 3 Control Interface * diff --git a/ExplorerPatcher/settings10.reg b/ExplorerPatcher/settings10.reg index f192edf..b151429 100644 --- a/ExplorerPatcher/settings10.reg +++ b/ExplorerPatcher/settings10.reg @@ -145,7 +145,7 @@ ;b Register as shell extension ;"Virtualized_{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}_RegisterAsShellExtension"=dword:00000000 [HKEY_CURRENT_USER\Software\ExplorerPatcher] -;b Use classic drive groupings in This PC * +;b Use classic drive groupings in This PC "UseClassicDriveGrouping"=dword:00000000 [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;c 2 Control Interface