我遇到了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;
}
有什么想法吗?提前谢谢!
答案 0 :(得分:1)
您不能从32位进程在64位操作系统上调用Explorer API,并且期望返回64位信息(反之)。
因此,编译为32位的代码仅适用于32位控制面板扩展(在我的64位Windows上,我有'Java','Flash Player','Quick Time'和'Mail') ,但不适用于64位扩展(在64位安装中占绝大多数,特别是对于Windows提供的扩展)。
有什么奇怪的是似乎可以工作,它根本不是恕我直言。
无论如何,要解决您的问题,只需将其编译为64位(x64)。