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

时间:2017-06-22 12:41:10

标签: windows exception go dll system-calls

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

我正在尝试使用Windows库设置事件挂钩以侦听网络接口更改,到目前为止,我已成功设置了NotifyAddrChange的侦听器。

现在我正在尝试使用以下代码的$search = 'sort'; // Identify the items having 'value' associated with $search $allItems = array_filter( $array['body'], function (array $item) use ($search) { // $item contains many tokens, keep $item if the first token has value == 'sort' // just to be sure you can also check here if $item[0]['token'] is 320 or the value of 'token_org_name' return $item[0]['value'] == $search; } ); // Pass all the found items to the function that produces the path foreach ($allItems as $item) { echo(getPath($item)."\n"); } function getPath(array $array) { // Collect the values here. // Start with an empty string to force a leading '/' in the output $path = array(''); // Walk the array, put the desired values in $path array_walk_recursive( $array, function($value, $key) use (&$path) { if ($key == 'value' ) { $path[] = $value; } } ); // Join the collected values and return the result return implode('/', $path); }

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 是CPU在程序试图访问未分配给它的内存但是查看我的代码时抛出的访问冲突我不能告诉它在哪里发生。传递的所有指针都是针对应用程序中的项目。

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

1 个答案:

答案 0 :(得分:1)

根据文档,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