PLUGIN/2.0 /*------------------------------------------------------------ Last Modified:20050312 −descriptの内容を書き忘れていた −選択肢横流し仕様を書き忘れていた ------------------------------------------------------------*/ この文書は未だ開発者版です。予告なくごっそり変更される可能性があります。 ■設計思想 ・手軽に本体やゴーストとやりとりできるよう改修し、SAORI群としてゴーストごとに分散してしまったもののうち  「便利機能」にあたる部分を統合し、利用者側の利便性を改善する。 ・プラグイン開発者から実行環境へ負担を移すほうが良いでしょう……多分。 ■影響評価 処理系作者 処理系にいろいろ負担を移すことを前提としているので、覚悟してください(苦笑 プラグイン作者 新たにコール用にrequestエクスポートを定義するので、PLUGIN/1.0との衝突は考慮する必要はありません。 スクリプトやイベント等のゴーストへの通知が非常に楽になる。 ゴースト作者 特定のプラグインにたとえ対応していなくてもデフォルトスクリプト仕様(後述)があるので致命的な事にならない。 どうしてもデフォルトスクリプトで雰囲気を壊されたくない場合は対応しましょう…… 利用者 ゴーストごとにちりぢりになった機能群をまとめて扱えるので便利かつ楽。 ■DLLエクスポート関数群 extern "C" __declspec(dllexport) BOOL __cdecl load(HGLOBAL h, long len); extern "C" __declspec(dllexport) BOOL __cdecl unload(void); extern "C" __declspec(dllexport) HGLOBAL __cdecl request(HGLOBAL h, long *len); ☆Borland系C/C++コンパイラでは_loadのように頭にアンダースコアがつくようですがそちらにも対応した方が良いでしょう。 load 読み込み時にコールされます。HGLOBALにDLLの入るディレクトリのパスが入ります。 GlobalAlloc(GMEM_FIXED,xxx) されたものなのでそのままポインタ(char *)にキャストして利用してください。 また、必ずDLL側でGlobalFreeしてください。 return - 常にtrue 規定ではロード失敗時にfalseですが、falseを返しても何も処理されません。 unload DLL開放直前(=SSP/CROW終了時+上書きインストール時、DLL_PROCESS_DETACH前)にコールされます。 return - 常にtrue 規定では開放失敗時にfalseですが、falseを返しても無視されます。 request ロード・アンロード以外の処理はすべてここで行われます。 注意事項はloadと同じです。 return - 下記プロトコル説明のとおり レスポンス用の返り値HGLOBALも、GlobalAlloc(GMEM_FIXED,xxx)で確保されたものにしてください。 ■リクエスト規定 典型的なリクエスト例は以下のとおりです。 GET PLUGIN/2.0[CRLF] ID: OnGhostChange[CRLF] Charset: UTF-8[CRLF] Reference0: 54[CRLF] [CRLF] NOTIFY PLUGIN/2.0[CRLF] ID: OnMenuExec[CRLF] Charset: UTF-8[CRLF] Sender: こむ&エクセ Reference0: 17982[CRLF] [CRLF] ※[CRLF]=CR+LF 空行で終了。Zero-Terminateとは限らないので注意してください。 PLUGIN/2.0のフォーマットは基本的にSHIORI/3.0仕様に準じています。 イベント識別子のIDヘッダと、任意の数(8以降あり)の追加情報であるReferenceヘッダから構成されます。 Referenceの内容はIDによって変わります。 Reference等の内容に改行等を含めたい場合、また含めなければならないと規定したい場合は、%8f%73のように、 回避したい文字のみURLエンコードして渡すよう規定することを *強く推奨* します(仕様ではありませんが) Senderの内容は、後述するゴースト側からの呼び出し仕様によって呼び出された場合、ゴースト名となります。 本体側からコールされた場合はSenderヘッダ自体が消滅するか空文字列が代入されます。 SHIORIのように「本体の名前(SSPとかCROWとか)」が入るわけではないので注意してください。 NOTIFYの方で来た場合、ゴースト側にイベントを送ったりすることはできません。 EventヘッダやScriptヘッダを返しても無視されます。 [NOTIFY]として特記されているもの以外は、GET/NOTIFYの双方で来る可能性があります。 ID - version [NOTIFY] Referenceなし 必ずロード直後に呼ばれ、プラグインの情報を要求してきています。 Valueヘッダでプラグインのバージョン情報を返してください。 (例:SwissArmyKnife/1.0) この時Charsetヘッダも同時に返すと、以降そのCharsetでリクエストが来るようになります。 versionリクエストのみレスポンス形式が特殊であることに注意してください。 これ以外は基本的に下で述べるレスポンス形式に従ってください。 ID: installedplugin [NOTIFY] Reference0以降:プラグイン名[\1]プラグインID インストール済のプラグインを列挙します。 ID: ghostpathlist [NOTIFY] balloonpathlist [NOTIFY] headlinepathlist [NOTIFY] pluginpathlist [NOTIFY] Reference0以降:フォルダのフルパス 読み込み中のそれぞれ(ゴースト/バルーン/ヘッドライン/プラグイン)のフォルダを通知します。 複数フォルダに対応する処理系では、Reference1以降もある可能性があります。 ID - OnMenuExec Reference0:sakura HWND、またはプラグインがウィンドウを出す時親に設定すべきウィンドウ プラグインメニュー等からそのプラグインが選択されたことを通知します。 設定ダイアログ・メッセージボックス等を出す、スクリプトを返す等、何らかの反応を行うことを強く推奨します。 ID - OnSecondChange:秒変化 Referenceなし ID - OnGhostBoot:ゴースト起動 ID - OnGhostExit:ゴースト終了 [NOTIFY] ID - OnGhostInfoUpdate:シェル変化やHWND変更など、ゴースト情報の更新(load直後にも送られる可能性あり) [NOTIFY] Reference0:sakura HWND[\1]kero HWND[\1]3 HWND[\1]4 HWND ... Reference1:現在のゴースト名 Reference2:現在のシェル名 Reference3:ゴーストID (Authorized SSTP(Owned SSTP)で送られるものと同じ) リクエストされるHWND群は、まだ構築されていない場合0が渡される可能性もあります。十分注意して扱ってください。 Reference3のゴーストIDを識別子として、プラグイン内でゴーストリストを作成しておくと良いでしょう。 ID - OnInstallComplete : インストール終了 Reference0 : インストールタイプ(\1区切り) Reference1 : インストールされたものの名前(\1区切り) Reference2 : インストールされたフルパス(\1区切り) ■レスポンス規定 レスポンスの例は以下のとおりです。 CRLF区切りはリクエストと同様ですので[CRLF]は省略しています。 PLUGIN/2.0 200 OK Charset: Shift_JIS Target: 54 Event: OnResourceLow Reference0: 19 Reference1: 31 Reference2: 65 Script: すくりぷと〜 ※複数起動対応の処理系のみ※ 現在起動中のゴーストでTargetに該当するゴーストがいたらそれで処理されます。 "__SYSTEM_ALL_GHOST__"が指定されている場合は、「起動中の全ゴースト」に通知されます。 該当しない場合、何も指定しない場合は処理系に応じて適当なゴースト「1体」で処理されます。 また、後述のゴースト側からの呼び出し仕様で呼ばれた場合は、Targetヘッダで明示的に指定がされない限り、 呼んだゴーストに返ります。 ※対応していない処理系ではそもそも1体しかありませんのでそのゴーストが毎度呼び出されます。 EventヘッダとReferenceヘッダはゴースト側に送るイベントです。 これにゴーストが反応しない場合、デフォルトスクリプトであるScriptヘッダが再生されます。 Event,Reference,Target,Scriptはすべて省略可能です。 例えばイベントだけ送りたい、デフォルトスクリプトは要らん、という場合はScriptヘッダを省略してください。 ※スクリプトだけ送りたい場合はその逆ですね。 プラグインのレスポンスでかえってきたスクリプト内、またはEventヘッダでゴーストにイベント通知して 帰ってきたスクリプト内に選択肢があれば、その1回分だけOnChoiceSelect/On????をプラグインに横流しします。 (汚い仕様ですが、これがあると選択肢をバルーンに出して設定、などもできますしね) ■プラグインID プラグインごとに一意につけられるIDです。 ぶつかる可能性が「極端に低い」63バイトまでの1バイト文字列なら何でもかまいません。 通常、GUID/UUIDと呼ばれるものを使います。 ※それなりに開発環境をそろえておられる方なら、guidgen.exeのRegistry Formatが生成に使えると思います。 ※ない人はこちら > http://ssp.shillest.net/docs/guid.zip ※処理系側は最低でも63バイトまで受け付ける必要がありますが、そもそも制限を設けないことを推奨します。 descript.txtのIDエントリに、次のように書いてください。 例:id,3491996A-B383-4890-B863-5CE258678093 ゴースト側からはプラグイン名以外にこのIDを使ってプラグインを呼び出すことができます。 意味的には、このIDが同じであるということは、たとえ名前が変っても互換性がある、という事を示すことになります。 ■descript.txt プラグイン特有のエントリのみ記述します。 secondchangeinterval OnSecondChangeを呼ぶ間隔を指定します。もちろん標準値は1です。 0にするとOnSecondChage自体を送信しません。 disableAllNotifyCall 上記の全てのリクエストを一切停止します。 load/unloadのみでアプリケーションにフックをかけ、他は要らないというプラグインに有用でしょう。 ■ゴースト側拡張 ・スクリプト拡張 \![raiseplugin,プラグイン名,イベント,Reference0...] \![raiseplugin,プラグインID,イベント,Reference0...] 指定したプラグインに指定したイベントを(GETで)送信します。 プラグイン側でTarget指定がない限り(system_any)、プラグインからのレスポンスはraisepluginしたゴーストに 優先的に割り振られますので、SAORIもどき的な使い方も可能です。 ・SHIORIイベント拡張 NOTIFY SHIORI/3.0 ID: installedplugin Reference0以降:プラグイン名[\1]プラグインID インストール済のプラグインを列挙します。バイト値1区切りでプラグイン名、プラグインIDとなります。 プラグインIDは必ず存在するものではありません。 ■ghost with plugin >> INSTALL/1.5を参照 --------------------------------------- by:SSP BUGTRAQ 開発部 ・内容の正確性については保証しません。バグってるかも。 ・この文書は営利目的でない限り自由に配布・複製・変更(変更したものの再配布含む)することができます。 ・予告無く変更されることがいっぱいありますが、刺さないでね。 ・というか煮るなり焼くなり好きにしてくださいまし。