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

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

DCOM. Работа с объектами в потоках. [Delphi, Windows]


Артем Кудлаенко ©   (2005-10-22 16:57:00) 

Создаю два объекта на 2-х удаленных машинах.
В первом потоке вызываю метод первого объекта, во втором - второго.
Все это в потоках для того, чтобы не ждать завершения работы методов, т.е. выполнять методы параллельно. Все это не работает без синхронизации, а с использованием синхронизации методы выполняются последовательно.
Что можно сделать для того, чтобы работа с методами выполнялась параллельно?


Набережных С.   (2005-10-29 06:43:00) [1]


> Артем Кудлаенко ©   (28.10.05 23:10) [8]

В том смысле, что в D6 декларация неправильная, а в D7 ее исправили.


Артем Кудлаенко   (2005-10-28 23:10:00) [2]


> Не обращай вниманания - брехня!


В смысле? :)


Набережных С.   (2005-10-27 22:00:00) [3]


> А вот как выглядит декларация этого интерфейса в Delphi
> 6

Не обращай вниманания - брехня!


Артем Кудлаенко   (2005-10-25 20:48:00) [4]

Большое человеческое спасибо за пример.

В Delphi 7 все в порядке.
А вот как выглядит декларация этого интерфейса в Delphi 6:

 
IGlobalInterfaceTable = interface(IUnknown)
   ['{00000146-0000-0000-C000-000000000046}']
   function RegisterInterfaceInGlobal(const pUnk: IUnknown; const riid: TIID;
                                      out dwCookie: DWORD): HResult; stdcall;
   function RevokeInterfaceFromGlobal(const riid: TIID): HResult; stdcall;
   function GetInterfaceFromGlobal(dwCookie: DWORD; const riid: TIID;
                                   out ppv): HResult; stdcall;
 end;


Набережных С.   (2005-10-24 19:26:00) [5]


> Артем Кудлаенко ©   (24.10.05 17:04) [4]
>
> > function GitRevoke(Cookie: Cardinal): HResult; stdcall;
>
>
> заменил на
>
> function GitRevoke(Cookie: TGUID): HResult; stdcall;
> Была ошибка Icompatible types 'TGUID' and 'Cardinal'.


Э-э-э... чево? :)) Ты, брат, откуда берешь декларацию IGlobalInterfaceTable?
Никаких ошибок быть не должно, код неоднократно проверен.
Вот такая декларация правильная(ActiveX.pas, D7):

 IGlobalInterfaceTable = interface(IUnknown)
   ['{00000146-0000-0000-C000-000000000046}']
   function RegisterInterfaceInGlobal(const pUnk: IUnknown; const riid: TIID;
                                      out dwCookie: DWORD): HResult; stdcall;
   function RevokeInterfaceFromGlobal(dwCookie: DWORD): HResult; stdcall;
   function GetInterfaceFromGlobal(dwCookie: DWORD; const riid: TIID;
                                   out ppv): HResult; stdcall;
 end;

Она соответствует описанию в MSDN, в СИ-шных заголовках и реальности:)

P.S. Нельзя же так - чуть до удара старика не довел:)))

> 1. В начале я вызываю:
>
> AllocStdGit();
>
> 2. Затем
>
> GitMarshal(IID, Obj, Cookie)
>
> и передаю параметры:
>   IID - GUID своего интерфейса ICalc
>   Obj - саму ссылку на Calc типа ICalc
>   Cookie - переменная, которая будет содержать некий Cookie.
>

Все правильно.

> Я так понимаю, эта функция именно это и делает? И вместо
> того кода, который передает ссылку на com-объект в поток,
>  что мне необходимо сделать?

А вот этот полученный кук и передать в поток(например, через конструктор потока). Это - идентификатор сохраненной в GIT маршалированной интерфейсной ссылки. Потом поток может вызвать GitUnmarshal, передав в него этот кук, и получить тот самый маршалированный тобой ICalc, но уже демаршалированный в апартамент этого потока. Вызов в Execute потокa может выглядеть так:

var
 Calc: ICalcж
begin
 CoInitialize(nil);
 try
   if S_OK = GitUnmarshal(FCookie, ICalc, Calc) then
   begin
// Теперь с интерфейсом можно работать
     Calc.MyMethod1;
     Calc.MyMethod2;
....
   end;
 finally
   CoUninitialize;
 end;
end;


Ну а когда больше не нужно будет хранить данный экзэмпляр ICalc in GIT, следует вызвать GitRevoke опять с тем же куком, после чего значение этого кука станет недействительным, а пакет с маршалированным экзэмпляром ICalc будет удален из GIT.


Артем Кудлаенко   (2005-10-24 17:04:00) [6]


> function GitRevoke(Cookie: Cardinal): HResult; stdcall;

заменил на

function GitRevoke(Cookie: TGUID): HResult; stdcall;
Была ошибка Icompatible types 'TGUID' and 'Cardinal'.

И вопрос: как мне использовать Ваш пример?

Примерно так:
1. В начале я вызываю:

AllocStdGit();

2. Затем

GitMarshal(IID, Obj, Cookie)

и передаю параметры:
  IID - GUID своего интерфейса ICalc
  Obj - саму ссылку на Calc типа ICalc
  Cookie - переменная, которая будет содержать некий Cookie.


> Чтобы напрямую вызывать из "дополнительных" апартаментов(в
> данном случае, видимо,  именно это имеет место быть), необходимо
> интерфейсы туда маршалировать


Я так понимаю, эта функция именно это и делает? И вместо того кода, который передает ссылку на com-объект в поток, что мне необходимо сделать?

В общем, пожалуйста, поподробнее.


Набережных С.   (2005-10-23 18:09:00) [7]

Если моя догадка верна, то, пожалуй, вместо вышеуказанных функций удобней использовать следующее(или как пример):

unit StdGlobalInterfaceTable;

interface

uses
 ActiveX;

const
 CLSID_StdGlobalInterfaceTable: TGUID = '{00000323-0000-0000-C000-000000000046}';

function GitMarshal(const IID: TGUID; const Obj: IUnknown; out Cookie: Cardinal): HResult; stdcall;
function GitUnmarshal(Cookie: Cardinal; const IID: TGUID; out Obj): HResult; stdcall;
function GitRevoke(Cookie: Cardinal): HResult; stdcall;
function AllocStdGit(): HResult; stdcall;

implementation

var
 IGit: IGlobalInterfaceTable = nil;

function AllocStdGit(): HResult;
begin
 if Assigned(IGit) then Result:=S_OK else
 Result:=CoCreateInstance(
     CLSID_StdGlobalInterfaceTable, nil, CLSCTX_INPROC_SERVER,
     IGlobalInterfaceTable, IGit)
end;

function GitMarshal(const IID: TGUID; const Obj: IUnknown; out Cookie: Cardinal): HResult; stdcall;
begin
 if Assigned(IGit) then
   Result:=IGit.RegisterInterfaceInGlobal(Obj, IID, Cookie)
 else
   Result:=E_UNEXPECTED;
end;

function GitUnmarshal(Cookie: Cardinal; const IID: TGUID; out Obj): HResult; stdcall;
begin
 if Assigned(IGit) then
   Result:=IGit.GetInterfaceFromGlobal(Cookie, IID, Obj)
 else
   Result:=E_UNEXPECTED;
end;

function GitRevoke(Cookie: Cardinal): HResult; stdcall;
begin
 if Assigned(IGit) then
   Result:=IGit.RevokeInterfaceFromGlobal(Cookie)
 else
   Result:=E_UNEXPECTED;
end;

end.

Но проверял я это только в W2k and WinXP.


Набережных С.   (2005-10-23 17:33:00) [8]

Ни-и-и-че не понял:((
Попробую догадаться. "с использованием синхронизации"- это, по-видимому, Synchronize. В этом случае просто сам вызов метода интерфейса происходит в основном потоке. Чтобы напрямую вызывать из "дополнительных" апартаментов(в данном случае, видимо,  именно это имеет место быть), необходимо интерфейсы туда маршалировать, а не просто передать ссылку.
См. пары
CoMarshalInterThreadInterfaceInStream(CoMarshalInterface)
+
CoGetInterfaceAndReleaseStream(CoUnmarshalInterface)
И про CoInitialize/CoUninitialize не забудь.


Артем Кудлаенко   (2005-10-22 17:09:00) [9]

Уточню.
Создается по одному объекту на машину.
С синхронизацией видно в закладке Сеть Диспетчера задач Windows, что данные передаются и получаются. Я передаю массив с 2 000 000 элементов по этому передачу данных легко видеть на графике.
Без синхронизации создается эффект, как будто вызов метода пропускается.


Наверх

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