尝试使用互操作将 C++ 转换为 C#

Attempting to convert C++ into C# with interop

我有一个在 C++ 中调用 EGL 的程序。我想在 C# 中进行相同的调用,但在 C# 中似乎没有等效的概念。

当执行上下文进入 C++ EGL 代码时,我收到 read/write 拒绝访问错误。

这是我试图转换为 C# 的 C++ 程序中的代码:

PropertySet^ surfaceCreationProperties = ref new PropertySet();
surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), somethingOtherThanAWindow);

mEglSurface = eglCreateWindowSurface(mEglDisplay, config, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes));

我有一个 C# class 可以将 C# EGL 调用转换为 C++ 调用。我相信 C++ 是非托管的,尽管我不知道如何肯定地告诉你。

C# class 看起来像这样:

public static IntPtr CreateWindowSurface(IntPtr dpy, IntPtr config, IntPtr win, int[] attrib_list)
{
    IntPtr retValue;

    unsafe {
        fixed (int* p_attrib_list = attrib_list)
        {
            retValue = Delegates.peglCreateWindowSurface(dpy, config, win, p_attrib_list);
        }
    }
    return (retValue);
}

更多代码可以在这里看到:https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/Egl.VERSION_1_0.cs#L751

您可能会注意到此方法有一个 IntPtr win -- 这是我传递 PropertySet 的地方。通常我认为这将是一个 System.Windows.Forms.Control,但在 C++ EGL 代码中进行了一些检查以查看它是否是,或者它是否是 PropertySet.

正在调用的 C++ 方法是这样的:

EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)

更多可以在这里看到:https://github.com/Microsoft/angle/blob/ms-holographic-experimental/src/libGLESv2/entry_points_egl.cpp#L241

如您所见,C++ 方法需要 EGLNativeWindowType。我不确定 IInspectable 和 PropertSet 之间的关系是什么 - 这似乎很奇怪。

EGLNativeWindowType 具有以下类型定义:

typedef HWND EGLNativeWindowType;

这意味着它必须是某种 window 句柄。我不明白 PropertySet 怎么可能是 window 句柄。

我怀疑主要问题在于选择正确的对象类型以传递给 C# EGL 实现。 PropertySet 似乎是正确的选择,但 reinterpret_cast 真的让我失望。

谁能帮我解决这个问题?

我认为参数类型肯定是错误的。

如需完整示例,您应该阅读 https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/NativeDeviceContext.cs 中的 DeviceContext 实现。您还应该看到调用此代码的位置,以便获得初始化 EGL 所需的实际调用序列: - 工厂方法:https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/DeviceContextFactory.cs - 控制集成:https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/GlControl.cs

如您所见,句柄是 Control.Handle 属性。可能要传递的实际值取决于当前 OS 实现 EGL,但它应该是承载绘图结果的 window(或控件)的句柄。


或者,您可以检查实际的 EGL 方法实现,并遵循参数用法直到实际的 DirectX 调用,我当时就是这样做的。

Typically I believe this would be a System.Windows.Forms.Control...

这是一个令人痛苦的错误假设。理解打字需要写三本书,在 SO 答案中很难做到。如果您真的打算从 Winforms 应用程序执行此操作,请立即停止,那永远行不通。

OpenGL 使用 非常 松散类型,其 api 函数的参数只不过是 void*,一个原始指针。这使得它非常灵活,但指针实际指向的内容 确实 很重要。如果客户端程序和视频适配器接口在 最轻微的 方面不同意,那么您的程序将构建得很好,但会在运行时以完全无法诊断的方式崩溃和烧毁。 Microsoft 放弃 OpenGL 并决定创建自己的 DirectX 的一个主要原因。

它也使用指针,但它们更聪明,它们支持运行时的类型发现。它们是 IUnknown 指针,其 QueryInterface() 方法允许查明对象是否支持特定的预期接口。您在这里看到的风格是完全相同类型的指针,IInspectable 是比 IUnknown 和所有 WinRT classes 实现的基本接口稍微聪明的版本。你确实确实必须传递一个IInspectable*,因为这是ANGLE端口所期望的。

您通常希望只传递一个 ICoreWindow 接口指针并完成它,这是 window 的 WinRT 接口。然而,渲染器需要的信息不仅仅是 ICoreWindow。不确定为什么,我认为这与 WinRT 中的分辨率独立性有关。它需要知道表面大小和比例因子。

问题是,OpenGL 无法传递该信息。所以 Microsoft 程序员使用了一个非常 hokey hack,而不是 添加 一个函数来传递这个信息他 ab/used 传递任何类型的 IInspectable* 的能力,他传递一个 IMap<String^, IInspectable*> 指针。基本上是一个 属性 包,ANGLE 端口中的 CoreWindowNativeWindow.cpp 在其 CoreWindowNativeWindow::initialize() 函数中再次从包中挖掘属性。

PropertySet 是实现IMap<K, V> 的C++ 语言投影中的具体class。请注意,它特定于 C++,在 C# 中,您将使用 Dictionary<string, IntPtr> 代替。内置于 CLR 中的语言投影自动将托管字典映射到本机 IMap 接口。

哦,快乐,更多 IntPtr。 IInspectable* 完全隐藏在您在 C# 中使用的语言投影中,这并不容易。我 98% 确定您可以使用 Marshal.GetIUnknownForObject() 来获得一个有效的指针,即使它是错误的风格。因为 C++ 代码做了正确的事情并使用了 QueryInterface :) 你必须在之后调用 Marshal.Release() 来清理,不这样做会导致内存泄漏。

请注意,您做错事的暗示很强烈。我想你是,Microsoft 提供这个 ANGLE 分支只是为了 一个 原因。他们试图让公司能够轻松地将他们的 iOS 游戏移植到 WinRT/UWP。有点必要让商店充满顾客喜欢的游戏。 ANGLE 端口的目的只是为了便于从以 ObjectiveC 或 C++ 开始的代码中使用,这些语言用于编写这些游戏。

他们可以使从 Javascript 或 C# 等语言使用库变得容易得多,但他们没有这样做是因为没有必要。如果您必须将使用 OpenGL 的 C++ 代码转换为 C#,那么当您改用 DirectX 时,很可能 much 会更好。期待更多此类映射与其他功能的麻烦,并对实验性 HoloLens 端口感到厌倦。