Q&A ありがちな失敗について

 Plug-in制作中で私がはまった点について書いておきます。 他にも解決方法があるかもしれませんが、私の場合の解決法を書いておきます。 ちなみに以下の項目はおぼろげな記憶とバグ修正履歴から再構成してお送りしてます。

めにゅ〜

  1. Plug-inがうまく認識されない
  2. 内蔵DOCが表示されない
  3. 書庫内ファイルがうまく読めない
  4. Macバイナリの付いたファイルが読めない
  5. Plug-in設定ダイアログで日本語しかでない
  6. VC++で作成したPlug-inがWin32s環境で動作しない
  7. GetPictureで不正なBITMAPINFOヘッダが返却される
  8. デバッグ中にINT 3Hで止まる
  9. Plug-inの引数の「フラグ」の値の指定はどうするの

  1. Plug-inがうまく認識されない(という現象だったかな?)

     Plug-inの各APIはWin3.1で言うところのPASCAL呼び出し、 Win32で言うところの__stdcallです。 Win32でもWindows.hでは

      #define PASCAL __stdcall

    となっているので、そのままでPASCALって書いてあげればOKです。 これが違っていると関数コールから戻った際にスタックがおかしくなるので 訳の分からない事になります。 また何故か関数名のエクスポートが__declspec(dllexport)ではうまくいかないことがあります。 おそらく序数の付く形式ではうまくいかないアプリケーションが存在するのでしょう。 そういうアプリケーションのためにWin3.1の頃と同じようにDEFファイルも書いてあげます。 私は面倒なので最低限しか書いてません(書かなくても良い様な気がするのですが、書いてあげるとうまくいきます)。

      Mint Plug-inでの例
      LIBRARY IFMINT.SPI
      DESCRIPTION 'Susie Plugin. support mint title[HoshihanaKyoko-III] format'

      EXPORTS
        GetPluginInfo
        IsSupported
        GetPictureInfo
        GetPicture
        GetPreview

    という感じです。Susie ver0.40以降で利用できる設定ダイアログを実装する場合には
        ConfigurationDlg

    も追加してあげます。

  2. 内蔵DOCが表示されない

     これはGetPictureInfoでも記述しています。 spi_api.txtからヘッダファイルを作った時にPictureInfo構造体メンバのオフセットがアライメントの関係で本来の位置とずれてしまったからです。

    対策はPictureInfo構造体の前後を次のようにします。


      VC++の場合
      #include <pshpack1.h>
      struct PictureInfo ......
      #include <poppack.h>

      BC++の場合(未確認)
      #pragma option -a-
      struct PictureInfo ......
      #pragma option -a.


  3. 書庫内ファイルがうまく読めない

     メモリインタフェースとファイルインタフェースのどちらも実装しましたか?。

  4. Macバイナリの付いたファイルが読めない

     GetPictureInfo/GetPicture/GetPreviewの各関数で ファイルインタフェースであった場合にファイルオフセットを きちんと扱っていますか?。

    こんなのはまるの私だけ・・・だよね。

  5. Plug-in設定ダイアログで日本語しかでない

     Susieではメニューなどの言語設定ができます(設定ダイアログの[ウィンドウ]の画面)。 この設定の結果はWin32(95/98/NT)環境では以下のレジストリに反映されます。


      HKEY_CURRENT_USER:Software/takechin/Susie/Resource
        Japanese : REG_DWORD : 英語(0) / 日本語(1)
          この値が存在しない時は1(日本語)とする

    またWin32s(Win3.1+Win32s 1.3C)環境ではWindowsディレクトリにあるファイルに以下のように保存されています。

      ファイル名:Susie.ini
      [Resource]
      Japanese=英語(0) / 日本語(1)
        この値が存在しない時は1(日本語)とする。このあたりはWin32と同じ

    ダイアログは日本語と英語をそれぞれ用意しておいて上記レジストリの値を読んで切り替えてあげます。 J6I Plug-in Ver 0.03ではこのことに気がついてなくて英語のリソースが存在しません。

  6. VC++で作成したPlug-inがWin32s環境で動作しない

     もしかしてSusie起動時に以下のようなメッセージが表示されませんか?。


      MSVCRT40.DLL for Win32
      Error: This version of MSVCRT40.DLL is not compatible
      with Win32s

     これはMSVCRT40.DLLがWin32s用とWin32(Win95/WinNT)用で違うものだからです。 Win32s用のMSVCRT40.DLLをVC++4.xのCDROMからコピーしなおすか、 VC++ Pro以上であれば使用するライブラリをスタティックリンクする事で 回避できます(Learning Editionでも統合環境からスタティックリンクのオプションが指定出来ないだけだそうです)。 しかしWin32s用のMSVCRT40.DLLはWin32s 1.30cの配布パッケージには含まれていないのでスタティックリンクする方がよいでしょう。

     その他の原因としてPlug-inがWin32sでサポートされていないWin32 APIを使っていませんか?。 例えばTLS(Thread Local Storage)MutexなどはWin32sではサポートされていません。 またWin32sでサポートされていないダイアログリソースのフラグもありますので注意しましょう(SpinコントロールやEditコントロールの右寄せなど;_;)。

     またVC++4.2以上では正式にはWin32sはサポートされない事になっています。 しかしライブラリをDLLを使った時には上記のようなメッセージボックスを表示しますが、 スタティックリンクした場合にはWin32sかどうかを意識していません。 よってVC++4.2以上でもスタティックリンクする事で動作の可能性があります。 ちなみにMint Plug-in程度であればVC++4.2でもWin32sで動作していました。

  7. GetPictureで不正なBITMAPINFOヘッダが返却される

     Plug-in制作よりは利用の時にはまるかもしれません。
     spi_api.txtのGetPictureの説明のところと関数ヘッダの定義のところで、 pHBInfoとpHBmの並び順が違うのでついプログラムを書く時に間違ってしまいます。 私が使っているヘッダではこの点は普通の順に並び変えています。

    壁紙チェンジャーを作った時にはまって3時間ぐらい悩んだのは内緒です(^^;)。

    補足:
    spi_api.txtでは間違ったことは記述されていません。 単に読み手が引数の書かれている順に、説明も書かれていると暗に期待するために読み間違うだけです。 注意深く読めば間違うことはありません。

  8. デバッグ中にINT 3Hで止まる

     デバッグ中に見知らぬコードの中でINT 3Hで止まってしまう事があります。 具体的には各Plug-in->LocalFree->RtlFreeHeap->.....->DbgBreakPoint のような呼び出しです。

    私が少し追いかけたところでは、LocalFreeの中で呼ばれるルーチンのチェックコードに引っ掛かっているのは確認できました。 LocalFreeはSetLastError(ERROR_INVALID_HANDLE)を呼んでエラーコードを設定していることと、この現象が発生しないPlug-inがあることから、 該当のPlug-inかPlug-inが使っているライブラリの問題のような気がします。 lhasad.spi/ifgif.spi/ifpi.spi/ifpic.spiなどで発生します。

    私はどうしようもないので(VC++で)"SPACE"と"F5"を連打してきりぬけています。

  9. Plug-inの引数の「フラグ」の値の指定はどうするの

    SPIの仕様書においてフラグの説明はビットフラグ(2進数)として説明されています。 ですから、「SSS」が「1」とは「001(2進数)」のことです。

    例:GetFileInfoで、メモリインタフェースかつファイル情報の大文字・小文字を同一視する場合。
    この場合は「I」を1、「SSS」を1として呼び出します。 ですから、フラグは「xxxx xxxx 1xxx x001」を指定します。 このうちxには0を指定しますので「0000 0000 1000 0001(2進数)」となります。 つまり「0081(16進数)」となります。