How to host a hwnd C# user control control within an ATL control
Background:
Compiler: MSDEV10
Projects 64BIT
Target: WIN7/8
Language: C++
Fameworks: ATL
I have an existing code base which is all ATL which needs to use a third pa=
rty C# Assembly component. We cannot use Common Language Runtime in the sol=
ution. The given assembly has not been designed for COM in mind, and theref=
ore when you create a TLB for the assembly the GUIDS's are dynamic all the =
time and half of the methods don't exported because they have not been expl=
icitly declared as COMVisible in C#. We cannot disassemble this assembly an=
d provide the hard coded GUID's ourselves.
Assembly information:
This is a third party control which does some advanced graphics manipulatio=
n - and we just need access to the HWND and some other business logic funct=
ions. However, the HWnd is the key one.
Current implmentation:
Create a C# library that is COM designed. Within this library we inherit fr=
om the third party control as well as our own interface which will essentia=
lly act as a wrapper around our component.
This library will then be made COMVisible from the assembly configuration o=
f the project. RegAsm will then be used to create a TLB from this library a=
nd sibsequently register the TLB.
Our ATL component will then import this TLB, grab the handle of the from th=
e interface then subclass it within the ATL component.
User Control:
namespace CSharpControl
{
public partial class CSharpControl : UserControl
{
public CSharpControl()
{
InitializeComponent();
}
}
}
User wrapper library:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using CSharpControl;
namespace CSharpControlWrapper
{
[Guid("0AFABFC6-B85F-4874-968D-21C3391D3678")]
public interface IControl
{
IntPtr GetHandle();
}
[Guid("CAE265D7-BA4D-4E04-9E93-7583C0B69261"), ClassInterface(ClassInte=
rfaceType.None), ComSourceInterfaces(typeof(IControl))]
public class CSharpControlWrapper : CSharpControl.CSharpControl, IContr=
ol
{
public IntPtr GetHandle()
{
return this.Handle;
}
}
}
ATL Component:
This is s standard control, no aggregation, and it based on a static contro=
l.
I thought this would be the best way to show the window from the retrieved =
hwnd:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL&=
/*bHandled*/)
{
RECT rc;
GetWindowRect(&rc);
rc.right -= rc.left;
rc.bottom -= rc.top;
rc.top = rc.left = 0;
m_ctrl.CreateInstance(__uuidof(LIBID_CSharpControl));
//get our control handle and subclass it
__int64 handle = m_ctrl->GetHandle();
HWND hWnd = (HWND)handle;
m_ctlStatic.Create(hWnd, rc);
m_ctlStatic.SubclassWindow(hWnd);
return 0;
}
However, that doesn't work. This however does - but I don't think its the c=
orrect approach:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL&=
/*bHandled*/)
{
RECT rc;
GetWindowRect(&rc);
rc.right -= rc.left;
rc.bottom -= rc.top;
rc.top = rc.left = 0;
m_ctrl.CreateInstance(__uuidof(LIBID_CSharpControl));
__int64 handle = m_ctrl->GetHandle();
HWND hWnd = (HWND)handle;
::SetParent(hWnd, m_hWnd);
return 0;
}
Thanks for any assistance.