登录
首页 >  Golang >  Go问答

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

来源:Golang技术栈

时间:2023-03-26 13:12:11 477浏览 收藏

有志者,事竟成!如果你在学习Golang,那么本文《从没有 CGo 的 Go 调用 COM 对象方法》,就很适合你!文章讲解的知识点主要包括golang,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~

问题内容

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

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

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

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

我知道Go-OLE库,它声明它在没有 CGo 的情况下调用 COM 接口,但我无法从源代码中看到我将如何为 Direct3D9 做同样的事情。一个仅包含相关部分的简单示例将有很大帮助。

正确答案

我问了来自 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) 马特

今天关于《从没有 CGo 的 Go 调用 COM 对象方法》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:Golang技术栈 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>
评论列表