sta*_*ica 7 .net com direct3d com-interop direct2d
在研究 Direct2D 支持哪些 COM 单元线程模型时,我发现尽管外观和事实可以使用来自 .NET 的 API 使用 COM 互操作性,但Direct2D(与其他 DirectX API 一样)实际上根本不是 COM API。(1)无论是维基百科上的Direct2D文章(2) ,以及一个由托马斯·奥尔森MSDN博客文章(3)指的是使用一个“轻量级COM”的方式这些API。
但是,我还没有找到关于这个“轻量级 COM”究竟是什么的任何官方定义。有没有这样的定义(可能是微软)?
Mike Danes 对 MSDN 论坛问题“CoInitialize/CoUninitialize,Direct2D 和 DirectWrite 真的需要它们吗?”的回答 . 这是有趣的一点:
“DirectWrite/Direct2D/Direct3D 是 COM 之类的 API,但它们不使用 COM。它们不像普通的 COM 组件那样在注册表中注册,它们不遵循 COM 线程模型,它们不支持任何类型的编组等。它们”不是 COM。”
“Direct2D 是一种基于 C++ 的本机代码 API,可由托管代码调用,并使用类似于 Direct3D 的“轻量级 COM”方法,具有最少的抽象。”
Thomas Olsen 的 MSDN 博客文章提到以下作为 Direct2D 的设计目标:
“轻量级 COM——应该使用 C++ 风格的接口来模拟 Direct3D 的使用。不支持代理、跨进程远程处理、BSTR、VARIANT、COM 注册(例如重量级的东西)。”
鉴于上述评论以及从未发布过 COM 规范的事实(除了1995 年的 0.9 版草稿),要求定义“轻量级 COM”可能毫无意义:如果“COM”不是精确定义的东西(但更多的是一个想法),那么“轻量级 COM”也许也是如此。理论上,对于使用该想法的不同 API,它可能意味着略有不同的含义。
以下尝试定义 DirectX 风格的 API 使用哪种“轻量级 COM”。我还包括我自己的“轻量级 COM”组件的代码示例。
IUnknown
”、“接口永远不会改变,一旦发布”的世界观。IUnknown
接口与 COM 的IUnknown
.QueryInterface
并使用 IID 来检索接口指针。__stdcall
调用约定、HRESULT
返回值等。组件未通过 CLSID 在注册表中注册。也就是说,组件不是通过调用来实例化的CoCreateInstance
;相反,客户端直接引用 API 的库,该库公开工厂函数(例如 Direct2D 的D2D1CreateFactory
in d2d1.dll
)。可以从此“入口点”工厂对象检索其他对象。
由于 DLL 直接加载到客户端进程中,因此“轻量级 COM”API(与 COM 不同)仅支持进程内服务器。因此不需要也不支持远程存根和代理。
理论上,“轻量级COM”库根本不依赖OLE32.dll
,即不需要调用CoXXX
函数(例如CoInitialize
设置线程的单元、CoCreateInstance
实例化共同类等)。
(但是,如果“轻量级 COM”库与实际的 COM 库或与 .NET 编组器(假定它正在处理 COM 库)互操作,则它可能仍必须使用 COM 内存分配器(CoTaskMemAlloc
、、)。)CoTaskMemRealloc
CoTaskMemFree
由于CoInitialize
不需要,因此“轻量级 COM”不使用 COM 的单元线程模型。“轻量级 COM” API 通常实现它们自己的线程模型,例如Direct2D 的多线程模型。(事实上,这个页面没有包含任何 Direct2D 支持的 COM 单元模型的提示,这表明 COM 单元根本不适用于 Direct2D!)
下面的 C++ 文件 ( Hello.cc
) 实现了一个“轻量级 COM”组件Hello
。为了说明这将独立于 COM,我不包括任何 COM 或 OLE 头文件:
#include <cinttypes>
#include <iostream>
// `HRESULT`:
typedef uint32_t HRESULT;
const HRESULT E_OK = 0x00000000;
const HRESULT E_NOINTERFACE = 0x80004002;
// `GUID` and `IID`:
typedef struct
{
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
} GUID;
bool operator ==(const GUID &left, const GUID &right)
{
return memcmp(&left, &right, sizeof(GUID)) == 0;
}
typedef GUID IID;
// `IUnknown`:
const IID IID_IUnknown = { 0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
class IUnknown
{
public:
virtual HRESULT __stdcall QueryInterface(const IID *riid, void **ppv) = 0;
virtual uint32_t __stdcall AddRef() = 0;
virtual uint32_t __stdcall Release() = 0;
};
// `IHello`:
const IID IID_IHello = { 0xad866b1c, 0x5735, 0x45e7, 0x84, 0x06, 0xcd, 0x19, 0x9e, 0x66, 0x91, 0x3d };
class IHello : public IUnknown
{
public:
virtual HRESULT __stdcall SayHello(const wchar_t *name) = 0;
};
// The `Hello` pseudo-COM component:
class Hello : public IHello
{
private:
uint32_t refcount_;
public:
Hello() : refcount_(0) { }
virtual HRESULT __stdcall QueryInterface(const IID *riid, void **ppv)
{
if (*riid == IID_IUnknown)
{
*ppv = static_cast<IUnknown*>(this);
}
else if (*riid == IID_IHello)
{
*ppv = static_cast<IHello*>(this);
}
else
{
*ppv = nullptr;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return E_OK;
}
virtual uint32_t __stdcall AddRef()
{
return ++refcount_;
}
virtual uint32_t __stdcall Release()
{
auto refcount = --refcount_;
if (refcount == 0)
{
delete this;
}
return refcount;
}
virtual HRESULT __stdcall SayHello(const wchar_t *name)
{
std::wcout << L"Hello, " << name << L"!" << std::endl;
return E_OK;
}
};
// Factory method that replaces `CoCreateInstance(CLSID_Hello, …)`:
extern "C" HRESULT __stdcall __declspec(dllexport) CreateHello(IHello **ppv)
{
*ppv = new Hello();
return E_OK;
}
Run Code Online (Sandbox Code Playgroud)
我用 Clang 编译了上面的代码(链接到 Visual Studio 2015 的 C++ 标准库),同样没有链接到任何 COM 或 OLE 库:
clang++ -fms-compatibility-version=19 --shared -m32 -o Hello.dll Hello.cc
Run Code Online (Sandbox Code Playgroud)
现在,鉴于生成的 DLL 位于我的 .NET 代码的搜索路径中(例如在bin\Debug\
或bin\Release\
目录中),我可以使用 COM 互操作在 .NET 中使用上述组件:
using System.Runtime.InteropServices;
[ComImport]
[Guid("ad866b1c-5735-45e7-8406-cd199e66913d")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IHello
{
void SayHello([In, MarshalAs(UnmanagedType.LPWStr)] string name);
}
class Program
{
[DllImport("Hello.dll", CallingConvention=CallingConvention.StdCall)]
extern static void CreateHello(out IHello outHello);
static void Main(string[] args)
{
IHello hello;
CreateHello(out hello);
hello.SayHello("Fred");
}
}
Run Code Online (Sandbox Code Playgroud)
当您使用VTable 绑定(也曾被称为“早期绑定”)+ IUnknown定义时,您会执行轻量级 COM 。就是这样。你永远不会在古老的微软出版物中找到它的定义,因为它从来没有用这个名字存在过。
作为一个 API 开发者,当你声明你做“轻量级 COM”时,你基本上是在声明你不关心以下内容:
请注意,这并不意味着你不会有吧,其实,你将拥有它是免费的,具体取决于您使用的工具(即Visual Studio中的工具,例如,它在某种程度上更容易依靠(M)IDL的抽象它提供),只是您喜欢拥有可扩展 API 的想法(使用 COM,您可以在二进制组件之间“转换”对象)而无需支持所有这些服务。
还要注意,“轻量级 COM”在任何平台和任何语言(称之为“开放”)上都非常非常便携,这在今天更有趣。
归档时间: |
|
查看次数: |
607 次 |
最近记录: |