WaveInProc の中から VB を callback するには?

解決


punto  2004-02-18 23:13:42  No: 82108  IP: [192.*.*.*]

C で 音声入力を処理する DLL を作成しました.この DLL に 
“AddressOf” を使って,VB 側で作成した callback routine 
を知らせておいて,DLL が WIM_DATA を受け取ったところでそ
れを呼びました.

すると,VB の callback routine に入った所で memory fault 
で落ちてしまいます.何故でしょう? 

同じ DLL を同じように使用する C で作成した program は全く
問題なく動作します.また,同じ VB の callback routine でも 
WIM_DATA を受け取った場合以外(例えば timer の満了時など)
では問題を起こしません.

======================================================
C 側(Thread を起こして dummy の Window を create たり
していますがその辺りは省略.)

HANDLE  hThisModule;

BOOL APIENTRY DllMain(HANDLE hModule, ...)
{
    if (ulReason == DLL_PROCESS_ATTACH) {
         m_hThisModule = hModule;
        ...
    }
    ...
    return TRUE;
}

EXPORT void CALLBACK SetCallbackFunction(pfn) 
{
    ...
    pfnVbCallBack = (void (CALLBACK *)(void))pfn;
    ...
}

EXPORT void CALLBACK OpenWaveInput() 
{
    ...
   MMRESULT mmresult = waveInOpen(hWaveIn, ...);
    ...
}

void CALLBACK WaveInProc(HWAVEIN hwi, UINT uMsg, ...)
{
    switch (uMsg)
    {
    ...
    case MM_WIM_DATA:
       ...
       (*pfnVbCallBack)();
       ...
    ...
    }
...
}

------------------------------------------------------

VB 側
...
Private Declare Sub SetFuncAddr ...
Private Declare Sub OpenWaveInput ...
...
    どこか…
    OpenWaveInput
    SetFuncAddr AddressOf VbCallBack
...
Public Sub VbCallBack()
  ここで落ちる…

======================================================

編集    削除
punto  2004-02-18 23:18:08  No: 82109  IP: [192.*.*.*]

すみません,VB 側の SetFunAddr は SetCallbackFunction の誤り.
それと,呼ぶ順序が逆じゃないと駄目ですね...
VB 側
    SetCallbackFunction AddressOf VbCallBack
    OpenWaveInput

編集    削除
punto  2004-02-19 01:37:47  No: 82110  IP: [192.*.*.*]

EXPORT void CALLBACK SetCallbackFunction(PVOID pfn)
ですね,すみません….宜しくお願い致しますです.

編集    削除
魔界の仮面弁士  2004-02-19 02:43:24  No: 82111  IP: [192.*.*.*]

「引数の個数」「ByVal/ByRef」「引数のデータ型」「戻り値の型」といった
『コールバック関数の定義』を間違えると、メモリ例外を引き起こす事がありますよ。

例えば今回の場合、

> Public Sub VbCallBack()

と、引数が0個になっていますが、waveInProcの定義は、

  void CALLBACK waveInProc(
    HWAVEIN hwi,
    UINT uMsg,
    DWORD dwInstance,
    DWORD dwParam1,
    DWORD dwParam2
  );

ですよね。

編集    削除
punto  2004-02-19 07:00:34  No: 82112  IP: [192.*.*.*]

res ありがとう。
掲げた code は飽くまで例ですが・・・(~_~)
waveInProc は C 側にあります。
その waveInProc の中で事前にその address を取っておいた VB の  procedure を呼ぶわけです。という訳でこの WaveInProc が例えば 
TimerProc だと問題ないのです。この “VB側” を C にしてしまう
とこれまたなにも問題がない…。はぁ〜

編集    削除
punto  2004-02-19 11:56:17  No: 82113  IP: [192.*.*.*]

あ、VB 側の function を waveInProc に指定するのもおんなじように駄目です。

編集    削除
岡田 之仁  2004-02-19 12:27:03  No: 82114  IP: [192.*.*.*]

waveInProc へ渡す関数で、それはVBの標準フォームに
書かれていますか?

あと、環境ですが、VB6ですよネ?

私も昔その手のコードを書きましたが、音のサンプリングで
waveInProcのコールバック関数は高速性を要求しますので、
昔はVBの関数を渡した場合、よくクラッシュした経験があ
り、結果として、音の録音部分は、C言語側に書きました。

で、そのイベントをVBに返す部分のコーディングとしては
そのC言語の部分を通常のDLLではなく、ActiveX OCX に
したて、ActiveX の実装で返すことで切り抜けました。

また、waveInProc では、音の録音の為のバッファを高速に
応答しないと、バッファオーバーラン的クラッシュもあり、
VBで行うには、性能的問題があると思います。
waveInAddBuffer の部分のコーディングはどうなっています
か?

あと、Memory Fau;t の原因ですが、音が録音されてそのバッファ
アドレスからデータを抜き出すのですが、そのアドレス域が、
( LPSTR )GlobalAlloc( GPTR , AllocSize );
のように記述していました。
最初は、
( LPSTR )HeapAlloc( GetProcessHeap() , HEAP_ZERO_MEMORY , AllocSize );
と記述していましたが、何か問題があったようで、GlobalAlloc
に変更していました。よって、そのアドレスのデータエリアから
データを抜き出すmemcpyへのアドレスの渡し方でfaultしていない
でしょうか?

この辺のデバッグを行うに、VBと連携してVCで行うには、
ちょっと無理があり・・・ブレークポイントをおいても、録音
部分(waveInProc)で、応答が返らないので、クラッシュ・・・
と言う現象もあります。たまたまですが、当時、SoftICEと言う
デバッガを使ってfaultの原因追求を行いましたが、高価なデバ
ッガではありましたが、難なく問題を発見・根絶することがで
きました。

ご参考までに・・・

以上。

編集    削除
岡田 之仁  2004-02-19 12:59:05  No: 82115  IP: [192.*.*.*]

あと・・・

完全に動作するコードをお渡しはできないのですが、
その当時作成したActiveX OCX (MFC) でのコードで、
音関係の部分を抜き出したソースをダウンロード可能
にしておきましたので、参考にして下さい。

あくまで、ロジックを確認すると言うのみです。
よって、必要なコード部分しかありません。
ヘッダーファイルや他のActiveX としてのリソース関
係も添付していません。
申し訳ないですが、コメント関係もほとんど抜いてあ
ります。

ご参考までに・・・

http://www.accession.jp/CWaveCtrl.zip

以上。

編集    削除
punto  2004-02-19 13:47:01  No: 82116  IP: [192.*.*.*]

うぅん!そぅかぁ、処理速度の問題だぁ…
道理で自分のトロい PC だと全然だめだったのに、ちょっと速い PC
のときはうまくいったりした。VBP を開いて debug すると全然だめ
なのに、compile した module だとちょっと動いたりもした。言われて
みれば思い当たる節だらけ…。しかし VB に渡るのって、結構負荷がか
かるんだねぇ。

waveInAddBuffer は VB から帰ってきたところでやってました。ひょっとして先にやればいい?

Source ありがとうございます。残念ながらちょこちょこっとみて、
あぁあぁなぁる…、って言えるほどの skill はないので後ほどゆっくり
拝見させて頂きます。

res 本当にありがとうございました。とりあえず、この件はここで一旦
解決としておきます。

編集    削除