> Thank you Peter.
>
[quoted text clipped - 17 lines]
>> This posting is provided "AS IS" with no warranties, and confers no
> rights.
Martin and Mircea,
I was also trying to host Windows forms control in MFC and VC 6.0. i was
able to receive events as well. But tab order got messed up. Tab order goes
with in the windows forms controls and goes in reverse before the focus goes
to the un-managed controls.
I used the Chris sells ariticle in onedotnet and another article in
codeproject and MSDN.
But the working solution is create the eventsink manually. End of the day.
its not complete working solution.. Tab problem..
Have you come across the Tabbing issues ?
Here is my code..
Steps
1. Genenrate the Wraper class. works fine for creating the control etc
2. Manually sink the event sink. refer the type library
.h file of the dialog..
#include <afxctl.h>
#import "WnCtrlLib3.tlb" no_namespace named_guids// raw_interfaces_only
#include "csharpusercontrol1.h"
CWnCtrlClientDlg(CWnd* pParent = NULL); // standard constructor
ICSharpCOMInterfacePtr m_spWnCSMConnObj;
DWORD m_dwCookie;
bool Clear();
bool InitSink();
CCsharpusercontrol1 m_csharpctgrl;
.cpp file
CWnCtrlClientDlg::CWnCtrlClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CWnCtrlClientDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
EnableAutomation();
m_spWnCSMConnObj = NULL;
m_dwCookie = 0;
}
InitDialog()
{
InitSink();
}
bool CWnCtrlClientDlg::Clear()
{
if (this && m_dwCookie)
{
LPUNKNOWN pUnkSink = this->GetIDispatch(FALSE);
//Terminate a connection between source and sink.
//m_pUnkSrc is IUnknown of server obtained by CoCreateInstance().
//m_dwCookie is a value obtained through AfxConnectionAdvise().
BOOL bRet = AfxConnectionUnadvise(m_spWnCSMConnObj, DIID_ICSharpCOMEvents
, pUnkSink, FALSE, m_dwCookie);
ASSERT(bRet);
}
if (m_spWnCSMConnObj)
{
m_spWnCSMConnObj.Release();
m_spWnCSMConnObj = NULL;
}
return true;
}
bool CWnCtrlClientDlg::InitSink()
{
// set the pointer to m_spWnCSMConnObj from the control..
LPUNKNOWN pUnk = m_csharpctgrl.GetControlUnknown();
// From there get the ICSharpCOMInterface interface of control
if (SUCCEEDED(pUnk->QueryInterface(
IID_ICSharpCOMInterface,
(LPVOID*)&m_spWnCSMConnObj)))
{
/ //dispinterface and the IUnknown and IDispatch pointers will be same.
LPUNKNOWN pUnkSink = this->GetIDispatch(FALSE);
//Establish a connection between source and sink.
//m_pUnkSrc is IUnknown of server obtained by CoCreateInstance().
//m_dwCookie is a cookie identifying the connection, and is needed
//to terminate the connection.
BOOL bSuccess = FALSE;
LPCONNECTIONPOINTCONTAINER pCPC;
if (SUCCEEDED(m_spWnCSMConnObj->QueryInterface(
IID_IConnectionPointContainer,
(LPVOID*)&pCPC)))
{
ASSERT_POINTER(pCPC, IConnectionPointContainer);
LPCONNECTIONPOINT pCP;
if (SUCCEEDED(pCPC->FindConnectionPoint(DIID_ICSharpCOMEvents, &pCP)))
{
ASSERT_POINTER(pCP, IConnectionPoint);
HRESULT hrAdvise = pCP->Advise(pUnkSink, &m_dwCookie);
// Call Advise again if an error occurs here
if (!SUCCEEDED(hrAdvise))
HRESULT hrAdvise = pCP->Advise(pUnkSink, &m_dwCookie);
if (SUCCEEDED(hrAdvise))
bSuccess = TRUE;
pCP->Release();
// The connection point just AddRef'ed us. If we don't want to
// keep this reference count (because it would prevent us from
// being deleted; our reference count wouldn't go to zero), then
// we need to cancel the effects of the AddRef by calling
// Release.
if (bSuccess)
pUnkSink->Release();
}
pCPC->Release();
}
return true;
}
return false;
}
void CWnCtrlClientDlg::OnDestroy()
{
Clear();
}
BEGIN_DISPATCH_MAP(CWnCtrlClientDlg, CDialog)
//{{AFX_DISPATCH_MAP(CCSM7RegDlg)
DISP_FUNCTION_ID(CWnCtrlClientDlg,"EventA",0x00000001,EventA,VT_EMPTY,VTS_NONE)
DISP_FUNCTION_ID(CWnCtrlClientDlg,"EventB",0x00000002,EventB,VT_EMPTY,VTS_I4)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
BEGIN_INTERFACE_MAP(CWnCtrlClientDlg, CDialog)
INTERFACE_PART(CWnCtrlClientDlg, DIID_ICSharpCOMEvents, Dispatch)
END_INTERFACE_MAP()
void CWnCtrlClientDlg::EventA()
{
AfxMessageBox("Received event");
}
void CWnCtrlClientDlg::EventB(long nVal)
{
CString str;
str.Format("Received value %d",nVal);
AfxMessageBox(str);
}
void CWnCtrlClientDlg::OnBnClickedButton1()
{
m_spWnCSMConnObj->MethodB(45);
}
----------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
using System.Reflection;
using Microsoft.Win32;
[assembly:ClassInterface(ClassInterfaceType.AutoDual)]
namespace CSharpCOMEvent
{
///
/// Summary description for UserControl1.
///
[ Guid("A81D14C0-73B9-487a-8526-4D5B2DA82ABB") ]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICSharpCOMInterface
{
void MethodA();
void MethodB(int a);
}
[ComVisible(false)]
public delegate void CSharpEventHandlerA ();
[ComVisible(false)]
public delegate void CSharpEventHandlerB (int a);
[Guid("71BC0ECA-344D-4f6a-8184-2B497ECBA7FA"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICSharpCOMEvents
{
[DispId(1)]void EventA();
[DispId(2)]void EventB(int a);
}
[GuidAttribute("C3308D40-B96A-4ff5-BCA2-E26B320435AE")]
[ProgId("CSharpCOMEvent.CSharpUserControl")]
[ComSourceInterfacesAttribute(typeof (ICSharpCOMEvents))]
[ClassInterface(ClassInterfaceType.None)]
public class CSharpUserControl : System.Windows.Forms.UserControl,
ICSharpCOMInterface
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
[Category("Action")]
public event CSharpEventHandlerA EventA;
[Category("Action")]
public event CSharpEventHandlerB EventB;
public CSharpUserControl()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitForm call
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}
public void MethodA()
{
this.textBox1.Text = "MethodA";
OnMyEventA();
}
public void MethodB(int a)
{
OnMyEventB(a);
}
protected virtual void OnMyEventA()
{
if (EventA != null)
{
this.textBox1.Text = "Event fired!";
EventA();
}
}
protected virtual void OnMyEventB(int a)
{
if (EventB != null)
EventB(a);
}
[ComRegisterFunction()]
public static void RegisterClass ( Type t )
{
// Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
string sb = @"CLSID\" + t.GUID.ToString("B");
sb.Replace(@"HKEY_CLASSES_ROOT\","") ;
// Open the CLSID\{guid} key for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);
// And create the 'Control' key - this allows it to show up in
// the ActiveX control container
RegistryKey ctrl = k.CreateSubKey ( "Control" ) ;
ctrl.Close ( ) ;
using( RegistryKey subkey = k.CreateSubKey("MiscStatus") )
{
subkey.SetValue("", "131473");
}
using( RegistryKey subkey = k.CreateSubKey("MiscStatus\\1") )
{
subkey.SetValue("", "197009");
}
// Next create the CodeBase entry - needed if not string named and GACced
RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true );
inprocServer32.SetValue ( "CodeBase" ,
Assembly.GetExecutingAssembly().CodeBase ) ;
inprocServer32.Close ( ) ;
// Now create the Version entry
RegistryKey vers = k.CreateSubKey("Version");
vers.SetValue("", "1.0");
vers.Close();
RegistryKey inst = k.CreateSubKey ( "Insertable" ) ;
inst.Close ( ) ;
// And the Type Lib Entry
using( RegistryKey subkey = k.CreateSubKey("TypeLib") )
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(t.Assembly);
subkey.SetValue("", libid.ToString("B"));
}
// Finally close the main key
k.Close ( ) ;
}
[ComUnregisterFunction()]
public static void UnregisterClass ( string key )
{
StringBuilder sb = new StringBuilder ( key ) ;
sb.Replace(@"HKEY_CLASSES_ROOT\","") ;
// Open HKCR\CLSID\{guid} for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);
// Delete the 'Control' key, but don't throw an exception if it does not
exist
k.DeleteSubKey ( "Control" , false ) ;
// Next open up InprocServer32
RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true );
// And delete the CodeBase key, again not throwing if missing
k.DeleteSubKey ( "CodeBase" , false ) ;
k.DeleteSubKey ( "TypeLib" , false ) ;
k.DeleteSubKey ( "Version" , false ) ;
// Finally close the main key
k.Close ( ) ;
}
#region Component Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(8, 8);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(192, 20);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1";
//
// button1
//
this.button1.Location = new System.Drawing.Point(8, 32);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(192, 24);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// CSharpUserControl
//
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.Name = "CSharpUserControl";
this.Size = new System.Drawing.Size(208, 64);
this.ResumeLayout(false);
}
#endregion
private void button1_Click(object sender, System.EventArgs e)
{
OnMyEventA();
}
}
}
> Hi Mircea
>
[quoted text clipped - 43 lines]
> >> This posting is provided "AS IS" with no warranties, and confers no
> > rights.
Greg - 15 Jun 2005 18:31 GMT
Hello VR,
I am doing the same thing you are doing.
I am also having the TAB problems. Have you been able to find any solution
to this? My situation is a bit different then yours, but I think it is
related: When I tab through all controls on the unmanaged (MFC) dialog, the
tab seems to 'disapear'. When I hit tab again, then it enters the managed
.net windows forms control... kind of spinning my wheels trying to fix this
now....
> Martin and Mircea,
> I was also trying to host Windows forms control in MFC and VC 6.0. i was
[quoted text clipped - 278 lines]
> protected virtual void OnMyEventB(int a)
> {
VR Ravinuthala - 16 Jun 2005 06:34 GMT
No. I could not figure out why. But i worked around a solution that works for
my situation. Instead of placing multiple COM compliant .NET controls, i had
1 external control and inside that had multiple user controls. That basically
avoided the problem.
> Hello VR,
>
[quoted text clipped - 278 lines]
> > protected virtual void OnMyEventA()
> > {