Sign in to follow this  

[.net] Interfacing c# with unmanaged c++

This topic is 4661 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a "engine" written in C++ and compiled into a .lib file and I would like to make the editor in C# because after messing around with it for a while I found out how easy it was to make GUI apps with it. Unfortuanatly I can't find anything about interfacing managed code with native code. I hear about it and how it's really hard but I can't find any information on it. I searched with google but I can't find anything about it (I get things like . If anyone could point me to some resources or explain it to me it would be much appreciated.

Share this post


Link to post
Share on other sites
Interfacing with c++ can get complicated, as it requires you to expose your engine as COM+ interfaces. However if its possible to use your engine with C functions, interfacing is a piece of cake.

Firstly, your engine will need to be built as a dll, then export a set of functions such as:


typedef int* EngineHandle;

extern "C" _declspec(dllexport) EngineHandle* CreateEngine();
extern "C" _declspec(dllexport) void DrawModel(EngineHandle *pEngine, char *data);

etc.


then in the editor,


namespace Engine
{
class Native
{
[DllImport("engine.dll", EntryPoint="CreateEngine", CallingConvention=CallingConvention.StdCall)]
public static extern IntPtr CreateEngine();

[DllImport("engine.dll", EntryPoint="DrawModel", CallingConvention=CallingConvention.StdCall)]
public static extern void DrawModel(IntPtr pEngine, byte[] data);
}
}


Certainly easier than COM+ but it requires you to write a abstraction layer on top of your engine in C.

Share this post


Link to post
Share on other sites
Or you can create a managed class around your engine:

namespace Blah
{
__gc public class Engine
{
private:
NativeEngine* m_engine;

public:
void Initialize(System::Windows::Form* form)
{
HWND hwnd = (HWND)form->Handle;
m_engine->InitializeDirectX(hwnd);
}

void Render()
{
m_engine->Render();
}
};
}
This page has the managed C++ reference. Then you can use the object in C# as follows (after importing the DLL into your project):

Form mainForm;
Blah.Engine engine = new Blah.Engine();
engine.Initialize(mainForm);
engine.Render();


Note that the syntax I show here is for .NET 1.0/1.1 (VS.NET 2002/2003), and has been deprecated for CLI/C++ in .NET 2.0 (VS.NET 2005).

Share this post


Link to post
Share on other sites
Nice repiles. I learned a lot aswell. I've been wanting to do this project for a few months but in C# and i need to use a DLL written in C++. Im much more compentant with C++ and doing the equilvant work C# would be really hard for me if not impossible right now.

I have a question please for the love of all thats holy someone that knows answer please..

Okay i finally got a mixed DLL working with C# using a proxy a class, thanks Mutex.
Everything is working it seems.
Except i don't know how to pass char*'s to the DLL and return them from the DLL. Numeric params and returns are working.

How would I get this type of code to work right in C#?

[source language="C#"]
Native.ReplayProxy proxy = new Native.ReplayProxy();
string b = "hello";
string c;
proxy.accept_cstr(b);
c = proxy.return_cstr();





Im so close to actually get this program i envisioned off the ground please help!

Amnesty

Share this post


Link to post
Share on other sites
You have to massage strings a bit to cross the .NET boundary. To go from C/C++ strings to .NET, you simply construct a System::String object and pass the string in as a parameter. System::String() can take char* or wchar_t* as input. To go from a .NET string back to a character array you need to use a function to access the underlying buffer, and then copy that to your own buffer.


#include <vcclr.h> // for PtrToStringChars
using namespace System;

// Convert to System.String, which has constructors for both char* and wchar_t*.
std::string std_string = "std string";
String* net_string = new String(std_string.c_str());

Console::WriteLine(net_string);

// Convert from System.String.
// p is a pointer to the character buffer in netstring, but since netstring
// is a garbage-collected object, it may move. __pin prevents the object from
// moving in memory.
String* netstring = new String(_T("Hello from .NET"));
const wchar_t __pin* p = PtrToStringChars(netstring);

// Note that p is a wide string, need to convert to char* to allow construction
// with std::string.
size_t length = wcslen(p);
char* rawstring = new char[length+1];
wcstombs(rawstring, p, length+1);
std_string = string(rawstring);
delete [] rawstring;

std::cout << std_string << std::endl;




This page has some info on it. Double-check my .NET->std::string conversion, I'm on incredibly little sleep and it might have bugs.

Share this post


Link to post
Share on other sites
@Mutex, your idea does sound like it would be ok but unfortuanatly I do not have access to a managed C++ compiler.

@Baron_von_PartyHat: I'm not sure I would wan't to do that, but if I can't come up with another way I will do it that way.

Is there another possible way?

Share this post


Link to post
Share on other sites
::Mutex, your idea does sound like it would be ok but unfortuanatly I do not
::have access to a managed C++ compiler.

How comes? Isnt't a C++ compiler part of the .NET framework?

Without a maanged C++ compiler you are - sorry - fucked. Interop sis limited and ina lot of situations turns into a pain. Managed C++ is THE solution to make a separate DLL that exposes .NET classes and talks "native" to the underlying engine.

Been there, tried, cured - in my case it was the attempt to use the standard ISDN-interface from C# which resulted in tons of hardly maintainable code. Or to use DIrectShow (low level) - same result. Managed C++ is painless on these API's.

Get a managed C++ compiler.

Share this post


Link to post
Share on other sites
Well I am using Visual C# express and that didn't come with Visual C++. Oh well Im off to spend another few hours downloading Visual C++ express....

Share this post


Link to post
Share on other sites
Does the Visual C++ Toolkit compiler (eg: VC++ 7.1) support the /clr compiler option? If so, you should be able to compile managed code with that.

ONDotNet has a couple of decent intro tutorials to writing managed C++ wrappers (Look for Sam Gentile's articles).

Share this post


Link to post
Share on other sites
It might be easier just to have a common file format for the "editor" and the "engine". That way you don't need to interface the two, you just share the files.

Though I guess if your editor needs to use your engine directly, that approach won't work for you.

Share this post


Link to post
Share on other sites
Quote:
Original post by paulecoyote
It might be easier just to have a common file format for the "editor" and the "engine". That way you don't need to interface the two, you just share the files.

Though I guess if your editor needs to use your engine directly, that approach won't work for you.

I need it so I can render things.

@evolutional: Thanks, I was using GCC but I should be able to switch to that with no problem.

Share this post


Link to post
Share on other sites
Thanks again. I got strings working to & from C#

Alas i have one more question.
It's a little hard to explain so bare with me.


The API i would like to wrap has a topography like this

Replay (the main class)
--Has instance of a Time class
--Has instance of a Action class
--Has instance of a Header
----Has instance of a Player class

or in C++ code something like this

class replay
{
...
replay_time m_time;
replay_actions m_actions;
header m_header;
};

I'd like to very much to mimic this topography for my managed proxy class so i created a managed proxys classes for those aswell that my managed (main class) Replay will have instances of (pheww say that ten times fast).

So it would look something like this


__gc class Header
{
public:
Header (replay* arg) : m_replay(arg) {}
~Header () {}
String* get_creator_name()
{
String __pin *str = new String(m_replay->m_Header.get_creator_name());
return str;
}
private:
// this is a pointer to the main class in the native API
// its initialized in the ctor
// through this pointer it pretends to be the native header class
// by just delagating all of replay.header functions
replay* m_replay;
};




Get it? The Header class takes a replay pointer and just delegates as if it were the native API right?

Ideally in C# code i could then use the API like, how its done in C++

Native.Replay rep = new Native.Replay();
rep.open("somestring");

rep.get_header().get_creation_date();





Anyway doing this compiles fine. But when it try and use it in C#, it crashes.

However if i ignore the proxy and write a function inside the the managed Replay class to access that function without trying to use the proxy it works.

i.e

rep.get_creation_date();




Id rather not do this though. As that one class will have like 100 or so functions if i didn't split it up! And that would just be unwielding.



Any help would be extreamly appreciated

Thanks

Share this post


Link to post
Share on other sites

This topic is 4661 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this