返回时c ++ win32api值编码损坏

abd*_*doe 0 c++ winapi encoding callback

我几乎不知道如何描述这种行为,所以这可能是我无法自己找到答案的原因 - 我根本就不知道如何命名这个问题.所以,如果标题是误导性的,或者问题在某种程度上是错误的,请耐心等待,但是这里来了

我有一个类方法,我打开一个文件并获取文件名:

OPENFILENAME GuiUtils::ChooseFileDialog(HWND hwnd)
{
    OPENFILENAME ofn;
    char szFile[260];
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = (LPWSTR)szFile;
    ofn.lpstrFile[0] = '\0';
    ofn.nMaxFile = sizeof(szFile);
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0");
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    HANDLE hf;

    // Display the Open dialog box. 
    if (GetOpenFileName(&ofn) == TRUE)
    {
        hf = CreateFile(ofn.lpstrFile,
            GENERIC_READ,
            0,
            (LPSECURITY_ATTRIBUTES)NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            (HANDLE)NULL);
    }
    return ofn;
}
Run Code Online (Sandbox Code Playgroud)

当我看到ofn.lpstrFile一切看起来正确编码 在此输入图像描述

当我继续使用我的调试器并跳回调用函数时,有些东西搞砸了:

调用类方法:

INT_PTR CALLBACK FormCreator::Callback(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
    switch (Message)
    {
    case WM_COMMAND:
        if (LOWORD(wParam) == IDCHOOSEFILE)
        {
            GuiUtils *guiUtils = new GuiUtils();
            OPENFILENAME ofn = guiUtils->ChooseFileDialog(hwnd);
            ORMFactory* db = new ORMFactory(); // value in debugger changes here
            AbstractORM* sqlite = db->GetORMProvider(TEXT("SQLITE"));
            this->databaseFileName = (wstring)ofn.lpstrFile;
        }
        break;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

有人可以让我知道这里有什么问题ofn.lpstrFile以及如何解决这个问题?

谢谢

Rem*_*eau 6

您使用的是Unicode版本GetOpenFileName(),但是您为其提供了一个ANSI缓冲区来存储所选的文件名.在将lpstrFile字段分配给字段时,您将对缓冲区进行类型转换,隐藏可能会提醒您不匹配的编译器错误.

您需要将缓冲区更改charwchar_t并删除类型转换.

但是,即使您修复了此问题,代码中也会出现其他错误.

您将填充填充OPENFILENAME到调用者,但它仍然指向ChooseFileDialog()退出时超出范围的本地缓冲区.因此,当调用者访问该lpstrFile字段时,它正在调用未定义的行为.

ChooseFileDialog()每次GetOpenFileName()成功时都会泄漏文件句柄.您没有对文件句柄执行任何操作,并且您没有关闭它.因此,您根本不应该打开文件

而且你在回调中泄漏动态的alloxated对象.

尝试更像这样的东西:

std::wstring GuiUtils::ChooseFileDialog(HWND hwnd)
{
    OPENFILENAMEW ofn;
    wchar_t szFile[MAX_PATH];
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = szFile;
    ofn.lpstrFile[0] = '\0';
    ofn.nMaxFile = MAX_PATH;
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    HANDLE hf;

    // Display the Open dialog box. 
    if (!GetOpenFileNameW(&ofn))
        return L"";

    // what is this for???
    /*
    hf = CreateFileW(ofn.lpstrFile,
            GENERIC_READ,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL);
    */

    return ofn.lpstrFile;
}

INT_PTR CALLBACK FormCreator::Callback(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
    switch (Message)
    {
    case WM_COMMAND:
        if (LOWORD(wParam) == IDCHOOSEFILE)
        {
            GuiUtils guiUtils;
            std::wstring fname = guiUtils.ChooseFileDialog(hwnd);
            if (fname.empty()) break;
            ORMFactory db;
            AbstractORM* sqlite = db.GetORMProvider(L"SQLITE");
            this->databaseFileName = fname;
        }
        break;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • @abdoe这不是编码问题.这是对API的公然滥用.您对内存和数据类型管理不善.调用者屏幕截图中显示的错误是由于检查不再有效的内存. (2认同)