Classic file picker (second method)
Jan 7, 2024 15:54:04 GMT -8
Post by Deleted on Jan 7, 2024 15:54:04 GMT -8
The common dialog library (comdlg32) has a function "IsCommonItemDialogAvailable" that checks for the theme property flags, if the property flags of the application are STAP_ALLOW_NONCLIENT (1 << 0) the function returns 0, this function is used for determining what dialog resource to use.
CLSID redirection is not really needed, both of CLSID are calling CFileOpenSave::s_CreateInstance from the library with different flags, we can hook into the function and change the flags to the "legacy" ones. This way .NET programs (maybe other programs) will get the COM interface that its expecting.
Custom controls should work since the "legacy" dialog is still using the new CFileOpenSave class and every function is implemented to work depending on what dialog resource is being used, the controls are indeed created in the window handle, but they are out of bounds, i still need to take a look how they work more indepth.
CLSID redirection is not really needed, both of CLSID are calling CFileOpenSave::s_CreateInstance from the library with different flags, we can hook into the function and change the flags to the "legacy" ones. This way .NET programs (maybe other programs) will get the COM interface that its expecting.
Custom controls should work since the "legacy" dialog is still using the new CFileOpenSave class and every function is implemented to work depending on what dialog resource is being used, the controls are indeed created in the window handle, but they are out of bounds, i still need to take a look how they work more indepth.
Update: now should work with all dialogs
Here is the mod that works without the need of classic theme and works on .NET programs:
// ==WindhawkMod==
// @id classic-file-picker2
// @name Classic File Picker2
// @description Redirect the Windows Vista+ file picker to the Windows XP one
// @version 0.1
// @include *
// ==/WindhawkMod==
#include <windhawk_utils.h>
#ifdef _WIN64
#define THISCALL __cdecl
#else
#define THISCALL __thiscall
#endif
typedef int (THISCALL *IsCommonItemDialogAvailable)(void);
IsCommonItemDialogAvailable IsCommonItemDialogAvailable_orig;
int THISCALL IsCommonItemDialogAvailable_hook(void) {
return 0;
}
typedef long (THISCALL *CFileOpenSave__s_CreateInstance)(int, GUID*, void**);
CFileOpenSave__s_CreateInstance CFileOpenSave__s_CreateInstance_orig;
long THISCALL CFileOpenSave__s_CreateInstance_hook(int param_1, GUID *param_2, void **param_3) {
param_1 = (param_1 > 1) ? param_1 -= 2 : param_1;
return CFileOpenSave__s_CreateInstance_orig(param_1, param_2, param_3);
}
BOOL Wh_ModInit() {
HMODULE module = LoadLibrary(L"comdlg32.dll");
if (!module) {
Wh_Log(L"comdlg32.dll not detected");
return FALSE;
}
#ifdef _WIN64
WindhawkUtils::SYMBOL_HOOK symbolHook[] = {
{
{L"int __cdecl IsCommonItemDialogAvailable(void)"},
(void**)&IsCommonItemDialogAvailable_orig,
(void*)IsCommonItemDialogAvailable_hook,
},
{
{L"public: static long __cdecl CFileOpenSave::s_CreateInstance(enum DIALOGINITFLAGS,struct _GUID const &,void * *)"},
(void**)&CFileOpenSave__s_CreateInstance_orig,
(void*)CFileOpenSave__s_CreateInstance_hook,
}
};
#else
WindhawkUtils::SYMBOL_HOOK symbolHook[] = {
{
{L"int __stdcall IsCommonItemDialogAvailable(void)"},
(void**)&IsCommonItemDialogAvailable_orig,
(void*)IsCommonItemDialogAvailable_hook,
},
{
{L"public: static long __stdcall CFileOpenSave::s_CreateInstance(enum DIALOGINITFLAGS,struct _GUID const &,void * *)"},
(void**)&CFileOpenSave__s_CreateInstance_orig,
(void*)CFileOpenSave__s_CreateInstance_hook,
}
};
#endif
if (!WindhawkUtils::HookSymbols(module, symbolHook, ARRAYSIZE(symbolHook))) {
Wh_Log(L"Error hooking");
return FALSE;
}
return TRUE;
}