4

我正在尝试调用 Windows API 函数EnumerateTraceGuids

ULONG EnumerateTraceGuids(
  __inout  PTRACE_GUID_PROPERTIES *GuidPropertiesArray,
  __in     ULONG PropertyArrayCount,
  __out    PULONG GuidCount
);

MSDN 上的代码示例开始:

ULONG status = ERROR_SUCCESS;
PTRACE_GUID_PROPERTIES *pProviders = NULL;
ULONG RegisteredProviderCount = 0;
ULONG ProviderCount = 0;

pProviders = (PTRACE_GUID_PROPERTIES *) malloc(sizeof(PTRACE_GUID_PROPERTIES));
status = EnumerateTraceGuids(pProviders, ProviderCount, &RegisteredProviderCount);

我将代码转换为Delphi:

var
    providers: PPointerList;
    providerCount: LongWord;
    registeredProviderCount: LongWord;
    res: LongWord;
begin
    providerCount := 0;
    registeredProviderCount := 0;
    providers := AllocMem(SizeOf(Pointer));
    ZeroMemory(providers, SizeOf(Pointer));

    res := EnumerateTraceGuids(providers, providerCount, {out}registeredProviderCount);
end;

使用 api 调用:

function EnumerateTraceGuids(
      GuidPropertiesArray: Pointer; 
      PropertyArrayCount: Cardinal; 
      var GuidCount: Cardinal): Cardinal; stdcall; external 'advapi32.dll';

我得到结果代码ERROR_INVALID_PARAMETER(87,参数不正确)。

我究竟做错了什么?


MSDN 描述了会导致什么ERROR_INVALID_PARAMETER

ERROR_INVALID_PARAMETER

以下情况之一为真:

  • PropertyArrayCount 为零
  • GuidPropertiesArray 为 NULL

第一种情况是正确的,我的第二个参数PropertyArrayCount 为零- 就像样本所说的那样。

4

1 回答 1

3

据我所知,您的代码应该与 MSDN 示例相同。然而,正如 Code 所说,MSDN 示例看起来确实有点时髦。事实上,在我看来,MSDN 示例只是偶然发挥作用。

请注意,该代码中的注释指出:

// EnumerateTraceGuids requires a valid pointer. Create a dummy
// allocation, so that you can get the actual allocation size.

然后它分配空间pProviders来存储单个指针。但是,pProviders实际包含的值很重要。不可能NULL。实际上,在您的 Delphi 代码中,您将该内存归零两次。一次AllocMem和一次ZeroMemory。如果您只是更改您的 Delphi 代码以使内容providers非零,那么 Delphi 代码将开始工作。

这是一个非常简单的项目,它准确地说明了正在发生的事情:

program _EnumerateTraceGuidsFaultDemo;

{$APPTYPE CONSOLE}

function EnumerateTraceGuids(
      GuidPropertiesArray: Pointer;
      PropertyArrayCount: Cardinal;
      var GuidCount: Cardinal): Cardinal; stdcall; external 'advapi32.dll';


var
  providers: Pointer;
  providerCount: LongWord;
  registeredProviderCount: LongWord;
  res: LongWord;
begin
  providerCount := 0;
  registeredProviderCount := 0;

  providers := AllocMem(SizeOf(Pointer));//zeroises memory
  res := EnumerateTraceGuids(providers, providerCount, registeredProviderCount);
  Writeln(res);//outputs 87

  PInteger(providers)^ := 1;
  res := EnumerateTraceGuids(providers, providerCount, registeredProviderCount);
  Writeln(res);//outputs 234

  Readln;
end.

所以我认为这可以解释问题,但实际上我会比这更彻底地解决它。我将继续您的工作的下一步,并EnumerateTraceGuids完全使用与TRACE_GUID_PROPERTIES结构等效的真正 Delphi 声明。

我可能会写这样的代码:

program _EnumerateTraceGuids;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Windows;

type
  PTraceGuidProperties = ^TTraceGuidProperties;
  TTraceGuidProperties = record
    Guid: TGUID;
    GuidType: ULONG;
    LoggerId: ULONG;
    EnableLevel: ULONG;
    EnableFlags: ULONG;
    IsEnable: Boolean;
  end;

function EnumerateTraceGuids(
  var GuidPropertiesArray: PTraceGuidProperties;
  PropertyArrayCount: ULONG;
  var GuidCount: ULONG
): ULONG; stdcall; external 'advapi32.dll';

function GetRegisteredProviderCount: ULONG;
var
  provider: TTraceGuidProperties;
  pprovider: PTraceGuidProperties;
  providerCount: LongWord;
  registeredProviderCount: ULONG;
  res: ULONG;
begin
  providerCount := 0;
  pprovider := @provider;
  res := EnumerateTraceGuids(pprovider, providerCount, registeredProviderCount);
  if (res<>ERROR_MORE_DATA) and (res<>ERROR_SUCCESS) then
    RaiseLastOSError;
  Result := registeredProviderCount;
end;

var
  i: Integer;
  provider: TTraceGuidProperties;
  pprovider: PTraceGuidProperties;
  providers: array of TTraceGuidProperties;
  pproviders: array of PTraceGuidProperties;
  providerCount: ULONG;
  registeredProviderCount: ULONG;
  res: ULONG;
begin
  providerCount := GetRegisteredProviderCount;
  SetLength(providers, providerCount);
  SetLength(pproviders, providerCount);
  for i := 0 to providerCount-1 do
    pproviders[i] := @providers[i];
  res := EnumerateTraceGuids(pproviders[0], providerCount, registeredProviderCount);
  if res<>ERROR_SUCCESS then
    RaiseLastOSError;
  //do stuff with providers
end.

我并没有试图变得太可爱GetRegisteredProviderCount,而是传递了一个真正的指针TRACE_GUID_PROPERTIES

于 2012-02-14T07:42:43.447 回答