· 

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

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

 

ってでる

ので、うまくいったんだろう。

ここまでは、いい感じ!がんばればいいこともある。、、、といいな。