2025年2月3日月曜日

Go言語入門(7)

 

興味本位でGo言語に触れてみようと思う。WSLで64bit Windows DLLを生成してしてみる。で、配列を引数や戻り値にする。



参考サイトは、、、ない。試行錯誤のみ。C言語みたいに引数がポインタなのに処理するコードは配列として扱うぜってことができない。ポインタだからと言ってアドレスをインクリメントして処理するってこともできない(やり方があるのかもしれんが)。で、構造体のポインタにキャストしてある意味無理矢理やっつける。
例によっていきなりコードを載せる。決め手はarr16とかarr32とかいう構造体を定義して、unsafe.Pointer()で引数(配列の先頭アドレス)を構造体型にキャストして、構造体の中の配列変数にアクセスしている。最初っから配列のサイズがわかっている場合はこれでいいけど、わかってない場合は、、、いずれ考えるかもしれない。

dlltry3.go
  1. package main
  2.  
  3. /*
  4. #include <stdint.h>
  5. */
  6. import "C"
  7. import "unsafe"
  8.  
  9. type arr16 struct {
  10.     v [16]C.uint8_t
  11. }
  12. type arr32 struct {
  13.     v [32]C.uint8_t
  14. }
  15.  
  16. //export myconnect
  17. func myconnect(a *C.uint8_t, b *C.uint8_t, c *C.uint8_t) C.int {
  18.     ap := (*arr16)(unsafe.Pointer(a))
  19.     bp := (*arr16)(unsafe.Pointer(b))
  20.     cp := (*arr32)(unsafe.Pointer(c))
  21.     for i := 0; i < 16; i++ {
  22.         (*cp).v[i] = (*ap).v[i]
  23.         (*cp).v[16+i] = (*bp).v[i]
  24.     }
  25.     return 0
  26.     /*
  27.         for i := 0; i < 16; i++ {
  28.             c[i] = a[i]
  29.             c[16+i] = b[i]
  30.         }
  31.         return 0
  32.     */
  33.     /*
  34.         for i := 0; i < 16; i++ {
  35.             *(c + i) = *(a + i)
  36.             *(c + 16 + i) = *(b + i)
  37.         }
  38.         return 0
  39.     */
  40. }
  41.  
  42. func main() {
  43.  
  44. }
C言語使いだとこうやっちゃうなーってのをコメントで残している。

dllmain.go
  1. package main
  2.  
  3. /*#include "dllmain.h"*/
  4. import "C"

dllmain.h
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <windows.h>
  4.  
  5. STARTUPINFO si;
  6. PROCESS_INFORMATION pi;
  7.  
  8. int32_t initialize(){
  9.     ZeroMemory(&si,sizeof(si));
  10.     si.cb=sizeof(si);
  11.     ZeroMemory(&pi,sizeof(pi));
  12.     if(!CreateProcess(NULL,"calc.exe",NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){
  13.         printf( "(C)CreateProcess failed (%d).\n", GetLastError() );
  14.         return -1;
  15.     }
  16.     return 0;
  17. }
  18. void finalize(){
  19.     // Close process and thread handles.
  20.     CloseHandle( pi.hProcess );
  21.     CloseHandle( pi.hThread );
  22. }
  23.  
  24. BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved ){
  25.     switch( fdwReason )
  26.     {
  27.         case DLL_PROCESS_ATTACH:
  28.             printf("DLL_PROCESS_ATTACH\n");
  29.             initialize();
  30.             break;
  31.  
  32.         case DLL_THREAD_ATTACH:
  33.             printf("DLL_THREAD_ATTACH\n");
  34.             break;
  35.  
  36.         case DLL_THREAD_DETACH:
  37.             printf("DLL_THREAD_DETACH\n");
  38.             break;
  39.  
  40.         case DLL_PROCESS_DETACH:
  41.             printf("DLL_PROCESS_DETACH_1\n");
  42.             if (lpvReserved != NULL){
  43.                 break; // do not do cleanup if process termination scenario
  44.             }
  45.             printf("DLL_PROCESS_DETACH_2\n");
  46.             finalize();
  47.             break;
  48.     }
  49.     return TRUE;
  50. }

Makefile
  1. OPT_CC= CC=x86_64-w64-mingw32-gcc
  2. #OPT_CC= CC=i686-w64-mingw32-gcc
  3. OPT_CGO= CGO_ENABLED=1
  4. OPT_OS= GOOS=windows
  5. OPT_ARCH= GOARCH=amd64
  6. #OPT_ARCH= GOARCH=386
  7. GOFLAGS=build -buildmode=c-shared
  8. #GOFLAGS=build -ldflags "-s -w" -buildmode=c-shared
  9. GO=go
  10. #SRCS=dll64wdllmain.go dllmain.go
  11. SRCS=dlltry3.go dllmain.go
  12. TARGET=dlltry3.dll
  13.  
  14. $(TARGET) : $(SRCS)
  15.     $(OPT_CC) $(OPT_CGO) $(OPT_OS) $(OPT_ARCH) $(GO) $(GOFLAGS) -o $(TARGET) $(SRCS)
  16.  
  17. clean :
  18.     rm dlltry3.dll dlltry3.h

dlltest3.c
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <windows.h>
  4. typedef int (__stdcall *myconnect_type)(uint8_t* a,uint8_t* b,uint8_t* c);
  5. HMODULE dll;
  6. myconnect_type myconnect;
  7.   
  8. int main(int argc,char** argv){
  9.     int r,i;
  10.     uint8_t aa[16]={0x12,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
  11.     uint8_t bb[16]={0xff,0xee,0xdd,0xcc,0xbb,0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x23};
  12.     uint8_t cc[32]={
  13.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  14.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  15.     };
  16.     dll=LoadLibrary("dlltry3.dll");
  17.     myconnect=(myconnect_type)GetProcAddress(dll,"myconnect");
  18.     r=myconnect(aa,bb,cc);
  19.     for(i=0;i<16;i++){
  20.         printf("%02x",aa[i]);
  21.     }
  22.     printf("\n");
  23.     for(i=0;i<16;i++){
  24.         printf("%02x",bb[i]);
  25.     }
  26.     printf("\n");
  27.     for(i=0;i<16;i++){
  28.         printf("%02x",cc[i]);
  29.     }
  30.     printf("\n");
  31.     for(;i<32;i++){
  32.         printf("%02x",cc[i]);
  33.     }
  34.     printf("\n");
  35.     return 0;
  36. }

まぁうまくいってる。
Goってどういう用途をターゲットにしているのかわからんけど、C言語で当たり前のことがなんとも困難。それだけC言語の自由度が高いってことなのか、、、もちっと公式の資料が充実していてもいいのに、、、あ、C言語の方が呪文系やろって思っている人も相当数いるか。まぁそんなもん。

なんたらショック(アレとアレです)が起こってマーケットがぁぁ( இωஇ )

0 件のコメント:

コメントを投稿