从没有CGo的Go调用COM对象方法

时间:2016-08-26 08:43:47

标签: windows dll go com

我在Go中创建了一个Direct3D9 wrapper,它使用CGo与C中的COM对象进行交互。

我想摆脱Windows下对C编译器的依赖,这样用户就不必安装MinGW或Cygwin来使用Go中的DirectX。

问题是d3d9.dll不暴露C函数但使用COM。加载DLL(syscall.LoadLibrary("d3d9.dll"))后可以直接调用的唯一函数是Direct3DCreate9。这将返回一个COM对象,该对象将所有功能公开为方法。

如何在没有CGo的纯Go中调用DLL中的COM对象方法?

我知道Go-OLE库声称它在没有CGo的情况下调用COM接口但我不能从源头看到我将如何为Direct3D9做同样的事情。只有相关部分的简单例子会有很大的帮助。

2 个答案:

答案 0 :(得分:2)

(不是一个全面的答案,因为我没有时间对此进行实际测试,但仍然......)

虽然MSDN大部分时间都假设你使用一些内置的" glue"对于它们(例如Visual C ++™产品或类似的东西),实际上可以使用普通的C-look herehere来启动COM对象。

研究这些资源,你可以学习在" COM接口上调用方法"相当于正确使用它的" VTBL" ( V irtual函数 T 一个 BL e)块,它总是位于一个众所周知的地方,相对于那个&#伪装的指针34;接口" "东西"由实例化COM对象的函数返回。

go-ole包在plain Go中实现了你在普通C中所做的事情,因此我们需要在COM对象上调用方法,我们需要在其VTBL上操作" #34;我们可以在该包中找到IDispatch support的实现。所以我从那里开始。

我也直接进入go-ole问题跟踪器,要求实现一段示例代码,该代码将演示如何调用COM对象的方法,该方法通过调用以外的方式获取来自go-ole包的函数。

答案 1 :(得分:1)

我问过那些来自go-ole的人,就像@kostix建议的那样。

以下是解决方案:

  

d3d9通常没有COM vtbl。例如,它没有   IDispatch接口。所以你不能使用go-ole用于d3d9。但你可以做到   它用go编写所有接口。

package main

import (
    "fmt"
    "log"
    "syscall"
    "unsafe"
)

const (
    D3D9_SDK_VERSION = 32
)

var (
    libd3d9             = syscall.NewLazyDLL("d3d9.dll")
    procDirect3DCreate9 = libd3d9.NewProc("Direct3DCreate9")
)

type IDirect3D struct {
    lpVtbl *IDirect3DVtbl
}

type IDirect3DVtbl struct {
    QueryInterface uintptr
    AddRef         uintptr
    Release        uintptr

    RegisterSoftwareDevice      uintptr
    GetAdapterCount             uintptr
    GetAdapterIdentifier        uintptr
    GetAdapterModeCount         uintptr
    EnumAdapterModes            uintptr
    GetAdapterDisplayMode       uintptr
    CheckDeviceType             uintptr
    CheckDeviceFormat           uintptr
    CheckDeviceMultiSampleType  uintptr
    CheckDepthStencilMatch      uintptr
    CheckDeviceFormatConversion uintptr
    GetDeviceCaps               uintptr
    GetAdapterMonitor           uintptr
    CreateDevice                uintptr
}

func (v *IDirect3D) AddRef() int32 {
    ret, _, _ := syscall.Syscall(
        v.lpVtbl.AddRef,
        1,
        uintptr(unsafe.Pointer(v)),
        0,
        0)
    return int32(ret)
}

func (v *IDirect3D) Release() int32 {
    ret, _, _ := syscall.Syscall(
        v.lpVtbl.Release,
        1,
        uintptr(unsafe.Pointer(v)),
        0,
        0)
    return int32(ret)
}

func (v *IDirect3D) GetAdapterCount() uint32 {
    ret, _, _ := syscall.Syscall(
        v.lpVtbl.GetAdapterCount,
        1,
        uintptr(unsafe.Pointer(v)),
        0,
        0)
    return uint32(ret)
}

func main() {
    v, r, err := procDirect3DCreate9.Call(uintptr(D3D9_SDK_VERSION))
    if r != 0 && err != nil {
        log.Fatal(err)
    }
    d3d := *((**IDirect3D)(unsafe.Pointer(&v)))

    d3d.AddRef()
    defer d3d.Release()

    fmt.Println(d3d.GetAdapterCount())
}

(c) mattn