Как передать в API функцию ссылку на массив структур
От: ayap Россия  
Дата: 22.12.05 09:04
Оценка:
Привет всем!

Вот пытаюсь прикрутить к программе диалог выбора пользователя из Active Directory.
Живет этот диалог в ..Windows\system32\objsel.dll

Есть там одна структура:

The DSOP_INIT_INFO structure contains data required to initialize an object picker dialog box. This structure is used with the IDsObjectPicker::Initialize method.

typedef struct _DSOP_INIT_INFO
{
ULONG cbSize;
PCWSTR pwzTargetComputer;
ULONG cDsScopeInfos;
PDSOP_SCOPE_INIT_INFO aDsScopeInfos;
ULONG flOptions;
ULONG cAttributesToFetch;
PCWSTR* apwzAttributeNames;
} DSOP_INIT_INFO, *PDSOP_INIT_INFO;

В поле aDsScopeInfos надо положить указатель на массив структур:
Pointer to an array of DSOP_SCOPE_INIT_INFO structures

Проблема в том, что эти структуры передаются как параметры при вызавах COM-методов
(да, кстати, они еще и не OleAutomation)

На c++ все работает, а вот на Delphi — Access violation при вызове

(obj as IDsObjectPicker).Initialize(InitInfo);

Вопрос как правильно создать массив структур и в поле aDsScopeInfos его положить?
Re: Как передать в API функцию ссылку на массив структур
От: ekamaloff Великобритания  
Дата: 22.12.05 09:12
Оценка:
Здравствуйте, ayap, Вы писали:

A>Вопрос как правильно создать массив структур и в поле aDsScopeInfos его положить?


Может приведете свой код полностью, с инициализацией полей структуры DSOP_INIT_INFO?
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[2]: Как передать в API функцию ссылку на массив структур
От: ayap Россия  
Дата: 22.12.05 09:35
Оценка:
Здравствуйте, ekamaloff, Вы писали:

E>Здравствуйте, ayap, Вы писали:


A>>Вопрос как правильно создать массив структур и в поле aDsScopeInfos его положить?


E>Может приведете свой код полностью, с инициализацией полей структуры DSOP_INIT_INFO?


Пжалста:

...


type
  DSOP_SCOPE_INIT_INFO = record
    cbSize: Longint;
    flType: Longint;
    flScope: Longint;
    FilterFlags: DSOP_FILTER_FLAGS;
    pwzDcName: LPWSTR;
    pwzADsPath: LPWSTR;
    hr: HResult;
  end;

  PDSOP_SCOPE_INIT_INFO = ?


  DSOP_INIT_INFO = record
    cbSize: Longint;
    pwzTargetComputer: LPWSTR;
    cDsScopeInfos: Longint;
    aDsScopeInfos: PDSOP_SCOPE_INIT_INFO;
    flOptions: LongInt;
    cAttributesToFetch: Longint;
    apwzAttributeNames: PLPWSTR;
  end;
  PDSOP_INIT_INFO = ^DSOP_INIT_INFO;

  IDsObjectPicker = interface(IUnknown)
    ['{0C87E64E-3B7A-11D2-B9E0-00C04FD8DBF7}']
     function Initialize(pInitInfo: PDSOP_INIT_INFO ): HResult; stdcall;
     function InvokeDialog(Parent: HWND; doSelections: IUnknown): HResult; stdcall;
  end;

...
var
  InitInfo: PDSOP_INIT_INFO;
  aScopeInit: PDSOP_SCOPE_INIT_INFO;
...
begin
  try
...
    InitInfo := GetMemory(sizeof(DSOP_INIT_INFO));
    InitInfo.cbSize := sizeof(DSOP_INIT_INFO);
    InitInfo.pwzTargetComputer := LPWSTR(CompName);
    InitInfo.cDsScopeInfos := sizeof(aScopeInit);
    InitInfo.aDsScopeInfos := aScopeInit;
    InitInfo.flOptions := DSOP_FLAG_MULTISELECT or DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;
    InitInfo.cAttributesToFetch := 0;
    InitInfo.apwzAttributeNames := nil;

    (obj as IDsObjectPicker).Initialize(InitInfo);
  finally
    FreeMemory(InitInfo);
  end;

end;



Непонятно все выделенное жирным
Re[3]: Как передать в API функцию ссылку на массив структур
От: ekamaloff Великобритания  
Дата: 22.12.05 09:45
Оценка:
Здравствуйте, ayap, Вы писали:

[...]

Я так понимаю вы должны передать в функцию массив структур DSOP_SCOPE_INIT_INFO, полученный ранее каким-то образом (где это у вас в коде?). Представим что они у вас все таки есть и что это просто локальный массив, инициализируемый перед вызовом IDsObjectPicker::Initialize. Тогда передаваться он будет следующим образом:


var
A>  InitInfo: PDSOP_INIT_INFO;
A>  aScopeInit: array[0..1] of DSOP_SCOPE_INIT_INFO;
A>...
A>begin
A>  try
A>...
      // Инициализируем массив aScopeInit
      // ...
A>    InitInfo := GetMemory(sizeof(DSOP_INIT_INFO));
A>    InitInfo.cbSize := sizeof(DSOP_INIT_INFO);
A>    InitInfo.pwzTargetComputer := LPWSTR(CompName);
A>    InitInfo.cDsScopeInfos := Length(aScopeInit);
A>    InitInfo.aDsScopeInfos := @aScopeInit[0];
A>    InitInfo.flOptions := DSOP_FLAG_MULTISELECT or DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;
A>    InitInfo.cAttributesToFetch := 0;
A>    InitInfo.apwzAttributeNames := nil;

A>    (obj as IDsObjectPicker).Initialize(InitInfo);
A>  finally
A>    FreeMemory(InitInfo);
A>  end;

A>end;
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[3]: Как передать в API функцию ссылку на массив структур
От: Danchik Украина  
Дата: 22.12.05 09:49
Оценка:
Здравствуйте, ayap, Вы писали:

[Skip]

A>Непонятно все выделенное жирным


Кажется так
var
  aScopeInit: PDSOP_SCOPE_INIT_INFO;
  aScopeInitArray : array of [0..3 {сколько надо}] of DSOP_SCOPE_INIT_INFO
...

  {заполняй структуры}
  aScopeInitArray [0]....
  aScopeInitArray [1]....
  aScopeInitArray [2]....
  ...

  aScopeInit := @aScopeInitArray[0];
Re[4]: Как передать в API функцию ссылку на массив структур
От: Oleg A. Bachin Украина  
Дата: 22.12.05 10:23
Оценка:
Здравствуйте, ekamaloff, Вы писали:


E>Я так понимаю вы должны передать в функцию массив структур DSOP_SCOPE_INIT_INFO, полученный ранее каким-то образом (где это у вас в коде?). Представим что они у вас все таки есть и что это просто локальный массив, инициализируемый перед вызовом IDsObjectPicker::Initialize. Тогда передаваться он будет следующим образом:


при кол-ве структур 1 — разницы никакой. а вот packed record надо бы на автопилоте приучиться писать.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re[5]: Как передать в API функцию ссылку на массив структур
От: ekamaloff Великобритания  
Дата: 22.12.05 10:28
Оценка:
Здравствуйте, Oleg A. Bachin, Вы писали:

OAB>при кол-ве структур 1 — разницы никакой.


Не совсем понял, о чем это.

OAB>а вот packed record надо бы на автопилоте приучиться писать.


Там и record в моем посте не было.
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[6]: Как передать в API функцию ссылку на массив структур
От: Oleg A. Bachin Украина  
Дата: 22.12.05 10:48
Оценка:
Здравствуйте, ekamaloff, Вы писали:

E>Здравствуйте, Oleg A. Bachin, Вы писали:


OAB>>при кол-ве структур 1 — разницы никакой.

E>Не совсем понял, о чем это.
сорри, не вчитался... подумал что как всегда массив указателей на структуры...

OAB>>а вот packed record надо бы на автопилоте приучиться писать.

E>Там и record в моем посте не было.
это я в продолжение, чтоб 2 поста не писать
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re[7]: Как передать в API функцию ссылку на массив структур
От: ayap Россия  
Дата: 22.12.05 11:12
Оценка:
Здравствуйте, Oleg A. Bachin, Вы писали:

OAB>Здравствуйте, ekamaloff, Вы писали:


E>>Здравствуйте, Oleg A. Bachin, Вы писали:


OAB>>>при кол-ве структур 1 — разницы никакой.

E>>Не совсем понял, о чем это.
OAB>сорри, не вчитался... подумал что как всегда массив указателей на структуры...

OAB>>>а вот packed record надо бы на автопилоте приучиться писать.

E>>Там и record в моем посте не было.
OAB>это я в продолжение, чтоб 2 поста не писать

За всё спасибо, конечно, но я примерно так всё и делал — не работает однако

Привожу полный код для внесения ясности:


unit uTestForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComObj, ActiveX;

type
  TTestForm = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  DSOP_UPLEVEL_FILTER_FLAGS = packed record
    flBothModes: Longint;
    flMixedModeOnly: Longint;
    flNativeModeOnly: Longint;
  end;

  DSOP_FILTER_FLAGS = packed record
    Uplevel: DSOP_UPLEVEL_FILTER_FLAGS;
    flDownlevel: Longint;
  end;

  DSOP_SCOPE_INIT_INFO = packed record
    cbSize: Longint;
    flType: Longint;
    flScope: Longint;
    FilterFlags: DSOP_FILTER_FLAGS;
    pwzDcName: LPWSTR;
    pwzADsPath: LPWSTR;
    hr: HResult;
  end;

  PDSOP_SCOPE_INIT_INFO = ^DSOP_SCOPE_INIT_INFO;

  DSOP_INIT_INFO = packed record
    cbSize: Longint;
    pwzTargetComputer: LPWSTR;
    cDsScopeInfos: Longint;
    aDsScopeInfos: PDSOP_SCOPE_INIT_INFO;
    flOptions: LongInt;
    cAttributesToFetch: Longint;
    apwzAttributeNames: PLPWSTR;
  end;
  PDSOP_INIT_INFO = ^DSOP_INIT_INFO;

  IDsObjectPicker = interface(IUnknown)
    ['{0C87E64E-3B7A-11D2-B9E0-00C04FD8DBF7}']
     function Initialize(pInitInfo: PDSOP_INIT_INFO ): HResult; stdcall;
     function InvokeDialog(Parent: HWND; doSelections: IUnknown): HResult; stdcall;
  end;

var
  TestForm: TTestForm;

const
  CLSID: TGUID = '{17D6CCD8-3B7B-11D2-B9E0-00C04FD8DBF7}';
  IID: TGUID   = '{0C87E64E-3B7A-11D2-B9E0-00C04FD8DBF7}';
  DSOP_FLAG_MULTISELECT = $00000001;
  DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK = $00000002;

implementation

{$R *.dfm}

procedure TTestForm.Button2Click(Sender: TObject);
var
  obj: IUnknown;
  InitInfo: PDSOP_INIT_INFO;
  CompName: WideString;
  aScopeInit: array[0..0] of DSOP_SCOPE_INIT_INFO;
begin
  CoInitialize(nil);
  try
    CompName := 'LOCALHOST';
    CoCreateInstance(CLSID, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IID, obj);

    aScopeInit[0].cbSize := sizeof(DSOP_SCOPE_INIT_INFO);
    aScopeInit[0].flType := $0000037F;
    aScopeInit[0].flScope := $000000C3;
    aScopeInit[0].FilterFlags.Uplevel.flBothModes    := $00000042;
    aScopeInit[0].FilterFlags.Uplevel.flMixedModeOnly    := $00000000;
    aScopeInit[0].FilterFlags.Uplevel.flNativeModeOnly := $00000000;
    aScopeInit[0].FilterFlags.flDownlevel := $80000005;

    InitInfo := GetMemory(sizeof(DSOP_INIT_INFO));
    InitInfo.cbSize := sizeof(DSOP_INIT_INFO);
    InitInfo.pwzTargetComputer := LPWSTR(CompName);
    InitInfo.cDsScopeInfos := Length(aScopeInit);
    InitInfo.aDsScopeInfos := @aScopeInit[0];
    InitInfo.flOptions := DSOP_FLAG_MULTISELECT or DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK;
    InitInfo.cAttributesToFetch := 0;
    InitInfo.apwzAttributeNames := nil;

    (obj as IDsObjectPicker).Initialize(InitInfo); // Здесь Access Violation in "objsel.dll"
  finally
    FreeMemory(InitInfo);
    CoUnInitialize;
  end;
end;

end.



Ещё раз обратите внимание на выделенные места, особенно правильно ли я определил следующий тип:

PDSOP_SCOPE_INIT_INFO = ^DSOP_SCOPE_INIT_INFO;

Всем большое спасибо за обсуждение
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.