douweibiao8471 2016-06-13 04:06
浏览 1338

如何在Golang中使用COM(组件对象模型)

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

This is a DLL Viewer picture

I want to use the ConnectServer COM Method.

Here is my code

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

compile error:

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

  • 写回答

1条回答 默认 最新

  • doushitang4276 2017-09-15 08:01
    关注

    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.

    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
    );
    

    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
    }
    

    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.

    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.

    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()
    

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

报告相同问题?

悬赏问题

  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100