度々で申し訳ありません。
OS:windowsXP Pro SP2
VC.NET2003, VB.NET2003
(VC側)
①extern "C" __declspec(dllexport) SAFEARRAY* __stdcall test1(LPCTSTR lp);
②extern "C" __declspec(dllexport) BSTR __stdcall test2(long ld, BOOL b = TRUE);
(VB側)Module1
Declare Function test1 Lib "xxx.dll" (ByVal s As String) As String()
Declare Unicode Function test2 Lib "xxx.dll" _
(ByVal ld As Long,Optional ByVal b As Long = True) As String
(VB側)Form1
Dim str() As String
str = test1("123")
MsgBox(str(0))
Dim s As String
s = New String(CChar(" "), 256)
s = test2(20000)
MsgBox(s)
まず、①の呼出しで
'System.Runtime.InteropServices.MarshalDirectiveException' のハンドルされていない例外が test2.exe で発生しました。
追加情報 : return valueをマーシャルできません。
となります。
②では
True, Falseのどちらを設定してもFalseの時の値しか戻ってきません。
VB側の記述方法に問題があると思い、いろいろ調べたのですが、
解決策がわかりません。
よろしくお願いします。
丸付き数字は使わないほうがいいです。
(1)とりあえず
http://msdn2.microsoft.com/ja-jp/library/z6cfh6e6(VS.80).aspx
をよんでみてください。
おそらく、<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_BSTR)> のような指定が必要なんでしょう。
# VB.NETでDeclareはあんまつかわないから微妙。(全部DllImportで書くから)
(2)VB6やVBAと違って、LONG型(=long int型),BOOL型(=int型)はLong型ではありません。
Integer型もしくはSystem.Int32型を使ってください。
(Long型はSystem.Int64つまりVCでいうint64型です)
それと、TRUEは1の#defineですので、Optionalを指定するのであれば、
Trueではなく1を指定したほうがいいです。
Blueさん、いつもすみません。
専属トレーナーみたいになって申し訳ないです。
(2)は以下で解決しました。ありがとうございます。
<DllImport("D:\Visual Studio Projects\VC\ComProc\Release\ComProc.dll", _
CharSet:=CharSet.Unicode)> _
Public Function test2( _
ByVal a As System.Int32, _
Optional ByVal b As System.Int32 = 1) As String
End Function
(1)で悩んでます。msdnは見ましたが難しいです。
以下では同じエラーになります。
(VB.NET)Module1
Imports System.Runtime.InteropServices
<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_BSTR)> _
Public str() As String
(VB.NET)Form1
Imports System.Runtime.InteropServices
str = test1("123", "あああ") -----> ここでエラー
MsgBox(str(0))
また「ちがうっぽ。」と怒られそうですが
よろしくお願いします。
ん〜
実験したコードです。
# (1)のは以前解答したもの
VC,DLL
SAFEARRAY* WINAPI Sample21()
{
SAFEARRAYBOUND sb;
sb.lLbound = 0;
sb.cElements = 3;
SAFEARRAY* psa = ::SafeArrayCreate( VT_BSTR, 1, &sb );
//BSTR* data;
//::SafeArrayAccessData( psa, ( void** )&data );
//
//data[ 0 ] = ::SysAllocString( L"イチロー" );
//data[ 1 ] = ::SysAllocString( L"松井秀喜" );
//data[ 2 ] = ::SysAllocString( L"松坂大輔" );
//::SafeArrayUnaccessData( psa );
::SafeArrayLock( psa );
long i;
i = 0;
::SafeArrayPutElement( psa, &i, ::SysAllocString( L"イチロー" ) );
i = 1;
::SafeArrayPutElement( psa, &i, ::SysAllocString( L"松井秀喜" ) );
i = 2;
::SafeArrayPutElement( psa, &i, ::SysAllocString( L"松坂大輔" ) );
::SafeArrayUnlock( psa );
return psa;
}
BSTR WINAPI test2(long ld, BOOL b = TRUE)
{
if (b)
return ::SysAllocString(L"斉藤隆");
return ::SysAllocString(L"田口壮");
}
VB
Module Module1
Declare Unicode Function Sample21 Lib "VBDll.dll" () As <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_BSTR)> String()
Declare Unicode Function test2 Lib "VBDll.dll" _
(ByVal id As Integer, Optional ByVal b As Integer = 1) As String
Sub Main()
Dim a() As String
a = Sample21()
For Each name As String In a
MsgBox(name)
Next
Dim s As String
s = test2(0)
MsgBox(s)
s = test2(1, 0)
MsgBox(s)
End Sub
End Module
Blueさんへ
迅速、的確で丁寧なご指導、ありがとうございます。
やはり「ちがうっぽ。」でしたね。
申し訳ありません。
VB
Module Module1
<DllImport("D:\Visual Studio Projects\VC\ComProc\Release\ComProc.dll")> _
Public Function test1( _
ByVal a As String, _
ByVal b As String) As <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_BSTR)> String()
End Function
Form1
Dim str() As String
str = test1("123", "あああ")
MsgBox(str(0))
で解決しました。
ありがとうございました!!
メモリの解放について意識してるんだろうか。
// 私も BStr を返値としてマーシャリングさせた場合はその途中で解放されるってことくらいしか知らないけれど。
ツイート | ![]() |