在Golang生成的DLL桩代码中,我们可以看到各Go语言基础类型的对应定义(以下为64位系统的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
/* Created by "go tool cgo" - DO NOT EDIT. */ /* package command-line-arguments */ #line 1 "cgo-builtin-prolog" #include <stddef.h> /* for ptrdiff_t below */ #ifndef GO_CGO_EXPORT_PROLOGUE_H #define GO_CGO_EXPORT_PROLOGUE_H typedef struct { const char *p; ptrdiff_t n; } _GoString_; #endif /* Start of preamble from import "C" comments. */ /* End of preamble from import "C" comments. */ /* Start of boilerplate cgo prologue. */ #line 1 "cgo-gcc-export-header-prolog" #ifndef GO_CGO_PROLOGUE_H #define GO_CGO_PROLOGUE_H typedef signed char GoInt8; typedef unsigned char GoUint8; typedef short GoInt16; typedef unsigned short GoUint16; typedef int GoInt32; typedef unsigned int GoUint32; typedef long long GoInt64; typedef unsigned long long GoUint64; typedef GoInt64 GoInt; typedef GoUint64 GoUint; typedef __SIZE_TYPE__ GoUintptr; typedef float GoFloat32; typedef double GoFloat64; typedef float _Complex GoComplex64; typedef double _Complex GoComplex128; /* static assertion to make sure the file is being used on architecture at least with matching size of GoInt. */ typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; typedef _GoString_ GoString; typedef void *GoMap; typedef void *GoChan; typedef struct { void *t; void *v; } GoInterface; typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; #endif /* End of boilerplate cgo prologue. */ #ifdef __cplusplus extern "C" { #endif extern void PrintBye(); extern GoInt Sum(GoInt p0, GoInt p1); extern GoUint8 SetupUserByBDUSS(GoString p0, GoString* p1); extern GoUint8 CheckLoginStatus(GoString* p0); extern GoUint8 FilesDirectoriesList(GoString p0, GoString* p1); extern GoUint8 Config(GoInt p0, GoInt p1, GoInt p2, GoString p3, GoString* p4); #ifdef __cplusplus } #endif |
其中,第一个就是GoString的定义:
1 |
typedef struct { const char *p; ptrdiff_t n; } _GoString_; |
在《Golang编译成DLL文件》一文中给出了一个GoString在C#中的实现:
这种方式对于英文字符串而言没有问题,但对于中文字符串而言则会导致抛出异常:
其中,fmt.Printf的乱码是由于Console不支持UTF8编码,无甚大碍。而该异常:
1 |
在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符。 (异常来自 HRESULT:0x80070459) |
表示遇到了非法的Unicode CodePoint。然而,搜遍全网均未找到该问题与Golang相关的结果。
实际上,虽然字符串在Go语言内部是使用UTF编码的,但转成DLL后其编码格式变为UTF-8,故而GoString的正确定义应该是:
由于使用了运算符重载,因而我们可以像使用普通字符串一样的方式使用GoString了,而且不会有乱码和异常问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[DllImport("exportgo.dll", EntryPoint = "Test1")] static extern bool Test1(GoString bduss, ref GoString errorMessage); [DllImport("exportgo.dll", EntryPoint = "Test")] static extern bool Test2(GoString path, ref GoString jsonResult); private void button_Click(object sender, EventArgs e) { GoString testString1 = "test"; GoString errorMessage = new GoString(); bool result = Test1(testString1, ref errorMessage); result = Test2("/", ref errorMessage); Console.WriteLine(errorMessage); } |
参考资料:
1、https://zhuanlan.zhihu.com/p/46979047
2、https://github.com/Baozisoftware/go-dll/wiki/C%23%E8%B0%83%E7%94%A8Go%E7%89%88DLL%E7%9A%84%E5%AE%8C%E6%95%B4%E7%A4%BA%E4%BE%8B
转载时请保留出处,违法转载追究到底:进城务工人员小梅 » 全网首发:.Net中调用Go语言DLL时使用GoString的正确姿势(解决.Net中调用Go语言DLL时中文乱码和Unicode的异常问题)