NonSoft

VB6とVB.NETのAPI宣言(Declare)の違いを
比較したサンプル


 サンプル(ソース/コード)
長年VB6のプログラマをやっていた技術者がVB.NETでプログラムを作る時によく悩むのが
APIの宣言方法と引数の渡し方だと思います。特にVB6でAny、String、構造体を使っていた時に
VB.NETではどうするのか、、、長時間、検索エンジンに頼る事になると思います。
(VB.NETでAPIなんか使うな!! とか言わないの・・・)

VB6とVB.NETのDeclare(宣言)方法の違いのポイントは以下のような感じです。
(1)VB6のDeclareはVB.NETのDeclareに対応し同じなのです。
  このサンプルではDeclareを使用していますが、<DllImport("mydll.dll")>を使用した方が
  良いかもしれません。
(2)VB6のLongは4バイトなのでVB.NETのIntegerは4バイト(Longは8バイト)に対応します。
(3)VB6の"String * 10"のような変数の宣言はVB.NETの"New String("", 10)"に対応します。
  ただし、構造体のメンバ変数の場合は(3)参照。
(4)構造体のメンバ変数が配列の場合の対応は以下のようになります。(サンプル有り)
  ・文字列の場合
     (VB6   の場合)s2 As String * 7
   (VB.NETの場合)<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=7)> Dim s2 As String
  ・配列の場合
     (VB6   の場合)s4(1) As Long
   (VB.NETの場合)<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Dim s4 As Integer()
(5)VB.NETにはAnyのような曖昧な宣言は出来ないので、最適な型に置き換えます。
(6)VB6のVariantはVB.NETのObjectに対応します。

サンプルソースを見た方が速いと思いますので、
VB6でのDeclare(宣言)方法とVB.NETでのDeclare(宣言)方法を比較したサンプルソースを以下に載せます。

このVB.NETのサンプルをC#.NETに移植したものがあります。
移植後のサンプルはVB6とC#.NETのAPI宣言(Declare)の違いを比較したサンプルです。
VB6とVB.NETとC#.NETのAPI宣言の比較が出来ます。

ちなみに、今回使用したAPIはVC++で作ったサンプルで、第一引数を第二引数にコピーする仕様です。
戻り値は第一引数のサイズを返します。VC++でDLLを作成するサンプルはこちらです。
VCからもVBからも呼び出せるDLLのサンプル(VC6)


<比較結果詳細> 1.VC++で作ったAPIのサンプルソース typedef struct { char s1; char s2[7]; int s3; int s4[2]; } MYSTRUCT; __declspec(dllexport) int __stdcall MyCopyChar(char v1, char *v2){ *v2 = v1; return sizeof(v1); } __declspec(dllexport) int __stdcall MyCopyString(char *v1, char *v2){ strcpy(v2, v1); return strlen(v1); } __declspec(dllexport) int __stdcall MyCopyInteger(int v1, char *v2){ *v2 = v1; return sizeof(v1); } __declspec(dllexport) int __stdcall MyCopyStruct(MYSTRUCT *v1, MYSTRUCT *v2){ v2->s1 = v1->s1; memcpy(v2->s2, v1->s2, sizeof(v1->s2)); v2->s3 = v1->s3; memcpy(v2->s4, v1->s4, sizeof(v1->s4)); return sizeof(*v1); }
2.VB6からVC++のAPIを呼ぶサンプルソース Private Type MYSTRUCT s1 As Byte s2 As String * 7 s3 As Long s4(1) As Long End Type Private Declare Function MyCopyChar Lib "mydll.dll" _ (ByVal v1 As Byte, ByRef v2 As Byte) As Long Private Declare Function MyCopyString Lib "mydll.dll" _ (ByVal v1 As String, ByVal v2 As String) As Long Private Declare Function MyCopyInteger Lib "mydll.dll" _ (ByVal v1 As Long, ByRef v2 As Long) As Long Private Declare Function MyCopyStruct Lib "mydll.dll" _ (ByRef v1 As MYSTRUCT, ByRef v2 As MYSTRUCT) As Long Private Sub Command1_Click() Dim rtn As Long ' APIの引数としてByteの値とByteの参照(アドレス)を渡す例 Dim v1_b As Byte Dim v2_b As Byte v1_b = 65 rtn = MyCopyChar(v1_b, v2_b) Debug.Print ("------MyCopyChar------") Debug.Print "v1_b=" & v1_b & ":" & "v2_b=" & v2_b Debug.Print "rtn=" & rtn ' APIの引数としてStringの値とStringの参照(アドレス)を渡す例 Dim v1_s As String Dim v2_s As String * 10 v1_s = "abcdefg" rtn = MyCopyString(v1_s, v2_s) Debug.Print ("------MyCopyString------") Debug.Print "v1_s=" & v1_s & ":" & "v2_s=" & v2_s Debug.Print "rtn=" & rtn ' APIの引数としてLongの値とLongの参照(アドレス)を渡す例 Dim v1_l As Long Dim v2_l As Long v1_l = 65 rtn = MyCopyInteger(v1_l, v2_l) Debug.Print ("------MyCopyInteger------") Debug.Print "v1_l=" & v1_l & ":" & "v2_l=" & v2_l Debug.Print "rtn=" & rtn ' APIの引数として構造体(配列メンバ有り)の参照(アドレス)を渡す例 Dim v1_t As MYSTRUCT Dim v2_t As MYSTRUCT v1_t.s1 = 65 v1_t.s2 = "abcdefg123" v1_t.s3 = 66 v1_t.s4(0) = 67 v1_t.s4(1) = 68 rtn = MyCopyStruct(v1_t, v2_t) Debug.Print ("------MyCopyStruct------") Debug.Print "v1_t.s1=" & v1_t.s1 & ":" & "v2_t.s1=" & v2_t.s1 Debug.Print "v1_t.s2=" & v1_t.s2 & ":" & "v2_t.s2=" & v2_t.s2 Debug.Print "v1_t.s3=" & v1_t.s3 & ":" & "v2_t.s3=" & v2_t.s3 Debug.Print "v1_t.s4(0)=" & v1_t.s4(0) & ":" & "v2_t.s4(0)=" & v2_t.s4(0) Debug.Print "v1_t.s4(1)=" & v1_t.s4(1) & ":" & "v2_t.s4(1)=" & v2_t.s4(1) Debug.Print "rtn=" & rtn End Sub ===実行結果======================================== ------MyCopyChar------ v1_b=65:v2_b=65 rtn=1 ------MyCopyString------ v1_s=abcdefg:v2_s=abcdefg rtn=7 ------MyCopyInteger------ v1_l=65:v2_l=65 rtn=4 ------MyCopyStruct------ v1_t.s1=65:v2_t.s1=65 v1_t.s2=abcdefg:v2_t.s2=abcdefg v1_t.s3=66:v2_t.s3=66 v1_t.s4(0)=67:v2_t.s4(0)=67 v1_t.s4(1)=68:v2_t.s4(1)=68 rtn=20
3.VB.NET(2005)からVC++のAPIを呼ぶサンプルソース Imports System.Runtime.InteropServices Public Class Form1 Private Structure MYSTRUCT1 Dim s1 As Byte <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=7)> Dim s2 As String Dim s3 As Integer <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Dim s4 As Integer() End Structure Private Structure MYSTRUCT2 Dim s1 As Byte <MarshalAs(UnmanagedType.ByValArray, SizeConst:=7)> Dim s2 As Byte() Dim s3 As Integer <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Dim s4 As Integer() End Structure Private Structure MYSTRUCT3 Dim s1 As Byte <MarshalAs(UnmanagedType.ByValArray, SizeConst:=7)> Dim s2 As Byte() Dim s3 As Integer <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Dim s4 As Integer() Sub New(ByVal dummy As Integer) ReDim s2(6) ReDim s4(1) End Sub End Structure Private Declare Function MyCopyChar Lib "mydll.dll" _ (ByVal v1 As Byte, ByRef v2 As Byte) As Integer Private Declare Function MyCopyString Lib "mydll.dll" _ (ByVal v1 As String, ByVal v2 As String) As Integer Private Declare Function MyCopyString Lib "mydll.dll" _ (ByVal v1 As String, ByVal v2 As Byte()) As Integer Private Declare Function MyCopyInteger Lib "mydll.dll" _ (ByVal v1 As Integer, ByRef v2 As Integer) As Integer Private Declare Function MyCopyStruct Lib "mydll.dll" _ (ByRef v1 As MYSTRUCT1, ByRef v2 As MYSTRUCT1) As Integer Private Declare Function MyCopyStruct Lib "mydll.dll" _ (ByRef v1 As MYSTRUCT2, ByRef v2 As MYSTRUCT2) As Integer Private Declare Function MyCopyStruct Lib "mydll.dll" _ (ByRef v1 As MYSTRUCT3, ByRef v2 As MYSTRUCT3) As Integer Private Sub Button1_Click( _ ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click Dim rtn As Integer ' APIの引数としてByteの値とByteの参照(アドレス)を渡す例 Dim v1_b As Byte Dim v2_b As Byte v1_b = 65 rtn = MyCopyChar(v1_b, v2_b) Debug.Print("------MyCopyChar------") Debug.Print("v1_b=" & v1_b & ":" & "v2_b=" & v2_b) Debug.Print("rtn=" & rtn) ' APIの引数としてStringの値とStringの参照(アドレス)を渡す例1 Dim v1_s1 As String Dim v2_s1 As String = New String("", 10) v1_s1 = "abcdefg" rtn = MyCopyString(v1_s1, v2_s1) Dim v2_s1_o As String = v2_s1 Dim l1 As Integer = v2_s1_o.IndexOf(Chr(0)) If l1 >= 0 Then v2_s1_o = v2_s1_o.Substring(0, l1) Debug.Print("------MyCopyString1------") Debug.Print("v1_s1=" & v1_s1 & ":" & "v2_s1=" & v2_s1_o) Debug.Print("rtn=" & rtn) ' APIの引数としてStringの値とStringの参照(アドレス)を渡す例2 Dim v1_s2 As String Dim v2_s2 As Byte() = New Byte(9) {} v1_s2 = "abcdefg" rtn = MyCopyString(v1_s2, v2_s2) Dim v2_s2_o As String = _ System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(v2_s2) Dim l2 As Integer = v2_s2_o.IndexOf(Chr(0)) If l2 >= 0 Then v2_s2_o = v2_s2_o.Substring(0, l2) Debug.Print("------MyCopyString2------") Debug.Print("v1_s2=" & v1_s1 & ":" & "v2_s2=" & v2_s2_o) Debug.Print("rtn=" & rtn) ' APIの引数としてIntegerの値とIntegerの参照(アドレス)を渡す例 Dim v1_l As Integer Dim v2_l As Integer v1_l = 65 rtn = MyCopyInteger(v1_l, v2_l) Debug.Print("------MyCopyInteger------") Debug.Print("v1_l=" & v1_l & ":" & "v2_l=" & v2_l) Debug.Print("rtn=" & rtn) ' APIの引数として構造体(配列メンバ有り)の参照(アドレス)を渡す例1 Dim v1_t1 As MYSTRUCT1 = New MYSTRUCT1 Dim v2_t1 As MYSTRUCT1 = New MYSTRUCT1 v1_t1.s1 = 65 v1_t1.s2 = "abcdefg123" v1_t1.s3 = 66 v1_t1.s4 = New Integer(1) {67, 68} rtn = MyCopyStruct(v1_t1, v2_t1) Debug.Print("------MyCopyStruct1------") Debug.Print("v1_t1.s1=" & v1_t1.s1 & ":" & "v2_t1.s1=" & v2_t1.s1) Debug.Print("v1_t1.s2=" & v1_t1.s2 & ":" & "v2_t1.s2=" & v2_t1.s2) Debug.Print("v1_t1.s3=" & v1_t1.s3 & ":" & "v2_t1.s3=" & v2_t1.s3) Debug.Print("v1_t1.s4(0)=" & v1_t1.s4(0) & ":" & "v2_t1.s4(0)=" & v2_t1.s4(0)) Debug.Print("v1_t1.s4(1)=" & v1_t1.s4(1) & ":" & "v2_t1.s4(1)=" & v2_t1.s4(1)) Debug.Print("rtn=" & rtn) ' APIの引数として構造体(配列メンバ有り)の参照(アドレス)を渡す例2 Dim v1_t2 As MYSTRUCT2 = New MYSTRUCT2 Dim v2_t2 As MYSTRUCT2 = New MYSTRUCT2 v1_t2.s1 = 65 v1_t2.s2 = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetBytes("abcdefg123") v1_t2.s3 = 66 v1_t2.s4 = New Integer(1) {67, 68} rtn = MyCopyStruct(v1_t2, v2_t2) Debug.Print("------MyCopyStruct2------") Debug.Print("v1_t2.s1=" & v1_t2.s1 & ":" & "v2_t2.s1=" & v2_t2.s1) Debug.Print("v1_t2.s2=" & _ System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(v1_t2.s2) & _ ":" & "v2_t.s2=" & _ System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(v2_t2.s2)) Debug.Print("v1_t2.s3=" & v1_t2.s3 & ":" & "v2_t2.s3=" & v2_t2.s3) Debug.Print("v1_t2.s4(0)=" & v1_t2.s4(0) & ":" & "v2_t.s4(0)=" & v2_t2.s4(0)) Debug.Print("v1_t2.s4(1)=" & v1_t2.s4(1) & ":" & "v2_t.s4(1)=" & v2_t2.s4(1)) Debug.Print("rtn=" & rtn) ' APIの引数として構造体(配列メンバ有り)の参照(アドレス)を渡す例3 Dim v1_t3 As MYSTRUCT3 = New MYSTRUCT3(0) Dim v2_t3 As MYSTRUCT3 = New MYSTRUCT3(0) v1_t3.s1 = 65 v1_t3.s2(0) = Asc("a") v1_t3.s2(1) = Asc("b") v1_t3.s2(2) = Asc("c") v1_t3.s2(3) = Asc("d") v1_t3.s2(4) = Asc("e") v1_t3.s2(5) = Asc("f") v1_t3.s2(6) = Asc("g") v1_t3.s3 = 66 v1_t3.s4(0) = 67 v1_t3.s4(1) = 68 rtn = MyCopyStruct(v1_t3, v2_t3) Debug.Print("------MyCopyStruct3------") Debug.Print("v1_t3.s1=" & v1_t3.s1 & ":" & "v2_t3.s1=" & v2_t3.s1) Debug.Print("v1_t3.s2=" & _ System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(v1_t3.s2) & _ ":" & "v2_t3.s2=" & _ System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(v2_t3.s2)) Debug.Print("v1_t3.s3=" & v1_t3.s3 & ":" & "v2_t3.s3=" & v2_t3.s3) Debug.Print("v1_t3.s4(0)=" & v1_t3.s4(0) & ":" & "v2_t3.s4(0)=" & v2_t3.s4(0)) Debug.Print("v1_t3.s4(1)=" & v1_t3.s4(1) & ":" & "v2_t3.s4(1)=" & v2_t3.s4(1)) Debug.Print("rtn=" & rtn) End Sub End Class ===実行結果======================================== ------MyCopyChar------ v1_b=65:v2_b=65 rtn=1 ------MyCopyString1------ v1_s1=abcdefg:v2_s1=abcdefg rtn=7 ------MyCopyString2------ v1_s2=abcdefg:v2_s2=abcdefg rtn=7 ------MyCopyInteger------ v1_l=65:v2_l=65 rtn=4 ------MyCopyStruct1------ v1_t1.s1=65:v2_t1.s1=65 v1_t1.s2=abcdefg:v2_t1.s2=abcdefg v1_t1.s3=66:v2_t1.s3=66 v1_t1.s4(0)=67:v2_t1.s4(0)=67 v1_t1.s4(1)=68:v2_t1.s4(1)=68 rtn=20 ------MyCopyStruct2------ v1_t2.s1=65:v2_t2.s1=65 v1_t2.s2=abcdefg:v2_t.s2=abcdefg v1_t2.s3=66:v2_t2.s3=66 v1_t2.s4(0)=67:v2_t.s4(0)=67 v1_t2.s4(1)=68:v2_t.s4(1)=68 rtn=20 ------MyCopyStruct3------ v1_t3.s1=65:v2_t3.s1=65 v1_t3.s2=abcdefg:v2_t3.s2=abcdefg v1_t3.s3=66:v2_t3.s3=66 v1_t3.s4(0)=67:v2_t3.s4(0)=67 v1_t3.s4(1)=68:v2_t3.s4(1)=68 rtn=20