【Excel(64bit) VBA】【Winsock API】recvfrmの第2引数(char* buf)にはVBAからByval string型で渡す必要がある件

EXCEL

 3日くらいドはまりした。しかも、あまり納得できていないがそういうものだと思うしかない。そして、調べてみたら、この件について思うことや対応策を考えている人がわずかにいて、安心した。

まず前提(自分の思い込みかもしれないが)

  • VB(VBA)を多少かじったものとして、Byvalは値渡し、Byrefは参照渡し、参照渡しであれば、処理結果が戻ってくるという認識を持っている。
  • C言語もちょっとだけかじったものとして、関数の引数にchar * とあれば char 型のポインタが必要だんだな、参照渡しだね と判断している。

この前提でrecvfrmの定義をmirosoftのサイトで確認すると、第2引数は char *buf となっているため、 参照渡しが必要だとわかる。

ちなみに第3引数 int len が 第2引数のサイズ(長さ)を示し、処理が成功すれば、第2引数 char *buf を先頭アドレス len バイト分のデータ電文をが受信できる。だったら、recvfrmの第2引数はbyref(参照渡し)指定だねと思うがこれが間違い。デバッグ中にExcelが突然死するほど目にあった。

int recvfrom(
  SOCKET   s,
  char     *buf,
  int      len,
  int      flags,
  sockaddr *from,
  int      *fromlen
);

正解はByval 指定

一例、まず定義では、第2引数はbyvalのstring型とする。

Public Declare PtrSafe Function recvfrom Lib "wsock32.dll" (ByVal SOCKET As LongPtr, ByVal buf As String, ByVal length As LongPtr, ByVal Flags As Long, fromAddr As SOCKADDR_IN, fromAddrSize As Long) As Long

recvfromの呼び出し方は以下の通り

Const RecvBuffSize As Long = 2048
 Dim recvBuffer As String * RecvBuffSize

~~ 略 ~~
recvResult = recvfrom(ListenSocketHandle, recvBuffer, RecvBuffSize, 0, remoteAddr, LenB(remoteAddr))

このパターンでサンプルコードを作成したら、確かに電文受信ができた。

その理由(Microsoftのサイトより、仕様確認)

C/C++ および VBA の引数の型
C/C++ と VBA の引数の型の宣言を比較するときには、次の点に注意が必要です。
VBA の String は、ByVal 渡しの場合はバイト文字列 BSTR 構造体へのポインターとして渡されます。ByRef 渡しの場合はポインターへのポインターとして渡されます。

Excel で DLL にアクセスする | Microsoft Docs

つまり、Byval Stringと定義して stringを渡せば、それがそのまま string型の先頭アドレス(ポインタ)がwsock32.dllのrecvfromにわたっているらしい。

これ正直、あまり納得できないわかりずらい仕様だと思う。

でも慣れていくしかないかな。新しい知識が増えたと思って

その仕様に関する先人の見解や対応策

http://chaichan.lolipop.jp/vbtips/VBMemo200708-26.htm

Win32APIの関数をVBで使うには… - Programming Field
VBでWin32APIの関数を呼び出す際に、全般的にどのようにDeclareステートメントを記述することで呼び出すことができるようになるかを解説しています。
Excel VBA で Win32API CreateFileA などの String型引数は、なぜ ByVal?
Excel VBA から Win32API を実行する場合の、String型引数に関する質問です。【背景】Win32API の CreateFileA,MoveFileA,DeleteFileA など、関数名最後が "A" となている関数の...
404 Not Found - Qiita - Qiita
「VB6.0 と VC++6.0 の連携」(1) VB業務アプリケーション開発研究室 − @IT
「VB6.0 と VC++6.0 の連携」に関する質問と回答の一覧です。(1) VB業務アプリケーション開発研究室 − @IT
Excel で DLL にアクセスする
Office 開発者クライアント VBA リファレンス ドキュメント

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました