如何在Golang中使用COM(组件对象模型) [英] How to use COM (Component Object Model) in Golang
问题描述
我有一个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 uintptr
s (Call
expects all arguments to be uintptr
s).
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屋!