您的位置:首页 > 运维架构

解决CB中TOpenDialog, TOpenPictureDialog打开文件数量有限制的问题

2012-05-23 13:11 381 查看
调用TOpenPictureDialog选择大量图片时候发现,返回的Files里面只有前面的一千多个文件,实际只有我选择文件的一半左右。开始以为是CB的BUG,于是把OpenDialog源码中的MultiSelectBufferSize改大,测试没效果。网上有人说,GetOpenFileName的Ansi版本有32K内存限制,Unicode版本没有限制。实际我的程序已经是Unicode的了。Ansi的API只是进行的字符转换,之后还是调用Unicode版本的API,所以这个方法行不通。

在一个博客里面介绍,可以通过Shell接口自己获取选择的文件,有参考代码,这就好办了,有了解决问题的方向。

那怎么加入CB中呢,直接调用GetOpenFileName? 重写TOpenDialog?都太麻烦了,打开源码,发现有TOpenDialog有个函数void __fastcall GetFileNames(tagOFNW &OpenFileName)是用来取得所选文件的,正好就改它了。这里给出改好的代码,加入工程源码中就可以。

#include <shlobj.h>
#ifndef WM_GETISHELLBROWSER
#define WM_GETISHELLBROWSER (WM_USER+7)
#endif
#define GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
#define GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])

BOOL ILIsFile(LPCITEMIDLIST pidl)
{
BOOL bRet = FALSE;
LPCITEMIDLIST pidlChild = NULL;
IShellFolder* psf = NULL;
HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*) & psf, &pidlChild);
if (SUCCEEDED(hr) && psf)
{
SFGAOF rgfInOut = SFGAO_FOLDER | SFGAO_FILESYSTEM;
hr = psf->GetAttributesOf(1, &pidlChild, &rgfInOut);
if (SUCCEEDED(hr))
{
if ((~rgfInOut & SFGAO_FOLDER) && (rgfInOut & SFGAO_FILESYSTEM))
{
bRet = TRUE;
}
}
psf->Release();
}
return bRet;
}

void __fastcall TOpenDialog::GetFileNames(tagOFNW &OpenFileName)
{
static TStringList *lst = new TStringList;
FORMATETC fmte;
STGMEDIUM stgmedium;
LPITEMIDLIST pidlFull = NULL;
IShellView * pIShellView = NULL;
LPMALLOC pMalloc = NULL;
IDataObject* pIDataObject = NULL;
IShellBrowser* pSB = (IShellBrowser*)SendMessage(GetParent(Handle), WM_GETISHELLBROWSER, 0, 0);
TCHAR szPath[_MAX_PATH];

if (pSB == NULL) //GetFileNames被调用两次,第二次pSB为空, 返回第一次结果
{
if (lst)
{
FFileName = OpenFileName.lpstrFile;
FFiles->Assign(lst);
delete lst;
lst = NULL;
}
return;
}

if (lst == NULL)
lst = new TStringList;

ZeroMemory((LPVOID) & fmte, sizeof(STGMEDIUM));
ZeroMemory((LPVOID) & fmte, sizeof(FORMATETC));
fmte.tymed = TYMED_HGLOBAL;
fmte.lindex = -1;
fmte.dwAspect = DVASPECT_CONTENT;
fmte.cfFormat = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
do
{
HRESULT hr = pSB->QueryActiveShellView(&pIShellView);
if (FAILED(hr))
break;
hr = ::SHGetMalloc(&pMalloc);
if (FAILED(hr))
break;
hr = pIShellView->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (LPVOID*) & pIDataObject);
if (FAILED(hr))
break;
if (pIDataObject == NULL)
break;
hr = pIDataObject->GetData(&fmte, &stgmedium);
if (FAILED(hr))
break;
LPIDA pida = (LPIDA)GlobalLock(stgmedium.hGlobal);
if (pida)
{
LPCITEMIDLIST pidlFolder = GetPIDLFolder(pida);
for (UINT i = 0; i < pida->cidl; i++)
{
LPCITEMIDLIST pidl = GetPIDLItem(pida, i);
pidlFull = ILCombine(pidlFolder, pidl);
if (ILIsFile(pidlFull))
{
ZeroMemory(szPath, sizeof(TCHAR) * _MAX_PATH);
hr = SHGetPathFromIDList(pidlFull, szPath);
if (SUCCEEDED(hr))
{
lst->Add((szPath));
}
}
pMalloc->Free(pidlFull);
pidlFull = NULL;
}
}
GlobalUnlock(stgmedium.hGlobal);
ReleaseStgMedium(&stgmedium);
}
while (FALSE);

if (pIDataObject)  		pIDataObject->Release();
if (pIShellView)		pIShellView->Release();
if (pMalloc)
{
if (pidlFull) 		pMalloc->Free(pidlFull);
pMalloc->Release();
}
}


加入代码后,不管TOpenDialog还是TOpenPictureDialog,打开文件数量都不再受限制(当然受内存限制,也不是无限的)。

在此BS一下微软的程序员。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: