🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

How can we use own cpp game engine in C#?

Started by
4 comments, last by Shaarigan 4 years, 7 months ago

I'm currently making a game engine in CPP with DirectX 11 and planning to make a game tool like the unity in C# WPF.

I'm really wonder how can we access the objects of own gameengine if we cannot use pointer in C#?

I have made a couple of C# applications with WPF and have done plotting DirectX screen on C# application via C++/C# CLR(CLI) (sorry I don't know official correct name).

Anyway now I have more than 20 objects that need to be accessed outside of engine and they are all in pointer of course. Does anyone know how to access them? Please note I'm not good at CLR(CLI) syntax.


Advertisement

You are probably looking for P/Invoke:
https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke

For a more complete answer: you can use .NET/CLI as the lowest level bridge between C++ and .NET. It has some advantages to be able to interact with the Cpp code in a more convinient way but you need to take attention to the GC and it is Windows only since Mono dosen't support it.

The alternative is a cross-language layer or the so-called p/Invoke. You write your code in full featured C# and declare every function you want to use from your engine in C#. The CLR then lazy binds those functions at runtime if they are used for the first time. The disadvantage of this is however that you have to take attention how your function is defined in Cpp, parameter types, calling convention etc. because the CLR dosen't help you here or provide usefull information if something fails.

Also you have to take attention how you expose the functions you want to use. p/Invoke works with C-Style APIs only, it is very difficult to call a static class function for example. Also you should avoid namespaces because of the compiler name mengling problem in those cases.

What I did with my C# editor to Cpp engine code is to use p/Invoke but have a special exposure layer between the engine code and C#. It is written in pure C-Style and provides access to the engine features and functions. For example if I need access to an array of available devices, I have a function in my exposure layer

#define api_export __declspec(dllexport) cdecl

force_inline api_export void* GetDeviceList()
{
    int16 numDevices = Graphics::GetDisplayDevices(nullptr);
    Array<DisplayDevice> devices = *Allocator::Default::Allocate(numDevices);
    Graphics::GetDisplayDevices(&devices);
    
    return &devices;
}

So this way I manage the engine memory on the engine side while exposing IntPtr to the C# side. For more convinience, for example to access the native array, there are also exposure functions for Get/Set, Length etc.

Finally I wrapped those functions on the C# side into a bindings layer, a collection of classes that make use of the exposure functions but mimic to C# as if this were all OOP. I have a NativeArray, NativeAllocator that also does memory cleanup if it gets disposed etc.

My editor code in the end uses the bindings layer, for example to enumerate the display devices with native array encapsulated into some more convinient classes

Another way to handle this is to serialize the data flowing between the editor and the engine/game and use some sort of data pipe to communicate between them. I am doing this for my engine and it works really well. I have a C# application which acts as the user interface for the level editor and it starts up a version of the game which does most of the actual editing + rendering. The rendered output is then shown inside the C# app. Then I set up a network connection between the two processes and issue commands and data across that connection. This has the added benefit that you can use any languages you like as long as they can talk to the other process.

It works by the way also the other way round. If you want for example to instantiate an OpenGL render context it is possible to pass the window handle IntPtr to your C++ API from a Winforms application and start rendering at a WinForms or Control instance. Just usefull to know

This topic is closed to new replies.

Advertisement