syscall GetLastError()不会返回错误

时间:2017-09-21 07:23:31

标签: c++ winapi go

在golang syscall.GetLastError()中不会返回上一个错误。请参阅以下示例

if handle := _OpenSCManager(machineNamePtr, databaseNamePtr, desiredAccess); handle == nil {
    if err := syscall.GetLastError(); err != nil {
        return InvalidServiceDatabaseHandleHandle, ServiceErrno(err.(syscall.Errno))
    }
}

err始终为nil。假设machineNamePtr是一台不存在的机器。使用c ++和GetLastError()测试相同的代码抛出RPC server is not available。那么为什么不在go

修改

_OpenSCManager是使用go generate生成的。 //sys _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle) = advapi32.OpenSCManagerW

func _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle) {
r0, _, _ := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(desiredAcces))
handle = ServiceDatabaseHandle(r0)
return

}

2 个答案:

答案 0 :(得分:0)

所以我终于有了这个工作。首先,我尝试使用以下签名//sys _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle, lasterror error) = advapi32.OpenSCManagerW返回错误变量。但go generate总是Only last windows error is allowed as second return value...。但如果将其更改为//sys ... (handle ServiceDatabaseHandle, err error) = advapi32.OpenSCManagerW,则会成功生成代码。所以你明确要写err error。有人知道为什么吗?所以现在函数看起来像

func _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle, err error) {
r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(desiredAcces))
handle = ServiceDatabaseHandle(r0)
if handle == 0 {
    if e1 != 0 {
        err = errnoErr(e1)
    } else {
        err = syscall.EINVAL
    }
}
return
}

并返回错误。因此无需致电GetLastError()

答案 1 :(得分:0)

IIUC,Windows上的syscall.Syscall()在实际系统调用完成后自动和原子调用GetLastError()。这应该是可以理解的,一旦你考虑到goroutine从系统调用退出,Go运行时调度程序可以自由地抢占它并在正好运行的刚刚被抢占的goroutine的线程上运行另一个goroutine。 / em>的

由于GetLastError()访问每线程状态,如果第二个goroutine进行另一个系统调用,它可能会破坏最后一个错误值,因此在Go的上下文中,每个系统调用都应伴随以下对{的调用{1}}在单个系统调用调用的上下文中完成 - 从Go端看。