2004.07/02 更新

Susieプラグイン解体新書


目次


調査対象

ベータ版については異なる場合のみ記述。
OS は Windows XP HomeEdhition でテストしています。


DIBへの対応詳細

各アプリのDIBへの対応具合を細かく調べてみます。
DIBの仕様の中にはあまり使われないものがあります。
色深度が16ビット、32ビットのもの。(カラーマスクのあるものないもの)
トップダウン や RLE 。

テスト画像は、増田 隆氏 の「まんでる version 1.70」(マンデルブロー集合描画ソフト)で作成した画像を、"SeeDIB.exe" で変換して用意しました。
トップダウン の BMP はバイナリエディタで biHeight の値を書き換えて作成しました。
RLE の BMP は "SeeDIB.exe" で変換して作成しました。
テストで使用した BMP ファイル(174,592 バイト)

調査には 後藤あきら氏 の「Susie32 Bitmap Plug-in Ver.0.10.6501」を使用しました。
このプラグインは設定により、16ビット、32ビットDIB を 24ビットDIB に変換せずにそのまま返します。
また RLE、トップダウンもそのまま返す設定があります。

"SeeDIB.exe" は
http://support.microsoft.com/support/kb/articles/Q94/3/26.asp
からダウンロードしたソースを Visual C++6.0SP4 でコンパイルしたものを使用しました。


Susie ver0.47b

DIBの種類カタログの表示「開く」での表示
16ビットBI_RGB ○本体がこのBMPを処理した場合はOK。
×プラグインが返した場合は真っ黒に表示される。
◎OK
16ビットBI_BITFIELDS ×本体はこのBMPに対応していない。
×プラグインが返した場合は真っ黒に表示される。
×本体はこのBMPに対応していない。
×プラグインが返した場合は正常には表示されない。
32ビットBI_RGB ○本体がこのBMPを処理した場合はOK。
×プラグインが返した場合は真っ黒に表示される。
◎OK
32ビットBI_BITFIELDS ×本体はこのBMPに対応していない。
×プラグインが返した場合は真っ黒に表示される。
×本体はこのBMPに対応していない。
×プラグインが返した場合は正常には表示されない。
トップダウン ×本体がこのBMPを処理しようとした場合は exception エラーで終了したり、「窓を開けない」エラーを出して動作がおかしくなる。
×プラグインが返した場合は横に細長く表示される(高さがマイナス表示)。
×本体がこのBMPを処理しようとした場合はクラッシュする。
×プラグインが返した場合は正常に表示されない(高さはマイナス表示)。
RLE ○本体がこのBMPを処理した場合はOK。
×プラグインが返した場合は exception エラーで終了したり、「窓を開けない」エラーを出して動作がおかしくなる。。
◎OK


ViX V2.21

備考:プラグインの返却テスト時には「画像のロード」を「プラグイン優先」にしています
DIBの種類カタログ表示
16ビットBI_RGB ◎OK ◎OK
16ビットBI_BITFIELDS ◎OK ◎OK
32ビットBI_RGB ◎OK ◎OK
32ビットBI_BITFIELDS ◎OK ◎OK
トップダウン ○本体がこのBMPを処理した場合は OK。
×プラグインが返した場合はアイコン表示になる。
○本体がこのBMPを処理した場合は OK。
×プラグインが返した場合はI/Oエラーメッセージが表示される。
RLE ○本体がこのBMPを処理した場合は OK。
×プラグインが返した場合は正常に表示されない。
◎OK


Linar Ver 1.6.100

備考:Ver 1.7β2.1も同様の結果
DIBの種類サムネイル表示表示
16ビットBI_RGB ◎OK ◎OK
16ビットBI_BITFIELDS ◎OK ◎OK
32ビットBI_RGB ◎OK ◎OK
32ビットBI_BITFIELDS ◎OK ◎OK
トップダウン ×本体はこのBMPに対応していない。
×プラグインが返した場合はアイコン表示になる。
×本体はこのBMPに対応していない。
×プラグインが返した場合は「画像表示できません」。
RLE ◎OK ◎OK


まとめ

アプリ名16・32ビットDIB対応備考
Susie × 対応しているとはいえない。
ViX V2.0以降を使用する事。
Linar version 1.6以降を使用する事。


プラグインの扱い

各アプリがどのようにプラグインを利用しているのかを調査する。
拙作の「TEST00IN」「TEST00AM」の結果をまとめたものです。
※間違いの無いように気をつけてはいるのですが、この結果は一例に過ぎないかもしれません...


Susie ver0.47b

起動時にプラグインはすべて一度ロードされ、GetPluginInfo の後にアンロードされる。以降は設定と必要に応じてロード、アンロードされる。
プラグインの読みこみモードの設定変更はすぐに反映される。
カタログをバックグラウンドで作成可能になったため、プラグインはスレッドセーフを気にする必要がある。

メモリ入力で渡されるデータのサイズは GetArchiveInfo で得た fileInfo の filesize が渡されるようだ。
Susie本体はメモリ入力時のデータサイズをきちんと見ているようで、fileInfo の filesize が実際より少ない場合には、BMP画像の上部分が黒く表示されたり、コピーしたときにデータが途中で切れてしまう。
fileInfo の filesize が 0 の場合には、LocalSize で得られるサイズ(4の倍数切り上げ?)が渡されるようだ。

■画像ファイルを表示する際の呼び出しシーケンス
1.IsSupported
非0 を返すと2.へ。
0 を返すと1-1.へ。

1-1.IsSupported
また同じ条件で呼ばれる。
0 を返すと 今度は 128バイトずらしたメモリを渡される。
非0 を返すと2.へ。

2.GetPictureInfo
どのような値を返しても 3.へ

3.GetPicture
0 を返すと表示される。

●00IN 備考
GetPluginInfo
infonobuflen
0 8
1 128
2以降 255

Plug-in APIバージョン はチェックされる。
00IN か 00AM なのかはこの文字列で判断される。

2n+2、2n+3 のペアを返した数だけ IsSupported の呼ばれる回数が増えるようだ。
IsSupported 常にメモリ渡し。
GetPictureInfo flag は 0(ディスクファイル入力)。
書庫内ファイルは 1(メモリ上のイメージ)。
オフセットは IsSupported で 非0 を返したときのもの。
PictureInfo は 0 初期化されていない。
返却した PictureInfo は hInfo 以外は使用されていないようだ。
0 以外を返してもエラーにはならない。
GetPicture flag は 0(ディスクファイル入力)。
書庫内ファイルは 1(メモリ上のイメージ)。
オフセットは IsSupported で 非0 を返したときのもの。
pPrgressCallback は NULL ではない。
biXPelsPerMeter, および biYPelsPerMeter は(解像度ではなく)アスペクト比として使用されるようだ。
GetPreview GetPicture に同じ。
カタログ作成時にのみ呼び出される。
-1 を返すと GetPicture が呼ばれる。
ConfigurationDlg 特に無し。
しいていえば、戻り値は何を返しても問題無い。

■書庫ファイルを展開する際の呼び出しシーケンス
IsSupported → GetArchiveInfo, IsSupported が何度か呼ばれ、GetFile。
アーカイブ内のファイル情報がキャッシュされている場合は GetArchiveInfo は省略される。

●00AM 備考
GetPluginInfo 00IN に同じ。
IsSupported 00IN に同じ。
GetArchiveInfo flag は 0(ディスクファイル入力)。
書庫内ファイルは 1(メモリ上のイメージ)。
オフセットは IsSupported で 非0 を返したときのもの。

この関数の成否はエラーコードで判断されない。
*lphInf が NULL かどうかで判断しているようだ。
GetFileInfo アーカイブ内のファイル情報をキャッシュする機能により GetFileInfo は呼び出されなくなった。
GetFile 基本的にディスクファイル入力、出力先はメモリ。
書庫内ファイルはメモリ上のイメージ入力。
ConfigurationDlg 00IN に同じ。


ViX V2.21

起動時にプラグインデータベース(pluginDatabase.xml)と照合する。ただしチェックはファイル名とファイルの更新日時で行われる。
未登録や更新されたプラグインはロードされ、GetPluginInfo で情報を取得しデータベースに登録する。
ロードされていないプラグインは必要になったときにはじめてロードされるが、後はロードされたままで終了まで解放される事は無い。
プラグインの有効・無効の設定の変更は即有効。
書庫内書庫はサポートされない。

ファイルの拡張子により使用するプラグインが決まるようだ。
対応拡張子にマッチしないファイルに対してプラグインは使用されない。
「画像のロード」をプラグイン優先にしていても、*.jpg ファイルはViXが処理してしまう。


■画像ファイルを表示する際の呼び出しシーケンス
IsSupported をオフセット 0 で呼ぶ。
非0 を返すと GetPicture が呼ばれる。

●00IN 備考
GetPluginInfo buflen は 512。
Plug-in APIバージョン はチェックされる。
00IN か 00AM なのかはこの文字列で判断される("00IM", "00AN" も受け付ける。)
でたらめなバージョンでも終了するまでロードされたまま(使用される事は無い)。
書きこんだ文字列は戻り値のバイト数以降は捨てられるようだ。
IsSupported 常にメモリ渡し。
GetPictureInfo 全く使用されない。
GetPicture flag は 0(ディスクファイル入力)。
オフセットは 0。
書庫内はメモリ入力。(設定によりテンポラリファイル経由も可)
pPrgressCallback は NULL ではない。
biXPelsPerMeter, および biYPelsPerMeter は使用されない。

エラーを返すとViXがサポートしているものはViXで表示され、サポートしていないものは関連付けられたアプリケーションで開かれる。
GetPreview GetPicture に同じ。
カタログ作成時にのみ呼ばれる。
-1 を返すと GetPicture が呼ばれる。
ConfigurationDlg 特に無し。

■書庫ファイルを展開する際の呼び出しシーケンス
書庫ファイルは拡張子で判断される。(設定によりチェックさせることもできる)
IsSupported が何度か呼ばれる。
非0 を返していると GetArchiveInfo が呼ばれる。
IsSupported がまた呼ばれる。
ファイル数の分だけ IsSupported, GetFileInfo, GetFile を繰り返す。

●00AM 備考
GetPluginInfo 00IN に同じ。
IsSupported 00IN に同じ。
GetArchiveInfo flag は常に 0(ディスクファイル入力)。
オフセットは 0。
GetFileInfo flag は常に 0x80。
ディスクファイル入力、ファイル名の大文字小文字を同一視する。
オフセットは 0。
GetFile flag は常に 0x100。
ディスクファイル入力、出力先はメモリ。
ConfigurationDlg 00IN に同じ。


Linar Ver 1.6.100(Ver 1.7β2.1)

起動時に、設定で指定されたフォルダのプラグインを全ていったんロードする。ロードするときには GetPluginInfo を呼ぶ。「選択したプラグインのみをロードする」でなければ終了するまでプラグインはロードされたまま。プラグインの有効・無効の設定の変更は即有効。もちろん起動時のチェック時に存在していないプラグインは設定できない。
書庫内書庫はサポートされない。

メモ:
カタログにアイコンで表示されているファイルは、なんらかのタイミングで何度でもチェックし表示しようとする。

■カタログ作成時の呼び出しシーケンス
IsSupported がオフセット 0 で呼ばれる。
「Macintoshバイナリの調査をする」にしている場合は、オフセット0、128、256、384、512と呼ばれる。
IsSupported で対応していれば GetPictureInfo が ファイル入力オフセット 0 で呼ばれる。
※「Macintoshバイナリの調査をする」にしている場合もオフセット0で呼ばれる。
GetPictureInfo でエラーを返しても GetPicture が ファイル入力オフセット 0 で呼ばれる。
「Macintoshバイナリの調査をする」にしている場合は、オフセット0、128、256、384、512と呼ばれる。

■画像ファイルを表示する際の呼び出しシーケンス
カタログで表示に使用したプラグインを使用するようだ。
GetPicture がファイル入力オフセット0で呼ばれる。
「Macintoshバイナリの調査をする」にしている場合にエラーを返すと、オフセット128、256、384、512 で呼ばれる。

●00IN 備考
GetPluginInfo buflen は 256。
Plug-in APIバージョン はチェックされる。
00IN か 00AM なのかはこの文字列で判断される。
IsSupported メモリ渡し。
GetPictureInfo カタログ作成時にのみ呼ばれる。
flagは 0(ディスクファイル入力)。
書庫内はメモリ入力。
PictureInfo は 0 初期化されている。
返却した PictureInfo は情報一覧ビューに使用される。
GetPicture flagは 0(ディスクファイル入力)。
書庫内はメモリ入力。
pPrgressCallback は NULL ではない。
biXPelsPerMeter, および biYPelsPerMeter は使用されない。
GetPreview 全く使用されない。
ConfigurationDlg 特に無し。

■書庫ファイルを展開する際の呼び出しシーケンス
拡張子で書庫ファイルとみなされる。(「書庫ファイルをツリーに表示する」設定にしなければ書庫ファイルは扱えない)
IsSupported がファイルハンドル渡しオフセット 0 で呼ばれる。
「Macintoshバイナリの調査をする」にしている場合は、オフセット0、128、256、384、512と呼ばれる。
非0 を返すと GetArchiveInfo が呼ばれる。
GetFile が同じファイルに対して何度か呼ばれる。

●00AM 備考
GetPluginInfo 00IN に同じ。
IsSupported 00IN に同じ。
GetArchiveInfo flag は常に 0(ファイル入力)。
GetFileInfo 全く使用されない。
GetFile flag は 0x100。
ファイル入力、出力先はメモリ。
ConfigurationDlg 00IN に同じ。

■Linar version 1.6 → version 1.6.16β でのプラグイン関係の変更点
GetArchiveInfo の戻り値は無視される。lphinfのハンドル検査で成否判定。
fileInfo の position が 0 か、filesize が 0 の場合 GetFileInfo を呼ぶ。
らしい...(未確認)


プラグインの実装例

Susieプラグイン の仕様の通りに対応アプリケーションを作成したはずだが、動作しない Susieプラグイン があるのは何故だろうか?

Susieプラグイン の仕様は明確にされていないところもあり、プラグイン製作者によって実装が異なる場合がある。それでも仕様の範囲内であればその差は吸収できるはずだ。しかし、中には Susie で動作しさえすれば良いとばかりに、Susie では使用されない部分は実装していないこともある。そのようなプラグインもサポートしたいのならば、Susie と同様なプラグイン呼び出しをするしかないだろう。

ここでは Susieプラグイン が実際にはどのように実装されているのかを調査し、プラグインをどのように扱ったら良いのかを検討していく。

●00INプラグイン
GetPluginInfo
infono...
0 バージョン番号は「4バイト」だが、実際には {'0','0','I','N','\0'} と5バイト書きこむのがほとんどである。
バッファを4バイトしか用意しないと {'0','0','I','\0'} を返すものもある。
よって、バッファは 5 バイト以上用意するべきだろう。
1 以降 文字列は NULL終端 されると思われるが、もしもバッファサイズが足りない場合でも必ず NULL終端 されるだろうか?
返す「書きこんだバイト数」は strlen で計算した値(NULLターミネータは数えない)であることも多い。
心配ならば、buflen にはバッファサイズ-1 を渡し、NULL終端 する。

IsSupported ファイルハンドルを渡すとファイルがより良くチェックされるように思われるかもしれないが、そのようなことはほとんど無いだろう。Susieでは常にメモリで渡されるためか、メモリ渡しでは対応するがファイルハンドル渡しでは対応しないプラグインもあるようだ。
個人的には、プラグインの作者にファイルハンドル渡しにも対応してもらいたいところだ。

IsSupported では「対応している」「対応していない」のどちらかしか返されないためエラーが起きても判断のしようがない。
GetPictureInfo この関数で得られる情報は「画像ファイルの情報」であって、GetPicture で返される DIB の情報 ではない。(Susie では 16・32ビットDIB に対応していないことから、GetPictureInfo では 16ビット であっても、GetPicture で返される DIB は 24ビット、ということがある)
Susie でもあまり重要視されない関数であることから、実装されていない、または常にエラーを返すプラグインもあるようだ。
画像内のテキスト情報を得るための関数と割り切るしかないのかもしれない。

関数に渡す PictureInfo 構造体は 0 で埋めておくのが無難である(プラグインの中には、特定のメンバにしか値を書きこまないものがある)。
GetPicture lpPrgressCallback に NULL を渡されることがあるのを考慮していないプラグインが存在する。これは仕様にもあるのだからプラグイン作者に修正してもらいたいところだ。
コールバック関数の必要が無いアプリケーションであっても、何もしないダミーのコールバック関数を渡すようにするといいだろう。
このことはコールバック関数が渡される他の関数でも同様である。

00INプラグインでは、ファイル入力かメモリ入力かの違いで苦労することは無さそうに思われるが、Susieでは基本的にファイル入力で書庫内のファイルはメモリ入力であることからか、どちらか片方の入力しか受け付けないプラグインがあるかもしれない。
GetPreview -1 を返すだけの関数でも実装しなければならないはずだが、この関数が無いプラグインも存在するようだ。
ConfigurationDlg 唯一この関数だけが実装していなくても構わない関数のはずである。
-1 を返すだけの関数をインプリメントするのもまぎらわしい。
必要でなければ実装するべきではないだろう。

●00AMプラグイン
GetPluginInfo 00INプラグインに同じ。
IsSupported 00INプラグインに同じ。
GetArchiveInfo 古いバージョンの Susie では GetFile の前に必ず GetFileInfo が呼ばれたため、GetArchiveInfo ではダミーの情報を返すプラグインがあった。
※Susie ver0.45h 以降は GetFileInfo は呼ばれず GetArchiveInfo のみ使用されている
一度展開しなければ filesize(元のファイルサイズ)を得ることができないアーカイブ形式のプラグインが filesize を 0 に設定する程度で、position がダミー情報のプラグインは未確認。

Plug-in package ver0.07以前に含まれる lhasad.spi は GetArchiveInfo を呼び出すと成功しても 2 を返す。
※Plug-in package ver0.08 の lhasad.spi では修正されている
対処法としては渡すハンドルに NULL を入れて呼び出した後も NULL であるかを見るか、呼び出した後に有効なハンドルであるかを見る。Susie は前者の方法で判断しているようであるから、同じチェック方法で十分だろう。
GetFileInfo 古いプラグインでは、GetFileInfo を呼ばなければ真の情報を得られないことがある。
GetFile 後回しにしてしまったが、00AMプラグイン ではメモリ入力を受け付けないプラグインがある。
これは Susieプラグイン の仕様では、メモリ入力では対応が難しい形式があるためであろう。(Susie ではメモリ入力で渡されるのは書庫内のファイルのみ、ということもあるが)

仕様にはファイルへの出力もあるが、Susie では使用されないためか実装していないプラグインが多い。
実装されていたとしてもファイルへの出力は使用せず、メモリ出力を使用してアプリケーション側でファイルに出力するのが無難である。
ConfigurationDlg 00INプラグインに同じ。


更新履歴

2004.07/02
 ・最新の安定版(開発版)について調査した
  Susie ver0.47b, ViX V2.21, Linar Ver 1.6.100(Ver 1.7β2.1)
 ・「プラグインの実装例」を Susie ver0.47b + Susie 32bit plug-in library Ver0.08 に合わせた
 ・CSSできれいにしたいな
2003.03/20
 ・古すぎる情報はSusieプラグイン対応アプリケーションの挙動に残して、こちらに新しい情報をまとめる
 ・最新情報に更新したい


戻る