Конференция "Corba" » Вызов OnTerminate в потоках из COM
 
  • User192 (22.04.13 13:28) [0]
    Создаю COM сервер в dll. В сервере создается поток на OnTerminate которого назначается некоторое событие. Данное событие не вызывается, т.к. вызов OnTerminate производится через Sychronize (в котором поток зависает на WaitFor). Подскажите как можно корректно вызывать Synchronize из потока в COM?

    unit BackgrounWorker;

    {$WARN SYMBOL_PLATFORM OFF}

    interface

    uses
     Windows, ComObj, Messages, ActiveX, AxCtrls, Classes, Dialogs, BackgrounWorkerDemo_TLB, StdVcl;

    type
     TWorkerThread = class(TThread)
     protected
       procedure Execute; override;
     end;

     TBackrgoundWorker = class(TAutoObject, (*IConnectionPointContainer, *) IBackrgoundWorker)
     private
       { Private declarations }
     public
       Thread : TWorkerThread;
       destructor Destroy; override;
       procedure OnWorkTerminate(Sender : TObject);
     protected
       procedure Work; safecall;
     end;

    implementation

    uses ComServ;

    destructor TBackrgoundWorker.Destroy;
    begin
     inherited;
    end;

    procedure TBackrgoundWorker.OnWorkTerminate(Sender : TObject);
    begin
     ShowMessage('Work Terminate');
    end;

    procedure TBackrgoundWorker.Work;
    begin
     Thread := TWorkerThread.Create(True);
     Thread.FreeOnTerminate := True;
     Thread.OnTerminate := OnWorkTerminate;
     Thread.Start;
     { главный цикл сообщений потока }

    end;

    { TWorkerThread }

    procedure TWorkerThread.Execute;
    var
     i: Integer;
    begin
     for i := 0 to 10 do
       Sleep(100);
     //OnTerminate не вызывается, т.к. используется Synchronize
    end;

    initialization
     TAutoObjectFactory.Create(ComServer, TBackrgoundWorker, Class_BackrgoundWorker,
       ciMultiInstance, tmApartment);

    end.

  • han_malign (26.04.13 13:09) [1]
    - очевидно, не использовать Synchronze, т.к. контейнер, который владеет основным потоком, ничего не знает о твоем classes.CheckSynchronize() и тем более о его контексте связывания...

    - а вызвать в контексте потока в конце Execute...

    а наружу, в случае STA модели, событие надо отдавать через явный маршалинг в котором и будет сделана вся необходимая сериализация...
    CoMarshalInterface/CoUnmarshalInterface
    или хелпер:
    CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream

    то бишь где то так:
    procedure TBackrgoundWorker.Work;
    begin
       ...
       if( S_OK = CoMarshalInterThreadInterfaceInStream(IBackrgoundWorker, self as IBackrgoundWorker, @Thread.FMarshalStream) )then begin
          Thread.Start
       end else begin
          Thread.Free;
          raise EOleException.Create('Мне лень', E_FAIL, 'Work', '', -1);
       end;
    end;

    procedure TWorkerThread.Execute;
    var intf: IBackrgoundWorker;
    begin
       ...
       if( S_OK = CoGetInterfaceAndReleaseStream(FMarshalStream, IBackrgoundWorker, @intf) )then
          intf.DoOnWorkTerminate(...);
    end;

  • han_malign (26.04.13 13:35) [2]
    З.Ы. и в контексте TWorkerThread надо соответственно
    CoInitialize(nil);
    ...
    intf:= nil;{при неявной(магической) очистке навернется после CoUninitialize();}
    CoUninitialize();
  • User192 (08.05.13 14:38) [3]
    Ок... Перешел на сообщения
 
Конференция "Corba" » Вызов OnTerminate в потоках из COM
Есть новые Нет новых   [134427   +26][b:0][p:0.002]