gomasch Development Notes

Donnerstag, Oktober 13, 2005

Hosting Windows.Forms User Controls in Mfc 7.1

Here's the setup: 
A GUI is written in .Net and has to be integrated into third party product (say like Outlook) as an ActiveX control. Unfortunately the only supported host for Windows.Forms user controls in .Net Framework 1.1 is currently .Net itself, the Internet Explorer 7 and ... MFC 7.1 (see MSDN mag 2003/03). This happened to be true for our case as well. The hack of putting the user control directly into the 3rd party app did not work. (The hack: register the assembly and add some registry keys, see ".NET and COM - The Complete Interoperability Guide" by Adam Nathan page 471. It worked in the ActiceX Control Test Container but not the our 3rd party app).

The MSDN article has example source code to host a Windows.Forms.Control in MFC 7.1. It works pretty well, but only in Debug mode(I'm building an ActiveX OCX). Compiled as Release I always got strange a NullReferenceException in the copied MSDN code. I tracked it down to this line (in ::OnCreate):

 spunkControl.Attach((IUnknown*)System::Runtime::InteropServices::Marshal::GetIUnknownForObject(ctrlWinForms).ToPointer());

This line works perfectly well when compiled in Debug . In the Release build it's not working for me (and causing MSDN code later to throw a NullReferenceException), maybe due to optimization?

Doing each step one by one is working in Release too:

System::Windows::Forms::Control* ctrlWinForms;
CComPtr<IUnknown> spunkControl;

// load assembly and stuff ...

System::IntPtr iUnknown = System::Runtime::InteropServices::Marshal::GetIUnknownForObject(ctrlWinForms);
if (System::IntPtr::Zero == iUnknown)
{    
// failed to get IUnknown
    
::MessageBox(NULL, "Failed to get an IUnknown for ctrlWinForms ", "Init failed", MB_OK);
    
return VARIANT_FALSE;
}

spunkControl.Attach((IUnknown*)iUnknown.ToPointer());
if (!spunkControl)
{    
// failed to attach
    
::MessageBox(NULL, "Failed to attach the IUnknown for ctrlWinForms ", "Init failed", MB_OK);
    
return VARIANT_FALSE;
}

Final note: the docs for GetIUnknownForObject are explicitly stating, that one has to call a Marshal.Release later. CComPtr<>::Attach is not doing an AddRef though and being a smartpointer calls Release automaticly on exit.

Martin 19:19

0 Comments:

Add a comment