いにしえの Borland C++ 5.02J (OWL) で作った DLL を年度ごとに切り替えて計算するシステムがあります
その DLL を VS2017 の Visual Basic から呼びだす必要があり、数十年ぶりに VB を使ってみました
# ウィンドウのある Basic は Windows 3.0A とかの頃だったかな…
Visual Studio 2017 は Visual Basic を選択して入れてありますので、折角ですので試してみました
1. DLL の種類
extern "C" double FAR _stdcall _export _calc_exec(int,int,double,double);
extern "C" void FAR _stdcall _export _get_version( char far*);
void FAR _stdcall _export _get_version( char far *ptr)
double FAR _stdcall _export _calc_exec( int type,int argv1,double argv2,double argv3)
こんな感じで C の関数を宣言して用意してあります
もちろん、旧システムでも、比較的最近の VS 2017 の C++ からも呼びだす事が出来ています
作っているのは、このためだけに VMware で飼っている Windows 2000 の Borland C++ 5.02J です
Turbo C の頃から飼い続けています ^^;
なので、 MS の C とは若干 書き方が違っていると思います
.
2. char* に文字列を返す
ANSI の文字列を VB へ返すだけの VOID 型の関数です
宣言と呼び出し方はこんな感じ
Public Declare Ansi Sub _get_version Lib "xxxx_h29.dll" (ByVal vers As String)
VOID 型なので Sub で宣言してあり、戻り値の指定がありません
呼出方
Dim vers As String
vers = New String(" ", 512)
_get_version(vers)
MessageBox.Show(vers.ToString, "DLL Load & char pointer TEST", MessageBoxButton.OK)
.
3. __stdcall の関数に int,double の引数並びを渡す
複数の引数を持つ STDCALL 宣言の関数に複数の引数を渡して、double 型の戻り値を受け取ります
また、上の関数も、複数の年度に渡って同名の関数がありますので、使い分けなければなりません
宣言と呼び出し方はこんな感じです
<DllImport("xxxx_h2.dll", CallingConvention:=CallingConvention.StdCall)>
Public Shared Function _calc_exec(ByVal TaxType As Integer, ByVal Huyou As Integer, ByVal Taxable As Double, ByVal Zengetsu As Double) As Double
End Function
<DllImport("xxxx_h29.dll", CallingConvention:=CallingConvention.StdCall, EntryPoint:="_calc_exec")>
Public Shared Function _calc_exec_h29(ByVal TaxType As Integer, ByVal Huyou As Integer, ByVal Taxable As Double, ByVal Zengetsu As Double) As Double
End Function
平成二年は基底なので、試しにそのまま宣言してみました
平成二十九年は 別名で宣言してみました
EntryPoint でエントリー名を指定して、別名の関数名にしてみました
Declareでは stdcall の指定が出来ませんので DllImport で宣言しています
前の関数の _get_version() は戻り値無しの、引数がポインター(整数一個)なので stdcall でも cdecl でも問題ないんだと思います
呼び出し方
Dim ret As Double
ret = 0
ret = _calc_exec(5, 2, 300000, 0)
MessageBox.Show(ret.ToString, "TEST H2", MessageBoxButton.OK)
ret = 0
ret = _calc_exec_h29(5, 2, 300000, 0)
MessageBox.Show(ret.ToString, "TEST H29", MessageBoxButton.OK)
こんな感じで、警告もエラーもなくダイアログボックスが表示されています
4.その他
VB のプロジェクトの設定で 64bit になっているかもしれません
Integer を Int16 にした方が良いときもあるかもしれません
なんて気楽に考えていたら、64bit で用意したプロジェクトからは 32bit の DLL をコールできません
解決方法もないようです…
System.BadImageFormatException: '間違ったフォーマットのプログラムを読み込もうとしました。 (HRESULT からの例外:0x8007000B)'
VOID で宣言してあるのにレザルトもナニもないだろう…
しかも、引数は 整数 (Int16 と宣言してもダメだった) と Double なのに…ねぇ..
さて、こまった…
実際は IIS のプロジェクトで利用する予定のようですが、うちの IIS じゃないので設定が変更できるかどうかも解りません ^^..
別に VS C# とか VS C++ でラップするしかないのかな…
メンテナンスコストを抑えるために、いにしえの資産の利用を考えているのに、中間アプリ作ってもなぁ…
IIS の設定で 32bit を有効化するするコトがきでるらしいのですが…
こういうとき、Basic はムズカシイネ…
.