Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在IUnknown中添加ref和发布,它们实际上是做什么的?_C++_C_Windows_Shell - Fatal编程技术网

C++ 在IUnknown中添加ref和发布,它们实际上是做什么的?

C++ 在IUnknown中添加ref和发布,它们实际上是做什么的?,c++,c,windows,shell,C++,C,Windows,Shell,我一直在试着让我的大脑绕过windows中的外壳扩展。需要实现的一些函数是addref()和release()。它说,它会跟踪对象引用,并在不使用时释放它们 简单解释一下,它到底在跟踪什么?在我看来,您可以创建自己的对象,根据自己的目的实现各种接口,然后让classfactory将该对象返回给com引擎运行,除非我弄错了 我只是对这个概念理解得很慢。也是一个循序渐进的过程,windows com引擎加载shell扩展,从识别dll到实际执行再到卸载。请简单解释一下。问候 简单解释一下,它到底在跟

我一直在试着让我的大脑绕过windows中的外壳扩展。需要实现的一些函数是addref()和release()。它说,它会跟踪对象引用,并在不使用时释放它们

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

我只是对这个概念理解得很慢。也是一个循序渐进的过程,windows com引擎加载shell扩展,从识别dll到实际执行再到卸载。请简单解释一下。问候

简单解释一下,它到底在跟踪什么

很简单,你所说的:

它跟踪对象引用,并在不使用时释放它们

它们用于跟踪正在使用的对象引用的数量

调用addref()会增加引用计数,而release()会减少引用计数。调用addref()以确保它知道您正在使用该对象,从而不会破坏它。完成后,释放()以告知对象已完成

一旦每个人都处理完对象(引用计数降至零),对象就可以被销毁


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

Shell扩展只是普通的COM对象

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

对象/接口的“用户”在使用完后调用Release:

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(); 
}
};
#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); }
};
创建对象的代码不需要知道其他代码对对象所做的任何事情,它只负责自己与对象的交互

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

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

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(); 
}
};
#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的框架/合同
不管是什么类别:公共IWhatever{
乌龙参考计数;
Whatever():refcount(1){}//实例refcount应该从1开始
HRESULT查询接口(…){…}
ULONG AddRef(){return++refcount;}
乌龙释放()
{
if(-refcount==0)//还有人在使用我吗?
{
删除这个;//不,我可以毁掉自己
返回0;
} 
返回引用计数;
}
void dowhateverthishingdoes(){PerformMagic(this);}
};
必须在注册表中注册此特定IWhatever实现(CLSID_Something)的CLSID,以便COM可以找到它。注册包括代码所在.DLL的路径。此.DLL必须导出函数

DllGetClassObject提供了其IClassFactory实现的一个实例,当COM请求一个新的IWhatever实例时,工厂只会调用
newwhere()

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

用一个单一的答案来解释COM是不可能的,但有很多答案

您可以使用/使用由Microsoft和第三方创建的shell对象,也可以创建自己的实现

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


MSDN列出了最常用的扩展类型。如果您想编写一个对象,这是一个很好的起点。

是的,但这些对象是什么?您只有一个shell扩展对象来实现该功能,对吗?比如说实现icontextmenu的对象,比如说对象的实例。那个对象就足够了,但为什么要跟踪多个对象呢?只是困惑。或者可能只是以错误的方式看它。@Chopnut只有一个对象,你说的“这些对象”是什么意思?@m.m哦,我想是对象引用?它说它跟踪对象引用,我想这让我很困惑。Dlladdref()用于添加引用,release()用于在不使用时减少引用或释放。那么这些引用是什么,为什么会有多个对对象的引用。。。我只是想知道我是否理解它的错误方式,当它说保持参考,当只有一个对象..做我的头在你理解的对象有多个接口。。。如果您有两个指向对象的接口指针,那么这就是两个引用哇!这就是我一直在寻找的答案,但在网上的任何教程中都找不到。精确,简单,初学者友好的解释。接受答案!我读了第一段,它似乎符合我的要求,并用示例代码直截了当。希望像我这样困惑的人也能从中受益。