DOBON.NET DOBON.NETプログラミング掲示板過去ログ

64bit版DLLとの値の受け渡しがうまくいかない

環境/言語:[Windows7 64Bit ,Visual Studio 2005 Academic,]
分類:[.NET]

2012/06/28(Thu) 14:30:51 編集(投稿者)

はじめまして。
Windows7(32Bit) で利用していたDLLをWindows7(64Bit)へ移植する必要が発生し
調べているうちにここへたどり着きました。

VB2005でテストプログラムを作成し、とVC2005でテスト用DLLを作成したのですが
VB側exeをターゲットCPUをx86、VC側DLLをWin32でコンパイルすれば正常に動作する
関数が、VB側exeをターゲットCPUをx64、VC側DLLをx64でコンパイルすると異常な動作になります。

VB側のプログラム----------

Declare Sub TEST_FUNC Lib "MPL.dll" ( Byref Source As Byte )

Private Sub Command1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Command1.Click

Private wdata1(DATA - 1) As Byte

Dim i As Long
For i = 0 To DATA - 1
wdata1(i) = i
Next

TEST_FUNC(wdata1(0))

End Sub

VC側のプログラム----------

void TEST_FUNC(char *pnData)
{
long i;
short int iDat1;

for(i=0;i<10;i++){
iDat1 = *pnData;
sprintf(bufDBG,"iDat1 = %x\n",iDat1);
OutputDebugString(bufDBG);
pnData++;
}

}

正常に動作すれば、VC側でpnDataポインタで0,1,2,3,4,5,6,7,8,9と参照できると思うのです。x86でコンパイルするとそのように動作するのですが、x64でコンパイルすると、まったく関係ない値が取得されます。

64ビットネイティブコードでDLLを作成する必要があります。
(WOW64は使えない環境というかWOW64に対応していないデバイスを利用する必要がある。)

なぜこのような違いが生まれるのでしょうか?
よろしくお願いいたします。
> Declare Sub TEST_FUNC Lib "MPL.dll" ( Source As Byte )
Source As ByteにByRef付けてないと環境によらず決して想定の動作はしない気がするのですけど。

VB.NETでは、アンマネージ関数が引数に配列を要求する場合、Declare文における引数も配列で定義するのが一般的です。
ByVal source As Byte()
ByRefで配列の先頭要素を渡したときに動作していたのはあくまで偶然であったとお考えください。
2012/06/28(Thu) 15:03:32 編集(投稿者)

すみません。コピーミスでした。

ByRef Source As Byte

このように宣言しています。この部分を

ByRef Source As Byte()

このように変更してみましたが、変化はありませんでした。
ちなみにByValだと値は思う通りの値が渡されますが、
DLL側で値に変更を行ってVB側へ返すには、Byrefでなければなりませんよね?

■No30652に返信(Hongliangさんの記事)
>>Declare Sub TEST_FUNC Lib "MPL.dll" ( Source As Byte )
> Source As ByteにByRef付けてないと環境によらず決して想定の動作はしない気がするのですけど。
>
> VB.NETでは、アンマネージ関数が引数に配列を要求する場合、Declare文における引数も配列で定義するのが一般的です。
> ByVal source As Byte()
> ByRefで配列の先頭要素を渡したときに動作していたのはあくまで偶然であったとお考えください。
■No30653に返信(shouichi_M3さんの記事)
> このように変更してみましたが、変化はありませんでした。
> ちなみにByValだと値は思う通りの値が渡されますが、
> DLL側で値に変更を行ってVB側へ返すには、Byrefでなければなりませんよね?

ByValです。
ただし,OutAttributeを付けて,書き換えられることを宣言する必要があります。
Declare Sub TEST_FUNC Lib "MPL.dll" (<[In], Out> ByVal source As Byte())

詳しくは,
・アンマネージ コードとの相互運用 http://msdn.microsoft.com/ja-jp/library/sd10k43k(v=vs.80)
から,
・型の配列のマーシャリング http://msdn.microsoft.com/ja-jp/library/dd93y453(v=vs.80)
とか
・さまざまな型の配列のマーシャリング http://msdn.microsoft.com/ja-jp/library/hk9wyw21(v=vs.80)
を参照するとよいでしょう。
ありがとうございます。正常動作しました。

宣言を下記に変更し、

Declare Sub TEST_FUNC Lib "MPL.dll" (<[In](), Out()> ByVal Source() As Byte )

呼び出し部を下記のように変更すると、DLL側で値の参照が可能で、DLL内部での
変更が可能になりました。

TEST_FUNC(wdata1)

VB6ではDLL内部での変更を行う場合、Byrefである必要があったので、混乱しますね。
でもそうなると、VB2005のByrefは何のためにあるのかですね?。

■No30654に返信(YuOさんの記事)
> ■No30653に返信(shouichi_M3さんの記事)
>>このように変更してみましたが、変化はありませんでした。
>>ちなみにByValだと値は思う通りの値が渡されますが、
>>DLL側で値に変更を行ってVB側へ返すには、Byrefでなければなりませんよね?
>
> ByValです。
> ただし,OutAttributeを付けて,書き換えられることを宣言する必要があります。
> Declare Sub TEST_FUNC Lib "MPL.dll" (<[In], Out> ByVal source As Byte())
>
> 詳しくは,
> ・アンマネージ コードとの相互運用 http://msdn.microsoft.com/ja-jp/library/sd10k43k(v=vs.80)
> から,
> ・型の配列のマーシャリング http://msdn.microsoft.com/ja-jp/library/dd93y453(v=vs.80)
> とか
> ・さまざまな型の配列のマーシャリング http://msdn.microsoft.com/ja-jp/library/hk9wyw21(v=vs.80)
> を参照するとよいでしょう。

DOBON.NET | プログラミング道 | プログラミング掲示板