我试着用Go中的callback来实现MiniDumpWriteDump.

MiniDumpWriteDump人的呼唤:

    callback := syscall.NewCallback(miniDumpCallback)
    var newCallbackRoutine MINIDUMP_CALLBACK_INFORMATION
    newCallbackRoutine.CallbackParam = 0
    newCallbackRoutine.CallbackRoutine = callback
    ret, _, err := miniDumpWriteDump.Call(
        uintptr(processHandle),
        uintptr(processId),
        uintptr(dumpFile),
        uintptr(options),
        0,
        0,
        uintptr(unsafe.Pointer(&newCallbackRoutine)),
    )

Callback功能本身:

func miniDumpCallback(_ uintptr, CallbackInput *MINIDUMP_CALLBACK_INPUT, _ uintptr) uintptr {
    fmt.Println(CallbackInput.ProcessId, CallbackInput.CallbackType)
    return 1
}

Type个定义:

type MINIDUMP_CALLBACK_INPUT struct {
    ProcessId     win32.ULONG
    ProcessHandle win32.HANDLE
    CallbackType  win32.ULONG
    CallbackInfo  uintptr
}

type MINIDUMP_CALLBACK_INFORMATION struct {
    CallbackRoutine uintptr
    CallbackParam   uintptr
}

调用回调后,一些字段会收到正确的数据,但有些字段会得到nonsensical个值.

例如,上面的回调正确地接收CallbackInputProcessId字段,但将随机整数接收为CallbackType,而它应该接收MINIDUMP_CALLBACK_TYPE个枚举.

输出:

12544 0
12544 1133445120
12544 12548
12544 13028
12544 1114112
12544 1023344640
12544 999620608
12544 990117888
12544 992542720
12544 1005518848
12544 1994850304
12544 1114112
12544 1994915840

推荐答案

正如 comments 所暗示的那样,问题出在structure alignment个.

正如@IInspectable解释的那样,导出MiniDumpWriteDump函数和MINIDUMP_CALLBACK_INPUT struct 的minidumPapiset.h对32bit64bit架构都使用4-byte对齐,而Go默认对64位使用8-byte对齐,并且不提供自动更改它的方法.

解决方案是手动读取 struct .下面是一个实用的例子:

type MINIDUMP_CALLBACK_INPUT struct {
ProcessId     uint32
ProcessHandle uintptr
CallbackType  uint32
CallbackInfo uintptr}

func ptrToMinidumpCallbackInput(ptrCallbackInput uintptr) MINIDUMP_CALLBACK_INPUT{
    var input MINIDUMP_CALLBACK_INPUT
    input.ProcessId = *(*uint32)(unsafe.Pointer(ptrCallbackInput))
    input.ProcessHandle = *(*uintptr)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0))))
    input.CallbackType = *(*uint32)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0)) + unsafe.Sizeof(uintptr(0))))
    input.CallbackInfo = *(*uintptr)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0)) + unsafe.Sizeof(uintptr(0)) + unsafe.Sizeof(uint32(0))))
    return input}

原始代码应该可以在32位体系 struct 上很好地工作,因为它的填充(4字节)与minidumPapiset.h使用的填充相匹配.

Go相关问答推荐

正在使用terratest执行terraform脚本测试,但遇到错误退出状态1

如何修复Go中调用GetRawInputDeviceInfA Windows API函数时的错误?

[0]Func()as";请勿比较哨兵类型

如何在Golang中使用ECHO服务器实现Socket.IO服务器

如果第一次匹配条件,如何跳过切片中的值

将这两个函数合二为一的惯用方法

Go Gin:验证 base64

如何将任何类型的数据值传递到 Golang 中的 GRPC Protobuf struct ?

Golang 中的泛型类型转换

Go http.FileServer 给出意外的 404 错误

查找、解析和验证邮箱地址

使用 go.work 文件在多个测试文件上运行 go test 命令

使用innerxml在 Go 中编码 XML 是否仅适用于某些类型?

没有堆栈跟踪的 go 程序崩溃是什么意思?

将 Simple Go Web 应用程序部署到 Elastic Beanstalk

Go:为一组单个结果实现 ManyDecode

如何使用通用字段初始化匿名struct数组

如何将类型转换为字节数组golang

Golang 查询扫描未将查询正确扫描到 struct 中

如何在程序退出时使用 golang 删除文件?