IUnknown中的addref和release,它们实际上做了什么?

时间:2017-03-24 22:31:47

标签: c++ c windows shell

我一直试图让我的大脑围绕着Windows中的shell扩展。需要实现的一些函数是addref()和release()。它说,它保留了对象引用的跟踪,并在不使用时释放它们。

只是在一个简单的解释中它实际跟踪的是什么?在我的想法中,您创建自己的对象,根据您的目的实现各种接口,然后让classfactory将对象返回到com引擎运行,除非我错了。

理解这个概念真的很慢。还有一步一步的过程,即windows com引擎加载shell扩展,从识别dll到实际执行再到卸载。请简单解释一下。此致

2 个答案:

答案 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有一个最常用的扩展类型列表hereThe Complete Idiot's Guide to Writing Shell Extensions是一个很好的起点,如果你想写一个。

答案 1 :(得分:0)

  

只是简单的解释一下它实际跟踪的是什么?

很简单,你说的是什么:

  

它保留对象引用的跟踪并在不使用时释放它们

它们用于跟踪对象的引用数量。

调用addref()会增加引用计数,release()会减少它。您调用addref()以确保它知道您正在使用该对象,以便它不会销毁它。完成后,释放()告诉它你完成了对象。

一旦每个人都完成了对象(引用计数降为零),就可以销毁对象。

请注意,获取接口引用(例如DllGetClassObject)将为您调用addref(),因此您收到的接口引用的引用计数(至少)为1。

相关问题