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

C言語で作成されたDLLのVB.NETでの呼び出しについて

環境/言語:[OS : Windows XP Professional]
分類:[.NET]

【解決したい問題】

はじめまして
VB.NETを使用して1ヶ月のものです。

C言語で作成したDLLを呼び出し処理を行うプログラムを作成しています。
C言語のプログラムはUNIXベースの物で引数、処理等の変更はできません。
呼び出しのみ__declspec(dllexport)や__stdcall等を付加しています。
このDLLの関数をコールした際、値渡しの引数が渡らない(nullreference.exception)がthrowされる。参照渡しの場合戻り値が異常になるという現象に困っております。

以下のようなテストプログラムを作成しましたが同様の現象が発生します。
ネット上で調べた方法で作ってみたのですが、解決できません。
アドバイスいただきたいと思います。よろしくお願いします。

Tasu関数の引数を値渡しにするとNullReferenceExceptionがthrowされる。
Tasu関数の引数を参照渡しにすると戻り値が不正(1,1)を引数で渡した場合5327151016443906となる。

C言語
#include <windows.h>

#define Extern __declspec(dllexport)

#ifdef __cplusplus
extern "C" {
#endif
Extern int __stdcall Tasu();
#ifdef __cplusplus
extern }
#endif

Extern int __stdcall Tasu(x,y,z)
int *x;
int *y;
int *z;
{
*z = *x + *y;

return *z;
}

VB.NETのソース
Public Declare Ansi Function Tasu Lib "TESTDLL" (ByRef x As Long, ByRef y As Long, ByRef z As Long) As Long

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim a As Long = Val(CStr(TextBox1.Text))
Dim b As Long = Val(CStr(TextBox2.Text))
Dim c As Long

Dim d As Long = Tasu(a, b, c)


MsgBox(c)

End Sub
こんにちは。

> Tasu関数の引数を値渡しにするとNullReferenceExceptionがthrowされる。

こちらは tasu(x,y,z) の引数がポインタだからではないでしょうか。
ポインタに対して値渡しをしても、C言語側からはアドレスとしてしか
認識されないので、例えば TextBox1 に「1」と入力した場合は x
のアドレスが 1 になりますよね。その場合の *x の取りえる値を考
えると、
NullReferenceException が throw されることも納得が行くような
気がします。

> Tasu関数の引数を参照渡しにすると戻り値が不正(1,1)を引数で渡した場合5327151016443906となる。

これは C言語側と VB.NET 側の型が違っているためではないでし
ょうか。VB.NET 側では Long と指定していますが、C言語側では
int として処理されています。
MSDN で Long データ型を検索すると、以下のような解説がありま
す。

> -9,223,372,036,854,775,808 から 9,223,372,036,854,775,807
> (9.2...E+18) までの符号付き 64 ビット (8 バイト) の整数です。

また、以下の解説も。

> オートメーション オブジェクトや COM オブジェクトなど、.NET
> Framework 向けに作成されていないコンポーネントを使用する場
> 合、他の環境では整数型(Long) のデータ幅が異なる (32 ビット)
> ことに注意してください。そのようなコンポーネントに 32 ビットの
> 引数を渡す場合は、新しい Visual Basic のコードで、整数型
> (Long) ではなく短整数型 (Integer) として宣言します。

C言語側の int は 32 ビットなので、この場合は Long ではなく
Integer を渡す必要があるはずです。


ところで
> C言語で作成したDLLを呼び出し処理を行うプログラムを作成しています。
> C言語のプログラムはUNIXベースの物で引数、処理等の変更はできません。
DLL なのに UNIX ベースの物とは?
返事ありがとうございます。

>>Tasu関数の引数を値渡しにするとNullReferenceExceptionがthrowされる。
>
> こちらは tasu(x,y,z) の引数がポインタだからではないでしょうか。
> ポインタに対して値渡しをしても、C言語側からはアドレスとしてしか
> 認識されないので、例えば TextBox1 に「1」と入力した場合は x
> のアドレスが 1 になりますよね。その場合の *x の取りえる値を考
> えると、
> NullReferenceException が throw されることも納得が行くような
> 気がします。
説明不足で申し訳ありません。
例として貼り付けたプログラムは参照渡しになっていますが、これをC,VB側ともに値渡しにした場合にNullReferenceExceptionがthrowされてしまうのです。

>
>>Tasu関数の引数を参照渡しにすると戻り値が不正(1,1)を引数で渡した場合5327151016443906となる。
>
> これは C言語側と VB.NET 側の型が違っているためではないでし
> ょうか。VB.NET 側では Long と指定していますが、C言語側では
> int として処理されています。
> MSDN で Long データ型を検索すると、以下のような解説がありま
> す。
>
>>-9,223,372,036,854,775,808 から 9,223,372,036,854,775,807
>>(9.2...E+18) までの符号付き 64 ビット (8 バイト) の整数です。
>
> また、以下の解説も。
>
>>オートメーション オブジェクトや COM オブジェクトなど、.NET
>>Framework 向けに作成されていないコンポーネントを使用する場
>>合、他の環境では整数型(Long) のデータ幅が異なる (32 ビット)
>>ことに注意してください。そのようなコンポーネントに 32 ビットの
>>引数を渡す場合は、新しい Visual Basic のコードで、整数型
>>(Long) ではなく短整数型 (Integer) として宣言します。
>
> C言語側の int は 32 ビットなので、この場合は Long ではなく
> Integer を渡す必要があるはずです。

このサイトを参考にしてみましたのでlongにしていました。
http://www.angel.ne.jp/~mike/vb_dll/vb_dll04.html

すべてlongをintegerにして実行してみたところ無事動作しました。
ありがとうございます。

>>C言語で作成したDLLを呼び出し処理を行うプログラムを作成しています。
>>C言語のプログラムはUNIXベースの物で引数、処理等の変更はできません。
> DLL なのに UNIX ベースの物とは?
もともとUNIXのソフトをVBへ移植しているのです。
画面制御のみVBで記述して実際の計算処理等は共通のソースにするためです。

どうもありがとうございました。
解決済み!

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