标签:c++ getopenfilename lpstrfile 多选 设置缓存长度
场景:
1. 使用GetOpenFileName 时, 需要预先自定义lpstrFile的长度比如,buf[1024], 但是如果选择的文件过多怎么办?总不能创建一个超大的内存空间吧,
如果选择少时又浪费内存。
2. 微软的MSDN的坏处就是不提供实际的例子,而在别的地方提供,难道他们没遇到这类普通的问题?
3. 这里stackoverflow提供了一个微软使用lpfnHook 的例子来解决这个问题,这个例子对于unicode是有问题的,计算长度没有x2. 这个bug困扰了我半天。
找这个解决方案也找了半天。
static unsigned int CALLBACK DialogHook(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hwndParentDialog; LPOFNOTIFY lpofn; int cbLength; static LPTSTR lpsz = NULL; static int LastLen; switch (uMsg) { case WM_INITDIALOG: // You need to use a copy of the OPENFILENAME struct used to // create this dialog. You can store a pointer to the // OPENFILENAME struct in the ofn.lCustData so you can // retrieve it here in the lParam. Once you have it, you // need to hang on to it. Using window properties provides a // good thread safe solution to using a global variable. if(!SetProp(GetParent(hwnd), L"OFN", (void *) lParam)) MessageBox(NULL, L"SET PRop Failed", L"ERROR", MB_OK); return (0); case WM_COMMAND: { OutputDebugString(L"command\n"); } break; case WM_NOTIFY: // The OFNOTIFY struct is passed in the lParam of this // message. lpofn = (LPOFNOTIFY) lParam; switch (lpofn->hdr.code) { case CDN_SELCHANGE: LPOPENFILENAME lpofn; cbLength = CommDlg_OpenSave_GetSpec(GetParent(hwnd), NULL, 0); cbLength += _MAX_PATH; // The OFN struct is stored in a property of dialog window lpofn = (LPOPENFILENAME) GetProp(GetParent(hwnd), L"OFN"); if (lpofn->nMaxFile < cbLength) { // Free the previously allocated buffer. if(lpsz) HeapFree(GetProcessHeap(), 0, lpsz); // Allocate a new buffer, 注意要乘以2 lpsz = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbLength*2); if (lpsz) { lpofn->lpstrFile = lpsz; lpofn->nMaxFile = cbLength; } } break; } return (0); case WM_DESTROY: // Also need to free the property with the OPENFILENAME // struct. RemoveProp(GetParent(hwnd), L"OFN"); return (0); } return (0); } void OpenSelectFileWindow(std::vector<std::wstring>& file_paths, const wchar_t* filter,const wchar_t* title) { OPENFILENAME ofn = { sizeof ofn }; wchar_t file[1024]; file[0] = ‘\0‘; ofn.lpstrFile = file; ofn.lpstrFilter = filter; ofn.nMaxFile = 1024; ofn.lpstrTitle = title; ofn.hwndOwner = m_hWnd; ofn.lpfnHook = DialogHook; ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_ENABLEHOOK; BOOL res = GetOpenFileName(&ofn); wchar_t *temp_buf = ofn.lpstrFile; if(res!=0) { size_t len = lstrlen(temp_buf); //文件夹 std::wstring dir; dir.append(temp_buf,len); wchar_t *pos = temp_buf+len; while(*(++pos)) { len = lstrlen(pos); std::wstring path; path.append(dir).append(L"\\").append(pos,len); file_paths.push_back(path); pos+=len; } if(!file_paths.size()) { //只有一个文件时,不会出现目录和文件名分开的情况. file_paths.push_back(dir); } } }
注意: 稍微不负责任点的初级程序员估计会申请超大空间解决吧。
参考:
http://stackoverflow.com/questions/656655/getopenfilename-with-ofn-allowmultiselect-flag-set?rq=1
https://support.microsoft.com/en-us/kb/131462
[WTL/ATL]_[初级]_[如何使用GetOpenFileName多选文件-根据文件名长度计算lpstrFile长度]
标签:c++ getopenfilename lpstrfile 多选 设置缓存长度
原文地址:http://blog.csdn.net/infoworld/article/details/46492415