32bit DLLを64bitアプリからcallすることはできません。今、何かの32bit DLLを持っているとして、これの64bit版が必ず入手できるとは限らない。そして、世の中は64bit化していって64bit DLLしか存在しないって状況もあり得る。ということは、64bitアプリから64bitDLLだけでなく32bitDLLを読み出さないといけないっていう需要は必ずある。
ちなみにMicrosoftはこう言っている。「アウトプロセス COM サーバーでラップ」しろ、、、と。なんとも難しいことを言う。
で、COMサーバーではなくsocketでやってみる。前回は64bitアプリと32bitアプリでsocketを使って通信する(情報共有する)ってところまでやりました。
最終目標はこう
ですが、今回はいったんここ
までやってみる。
socketでの通信プロトコルは自分で定義していかないといけない。今回は
int wa(int,int);
int sa(int,int);
だけなので単純に、
として、
waを実行する場合は関数識別に0x01を、saを実行する場合は関数識別に0x02を入れるってことにする。で関数識別0xFFは32bit appが終了するってことにする。DLLは32bit DLLを64bitアプリから使う(1)で作った、MyDLL32.dllを使うので、作業フォルダにコピーしておく。今回のソースファイルは、DLLを呼び出してsocketからの指示に応答するソフト(32bit app)をMyDLLServer32.c、socketに指示するソフト(64bit app)をMyDLLClientApp64.cとします。
こんな感じになる。
さっそく、
MyDLLServer32.c
#include <stdio.h> #include <stdint.h> #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib, "ws2_32.lib") #define DIRECTION_TASU 0x01 #define DIRECTION_HIKU 0x02 #define DIRECTION_HALT 0xFF typedef union si4_consisted_of_ui1{ int32_t si4; uint8_t ui1[4]; }SI4_C_UI1; /* for calling DLL */ #define MyDLL32 "MyDLL32.dll" typedef int32_t (__stdcall *tasu_type)(int32_t arg1,int32_t arg2); typedef int32_t (__stdcall *hiku_type)(int32_t arg1,int32_t arg2); HMODULE dll; tasu_type ptasu; hiku_type phiku; int main() { WSADATA wsaData; SOCKET sock; SOCKET sockListen; struct sockaddr_in addr; struct sockaddr_in client; socklen_t clientlen = sizeof(struct sockaddr_in); SI4_C_UI1 arg1; SI4_C_UI1 arg2; SI4_C_UI1 wa; SI4_C_UI1 sa; int8_t buf[256]; int8_t endcmd[] = "END"; int32_t recvsize; int32_t end = 0; /* load DLL and get function address*/ dll=LoadLibrary(MyDLL32); if(dll==NULL){ printf("Failed to load dll.\n"); return -1; } ptasu=(tasu_type)GetProcAddress(dll, "tasu"); phiku=(hiku_type)GetProcAddress(dll, "hiku"); 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("recv:"); for(int i=0;i<recvsize;i++){printf("%02X", buf[i]);} printf("\n"); switch((uint8_t)(buf[0])){ case DIRECTION_TASU: memcpy(&(arg1.ui1[0]),&(buf[1]),4); memcpy(&(arg2.ui1[0]),&(buf[5]),4); wa.si4=ptasu(arg1.si4,arg2.si4); printf("%d + %d = %d\n",arg1.si4,arg2.si4,wa.si4); if (send(sockListen, &(wa.ui1[0]), 4, 0) < 0){ perror("send"); return -1; } break; case DIRECTION_HIKU: memcpy(&(arg1.ui1[0]),&(buf[1]),4); memcpy(&(arg2.ui1[0]),&(buf[5]),4); sa.si4=phiku(arg1.si4,arg2.si4); printf("%d - %d = %d\n",arg1.si4,arg2.si4,sa.si4); if (send(sockListen, &(sa.ui1[0]), 4, 0) < 0){ perror("send"); return -1; } break; case DIRECTION_HALT: printf("END\n"); end=1; break; } } } FreeLibrary(dll); closesocket(sockListen); closesocket(sock); WSACleanup(); return 0; }
まぁ、何のことはない前々回のtestMyDLL32.cと前回のserver32.cをいい感じで混ぜただけ。
出てきた黒い画面で、
カレントフォルダ移動
cd /d C:\Users\hoge\Documents\mscpp-vscode\projects\dll32-study\dllsrv32
コンパイル
cl MyDLLServer32.c
出来上がった実行ファイルが32bitかどうか確認
dumpbin /headers MyDLLServer32.exe | findstr machine
こうなる。たぶんうまくいってるんだろう。
で、次は64bit app。
MyDLLClientApp64.c
#include <stdio.h> #include <stdint.h> #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib, "ws2_32.lib") #define DIRECTION_TASU 0x01 #define DIRECTION_HIKU 0x02 #define DIRECTION_HALT 0xFF typedef union si4_consisted_of_ui1{ int32_t si4; uint8_t ui1[4]; }SI4_C_UI1; int32_t sendbytes(SOCKET* sockTalk, int8_t* sendbuf, int32_t nsend){ int32_t nsent; printf("send:"); for(int i=0;i<nsend;i++){printf("%02X",sendbuf[i]);} printf("\n"); nsent=send(*sockTalk, sendbuf, nsend, 0); if (nsent < 0){ perror("send"); } return nsent; } int32_t tasu(SOCKET* sockTalk,int32_t arg1,int32_t arg2){ int8_t sendbuf[256]; int8_t buf[256]; int32_t recvsize; SI4_C_UI1 st_arg1; SI4_C_UI1 st_arg2; SI4_C_UI1 st_wa; st_arg1.si4=arg1; st_arg2.si4=arg2; sendbuf[0]=DIRECTION_TASU; memcpy(&(sendbuf[1]),&(st_arg1.ui1[0]),4); memcpy(&(sendbuf[5]),&(st_arg2.ui1[0]),4); sendbuf[9]='\0'; sendbytes(sockTalk,sendbuf,9); recvsize = recv(*sockTalk, buf, sizeof(buf), 0); if (recvsize > 0){ printf("recv:"); for(int i=0;i<recvsize;i++){printf("%02X", buf[i]);} printf("\n"); } memcpy(&(st_wa.ui1[0]),&(buf[0]),4); return st_wa.si4; } int32_t hiku(SOCKET* sockTalk,int32_t arg1,int32_t arg2){ int8_t sendbuf[256]; int8_t buf[256]; int32_t recvsize; SI4_C_UI1 st_arg1; SI4_C_UI1 st_arg2; SI4_C_UI1 st_wa; st_arg1.si4=arg1; st_arg2.si4=arg2; sendbuf[0]=DIRECTION_HIKU; memcpy(&(sendbuf[1]),&(st_arg1.ui1[0]),4); memcpy(&(sendbuf[5]),&(st_arg2.ui1[0]),4); sendbuf[9]='\0'; sendbytes(sockTalk,sendbuf,9); recvsize = recv(*sockTalk, buf, sizeof(buf), 0); if (recvsize > 0){ printf("recv:"); for(int i=0;i<recvsize;i++){printf("%02X", buf[i]);} printf("\n"); } memcpy(&(st_wa.ui1[0]),&(buf[0]),4); return st_wa.si4; } void halt(SOCKET* sockTalk){ int8_t sendbuf[256]; sendbuf[0]=DIRECTION_HALT; sendbuf[1]='\0'; sendbytes(sockTalk,sendbuf,2); } int main(){ WSADATA wsaData; SOCKET sockTalk; struct sockaddr_in addr; int8_t sendbuf[256]; int8_t buf[256]; int32_t recvsize; int32_t arg1,arg2,wa,sa; 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; } arg1=10; arg2=3; wa=tasu(&sockTalk,arg1,arg2); printf("%d + %d = %d\n",arg1,arg2,wa); sa=hiku(&sockTalk,arg1,arg2); printf("%d - %d = %d\n",arg1,arg2,sa); halt(&sockTalk); closesocket(sockTalk); WSACleanup(); return 0; }
まぁ、こんな感じ。
あ、今回から変数の型名をサイズがわかるような表現に変えました。
出てきた黒い画面で、
cd /d C:\Users\hoge\Documents\mscpp-vscode\projects\dll32-study\dllsrv32
cl MyDLLClientApp64.c
dumpbin /headers MyDLLClientApp64.exe | findstr machine
とやっていきます。
こうなります。ちゃんと64bitで出来上がっています。
では、実行してみます。
2つの黒い画面の「x64_86 Cross Tools (なんちゃら)」のほうで、
MyDLLServer32.exe
と入れる。
そしてもう一つの黒い画面「x64 Native Tools (なんちゃら)」のほうで、
MyDLLClientApp64.exe
と入れる。
そすと、MyDLLServer32を起動した「x64_86 Cross Tools (なんちゃら)」のほうに
connected
recv:010A00000003000000
10 + 3 = 13
recv:020A00000003000000
10 - 3 = 7
recv:FFFFFFFF00
END
そすと、MyDLLClientApp64を起動した「x64_86 Cross Tools (なんちゃら)」のほうに
send:010A00000003000000
recv:0D000000
10 + 3 = 13
send:020A00000003000000
recv:07000000
10 - 3 = 7
send:FFFFFFFF00
ってでる
ので、うまくいったんだろう。
ここまでは、いい感じ!がんばればいいこともある。、、、といいな。
コメントをお書きください