问题描述
我有一个 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 查看器图片
This is a DLL Viewer picture
ConnectServer
ConnectServer
这是我的代码
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.LazyProcCall功能.查看 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
);
这意味着您必须将这三个参数作为 uintptr
传递给 proc.Call
(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
将是指向您创建的 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屋!