IUnknown 中的 addref 和 release,它们实际上是做什么的? [英] addref and release in IUnknown, what do they actually do?

查看:77
本文介绍了IUnknown 中的 addref 和 release,它们实际上是做什么的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力思考 Windows 中的 shell 扩展.一些需要实现的函数是 addref() 和 release().它说,它会跟踪对象引用并在不使用时释放它们.

I been trying to get my brain around shell extension in windows. Some functions that needs to be implemented are addref() and release(). It said, it keep tracks of object references and release them when not in use.

简单解释一下,它实际跟踪的是什么?在我看来,您可以根据自己的目的创建自己的对象来实现各种接口,然后让 classfactory 将对象返回给 com 引擎运行,除非我弄错了.

Just in a simple explanation what is it actually tracking? In my thought you create your own object that implements various interfaces according to your purpose, then let classfactory returns the object to com engine to run unless im mistaken.

我对这个概念的理解真的很慢.还有一步一步的过程,windows com引擎加载shell扩展,从识别dll到实际执行到卸载.请一些简单的解释.问候

Am just really slow in understanding the concept. Also the step by step process, that windows com engine loads shell extensions from identifying dll through actual execution to unloading. Something simple explanation please. Regards

推荐答案

Shell 扩展只是普通的 COM 对象.

Shell extensions are just normal COM objects.

接口(通常以大写 i 为前缀)基本上是一个契约.一个接口可以有一个或多个实现.

A interface (usually prefixed with uppercase i) is basically a contract. There can be one or more implementations of a interface.

发布是由用户"调用的对象/接口使用完毕后的状态:

Release is called by the "user" of a object/interface when they are done using it:

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 来表示我们不再需要这个接口,但我们实际上并不知道这个接口实例现在是否会被销毁.

In the preceding example we call Release to indicate that we no longer need this interface but we don't actually know if the interface instance is going to be destroyed right now.

如果我们想象 NotifyMyClients 已知的客户端/插件/扩展之一是这样实现的:

If we imagine that one of the clients/plug-ins/extensions known by NotifyMyClients is implemented like this:

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(); 
}
};

创建对象的代码不需要知道其他代码对对象做了什么,它只负责自己与对象的交互.

The code that created the object does not need to know anything about what the other code does with the object, it is only responsible for its own interactions with the object.

基本规则是:每次在对象上调用 AddRef 时调用一次 Release.如果你创建了一个对象实例,你也必须释放它.

The basic rules are: Call Release once for each time you call AddRef on a object. If you created a object instance you also have to release it.

用于实现 STA 接口的伪代码可能如下所示:

Pseudo code for the implementation of a STA interface might look something like this:

#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 0;
  } 
  return refcount;
}
void DoWhateverThisThingDoes() { PerformMagic(this); }
};

此特定 IWhatever 实现 (CLSID_Something) 的 CLSID 必须在注册表中注册,以便 COM 可以找到它.注册包括代码所在的 .DLL 的路径.此 .DLL 必须导出 DllGetClassObject 函数.

The CLSID of this particular IWhatever implementation (CLSID_Something) must be registered in the registry so COM can find it. The registration includes a path to the .DLL where the code is. This .DLL must export the DllGetClassObject function.

DllGetClassObject 分发它的 IClassFactory 实现的一个实例,当 COM 请求一个新的 IWhatever 实例时,工厂只会调用 new Whatever();.

DllGetClassObject hands out a instance of its IClassFactory implementation and when COM asks for a new IWhatever instance the factory would just call new Whatever();.

我没有介绍 QueryInterface,但它用于询问对象实例是否支持另一个接口.ICar 可能实现了 IVehicle 但没有实现 IBusITrain 等.所有 COM 对象都支持 IUnknown 接口和所有其他接口继承自 IUnknown.

I did not cover QueryInterface but it is used to ask a object instance if it supports another interface. ICar probably implements IVehicle but not IBus nor ITrain etc. All COM objects support the IUnknown interface and all other interfaces inherit from IUnknown.

不可能在一个答案中解释 COM,但是有很多 在线介绍文章.

It is impossible to explain COM in a single answer but there are plenty of introduction articles online.

您可以使用/使用由 Microsoft 和 3rd-party 创建的 shell 对象,并且您可以创建自己的 文档接口.

You can use/consume shell objects created by Microsoft and 3rd-parties and you can create your own implementation of documented interfaces.

如果我们以 IContextMenu 为例.它可以在单个系统上有许多实现.资源管理器为每个注册的和适用的(文件扩展名匹配注册等)创建一个实例,当您右键单击某物时,每个实例将其菜单项添加到菜单中时 IContextMenu 实现.再次调用添加所选菜单项的实例执行其动作,然后释放所有实例.

If we take IContextMenu as an example. There can be many implementations of it on a single system. Explorer creates one instance of each registered and applicable (file extension matches registration etc.) IContextMenu implementation when you right click on something and each instance adds their menu items to the menu. The instance that added the chosen menu item is called again to execute its action and then all the instances are released.

MSDN 有一个最常用的扩展类型列表 此处.编写 Shell 扩展的完整白痴指南 如果你想写一个,这是一个很好的起点.

MSDN has a list of extension types most commonly used here. The Complete Idiot's Guide to Writing Shell Extensions is a good starting point if you want to write one.

这篇关于IUnknown 中的 addref 和 release,它们实际上是做什么的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆