控制面板PIDL奇怪的行为

时间:2014-04-24 04:24:34

标签: c winapi com windows-shell

我遇到了Shell PIDL的三个问题(仅在选择控制面板项目时发生,一个示例是"通知区域图标")。

首先,取"通知区图标"的PIDL。并使用该PIDL和SIGDN_NORMALDISPLAY调用SHGetNameFromIDList。而不是获得"通知区域图标"回来(就像我为其他人做的那样),我得到了PIDL的解析名称(例如:: {control_panel_clsid} \ 0 \ :: {notif_area_clsid})。对于其他控制面板项和其他Shell项,这没有问题。

其次,取相同的PIDL并调用ShellexecuteEx,并将SHELLEXECUTEINFO.lpIDList设置为该PIDL,将SHELLEXECUTEINFO.fMask设置为SEE_MASK_IDLIST。它没有发布! Windows收到错误"没有关联的程序"或类似的东西。对于其他控制面板项和其他Shell项,这没有问题。

第三,使用相同的PIDL并使用该PIDL和包含SHGFI_PIDL的uFlags调用SHGetFileInfo。结果是Windows通用空白纸图标。对于其他控制面板项和其他Shell项,这没有问题。

我很困惑。我不知道这里发生了什么。这可能是某些控制面板虚拟文件夹的错误吗?

我的意思是,完全相同的代码适用于其他每个Shell项目(库,文件夹,甚至OneDrive),但一些(并非所有!)控制面板虚拟文件夹都显示完全与上述相同。如果需要,我可以获得具有这种奇怪行为的列表,但是"通知区域图标"是我记不起的那个。

我很可能做错了什么但是为什么它会适用于其他大多数事情呢?为了记录,PIDL来自IPersistFolder2 :: GetCurFolder。

我有一个我用简单C编写的程序来重现问题(它演示了上面描述的SHGetNameFromIDList的问题)。

代码如下(完全自包含):

要使用它,您只需要运行它,打开"通知区域图标",然后按任意键。它输出PIDL"正常显示" name,并输出PIDL"解析名称"。对于"通知区域图标",您会注意到它们是相同的,我认为这是错误的(SIGDN_NORMALDISPLAY应该回馈"通知区域图标")。

它还输出PIDL的十六进制转储。

#include <tchar.h>
#include <Windows.h>
#include <Shlwapi.h>
#include <ShlObj.h>
#include <strsafe.h>

int _tmain( int argc, _TCHAR* argv[] )
{
    if ( !SUCCEEDED( CoInitialize( NULL ) ) )
        return 1;

    system( "PAUSE" );

    IShellWindows *psw = NULL;
    IUnknown *punkEnum = NULL;
    IEnumVARIANT *pEnumVar = NULL;
    HRESULT hr = 0;

    while ( 1 )
    {
        if ( SUCCEEDED( hr = CoCreateInstance( &CLSID_ShellWindows,
            NULL,
            CLSCTX_ALL,
            &IID_IShellWindows,
            ( LPVOID ) &psw ) ) )
        {
            if ( FAILED( psw->lpVtbl->_NewEnum( psw, ( IUnknown** ) &punkEnum ) ) )
                goto clean_main;

            if ( FAILED( punkEnum->lpVtbl->QueryInterface( punkEnum,
                &IID_IEnumVARIANT,
                ( void** ) &pEnumVar ) ) )
            {
                goto clean_main;
            }

            VARIANT v;
            VariantInit( &v );

            while ( pEnumVar->lpVtbl->Next( pEnumVar, 1, &v, NULL ) == S_OK )
            {
                IShellBrowser *psb = NULL;
                IShellView *psv = NULL;
                IFolderView *pfv = NULL;
                IPersistFolder2 *ppf = NULL;
                IShellItem2  *psi = NULL;
                LPITEMIDLIST pidl = NULL;
                LPWSTR pszParsingName;
                LPWSTR pszName = NULL;
                SFGAOF attributes = 0;
                size_t dwLength = 0;
                size_t dwLengthParsing = 0;

                if ( SUCCEEDED( IUnknown_QueryService( ( IUnknown* ) v.pdispVal,
                    &SID_STopLevelBrowser,
                    &IID_IShellBrowser,
                ( void** ) &psb ) ) )
            {
                hr = psb->lpVtbl->QueryActiveShellView( psb, &psv );
                if ( FAILED( hr ) )
                    goto clean_inner;

                hr = psv->lpVtbl->QueryInterface( psv, &IID_IFolderView, ( void** ) &pfv );
                if ( FAILED( hr ) )
                    goto clean_inner;

                hr = pfv->lpVtbl->GetFolder( pfv, &IID_IPersistFolder2, ( void** ) &ppf );
                if ( FAILED( hr ) )
                    goto clean_inner;

                if ( SUCCEEDED( ppf->lpVtbl->GetCurFolder( ppf, &pidl ) ) )
                {
                    size_t i;
                    size_t cb = 0;
                    byte *pb = NULL;

                    if ( FAILED( hr = SHCreateItemFromIDList( pidl, &IID_IShellItem2, ( void** ) &psi ) ) )
                        goto clean_inner;

                    if ( FAILED( hr = psi->lpVtbl->GetDisplayName( psi, SIGDN_NORMALDISPLAY, &pszName ) ) )
                        goto clean_inner;

                    if ( FAILED( hr = psi->lpVtbl->GetDisplayName( psi, SIGDN_DESKTOPABSOLUTEPARSING, &pszParsingName ) ) )
                        goto clean_inner;

                    if ( FAILED( hr = psi->lpVtbl->GetAttributes( psi, SFGAO_CANLINK, &attributes ) ) )
                        goto clean_inner;

                    if ( FAILED( hr = StringCchLength( pszName, STRSAFE_MAX_CCH, &dwLength ) ) )
                        goto clean_inner;

                    if ( FAILED( hr = StringCchLength( pszParsingName, STRSAFE_MAX_CCH, &dwLengthParsing ) ) )
                        goto clean_inner;

                    cb = ILGetSize( pidl );
                    pb = ( byte* ) pidl;
                    WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), pszName, dwLength, NULL, NULL );
                    WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), L"\n", 1, NULL, NULL );
                    WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), pszParsingName, dwLengthParsing, NULL, NULL );
                    WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), L"\n", 1, NULL, NULL );

                    for ( i = 0; i < cb; ++i )
                    {
                        WCHAR szHex[ 4 ];
                        StringCchPrintf( szHex, ARRAYSIZE( szHex ), L"%02X", pb[ i ] );
                        WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), szHex, 3, NULL, NULL );
                    }

                    WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), L"\n", 1, NULL, NULL );
                    WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), L"\n", 1, NULL, NULL );
                }

            clean_inner:
                if ( pszParsingName )
                    CoTaskMemFree( pszParsingName );
                if ( pszName )
                    CoTaskMemFree( pszName );
                if ( psv )
                    psv->lpVtbl->Release( psv );
                if ( pfv )
                    pfv->lpVtbl->Release( pfv );
                if ( ppf )
                    ppf->lpVtbl->Release( ppf );
                if ( psi )
                    psi->lpVtbl->Release( psi );
                if ( psb )
                    psb->lpVtbl->Release( psb );
            }
        }
    }
clean_main:
    if ( pEnumVar )
        pEnumVar->lpVtbl->Release( pEnumVar );
    if ( punkEnum )
        punkEnum->lpVtbl->Release( punkEnum );
    if ( psw )
        psw->lpVtbl->Release( psw );

    system( "PAUSE" );
}
CoUninitialize();
return 0;
}

有什么想法吗?提前谢谢!

1 个答案:

答案 0 :(得分:1)

您不能从32位进程在64位操作系统上调用Explorer API,并且期望返回64位信息(反之)。

因此,编译为32位的代码仅适用于32位控制面板扩展(在我的64位Windows上,我有'Java','Flash Player','Quick Time'和'Mail') ,但不适用于64位扩展(在64位安装中占绝大多数,特别是对于Windows提供的扩展)。

有什么奇怪的是似乎可以工作,它根本不是恕我直言。

无论如何,要解决您的问题,只需将其编译为64位(x64)。