Raising events from .NET UserControl inside a VB6 MDI form(Interop Forms Toolkit)

Locked Raising events from .NET UserControl inside a VB6 MDI form(Interop Forms Toolkit)

  • quarta-feira, 3 de janeiro de 2007 09:24
     
     

    I have used the Interop Forms Toolkit example: http://blogs.msdn.com/vbteam/archive/2006/11/02/interop-roadmap-usercontrols-mdi-and-data.aspx, and am using the example InteropUserControl.

    I want to raise an event from my .NET UserControl which is hosted inside a VB6 VBControlExtender type:

    Private WithEvents moDynamic        As VBControlExtender

    Set moDynamic = Controls.Add("InteropUserControl.InteropUserControl", "DynamicControl")

    The control loads fine.

    How do I raise an event from the .NET UserControl so it is trapped by the VBControlExtender?

     

     


     


Todas as Respostas

  • quinta-feira, 4 de janeiro de 2007 01:38
    Moderador
     
     Respondido

    You'll need to handle the events using the same method you would for non-dynamic controls.

    1. Add a reference to the TLB (not in the toolbox, but by clicking Project->References)

    2. Use the following code:

    Dim WithEvents myCtl As VBControlExtender
    Dim WithEvents ctlEvents As CtlExtenderTest.InteropUserControl

    Private Sub ctlEvents_Click()
        MsgBox "Click event fired"
    End Sub

    Private Sub Form_Load()
        Set myCtl = Controls.Add("CtlExtenderTest.InteropUserControl", "NameOfNewControl")
        Set ctlEvents = myCtl.object
        myCtl.Visible = True
    End Sub

    Hope that helps,

    Jonathan

  • quarta-feira, 21 de fevereiro de 2007 17:44
     
     

    Hi,

    I have similar problem as David,

     

    is it possible to catch .NET UserControl events by VBControlExtender global event handler?

    Like:

    Private Sub mExtender_ObjectEvent(info As EventInfo)
        On Error GoTo ErrHandler
        
        msgbox "Event catched: " & info.Name
     
    ExitPoint:
        Exit Sub
       
    ErrHandler:
        MsgBox Err.Description, vbCritical, "mExtender_ObjectEvent"
        Resume ExitPoint
    End Sub

     

    Thanks for any hint.

  • terça-feira, 27 de fevereiro de 2007 05:44
    Moderador
     
     Respondido

    Unfortunately you won't be able to use ObjectEvent to catch these events centrally for the time being.  This wasn't a supported scenario when .NET 2.0 shipped, but we're adding this functionality in the next version.  This code will work for you if you have framework 3.5 installed (even if you're targetting the 2.0 framework, since the 3.5 framework will patch the assembly).

    If you really want a central way of handling the events I'd suggest handling the events on ctlEvents (in my code example above) and then for each instance call a procedure that has the central event handling code.

    Hope that helps,

    Jonathan

  • terça-feira, 27 de fevereiro de 2007 13:06
     
     

    Hi,

    It's good to see that MS team is working on this, because I was realy missing this, while using System.Runtime.Interop. So thanks for your reply.

    I done it by this way if it will help someone else: In .NET I created a interface with Register() method (ISender) and code that creates InteropOCX is calling this Register() method so .NET after knowes the caller. Caller of Register() method is implementing IListener interface.

    After if .NET OCX wants to raise event it will call caller.ExtendedEventHandler(ExtenderEventInfo info) with event params. So after we are in VB6 with extended EventInfo object, which we can pass to extender_ObjectEvent(byval info as EventInfo).

    I have to say also that you should implement ExtendedEventInfo in VB6 and add reference to generated dll in VS.NET from COM tab. Because if you will try to implement it in .NET and extend VBRUN.EventInfo and other interfaces. You will fail will Type Missmatch error on VB6 side.

     

    So it after behaves as event raised from .NET and catched in VB6 global event handler.

    Hope that helps someone and spend less time then me on this problem.

    Michal

  • quinta-feira, 25 de outubro de 2007 01:30
     
     

    I have just tried the following code using Dev Studio 2008 Beta 2 (With build target set to .Net Framework 3.5) and my event was not captured in the VBControlExtender.ObjectEvent event. In fact, as far as .NET is concerned when using my test control under VB, the Save delegate is null indicating that nothing is "listening" to this event. However, interestingly, when run under the Active X Control Test Container (TstCon32.exe, Visual Studio 6.0), something is listening, but an exception is thrown (show below).

     

    Ok, here's my test code:

     

    namespace VBActiveXTest

    {

      [Guid("C2361FB8-D0C4-4d2d-B782-028C45AA5DAD")]

      [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

      public interface IFinshAction

      {

        void Save(FinishAction fa);

      }

     

      public delegate void delSave(FinishAction fa);

     

      [Guid("766DAE80-E94A-4000-AAF2-83110E015BEB")]

      [ComSourceInterfaces(typeof(IFinshAction))]

      [ClassInterface(ClassInterfaceType.AutoDual)]

      // you need to select ".NET Category" under "Insert Control"->"Implemented Categories"

      // to see this prog ID in TSTCON32.EXE

      [ProgId("VBTest.BasicUI")]

      public partial class BasicUI : UserControl, MyOwnSomeOtherInterface

      {

        public event delSave Save;

        public BasicUI()

        {

          InitializeComponent();

        }

     

        #region MyOwnSomeOtherInterface Members

        // Implementation of MyOwnSomeOtherInterface Removed!!

     

        private void btnCancel_Click(object sender, EventArgs e)

        {

          // FinishAction is an enumration defined in some IDL I have.

          // Its definition should be irrelevent to this test and can be

          // changed to int for testing

          FinishAction myAction = FinishAction.faCancel;

          if (Save != null)

          {

            Save(myAction);

          }

          else

          {

            // If created and used within VBControlExtender we get here!!!!

            MessageBox.Show("No Event Sink!");

          }

        }

      }

    }

     

     

    TSTCON32.EXE reports the following .NET exception when the bnCancel_Click method in invoked.

     

    just-in-time (JIT) debugging instead of this dialog box.

    ************** Exception Text **************
    System.NotImplementedException: The method or operation is not implemented.
       at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
       at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
       at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
       at FMUITest3.IFinshAction.Save(FinishAction fa)
       at FMUITest3.BasicUI.btnCancel_Click(Object sender, EventArgs e) in C:\Documents and Settings\khazeldi\My Documents\Visual Studio 2008\Projects\FMUITest3\FMUITest3\BasicUI.cs:line 63
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

     

    ************** Loaded Assemblies **************
    mscorlib
        Assembly Version: 2.0.0.0
        Win32 Version: 2.0.50727.1378 (REDBITSB2.050727-1300)
        CodeBase:
    file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll

     

     

    Also...

     

    After shutting down TXTCON32.EXE with File->Exit. TSTCON32.EXE it is still visible in the Task Manager. This seems to happen only if it created a .NET "Active X Control" at sometime during its existence. 

     

    Conclusion.

     

    Either I am doing something wrong here or the code you allude to being in place in Framwork 3.5 (and patched 2.0) isn't yet in in place.

     

    If anyone else has any similar experience or has managed to get more success than I, I'd like to hear from you.

     

  • quinta-feira, 25 de outubro de 2007 19:17
    Moderador
     
     Respondido

    Hi Kevin,

     

    I just tested this out quickly in VB and everything works fine, here's what I did:

     

    1. New Interop UserControl, add a button called btnCancel and the following code at the bottom of the class:

     

    <ComClass(BasicUI.ClassId, BasicUI.InterfaceId, BasicUI.EventsId)> _

    Public Class BasicUI

     

    ...

     

    'Please enter any new code here, below the Interop code

    Public Delegate Sub delSave(ByVal fa As Integer)

    Public Event Save As delSave

     

    Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnCancel.Click

        RaiseEvent Save(1)

    End Sub

     

    End Class

     

    2. Open VB6 and add the following code:

    Dim WithEvents myCtl As VBControlExtender

     

    Private Sub Form_Load()
        Set myCtl = Controls.Add("VB6ActiveXTest.BasicUI", "NameOfNewControl")
        myCtl.Visible = True
    End Sub

     

    Private Sub myCtl_ObjectEvent(Info As EventInfo)
        MsgBox Info.Name & " - " & Info.EventParameters(0)
    End Sub

     

    The event fires and everything works fine.  Try changing your C# code to use ClassInterfaceType.None instead of AutoDual.  Other than that your code looks fine...if it's still not working try out the VB example above and open it in Reflector.  The VB compiler supports ComClass (C# doesn't) and so it takes care of a lot of this stuff for you automatically.  For more information check out http://blogs.msdn.com/vbteam/archive/2007/06/01/so-what-does-lt-comclass-gt-actually-do.aspx.

     

    Hope that helps,

     

    Jonathan

  • sexta-feira, 26 de outubro de 2007 04:30
     
     

    It did help - a lot. I tried using ClassInterfaceType.None in C# to no avail. However, redoing the whole project using the Interop UserControl Template (a downloadable add-in, I discovered) with VB.NET (3.5, in Dev Studio 2008) it worked. Top banana. Given some more time I might have another go at getting the C# version to work.

     

    Kevin.

     

  • quarta-feira, 23 de janeiro de 2008 21:19
     
     
    I've had this working for quite some time in C#, however, recently one of my PV guys' machines started encoutering this exception every time an interop event occurs. Since only one machine exhibits this behaviour and (most thankfully) it has never happened on site to any of our clients, I must conclude that I'm missing something........ No one knows what changed on that machine.

    On a lighter note, I'd like to say how pleased I am that I can create .NET ActiveX controls, wrap them in an ocx, and painlessly replace our old vb ocx.
  • terça-feira, 4 de maio de 2010 21:19
     
     Resposta Proposta

    Getting the events raised proved to be complicated in VB.Net, but this allows your assembly object to be declared WithEvents inside the VB6 project:

    <ComClass(ctrlTriSysV9_04.ClassId, ctrlTriSysV9_04.InterfaceId, ctrlTriSysV9_04.EventsId)> _

    Public

     

    Class ctrlTriSysV9_04

     

    Public Const ClassId As String = "aaaaaaaa-dd4f-424b-1234-ce0753900fd1"

     

    Public Const InterfaceId As String = "bbbbbbbb-aa6d-44c5-5678-fe82bedd30e6"

     

    Public Const EventsId As String = "cccccccc-bb33-4c49-9012-c173f09485e6"

    Obviously replace the above with your own GUID's

  • terça-feira, 21 de fevereiro de 2012 06:15
     
      Contém Código


    I had the exact problem is that you are missing the despatch ID the interface should be as follows:

      [Guid("C2361FB8-D0C4-4d2d-B782-028C45AA5DAD")]
      [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
      public interface IFinshAction
      {
    	[DispId(1)]
    	void Save(FinishAction fa);
      }