【问题标题】:How to create a dialog to select multiple files using winapi?如何使用winapi创建一个选择多个文件的对话框?
【发布时间】:2014-11-26 08:56:33
【问题描述】:

如何创建具有多文件选择可能性的正常文件打开对话框?我正在使用 GetOpenFileName() 函数打开一个对话框。

如果我将OFN_ALLOWMULTISELECT 设置为Flags,它会给我这样的对话框:

这不是我想要的,原因有很多。

我希望它看起来像这样:

是否有任何简单/容易的解决方案,还是我必须自己重新创建整个对话框?

编辑:这是我打开对话框的代码:

OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = "selectfile";
ofn.nMaxFile = 260;
ofn.lpstrFilter = "t1\0test1\0t2\0test2\0";
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.nFilterIndex = 1;
ofn.Flags = OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
ofn.lpstrTitle = TEXT("title");
GetOpenFileName(&ofn);

【问题讨论】:

    标签: c++ winapi visual-c++ windows-7


    【解决方案1】:

    您必须包含OFN_EXPLORER 标志以及OFN_ALLOWMULTISELECT 标志。

    使用GetOpenFileName 的缺点是您必须为所选文件分配缓冲区。因此这意味着您需要在显示对话框之前决定缓冲区应该有多大。这具有限制可以选择的文件数量的效果。

    在 Vista 及更高版本上,您可以使用 common item dialog 代替 GetOpenFileName。新的公共项目对话框的许多改进之一是调用者不分配缓冲区。因此可以选择的文件数量没有限制。


    您的代码的一个相当严重的问题是您没有分配缓冲区。你写道:

    ofn.lpstrFile = "selectfile";
    

    提供只读字符串文字而不是可变缓冲区。在继续之前,您需要解决该问题。此代码显示了显示支持多选的文件对话框所需的最低限度:

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

    【讨论】:

    • 成功了。奇怪的是,一旦我将OFN_EXPLORER 添加到示例代码中,我就设法使程序崩溃(退出后)。但在我的完整代码中,出于某种原因,它似乎工作正常。可能扩展列表生成不正确(我在完整版中使用自己的函数来执行此操作)。
    • 是的,示例代码有一个令人讨厌的错误,我将在答案的第二部分中介绍。
    • 啊,谢谢,我担心我的代码有更大的问题。我从完整版创建了代码 sn-p 以提供尽可能少的“工作”代码。
    • 没关系。你做了一个很好的简短例子,非常感谢。
    • FWIW,初始化结构的惯用方式如下:OPENFILENAME ofn = { sizeof ofn }; 设置第一个成员,默认初始化所有其他成员。
    【解决方案2】:

    使用多选打开文件对话框,工作示例

    #include <windows.h>
    #include <stdio.h>
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {
    OPENFILENAME ofn={0};
    char szFile[MAX_PATH + 1] = {0};
    char szDirect[MAX_PATH + 1] = {0}; 
    int fCount=0;   
    
    switch(iMsg)
        {
        case WM_CREATE:
        return 0;
    
        case WM_KEYDOWN:
        //(int)wParam - virtual key code, lParam - key data
        switch((int)wParam)
            {
            case VK_ESCAPE:
            PostQuitMessage(0);
            break;
            
            case VK_F1:
            ofn.lStructSize = sizeof(ofn);
            ofn.hwndOwner = hwnd;   
            ofn.lpstrFile = szDirect;
            *(ofn.lpstrFile) = 0;
            ofn.nMaxFile = MAX_PATH;
            
            //file type filter, \0 - null character (end of string)
            ofn.lpstrFilter = "All Files\0*.*\0Compressed Zip\0*.ZIP\0Text .txt\0*.TXT\0";
            
            ofn.nFilterIndex = 1;
            ofn.lpstrFileTitle = szFile;
            *(ofn.lpstrFileTitle) = 0;
            ofn.nMaxFileTitle = sizeof(szFile);
            ofn.lpstrInitialDir = NULL;
            ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT;
    
            //show dialog Open
            if (GetOpenFileName(&ofn)==TRUE) 
            {
            printf("files selected\n");
            char* ptr = ofn.lpstrFile;
            ptr[ofn.nFileOffset-1] = 0;
            printf("Directory path: %s\n", ptr);
            ptr += ofn.nFileOffset;
            
            while (*ptr)
                {
                fCount++;           
                printf("File: %i %s\n", fCount, ptr);
                ptr += (lstrlen(ptr)+1);
                }
                
            printf("\n");               
            printf("selected %i files\n", fCount);  
            }
            else
            {
            printf("no files selected\n");
            }
            
            break;
            case VK_F2:
            //GetSaveFileName() for example 
            break;          
            }
        break;  
    
        case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
        }
    
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
    //class name
    static char szAppName[] = "HelloWin";
    HWND hwnd;
    MSG msg;
    
    //declare class variable wc 
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; 
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;
    
    //register class variable wc 
    RegisterClass(&wc);
    
    //create window
    hwnd = CreateWindow
    (szAppName, "Standard Window", WS_OVERLAPPEDWINDOW, 
    100, 100, 600, 400, NULL, NULL, hInstance, NULL);
    
    //show window
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    
    while(GetMessage(&msg, NULL, 0, 0))
      {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
      }
    return msg.wParam;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多