EnumerateTraceGuids возвращает «Неверный параметр» (87) - PullRequest
4 голосов
/ 14 февраля 2012

я пытаюсь вызвать функцию 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 равен нулю - так же, как в примере сказано, что так и должно быть.

1 Ответ

3 голосов
/ 14 февраля 2012

Насколько я вижу, ваш код должен быть идентичен образцу 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 полностью, используя реальный Delphi, эквивалентный TRACE_GUID_PROPERTIES struct.

Я бы, наверное, написал код примерно так:

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.

...