How to get list of selected files when using GetOpenFileName() with multiselect flag?

♀尐吖头ヾ 提交于 2020-01-21 10:21:05

问题


I have tried googling, but people seem to have the same problem: we can't get a list of the selected files.

This is a simple piece of working code that is similar to what I use:

OPENFILENAME ofn = { sizeof ofn };
wchar_t file[1024];
file[0] = '\0';
ofn.lpstrFile = file;
ofn.nMaxFile = 1024;
ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER;
GetOpenFileName(&ofn);

How do I actually get the filenames I selected? Currently I can only get it to work without OFN_ALLOWMULTISELECT flag, so it returns the one selected filename into ofn.lpstrFile. I tried to print out all the string variables inside that struct, but found nothing. It only shows the main folder of the selected files.


回答1:


It looks like the ofn.lpstrFile contains all the filenames, separated with a NULL and ending with another NULL (effectively ending with an empty string).

If the OFN_ALLOWMULTISELECT flag is set and the user selects multiple files, the buffer contains the current directory followed by the file names of the selected files. For Explorer-style dialog boxes, the directory and file name strings are NULL separated, with an extra NULL character after the last file name. For old-style dialog boxes, the strings are space separated and the function uses short file names for file names with spaces. You can use the FindFirstFile function to convert between long and short file names. If the user selects only one file, the lpstrFile string does not have a separator between the path and file name.

From MSDN.

A possible implementation to parse the contents could be;

wchar_t* str = ofn.lpstrFile;
std::wstring directory = str;
str += ( directory.length() + 1 );
while ( *str ) {
  std::wstring filename = str;
  str += ( filename.length() + 1 );
  // use the filename, e.g. add it to a vector
}



回答2:


Checking nFileExtension may NOT be reliable because it can also be 0 if the user entered no file extension (but just the dot, like "file."). I think to distinguish between single and multi file selection one has to check if there is a null character (terminator) at position nFileOffset - 1.




回答3:


Try this:

wchar_t file[1025] = {0}; // room for an extra null terminator, just in case
...
ofn.nMaxFile = 1024;
...
wchar_t* ptr = ofn.lpstrFile;
ptr[ofn.nFileOffset-1] = 0;
std::wcout << L"Directory: " << ptr << std::endl;
ptr += ofn.nFileOffset;
while (*ptr)
{
    std::wcout << L"File: " << ptr << std::endl;
    ptr += (lstrlenW(ptr)+1);
}



回答4:


If you select a single file when using OFN_ALLOWMULTISELECT, the nFileExtension field contains the offset to the extension. If you select multiple files, the nFileExtension field contains 0.

This way you can determine if a single file was selected, and just read/copy the buffer pointed to by the lpstrFile field (which will be a single null terminated string containing the full path and filename including extension)

or if multiple files where selected, then you parse the buffer pointed to by the lpstrFile field, using nFileOffset to read/copy the folder first (using lstrcpyn for example and specifying length to read as the nFileOffset value) and then read/copy from nFileOffset to next null which is file1 string, add the file string length +1 to get next position to read/copy next file string etc till you reach a file string that starts with null - which is the double null for end of all files (as the last string before this is null terminated)




回答5:


Here is a more complete version of the answers by Niall and Remy.

vector<string> &filePaths;

if ( GetOpenFileName( &ofn ) == TRUE )
{
    wchar_t *p = ofn.lpstrFile;
    wstring path = p;
    p += path.size() + 1;
    if ( *p == 0 )
    {
        // there is only one string, being the full path to the file
        filePaths.push_back( ConvertWideCharToUtf8( path.c_str() ) );
    }
    else
    {
        // multiple files follow the directory
        for ( ; *p != 0 ; )
        {
            wstring fileName = p;
            filePaths.push_back( ConvertWideCharToUtf8( ( path + L"\\" + fileName ).c_str() ) );
            p += fileName.size() + 1;
        }
    }
}

Where we also have the function:

string ConvertWideCharToUtf8( const wchar_t *wideText )
{
    int len = WideCharToMultiByte( CP_UTF8, 0, wideText, -1, NULL, 0, NULL, NULL );
    char *buffer = (char *)malloc( len );
    WideCharToMultiByte( CP_UTF8, 0, wideText, -1, buffer, len, NULL, NULL );
    string s = buffer;
    free( buffer );

    return s;
}


来源:https://stackoverflow.com/questions/26317556/how-to-get-list-of-selected-files-when-using-getopenfilename-with-multiselect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!