Upcoming Events
5th Australasian Conference on Interactive Entertainment
12/3 - 12/5 @ Brisbane, Australia

2K Bot Prize
12/15 - 12/18 @ Perth, Australia

IEEE Symposium on Computational Intelligence and Games
12/15 - 12/18 @ Perth, Australia

IEEE Consumer Communications & Networking Conference
1/10 - 1/13 @ Las Vegas, NV

More events...


Quick Stats
4589 people currently visiting GDNet.
2240 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

  search:   

Hosting a C++ D3D engine in C# Winforms


Creating a C++/CLI wrapper DLL

Now how do we expose our fancy C++ engine DLL to our equally fancy C# Winforms application? Well there are many ways: pInvoke, SWIG, COM, etc. But the way I prefer is a C++/CLI DLL. With C++/CLI, exposing a class for usage in a C# application is as simple as declaring it as a ref class, like so:

class CD3DTestRender; 

public ref class D3DWrap
{
public:
	D3DWrap();
	~D3DWrap();

	HRESULT  Initialize(IntPtr hWnd);
	HRESULT  Shutdown();
	HRESULT  ProcessFrame();
	HRESULT  Resize();

protected:
	CD3DTestRender* m_pRenderer;
};
As long as the public member functions of D3DWrap take valid .NET types everything is as right as rain. Your private and protected members can do anything their C++ hearts desire. Also make sure not to expose any header files that C# might take offense to. I forward declare my CD3DTestRenderer class and keep a protected pointer to an instance of it. The associated .cpp file is where I actually include D3DTestRenderer.h. Then we import the D3DEngine.dll for use by linking with the stub .lib file generated when we built it.

The D3Dwrap implementation merely creates and destroys an instance of CD3DTestRenderer and forwards the function calls, but we can do much more if we like. This is also the class where we would add functions that our Winforms code would call to manipulate our internal C++ engine state.

Utilizing the wrapper in a C# application

Ok now that we have our C++/CLI DLL (D3DWrap.dll), using it in our C# application is trivial. Simply right click on the Reference subfolder of the C# project (under the Solution Explorer view of Visual Studio) and add a reference to our new DLL. We can then allocate an instance of D3DWrap in our form (or anywhere we like) like so:

m_D3DWrap = new D3DWrap();

Extracting an HWND from a panel control

To initialize our engine we have to supply it with an HWND. The panel we wish to draw to is nothing more than a high-level wrapper on a Win32 window, of which we can attain a HWND. To extract a HWND from a Winforms panel and pass it to our initialization, we do this:

m_D3DWrap.Initialize(panel1.Handle); //in our C#

m_pRenderer->Initialize((HWND)(hWnd.ToPointer()),TRUE,TRUE); //in our C++/CLI

Setting up an efficient render loop

Setting up an efficient render loop in a C# Winforms application is actually non-trivial, and has been hotly debated for some time. The technique I am using was developed by Tom Miller and presented in his blog.

MFC used to have a virtual member function you could override called OnIdle that would be called continuously in a loop when there were no windows messages to process. This was the ideal place for the update and draw functions of a rendering framework to be called.

Winforms, on the other hand, does not supply such a function. Instead we only have the Idle event that is pulsed when our application goes into and out of an idle state. So how do we draw on the equivalent of MFC’s OnIdle? The basic gist of the technique is to loop (in the handler for the Idle event) on the condition that there are no waiting messages to be processed, by using a low-level PeekMessage to test that criteria. It's actually quite clever, and you can refer the link provided for a more in depth explanation.

There are also many situations where you would not wish to draw on idle, and would rather just draw when the user manipulates the scene (such as in a modeler). Instead of placing your call to ProcessFrame in the idle loop we could just as well place it in the response to a WM_PAINT message.



Page 4


Contents
  Introduction
  Page 1
  Page 2
  Page 3
  Page 4

  Source code
  Printable version
  Discuss this article