我在我的Direct3D9 Go 包装器中遇到了类似的问题,请参阅这个线程,在那里我能够从纯 Go 调用 DirectX COM 函数。


在您的代码中,您尝试调用proc.ConnectServer(...),但调用 a 的方法syscall.LazyProc是使用它的Call函数。查看 DllGetClassObject的文档,签名是


HRESULT __stdcall DllGetClassObject(

  _In_  REFCLSID rclsid,

  _In_  REFIID   riid,

  _Out_ LPVOID   *ppv

);

这意味着您必须将这三个参数传递给proc.Callas uintptrs(Call期望所有参数都是uintptrs)。


package main


import "syscall"


var (

    xaSession      = syscall.NewLazyDLL("XA_Session.dll")

    getClassObject = xaSession.NewProc("DllGetClassObject")

)


func main() {

    // TODO set these variables to the appropriate values

    var rclsid, riid, ppv uintptr

    ret, _, _ := getClassObject.Call(rclsid, riid, ppv)

    // ret is the HRESULT value returned by DllGetClassObject, check it for errors

}

请注意,您需要正确设置参数值,CLSID 和 IID 可能包含在库随附的 C 头文件中,我不知道这个 XA_Session 库。


在这种ppv情况下,将是指向您创建的 COM 对象的指针。要使用 Go 中的 COM 方法,您可以创建包装器类型,前提是您知道它定义的所有 COM 方法及其正确顺序。所有 COM 对象都支持和函数QueryInterface,然后支持其他类型特定的方法。AddRefRelease


假设您的 XA_Session 对象还支持这两个功能(同样,我不知道它真正支持什么,您必须查一下)


int ConnectServer(int id)

DisconnectServer()

那么你可以做些什么来将它包装在 Go 中:


package xasession


import (

    "syscall"

    "unsafe"

)


// NewXASession casts your ppv from above to a *XASession

func NewXASession(ppv uintptr) *XASession {

    return (*XASession)(unsafe.Pointer(ppv))

}


// XASession is the wrapper object on which to call the wrapper methods.

type XASession struct {

    vtbl *xaSessionVtbl

}


type xaSessionVtbl struct {

    // every COM object starts with these three

    QueryInterface uintptr

    AddRef         uintptr

    Release        uintptr

    // here are all additional methods of this COM object

    ConnectServer    uintptr

    DisconnectServer uintptr

}


func (obj *XASession) AddRef() uint32 {

    ret, _, _ := syscall.Syscall(

        obj.vtbl.AddRef,

        1,

        uintptr(unsafe.Pointer(obj)),

        0,

        0,

    )

    return uint32(ret)

}


func (obj *XASession) Release() uint32 {

    ret, _, _ := syscall.Syscall(

        obj.vtbl.Release,

        1,

        uintptr(unsafe.Pointer(obj)),

        0,

        0,

    )

    return uint32(ret)

}


func (obj *XASession) ConnectServer(id int) int {

    ret, _, _ := syscall.Syscall(

        obj.vtbl.ConnectServer, // function address

        2, // number of parameters to this function

        uintptr(unsafe.Pointer(obj)), // always pass the COM object address first

        uintptr(id), // then all function parameters follow

        0,

    )

    return int(ret)

}


func (obj *XASession) DisconnectServer() {

    syscall.Syscall(

        obj.vtbl.DisconnectServer,

        1,

        uintptr(unsafe.Pointer(obj)),

        0,

        0,

    )

}