我一直试图让我的大脑围绕着Windows中的shell扩展。需要实现的一些函数是addref()和release()。它说,它保留了对象引用的跟踪,并在不使用时释放它们。
只是在一个简单的解释中它实际跟踪的是什么?在我的想法中,您创建自己的对象,根据您的目的实现各种接口,然后让classfactory将对象返回到com引擎运行,除非我错了。
理解这个概念真的很慢。还有一步一步的过程,即windows com引擎加载shell扩展,从识别dll到实际执行再到卸载。请简单解释一下。此致
答案 0 :(得分:4)
Shell扩展只是普通的COM对象。
接口(通常以大写字母i为前缀)基本上是一个合同。可以有一个或多个接口实现。
发布由"用户"使用它时对象/接口的说明:
IWhatever*pW;
if (SUCCEEDED(CoCreateInstance(CLSID_Something, ..., IID_IWhatever, (void**) &pW)))
{
pW->DoWhateverThisThingDoes();
NotifyMyClients(pW);
pW->Release(); // Tell this instance that we are done with it
}
在前面的示例中,我们调用Release来表示我们不再需要此接口,但我们实际上并不知道接口实例是否会立即被销毁。
如果我们想象NotifyMyClients
已知的某个客户端/插件/扩展程序是这样实现的:
class FooClient {
IWhatever*MyWhatever;
void FooClient::OnNotifyNewWhatever(IWhatever*p) // Somehow called by NotifyMyClients
{
p->AddRef(); // We want to use this object later even if everyone else are done with it
if (MyWhatever) MyWhatever->Release(); // Throw away the previous instance if we had one
MyWhatever = p;
SetTimer(...); // Activate timer so we can interact with MyWhatever later
}
FooClient::FooClient()
{
MyWhatever = 0;
}
FooClient::~FooClient()
{
if (MyWhatever) MyWhatever->Release();
}
};
创建对象的代码不需要知道其他代码对对象的作用,它只负责自己与对象的交互。
基本规则是:每次在对象上调用AddRef时,都会调用一次。如果您创建了一个对象实例,则还必须将其释放。
用于实现接口的伪代码可能如下所示:
#include <Whatever.h> // The skeleton/contract for IWhatever
class Whatever : public IWhatever {
ULONG refcount;
Whatever() : refcount(1) {} // Instance refcount should start at 1
HRESULT QueryInterface(...) { ... }
ULONG AddRef() { return ++refcount; }
ULONG Release()
{
if (--refcount == 0) // Anyone still using me?
delete this; // Nope, I can destroy myself
return refcount;
}
void DoWhateverThisThingDoes() { PerformMagic(this); }
};
此特定IWhatever实现(CLSID_Something)的CLSID必须在注册表中注册,以便COM可以找到它。注册包括代码所在的.DLL的路径。此.DLL必须导出DllGetClassObject
函数。
DllGetClassObject分发其IClassFactory实现的实例,当COM要求新的IWhatever实例时,工厂只会调用new Whatever();
。
我没有介绍QueryInterface,但它用于询问对象实例是否支持另一个接口。 ICar
可能实现IVehicle
但不是IBus
也不是ITrain
等。所有COM对象都支持IUnknown接口,所有其他接口都继承自IUnknown。
在一个答案中解释COM是不可能的,但有很多introduction articles online。
您可以使用/使用由Microsoft和第三方创建的shell对象,您可以创建自己的documented interfaces实现。
如果我们以IContextMenu为例。在单个系统上可以有许多实现。当您右键单击某个内容并且每个实例将其菜单项添加到菜单时,资源管理器会创建每个已注册和适用的实例(文件扩展名与注册等相匹配)IContextMenu实现。添加所选菜单项的实例再次被调用以执行其操作,然后释放所有实例。
MSDN有一个最常用的扩展类型列表here。 The Complete Idiot's Guide to Writing Shell Extensions是一个很好的起点,如果你想写一个。
答案 1 :(得分:0)
只是简单的解释一下它实际跟踪的是什么?
很简单,你说的是什么:
它保留对象引用的跟踪并在不使用时释放它们
它们用于跟踪对象的引用数量。
调用addref()会增加引用计数,release()会减少它。您调用addref()以确保它知道您正在使用该对象,以便它不会销毁它。完成后,释放()告诉它你完成了对象。
一旦每个人都完成了对象(引用计数降为零),就可以销毁对象。
请注意,获取接口引用(例如DllGetClassObject
)将为您调用addref(),因此您收到的接口引用的引用计数(至少)为1。