Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Обращение к удаленном OLE-объекту


Страницы:   1 2

GrBob ©   (2006-06-27 11:07:00) 

Здравствуйте.
На удаленном компьютере есть OLE-объект, у которого известно только название. (ну и соответственно легко получается CLSID, в реестре на данном компьютере информация об объекте есть). Вопрос: можно ли как-нибудь к нему обраться? CreateOLEObject работает только на текущей машине, а CreateRemoteComObject возвращает интерфейс, название которого я не знаю. (Как его получить?)
Заранее спасибо за ответы.


AbrosimovA   (2006-07-11 14:27:00) [1]

Это дополнение к коду из 5-го поста для процедуры
procedure EnumInterface(Dispatch: IDispatch; Entries: TStrings; Functions: Boolean);:

type TArgInfo = record
 Total: integer;
 Optional: integer;
 ArgsType: array[0..100] of TVARTYPE;
end;

var ArgInfo: array of TArgInfo;

SetLength(ArgInfo,TypeAttr.cFuncs);
//Общее число параметров метода
ArgInfo[iMethod].Total:=FuncDesc.cParams;
//Число необязательных параметров из них
ArgInfo[iMethod].Optional:=FuncDesc.cParamsOpt;параметров
//типы всех параметров
for i:=0 to FuncDesc.cParams-1 do           ArgInfo[iMethod].ArgsType[i]:=TVARTYPE(FuncDesc.lprgelemdescParam[i].tdesc.vt);< /CODE>


GrBob   (2006-07-11 12:31:00) [2]


> Как программно узнать, что нужно передавать через DispParams
> для безошибочного выполнения методов  через IDispatch.Invoke

Советую взглянуть в сторону интерфейсов ITypeLib и ITypeInfo. Сам еще не разобрался, но имхо должно подойти. Мне как раз сейчас это тоже понадобилось, просто времени совсем нет читать, если разберешься, отпишись :)


  (2006-07-09 20:53:00) [3]

Удалено модератором


AbrosimovA   (2006-07-07 16:54:00) [4]

Не могу найти ответа на следующий вопрос:

Как программно узнать, что нужно передавать через DispParamsдля безошибочного выполнения методов  через IDispatch.Invoke


AbrosimovA   (2006-07-07 14:44:00) [5]

Проверено на методе Addинтерфейса Documentsобъекта Word.Application- работает.

var iSrv: IDispatch;
    DID: integer;
    Value: OleVariant;

DID:=StrToInt(ListView2.Selected.Caption);
Value:=GetDispIDFromName(iSrv, ListView2.Items[iIndex].SubItems[0], DID);
case VarType(Value) of
 varDispatch:
   begin              
     //Connect;
     ISrv:=IDispatch(Value);
   end;
 varEmpty:
   begin
     //Exec;
     try        
       SetInvokeMethod(iSrv,DID);
     except
       on E: Exception do begin
         StatusBar1.SimpleText:=E.Message;
       end
     end
   end;
end;

procedure SetInvokeMethod(const Dispatch: IDispatch; const ID: integer);
var
DispParams: TDispParams;
Args: array[0..1] of TVariantArg;
ExcepInfo   : TExcepInfo;
iError      : UINT;
begin
Args[0].vt:= VT_ERROR;
Args[0].scode := DISP_E_PARAMNOTFOUND;
Args[1].vt:= VT_ERROR;
Args[1].scode := DISP_E_PARAMNOTFOUND;
FillChar(DispParams, SizeOf (DispParams), 0);
with DispParams do begin
  rgvarg := @Args;
  cArgs := 2;
  cNamedArgs := 0;
end;
OleCheck (Dispatch.Invoke(ID, GUID_NULL, LOCALE_SYSTEM_DEFAULT,
                 DISPATCH_METHOD, DispParams, nil, @ExcepInfo, @iError));
end;


GrBob   (2006-07-07 12:37:00) [6]

Аааа, ну это то конечно установлено :)


Ломброзо   (2006-07-07 12:27:00) [7]

Зайти в оснастку "Component Services" (на XP)->Свойства компьютера или dcomcnfg, проверить опцию, разрешающую использование DCOM.


GrBob   (2006-07-07 12:24:00) [8]

Права - я администратор как на своей, так и на удаленной (в данном случае опять же своей :) ) машине. Что необходимо настроить в DCOM?


Ломброзо   (2006-07-07 12:13:00) [9]

Да я так, на всякий случай.
Продолжаем разбираться дальше )
Как обстоят дела с настройками DCOM и правами?


GrBob   (2006-07-07 11:51:00) [10]


> Скопируйте эту вашу библиотеку на свою машину и зарегистрируйте
> её через regsvr32

Она у меня зарегестрирована :) На своей машине прекрасно работает, а эта ошибка выдается даже если указать в качестве удаленной машины - свою.


Ломброзо   (2006-07-07 11:38:00) [11]

> Инвоке возвращает очень содержательную ошибку с текстом "Ошибка"
Скопируйте эту вашу библиотеку на свою машину и зарегистрируйте её через regsvr32


GrBob   (2006-07-07 09:06:00) [12]


> AbrosimovA ©   (07.07.06 08:10) [14]
> Если только тебе заранее известны все методы и свойства
> исследуемого интерфейса.

Дак они мне известны (по крайней мере те, которые я хочу использовать), почему-то не работает :(

В общем вот такие вот первые итоги: привожу на примере службы индексирования, она описана в MSDN и стоит на Windows Server 2003 по умолчанию, да и не главное это :) Просто у Ворда слишком заумные методы, чтобы на нем тесты ставить:

unit Unit1;

interface

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

type
 TForm1 = class(TForm)
   ListBox1: TListBox;
   ServNameEdit: TEdit;
   Label4: TLabel;
   ValuePropEdit: TEdit;
   btnReadInterf: TButton;
   BtnRemConnect: TButton;
   StatusBar1: TStatusBar;
   Button1: TButton;
   AddCatalog: TButton;
   GroupBox1: TGroupBox;
   Label1: TLabel;
   Edit1: TEdit;
   Label2: TLabel;
   Edit2: TEdit;
   GroupBox2: TGroupBox;
   Start: TButton;
   Button4: TButton;
   procedure BtnRemConnectClick(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
   procedure AddCatalogClick(Sender: TObject);
   procedure StartClick(Sender: TObject);
 private
   procedure Invoke(const ID: integer; const DispParams: TDispParams);
   procedure SetInvoke(const ID: integer);
   procedure Exec(const Name: WideString; const DispParams: TDispParams);
 public
 end;

var
 Form1: TForm1;
 Srv: IDispatch;
 DID: integer;
 iIndex: integer;

implementation

{$R *.dfm}
uses ComObj, AxCtrls;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Srv := nil;
end;

procedure TForm1.SetInvoke(const ID: integer);
var
 aDispParams: TDispParams;
 aEI: TExcepInfo;
 iError: UINT;
 Command: OleVariant;
begin
 FillChar(aDispParams, SizeOf (aDispParams), 0);
 aDispParams.cArgs := 1;
 Command := True;
 GetMem(aDispParams.rgvarg, aDispParams.cArgs * SizeOf(TVariantArg));
 aDispParams.rgvarg[0] := TVariantArg(OleVariant('C:\'));
 aDispParams.rgvarg[1] := TVariantArg(OleVariant('D:\'));
 OleCheck(Srv.Invoke(ID, GUID_NULL, 0,
   DISPATCH_PROPERTYPUT, aDispParams, NIL, @aEI, @iError));
end;

procedure TForm1.Invoke(const ID: integer; const DispParams: TDispParams);
var
 aDispParams: TDispParams;
 aEI: TExcepInfo;
 iError: UINT;
begin
 aDispParams := DispParams;
 OleCheck(Srv.Invoke(ID, GUID_NULL, 0,
   DISPATCH_METHOD, aDispParams, NIL, @aEI, @iError));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 iIndex := -1;
end;

procedure TForm1.BtnRemConnectClick(Sender: TObject);
var
 CLSID: TGUID;
 RemoteComp: WideString;
begin
 CLSID := ProgIDToClassID('Microsoft.IsAdm');
 try
   RemoteComp := ServNameEdit.Text;
   Srv := CreateRemoteComObject(RemoteComp, CLSID) as IDispatch;
 except
   Exit;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 PName: PWideChar;
 iDispID: Integer;
 Name : WideString;
begin
 iIndex := Listbox1.ItemIndex;
 ListBox1.Items.NameValueSeparator := '-';
 Name := Listbox1.Items.ValueFromIndex[iIndex];
 PName := PWideChar(Name);
 if Srv.GetIDsOfNames(GUID_NULL, @PName, 1, GetThreadLocale, @iDispID) = S_OK then
   SetInvoke(iDispID);
end;

procedure TForm1.Exec(const Name: WideString; const DispParams: TDispParams);
var
 PName: PWideChar;
 iDispID: Integer;
begin
 PName := PWideChar(Name);
 Srv.GetIDsOfNames(GUID_NULL, @PName, 1, GetThreadLocale, @iDispID);
 Invoke(iDispID, DispParams);
end;

procedure TForm1.AddCatalogClick(Sender: TObject);
var
 DispParams: TDispParams;
 Catalog, Place: WideString;
begin
 FillChar(DispParams, SizeOf (DispParams), 0);
 DispParams.cArgs := 2;
 GetMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));
 try
   Catalog := Edit1.Text;
   Place := Edit2.Text;
   DispParams.rgvarg[0] := TVariantArg(OleVariant(Place));
   DispParams.rgvarg[1] := TVariantArg(OleVariant(Catalog));
   Exec('AddCatalog', DispParams);
 finally
   FreeMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));
 end;
end;

procedure TForm1.StartClick(Sender: TObject);
var
 DispParams: TDispParams;
begin
 FillChar(DispParams, SizeOf (DispParams), 0);
 DispParams.cArgs := 0;
 GetMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));
 try
   Exec('Start', DispParams);
 finally
   FreeMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));
 end;
end;

end.


Что дальше - ума не приложу. Инвоке возвращает очень содержательную ошибку с текстом "Ошибка" :( В чем может быть дело?


AbrosimovA   (2006-07-07 08:10:00) [13]


> Ломброзо ©   (07.07.06 02:10) [12]
> можно смело присвоить переменной типа OleVariant и вызывать
> всякие свойства и методы


Если только тебе заранее известны все методы и свойства исследуемого интерфейса.


GrBob   (2006-07-07 08:07:00) [14]

Предположим, так:
CLSID := ProgIDToClassID('Bla.Bla');
try
 RemoteComp := ServNameEdit.Text;
 Srv := CreateRemoteComObject(RemoteComp, CLSID) as IDispatch;
 OleVariant(Srv).Start;
except
 Exit;
end;

Получаю при вызове метода Start "Разрушительный сбой". Да и написана эта библиотека так, что библиотеки типов просто нет в списке импортируемых.


Ломброзо   (2006-07-07 02:10:00) [15]

Может я чего-то недопонимаю, но OleVariant устроен таким образом, что в том случае, если переменная типа OleVariant содержит указатель на интерфейс IDispatch, то все вызовы к "свойствам" и "методам" этой переменной транслируются в вызов IDispatch::Invoke(). Так что пользоваться IDispatch совершенно излишне. То бишь тот указатель на интерфейс, который был отмаршаллен с другого хоста, можно смело присвоить переменной типа OleVariant и вызывать всякие свойства и методы. Компилятор с разруливанием вызовов расправится сам.

Более того. Если эта библиотека, содержащая определение коклассов и интерфейсов, написана как положено и позволяет получить IDL, ничто не мешает импортировать библиотеку типов, сгенерировать из неё паскалевские заглушки и включить в проект.


GrBob   (2006-07-06 17:09:00) [16]

Да, необходимо. Но я еще поковырялся и нашел немного другой способ:

procedure TForm1.Button2Click(Sender: TObject);
var
 DispParams: TDispParams;
egin
 FillChar(DispParams, SizeOf (DispParams), 0);
 DispParams.cArgs := 2;
 GetMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));
 try
   DispParams.rgvarg[0] := TVariantArg(OleVariant('aaa'));
   DispParams.rgvarg[1] := TVariantArg(OleVariant('bbb'));
   Exec(Self.Caption, DispParams);
 finally
   FreeMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));
 end;
end;


Функция Exec потом ищет метод, вызывает его ну и т.д., не суть важно. Вроде работает, но надо еще проверять, почему то иногда падает (возможно даже не в этом месте :)).


AbrosimovA   (2006-07-06 16:54:00) [17]


> OleVariant(Args[0]) := 1;  OleVariant(Args[1]) := 2;  OleVariant(Args[2])
> := 3;


Так ли уж необходимо преобразовывать к олевариантному типу?


GrBob   (2006-07-06 15:54:00) [18]

Мне кажется, что писать для этого дополнительный объект - все же перебор. Продолжая разбираться со стандартным IDispatch'ем и его Invoke'ом я смог вызвать методы без параметров. С параметрами все намного грустнее. Нашел вот такой кусок кода:
var O : IDispatch;
 Disp: TDispParams;
 Args: array[0..2] of TVariantArg;
begin
 O := CreateOleObject('Project1.Test');

 // Присваиваю аргументы
 OleVariant(Args[0]) := 1;
 OleVariant(Args[1]) := 2;
 OleVariant(Args[2]) := 3;

 with Disp do begin
   rgvarg := @Args;
   cArgs := 3;
   rgdispidNamedArgs := nil;
   cNamedArgs := 0;
 end;

 O.Invoke(1,GUID_NULL,GetThreadLocale,DISPATCH_METHOD,Disp,nil,nil,nil);
end;


Я и сам пытался написать что-то подобное (естественно, уходя от CreateOLEObject), но он падает на  преобразовании TVariantArg'a к ОлеВарианту. В МСДН вроде написано, что должно работать, да и у автора этого кода тоже все работало. У меня же - Invalid Variant type. Подскажите, в чем дело?


Медвед   (2006-07-03 10:20:00) [19]

нужно написать прокси-объект, реализующий IDispatch
пример есть в исходниках Borland Socket Server


AbrosimovA   (2006-06-30 12:40:00) [20]


> осталось узнать как вызывать методы

Так как, я проект давно забросил, то в этом направлении я не копал.
Но думаю, в Invoke нужно использовать DISPATCH_METHODи правильно заполнить DispParams


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо