从 Go 调用 NotifyIpInterfaceChange 导致访问冲突异常

Calling NotifyIpInterfaceChange from Go caused Access Violation exceptions

这是我第一次不得不从 Go 调用本机库。

我正在尝试使用 windows 库设置事件挂钩以侦听网络接口更改,到目前为止,我已经成功地使用 NotifyAddrChange.

设置了一个侦听器

现在我正在尝试 NotifyIpInterfaceChange 使用以下代码

package main

import (
    "golang.org/x/sys/windows"
    "log"
    "syscall"
    "unsafe"
)

var (
    modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")

    procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
)

type context struct{}

func main() {
    log.Printf("Loaded [iphlpapi.dll] at {%#v}", modiphlpapi.Handle())
    log.Printf("Found [NotifyIpInterfaceChange] at {%#v}", procNotifyIpInterfaceChange.Addr())

    context := &context{}
    interfaceChange := windows.Handle(0)

    ret, _, errNum := procNotifyIpInterfaceChange.Call(syscall.AF_UNSPEC, syscall.NewCallback(callback), uintptr(unsafe.Pointer(context)), 0, uintptr(interfaceChange))
    log.Printf("%#v %#v", ret, errNum)

}

func callback(callerContext, row, notificationType uintptr) uintptr {
    log.Printf("callback invoked by Windows API (%#v %#v %#v)", callerContext, row, notificationType)
    return 0
}

代码编译正常并且启动没有任何问题,一旦调用函数就会出现问题,然后我得到以下异常

D:\>event-listen_type2.exe
2017/06/22 22:12:39 Loaded [iphlpapi.dll] at {0x7ffac96f0000}
2017/06/22 22:12:39 Found [NotifyIpInterfaceChange] at {0x7ffac96f7e20}
Exception 0xc0000005 0x1 0x0 0x7ffac96f7edb
PC=0x7ffac96f7edb

syscall.Syscall6(0x7ffac96f7e20, 0x5, 0x0, 0x454170, 0x54d360, 0x0, 0x0, 0x0, 0xc042015350, 0xc042015300, ...)
        /usr/local/Cellar/go/1.8.3/libexec/src/runtime/syscall_windows.go:174 +0x6b
github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows.(*Proc).Call(0xc04203a620, 0xc042050300, 0x5, 0x5, 0x30, 0x4b12e0, 0x1, 0xc042050300)
        /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows/dll_windows.go:139 +0x5c1
github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows.(*LazyProc).Call(0xc042050270, 0xc042050300, 0x5, 0x5, 0x1, 0xc04201a000, 0xc04202df78, 0x4043a3)
        /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows/dll_windows.go:309 +0x66
main.main()
        /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/main_windows.go:25 +0x229
rax     0x0
rbx     0xc3f10
rcx     0x1fb5cd87abfd0000
rdi     0x0
rsi     0x454170
rbp     0xc04202dc00
rsp     0x8fdf0
r8      0x8fb78
r9      0x7ffac96fb4c0
r10     0x0
r11     0x8fcf0
r12     0x0
r13     0xffffffee
r14     0x0
r15     0xaa
rip     0x7ffac96f7edb
rflags  0x10246
cs      0x33
fs      0x53
gs      0x2b

从一些谷歌搜索中我知道异常类型 0xc0000005 是 CPU 抛出的访问冲突,当程序试图访问未分配给它的内存但查看我的代码时我不能告诉发生的地方。传递的所有指针都是针对应用程序中的项目。

这里的任何帮助都会很棒。

根据文档,NotifyIpInterfaceChange 的最新参数既是 in/out 又需要是 指向 HANDLE 的指针。将系统调用更改为:

ret, _, errNum := procNotifyIpInterfaceChange.Call(syscall.AF_UNSPEC,
    syscall.NewCallback(callback),
    uintptr(unsafe.Pointer(context)), 
    0, 
    uintptr(unsafe.Pointer(&interfaceChange)))   //this must be pointer

编辑:
评论和this go-nuts discussion中提到,对于多线程回调,需要添加import "C",即使我们不使用cgo