You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Go读取ETW提供者:调用EnumerateTraceGuids遇参数错误87

Hey there! Let's figure out why you're hitting ERROR_INVALID_PARAMETER (code 87) when calling EnumerateTraceGuids from Advapi32.dll in Go—especially since you're just starting out and using that Moby ETW logger code as a reference. This error almost always boils down to mismatched parameter types, incorrect buffer handling, or a misaligned struct definition. Let's break down the fixes step by step:

Common Causes for Error 87

  • Incorrect buffer size handling: This function requires a two-step call pattern (first to get required buffer size, then to fetch the actual data). Skipping this or miscalculating the size will trigger invalid parameters.
  • Misaligned or incorrect struct definitions: The TRACE_GUID_INFO struct (used by the function) has a specific memory layout that needs to match exactly what Windows expects. Go's default struct alignment might not match C's if you don't define it properly.
  • Wrong function version: Windows provides ANSI (EnumerateTraceGuidsA) and Unicode (EnumerateTraceGuidsW) versions of the function. Using the wrong one (e.g., ANSI when passing Unicode-compatible data) will cause parameter errors.
  • Parameter order mix-up: The function expects parameters in a specific order—mixing them up is a classic source of error 87.

Step-by-Step Fixes (Based on the Moby Reference)

Let's align your code with how the Moby implementation handles this function:

1. Define the TRACE_GUID_INFO Struct Correctly

The Windows API struct looks like this in C:

typedef struct _TRACE_GUID_INFO {
DWORD GuidCount;
GUID GuidList[ANYSIZE_ARRAY];
} TRACE_GUID_INFO, *PTRACE_GUID_INFO;

In Go, you need to replicate this with a struct that accounts for the variable-length GuidList:

import (
    "syscall"
    "unsafe"
)

type TraceGuidInfo struct {
    GuidCount uint32
    GuidList  [1]syscall.GUID // [1] represents the variable-length array; we'll allocate extra memory later
}

2. Implement the Two-Step Call Pattern

This is critical—you can't fetch the GUIDs in one call. Here's how to do it properly:

func main() {
    // Load Advapi32.dll and get the function address for the Unicode version
    advapi32, err := syscall.LoadLibrary("advapi32.dll")
    if err != nil {
        panic(err)
    }
    defer syscall.FreeLibrary(advapi32)

    enumGuidsAddr, err := syscall.GetProcAddress(advapi32, "EnumerateTraceGuidsW")
    if err != nil {
        panic(err)
    }

    // Step 1: Call with NULL to get required buffer size and GUID count
    var guidCount uint32
    var listSize uint32
    _, _, err = syscall.Syscall(enumGuidsAddr, 3,
        uintptr(unsafe.Pointer(nil)), // pGuidList = NULL
        uintptr(unsafe.Pointer(&guidCount)),
        uintptr(unsafe.Pointer(&listSize)))
    
    // Ignore ERROR_INSUFFICIENT_BUFFER—it's expected here
    if err != syscall.Errno(0) && err != syscall.ERROR_INSUFFICIENT_BUFFER {
        panic(err)
    }

    if guidCount == 0 {
        println("No trace GUIDs found")
        return
    }

    // Step 2: Allocate buffer matching the required size
    buffer := make([]byte, listSize)
    tgi := (*TraceGuidInfo)(unsafe.Pointer(&buffer[0]))
    tgi.GuidCount = guidCount

    // Call again to fetch the actual GUIDs
    _, _, err = syscall.Syscall(enumGuidsAddr, 3,
        uintptr(unsafe.Pointer(tgi)), // pGuidList = our buffer
        uintptr(unsafe.Pointer(&guidCount)),
        uintptr(unsafe.Pointer(&listSize)))
    
    if err != syscall.Errno(0) {
        panic(err)
    }

    // Access the GUID list as a slice
    guids := unsafe.Slice(&tgi.GuidList[0], guidCount)
    for _, guid := range guids {
        println("Found GUID:", guid.String())
    }
}

3. Double-Check Critical Details

  • Use the Unicode function version: Always load EnumerateTraceGuidsW (not the ANSI A version) to match modern Windows API conventions.
  • Respect the returned listSize: Don't calculate the buffer size manually—use the value returned by the first call, as it accounts for struct padding and variable-length data.
  • Parameter order: The function signature is BOOL EnumerateTraceGuidsW(PTRACE_GUID_INFO pGuidList, PDWORD pGuidCount, PDWORD pListSize). If you swap any parameters, you'll get error 87 immediately.

Quick Troubleshooting Checklist

  • Did you initialize guidCount and listSize to 0 before the first call?
  • Is your TraceGuidInfo struct's field order exactly GuidCount followed by GuidList?
  • Are you using unsafe.Pointer correctly when passing parameters to the syscall?

内容的提问来源于stack exchange,提问作者EmFl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:15:27