在 32 位程序中,如何让打开/保存文件对话框显示 64 位系统的 System32 文件夹中的文件?
(Wow64DisableWow64FsRedirection
不起作用,因为由于某种原因它不适用于对话框,我猜是因为它在不同的线程上。当然 usingSysNative
不起作用,因为用户不知道内部发生了什么; 他只想查看计算机上的“实际”文件。)
这是提问的另一种方式:
是否有任何System32
32 位程序从打开文件对话框浏览 64 位文件夹?
在 32 位程序中,如何让打开/保存文件对话框显示 64 位系统的 System32 文件夹中的文件?
(Wow64DisableWow64FsRedirection
不起作用,因为由于某种原因它不适用于对话框,我猜是因为它在不同的线程上。当然 usingSysNative
不起作用,因为用户不知道内部发生了什么; 他只想查看计算机上的“实际”文件。)
这是提问的另一种方式:
是否有任何System32
32 位程序从打开文件对话框浏览 64 位文件夹?
我相信这根本不可能。
即使您可以让对话框显示文件,当它们返回到您的 32 位进程时,它们的名称是什么?Sysnative 有点小技巧,无论如何在 XP 64 上都不可用。这只是重载 system32 名称的结果。
另一个思想实验。如果可能的话,您需要执行枚举的线程来禁用重定向。由于该线程不在您的控制范围内,因此必须有一个已发布的选项来禁用它。没有。允许您从外部禁用重定向是没有好处的,因为当 32 位进程尝试加载 shell 扩展时,这会导致 DLL 加载失败 - 如果您要加载 DLL,则不能禁用重定向,因为您会得到错误的
我想如果你想绕过这个限制,你应该编写一个 64 位程序。
我有一个可行的解决方案。这有点像黑客,但它确实有效。
在我展示解决方案之前的简短免责声明。我基本上同意赫弗曼的观点。这不是应该的。我实际上不建议为运输代码这样做。这是 32 位文本编辑器、文字处理器(包括 32 位 Office)或普通应用程序不支持的东西。64 位系统上的普通用户不会直接在系统目录中打开或保存文件。而且大多数非管理员用户无论如何都没有适当的权限来触摸那里的文件。Microsoft 为 32 位应用程序重定向文件系统有很好的理由。不要试图与之抗争。
现在开始解决方案。
诀窍是在 DllMain 中为每个 DLL_THREAD_ATTACH 回调有一个 DLL 调用 Wow64DisableWow64FsRedirection。
首先创建一个只有 DllMain 并导出几个函数的简单 DLL:“StartDisableRedirect”和“DisableRedirection”。
bool g_fDisableRedirect = false;
__declspec(dllexport)
int DisableRedirection()
{
void* pVoid = NULL;
Wow64DisableWow64FsRedirection(&pVoid);
return 0;
}
__declspec(dllexport)
int StartDisableRedirect()
{
g_fDisableRedirect = true;
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
{
void* pVoid = NULL;
if (g_fDisableRedirect)
{
DisableRedirection();
}
break;
}
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
让您的二进制文件(EXE 或 DLL)直接与此 DLL 链接。然后在调用 GetOpenFileName 之前,调用 StartDisableRedirect(这样后续线程不会被重定向)和 DisableRedirect(对于当前线程)。
我特意制作了一个“开始”函数,以便在钩子实际开始处理线程之前加载所有 DLL(包括系统 DLL)。我不想假设实现 Wow64Disable 的 DLL 会在我的 DLL 之前加载。从 DllMain 调用代码时,您必须非常小心(阅读:不应该)。
extern int StartDisableRedirect();
extern int DisableRedirection();
void OnFile(HWND hwndParent)
{
StartDisableRedirect();
DisableRedirection();
OPENFILENAME ofn = {};
WCHAR szFile[MAX_PATH*2] = {};
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwndParent;
ofn.lpstrFilter = L"All Files\0*.*\0\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFile;
ofn.nMaxFile = ARRAYSIZE(szFile);
ofn.Flags = OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
::GetOpenFileName(&ofn);
}
这是安装人员的常见问题。人们希望为 32 位和 64 位系统提供一个可执行的安装程序,这意味着它必须是 32 位的。然而,32 位安装程序无法将 64 位可执行文件放在正确的位置。正如 Raymond Chen 所描述的,解决方案是拥有一个单独的 64 位安装程序,由 64 位机器上的 32 位版本调用。
您将创建一个 64 位程序,其工作是以您的应用程序窗口作为所有者打开一个通用对话框。在 64 位系统上,您只需创建打开对话框的进程,将您要传递给的参数GetOpenFileName
或其他参数传递给它。您可以在 stdout 上侦听文件名或使用其他 IPC 机制。Wow64DisableWow64FsRedirection
打开返回的文件时记得使用!在另一个进程中运行 UI 可能看起来很笨拙,但它对用户来说是无缝的,并且许多 Web 浏览器在不同的进程中运行不同的选项卡或插件。
如果您可以使用 Vista 或更高版本,您可以使用IFileDialog
允许您为SysNative
目录添加“位置”的界面。这样,您的用户仍然可以在需要时访问这些文件。甚至可能有一种简单的方法来重定向内容,以便当有人单击System32
您将他们带到的目录时SysNative
。