尝试使用interop将C ++转换为C#

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

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

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

PropertySet^ surfaceCreationProperties = ref new PropertySet(); surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), somethingOtherThanAWindow); mEglSurface = eglCreateWindowSurface(mEglDisplay, config, reinterpret_cast(surfaceCreationProperties), surfaceAttributes)); 

我有一个C#类,它将C#EGL调用转换为C ++调用。 我相信C ++是不受管理的,但我不知道如何告诉你。

C#类看起来像这样:

 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; 

这意味着它必须是某种窗口句柄。 我不明白PropertySet如何成为一个窗口句柄。

我怀疑主要问题是选择正确类型的对象传递给C#EGL实现。 PropertySet看起来可能是正确的选择,但是reinterpret_cast真的让我失望了。

任何人都可以带我走过这个吗?

通常我相信这将是一个System.Windows.Forms.Control …

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

OpenGL使用非常宽松的类型,它们的api函数的参数只不过是void* ,一个原始指针。 这使得它非常灵活,但指针实际指向的非常重要。 如果客户端程序和video适配器接口不能以最轻微的方式达成一致,那么您的程序将构建得很好,但会在运行时以完全不可识别的方式崩溃和刻录。 微软放弃OpenGL并决定创建自己的DirectX的一个主要原因就是结果。

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

你通常希望你可以传递一个ICoreWindow接口指针并完成它,这是一个窗口的WinRT接口。 然而,渲染器需要的信息不仅仅是ICoreWindow。 不完全确定原因,我认为它与WinRT中的Independence分辨率有关。 它还需要知道表面尺寸和比例因子。

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

PropertySet是C ++语言投影中的一个具体类,它实现了IMap 。 请注意它是特定于C ++的,在C#中你会使用Dictionary 。 内置于CLR中的语言投影会自动将托管字典映射到本机IMap接口。

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

请注意,你有很强烈的暗示你做错了事。 我想你是,微软提供这个ANGLE分支只是出于一个原因。 他们试图让公司轻松将他们的iOS游戏移植到WinRT / UWP。 有点必要,以满足客户喜欢的游戏类型。 ANGLE端口只是易于使用从ObjectiveC或C ++开始的代码,这是用于编写这些游戏的语言。

他们可以使用Javascript或C#等语言更容易地使用库,他们没有,因为没有必要。 如果你必须将使用OpenGL的C ++代码的公制里程转换为C#,那么当你使用DirectX时,你很可能会好得多。 期待更多这种类型映射其他function的麻烦,并厌倦实验HoloLens端口。

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

有关完整示例,您应该阅读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属性。 可能要传递的实际值取决于当前实现EGL的操作系统,但它应该是托管绘图结果的窗口(或控件)的句柄。


或者,你可以检查实际的EGL方法实现,并按照参数用法直到实际的DirectX调用,就在那时我做的。