· 

32bit DLLを64bitアプリから使う(4)

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;
}

で、コンパイルして、

MyDLLServer32.exe

を作る。

 

次に、64bit app側ですが、

単に、ここの通りにやっただけ。

 

MyDLLClientApp64a.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("(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を押す。

終了になります。そして、

タスクマネジャからいなくなるので、意図通りです。