Click here to Skip to main content
15,881,752 members
Please Sign up or sign in to vote.
3.00/5 (1 vote)
See more:
So here is the setup. I have a large legacy codebase written in C++ and uses a lot of MFC. I created a new page/Class and need to use a C# form. using VS2010
* I was able to compile the single new class with the /clr flag.
* I was able to add a simple C# project to my solution and use it during a call.

Question is: How do I keep a handle to this C# object in my C++ Code. I realize my managed object reference needs to reside in the class definition, but I'm having issues getting it into the header. I could be misunderstanding some fundamental C++/CLI concepts.

I am trying to refactor as little legacy code as possible. This is why I used the option to set the single file/class to compile with /clr. I know that headers dont actually compile, and this is why there are no compilation options. This makes me unable to add the System references

Please see examples below for reference.

C++
//Setup.h
#include "stdafx.h"
/* Doesn't Like these
using namespace System;
using namespace TestCSharpForm;
using namespace System::Windows::Forms;
*/
class SetupPage: public Page
{
public:
	void activate();
	void deActivate();
	
	SetupPage(Page* pParent = NULL);   
	virtual ~SetupPage();
protected:
	virtual void DoDataExchange(CDataExchange* pDX);    

private:
//    TestCSharpForm::myForm^ myCSharpForm;
};
//END Setup.h

C++
//Setup.cpp
using namespace System;
using namespace System::Windows::Forms;
using namespace TestCSharpForm;

SetupPage::SetupPage(GLTreePage *pParent): Page(UITreeWizard_InspectionSetup::IDD, pParent)
{
   //I have no member definition of TestCSharpForm to create
}


SetupPage::~SetupPage()
{
	clear();
}

//This works, and I can access the object locally within activate()
void SetupPage::activate()
{
    TestCSharpForm::myForm^ myCSharpForm = gcnew TestCSharpForm::myForm();
}


Thank you to anyone in advance for a solution, or a point in the correct direction. If I can provide any kind of clarification please let me know.
Posted
Comments
Sergey Alexandrovich Kryukov 11-Feb-14 18:10pm    
Not clear what the problem is and what is the "handle". In CLI, there are "references", aka "managed pointers", '^'...
I don't see what's the problem with using an assembly written in C#. Basically, all kinds of .NET languages produce assemblies with the same expressive capabilities, with some deficiencies in VB.NET and some extra in C++/CLI... Maybe really your "misunderstanding some fundamental C++/CLI concepts", but I'm not quite sure.

—SA

Try this:

Quick and dirty. If your form can live as a singleton (only once instance at any time), declare it as static in Setup.cpp. It's not pretty but should work. However, I suggest keeping managed and unmanaged code separate.

Better: you already have an MFC project for you EXE and you've added a C# project for this new UI addition. Create a third project for your C++/CLI code. This will be your shim between the .NET and native code. You don't need an Active-X control (you can but it is more work). You'll end up with two assemblies and an EXE.

The C++/CLI assembly can export what is needed so that your MFC app can pass parameters and get back results. It is also possible to have native callback functions in the CLI wrapper that respond to delegates fired in your C# assembly.

You must constrain the C++/CLI to only include types valid in native C++. That means converting C# strings to MFC CStrings or STL std::strings.

As a rule, keep the amount of code in the CLI wrapper as small as possible. Do .NET work in the C# assembly and native work in the MFC app.

Don't forget to turn on "Mixed" debugging so you can step into / out of managed vs. unmanaged code in the debugger.

Good luck.
 
Share this answer
 
Please see my comment to the question.

First of all, #include "stdafx.h" is not like "using", not even close. This is just includes files, which is not needed in CLI in general, is just the C++-specific thing.

"Using" is also nothing special. This exactly like with unmanaged C++ "using". It does nothing, only introduces shortened type names. For example, you can use System::Windows::Forms::Form without any "using", or you can use using System::Windows::Forms, which would allow you to use Form without the full type name mentioned above…

I don't know what else could be unclear.

—SA
 
Share this answer
 
v2
Comments
Jake Driscoll 12-Feb-14 9:24am    
Sergey, thank you so much for the response on this. Basically I was trying to cludge things together without taking the time to fully understand them. I'm basically going to need to make a transitional area in my code to handle my differing code types. I had basically took pure C++ code and put the /clr flag on it and spawned a managed object without understanding what I had done.
Sergey Alexandrovich Kryukov 12-Feb-14 11:06am    
You are welcome. Will you accept the answer formally now (green "Accept" button)?
—SA
Although your question is not clear, the following might be useful if you need to keep an handle to a managed type Inside your native class.

How to: Declare Handles in Native Types[^]

If only some files are commpiled as managed, then usually you will either use 2 distinct pre-compiled header files or uses them only for native code file (those compiled without /clr option).

Even though I have done mixed mode programming, all the interface was managed in my case. If forms are used like a dialog, then it should not be hard to use them from your application but you might want to implement IWin32Window interface for ownership purpose...

Otherwise, if the UI is intended to be used Inside an MFC dialog, then I think that it should be user control on managed side (best to use C# for that) and they probably should be exported as Active/X controls. I have no experience into that but using Google, you should be able to do that. Here are some ot the top results for the search uses c# user control as activex:

http://www.codeguru.com/csharp/.net/net_general/comcom/article.php/c16257/Create-an-ActiveX-using-a-Csharp-Usercontrol.htm[^]

http://www.telerik.com/support/kb/winforms/details/wrapping-a-net-user-control-as-an-activex[^]

http://stackoverflow.com/questions/7409433/expose-a-winforms-usercontrol-as-an-activex-control[^]

If the page class you are creating is to be used Inside a stand-alone dialog that is not used by any MFC page, then in that case, I think it would preferable to make the whole dialog in C#.

You might have to do some special handling to properly handle messages if you have a mixed UI for things like keyboard processing, idle processing, activation...
 
Share this answer
 
Comments
Jake Driscoll 12-Feb-14 9:28am    
Philippe,
Thank you for the response, the link "How to: Declare Handles in Native Types" was a great help to me understanding what kind of code I had constructed. The C# form will live as a singleton, and can essentially be a standalone dialog, so I'm going to keep it all in C#.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900