32bit DLLを64bitアプリからcallすることはできません。今、何かの32bit DLLを持っているとして、これの64bit版が必ず入手できるとは限らない。そして、世の中は64bit化していって64bit DLLしか存在しないって状況もあり得る。ということは、64bitアプリから64bitDLLだけでなく32bitDLLを読み出さないといけないっていう需要は必ずある。
ちなみにMicrosoftはこう言っている。「アウトプロセス COM サーバーでラップ」しろ、、、と。なんとも難しいことを言う。
で、64bitアプリから32bitアプリにsocketで指示を出し、32bit dllの関数を実行し、結果を得るってところまでやりました。
で、いちいち32bitアプリを立ち上げるのはめんどうなので、64bitアプリから自動的に立ち上げる。今回は正直小ネタです。
ちょっとその前に32bitアプリをちょこっとだけ修正します。コンソールへの出力にサーバー側だってことがわかるよう(S)を付けます。そんだけ。
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("(S)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("(S)socket failed\n"); return -1; } if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR){ printf("(S)bind:error"); return -1; } if (listen(sock, 5) == SOCKET_ERROR){ printf("(S)listen:error"); return -1; } sockListen = accept(sock, (struct sockaddr *)&client, &clientlen); printf("(S)connected\n"); while (end == 0){ recvsize = recv(sockListen, buf, sizeof(buf), 0); if (recvsize > 0){ printf("(S)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("(S)%d + %d = %d\n",arg1.si4,arg2.si4,wa.si4); if (send(sockListen, &(wa.ui1[0]), 4, 0) < 0){ perror("(S)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("(S)%d - %d = %d\n",arg1.si4,arg2.si4,sa.si4); if (send(sockListen, &(sa.ui1[0]), 4, 0) < 0){ perror("(S)send"); return -1; } break; case DIRECTION_HALT: printf("(S)END\n"); end=1; break; } } } FreeLibrary(dll); closesocket(sockListen); closesocket(sock); WSACleanup(); return 0; }
#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("(C)send:"); for(int i=0;i<nsend;i++){printf("%02X",sendbuf[i]);} printf("\n"); nsent=send(*sockTalk, sendbuf, nsend, 0); if (nsent < 0){ perror("(C)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("(C)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("(C)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; STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); if(!CreateProcess(NULL,"MyDLLServer32.exe",NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){ printf( "(C)CreateProcess failed (%d).\n", GetLastError() ); return -1; } 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("(C)socket failed\n"); return -1; } if (connect(sockTalk, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0){ printf("(C)connect failed\n"); return -1; } arg1=10; arg2=3; wa=tasu(&sockTalk,arg1,arg2); printf("(C)%d + %d = %d\n",arg1,arg2,wa); sa=hiku(&sockTalk,arg1,arg2); printf("(C)%d - %d = %d\n",arg1,arg2,sa); getch();//process状態を確認するため一旦止める halt(&sockTalk); closesocket(sockTalk); WSACleanup(); // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return 0; }
こちらもコンソール出力に(C)を追加しています。
で、コンパイルして、
MyDLLClientApp64a.exe
を作る。
そして、実行。すると、
一つのコンソールに両方のプロセスから出力があります。なので(S)とか(C)とかつけたんですよ。
で、
getch()
を入れているので、止まります。ここでタスクマネージャ上ではどうなっているか見てみると、
こうなっているので、MyDLLServer32.exeを起動してくれたってのがわかります。
そして、黒い画面でEnterを押す。
終了になります。そして、
タスクマネジャからいなくなるので、意図通りです。
コメントをお書きください