C ++在窗口中打开文件对话框

时间:2015-08-28 09:04:02

标签: c++ winapi

我有C ++代码来显示对话框选择器文件。我想用户只能选择指定的类型文件。我的对话框可以显示指定的类型文件,但用户可以在文件名中输入其他类型文件,如我的图片

enter image description here

那么,如何让用户只输入lpstrFilter中指定的文件名和搜索类型文件?或者我可以禁用文件名框吗?

这是我的代码

const wchar_t* ChooserFile(const char* typeFile)
{
    try
    {
        ZeroMemory( &sfn , sizeof( sfn));
        sfn.lStructSize = sizeof ( sfn );
        sfn.hwndOwner = NULL ;
        wchar_t w_syFile[MAX_PATH];
        //mbstowcs(w_syFile, syFile, strlen(syFile)+1);//Plus null
        size_t convertedChars = 0;
        mbstowcs_s(&convertedChars, w_syFile, MAX_PATH, syFile, _TRUNCATE);
        sfn.lpstrFile = w_syFile ;
        sfn.lpstrFile[0] = _T('\0');
        sfn.nMaxFile = sizeof( syFile );

        //TypeFile
        sfn.lpstrFilter = TEXT("Microsoft Office Word Documents (*.xlsx)\0*.XLSX\0");

        sfn.nFilterIndex =1;
        sfn.lpstrFileTitle = NULL ;
        sfn.nMaxFileTitle = 0 ;
        sfn.lpstrInitialDir=NULL;

        //sfn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT|OFN_EXPLORER | OFN_ENABLEHOOK ;
        sfn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_NOVALIDATE|OFN_HIDEREADONLY  ;
        if (GetOpenFileName( &sfn ) != TRUE)
        {
            wstrPathFile = TEXT("");
            return wstrPathFile.c_str();
        }

        DWORD  retval=0;
        //BOOL   success; 
        TCHAR  buffer[BUFSIZE]=TEXT(""); 
        TCHAR  buf[BUFSIZE]=TEXT(""); 
        TCHAR** lppPart={NULL};

        wchar_t wstrPath[BUFSIZE];
        retval = GetFullPathNameW(sfn.lpstrFile,sfn.nMaxFile,wstrPath,lppPart);
        if (retval==0)
        {
            wstrPathFile = TEXT("");
            return wstrPathFile.c_str();
        }
        std::wstring s(wstrPath);
        wstrPathFile = s;
        wcout<<wstrPathFile<<endl;
        return wstrPathFile.c_str();
    }
    catch (...)
    {
        PrintToFile("ChooserFile","Error");
        wstrPathFile = TEXT("");
        return wstrPathFile.c_str();
    }
}

2 个答案:

答案 0 :(得分:4)

  

我想用户只能选择指定的文件类型。

您无法通过在文件名编辑控件中输入来阻止用户选择他们喜欢的任何文件。因此,您应该让他们这样做,而是验证文件名是否符合您的要求。

你有几个选择:

  1. 让对话框返回,如果文件名不符合您的要求,请向用户显示错误对话框,让他们知道出了什么问题。
  2. lpfnHook结构的OPENFILENAME成员中提供钩子过程。当用户尝试接受文件时,会收到CDN_FILEOK通知消息。执行验证以响应该消息。如果文件名不符合要求,则显示该效果的消息并返回非零值以强制对话框保持打开状态。

答案 1 :(得分:0)

您的代码正在评论OFN_EXPLOREROFN_ENABLEHOOK标记,因此您必须已经了解Explorer-style hooking的存在。正如其他人告诉您的那样,您可以使用该钩子来捕获CDN_FILEOK通知以接受/拒绝所选文件名。例如:

UINT_PTR CALLBACK MyOFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
    if (uiMsg == WM_NOTIFY)
    {
        LPOFNOTIFY ofn = (LPOFNOTIFY) lParam;    
        if (ofn->hdr.code == CDN_FILEOK)
        {
            LPOPENFILENAMEW lpOFN = (LPOPENFILENAMEW) ofn->lpOFN;

            LPWSTR lpExt = PathFindExtensionW(lpOFN->lpstrFile);
            if (lstrcmpiW(lpExt, L".XLSX") != 0)
            {
                SetWindowLongPtr(hdlg, DWL_MSGRESULT, 1);
                return 1;
            }
        }
    }

    return 0;
}

std::wstring ChooserFile(const char* typeFile)
{
    OPENFILEAMEW sfn = {0};
    wchar_t w_syFile[MAX_PATH+1] = {0};
    size_t convertedChars = 0;

    sfn.lStructSize = sizeof(sfn);
    sfn.hwndOwner = NULL;
    mbstowcs_s(&convertedChars, w_syFile, MAX_PATH, syFile, _TRUNCATE);
    sfn.lpstrFile = w_syFile;
    sfn.nMaxFile = MAX_PATH;

    //TypeFile
    sfn.lpstrFilter = L"Microsoft Office Word Documents (*.xlsx)\0*.XLSX\0";

    sfn.nFilterIndex = 1;
    sfn.lpstrFileTitle = NULL;
    sfn.nMaxFileTitle = 0;
    sfn.lpstrInitialDir = NULL;

    sfn.lpfnHook = &MyOFNHookProc;

    sfn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOVALIDATE | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLEHOOK;

    if (!GetOpenFileNameW(&sfn))
        return L"";

    WCHAR szPath[MAX_PATH+1] = {0};

    DWORD retval = GetFullPathNameW(sfn.lpstrFile, MAX_PATH, szPath, NULL);
    if ((retval == 0) || (retval > MAX_PATH))
        return L"";

    std::wstring wstrPath(szPath, retval);
    std::wcout << wstrPath << endl;
    return wstrPath;
}