【问题标题】:32-bit OpenFileDialog --> 64-bit System32?32 位 OpenFileDialog --> 64 位 System32?
【发布时间】:2011-03-09 04:47:29
【问题描述】:

在 32 位程序中,如何让打开/保存文件对话框显示 64 位系统的 System32 文件夹中的文件?

(Wow64DisableWow64FsRedirection 不起作用,因为由于某种原因它不适用于对话框,我猜是因为它在不同的线程上。当然使用 SysNative 不起作用,因为用户不知道内部发生了什么;他只想查看计算机上的“实际”文件。)


这是提问的另一种方式:

任何 32 位程序是否从打开文件对话框浏览 64 位 System32 文件夹?

【问题讨论】:

  • 当你想在system32文件夹中显示文件时,你不应该在对话框中设置正确的初始文件夹吗?
  • @GolezTrol:它适用于文本编辑器(以及我制作的类似应用程序),而 没有(或者更确切地说,不能)有任何用户选择的偏好,但如果他想在System32 中选择一些东西,那么他不能。无论如何,这不是一个真正的解决方案,而只是一种实际上不起作用的解决方法。 (不过感谢您的建议。)
  • 如果你使用 C#,为什么不直接编译 AnyCPU 而不用担心呢?
  • 这不是真正的解决方案:如果您需要在代码中使用 32 位 DLL,它就行不通。这种方法还有更多问题,但基本上整个问题是关于让它在 32 位程序中工作,而不是找到完全绕过这个问题的解决方案。 :(
  • 如果可能的话,你可以期待 Raymond Chen 会在blogs.msdn.com/b/oldnewthing/archive/2010/12/31/10110525.aspx 的后续跟进中提到它

标签: c# .net winapi openfiledialog wow64


【解决方案1】:

我相信这根本不可能。

即使您可以让对话框显示文件,当它们返回到您的 32 位进程时,它们的名称是什么? Sysnative 有点小技巧,在 XP 64 上无论如何都不可用。这只是重载 system32 名称的结果。

另一个思想实验。如果可能的话,您需要执行枚举的线程来禁用重定向。由于该线程不在您的控制范围内,因此必须有一个已发布的选项来禁用它。没有。允许您从外部禁用重定向是没有好处的,因为当 32 位进程尝试加载 shell 扩展时,这会导致 DLL 加载失败 - 如果您要加载 DLL,则不能禁用重定向,因为您会得到错误的

我想如果你想绕过这个限制,你应该编写一个 64 位程序。

【讨论】:

  • 这与禁用重定向后使用标准FindFirstFile API 枚举文件有何不同?它将返回文件的真实名称,简单明了...
  • 如果它将 system32 返回到您的 32 位进程,那么当您访问该文件时,您将被重定向到 syswow64。
  • @David:不,我不会,因为我会禁用重定向...这就是Wow64DisableWow64FsRedirection 的重点。
  • @David:顺便说一句:“不可能”实际上是永远的答案——理论上你总是可以挂钩函数调用和线程创建,例如,但这很痛苦……有更好的方法吗?
  • 禁用重定向在这里不起作用。你已经发现了。解决办法就是停止使用模拟器,像我在回答中说的那样写一个64位的程序。
【解决方案2】:

我有一个可行的解决方案。这是一种 hack,但它确实有效。

在我展示解决方案之前,请先声明一下。我基本上同意赫弗曼的观点。这不是应该的。我实际上不建议为运输代码这样做。这是 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);

}

【讨论】:

  • 哇,太好了! o__o 那么...如何处理系统 DLL 在不同线程中延迟加载的情况(这似乎在第一次加载对话框时几乎发生)?
  • @Mehrdad 它不会。 Shell 扩展将被杀死。
  • @David:我不是真的在谈论 shell 扩展,我是在谈论像Ole32.dll 这样的 常规 DLL,这是 Windows 的正常部分并且会延迟-在每个情况下加载。我很好奇这是如何处理的,因为@selbie 显然说它有效。 :)
  • 我会假设 DLL 加载器不会受到 Wow64DisableRedirect 的影响。如果是这样,那将是一个应用程序错误农场。 YMMV。
  • DLL 加载程序受重定向禁用的影响。这就是文档所说的。
【解决方案3】:

这是安装程序的常见问题。人们希望为 32 位和 64 位系统提供一个可执行的安装程序,这意味着它必须是 32 位的。然而,32 位安装程序无法将 64 位可执行文件放在正确的位置。解决方案as described by Raymond Chen 是拥有一个单独的 64 位安装程序,由 64 位机器上的 32 位版本调用。

您将创建一个 64 位程序,其工作是以您的应用程序窗口作为所有者打开一个通用对话框。在 64 位系统上,您只需创建打开对话框的进程,将您将传递给 GetOpenFileName 的参数传递给它。您可以在 stdout 上侦听文件名或使用其他 IPC 机制。打开返回的文件时记得使用Wow64DisableWow64FsRedirection!在另一个进程中运行 UI 可能看起来很笨拙,但它对用户来说是无缝的,并且许多 Web 浏览器在不同的进程中运行不同的选项卡或插件。

如果您可以使用 Vista 或更高版本,您可以使用 IFileDialog 界面,它允许您为 SysNative 目录添加“位置”。这样,您的用户仍然可以在需要时访问这些文件。甚至可能有一种简单的方法来重定向内容,这样当有人点击System32 目录时,您会将他们带到SysNative

【讨论】:

  • 跨进程的东西对我不起作用,但是关于IFileDialog的有趣想法。
  • @Mehrdad:当你说它不起作用时,你的意思是你不能使用这个解决方案,还是它实际上失败了?
  • 我的意思是前者。 :\ 谢谢你的想法。
猜你喜欢
  • 2010-10-31
  • 2012-10-26
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 2013-06-21
  • 2018-12-29
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多