Click here to Skip to main content
12,949,858 members (91,313 online)
Click here to Skip to main content
Add your own
alternative version


88 bookmarked
Posted 10 Oct 2009

How to Integrate C# Window in C++ Project

, 10 Oct 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
This article describes how to integrate C# Window Form in C++ Project
Sample Image - maximum width is 600 pixels


This article describes how to integrate C# Forms (also called Windows Forms) in C++ Window. Our C++ Window is built with pure Win32 API and doesn't require MFC.


In general, Windows programming in C# is much easier than in C++, especially when we can't use MFC library in C++. Therefore many programmers prefer to build their projects in C# environment. But sometimes it is necessary to program in C++ environment. For example: when you want to develop an add-on to C++ application. We contend with this problem while developing a plug-in for, well known, Notepad++ application. Notepad++ is written in C++ and uses pure Win32 API and STL which ensures a higher execution speed and smaller program size. BUT, it also makes it difficult to design and develop UI. So, we took a challenge and decided to build our plug-in in C#. How we succeeded to integrate our .NET plug-in in Windows that builds with pure Win32 API? I hope that this article will help you understand.

We have built a small example for this article. If you prefer to view the whole source code of our plug-in for Notepad++, visit our plug-in homepage.

Creating ActiveX Control with C#


This part of the solution is based on the article that was posted by Morgan Skinner (Exposing Windows Forms Controls as ActiveX controls). Although Skinner provides his solution for Beta version of Visual Studio 8, his example works fine in the release version of VS8 (with small changes). Here is a list of changes we have made to Skinner's solution:

  1. Set ClassInterface to ClassInterfaceType.None (In this way, we expose only specific methods to COM). More information in the following section.
  2. The project should be set as visible to COM. This can be done via: Project Properties --> Application Tab --> Assembly Information --> Make assembly COM visible

  3. You should also register the project for COM Interop (Pay attention that in release version of VS8, Build Properties Window has a different design that in the beta version). When this feature enabled, Visual Studio will automatically register .NET ActiveX control after successful compilation.

  4. In Skinner's article, there is a little mistake in the ComUnregisterFunction() function. This is the correct function:
    /// <summary>
    /// Unregister ActiveX DLL function
    /// </summary>
    /// <param name="i_Key"></param>
    public static void UnregisterClass(string i_Key)
    	// strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
    	StringBuilder sb = new StringBuilder(i_Key);
    	sb.Replace(@"HKEY_CLASSES_ROOT\", "");
    	// open HKCR\CLSID\{guid} for write access
    	RegistryKey registerKey = 
    		Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
    	// delete the 'Control' key, 
    	// but don't throw an exception if it does not exist
    	registerKey.DeleteSubKey("Control", false);
    	// next open up InprocServer32
    	RegistryKey inprocServer32 = 
    		registerKey.OpenSubKey("InprocServer32", true);
    	// and delete the CodeBase key, again not throwing if missing
    	inprocServer32.DeleteSubKey("CodeBase", false);
    	// finally close the main key

Exposing Specific Methods to COM

For more accurate programming, we expose only specific methods to COM. Every external application that will use our control will receive access to necessary methods only.

The best way to expose specific methods is by creating an interface that contains all the relevant methods. Then, special attribute should be added to this interface. Form Class should implement this interface:

/// <summary>
/// COM Interface - enables to run c# code from c++
/// </summary>
public interface ICSSExplorerInterface
	void setButtonCaption(String strNewCaption);
	void setAdapterDllPtr(IntPtr i_AdapterDllPtr);

Using Microsoft Message System

We use Microsoft Message System to communicate with our container window, and with other windows in VC++ project. We don't deal with events, because it's more complicated and it isn't necessary for our solution.

We added this code to our MyDotNetActiveX class to allow message transmit:

private static uint DOT_NET_BUTTON_PRESSED = 0x0400;

private void btnOK_Click(object sender, EventArgs e)
	DOT_NET_BUTTON_PRESSED, IntPtr.Zero, IntPtr.Zero);


[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern IntPtr SendMessage(
	int hwnd, uint wMsg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(
	int hwnd, uint wMsg, int wParam, string lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(
	int hwnd, uint wMsg, int wParam, out int lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int GetNbFiles(
	int hwnd, uint wMsg, int wParam, int lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int GetFileNames(
	int hwnd, uint wMsg,
	[MarshalAs(UnmanagedType.LPArray)]IntPtr[] wParam,
	int lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(
	int hwnd, uint wMsg, int wParam, StringBuilder lParam);


On initialization, we suppose that our container window will send us its handle (hwnd) for communication.

Compiling the Project

Now we are ready to compile and test the control. Visual Studio automatically registers our ActiveX control after successful compilation. You can see registered data via freeware RegDllView application.

Testing the Control on ActiveX Control Test Container

Before we jump to the next step in the article, this is a good time to test our control in third-party applications. For the test, we use ActiveX Control Test Container (tstcon32.exe). This application is available with the installation of Visual Studio.

  1. Insert the Control via Edit menu -->Insert New Control

  2. Now choose Control menu -->Invoke Methods
  3. Choose setButtonCaption from Method Name combo-box
  4. Type "Hello" in Parameter Value text-box & press Invoke button

  5. Here is the result of our test:

Adding C# ActiveX Control to C++ Window

Using ATL Control Containment

Any window can host ActiveX control by using Active Template Library (ATL).
In this part of the guide, we will:

  1. Create C++ Win32 Application Project
  2. Insert our ActiveX control into C++ window
  3. Send commands to the ActiveX
  4. Receive message from our ActiveX

Creating C++ Win32 Application Project

  1. Create new Win32 Project and name it CPP_Container:

  2. Use default settings and press OK:

Inserting C# ActiveX Control into C++ Window

  1. Add the following code at the beginning of CPP_Container.cpp:
    #define DOT_NET_BUTTON_PRESSED  0x0400
    HWND                                            _hAtl;
    HWND                                            _hSelf;
    IUnknown*                                       _pUnk;
    DotNetActiveX::ICSSExplorerInterfacePtr         _pDotNetCOMPtr;
    HINSTANCE _hWebLib = ::LoadLibrary(TEXT("ATL.DLL")); 
  2. When Visual Studio compiled our C# project, it created DotNetActiveX.tlb file. This file contains all public methods and structures in the project. We will import this data via the following command:
    // import C# control function and structures
    #import "DotNetActiveX.tlb" named_guids raw_interfaces_only 
  3. Add the following function to CPP_Container.cpp file. This function inserts ATL container to the Window and loads our C# ActiveX:
    void loadActiveX(LPCTSTR strActiveXName)
        //Initialize ATL control containment code.
        BOOL (WINAPI *m_AtlAxWinInit)();
        m_AtlAxWinInit = (BOOL (WINAPI *)(void))::GetProcAddress
    				(_hWebLib, "AtlAxWinInit");
        // Get the dimensions of the main window's client 
        // area, and enumerate the child windows. Pass the 
        // dimensions to the child windows during enumeration. 
        RECT rcClient; 
        GetClientRect(_hSelf, &rcClient); 
        _hAtl = ::CreateWindowEx(
        		0, 0, rcClient.right, rcClient.bottom,\
        if (!_hAtl)
        	MessageBox( NULL, TEXT("Can not load AtlAxWin!"), 
    				szTitle, MB_OK | MB_ICONSTOP);
        	throw int(106901);
        HRESULT (WINAPI *m_AtlAxGetControl) (HWND h, IUnknown** pp);
        m_AtlAxGetControl = (HRESULT (WINAPI *) 
    		(HWND, IUnknown**))::GetProcAddress(_hWebLib, "AtlAxGetControl");
        m_AtlAxGetControl(_hAtl, &_pUnk);
    					(LPVOID *) &_pDotNetCOMPtr);
        if (_pDotNetCOMPtr != NULL)
        	_pDotNetCOMPtr->setAdapterDllPtr((long) _hSelf);
        	// Get the dimensions of the main window's client 
        	// area, and enumerate the child windows. Pass the 
        	// dimensions to the child windows during enumeration. 
        	RECT rcClient; 
        	GetClientRect(_hSelf, &rcClient);
        	_hAtl = ::CreateWindowEx(
        				TEXT("MSHTML:""Please register ActiveX 
    				    control before using this plugin."""),\
        				0, 0, rcClient.right, rcClient.bottom,\
  4. For accurate programming, add the following code in WM_DESTORY case in WndProc function:
  5. Finally add a call to loadActiveX function in _tWinMain function:

Sending Commands to C# ActiveX Control

After TLB file insertion, C++ file is familiar with all the methods that we exposed in C# project. Now, we can simply call the relevant method:

char *strHelloWorld = "Hello World!";
_bstr_t bstrHelloWorld(strHelloWorld);

This will change button caption to "Hello World!"

Receiving Messages from C# ActiveX Control

Messages from C# control arrive via Microsoft Message System. We already sent the handle of our Window to the C# control (in loadActiveX function). So now, we only need to add some code in WndProc function. WndProc is the function that takes care of every message that arrives to the Window. So we will simply add additional case switch to this function:

    MessageBox(NULL, TEXT("Message from C# arrived: Button Pressed!!"), 

Now, you can press the button in the C# ActiveX control and look at the results:


We hope that this article will help others to develop combined C# & C++ projects. You can check our CSSExplorer plug-in for Notepad++. All the ideas that are mentioned in this article are implemented in our plug-in.


  1. C# Programming Guide - Example COM Class (C# Programming Guide)
  2. How to add ATL control containment support to any window in Visual C++
  3. Exposing Windows Forms Controls as ActiveX controls


  • 10th October, 2009: Initial post


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


About the Author

Daniel Yanovsky
Software Developer
Israel Israel
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionError when i build the code Pin
Vin$hi6-Nov-12 8:35
memberVin$hi6-Nov-12 8:35 
QuestionWhat a wonderful article! Pin
sdfsdfsdsdffw18-Nov-11 8:27
membersdfsdfsdsdffw18-Nov-11 8:27 
Generalcompiled app runs on development computer but not on all others Pin
hmaquet3-Nov-10 8:04
memberhmaquet3-Nov-10 8:04 
AnswerRe: compiled app runs on development computer but not on all others Pin
Daniel Yanovsky3-Nov-10 22:44
memberDaniel Yanovsky3-Nov-10 22:44 

Use regasm.exe to register C# library that you created. Here is step by step description:

1) On Development Computer: Go to BIN directory of your C# project. Here you will find DEBUG or RELEASE directory. In one of these directories you will find DLL file (this is compiled output of your project). Copy this DLL file to the target Computer.

2) On Target Computer: locate regasm.exe program (This program come with .NET redistributable package and located in %WINDIR%\Microsoft.NET\Framework).

3) Open Command Shell go to regasm.exe directory and execute: regasm.exe [your DLL file full path].
For example if your DLL file path is D:\DotNetActiveX.dll, execute: regasm.exe D:\DotNetActiveX.dll

Note: You can create setup program that will automatically register your DLL file on target computer. Look at:[^]

Good luck,
GeneralRe: compiled app runs on development computer but not on all others Pin
hmaquet9-Nov-10 6:01
memberhmaquet9-Nov-10 6:01 
GeneralRe: compiled app runs on development computer but not on all others Pin
hmaquet18-Nov-10 9:12
memberhmaquet18-Nov-10 9:12 
GeneralInteresting... Pin
Vitaly Tomilov3-May-10 8:07
memberVitaly Tomilov3-May-10 8:07 
QuestionHow can i host a wpf control as ActiveX in the MFC Pin
yqy331014-Mar-10 23:05
memberyqy331014-Mar-10 23:05 
GeneralC# form in C++ Dialog Pin
Member 225651225-Nov-09 1:08
memberMember 225651225-Nov-09 1:08 
GeneralRe: C# form in C++ Dialog Pin
Daniel Yanovsky11-Jan-10 4:34
memberDaniel Yanovsky11-Jan-10 4:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170524.1 | Last Updated 10 Oct 2009
Article Copyright 2009 by Daniel Yanovsky
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid