32bit DLLを64bitアプリからcallすることはできません。今、何かの32bit DLLを持っているとして、これの64bit版が必ず入手できるとは限らない。そして、世の中は64bit化していって64bit DLLしか存在しないって状況もあり得る。ということは、64bitアプリから64bitDLLだけでなく32bitDLLを読み出さないといけないっていう需要は必ずある。
ちなみにMicrosoftはこう言っている。「アウトプロセス COM サーバーでラップ」しろ、、、と。なんとも難しいことを言う。
で、COMサーバーについて、色々調べたところ、MFCやらATLやら、これらが世に現れたころBorland派だったので見て見ぬふりしていたワードがちらほら出てきて、結局のところ、VisualStudio(VSCodeではなく完全な開発環境)で作る例しか見つからなかった。、、、VisualStudioCommunityとか無料で入れられるけど、ライセンスとかどうなっているのか考えると企業でちょろっとやってみるにしてはハードルを感じる(ていうかダメっぽい)。VisualStudioExpressは問題なかった。
で、どうするか、「プロセス間通信 windows」でぐるぐるといくつか方法が出てくるけど、今回は比較的応用しやすそうなsocketを使う。socketというと、LANケーブルでつなぐやつって印象もあるけど、1つのPC内での通信にも使えるらしい。
さっそく、
server32.c
#include <stdio.h> #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wsaData; SOCKET sock; SOCKET sockListen; struct sockaddr_in addr; struct sockaddr_in client; socklen_t clientlen = sizeof(struct sockaddr_in); char buf[256]; char endcmd[] = "END"; int recvsize; int end = 0; WSAStartup(WINSOCK_VERSION, &wsaData); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.S_un.S_addr = INADDR_ANY; sock = socket(addr.sin_family, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { printf("socket failed\n"); return -1; } if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { printf("bind:error"); return -1; } if (listen(sock, 5) == SOCKET_ERROR) { printf("listen:error"); return -1; } sockListen = accept(sock, (struct sockaddr *)&client, &clientlen); printf("connected\n"); while (end == 0) { recvsize = recv(sockListen, buf, sizeof(buf), 0); if (recvsize > 0) { printf("%s\n", buf); if (strncmp(buf, endcmd, 3) == 0) { end = 1; } } } closesocket(sockListen); closesocket(sock); WSACleanup(); return 0; }
今回の目的からいうとserver側は32bitである必要があるので、(現時点ではファイル名だけの話だけど)server32.cとしています。
#pragma comment(lib, "ws2_32.lib")
って方法があるんやね、、、これがあると、
cl ws2_32.lib server32.c
ってせんでも
cl server32.c
でコンパイルできる。先人のコードはいろいろためになります。
相変わらずのコメントなし。ていうか先人のコードに書いてあったコメントまで消してるし。
そして、
client64.c
#include <stdio.h> #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wsaData; SOCKET sockTalk; struct sockaddr_in addr; char sendbuf[256]; WSAStartup(WINSOCK_VERSION, &wsaData); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockTalk = socket(addr.sin_family, SOCK_STREAM, 0); if (sockTalk == INVALID_SOCKET) { printf("socket failed\n"); return -1; } if (connect(sockTalk, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { printf("connect failed\n"); return -1; } sprintf(sendbuf,"I am a clinet."); if (send(sockTalk, sendbuf, strlen(sendbuf)+1, 0) < 0) { perror("send"); return -1; } Sleep(1000); sprintf(sendbuf,"END"); if (send(sockTalk, sendbuf, strlen(sendbuf)+1, 0) < 0) { perror("send"); return -1; } closesocket(sockTalk); WSACleanup(); return 0; }
2つの文字列を送っていますが、その間に待ち時間を入れずに一気に送ると、、、一気に受信されてしまいます。この辺がDLLラッパーとして構築する際はネックになってしまうかも。まぁ後で考える。
では、動くかどうかを試してみます。
まずはserver32.cを32bitでコンパイルします。
出てきた黒い画面で、
カレントフォルダ移動
cd /d C:\Users\hoge\Documents\mscpp-vscode\projects\dll32-study\socktest
コンパイル
cl server32.c
出来上がった実行ファイルが32bitかどうか確認
dumpbin /headers server32.exe | findstr machine
とやっていきます。
こうなります。ちゃんと32bitで出来上がっています。
次にclient64.cを64bitでコンパイルします。
出てきた黒い画面で、
cd /d C:\Users\hoge\Documents\mscpp-vscode\projects\dll32-study\socktest
cl client64.c
dumpbin /headers client64.exe | findstr machine
とやっていきます。
こうなります。ちゃんと64bitで出来上がっています。
では、実行してみます。
2つの黒い画面の「x64_86 Cross Tools (なんちゃら)」のほうで、
server32
と入れる。
そしてもう一つの黒い画面「x64 Native Tools (なんちゃら)」のほうで、
client64
と入れる。
そすと、server32を起動した「x64_86 Cross Tools (なんちゃら)」のほうに
connected
I am a clinet.
END
ってでるので、うまく逝ったんだろう。
で、こんだけやっちまってから、結局どうしたいのかというと、
なかなかしんどそう。うまく逝くのかどうか、、、
しかし、相変わらず、やりたいことが多すぎてどれにも手を着けられない。やらないといけないことが多すぎてどれもやる気がしない。
平均余命表によると、後33年でおわりらしい。長いようで短い。なんかわからんけど、ちょっと、あせる。
コメントをお書きください