Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.03.11;
Скачать: CL | DM;

Вниз

DCOM. Работа с объектами в потоках.   Найти похожие ветки 

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

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


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

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


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

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


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

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

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-24 17:04) [4]


> 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-24 19:26) [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-25 20:48) [6]

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

В 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-27 22:00) [7]


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

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


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


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


В смысле? :)


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


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

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



Страницы: 1 вся ветка

Текущий архив: 2007.03.11;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.082 c
15-1171473167
GeLLeR
2007-02-14 20:12
2007.03.11
dll и компонент к ней...


2-1171872487
Человек
2007-02-19 11:08
2007.03.11
Как отключить отображение курсора?


1-1169047638
alpha5
2007-01-17 18:27
2007.03.11
Область прокрутки у компонента TListView


4-1162294775
dip63
2006-10-31 14:39
2007.03.11
Процедура по хуку клавиатуры вызывается два раза


15-1171391468
maxmaxov
2007-02-13 21:31
2007.03.11
Sky Link problems