与DLL相比,COM就是多了一些规范,按照规范写能够让系统进行调用
C++来写,uuid是定位COM
然后自动读取DLLCreateInstant,里面创建类工厂
然后类厂根据传入的CLSID , IID 然后创建对象.但在DELPHI
找不到DLLMain
那四个接口让DELPHI的ComServ自动处理
但是,不论我怎样简单的写,什么代码也没有(就用帮助的那个直接生成一个类和接口而已)
创建ActiveDll,然后建Com
注册
然后调用CreateComObject居然说没有类=.=(默认是继承自TComObject的)
到底怎么回事啊?
而且使用TypeLibrary建立接口,接口的类型不但定死,而且指针也没有似的,选择一个带*号的,然后选择out,居然报错,自己加入一些类型定义都给你去掉不让加
接口规定死是function类型.自己再写也照旧改掉写的.但看人家的就算TypeLibrary里面是Function,在外面可以写成Procedure的.我晕
也看见人家的TLB文件里面有自定义的函数指针的,我倒
现在的情况就是高不成低不就,想自己全部再写,DELPHI不让你写.用DELPHI带的,这又限制那又限制,
结果,还只是简单的写个DLL,露个函数出来,制造类厂,然后用这个类厂来创建其他类.唉.哪位高手能指点指点啊? C++转DELPHI果然就是痛苦,以为要做的不用做,想要做的不让做. 换过来DELPHI转C++,一直不做的却要做,什么都让做却不知道从哪开始做.
C++来写,uuid是定位COM
然后自动读取DLLCreateInstant,里面创建类工厂
然后类厂根据传入的CLSID , IID 然后创建对象.但在DELPHI
找不到DLLMain
那四个接口让DELPHI的ComServ自动处理
但是,不论我怎样简单的写,什么代码也没有(就用帮助的那个直接生成一个类和接口而已)
创建ActiveDll,然后建Com
注册
然后调用CreateComObject居然说没有类=.=(默认是继承自TComObject的)
到底怎么回事啊?
而且使用TypeLibrary建立接口,接口的类型不但定死,而且指针也没有似的,选择一个带*号的,然后选择out,居然报错,自己加入一些类型定义都给你去掉不让加
接口规定死是function类型.自己再写也照旧改掉写的.但看人家的就算TypeLibrary里面是Function,在外面可以写成Procedure的.我晕
也看见人家的TLB文件里面有自定义的函数指针的,我倒
现在的情况就是高不成低不就,想自己全部再写,DELPHI不让你写.用DELPHI带的,这又限制那又限制,
结果,还只是简单的写个DLL,露个函数出来,制造类厂,然后用这个类厂来创建其他类.唉.哪位高手能指点指点啊? C++转DELPHI果然就是痛苦,以为要做的不用做,想要做的不让做. 换过来DELPHI转C++,一直不做的却要做,什么都让做却不知道从哪开始做.
DLL主要是用其导出函数,所以在begin和end之间一般没有代码。
Delphi中写COM组件一般从基类继承,类似于MFC中的CCmdTarget实现了IUnkown一样,当然Delphi中已经实现的东西很多,所以不用什么都自己写。
新建项目的时候要想好自己要做什么样的COM组件
如果是普通的COM组件就选择COM Object,它会从TTypedComObject继承下来,默认是支持类型信息的(IProvideClassInfo接口)。
如果是自动化组件,就选Automation Object,他会从TAutoObject继承下来,它是在TTypedComObject的基础上实现了IDispatch接口。
此两种对象既可以是进程内的也可以是进程外的,所以Appilaction和Library的项目都可以添加。如果你的COM组件是可视控件,可以选择ActiveX Control,它可以直接将Delphi中的控件包装为ActiveX控件,因此你可以把你要做的东西当成Delphi组件来设计,然后包装一下就可以了。
如果你的COM组件是一个组合型的控件,建议使用Active Form,创建一个窗体,把你所需要的东西组合在一起,并发布接口来进程操作。
此两种对象只能是进程内组件,所以只能是ActiveX Library项目才能添加。Delphi中写进程内组件的话选择ActiveX Library,默认包含了ComServ单元,其中COM导出的四个标准方法在ComServ中已经实现。你可以选择添加一个或多个COM组件,选择后可以发现每一个组件都对应了类厂的实现(TTypedComObjectFactory或TAutoObjectFactory),而类厂都交给了ComServer进行管理,类厂的CreateInstance使用RTTI实现的,因此你只要简单的将你的COM对象的类型信息告诉它就可以了,而ComServer则会在DllGetClassObject中将对应的类厂查找出来提供给外部,所有的这些细节全部给处理好了,你可以专注于设计你的对外接口以及COM对象的实现。再跟你介绍以下TLB的设计器
其实各种类型都可以设计成指针类型(out),类型并不是只能选,可以手动输入的,在后面加上*号就可以是输出参数了。Delphi中,接口的方法有可能被标识为safecall,其含义是带HRESULT返回值的方法。Delphi中可以把IDL中描述的RetVal的参数映射为返回值(虽然实际返回值仍是HRESULT,RetVal只是个特殊的out类型参数而已),这个是编译器进行了相关的识别处理,并对HRESULT的返回值使用OleCheck进行处理,意味着在返回值不正确时会抛出异常(因此成为safecall)。由于编译器的处理导致TLB中的接口看起来跟C++的不一样(居然有procedure)。如果你研究透了Delphi对COM的支持的源代码的本质,你会发现他的思路很清晰,使用起来也很方便,优雅而大方(相对MFC和ATL来说)。TLB的设计器貌似挺好用的,我至今还没发现需要自己手动修改TLB的源代码才能实现某些功能,所以建议楼主不要轻易下结论,尽量按常规方法多尝试几次。
兄台,可以再赐教一下:
我到底如何操作,才能定义自己的函数指针?定义procedure 型函数?
还有就是,一个对象,继承自一TComObject和另一个线程接口 ,然后在initialize 里面已经加好 TComObjectFactory.Create (名字好像是这个).
通常,实现把线程采用面向对象式管理,
那么会在全局区定义 个线程入口函数.
然后,定义线程接口,每个线程类都继承自这个接口.
然后创建线程的时候,把Self当作参数传入BeginThread, 在线程入口函数里面,再采用QueryInterface 或者 直接强制类型转换(必须是类).
然后调用线程接口作为执行内容.(当然这个内容最好对自身的任何值都只是采用读取方式,要写就问题大了)
那么,就可以实现线程的面向对象式管理了,不过要带自定义参数就麻烦点.怪事就是这样开始了. 刚开始,线程是好好的运作的(需要不停的新建,同时会有6个线程运行左右) ,然后运行了不久,就会弹出错误.
说什么 访问失败, 或者什么ExcutXXXXXXXX 过多. 我倒.完全不知道什么错误.
我查了过20本书,居然没有一本书能够告诉我:到底我在ActiveX里面可不可以有多个组件? 多个组件怎样写?
如果可以多个组件,那么我会直接发布一个,然后提供多个接口.
组件里面由于有一个统一线程管理类.每个组件内部会有线程处理某些东西.
所以每个组件的交流必须通过这个核心的.
现在只是把组件交流的核心写成DLL(COM看样子是写不成=.=,本来想着只要注册了COM,然后这些组件不论放在哪里都可以正确读取DLL.)
对DELPHI所缺乏的知识太多了
而且现在的DLL,不知道为何.如果把代码写成非DLL形式,那么是不会出错的,放在DLL里面,就报错了.
组件跟核心的关系是 Has A 关系的,并非is a . 我也只是单单把这个a ,从普通的PAS 移到了DLL里面查询出来而已(查询出来是没错的,初期运行也没错的)
我真想哭-.-
type
TMyCallback = function(Param: Pointer): Integer;//TMyCallback也就是普通的回调函数指针
TMyEvent = procedure(Param: Pointer) of object;//of object表示该方法隐含Self指针,也就是thiscall
你要在接口中使用可以直接在TLB中将类型写成void *,它会映射成Pointer类型,使用的时候进行强制转换就行了
其实在COM中不是有连接点可以支持事件回调,如果你要用连接点的话需要用Automation Object类型,在TLB设计器中添加一个dispinterface,指定一个CoClass实现它,并将该接口设置为Source,然后重写CoClass的EventSinkChanged方法,如
procedure TMyAutoObject.EventSinkChanged(const EventSink: IUnknown);
begin
FEvents := EventSink as IMyEvents;
inherited EventSinkChanged(EventSink);
end;
IMyEvents是dispinterface(实际就是一个dispid的对应表,编译器在调用时会根据后面的dispid调用Invoke)
你要触发事件时就直接调用FEvents.On...2、COM的线程模型
COM的线程模型向来有两种
一、Apartment
运行于套间的COM组件,你写组件的时候就不再需要考虑方法重入的问题,因为COM库对于注册为Apartment的对象,如果跨线程调用会直接报错(非创建线程)。对该类组件,客户端如果一定要跨线程(进程)调用,需要将接口进行列集(CoMarshalInterface),然后在另一个线程(进程)中进行散集(CoUnmarshalInterface),这样处理之后COM库会对接口的调用进行同步处理。
二、Free
自由线程组件,写该类组件时所有同步都需要考虑,接口的各种方法都需要是线程安全的。客户端可以在任何线程使用组件。
不过楼主所说的线程貌似是COM组件内部的东西,对于客户端来说并不可见,应该不会有什么影响。而COM跟普通的DLL并没什么不同,代码移植应该是可以的,大概是某些细节被忽略了吧。楼主很多东西说的太笼统,我没法理解出楼主想要实现的功能,例如那个线程接口是个什么东西。
向外伸出线程执行内容接口.使用方法就是外面向里面赋上执行函数入口,然后DLL里面进行创建线程并调用.
而线程是在COM内部创建运行的.现在一个最大的问题就是:
对于普通的PAS单元.
我使用 WaitForSingleObjec(BeginThread(XXXX)) 这样,主线程是不会锁死的.
但是如果我在DLL单元里面伸出一个接口 InsertThread
procedure InsertThread
begin
WaitForSingleObjec(BeginThread(XXXX))
end然后在主线程里面写上
procedure InsertThread external 'XXX.dll'然后对这个函数进行调用.百分百会死锁.经过测试,不论DLL内部的线程有多少.
只要外部主线程对这个DLL有所操作,主线程都是优先处理的.
任何一个地方使用WaitFor函数,即使主线程处理等待状态.DLL里面的线程也照旧不会执行下去的.
这样就发生优先权死锁的问题.COM也不想考虑了.现在只弄个DLL,里面创建线程能够跟调用的线程处于同等级的priority 来执行我就满足了.
因为:假如DLL内部线程进行获得一个临界,然后这个主线程向DLL调用申请,也要获得临界的.
那么DLL里面的线程会停下来,主线程也会由于得不到临界而一直等待.如果放在普及PAS里面,主线程是等待,但起码,子线程会继续执行,主线程等子线程释放临界就会继续运行下去了.
而子线程是放在DLL里面,那么主线程调用个申请,子线程都会立刻停止等到响应完主线程的任何再继续自身的线程,这样再怎么简单的一个线程也死锁啊
为了实现DLL线程这个东西,我所有线程同步的方法都用过了,没有一个成功,包括设置优先权为 ABOVE_NORMAL (并且是设置成功的)可以有人告诉我是怎么一个回事么?
[QUOTE CSDN]
..
[/QUOTE]
就像上述那样.
一句普通的开启线程并等待返回,在PAS里面写,然后编译执行,是不会锁死的这个人人都知道.
但是如果这个过程是调用DLL来做,那么就会锁死了.子线程里面就算简单到只作 1+2 .
只要是采用DLL创建线程,并且是WaitForSingleObject(BeginThread(XXX),INFINITE);
这样主线程就会锁死了.DLL 线程里面执行,有一个
CriticalSection.Acqurie
//执行代码
CriticalSection.Release要是在执行代码的过程中,主线程向DLL发出调用.
调用过程中,也有一句
CriticalSection.Acqurie
//执行另一段代码
CriticalSection.Release.这段插入,很明显普通来说 : DLL中的线程还没有执行代码完毕,是不会Release放临界的
但是,只要主线程向DLL一发出调用,如果DLL中的线程还没有Release.
那么主线程肯定会在Acqurie过程中等待.普通来说,主线程这个等待,子线程是会继续执行完并释放临界的.
但DLL里创建的线程就有区别了,主线程只要一申请,那么两个就会立刻相互死锁.
主线程在等待临界,DLL子线程也在等待主线程返回.难道真的是要采用注入方式申请线程才能解决问题?
难道你是
CriticalSection.Acqurie
WaitForSingleObject(BeginThread(XXX),INFINITE);
CriticalSection.Release.XXX中
CriticalSection.Acqurie
//执行代码
CriticalSection.ReleaseCriticalSection在exe和dll中是同一个么?
library TestDll;uses
……
exports
……
procedure DllEntry(dwReason:Integer);
begin
//add your code here
end;begin
EntryProc:=@DllEntry;
DllEntry(DLL_PROCESS_ATTACHE);
end;
谢谢 lake_cx 等各位的帮助,派分了