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を押す。
終了になります。そして、
タスクマネジャからいなくなるので、意図通りです。

コメントをお書きください