2012-02-14 3 views
4

я пытаюсь вызвать функцию API для Windows EnumerateTraceGuids:EnumerateTraceGuids возвращает "неправильный параметр" (87)

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

Начиная от образца кода 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); 

преобразовать код в 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 равна нулю
  • GuidProper tiesArray является NULL

Первый случай, правда, мой второй параметр PropertyArrayCountявляется ноль - так же, как образец говорит, что это должно быть.

+0

Ugh, это действительно какой-то * ужасный * пример кода на странице MSDN. Но обрезанный сниппп, который вы написали на C, действительно работает, возвращая 'ERROR_MORE_DATA', как и ожидалось. К сожалению, я не знаю Delphi, поэтому я не могу сказать, как исправить этот код, но я уверен, что ошибка вошла во время перевода. –

+0

@Cody Интересно, что код MSDN работает только случайно. Если вызов malloc возвращает память, которая инициализируется нулем, тогда этот код выходит из строя! Таким образом, ваше ощущение о коде было спот-на. –

ответ

2

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

Я бы, наверное, написать код что-то вроде этого:

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.

+0

Ahhhh, указатель мусора! Тонкий, тонкий, тонкий! –

+0

В моем фактическом коде используется динамический массив указателей и динамический массив 'TRACE_GUID_PROPERTIES' (т. Е. SetLength()), который не инициализирует память и упрощает управление. –

+0

@Ian Так делает мой код! –

Смежные вопросы