请教DCOM的运行问题 最近开发了一个DCOM服务器,内部有个队列任务。客户端可以连接调用以添加任务到队列。现在有个问题是当客户端调用完断开连接后,DCOM服务器的队列任务还没执行完毕DCOM就退出了。请问有什么办法可以让队列执行完才退出呢? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 调用addRef来增加一个COM的引用计数就可以了。 你都没试怎么知道不行?经常我们为了防止异步线程处理的业务不因为用户的断开使得进程退出而中断,就为COM增加一个引用计数,便得用户断开之后引用计数不为零而保留进程,直到业务完成,才退出。 我试过才回复的,我加了引用计数都为-1,并在DCOM服务器中加了finalization来标识程序关闭,并在任务管理器观察DCOM进程.客户端调用自动化对象的方法后,进程消失了,打开日志,并没发现有finalization的标识.证明DCOM是什么都不运行就消失了,真奇怪. 其实有两种办法,一个是正规的做法,通过AddTerminateProc来拦载,Terminate,然后判断自己的计数是否为0,如果不为0就返回false.另一种是不推荐的做法,其实引用计数在ComServer实例当中保存着,本来可以调用CountObject(True)增加和CountObject(False)来减少,不过这个却是一个protected函数。一种破坏性的做法,那就是:增加:InterlockedIncrement( PInteger(Integer(ComServer) + sizeof(Pointer))^);减少:InterlockedDecrement( PInteger(Integer(ComServer) + sizeof(Pointer))^); 还有第三种方法就是自己创建一个自己的COM实例(忘说了,我们使用的是这种方法^_^)。 _Addref是可行的,不能放在Create过程当中。可以放在被调用方法当中。正好可以替代第二种方法,但是此时有一个问题是导致DllCanUnloadNow调用时返回False,而必须自己去判断并释放。否则就会多出引用计数。这个问题很严重。上面给出的第二种方法也是不可行的。所以方法三,创建自己的COM实例应该是最有效的方法。 终于完成了一个演示,希望对楼主有用。方法比较简单。演示是通过增加一个方法Method1,被用户调用后,记下自己当前的ThreadID(GetCurrentThradId获得),然后调用_Addref增加引用计数。启动一个线程,在线程当中只做一个事,等待15秒,线程置为FreeOnTerminate,并且OnTerminated事件置过程放在COM对象当中,事件发生时(线程是主线程),调用_Release释放引用计数。此时COM的处理线程会在等待消息,所以不会去释放对象,但是此时可以PostThreadMessage(ThreadID,0,0)唤醒线程,线程就会检查计数,(而此时计数正好为0)并释放对象。 unit Unit4;{$WARN SYMBOL_PLATFORM OFF}interfaceuses Windows, Messages, SysUtils, Classes, ComServ, ComObj, VCLCom, DataBkr, DBClient, Project2_TLB, StdVcl;type Tcc = class(TRemoteDataModule, Icc) private { Private declarations } ThrdID: DWORD; procedure OnThradTerminated(Sender: TObject); protected class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; procedure Method1; safecall; public { Public declarations } end; //一个定时器线程 TMyThread = Class(TThread) protected procedure Execute;override; End;implementation{$R *.DFM}procedure TMyThread.Execute;var I: Integer;begin I := 15000;//15秒 while I>0 do begin Sleep(15); Dec(I,15); end;end;class procedure Tcc.UpdateRegistry(Register: Boolean; const ClassID, ProgID: string);begin if Register then begin inherited UpdateRegistry(Register, ClassID, ProgID); EnableSocketTransport(ClassID); EnableWebTransport(ClassID); end else begin DisableSocketTransport(ClassID); DisableWebTransport(ClassID); inherited UpdateRegistry(Register, ClassID, ProgID); end;end;procedure Tcc.Method1;var Thd: TMyThread;begin //添加引用计数 _AddRef; //取得当前线程的ID,以方便释放时唤醒 ThrdID := GetCurrentThreadId; //创建一个线程用于15秒后释放计数,以模拟线程异步操作 Thd := TMyThread.Create(True); //置线程线程事件过程,以执行释放计数的过程代码 Thd.OnTerminate := OnThradTerminated; //线程自动销毁 Thd.FreeOnTerminate := True; //唤醒线程 Thd.Resume;end;procedure Tcc.OnThradTerminated(Sender: TObject);begin //线程结束,表示异步任务完成,释放计数 _Release; //唤醒COM线程 PostThreadMessage(ThrdID,0,0,0);end;initialization TComponentFactory.Create(ComServer, Tcc, Class_cc, ciMultiInstance, tmApartment);end. 谢谢楼上的热心帮助,如果我是在调用方法里再创建执行事务线程(不是引用计数线程)的。如果用你的15秒释放引用计数的话,当调用完后也是再等待多15秒COM对象就释放了吧,但我的事务线程不一定执行完毕呢。 RAD Studio 2007发布消息 救命呀!关于图片问题!高手请快来…… 如何使DBGRID满足条件的行呈红色显示? 大侠请进:有关局域网copy文件? 怎么模拟银行的转帐系统????高手速进!!!!! 请求帮忙,谢谢合作!!!! 这怎么写啊 怎样将Word Excel的内容倒入Oracle中 ? 多层应中使用命令存取远程数据的一个问题! 关于WebSnap程序发布在IIS上的问题,目录访问权限得不到 serversocket 绑定IP 一个关于dbgrid显示数据问题
增加:
InterlockedIncrement( PInteger(Integer(ComServer) + sizeof(Pointer))^);
减少:
InterlockedDecrement( PInteger(Integer(ComServer) + sizeof(Pointer))^);
演示是通过增加一个方法Method1,被用户调用后,记下自己当前的ThreadID(GetCurrentThradId获得),然后调用_Addref增加引用计数。
启动一个线程,在线程当中只做一个事,等待15秒,线程置为FreeOnTerminate,并且OnTerminated事件置过程放在COM对象当中,事件发生时(线程是主线程),调用_Release释放引用计数。此时COM的处理线程会在等待消息,所以不会去释放对象,但是此时可以PostThreadMessage(ThreadID,0,0)唤醒线程,线程就会检查计数,(而此时计数正好为0)并释放对象。
Windows, Messages, SysUtils, Classes, ComServ, ComObj, VCLCom, DataBkr,
DBClient, Project2_TLB, StdVcl;type
Tcc = class(TRemoteDataModule, Icc)
private
{ Private declarations }
ThrdID: DWORD;
procedure OnThradTerminated(Sender: TObject);
protected
class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override;
procedure Method1; safecall;
public
{ Public declarations }
end; //一个定时器线程
TMyThread = Class(TThread)
protected
procedure Execute;override;
End;
implementation{$R *.DFM}procedure TMyThread.Execute;
var
I: Integer;
begin
I := 15000;//15秒
while I>0 do begin
Sleep(15);
Dec(I,15);
end;end;
class procedure Tcc.UpdateRegistry(Register: Boolean; const ClassID, ProgID: string);
begin
if Register then
begin
inherited UpdateRegistry(Register, ClassID, ProgID);
EnableSocketTransport(ClassID);
EnableWebTransport(ClassID);
end else
begin
DisableSocketTransport(ClassID);
DisableWebTransport(ClassID);
inherited UpdateRegistry(Register, ClassID, ProgID);
end;
end;procedure Tcc.Method1;
var
Thd: TMyThread;
begin
//添加引用计数
_AddRef;
//取得当前线程的ID,以方便释放时唤醒
ThrdID := GetCurrentThreadId;
//创建一个线程用于15秒后释放计数,以模拟线程异步操作
Thd := TMyThread.Create(True);
//置线程线程事件过程,以执行释放计数的过程代码
Thd.OnTerminate := OnThradTerminated;
//线程自动销毁
Thd.FreeOnTerminate := True;
//唤醒线程
Thd.Resume;
end;procedure Tcc.OnThradTerminated(Sender: TObject);
begin
//线程结束,表示异步任务完成,释放计数
_Release;
//唤醒COM线程
PostThreadMessage(ThrdID,0,0,0);
end;initialization
TComponentFactory.Create(ComServer, Tcc,
Class_cc, ciMultiInstance, tmApartment);
end.