Question

I'm having three issues with Shell PIDLs (only happening with select Control Panel items, one example is "Notification Area Icons").

First, take the PIDL of "Notification Area Icons" and call SHGetNameFromIDList with that PIDL and SIGDN_NORMALDISPLAY. Instead of getting "Notification Area Icons" back (like I do for others), I get the parsing name of the PIDL (e.g. ::{control_panel_clsid}\0\::{notif_area_clsid}). For other Control Panel items, and other Shell items, this works no problem.

Second, take that same PIDL and call ShellexecuteEx with the SHELLEXECUTEINFO.lpIDList set to that PIDL and SHELLEXECUTEINFO.fMask set to SEE_MASK_IDLIST. It doesn't launch! Windows chucks up an error "there is no program associated" or something similar. For other Control Panel items, and other Shell items, this works no problem.

Third, take that same PIDL and call SHGetFileInfo with that PIDL and with uFlags containing SHGFI_PIDL. The result is the Windows generic blank paper icon. For other Control Panel items, and other Shell items, this works no problem.

I'm confused. I have no clue what is going on here. Is this a possible bug with some of the Control Panel virtual folders?

I mean, the exact same code works for every other Shell item (libraries, folders, even OneDrive), but some (not all!) Control Panel virtual folders all exhibit the exact same as above. I could get a list of the ones that have this odd behavior if needed, but "Notification Area Icons" is the one I remember off the top of my head.

It is very possible I'm doing something wrong but then why would it work for most other things? And for the record, the PIDL comes from IPersistFolder2::GetCurFolder.

I have a program that I wrote in plain C that reproduces the problem (it demonstrates the issue with SHGetNameFromIDList described above).

The code is below (completely self contained):

To use it you just need to run it, open "Notification Area Icons", and press any key. It'll output the PIDL "normal display" name, and also output the PIDL "parsing name". For "Notification Area Icons", you'll notice they are the same, which I believe is wrong (SIGDN_NORMALDISPLAY should give back "Notification Area Icons").

It also outputs a hex dump of the 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;
}

Any ideas? Thanks in advance!

Was it helpful?

Solution

You can't call Explorer API on a 64-bit OS from a 32-bit process and expect 64-bit information back (and the reverse).

So, your code compiled as 32-bit works only with 32-bit only control panel extensions (on my 64bit Windows, I have 'Java', 'Flash Player', 'Quick Time' and 'Mail' for example), but not for 64-bit extensions (which is the vast majority on a 64-bit installation, and especially for Windows-provided ones).

What's strange though is it seems to work, where it shoulnd't at all IMHO.

Anyway, to fix your issue, just compile it for 64-bit (x64).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top