我正在尝试从Go中访问Advapi32.dll的EnumerateTraceGuids函数。 我现在处于初期阶段,仍然试图破译我必须做的事情。我有以下代码一直给我错误:87,意思是ERROR_INVALID_PARAMETER。
我已经使用这个文件作为起点,虽然它只是写作而不是阅读: https://github.com/moby/moby/blob/master/daemon/logger/etwlogs/etwlogs_windows.go
我试图调用的函数的官方文档在这里: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363713(v=vs.85).aspx
它需要GuidPropertiesArray [in,out]指向TRACE_GUID_PROPERTIES结构的指针数组。此结构如下(https://msdn.microsoft.com/en-us/library/windows/desktop/aa364143(v=vs.85).aspx)
typedef struct _TRACE_GUID_PROPERTIES {
GUID Guid;
ULONG GuidType;
ULONG LoggerId;
ULONG EnableLevel;
ULONG EnableFlags;
BOOLEAN IsEnable;
} TRACE_GUID_PROPERTIES, *PTRACE_GUID_PROPERTIES;
我有以下代码尝试执行此操作:
package main
import (
"errors"
"fmt"
"syscall"
"unsafe"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
)
const (
win32CallSuccess = 0
MaxProv = 50
nbProviders = 50
)
var (
modAdvapi32 = windows.NewLazySystemDLL("Advapi32.dll")
procEnumerateTraceGuids = modAdvapi32.NewProc("EnumerateTraceGuids")
)
type ulong int32
type TRACE_GUID_PROPERTIES struct {
Guid syscall.GUID
GuidType ulong
LoggerId ulong
EnableLevel ulong
EnableFlags ulong
IsEnable bool
}
func callEnumerateTraceGuids() error {
GuidPropertiesArray:= make([]TRACE_GUID_PROPERTIES, 1)
ptr := &GuidPropertiesArray[0]
ret, _, _ := procEnumerateTraceGuids.Call(uintptr(unsafe.Pointer(&ptr)), MaxProv, nbProviders)
if ret != win32CallSuccess {
errorMessage := fmt.Sprintf("Failed to register ETW provider. Error: %d", ret)
logrus.Error(errorMessage)
return errors.New(errorMessage)
}
return nil
}
func main() {
callEnumerateTraceGuids()
}
此时我不确定我必须做什么。我已经尝试了很多初始化阵列的变化而没有成功。 希望有人能指出我正确的方向。 谢谢!
编辑:根据评论更改了代码,但仍然收到相同的错误。
PS:这是我第一次发布到stackoverflow,我已经被告知我在发布问题后不到12小时就懒了(耶!)所以不确定我问的是这个......我我不太熟悉go并且之前从未调用过windows DLL,因为我一直打到那个ERROR_INVALID_PARAMETER我想伸出手来尝试通过这个第一面墙,以便能够同时掌握一些概念。希望这有助于理解我的要求(即我和平相处)。答案 0 :(得分:1)
好的,我有一点空闲时间和访问Windows XP的盒子, 所以我决定粉碎我的Windows编程技巧 并写了一个有效的解决方案:
package main
import (
"golang.org/x/sys/windows"
"log"
"syscall"
"unsafe"
)
var (
modAdvapi32 = windows.NewLazySystemDLL("advapi32")
procEnumerateTraceGuids = modAdvapi32.NewProc("EnumerateTraceGuids")
)
type traceGuidProperties struct {
guid syscall.GUID
guidType uint32
loggerId uint32
enableLevel uint32
enableFlags uint32
isEnable uint32
}
func enumerateTraceGuids(ptr **traceGuidProperties, count uint32, out *uint32) error {
rc, _, _ := procEnumerateTraceGuids.Call(uintptr(unsafe.Pointer(ptr)),
uintptr(count), uintptr(unsafe.Pointer(out)))
if rc != 0 {
return syscall.Errno(rc)
}
return nil
}
func enumTraceGuids() ([]*traceGuidProperties, error) {
var errMoreData = syscall.Errno(234)
var (
dummyProps traceGuidProperties
dummyPtr = &dummyProps
count uint32
)
err := enumerateTraceGuids(&dummyPtr, 0, &count)
if err != errMoreData {
return nil, err
}
items := make([]*traceGuidProperties, count)
for i := range items {
items[i] = new(traceGuidProperties)
}
for {
err = enumerateTraceGuids(&items[0], count, &count)
if err == nil {
break
}
if err != errMoreData {
return nil, err
}
for i := 0; i < int(count)-len(items); i++ {
items = append(items, new(traceGuidProperties))
}
}
return items[:count], nil
}
func main() {
log.SetFlags(0)
data, err := enumTraceGuids()
if err != nil {
log.Fatal(err)
}
log.Printf("len(data)=%d\n", len(data))
for i := range data {
log.Println(*(data[i]))
}
}
关键点:
我告诉你的时候我错了
«你......应该分配一个结构数组(而不是指针)» - 事实上
EnumerateTraceGuids
确实需要一组指针。
正如所暗示here,
EnumerateTraceGuids
如何运作有两个细微之处:
PropertyArrayCount
进行调用
参数设置为0,在这种情况下,它应该返回ERROR_MORE_DATA
同时将GuidCount
设置为输入元素的数量
(下一次)调用成功完成所需的数组。
IOW,我们知道系统当前有多少跟踪GUID
“知道”。事实证明,该函数需要一个指针数组
TRACE_GUID_PROPERTIES
阻止您分配。
换句话说,如果它说你知道10个跟踪GUID,
你必须分配10个TRACE_GUID_PROPERTIES
类型的值,
然后创建一个包含10个指向这些值的数组并传递指针
到该函数的第一个元素。
请注意,更改之间存在固有的竞争
在系统中(由于各种原因添加或删除的那些痕迹)
以及对EnumerateTraceGuids
的调用。
这意味着如果第一次调用此函数告诉你它“知道” 大约10个跟踪GUID,在下次调用时可能会结果 已经有20个跟踪GUID或5个GUID (或任何其他数量的FWIW)。
因此,我们通过以下方式解释了这两种可能性:
首先我们使用指向单个(但有效)的指针进行调用
TRACE_GUID_PROPERTIES
值,静态分配
(因此函数“看到”看起来像单个元素的数组),
在告诉函数时,输入“数组”的元素为零。
我们希望该功能失败,ERROR_MORE_DATA
并将它“知道”的实际跟踪GUID数放入变量中
我们已经提供了指向。
我们分配了很多TRACE_GUID_PROPERTIES
内存块
第一次通话时显示的功能。
为此,我们使用new()
内置函数,它在某种程度上表现出来
与标准C库中的malloc()
类似,它为内存分配
指定类型的值,并返回指向已分配的指针
记忆块。
我们创建一个指向这些已分配内存块的指针数组
并再次致电EnumerateTraceGuids
。
如果成功,我们会处理它返回的可能性 比我们分配的元素,并重新分配我们的切片。
如果它与ERROR_MORE_DATA
失败,我们会延长切片
无论需要多少元素(为他们分配内存)
先TRACE_GUID_PROPERTIES
阻止,然后再次尝试调用该函数。
“幻数”234是ERROR_MORE_DATA
值的实际代码。
抱歉最初的混乱。