COM系列问题之一:关于类工厂(300分)

  • 主题发起人 主题发起人 wrench
  • 开始时间 开始时间
W

wrench

Unregistered / Unconfirmed
GUEST, unregistred user!
大家知道
我们创建COM对象时,可以先用CoGetClassObject来得到该COM组件的类工厂
然后用类工厂的CreateInstance来创建相应的COM组件
问:
1: 这样创建组件和用CoCreateInstance创建组件有什么不同吗?
为什么要有类工厂这种东西存在,为什么我们不直接用CoCreateInstance来创建组件?
2: 后来MS好象又搞出了IClassFactory2的接口,
我怎么得到这个接口,是先得到IClassFactory的接口,然后再QueryInterface,
还是另有专门的函数?
3: IClassFactory2支持许可和权限功能,那我怎么使用这些功能呢?
用IClassFactory2创建组件和IClassFactory创建组件有什么不同?
我怎么知道客户有没有权利创建组件呢?
烦请各位大虾给一个小小例子
 
只能listen
 
这个问题么。。。倒
下星期答复你。
 
实际上CoCreateInstance内部封装了CoGetClassObject和CreateInstance
的功能,也就是说,在用CoCreateInstance创建COM对象时,不必考虑什么
创建类工厂了。但是CoCreateInstance不支持创建DCOM对象,要建DCOM对象
要用CoCreateInstanceEX
 
TO ABLE:
您说的我都知道,
我的意思是说
为什么中间要搞一个类工厂出来,写一个函数,直接根据一个CLSID,
得到一个接口指针,这样来创建组件,不可以吗?为什么中间要通过类工厂呢?
 
提请关注
 
使用类工厂可以一次创建多个com实例,而CoCreateInstance只能得到一个,
对于这两种客户的请求方式,com服务器的反应是不同的,最主要的不同就是,
对于第一种类工厂建立在客户端,第二种建立在服务器端,而且有的服务器,
客户是不能得到类工厂。也就是只能使用第二种方式。
至于IClassFactory2确实没听过,能介绍一些资料吗?
 
找到了下面的资料:


类对象
这个类对象是一个特殊的 COM 对象,它的主要目的是实现 IClassFactory 接口。(您将经常听到这个对象被引用为“类工厂”,甚至“类工厂对象”,但是更准确地应该引用为类对象。)

如果您经常使用 Java,可以粗略地将 COM 类对象看成一个 "Class" 类的 Java 对象。而且您将发现 Java 的 Class.newInstance 类似于 IClassFactory::CreateInstance,COM 的 CoGetClassObject 类似于 Class.forName 静态方法程序。

这个对象是特殊的,因为与大多数 COM 对象不同,它不是通过调用 CoCreateInstance 或 IClassFactory::CreateInstance 创建的。相反,它总是通过调用 CoGetClassObject 创建的。在本篇文章的末尾,我们将看到特殊 COM 对象的其他实例。(正如所证明的,CoGetClassObject 并不总是创建一个类对象。如果 COM 有正确类的一个类对象,它可以只返回该类对象的一个接口指针。)

在调用 CoGetClassObject 之后,代码不必关心它创建了哪种对象,例如不管该对象是一个进程内服务程序还是本地服务程序。类对象管理所有这些差别。为了知道如何创建和查找 CLSID 所需的一个类对象,CoGetClassObject 不需要查找注册表(以及已有的注册了的类对象的列表)。

类对象是多态性的强大的一个良好实例。为了得到该对象,我们调用一个 COM API。但是,当得到该对象之后,我们可以断定它支持所需的标准接口 (IClassFactory),然后可以调用该接口的方法程序,这里是 IClassFactory::CreateInstance。注意,我们还不知道类对象的 CreateInstance 是如何工作的。所知道的一切是,如果它成功了,它会返回一个指向该对象的接口指针。我们不必也不想知道别的了(即封装内容),而且通过进行相同的函数调用(即多态性),可以得到特定类对象的正确行为—正是类对象的一致性确定了正确的行为。

每个类对象实例都与一个特定的 CLSID 相关—注意,IClassFactory::CreateInstance 不需要一个 CLSID 作为它的参数。相反,类对象知道要创建什么 CLSID。这意味着,对于您想要创建的每个单独的 CLSID,至少需要一个类对象。

除了 IclassFactory,类对象可以实现任何接口。例如,您可以定义一个接口,该接口允许为从特定类对象创建的对象实例设置默认行为。但是,要注意,并不能保证对于一个给定的 CLSID,只有一个类对象,所以如果您多次调用 CoGetClassObject,可能会得到指向不同类对象的接口指针。(由于您可以控制类对象的创建,可以在实现过程中定义这一点。)

为什么要有一个类对象
正如我们讨论过的,COM 需要实现一个类对象的最重要原因是,这样 COM 可以具有创建任何种类对象的标准多态方法,而客户程序不必知道创建过程的确切细节。类对象封装了这些内容,这样客户程序就不必知道。这暗示着,类对象和“真正的”对象具有非常紧密的关系—并且经常互相很了解。

但是,为什么不采用一个更简单的方案呢?例如,您可以想象在您的 COM DLL 中有一个函数,就叫 DLLCreateInstance 吧,它可以接受一个 CLSID,并且创建一个新实例。一个函数,比一个 COM 对象和 IclassFactory 要简单地多吧。

但是,它无法为 EXE 工作。您不能从 EXE 导出函数。而且,该函数也肯定不能很好地为远程对象工作。所以,当我们让类对象作为一个 COM 对象时,COM 会照顾所有的进程内和线外问题。这是个好买卖。

由于类对象是一个知道如何正确创建目标对象的实例的 COM 对象,注意,一旦创建了类对象,对于创建实例来说,COM 就不相关了。所以,对于所创建的特定类型的第一个对象,COM 必须做大量工作。首先,它需要在注册类对象列表中查找 CLSID(或者,如果不存在类对象,就在注册表中查找)。如果需要创建类对象,COM 会创建它,可能包括加载一个 DLL 或启动一个 EXE。最后,COM 调用正确类对象的 IClassFactory::CreateInstance 来创建您的实例。哇塞!

但是,如果您保留该类对象,对于后续实例,您可以越过大多数工作:为了创建其他对象,只需自己调用 IClassFactory::CreateInstance。这几乎与直接接通接线员一样快,而比让 COM 创建新对象要快得多。

重要内容 如果您保留一个类对象,则必须调用 IClassFactory::LockServer,以便告诉 COM 将服务程序保留在内存中。对类对象的引用不会自动将服务程序保留在内存中。这个行为是 COM 常规行为的例外。如果您不能锁定服务程序,在服务程序卸载之后,试图访问类对象就有可能造成一个保护性错误。当您处理完类对象之后,不要忘记解锁该服务程序。

最后,类对象支持创建对象的其他方法,例如使用 IClassFactory2 接口,而不使用 IClassFactory 创建许可控件。许可控件是在创建该控件之前需要用户拥有正确许可 ID 的控件。

 
发现如下代码
HRESULT CoCreateInstance(REFCLSID clsdi,IUnKnown *pInkOuter,
DWord grfContext,REFIIF iid,void **ppv)
{
IClassFactory *pCF;
HRESULT hr= ::CoGetClassObject(clsid,grfContent,NULL,
IID_IClassFactory,(void **)&pCF);
if (FAILED(hr))
{
return hr;
}

hr=pCF->CreateInstance(pUnkOuter,iid,(void)**ppv);
pCF->Release();

if (FAILED(hr))
{
*ppv=0;
}
return hr;
}

也就是说
我们用CoCreateInstanse创建组件,每创建一个组件,
会生成一个类工厂的实例,造成存储器的浪费
而我们先创建类工厂,再用类工厂创建组件,
就可以用一个类工厂的实例创建多个组件

我是这样看的,不知各路高手还有何指教
 
我EMAIL个玩艺过去了,你看看,可有用?
 
一头雾水,只好动耳(眼)不动口(手)了。
 
wrench:
提到COM我想你应该先提IUnkown接口,实际上COM可以看作是多个接口
的集合,COM既是标准又是实现,COM的复杂性在于它的类工厂,我觉得
不是先生成类工厂,而是通过IUnkown得到类工厂的指针,类工厂本身
可以看作一个虚表,声明此COM中定义的接口的多种方法、属性,然后
通过虚表来构造某一个接口(每个接口实际上就是一个类)实例,使其成为
对象。最后根据住所的不同生成线程或者一个进程。
 
在我看来 COM 就是二进制类的一个标准,具有语言无关性,类厂的存在只是在创建
多个COM对象实例是提供一个高效的手段而已,就这么理解吧... :)
 
各位
类工厂的问题我已经明白了
IClassFactoey2的问题有谁知道或者有资料
还有200分哦
 
我是新手
 
IClassFactory2接口是IClassFactory接口得扩展,它除了包含CreateInstance和
LockServer成员函数,还提供了三个与许可证有关得成员函数:GetLicInof、
RequestLicKey和CreateInstanceLic。其接口定义如下:
typedef struct tagLICINFO
{
LONG cbLicInfo;
BOOL fRuntimeKeyAvail;
BOOL fLicVerified;
} LICINFO;

class IClassFactory2 : public IClassFactory
{
public:
virtual HRESULT GetLicInfo(LICINFO * pLicInfo) = 0;
virtual HRESULT RequestLicKey(DWORD dwReserved, BSTR * pBstrKey) = 0;
virtual HRESULT CreateInstanceLic(IUnknown * pUnkOuter, IUnknown * pUnkReserved, REFIID riid, BSTR bstrKey, (void **)ppvObj) = 0;
};
GetLicInfo成员函数返回一个LICINFO结构,此结构的fRuntimeKeyAvail值指明运
行时刻的许可证是否可用,fLicVerified指明类厂是否已经检查过许可证。如果
LICINFO::fRuntimeKeyAvail值为TRUE,那么RequestLicKey成员函数可以创建许
可证,并返回给包容器程序。CreateInstanceLic与IClassFactory::CreateInstance
类似,但包容器程序必须在bstrKey参数中指定一个许可证(可以预先调用RequestLicKey
函数获得)。
许可证用于ActiveX控件设计时刻或运行时刻的许可证检查。设计时刻的许可证检查
是由ActiveX控件得包容器程序完成,如Visual Basic、Visual InterDev等。这些
包容器调用IClassFactory2::CreateInstanceLic函数,并且把bstrKey参数设为
NULL,这就指示由ActiveX控件得类厂对象检查许可证,然后判断是否合法,合法的
话则创建控件,否则返回CLASS_E_NOTLICENSED。运行时刻,不同的包容器程序对ActiveX
控件的许可证检查方法有所不同,在这也就不一一详述了。
 
附加功能 将问题提前
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
900
SUNSTONE的Delphi笔记
S
后退
顶部