- PR -

Shell Extension と CLSID と PIDL と ドラッグ&ドロップ処理について

1
投稿者投稿内容
笊頭刹那
ベテラン
会議室デビュー日: 2005/10/17
投稿数: 55
お住まい・勤務地: オーストラリア
投稿日時: 2005-12-12 16:25
画面見すぎて目が重くなってきたのでいい加減質問させていただきます(汗。

いくつかの質問があるのでまずは簡単なものから

PIDLからCLSIDの作成およびその逆を行う正当法
現在バイナリデータを解析して下記のようにして作成・読み取りしています。
コード:
/// <summary>
/// Create ITEMIDLIST Data from CLSID
/// </summary>
/// <param name="clsid"></param>
/// <returns></returns>
private static byte[] ILDataCreateFromCLSID(Guid clsid)
{
	byte[] guid = clsid.ToByteArray();
	byte[] data = new byte[4 + 16 + 2];
	data[0] = 20;
	data[1] = 0;
	data[2] = 31;
	data[3] = 96;
	for(int i=0;i<16;i++)
		data[i+4] = guid[i];
	data[20] = 0;
	data[21] = 0;
	return data;
}
/// <summary>
/// Create CLSID from pidl
/// </summary>
/// <param name="pidl"></param>
/// <returns></returns>
public static Guid CreateCLSIDFromPidl(IntPtr pidl)
{
	byte[] guid = new byte[16];
	Marshal.Copy((IntPtr)(pidl.ToInt32()+4),guid,0,guid.Length);
	return new Guid(guid);
}


見ていただければ分かると思いますが最初の4bitが何を示しているのかわかっていません(汗。data[3]=96としていますがスタートメニューからドラッグされたオブジェクトは128だったり80だったりしています。
この最初の4bitの意味はいったい何なのでしょうか?またPIDLとCLSIDを相互変換するようなAPIは存在するのでしょうか?

コントロールパネル要素が渡してくるShellIDListの意味
コントロールパネル要素(たとえば「アプリケーションの削除と追加」)はまったく違うShellIDListを渡してきます、これらが渡してくるITEMIDLISTはまずパス化できませんでした、親パスとILCombineでつなげてやっても見ましたがどちらにせよ空パスが帰ってきます、ちなみに親パスは{21EC2020-3AEA-1069-A2DD-08002B30309D}ようはコントロールパネルですね。
初期では空パスが帰ってきたときにCLSIDだと判断をし上記のコードで作成するようにしていたのですが{ffffff38-0020-0028-433a-5c57494e444f}という存在しないCLSIDを作ってしまいました.
渡されたITEMIDLISTのデータをバイナリで確認してみると(ショートカットを作成するとこれにさらにショートカットヘッダ?を前部に付け足したものが書き込まれるのでそのショートカットをバイナリで開いて確認。)
コード:
53 00 00 00 38 FF FF FF 20 00 28 00 43 3A 5C 57 49 4E 44 4F 57 53 5C 73 79 73 74 65 6D 33 32 5C 64 69 72 65 63 74 78 2E 63 70 6C 00 44 69 72 65 63 74 58 00 43 68 61 6E 67 65 73 20 70 72 6F 70 65 72 74 69 65 73 20 66 6F 72 20 44 69 72 65 63 74 58 00 00 00 00 00 00 00


となっていました、これの
コード:
43 3A 5C 57 49 4E 44 4F 57 53 5C 73 79 73 74 65 6D 33 32 5C 64 69 72 65 63 74 78 2E 63 70 6C


の部分が翻訳するとC:\WINDOWS\system32\directx.cplなのでバイナリ解析によってこの値を取得することにより一応解決しました、日本語環境の要素はUnicodeで英語環境の要素(DirectX SDKとか)はASCllだったので苦労しましたが開始位置が各言語で違いはあれど一応一緒のようなのでできました、がしかし「タスク」や「プリンタ」「接続」「スタートメニューとタスクバーのほにゃらら」では上記のバイナリとまったく違うデータが送られてきます(汗。こんなデータ
コード:
14 00 1F 50 E0 4F D0 20 EA 3A 69 10 A2 D8 08 00 2B 30 30 9D 14 00 2E 00 20 20 EC 21 EA 3A 69 10 A2 DD 08 00 2B 30 30 9D 1E 00 71 80 00 00 00 00 00 00 00 00 00 00 90 79 27 D6 6A 4C CF 11 8D 87 00 AA 00 60 F5 BF 00 00 00 00 00 00


まったく翻訳できませんでした、ちなみにSHGetPathFromIDListで叩いてやっても空パスを返してくるのみで駄目でした親パスとつなげてはいませんがつなげていない場合はデスクトップに在るとして返されるでしょうからやはりこれはパスのPIDLでは無いです。
しかし、そうかといってCLSIDでもありません、上記の方法でCLSIDを作成すると{00000000-0000-0000-0000-907927d66a4c}と、まぁ明らかに存在していないんです。
タスクなどの起動方法はCLSIDを利用する方法で分かっているのですがドラッグされたものがタスクなのかどうなのか判断できないため困っています、この辺の特殊なもののフォーマットについて書かれている文献などを探しているのですがマイドキュメントやゴミ箱のITEMIDLISTについてしか書かれていません(汗。いったいITEMIDLIST内に何が入っているんだ!ってことなのでご存知の方いらっしゃったら教えていただきたいです。

スタートメニュー項目の「名前を指定して実行」「ヘルプとサポート」の起動方法が分からない
ドラッグされたアイテムにCLSIDが正しくついているので判断はできるのですが起動方法が分かりません。"explorer /root,,{あひゃひゃひゃひゃ}"とやっても起動できませんし、レジストリの値を見ても
コード:
<CLSID\{あひゃ}\InProcServer>
(既定) = %SystemRoot%\system32\shdocvw.dll
<CLSID\{あひゃ}\Instance>
CLSID = {またちがうCLSID}
<CLSID\{あひゃ}\Instance\InitPropertyBag>
CLSID = {これまた違うCLSID}
command = @shell32,-12710
method = FileRun
...その他関係なさそうなのがちょこちょこ


というものしか発見できませんでした、これはdllを起動しろということですか?そんな無茶な……なんかレジストリの値を見ているとshdocvw.dllの"FileRun"というメソッドを起動しているみたいなんですけど……Dllのメソッドを起動する方法が分かりません(汗。
これに関してもいろいろと日本語・英語でしらべてみたのですが「アプリケーションを起動で快適Windows」だとか「How to use start->run」だとかまったく関係ないことばかりで関係のある資料が見つかりませんでした。資料ご存知のお方がいらっしゃったら教えていただきたいです。




あと、今回の質問にまったく関係ないのです、余談です。
またランチャを作っているのでアイコンキャッシュについて知りたいのですが、一般的にアイコンキャッシュとはどうするのでしょうか?
c#のシリアライズを利用してアイコンをキャッシュするとそれはもうかわいそうな結果となってしまいます(16色アイコンくらいで保存される)ビットマップで保存しようかとも思いましたがアイコンのアルファ情報がなくなってしまうのでやはりアイコン状態で保存したいです。上記の問題の性でかなり後回しとなっているためほとんどテストしていませんがよろしければアイコンキャッシュに関する資料など教えていただけるとうれしいです。


かなり深い内容のものをいくつもあげてしまい申し訳ありません、資料の提供だけでも助かります、よろしくお願いします。

【現時点で知っている資料】
MSDN - Specitying a Namespace Extension's LOcation
MSDN - The Shell Namespace
MSDN - Creating Shell Extension Handlers
The Code Project - Creating a shell extension with c#(上記内容を簡略化しc#で紹介している)
※ 知っていると理解しているは違うのでもし上記資料の中にヒントとなるようなものがありましたら教えてください、一応上記内容については理解しているつもりではありますが……
とっちゃん
大ベテラン
会議室デビュー日: 2005/07/19
投稿数: 203
投稿日時: 2005-12-12 17:37
とっちゃんです。

PIDL の解析ですが、場所によって解析方法が全く異なります。
というか、基本的にはその場所を管理する IShellFolder の実装次第となりますので
解析出来たとしても、それは特定のOSの特定バージョン以外では意味を持ちません。

PIDLは、実際の構造を見ていればわかると思いますが、エクスプローラのフォルダツリーを
表現するために導入された仮想的なツリー管理アイテムとなっています。

実際の操作は、IShellFolder の実装に任されており、エクスプローラ自身も個々のフォルダの実装については、関与していません。

そのため、構造そのものもかなりアバウトな表現しかなされておらず、
実際には、バイト数+実データ(==SHITEMID)の塊を数珠繋ぎ(==ITEMIDLIST)しているだけに過ぎません。

概要については、
The Shell Namespace に詳しく書かれています。

英語が苦ではないのなら、リンク先の一つ上の Shell Basics を一通り読破してください。

英語はダメ〜という場合は、とりあえず IShellFolder であちこち検索してみてください。
それなりに情報が転がっています(玉石混交ですけどね(^^

C++ の知識が前提となるところが殆どですが、C# が読み書きできるのであれば
文法的な違いはわずかですのでそれほど困ることはないでしょう(^^;

ちなみに、コントロールパネルの中身は基本的にDLLです(きちんとした規約があります)。
なので、コントロールパネルの中身で、いくつかのフォルダになっているもの以外は
全部DLLの実行となります。

実行そのものは、IShellFolder に実行させれば詳細は知らずとも行うことは可能です。
これは、他のフォルダでも同様です。

おそらく理解を深めるには(おまけ質問部分も含め)、一度エクスプローラもどきを
作ってみるというのが一番だと思います(^^;


_________________
// とっちゃん(高萩 俊行)@わんくま同盟
// とっちゃん’Blog
// MS-MVP for Developer Tools - Visual C++
// WindowsInstallerの話題はhttp://www.freeml.com/msiまで
笊頭刹那
ベテラン
会議室デビュー日: 2005/10/17
投稿数: 55
お住まい・勤務地: オーストラリア
投稿日時: 2005-12-12 17:56
二重投稿してしまったのでこっちを削除しました。

[ メッセージ編集済み 編集者: 笊頭刹那 編集日時 2005-12-12 18:02 ]
笊頭刹那
ベテラン
会議室デビュー日: 2005/10/17
投稿数: 55
お住まい・勤務地: オーストラリア
投稿日時: 2005-12-12 18:01
引用:

PIDL の解析ですが、場所によって解析方法が全く異なります。
というか、基本的にはその場所を管理する IShellFolder の実装次第となりますので
解析出来たとしても、それは特定のOSの特定バージョン以外では意味を持ちません。


非常に参考になりました、っというかいますっごい驚いてます、なんとなくそんな気はしていたのですが「特定のOSの特定バージョン以外では意味を持ちません」が辛いですね、プログラムすべて見直しです(汗。まぁオブジェクト指向の強み、カプセル化のおかげでその部分だけ変えればいいんですが……なんかいままでバイナリエディタにバイナリ解析ソフトにドラッグドロップ解析ソフト(作って)使ってやっていたことが無駄だったので(さぶ知識やWindowsの仕組みについての知識にはなりましたが)ちょっと…(苦笑。

引用:

実際の操作は、IShellFolder の実装に任されており、エクスプローラ自身も個々のフォルダの実装については、関与していません。


IShellFolderの実装は非常に大変なので(コーディング量が)なるべく使わないようにIL系API使ったりしていたんですがそれがたたりましたね(苦笑。ちゃんとIShellFolder使います、でもc#からCOMインターフェイスって本当に使いにくいんですよね…(汗。

引用:

英語が苦ではないのなら、リンク先の一つ上の Shell Basics を一通り読破してください。

英語はダメ〜という場合は、とりあえず IShellFolder であちこち検索してみてください。
それなりに情報が転がっています(玉石混交ですけどね(^^。

C++ の知識が前提となるところが殆どですが、C# が読み書きできるのであれば
文法的な違いはわずかですのでそれほど困ることはないでしょう(^^;


英語は苦ですが取得しなきゃいけないんで(左横の僕の居住地をご覧ください苦笑)もう一度読み直してみます、前回はIShellFolderを使わないでやろうと思っていたのでPIDLやITEMIDLIST,Shell IDList Arrayに力入れて読んでいたので今回はIShellFolderの方に血から入れて読んでみようと思います、不明点や疑問点などが出てきた場合はまた質問をさせていただきます。

IShellFolderでできる・繊細がThe Shell Namespaceに書いてある
非常に大きなヒントをいただけました、やはり糸が見えるとがんばれますありがとうございました。

また疑問点などが出てきたときは質問いたします、では。
1

スキルアップ/キャリアアップ(JOB@IT)