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

Windows 如何在Golang中使用COM(组件对象模型),windows,dll,go,com,Windows,Dll,Go,Com,我有一个Windows DLL(XA_Session.DLL)文件,但我不知道如何在golang中使用它 这是一个DLL查看器图片 我想使用ConnectServerCOM方法 这是我的密码 package main import ( "syscall" "fmt" ) var ( mod = syscall.NewLazyDLL("XA_Session.dll") proc = mod.NewProc("DllGetClassObject") ) fun

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

这是一个DLL查看器图片

我想使用
ConnectServer
COM方法

这是我的密码

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)


我在我的中遇到了类似的问题,我可以从纯Go调用directxcom函数

在代码中,您尝试调用
proc.ConnectServer(…)
,但调用
syscall.LazyProc
的方法是使用其
call
函数。看这张照片,签名是

HRESULT __stdcall DllGetClassObject(
  _In_  REFCLSID rclsid,
  _In_  REFIID   riid,
  _Out_ LPVOID   *ppv
);
这意味着您必须将这三个参数传递给
proc.Call
作为
uintpttr
s(
Call
希望所有参数都是
uintpttr
s)

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

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

假设您的XA_会话对象还支持这两个函数(同样,我不知道它真正支持什么,您必须查找)

然后,您可以执行以下操作将其包装到围棋中:

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,
    )
}
库具有ADSI COM对象的实现。它使用go ole和comutil库。
这可能是其他COM对象用例的良好起点。

您使用的
proc
不正确。它类似于函数DllGetClassObject的包装器,而不是DllGetClassObject返回的类对象。它没有这样的方法。我应该改变什么@我想用围棋使用com是相当困难的。试着更深入地研究com,看看这里。com不同于仅仅调用加载DLL的导出函数,因此我支持@V.Kravchenko,您可能应该使用专用包来处理com。至于调用导出函数,请查看Go源代码,特别是
src/syscall
目录下名称与
*\u windows.Go
匹配的文件:它们包含大量使用
NewProc()
syscall.syscall*()因此,我担心,实际上,用C++编译器生成的DLL与GO接口,您需要将DLL封装在另一个DC++中,C++编写并公开一个简单的C接口(通过<代码>外部)C“{…}”/COD>标准机制,封装这些C++方法,或者使用一个工具,如SWIG创建一个“桥”。“围棋代码。2) 在使用COM时,您不会直接加载提供COM对象的DLL,而是使用适当的Win32 API调用,通过COM对象的名称或GUID标识符间接为您实例化COM对象。然后间接地操作它。这就是
go-ole
所做的。
int ConnectServer(int id)
DisconnectServer()
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,
    )
}