【问题标题】:Why don't Direct2D and DirectWrite use traditional COM objects?为什么 Direct2D 和 DirectWrite 不使用传统的 COM 对象?
【发布时间】:2011-02-19 17:45:35
【问题描述】:

我正在使用 C# 中的一个小 2D 游戏引擎,并决定使用 Direct2D 和 DirectWrite 进行渲染。我知道有 Windows API 代码包和 SlimDX,但我真的很想深入研究并从头开始编写接口。我正在尝试不使用托管 C++,但 Direct2D 和 DirectWrite 似乎不使用传统的 COM 对象。它们定义了派生自 IUnknown 的接口,但似乎无法从 C# 与 COM 互操作实际使用它们。 d2d1.h 中有 IID,但没有 CLSID。

当然,我对 COM 互操作很陌生,所以也许我只是遗漏了一些东西。有人可以解释一下这种情况吗?

【问题讨论】:

标签: c# .net com direct2d directwrite


【解决方案1】:

codeplex 上有一个为 Direct2D 提供托管包装器的项目。我不知道它是否有什么好处,但源代码很可能会帮助您入门。

http://direct2dsharp.codeplex.com/

【讨论】:

  • 谢谢。不幸的是,它是用托管 C++ 编写的。我真的很想直接从 C# 使用 COM 互操作来做到这一点。
  • COM 互操作用于使用托管代码中的 COM 对象。您是否想找到本质上为您 P/Invoke 的 COM 包装器,以便您可以为它们生成互操作?如果是这样,我无法想象你期待什么样的表现......
【解决方案2】:

“用于 Microsoft® .NE​​T Framework 的 Windows® API 代码包”具有允许访问 Direct2D 和 DirectWrite 的托管库。

http://code.msdn.microsoft.com/WindowsAPICodePack

更新

虽然 DirectX 包装器是用托管 C++ 编写的,但它们会生成托管库。从外观上看,这些可以从 C# 中使用。下载中包含的大量示例正是这样做的,即使用来自 C# 的托管 C++ Direct 包装器库。

在我自己的 C# 应用程序中使用 Windows 7 功能会非常好,所以我目前正在安装 Window7 SDK(以便我可以构建托管 C++ DirectX 解决方案)并将给整个事情一个 bash。

我正在按照以下位置的说明进行操作:

http://blogs.msdn.com/msaleh/archive/2009/08/25/introducing-directx-features-of-windows-api-code-pack.aspx

更新 2

按照上面链接中的说明,我编译了托管 C++ 库,您确实可以非常轻松地从 C# 中使用它们。

现在我不确定我的理解是否正确,但您是否只是在寻找从 C# 中使用 Direct2D 和 DirectWrite 的某种方式,还是必须是 COM 或 P\Invoke。

我非常怀疑是否会有 COM 包装器,因为它是一种不匹配的技术。 COM 并不是为图形编程中那种高频方法调用模式而设计的——它太慢了。

如果你真的想做 P\Invoke,你可以随时查看 DirectX 头文件(在 Windows 7 SDK 中)并使用工具来创建所有 P\Invoke 调用存根,例如

http://www.pinvoker.com/

虽然以这种方式开发包装器,但这可能是一个主要的 PITA。

【讨论】:

  • 请阅读我的问题。我说我已经检查了 Windows API 代码包和 SlimDX,但它们是用托管 C++ 编写的,而我想用纯 C# 和 COM Interop/PInvoke 来做这件事。
  • 抱歉,没有正确扫描问题。我真的该睡觉了……
【解决方案3】:

知道了。您不能直接创建对象,但d2d1.dll 包含一个名为D2D1CreateFactory 的导出,它返回一个ID2DFactory 接口。使用它,您可以在没有托管 C++ 的情况下实现 Direct2D 包装器。

public static class Direct2D1Util {
    public const string IID_ID2D1Factory =
        "06152247-6f50-465a-9245-118bfd3b6007";

    [DllImport("d2d1.dll", PreserveSig = false)]
    [return: MarshalAs(UnmanagedType.Interface)]
    private static extern object D2D1CreateFactory(D2D1_FACTORY_TYPE factoryType,
        [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
        D2D1_FACTORY_OPTIONS pFactoryOptions);

    public static ID2D1Factory CreateFactory() {
        D2D1_FACTORY_OPTIONS opts = new D2D1_FACTORY_OPTIONS();
        object factory = D2D1CreateFactory(
            D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED,
            new Guid(IID_ID2D1Factory), opts);
        return (ID2D1Factory)factory;
    }
}

我不会包含所有类型,因为它们都在d2d1.h 中定义,但这里是使用代码获取工厂的方法:

ID2DFactory factory = Direct2D1Util.CreateFactory();

确保您的ID2DFactory 接口具有适当的GuidInterfaceType(ComInterfaceType.InterfaceIsIUnknown) 属性。

【讨论】:

  • D2D1CreateFactory 的签名是 HRESULT WINAPI D2D1CreateFactory( In D2D1_FACTORY_TYPE factoryType, In REFIID riid, In_opt CONST D2D1_FACTORY_OPTIONS * pFactoryOptions, Out void **ppIFactory );如何在 C# 中将其声明为返回对象的方法?因为 ppIFactory 是函数的最后一个参数?但为什么呢?
猜你喜欢
  • 2010-10-22
  • 1970-01-01
  • 2014-01-08
  • 2012-01-26
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
相关资源
最近更新 更多