如何从Windows API访问结构中的联合中的变量?

时间:2013-09-09 21:08:34

标签: struct go union cgo

我得到input.ki undefined (type C.INPUT has no field or method ki)

我尝试使用'union_'前缀,但没有任何运气。

有什么想法吗?

package main

// #include <windows.h>
// #include <winuser.h>
import "C"

// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
// typedef struct tagINPUT {
//   DWORD type;
//   union {
//     MOUSEINPUT    mi;
//     KEYBDINPUT    ki;
//     HARDWAREINPUT hi;
//   };
// } INPUT, *PINPUT;

func main() {
    var input C.INPUT
    var keybdinput C.KEYBDINPUT
    input._type = 1 // ok!
    // input.ki = keybdinput // input.ki undefined (type C.INPUT has no field or method ki)
    // input.union_ki = keybdinput // input.union_ki undefined (type C.INPUT has no field or method union_ki)
}

2 个答案:

答案 0 :(得分:2)

因为联合会打破类型安全,在Go中访问它们的唯一方法是使用不安全的包。我想你可以这样做:

*(*C.KEYBDINPUT)(unsafe.Pointer(uintptr(unsafe.Pointer(&input)) + unsafe.Sizeof(C.DWORD))) = keybdinput

如果我需要处理这些类型,我会声明包装类型以使其更容易:

type tagKbdInput struct {
    typ uint32
    ki  C.KEYBDINPUT
}

type tagMouseInput struct {
    typ uint32
    mi  C.MOUSEINPUT
}

type tagHardwareInput struct {
    typ uint32
    hi  C.HARDWAREINPUT
}

然后我可以通过unsafe.Pointer(没有指针算术)使用更简单的转换来访问它们:

(*tagKbdInput)(unsafe.Pointer(&input)).ki = keybdinput

答案 1 :(得分:0)

IIRC Go可能并非故意支持以任何方式访问工会会员。我认为你必须编写一个C包装器访问器函数来实现这一点。