Cho*_*nut 4 c c++ windows shell
我一直试图让我的大脑围绕 Windows 中的 shell 扩展。一些需要实现的函数是 addref() 和 release()。它说,它会跟踪对象引用并在不使用时释放它们。
简单解释一下,它实际跟踪的是什么?在我看来,您可以根据自己的目的创建自己的对象来实现各种接口,然后让 classfactory 将对象返回给 com 引擎运行,除非我弄错了。
我对这个概念的理解真的很慢。还有一步一步的过程,windows com引擎加载shell扩展,从识别dll到实际执行到卸载。请一些简单的解释。问候
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
}
Run Code Online (Sandbox Code Playgroud)
在前面的例子中,我们调用 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();
}
};
Run Code Online (Sandbox Code Playgroud)
创建对象的代码不需要知道其他代码对对象做了什么,它只负责自己与对象的交互。
基本规则是: 每次在对象上调用 AddRef 时调用一次 Release。如果您创建了一个对象实例,您还必须释放它。
用于实现 STA 接口的伪代码可能如下所示:
#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); }
};
Run Code Online (Sandbox Code Playgroud)
此特定 IWhatever 实现 (CLSID_Something) 的 CLSID 必须在注册表中注册,以便 COM 可以找到它。注册包括代码所在的 .DLL 的路径。此 .DLL 必须导出DllGetClassObject函数。
DllGetClassObject 分发其 IClassFactory 实现的实例,当 COM 请求新的 IWhatever 实例时,工厂将调用new Whatever();.
我没有介绍 QueryInterface 但它用于询问对象实例是否支持另一个接口。ICar可能实现IVehicle但不实现IBus也不ITrain等。所有 COM 对象都支持 IUnknown 接口,所有其他接口都继承自 IUnknown。
用一个答案来解释 COM 是不可能的,但是网上有很多介绍文章。
您可以使用/使用由 Microsoft 和 3rd-party 创建的 shell 对象,并且您可以创建自己的文档化接口实现。
如果我们以 IContextMenu 为例。它可以在单个系统上有许多实现。资源管理器为每个注册的和适用的(文件扩展名匹配注册等)创建一个实例,当您右键单击某物时,每个实例将其菜单项添加到菜单中时 IContextMenu 实现。再次调用添加所选菜单项的实例以执行其操作,然后释放所有实例。
MSDN 有一个在这里最常用的扩展类型列表。如果您想编写 Shell 扩展的完整白痴指南,这是一个很好的起点。