Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / June 2005

Tip: Looking for answers? Try searching our database.

.NET control exposed as ActiveX

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Mircea Pleteriu - 27 Apr 2005 07:42 GMT
Hi,

This is what I want to do:

I want to develop a .NET Windows Control, expose the control as an ActiveX
and host the control from a VB6 form.
The control has to expose a MyEvent event.
It should be possible the VB6 form to register the interest in the MyEvent
event.

This is what my poroblem is:

I've implemented the .NET control, exposed it as an ActiveX and hosted by
the VB6 form and registered the interest in MyEvent event.
The problem is that event is never fired.

I've tried to host the control by a VC++6 form. The event is visible in the
list of events, the handler is created but the event is never fired too.

Does anybody can help me? (I know there is no 100% backword compatibility
for hosting a .NET control from a VB container as I found on the internet)
"Peter Huang" [MSFT] - 27 Apr 2005 09:28 GMT
Hi Mircea,

Unfortunately, so far we did not support place .NET control on the VB6
Form, we only support host .NET control in IE.
Here is a KB link for your reference.
ActiveX control containers that support .NET controls (311334)
http://support.microsoft.com/default.aspx?scid=KB;EN-US;311334

If you do want to do that, I think you may need to host a webbrowser
control in your vb6 form and then host the .NET control in WebBrowser.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security 
This posting is provided "AS IS" with no warranties, and confers no rights.
Mircea Pleteriu - 27 Apr 2005 09:42 GMT
Thank you Peter.

> Hi Mircea,
>
[quoted text clipped - 14 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "AS IS" with no warranties, and confers no rights.
Martin Bühlmann - 27 Apr 2005 09:57 GMT
Hi Mircea

I did that some weeks ago. I tried several ways to implement an ActiveX,
hosting a .NET control.

1. Writing an ActiveX using C#
->Got the same problem as you described in your first message. No event ever
reached the client.

2. Write an ATL-Container, hosting the .NET control
->Worked with VB6, but frozed my MFC application when I clicked on the
control.

3. Write a MFC-ActiveX, wrapping the .NET control
->It is a bit tricky but the control works now in VB6 and MFC-based
applications.

I based my MFC-ActiveX on a sample found at:
http://msdn.microsoft.com/msdnmag/issues/03/03/WindowsForms/default.aspx

If you need some help, feel free to email me (remove the .nospan from my
email-address).

Regards,
Martin

> Thank you Peter.
>
[quoted text clipped - 17 lines]
>> This posting is provided "AS IS" with no warranties, and confers no
> rights.
VR Ravinuthala - 27 Apr 2005 23:01 GMT
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()
> >         {

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.