【问题标题】:GetOpenFileName fails in 64 bit, but works in 32Bit?GetOpenFileName 在 64 位中失败,但在 32 位中有效?
【发布时间】:2011-02-13 05:46:32
【问题描述】:

我有以下代码,我使用 Win32 API 打开文件打开对话框。它在 32 位中运行良好,但在 64 位(在 DLL 中)中使用时失败。我做错了什么?

 char Filestring[256];
Filter = "OBJ files\0*.obj\0\0";
char* returnstring = NULL;



OPENFILENAME opf;
opf.hwndOwner = mainHWND;
opf.lpstrFilter = Filter;
opf.lpstrCustomFilter = 0;
opf.nMaxCustFilter = 0L;
opf.nFilterIndex = 1L;
opf.lpstrFile = Filestring;
opf.lpstrFile[0] = '\0';
opf.nMaxFile = 256;
opf.lpstrFileTitle = 0;
opf.nMaxFileTitle=50;
opf.lpstrInitialDir = Path;
opf.lpstrTitle = "Open Obj File";
opf.nFileOffset = 0;
opf.nFileExtension = 0;
opf.lpstrDefExt = "*.*";
opf.lpfnHook = NULL;
opf.lCustData = 0;
opf.Flags = (OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT) & ~OFN_ALLOWMULTISELECT;
opf.lStructSize = sizeof(OPENFILENAME);

if(GetOpenFileName(&opf))
{
    returnstring = opf.lpstrFile;
    if (returnstring) {
        result = returnstring;
    }

}

编辑:通过失败,我的意思是打开文件对话框没有出现。代码仍然返回零,没有任何错误。

编辑 2:我调用了 CommDlgExtendedError() 并返回 1。从 MSDN 参考中,这是否意味着对话框的 lStructSize 无效?我检查了sizeof(OPENFILENAME),它返回了 140 个字节。

更新:在我的项目设置中,在代码生成下,“结构成员对齐”设置为 4 字节 (/Zp4)。我将其更改为默认值,它神奇地起作用了。请在下面查找答案及其相关信息以获取更多信息。

【问题讨论】:

  • 你是不是偶然调用了Wow64DisableWow64FsRedirection函数(msdn.microsoft.com/en-us/library/aa365743.aspx)?
  • 我不这么认为。整个项目中没有这样的调用。
  • 你能给我们更多的背景信息吗?这是一个什么样的项目?你在哪里使用 DLL?它是编译 到 64 位,还是只是在 64 位版本的 Windows 上运行 32 位 DLL?
  • 您好,我使用的是 Windows 7 64 位,代码在编译的 32 位 DLL 中工作正常,但不适用于编译的 64 位 DLL。 DLL 是另一个主机应用程序的插件。如果有帮助,我将在 (/MT) 静态中编译它们。
  • 您说“它失败了”,但事情不仅失败了,它们还会报告错误。请养成调查这些错误的习惯,并在发帖时将其全部包含在内。

标签: windows winapi 64-bit openfiledialog


【解决方案1】:

您没有初始化lpTemplateName,因此它包含随机堆栈噪声。这反过来会导致“hInstance”成为引用,其中也包含堆栈噪声。

当调用这样的函数时,首先应该将结构清零,并且只填写非零字段。像这样的:

OPENFILENAME opf={0};
opf.lStructSize = sizeof(OPENFILENAME);
opf.hwndOwner = mainHWND;
opf.lpstrFilter = Filter;
opf.nFilterIndex = 1L;
opf.lpstrFile = Filestring;
opf.lpstrFile[0] = '\0';
opf.nMaxFile = 256;
opf.lpstrInitialDir = Path;
opf.lpstrTitle = "Open Obj File";
opf.lpstrDefExt = "*.*";
opf.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;

没有必要明确排除OFN_ALLOWMULTISELECT,因为你一开始就没有包括它!

编辑

您在评论中声明这不起作用。致电CommDlgExtendedError 是个好主意,应该会告诉您失败的原因。

您也可以尝试运行最小的GetOpenFileName,即:

char Filestring[MAX_PATH] = "\0";
OPENFILENAME opf={0};
opf.lStructSize = sizeof(OPENFILENAME);
opf.lpstrFile = Filestring;
opf.nMaxFile = MAX_PATH;
GetOpenFileName(&opf);

【讨论】:

  • 感谢您的信息。我试过这样做,但仍然有同样的问题。代码返回零,但我没有看到任何对话框。
  • 是的,这可能是对的(我实际上并不倾向于阅读问题中的代码墙),但它没有解释为什么它适用于 32 -bit 进程,而不是 64 位进程。
  • @Cody 传递随机统一的堆栈噪声可以解释它。
  • 您好,我调用了 CommDlgExtendedError(),它返回 1。从 MSDN 参考中,这是否意味着对话框的 lStructSize 无效?
  • @gutsblow 控制结构的对齐方式以及它们使用的打包方式。如果您不熟悉这些术语,请阅读 Wikipedia 文章:en.wikipedia.org/wiki/Data_structure_alignment
【解决方案2】:

我有同样的问题和部分解决方案: + 下面的简单示例(建议 abobe)在 x64 模式下不起作用。 + 我将编译选项“struct Member Alignment”从 1byte /Zp1 更改为默认值,从而解决了这个问题(通过介绍其他人!!!)

char 文件字符串[MAX_PATH] = "\0"; OPENFILENAME opf={0}; opf.lStructSize = sizeof(OPENFILENAME); opf.lpstrFile = 文件字符串; opf.nMaxFile = MAX_PATH; GetOpenFileName(&opf);

【讨论】:

    【解决方案3】:

    要了解更多信息,您应该致电CommDlgExtendedError 以获取错误代码是哪里出了问题。除此之外,我会将结构的所有成员初始化为 0

    ZeroMemory(&opf, sizeof(opf));
    

    由于文件打开对话框实际上是一个 COM 组件,因此值得检查一下您的线程单元状态在 64 位下是否不同。

    if( RPC_E_CHANGED_MODE == CoInitialize(NULL) )
       ASSERT(FALSE); // MTA Apartment found
    CoUnitialize()
    

    你的, 阿洛伊斯克劳斯

    【讨论】:

    • OPENFILENAME opf={0} 等价于ZeroMemory。 +1 建议 CommDlgExtendedError。
    • 我不相信 COM 在这里是相关的。 GetOpenFileName 不是 COM 接口,如果我没记错的话可以追溯到 Windows 3.1!无论如何,我相信现代版本确实是在 COM 中实现的,但是如果您通过GetOpenFileName 进入,Windows 会启动许多其他线程并从这些线程中运行 COM。它必须为您处理 COM 初始化,因为 GetOpenFileName 最初打算在不需要 COM 初始化的情况下被调用。
    • 您好,我调用了 CommDlgExtendedError(),它返回 1。从 MSDN 参考中,这是否意味着对话框的 lStructSize 无效?
    • 虽然没关系你可以尝试做 ofn.lStructSize = sizeof(ofn);除此之外,如果示例代码msdn.microsoft.com/en-us/library/… 确实显示相同的问题,我会尝试。如果您对示例代码有同样的问题,那么可能是在 64 位以下,您的内存正在损坏。
    • 他已经完成了ofn.lStructSize = sizeof(ofn);,但问题是这将它设置为 140 而应该是 136。
    【解决方案4】:

    作为 Microsoft Office 2010 64 位的说明,我们放弃并使用内部包装器,因为结构变成了 140 字节,我们不知道如何更改对齐方式。

    Application.GetOpenFilename(FileFilter, FilterIndex, Title, ButtonText, MultiSelect) 和 Application.GetSaveAsFilename(InitialFilename, FileFilter, FilterIndex, Title, ButtonText)

    http://msdn.microsoft.com/en-us/library/ff834966.aspx

    http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel._application.getopenfilename.aspx

    不用说,我们认为所有在 Excel 中使用大量应用程序的人都应该开始考虑其他选项,因为跨多个客户端和平台维护未来版本可能只是......疯了!

    【讨论】:

      【解决方案5】:

      我设法通过在包含头文件之前适当地设置打包来解决这个问题。这样一来,为了实现这一功能,我们使用了“默认”的 16 字节对齐方式,但不必更改程序其余部分的打包对齐方式:

      #ifdef _WIN64
        #pragma pack( push )
        #pragma pack( 16 ) 
        #include "Commdlg.h"
        #pragma pack( pop )
      #else
        #include "Commdlg.h"
      #endif   // _WIN64
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-15
        • 1970-01-01
        • 2014-09-22
        • 2013-03-23
        • 2016-09-27
        • 1970-01-01
        相关资源
        最近更新 更多