-
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]Ок... Перешел на сообщения