windows - 拖动控制面板项时从 CIDA 获得错误的 PIDL

标签 windows winapi windows-shell

我现在正在处理拖放问题,并试图获取从 Windows shell 拖到我的应用程序的项目的 PIDL。

如果拖动的项目是“我的电脑”或“控制面板”本身,下面的代码可以获得正确的 PIDL,但当拖动的项目是“控制面板”中的项目时,它不起作用。

我的代码有什么问题?


#define GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
#define GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])

STGMEDIUM medium;

UINT fmt = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
FORMATETC fe= {fmt, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
HRESULT GETDATA_RESULT = pDataObject->GetData(&fe, &medium);

if (SUCCEEDED(GETDATA_RESULT))
{
    LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
    LPCITEMIDLIST pidlFolder = GetPIDLFolder(pida);

    int n = pida->cidl;  // the n is always correct
    if( n > 0 )
    {
        LPCITEMIDLIST pidlItem = GetPIDLItem(pida, 0);
        // the pidlItem is wrong when the dragged object is an item in 'Control Panel'
    }

    GlobalUnlock(medium.hGlobal);
}
ReleaseStgMedium(&medium);

有什么想法吗?谢谢

扎克@闪耀

最佳答案

如果我 D&D 鼠标、网络连接和字体,我会在我的测试应用程序中得到以下输出:

  • 0 鼠标 | sfgao=4 hr=0
  • 1::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\::{7007ACC7-3202-11D1-AAD2-00805FC1270E} | sfgao=20000004 hr=0
  • 2 C:\WINDOWS\Fonts | sfgao=60000004 hr=0

网络连接和字体 pidl 可以转换为完全限定的 shell 路径,而鼠标仅返回相对路径/显示名称。 如果您查看 IShellFolder::GetDisplayNameOf 的文档,这是有道理的:

...They do not guarantee that IShellFolder will return the requested form of the name. If that form is not available, a different one might be returned. In particular, there is no guarantee that the name returned by the SHGDN_FORPARSING flag will be successfully parsed by IShellFolder::ParseDisplayName. There are also some combinations of flags that might cause the GetDisplayNameOf/ParseDisplayName round trip to not return the original identifier list. This occurrence is exceptional, but you should check to be sure.

很明显,在处理控制面板项时,您需要保留 pidl,并且仅将 GetDisplayNameOf 用于 UI 中的显示字符串。 (鼠标 pidl 上的 IShellLink::SetIDList 将创建一个工作快捷方式,因此 pidl 有效)

void OnDrop(IDataObject*pDO) 
{
    STGMEDIUM medium;
    UINT fmt = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
    FORMATETC fe= {fmt, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
    HRESULT hr = pDO->GetData(&fe, &medium);
    if (SUCCEEDED(hr)) 
    {
        LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
        if (pida) 
        {
            LPCITEMIDLIST pidlFolder = GetPIDLFolder(pida);
            for (UINT i=0; i<pida->cidl; ++i) 
            {
                LPCITEMIDLIST pidlItem = GetPIDLItem(pida,i);
                LPITEMIDLIST pidlAbsolute = ILCombine(pidlFolder,pidlItem);
                if (pidlAbsolute) 
                {
                    IShellFolder*pParentSF;
                    hr= SHBindToParent(pidlAbsolute,IID_IShellFolder,(void**)&pParentSF,&pidlItem);
                    if (SUCCEEDED(hr))
                    {
                        STRRET str; 
                        hr= pParentSF->GetDisplayNameOf(pidlItem, SHGDN_FORPARSING, &str);
                        if (SUCCEEDED(hr))
                        {
                            TCHAR szName[MAX_PATH];
                            hr= StrRetToBuf(&str,pidlItem,szName,MAX_PATH);
                            if (SUCCEEDED(hr)) 
                            {
                                SFGAOF sfgao = SFGAO_FOLDER|SFGAO_FILESYSTEM|SFGAO_HASSUBFOLDER|SFGAO_CANLINK;
                                hr= pParentSF->GetAttributesOf(1,&pidlItem,&sfgao);
                                TRACE(_T("%u %s | sfgao=%X hr=%X\n"),i,szName,sfgao,hr);
                                CreateTestShortcut(pidlAbsolute);
                            }
                        }
                        pParentSF->Release();
                    }
                    ILFree(pidlAbsolute);
                }
            }
            GlobalUnlock(medium.hGlobal);
        }
        ReleaseStgMedium(&medium);
    }
}

关于windows - 拖动控制面板项时从 CIDA 获得错误的 PIDL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4559717/

相关文章:

java - Windows 64 中的 javaw.exe 进程是否消耗更多内存?

python - 如何停止在 Python 中播放的声音?

c++ - Win32 API : How to clip siblings using GetDCEx()?

winapi - 了解 GetDiBits。 C++

windows - 如何在没有 mt.exe 的情况下将 list 文件嵌入可执行文件?

windows - 当路径包含哈希时,导航 Shell 命令不起作用

registry - windows shell中右键上下文菜单的操作

c++ - 我可以使用 C++ 模板生成函数的 Unicode/ANSI 变体,而不是使用预处理器吗?

windows - 如何显示 'Send to' 和 'Open With' 上下文菜单?

c++ - 代码块中没有 openssl_applink