Excel VBAからC++へのポインタへの参照を渡すことは可能ですか?



Excel vba から独自の C++ dll 関数を呼び出したい:


void my_cpp_fun ( int& n_size, double*& my_array);

C++ 関数は、可変サイズ n_size の配列 my_array を作成します (このサイズは my_cpp_fun 内で計算されます)。


C++ コードで Excel 固有のものを使用せずに、この関数をそのまま VBA に接続できますか?


したがって、基本的に私が探しているのは、次のような VBA Declare ステートメントです


Declare Sub my_cpp_fun Lib "my_cpp.dll" (n_size As Long, Ref_to_Ptr_Qualifier my_array As Double) 

私に発生した追加の問題:new を使用して c++ dll 内にメモリを割り当てた場合、dll 関数が制御を VB に返すと、そのメモリは使用可能になりますか?そうでない場合、上記は無意味です...


答え:


簡単な答え:はい、VBA から DLL 内の関数を呼び出すことは可能です (私の意見では、COM ルートよりも簡単です)。私の経験では、ラッパー関数を C で記述するのが最善の方法です。 リンケージ (さまざまな C++ の名前マングリング スキームに遭遇するのを避けるため) および参照ではなくポインターのインターフェイスを公開する (参照引数または結果を宣言するための適切な VBA 型は予測がかなり難しいため)。


適切な Declare の書き方の優れたガイド ステートメント (32 ビット Windows を想定) は、書籍「Hardcore Visual Basic」の第 2 章です (見つけられる場合)。


Declare を介して VBA に公開されている関数にも注意してください。 ステートメントは stdcall (別名 WINAPI) 呼び出し規約を使用する必要があります。


前置き:


私ならこうします:



extern 'C' {
void WINAPI my_cpp_fun_wrapper ( int *n_size, double **my_array )
{
my_cpp_fun(*n_size, *my_array);
}
}

そして


Declare Sub my_cpp_fun_wrapper Lib "my_cpp.dll" (ptr_n_size As Long, ptr_ptr_my_array As Long)


さまざまな *Ptr を使用します データへのポインターを取得するための VB6/VBA の関数。


いくつかのコードの回答


#include <windows.h>
__declspec(dllexport) int __stdcall asAny(void* pointer) {
char buf[200];
if (! pointer) {
// return 0 (false) to indicate that pointer was a null pointer
return 0;
}
wsprintfA(buf, "pointer = %p, *pointer = %s", pointer, (wchar_t*) pointer);
MessageBoxA(0, buf, "asAny", 0);
// return -1 (true) to indicate that ptrFoo was not a null pointer
return -1;
}
option explicit  declare ptrSafe function asAny
_
lib "the.dll" ( _ byVal pointer as any _
) as boolean sub main()
if asAny( nothing ) then
debug.print("asAny( nothing )
returned true" )
else
debug.print("asAny( nothing )
returned false")
end if ' -------------------------------------------------------- ' if asAny( 0 ) then -->
Compilie error: Type mismatch ' --------------------------------------------------------
if asAny( vbNullString ) then
debug.print("asAny( vbNullString ) returned true" )
else
debug.print("asAny( vbNullString ) returned false")
end if ' --------------------------------------------------------
dim text as string
text = "Hello World"
if asAny( text ) then
debug.print("asAny( text )
returned true" )
else
debug.print("asAny( text )
returned false")
end if end sub
LIBRARY the EXPORTS   asAny