僕がプログラムを作る際、Visual C++ と Visual Basic を適材適所に用います。C言語で考えた方が素直になる場合、パフォーマンスが必要とされ、無駄を極力少なくしたい処理などは Visual C++、逆に、画面周りなどは Visual Basic で簡単に作ってしまうという風に。制御系のプログラムやそれをモニタするプログラム、又は、シミュレータ等をよく作るので、API をコールする場合も多く、また、マルチスレッドや COM ポートの制御やバッファリング等をあらわすには、C言語の方が適していると思われます。よって、この部分のロジックが重要で、画面周りはそれほど大切でない場合などが多くあり、先に記した方法がやり易いということになります。
そこで、よく用いる方法が Visual C++ を使用して DLL を作成し、Visual Basic で作成したプログラムがその DLL を呼び出すという方法です。通常、Visual Basic 側から DLL を呼び出しますが、つい最近、DLL 側から Visual Basic の関数を呼び出したいケースが現れたので、そのやり方をここに示します。
状況としては、デバイスにアクセスする API を呼び出したいが、いつ API から制御が戻ってくるかわからないので、その間、画面がフリーズするのはままずい。で、子スレッドでその API を呼び出し、親スレッドはすぐにリターンする。ここで問題になるのが、Visual Basic 側でいつ API の処理が終わったをどうやって知るかということです。その方法として、先のコールバックを用いる方法の他に、Visual Basic からポーリングのようなことをする方法や、ユーザ定義メッセージを使うことなどを考えましたが、タイムラグを少なくすることは、システムに負荷がかかる事につながるからポーリング方法は見送り、Visual Basic 側では凝ったことを極力したくないということで、ユーザ定義メッセージのやり方も見送りました(ところで、Visual Basic でユーザ定義メッセージは受信できるのだろうか・・・)。
前置きはこの辺にしておいて、以下に方法を示します。Visual C++ にる DLL の作成方法の具体的なコーディング方法は省略します。
まずは、DLL 側から。DLL からコールしたい関数の方と引数を宣言します。以上の処理で、DLL 内の関数 MyCallBack を Visual Basic から呼び出すことで、Visual Basic 側の関数 CallFromDLL が DLL から呼び出されることになります。
当初、コールバック関数の定義を
typedef int ( *MyFuncType )( BSTR* data )
としていて、全然成功しませんでした。そこで、MSDN を調べてみてやっと成功しました。詳細な原因としては、__stdcall と __cdecl の違いをきちんと把握しておらず、今回の Visual Basic では言語仕様適にこの __stdcall と __cdecl の区別がつかず、エラーが発生していたと思われます。