【 IShellFolder インターフェイス による コントロールパネル へのアクセス 】

1. インターフェイスの取得
2. ParseDisplayName メソッド
3. CLSID
4. コントロールパネル内のアイテムの名前の取得
5. ITEMIDLIST の構造
6. コントロールパネル内のアイテムのITEMIDLIST の作成
7. コントロールパネル内のアイテムの実行

Syntax
 
HRESULT			hr;
LPSHELLFOLDER		pDesktop;
 
hr = SHGetDesktopFolder( &pDesktop );


Syntax
 
HRESULT ParseDisplayName(
    HWND hwnd,
    LPBC pbc,
    LPOLESTR pwszDisplayName,
    ULONG *pchEaten,
    LPITEMIDLIST *ppidl,
    ULONG *pdwAttributes
);


hwnd
  • 対話処理を行なう場合は、ウィンドウハンドルを提供するべきです。
    そうでなければ NULL をセットします



  • pbc
  • このパラメーターは、通常 NULL がセットされます



  • pwszDisplayName
  • NULL で終了する Unicode 文字列を指定します。デスクトップフォルダー
    は、例えば、"C:\My Docs\My File.txt」のようなパスを受け付けます

  • また、"::{GUID}"を使用して指定します。

  • 例えば、デスクトップフォルダーからコントロールパネルを検索するため
    には、下記のように指定します

  •  
    ::{CLSID for My Computer}\::{CLSID for the Control Panel}
    


    *pchEaten
  • 表示名のキャラクタ数を返しますが、必要でなければ NULL を指定します



  • *ppidl
  • オブジェクトのための ITEMIDLIST を受け取ります。NULL が返された
    場合はエラーを意味します



  • *pdwAttributes
  • ファイル属性が必要な時に指定します。必要なければ NULL を指定しな
    ければなりません

  • 指定できる値はここでは紹介しません


  • CLSID はレジストリの HKEY_CLASSES_ROOT\CLSID に定義されています

  •   名称 CLSID
    1
    マイ コンピュータ
    20D04FE0-3AEA-1069-A2D8-08002B30309D
    2
    コントロール パネル
    21EC2020-3AEA-1069-A2DD-08002B30309D


    #include <shlobj.h>
    #include <comdef.h>
     
    void MyIShellFolder( )
    {
     
    	HRESULT			hr;
    	LPSHELLFOLDER		pDesktop;
    	LPSHELLFOLDER		pTargetFolder;
    	LPITEMIDLIST		pidlTarget;
    	LPITEMIDLIST		pidlItem;
    	LPENUMIDLIST		pEnum;
    	DWORD			dwRetrieved;
    	STRRET			str;	// STRRET 構造体
    	char			szName[MAX_PATH];
     
    	_bstr_t			MyComp( "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" );
    	_bstr_t			Cpanel( "::{21EC2020-3AEA-1069-A2DD-08002B30309D}" );
    	_bstr_t			Sep( "\\" );
    	_bstr_t			Target("");
    	Target.operator += (MyComp);
    	Target.operator += (Sep);
    	Target.operator += (Cpanel);
     
    	// デスクトップフォルダの取得
    	hr = SHGetDesktopFolder( &pDesktop );
    	if( FAILED( hr ) ) {
    		return;
    	}
     
    	hr = pDesktop->ParseDisplayName(
    		NULL,
    		NULL,
    		Target,
    		NULL,
    		&pidlTarget,
    		NULL
    	);
    	if ( pidlTarget == NULL ) {
    		pDesktop->Release();
    		return;
    	}
     
    	// フォルダオブジェクトの取得
    	hr = pDesktop->BindToObject(
    				pidlTarget,
    				NULL,
    				IID_IShellFolder,
    				(LPVOID*)&pTargetFolder
    			);
    	if( FAILED( hr ) ) {
    		pDesktop->Release();
    		return;
    	}
     
    	// 一覧の取得
    	hr = pTargetFolder->EnumObjects(
    				NULL,
    				SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
    				&pEnum
    			);
    	if( FAILED( hr ) ) {
    		pTargetFolder->Release();
    		pDesktop->Release();
    		return;
    	}
     
    	while( 1 ) {
     
    		// pidlItem に一つセットする
    		hr = pEnum->Next( 1, &pidlItem, &dwRetrieved );
    		if( FAILED( hr ) ) {
    			break;
    		}
    		if ( dwRetrieved == 0 ) {
    			break;
    		}
     
    		hr = pTargetFolder->GetDisplayNameOf( pidlItem, SHGDN_NORMAL, &str );
    		if( FAILED( hr ) ) {
    			continue;
    		}
     
    		WideCharToMultiByte( CP_ACP,
    				0,
    				str.pOleStr,
    				-1,
    				szName,
    				MAX_PATH,
    				NULL,
    				NULL
    			);
    		MessageBox( NULL, szName, "", MB_OK );
     
    	}
     
    	// 取得したものは解放
    	pEnum->Release();
    	pTargetFolder->Release();
    	pDesktop->Release();
     
    }
    

  • ターゲットが、C:\MyDocs\MyFile.htm の場合以下のようになります

  • My Computer C:\ MyDocs MyFile.htm 2バイトのNULL
  • それぞれの構造は以下のように定義されています

  • typedef struct _SHITEMID { 
        USHORT cb; 
        BYTE   abID[1]; 
    } SHITEMID, * LPSHITEMID;
    
  • さらに ITEMIDLIST は以下のように定義されています

  • typedef struct _ITEMIDLIST {
        SHITEMID mkid;
    } ITEMIDLIST;
    
  • つまり、SHITEMID 構造を持った複数のデータが並んで ITEMIDLIST として認識されます

  • データの最後には必ず2バイトの NULL( 0x00 ) が存在し、abID の大きさは不定で、 cb に実際の
    大きさが格納されます。つまり、リストデータとする為のダミーとして abID が存在します

  • ですから、このデータにアクセスする為には、cb と NULL を指標にしなければなりません
  • 処理可能な ITEMIDLIST を作成する為に、pidlTarget と pidlItem を正しい構造で結合する必要が
    あります

  • LPITEMIDLIST CreateNewIdlist( 
    LPMALLOC pMalloc,
    LPITEMIDLIST pidl1,
    LPITEMIDLIST pidl2
    )
    {
    	UINT cb1,cb2;
    	UINT cbWork;
    	LPITEMIDLIST pidlTemp;
    	LPITEMIDLIST pidlNew;
     
    	// pidl1 のサイズ取得
    	cbWork = 0;
    	pidlTemp = pidl1;
     
    	while ( pidlTemp->mkid.cb ) {
    		cbWork += pidlTemp->mkid.cb;
    		pidlTemp = (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidlTemp) + pidlTemp->mkid.cb );
    	}	
     
    	cb1 = cbWork;
     
    	// pidl2 のサイズ取得
    	cbWork = 0;
    	pidlTemp = pidl2;
     
    	while ( pidlTemp->mkid.cb ) {
    		cbWork += pidlTemp->mkid.cb;
    		pidlTemp = (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidlTemp) + pidlTemp->mkid.cb );
    	}	
     
    	cb2 = cbWork;
     
    	// 両方のサイズ + 2 でアロケート
    	pidlNew = (LPITEMIDLIST)pMalloc->Alloc( cb1 + cb2 + 2 );
    	ZeroMemory( pidlNew, cb1 + cb2 + 2 );
     
    	// データ転送
    	CopyMemory( pidlNew, pidl1, cb1 );
    	CopyMemory( ((LPBYTE)pidlNew) + cb1, pidl2, cb2 );
     
    	return pidlNew;
     
    }
    

    #include <shellapi.h>
     
    void ExecuteFolderItem(
    LPITEMIDLIST pidl1,
    LPITEMIDLIST pidl2
    )
    {
    	LPMALLOC		pMalloc;
    	LPITEMIDLIST		pidlTarget;
    	SHELLEXECUTEINFO	sei;
     
    	// ITEMIDLIST のメモリ領域は、このインターフェイスで作成しなければなりません
    	if ( FAILED( SHGetMalloc( &pMalloc ) ) ) {
    		return;
    	}
     
    	pidlTarget = CreateNewIdlist( pMalloc, pidl1, pidl2 );
     
    	// 呼び出しに必要な値のセット
    	ZeroMemory(&sei, sizeof(sei));
    	sei.cbSize     = sizeof(SHELLEXECUTEINFO);
    	sei.fMask      = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;
    	sei.lpIDList   = pidlTarget;
    	sei.nShow      = SW_SHOWDEFAULT;
     
    	ShellExecuteEx( &sei );
     
    	pMalloc->Free( pidlTarget );
       
    }
    
  • コントロールパネル内のアイテムの名前の取得後、以下のようにして呼び出します
  • if ( lstrcmp( szName, "プログラムの追加と削除" ) == 0 ) {
    	ExecuteFolderItem( pidlTarget, pidlItem );
    	break;
    }