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()
ここで落ちる…
======================================================
すみません,VB 側の SetFunAddr は SetCallbackFunction の誤り.
それと,呼ぶ順序が逆じゃないと駄目ですね...
VB 側
SetCallbackFunction AddressOf VbCallBack
OpenWaveInput
EXPORT void CALLBACK SetCallbackFunction(PVOID pfn)
ですね,すみません….宜しくお願い致しますです.
「引数の個数」「ByVal/ByRef」「引数のデータ型」「戻り値の型」といった
『コールバック関数の定義』を間違えると、メモリ例外を引き起こす事がありますよ。
例えば今回の場合、
> Public Sub VbCallBack()
と、引数が0個になっていますが、waveInProcの定義は、
void CALLBACK waveInProc(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
ですよね。
res ありがとう。
掲げた code は飽くまで例ですが・・・(~_~)
waveInProc は C 側にあります。
その waveInProc の中で事前にその address を取っておいた VB の procedure を呼ぶわけです。という訳でこの WaveInProc が例えば
TimerProc だと問題ないのです。この “VB側” を C にしてしまう
とこれまたなにも問題がない…。はぁ〜
あ、VB 側の function を waveInProc に指定するのもおんなじように駄目です。
編集 削除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の原因追求を行いましたが、高価なデバ
ッガではありましたが、難なく問題を発見・根絶することがで
きました。
ご参考までに・・・
以上。
あと・・・
完全に動作するコードをお渡しはできないのですが、
その当時作成したActiveX OCX (MFC) でのコードで、
音関係の部分を抜き出したソースをダウンロード可能
にしておきましたので、参考にして下さい。
あくまで、ロジックを確認すると言うのみです。
よって、必要なコード部分しかありません。
ヘッダーファイルや他のActiveX としてのリソース関
係も添付していません。
申し訳ないですが、コメント関係もほとんど抜いてあ
ります。
ご参考までに・・・
http://www.accession.jp/CWaveCtrl.zip
以上。
うぅん!そぅかぁ、処理速度の問題だぁ…
道理で自分のトロい PC だと全然だめだったのに、ちょっと速い PC
のときはうまくいったりした。VBP を開いて debug すると全然だめ
なのに、compile した module だとちょっと動いたりもした。言われて
みれば思い当たる節だらけ…。しかし VB に渡るのって、結構負荷がか
かるんだねぇ。
waveInAddBuffer は VB から帰ってきたところでやってました。ひょっとして先にやればいい?
Source ありがとうございます。残念ながらちょこちょこっとみて、
あぁあぁなぁる…、って言えるほどの skill はないので後ほどゆっくり
拝見させて頂きます。
res 本当にありがとうございました。とりあえず、この件はここで一旦
解決としておきます。