views:

596

answers:

6

I have a native (unmanaged) C++ application (using wxWidgets for what it's worth). I'm considering a separate tool application to be written in C# which would contain winform-based dialogs. putting some of those dialogs in a separate DLL would be useful as I'd hope to be able to use them from my C++ app.

But I have no idea how much messing about is needed to accomplish this, is it particularly easy?

EDIT:

I don't need to call dialogs functions directly. I just need a way for my C++ app to call an API in the C# DLL in order to pass data, and a way for the C# DLL to call methods on some kind of observer/back object in the C++ app.

e.g from C++:

CSharpManager *pCSM = SomehowGetPointerToCSharpObject();
CSharpObserver pCSO = new CSharpObserver;

pCSM->RegisterCPlusPlusObserver(pCSO);
pCSM->LaunchDialog();

As the user does stuff in the C# dialog, pCSO methods are called to pass data back into C++

So it's pretty much a raw C++/C# communication question, I think. But though I know C++ and C# I don't know how .net itself works. I know COM but would really rather avoid it, I doubt any other developers I work with know it.

+1  A: 

It depends on what you mean by "I'd hope to be able to use them from my C++ app."

In the native world, a dialog has a dialog template structure and you can "cook" this into your executable, be it DLL or EXE. Fine. But in the managed world, things are a little different. There is no "dialog template" resource type for Winforms applications. Instead, forms are just code.

However:

  • You can always CALL INTO a managed DLL from unmanaged code. This is trivial. That managed DLL can display your Winforms dialogs. So the native C++ portion of your app can invoke those dialogs. But it can't instantiate them directly without some additional work.

  • You can always insert a C++/CLI "shim DLL" between your native C++ code and your managed DLL. Within C++/CLI, you can load both managed and .NET resources/dialogs transparently.

  • For that matter, you can call .NET methods directly from native code, without an intermediary C++/CLI shim DLL, though it's a little messy.

But as for using the ".NET/Winforms dialog resource" directly...no. Not in the sense of using the same dialog template for both Winforms as well as native C++.

James D
I don't need to call dialogs functions directly. I just need a way for my C++ app to call an API in the C# DLL in order to pass data, and a way for the C# DLL to call methods on some kind of observer/back object in the C++ app.
John
+6  A: 

The lingua franca of interop in unmanaged code is COM. That's very easy to get going on the C# side, just use the [ComVisible] attribute. You'll need to write COM code in your C++ program to use it, not so easy to get going if you've never done that. Start with the #import directive if you use the MSVC compiler.

Your next option is to host the CLR in your unmanaged code yourself rather than relying on the COM interop layer to take care of it. It allows you to create managed types directly. This requires COM as well, but only to get the CLR loaded and initialized. This project shows the approach.

Hans Passant
Heh. "Lingua franca". Indeed. +1
James D
COM is NOT needed for this, so if the C++ app doesn't already use it I wouldn't start. Of course, in such a case calls back into the C++ code become calls to a global function passing a state object pointer as an argument, instead of to member functions of the state object, but this is SO much easier to write (and debug - if something gets overwritten due to p/invoke mismatch, at least you're still calling the right code even if the data is corrupted, unlike with COM where function calls rely on a valid v-table pointer).
Ben Voigt
@Ben: check the OP, this is an unmanaged EXE. Can't call back into C++ code until somebody loads the CLR and calls managed code first.
Hans Passant
Yes, and? The CLR will automatically be loaded because the .NET assembly has a dependency on mscoree.dll or one of its friends. It was pretty weird for me the first time I found out, but purely managed code CAN have native exports. Also native EXEs can export functions for their DLLs to use.
Ben Voigt
@Ben: please post sample code in your own post in this thread, I can't make sense of your comments. A managed assembly contains data, not code. IL and metadata. You can get the C++/CLI compiler to generate a thunk with a DLL export, that's the only trick I know. That's a long way from exporting a class, especially a C# one.
Hans Passant
@nobugz: Posted links to all kinds of sample code (IL and metadata) which have native exports. Of course they export functions, not classes, ALL native exports are either functions or global data. But exported classes are definitely not needed to accomplish the OP's goal. The .NET runtime is run when the .NET assembly is loaded, purely through the static dependency load process, since the .NET assembly imports from mscorlib.dll (sorry not mscoree). So mscorlib's DllMain runs first, and it JITs all the exports, so there is native code by the time LoadLibrary returns.
Ben Voigt
All this is going way over my head... I don't even know about CLR hosting let alone all this other stuff. Can anyone check out my pseudo-code example in my edited post and answer specifically in that context?
John
+1  A: 

Either use COM, or write a C++/CLI wrapper that calls your C# dialog, then call this C++/CLI wrapper from your unmanaged C++ code.

oefe
+1 I recommend using a C++/CLI wrapper.
Danny Varod
+1  A: 

I know there are a few answers here, but none of them point to a working example. When I ran into this problem I was able to figure out thanks to this example.

http://support.microsoft.com/kb/828736

Dremation
A: 

I was going to post this as a comment to an earlier post, but since you've not accepted any answers yet maybe it'll be the one you're looking for.

Your original post had one question: "is it particularly easy?" The answer to that is an emphatic no, as evidenced by the answers you're getting.

If the other suggestions (native exports/COM/etc) are "way over your head" (your words!), and you're not going to be able to dive in and learn, my suggestion would be that you need to reconsider your proposed architecture.

Why not write the shared functions in a C++ library, which can then more easily be used by your existing C++ application? As a general rule it's a lot easier to consume native components from managed code than vice versa - so writing your C# app to consume the shared C++ DLL would be a much easier job.

I realise this doesn't answer the original technical question, but perhaps it's a more pragmatic answer to the problem you're facing.

Dan Puzey