gpt4 book ai didi

go - 如何优雅地从 `syscall.Syscall()`的使用迁移?

转载 作者:行者123 更新时间:2023-12-03 10:06:39 26 4
gpt4 key购买 nike

不推荐使用 syscall 软件包。假设我有以下代码,希望将其迁移到不推荐使用的代码中:

someGoObject := &struct{int; float32}{5, 45.4}
syscall.Syscall6(someProc.Addr(), 1, uintptr(unsafe.Pointer(someGoObject)), 0, 0, 0, 0, 0)
其中 someProc的类型为 *syscall.LazyProc( Windows)。 syscall文档建议改为使用的 sys subrepository不再提供类似于 syscall.Syscall的功能,并且如果未在此处实现所需的功能,则可以尝试通过以下方式解决问题,并认为工作已完成:
someProc.Call(uintptr(unsafe.Pointer(someGoObject)))
因此,现在 someProc的类型为 *windows.LazyProc
但是,如果这样做,我们就不会获得 syscall.Syscall(和 friend )的担保之一,因为 LazyProc.Call() is not implemented in assembly:

(4) Conversion of a Pointer to a uintptr when calling syscall.Syscall.

The Syscall functions in package syscall pass their uintptr argumentsdirectly to the operating system, which then may, depending on thedetails of the call, reinterpret some of them as pointers. That is,the system call implementation is implicitly converting certainarguments back from uintptr to pointer.

If a pointer argument must be converted to uintptr for use as anargument, that conversion must appear in the call expression itself:

syscall.Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(n))

The compiler handles a Pointer converted to a uintptr inthe argument list of a call to a function implemented in assembly byarranging that the referenced allocated object, if any, is retainedand not moved until the call completes, even though from the typesalone it would appear that the object is no longer needed during thecall.

For the compiler to recognize this pattern, the conversion must appearin the argument list:

// INVALID: uintptr cannot be stored in variable
// before implicit conversion back to Pointer during system call.
u := uintptr(unsafe.Pointer(p))
syscall.Syscall(SYS_READ, uintptr(fd), u, uintptr(n))

(摘自 https://golang.org/pkg/unsafe/)
从我的角度来看,唯一安全的方法是使用C分配内存。但是,这意味着我们需要复制数据并增加需要编写的代码量。
someObject := (*struct{int; float32})(C.calloc(1, unsafe.Sizeof(struct{int; float32}{}))) // Alloc
*someObject = struct{int; float32}{123, 456.789} // Fill with desired data
someProc.Call(uintptr(unsafe.Pointer(someObject))) // The actual call
C.free(unsafe.Pointer(someObject)) // Clean up

有没有更好的办法?

最佳答案

我认为处理此问题的正确方法是使用mkwinsyscall工具。
您可以这样创建一个Go文件:

package main
//go:generate mkwinsyscall -output zmsi.go msi.go
//sys MsiOpenDatabase(dbPath string, persist int, db *windows.Handle) (e error) = msi.MsiOpenDatabaseW
然后运行 go generate,您将得到一个这样的结果文件(某些部分已删除
为简洁起见):
func MsiOpenDatabase(dbPath string, persist int, db *windows.Handle) (e error) {
var _p0 *uint16
_p0, e = syscall.UTF16PtrFromString(dbPath)
if e != nil {
return
}
return _MsiOpenDatabase(_p0, persist, db)
}

func _MsiOpenDatabase(dbPath *uint16, persist int, db *windows.Handle) (e error) {
r0, _, _ := syscall.Syscall(procMsiOpenDatabaseW.Addr(), 3, uintptr(unsafe.Pointer(dbPath)), uintptr(persist), uintptr(unsafe.Pointer(db)))
if r0 != 0 {
e = syscall.Errno(r0)
}
return
}
如您所见,它也会自动处理字符串转换
作为Syscall代码,甚至是错误处理。

关于go - 如何优雅地从 `syscall.Syscall()`的使用迁移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57979613/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com