Question

i am trying to call the Windows API function EnumerateTraceGuids:

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

Starting from the code sample on 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);

i convert the code to 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;

with the api call:

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

i get the result code ERROR_INVALID_PARAMETER (87, The parameter is incorrect).

What am i doing wrong?


MSDN describes what would cause ERROR_INVALID_PARAMETER:

ERROR_INVALID_PARAMETER

One of the following is true:

  • PropertyArrayCount is zero
  • GuidPropertiesArray is NULL

The first case is true, my 2nd parameter PropertyArrayCount is zero - just like the sample says it should be.

Was it helpful?

Solution

So far as I can see, your code should be identical to the MSDN sample. However, as Code says, the MSDN sample does look a bit funky. Indeed, it seems to me that the MSDN sample is only working by chance.

Note that comment in that code that states:

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

Then it allocates space in pProviders to store a single pointer. However, the value contained in pProviders actually matters. It cannot be NULL. In your Delphi code you zeroise that memory twice in fact. Once with AllocMem and once with ZeroMemory. If you just change your Delphi code to make the contents of providers non-zero then the Delphi code will start working.

Here is a very simple project that illustrates exactly what is going on:

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.

So I think that explains the problem, but I'd actually solve it more completely than that. I would move on to the next step of your work and declare EnumerateTraceGuids fully using a real Delphi equivalent to the TRACE_GUID_PROPERTIES struct.

I'd probably write the code something like this:

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.

Rather than trying to be too cute in GetRegisteredProviderCount, I have passed a pointer to a real TRACE_GUID_PROPERTIES.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top