如何在Golang中使用COM(组件对象模型) [英] How to use COM (Component Object Model) in Golang

查看:1153
本文介绍了如何在Golang中使用COM(组件对象模型)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Windows DLL(XA_Session.dll)文件,但我不知道如何在golang中使用它。

I have a Windows DLL (XA_Session.dll) file but I don't know how to use it in golang.

这是DLL Viewer图片

This is a DLL Viewer picture

我想使用 ConnectServer COM方法。

I want to use the ConnectServer COM Method.

这是我的代码

package main

import (
    "syscall"
    "fmt"
)

var (
    mod = syscall.NewLazyDLL("XA_Session.dll")
    proc = mod.NewProc("DllGetClassObject")
)

func main() {
    var bConnect bool
    bConnect = proc.ConnectServer("hts.ebestsec.co.kr", 20001)

    if bConnect {
        fmt.Println("Success")
    } else {
        fmt.Println("Fail")
    }
}

编译错误:


.\main.go: 17:proc.ConnectServer未定义(类型* syscall.LazyProc没有字段或方法ConnectServer)

.\main.go:17: proc.ConnectServer undefined (type *syscall.LazyProc has no field or method ConnectServer)


推荐答案

我在 Direct3D9 Go包装器,请参见此线程,在那里我可以从纯Go调用DirectX COM函数。

I had a similar problem in my Direct3D9 Go wrapper, see this thread, where I was able to call DirectX COM functions from pure Go.

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

In your code you try to call proc.ConnectServer(...) but the way to call a syscall.LazyProc is with its Call function. Looking at the documentation for DllGetClassObject, the signature is

HRESULT __stdcall DllGetClassObject(
  _In_  REFCLSID rclsid,
  _In_  REFIID   riid,
  _Out_ LPVOID   *ppv
);

这意味着您必须将这三个参数传递给 proc.Call uintptr s( Call 期望所有参数均为 uintptr s)。

This means you have to pass these three parameters to proc.Call as uintptrs (Call expects all arguments to be 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库。

Note that you need to set the parameter values correctly, the CLSID and IID may be contained in the accompanying C header file for the library, I don't know this XA_Session library.

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

The ppv will in this case be a pointer to the COM object that you created. To use COM methods from Go, you can create wrapper types, given you know all the COM methods defined by it and their correct order. All COM objects support the QueryInterface, AddRef and Release functions and then additional, type specific methods.

比方说,您的XA_Session对象还支持这两个函数(同样,我不知道它真正支持什么,您必须查看一下

Let's say your XA_Session object additionally supports these two functions (again, I don't know what it really supports, you have to look that up)

int ConnectServer(int id)
DisconnectServer()

然后可以在Go中进行包装:

then what you can do to wrap that in Go is the following:

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,
    )
}

这篇关于如何在Golang中使用COM(组件对象模型)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆