TuanVietNam
TuanVietNam

Reputation: 41

C++ Open file dialog in window

I have C++ code to show dialog chooser file. I want to the user can only chooser type file specified. My dialog can show type file specified but the user can input other type file in File name like my picture

enter image description here

So, how can I make the user only input File name and search type file specified in lpstrFilter? OR Can i disable File name box?

This is my code:

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();
    }
}

Upvotes: 4

Views: 9984

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598031

Your code is commenting out the OFN_EXPLORER and OFN_ENABLEHOOK flags, so you must already know about the existence of Explorer-style hooking. As others have told you, you can use that hook to catch the CDN_FILEOK notification to accept/reject a selected filename. For example:

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;
}

Upvotes: 0

David Heffernan
David Heffernan

Reputation: 613461

I want to the user can only chooser type file specified.

You can't stop the user choosing whatever file they like by typing into the file name edit control. So, you should simply let them do that and instead validate that the file name matches your requirements.

You have a couple of options to do that:

  1. Let the dialog return and if the file name does not meet your requirements, present the user with an error dialog letting them know what went wrong.
  2. Supply a hook procedure in the lpfnHook member of the OPENFILENAME struct. That will get sent a CDN_FILEOK notification message when the user attempts to accept a file. Perform your validation in response to that message. If the file name does not meet requirements, show a message to that effect and return a non-zero value to force the dialog to remain open.

Upvotes: 4

Related Questions