【问题原因:】
1:我在 func PP2 函数 使用map转JSON ,json.Marshal(obj) 返回[]byte 在string(str) 得到string 但是返回 客户端直接报错
,如果我直接使用 str :="JSON信息", 客户端调用OK。 【初步怀疑DLL服务端不能使用GO代码】,不知道有没有人遇到过这个问题。
2:原理很简单:就是 客户端吧数据传给DLL,然后DLL处理完毕,返回特定字符串我!并非整数 需要字符串返回的
3:我听说CGO调用CString后 貌似需要 C.free是否字符串 防止内存溢出, 不知道加哪里的
dll服务端代码部分:
~~~
package main
// #include <stdio.h>
// #include <stdlib.h>
import (
"C"
)
import (
"fmt"
//"unsafe"
)
//export PP2
func PP2(msg2 *C.char) *C.char {
//只能使用str :="字符串",如果使用以下map组合JSON 客户端调用马上报错
//map1 := make(map[string]string)
//map1["a"] = "1"
//map1["b"] = "2"
//map1["c"] = "3"
//json1, _ := Serialize(map1)*/ //这个函数用的是json.Marshal(obj) 返回[]byte 转换后实际还是string
//var str string = string(json1)
str := `{"a":"111","b":"2","c":"3"}`
msg2 = C.CString(str)
return msg2
}
func Serialize(obj interface{}) (b []byte, err error) {
b, err = json.Marshal(obj)
if err != nil {
return nil, err
}
return b, nil
}
~~~
调用客户端:
~~~
func main() {
//重来
dll3 := syscall.NewLazyDLL("mokuai2.dll")
f := dll3.NewProc("PP2")
r, _, _ := f.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("AAAA")))) //StringBytePtr
//获取C返回指针
p := (*byte)(unsafe.Pointer(r))
data := make([]byte, 0)
for *p != 0 {
data = append(data, *p)
r += unsafe.Sizeof(byte(0))
p = (*byte)(unsafe.Pointer(r))
}
name := string(data)
fmt.Println(name)
}
~~~
我也懵逼了,我发现导出下面这个方法,其他地方调用dll都报错,我看貌似是申请了堆内存。你的`str:="xxx"`实际上是栈内存,函数调用完就释放了。但是只要我在函数里面使用的方法会申请堆内存就会报错。我平时都是调用别人的dll,没用用go编写dll,我也坐等大神解惑额。还有就是`cgo`申请的内存不被Go接管,所以必须手动释放,因此`msg2 = C.CString(str)`申请了C内存,没有报错,至于啥地方释放就得你编写代码额。详情参考:[Go源码注释](https://github.com/golang/go/blob/c85848a4a62f839427bb56cb2772e008e405cf1f/src/cmd/cgo/doc.go#L269)
![image.png](https://static.golangjob.cn/221201/60ce58ffed1ac30e1fcab3c61c8aae6f.png)
```go
//export PrintBye
func PrintBye() {
fmt.Println("From DLL: Bye!")
}
```
#5
更多评论
我怀疑`syscall.StringToUTF16Ptr`用的不对,改为`syscall.StringBytePtr`试试看。前者转换的结果是双字节数据,和`*C.char`内存布局不同。
#1