人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Windows Explorerのシェル拡張についての質問です。
やりたい事は、選択→右クリック→項目指定 で呼び出される動作をコマンドラインからエミュレートしたい(呼び出されるアプリに渡す引数を指定してバッチ処理できるようにしたい)ということです。
レジストリを探索して問題のアプリを呼び出してるっぽいGetClassObjectをExportしているDLLファイルは特定できたのですが、このDLLをどう扱えば所望の動作になるのかわかりません。
動作環境はOffice/WSH/Powershellのみ使える環境とします。(VC等は使えない環境)
・Explorer上で選択されたファイルを右クリックして項目を選択したときに内部的にどういう動作が行われるのか詳しく解説しているサイトはないでしょうか。(shell拡張を作成するページには「こうすればこうなる」というケースしか書かれていないので、ファイル名を引数に取って?を呼び出す場合は?」という情報が見つけられません)

●質問者: しくおゲー日記
●カテゴリ:コンピュータ
✍キーワード:DLL EXPLORER Office PowerShell VC
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● ekrea
●61ポイント

エクスプローラで実行されている処理を(ざっくりですが)C++コードで示します。

これがOffice/wsh/PowerShellで実現可能かどうかは知りません。探した限りではそのような情報は見つけられませんでした。

DLL関数のロードと構造体の参照渡しをサポートした言語なら理論的には可能なはずですが、

道のりはかなり険しいかと思います。

(本来アプリケーションがGetClassObjectを直接呼び出すことは推奨されておらず、

通常はSDKに用意されたCoCreateInstance関数を使用します。)

IClassFactory *pIFactory;
IShellExtInit* pIShellInit;
IContextMenu* pContextMenu;

REFCLSID clsid = CLASS_ID;//拡張オブジェクトのクラスID
HKEY hKeyPlogID = PROG_ID;//ターゲットとなるファイルのファイルクラスが記述されたレジストリキー。
ITEMIDLIST* pItemIdList = FILE;//ターゲットとなるファイルのパスを表すアイテムIDリスト。

//COMサーバーの起動
HRESULT hr = GetClassObject(clsid, IID_IClassFactory, (LPVOID *)&pIFactory);

//シェルオブジェクトの生成及びインターフェースの取得。
pIFactory->CreateInstance(NULL, IID_IShellExtInit, (LPVOID *)&pIShellInit);
pIShellInit->QueryInterface(NULL, IID_IContextMenu, (LPVOID *)&pContextMenu);


//メニュー項目の取得
HMENU hMenu = CreateMenu();
pIShellInit->Initialize(pItemIdList,NULL, hKeyPlogID);
pContextMenu->QueryContextMenu( hMenu, 0, 1, 0xffff, CMF_NORMAL );


pIFactory->Release();
pIShellInit->release();
pContextMenu->release();

上記コードによってhMenuにコンテキストメニューの項目が追加されます。

コマンドを実行するには以下のようにします。

//iCommand: 実行するメニュー項目のオフセット
void exec(int iCommand,IContextMenu* pContextMenu){
 CMINVOKECOMMANDINFO cmi;
 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO); 
 cmi.fMask = 0; 
 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCE(iCommand - 1); 
 cmi.hwnd = NULL; 
 cmi.lpParameters = NULL; 
 cmi.lpDirectory = NULL; 
 cmi.nShow = SW_SHOWNORMAL; 
 cmi.dwHotKey = 0;
 cmi.hIcon = NULL;

 pContextMenu->InvokeCommand(&cmi);
}

流れとしては

1. GetClassObjectでCOMサーバーのインスタンスを生成し、それに関連付けられたIClassFactoryを取得。

2. IClassFactory.createInstanceでシェルオブジェクトを生成し、それに関連付けられたIShellExtInitを取得。

3. IShellExtInit.QueryInterfaceでシェルオブジェクトに関連付けられたIContextMenuを取得。

4. IShellExtInit.Initializeでシェルオブジェクトにターゲットファイルをセットする。

5. IContextMenu.QueryContextMenuでメニュー項目の取得。

6. IContextMenu.InvokeCommandで実行。

となります。

*アイテムIDリストはエクスプローラにおけるパスの内部表現です。エクスプローラはデスクトップやコントロールパネルなどの

ファイルでもフォルダでもないアイテムや、本来のディレクトリ構造とは異なる階層を扱うのでこんなややこしいことをしています。

参考:

エクスプローラの「元に戻す」を実行するC++コード

SHFileOperationによるファイル操作を元に戻す

こっちはもうちょっと簡単な方法でやってますね。


その他参考になりそうなところ

Emulating CoCreateInstance() - CodeProject CoCreateInstanceの内部でやっていること。

進め!中級プログラマー シェル拡張に使われるクラスの解説

シェルエクステンションって? アイテムIDリストはここがわかり易いかも


2 ● espresso3389
●35ポイント

本来であれば、COM経由で呼び出しといいたいところですが、シェル拡張で利用されているインターフェイスは、いわゆるデュアルインターフェイスではないことの方が多いので、C++やC#などを使わずに処理をすることは不可能だと思います。

なので、その方向性での実装ではない方向で考えると、PowerShellでは、.NETのライブラリは比較的簡単に使えるので、

System.Windows.Forms.SendKeys

を使って、キー処理をエミュレートするというのはどうでしょうか?タイミングの問題に翻弄されやすいことや、デスクトップがインタラクティブでないと動作しないなど問題が無いわけでは無いですが、ある程度までなら実現可能だと思います。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ