OpenFileName对话框返回亚洲字母而不是文件路径

OPENFILENAME dialog returns Asian letters instead of file path

本文关键字:文件 路径 对话框 返回 OpenFileName      更新时间:2023-10-16

我正在尝试创建一个函数,该函数从OpenFileName对话框中获取filepath。我的代码看起来像这样。

wstring src;
bool open()
{
    const string title  = "Select a File";
    wchar_t filename[MAX_PATH];
    OPENFILENAMEA ofn;
    ZeroMemory(&filename, sizeof(filename));
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize     = sizeof(ofn);
    ofn.hwndOwner       = NULL; 
    ofn.lpstrFilter     = "Music (.mp3)*.mp3All*.*";
    ofn.lpstrFile       = LPSTR(filename);
    ofn.nMaxFile        = MAX_PATH;
    ofn.lpstrTitle      = title.c_str();
    ofn.Flags           = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
    if (GetOpenFileNameA(&ofn))
    {
        src = filename;    //<----------Save filepath in global variable
        return true;
    }
    return false;
}

将断点放在评论的行上后,我可以检查" src"的价值以及"文件名",这对我来说,这是亚洲血统的不可识别的来信。为什么会发生这种情况?这是转换问题吗?

编辑:

多亏了快速答复和一些评论,该代码现在已完全函数。感谢Hans Passant提供了非常直接的解决方案,也要感谢Cody Gray重写该功能,解释了错误,并为我提供了应该如何处理的课程。由于我仍在采取第一步学习Winapi,因此这些信息将在以后的计划中为我提供良好的服务。

这是由混合ANSI和Unicode字符类型引起的经典错误。正如您所描述的那样

快速浏览您的代码,立即揭示了问题。您正在调用win32函数的ANSI版本(GetOpenFileNameA),并使用数据结构的ANSI版本-OPENFILENAMEA - yet您的filename数组由宽字符组成(wchar_t)。在Win32中,A-填充类型始终是ANSI,需要使用1字节char类型。W-填充类型始终是Unicode,需要使用2字节wchar_t类型。如果没有明确的转换,则无法使用MultiByteToWideChar和/或WideCharToMultiByte。进行混合。。

请注意,如果您没有使用明确的铸件将其关闭,则编译器会捕获此类型的不匹配错误。

在现代时代,您应该始终使用W -Suffed API,因为您始终想支持Unicode。世界不是ASCII,当每个人都切换到Windows NT和Windows 98/Me已死并埋葬时,Windows ANSI编码变得过时了。

因此,请按以下方式重写您的代码(我也借此自由来更改其他一些习语并以其他方式清理代码,例如将C 语言构造用于零内存):

std::wstring src;
bool open()
{
    const std::wstring title = L"Select a File";
    std::wstring filename(MAX_PATH, L'');
    OPENFILENAMEW ofn = { };
    ofn.lStructSize     = sizeof(ofn);
    ofn.hwndOwner       = NULL; 
    ofn.lpstrFilter     = L"Music (.mp3)*.mp3All*.*";
    ofn.lpstrFile       = &filename[0];  // use the std::wstring buffer directly
    ofn.nMaxFile        = MAX_PATH;
    ofn.lpstrTitle      = title.c_str();
    ofn.Flags           = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
    if (GetOpenFileNameW(&ofn))
    {
        src = filename;    //<----------Save filepath in global variable
        return true;
    }
    return false;
}

为了避免每次明确键入W的需要,请确保UNICODE_UNICODE均为您的项目定义。最好的方法是使用项目属性,您可以在其中预先定义这些符号。否则,您可以在预编译标头的顶部定义它们。这样可以确保即使省略后缀,始终使用的 W -suffix suffix suffix变体始终使用。因此,您可以简单地说GetOpenFileNameOPENFILENAME。Windows标题文件中的宏处理分辨率。

这样的优点是,如果您忘记将L前缀的宽串文字前缀前缀前缀,则会导致编译器产生类型的不匹配错误,如果您还没有这样做的习惯,这是一个常见的错误。(当然,这也假定您还摆脱了使用明确的演员来沉默编译器警告的坏习惯,因为您可以通过这样做来轻松击败此安全网。)