golang从dll获取char*作为返回值

我正在使用 golang 调用 Dll 函数,例如char* fn(),该 dll 不是我自己编写的,我无法更改它。这是我的代码:


package main


import (

    "fmt"

    "syscall"

    "unsafe"

)


func main() {

    dll := syscall.MustLoadDLL("my.dll")

    fn := dll.MustFindProc("fn")


    r, _, _ := fn.Call()


    p := (*byte)(unsafe.Pointer(r))

    // define a slice to fill with the p string

    data := make([]byte, 0)


    // loop until find '\0'

    for *p != 0 {

        data = append(data, *p)        // append 1 byte

        r += unsafe.Sizeof(byte(0))    // move r to next byte

        p = (*byte)(unsafe.Pointer(r)) // get the byte value

    }

    name := string(data) // convert to Golang string

    fmt.Println(name)

}

我有一些疑问:

  1. 有更好的方法吗?像这样的 dll 函数有数百个,我必须为所有函数编写循环。

  2. 对于像100k+字节这样的非常长的字符串,会append()导致性能问题吗?

  3. 解决了。原因unsafe.Pointer(r)linter govet显示警告possible misuse of unsafe.Pointer,但代码运行良好,如何避免此警告?解决方案:可以通过-unsafeptr=falsegovet命令行中添加来解决,对于vim-ale,添加let g:ale_go_govet_options = '-unsafeptr=false'

http://img.mukewang.com/64c0cd910001de9305570558.jpg

慕运维8079593
浏览 243回答 2
2回答

慕村9548890

将 uintptr 转换为上指针是非法的。您必须阅读规则: https://golang.org/pkg/unsafe/#Pointer但有一种 hacky 方法,不应该产生警告://go:linkname gostringn     runtime.gostringnfunc gostringn(p uintptr, l int) string//go:linkname findnull     runtime.findnull//go:nosplitfunc findnull(s uintptr) int// ....name := gostringn(r, findnull(r))函数接受指针,但我们从运行时将它们链接为 uintptr,因为它们具有相同的 sizeof。理论上可能有效。但也被人皱眉。回到你的代码,你可以用一行代码来完成:name := C.GoString((*C.char)(unsafe.Pointer(r)))

萧十郎

我通过跟踪go源码得到了以下解决方案os.Args,但是我是基于go1.17。如果您是其他版本,可以阅读源码来解决。func UintPtrToString(r uintptr) string {    p := (*uint16)(unsafe.Pointer(r))    if p == nil {        return ""    }    n, end, add := 0, unsafe.Pointer(p), unsafe.Sizeof(*p)    for *(*uint16)(end) != 0 {        end = unsafe.Add(end, add)        n++    }    return string(utf16.Decode(unsafe.Slice(p, n)))}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go