简体   繁体   English

尝试通过互操作将C ++转换为C#

[英]Attempting to convert C++ into C# with interop

I've got a program that calls to EGL in C++. 我有一个程序可以在C ++中调用EGL。 I want to make the same call in C#, but there doesn't seem to be an equivalent concept in C#. 我想在C#中进行相同的调用,但是C#中似乎没有一个等效的概念。

I'm getting a read/write access denied error when the execution context enters the C++ EGL code. 当执行上下文输入C ++ EGL代码时,出现读/写访问被拒绝错误。

This is the code in the C++ program that I'm trying to convert to C#: 这是我要转换为C#的C ++程序中的代码:

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

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

I have a C# class which converts C# EGL calls into C++ calls. 我有一个C#类,它将C#EGL调用转换为C ++调用。 I believe the C++ is unmanaged, though I wouldn't know how to tell you for certain. 我相信C ++是不受管理的,尽管我不知道该如何确定。

The C# class looks like this: 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);
}

More of that code can be seen here: https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/Egl.VERSION_1_0.cs#L751 可以在这里查看更多该代码: https : //github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/Egl.VERSION_1_0.cs#L751

You may notice that this method has an IntPtr win -- this is where I'm passing the PropertySet . 您可能会注意到此方法IntPtr winIntPtr win -这就是我传递PropertySet Typically I believe this would be a System.Windows.Forms.Control , but some checking is done in the C++ EGL code to see if it is, or if it's a PropertySet . 通常,我相信这将是System.Windows.Forms.Control ,但是会在C ++ EGL代码中进行一些检查以查看它是否为PropertySet

The C++ method that is being called is this: 被调用的C ++方法是这样的:

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

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

As you can see, the C++ method is expecting an EGLNativeWindowType. 如您所见,C ++方法期望使用EGLNativeWindowType。 I'm not exactly sure what the relationship to that is between an IInspectable, and a PropertSet - it seems strange that this can be casted. 我不确定IInspectable和PropertSet之间的关系是什么-可以强制转换似乎很奇怪。

EGLNativeWindowType has the following type definition: EGLNativeWindowType具有以下类型定义:

typedef HWND EGLNativeWindowType;

Which implies it has to be some sort of window handle. 这意味着它必须是某种窗口句柄。 I don't understand how a PropertySet could be a window handle. 我不明白PropertySet如何成为窗口句柄。

I suspect the main problem is around choosing the correct type of object to pass to the C# EGL implementation. 我怀疑主要问题在于选择正确类型的对象以传递给C#EGL实现。 PropertySet seems like it might be the right choice, but the reinterpret_cast is really throwing me off. PropertySet似乎是正确的选择,但是reinterpret_cast确实让我失望了。

Can anyone walk me through this? 谁能引导我完成这个任务?

Typically I believe this would be a System.Windows.Forms.Control... 通常我相信这将是System.Windows.Forms.Control ...

It is a painfully wrong assumption. 这是一个痛苦的错误假设。 Making sense of the typing requires writing three books, pretty hard to do in an SO answer. 要理解打字,需要写三本书,这在SO答案中很难做到。 If you actually intend to do this from a Winforms app then stop right now, that can never work. 如果您实际上打算从Winforms应用程序执行此操作,然后立即停止,那将永远无法进行。

OpenGL uses very loose typing, the arguments to their api functions are nothing much more than void* , a raw pointer. OpenGL使用非常宽松的类型,其api函数的参数只不过是void* (原始指针)而已。 Which makes it very flexible but it is really important what the pointer actually points to. 这使其非常灵活,但是指针实际指向的内容非常重要。 If the client program and the video adapter interface don't agree about that in the slightest way then your program will build just fine but will crash and burn in completely undiagnosable way at runtime. 如果客户端程序和视频适配器接口在丝毫不同意,则您的程序将构建得很好,但将在运行时崩溃并以完全无法诊断的方式刻录。 A major reason why Microsoft abandoned OpenGL and decided to create their own, DirectX was the result. 结果是Microsoft放弃OpenGL并决定创建自己的DirectX的主要原因。

Which uses pointers as well but they are the smarter kind, they support type discovery at runtime. 它也使用指针,但是它们是更聪明的一种,它们在运行时支持类型发现。 They are IUnknown pointers, its QueryInterface() method permits finding out if an object supports a specific expected interface. 它们是IUnknown指针,其QueryInterface()方法允许找出对象是否支持特定的预期接口。 The flavor you see being used here is the exact same kind of pointer, IInspectable is a slightly smarter version than IUnknown and the base interface implemented by all WinRT classes. 您在这里看到的风格与指针完全相同, IInspectable是一个比IUnknown稍微聪明的版本,并且所有WinRT类都实现了基本接口。 You really do have to pass an IInspectable* since that is what the ANGLE port expects. 你真的传递一个IInspectable *自认为是角度端口所期待的。

You'd generally expect that you could just pass an ICoreWindow interface pointer and be done with it, that's the WinRT interface for a window. 通常,您期望可以只传递一个ICoreWindow接口指针并完成操作,这就是窗口的WinRT接口。 The renderer however requires more information than just the ICoreWindow. 但是,渲染器不仅需要ICoreWindow,还需要更多信息。 Not exactly sure why, I think it has something to do with resolution Independence in WinRT. 不确定原因,我认为这与WinRT中的分辨率独立性有关。 It also needs to know the surface size and scaling factor. 它还需要知道表面的大小和比例因子。

Problem is, OpenGL doesn't have a way to pass that info. 问题是,OpenGL无法传递该信息。 So the Microsoft programmer used a very hokey hack, instead of adding a function to pass this info he ab/used the ability to pass any kind of IInspectable*, he passes a IMap<String^, IInspectable*> pointer. 因此,Microsoft程序员使用了一个非常棘手的技巧,而不是添加一个传递该信息的函数,而是使用了IMap<String^, IInspectable*>指针来使他不具有传递任何IInspectable *的能力。 Basically a property bag, CoreWindowNativeWindow.cpp in the ANGLE port digs the properties out of the bag again in its CoreWindowNativeWindow::initialize() function. 基本上是一个属性包,ANGLE端口中的CoreWindowNativeWindow.cpp在其CoreWindowNativeWindow :: initialize()函数中再次从该包中挖掘属性。

PropertySet is a concrete class in the C++ language projection that implements IMap<K, V> . PropertySet是C ++语言投影中的一个具体类,实现IMap<K, V> Do note it is specific to C++, in C# you'd use a Dictionary<string, IntPtr> instead. 请注意,它特定于C ++,在C#中,您应该使用Dictionary<string, IntPtr> The language projection built into the CLR automatically maps a managed dictionary to the native IMap interface. CLR中内置的语言投影会自动将托管字典映射到本机IMap接口。

Oh joy, more IntPtrs. 太高兴了,还有更多IntPtrs。 IInspectable* is completely hidden in the language projection you use in C#, that doesn't make it easy. IInspectable *完全隐藏在您在C#中使用的语言投影中,这并不容易。 I'm 98% sure that you can use Marshal.GetIUnknownForObject() to obtain a pointer that works, even though it is wrong flavor. 我98%的确定您可以使用Marshal.GetIUnknownForObject()获得有效的指针,即使它的味道不正确。 Since the C++ code does the right thing and uses QueryInterface :) You must call Marshal.Release() afterwards to clean up, not doing so causes a memory leak. 由于C ++代码做正确的事并使用QueryInterface :)您必须在之后调用Marshal.Release()进行清理,否则将导致内存泄漏。

Do note that there are strong overtones of you doing the wrong thing. 请注意,您做错事有很强的色彩。 I think you are, Microsoft provided this ANGLE fork only for one reason. 我想您是,Microsoft仅出于一个原因提供了ANGLE分支。 They tried to make it easy for companies to port their iOS game to WinRT/UWP. 他们试图使公司轻松将其iOS游戏移植到WinRT / UWP。 Kinda necessary to fill the store with the kind of games that customers like. Kinda必须为商店提供顾客喜欢的游戏。 The ANGLE port was only ever intended to be easy to use from code that started in ObjectiveC or C++, the kind of languages used to write these games. ANGLE端口仅旨在从以ObjectiveC或C ++开头的代码(用于编写这些游戏的语言)中轻松使用。

They could have made it a lot easier to use the library from languages like Javascript or C#, they didn't because it wasn't necessary. 他们本来可以使使用Java语言或C#等语言的库变得容易得多,但这并不是因为没有必要。 If you have to translate a metric mile of C++ code that uses OpenGL to C# then it is pretty likely you'd be much better off when you use DirectX instead. 如果您有翻译的C ++代码度量英里是使用OpenGL到C#则是相当有可能你会好得多 ,当您使用DirectX代替。 Expect more of this type mapping trouble with other functions and be weary of an experimental HoloLens port. 这种类型的映射会遇到更多其他功能的麻烦,并且会对实验性的HoloLens端口感到厌倦。

I think that the parameter type is definitely wrong. 我认为参数类型肯定是错误的。

For a complete example, you should read the DeviceContext implementation in https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/NativeDeviceContext.cs . 对于完整的示例,您应该阅读https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/NativeDeviceContext.cs中的DeviceContext实现。 You should also see where this code is called, so you get the actual calls sequence needed to initialize EGL: - factory method: https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/DeviceContextFactory.cs - control integration: https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/GlControl.cs 您还应该查看该代码的调用位置,以便获得初始化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

As you can see, the handle is the Control.Handle property. 如您所见,该句柄是Control.Handle属性。 Probably the actual value to pass is dependent on the current OS implementing EGL, but it should be an handle of the window (or control) hosting the drawing results. 可能传递的实际值取决于实现EGL的当前操作系统,但是它应该是承载绘图结果的窗口(或控件)的句柄。


Alternatively, you can check the actual EGL method implementation, and follow the parameter usage untill to the actual DirectX call, just I did at that time. 另外,您可以检查实际的EGL方法实现,并遵循参数用法直到真正的DirectX调用为止,就像我当时所做的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM