好的,我有一点空闲时间,还可以访问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
,则,
有两个微妙之处
枚举跟踪指南
工程:
-
与文件所述相反,
它实际上支持使用
PropertyArrayCount
参数设置为0,在这种情况下应返回
ERROR_MORE_DATA
设置时
GuidCount
输入的元素数
成功完成(下一个)调用所需的数组。
这样我们就能知道系统当前有多少跟踪GUID
“了解”。
-
尽管如此,即使在这种情况下,函数也会执行有效性检查
在输入阵列上(请参见下文)。
-
事实证明,函数需要一个指针数组
TRACE_GUID_PROPERTIES
块
由您分配。
换句话说,如果它说你知道10个跟踪GUID,
您必须分配10个类型的值
TRACE\u GUID\u属性
,则,
然后创建一个包含10个指向这些值的指针的数组,并传递一个指针
函数数组的第一个元素。
-
请注意,在发生的更改之间存在着固有的竞争
在系统中(由于各种原因添加或删除的记录道)
以及
枚举跟踪指南
。
这意味着如果对该函数的第一次调用告诉您它“知道”
大约10个跟踪GUID,下次调用时可能会出现
已经有20个跟踪GUID,或5个GUID
(或任何其他数量的FWIW)。
因此,我们通过以下方式考虑这两种可能性:
-
首先,我们使用指向单个(但有效)的指针进行调用
TRACE\u GUID\u属性
值,静态分配
(因此,函数“看到”看起来像单个元素的数组),
告诉函数输入“array”有零个元素。
我们预计该函数将失败
ERROR\u MORE\u数据
并将它“知道”的跟踪GUID的实际数量放入变量中
我们为它提供了一个指向的指针。
-
我们分配了那么多
TRACE\u GUID\u属性
内存块
第一次调用时指示的函数。
为此,我们使用
new()
具有某种行为的内置函数
喜欢
malloc()
在标准C库中,它为
指定类型的值,并返回指向已分配
内存块。
-
我们创建一个指向这些分配内存块的指针数组
和电话
枚举跟踪指南
再一次
-
如果它成功了,我们可以处理它返回的可能性更小
元素,并重新切片。
-
如果失败
ERROR\u MORE\u数据
,我们用
无论需要多少个元素(为其
TRACE\u GUID\u属性
块),然后再次尝试调用该函数。
-
“幻数”234是
ERROR\u MORE\u数据
价值
很抱歉最初的混淆。