From: cms0007 on
I have seen a lot of discussion about this topic but not a solution.
If I missed it please let me know.

Essentially my problem is that I have a VB6 client that is dynamically
instantiating OCXs on a Child form inside an MDI object using
VBControlExtender. Here is the code in the child form.

Dim WithEvents cfcurrobj As VBControlExtender

Private Sub cfcurrobj_ObjectEvent(Info As EventInfo)
'Dim objEvent As New testwepmodule.TestWepControl
'objEvent.CompletelySetupControl
MsgBox Info.Name


End Sub

Private Sub Form_Load()
Set cfcurrobj = Me.Controls.Add("TestWepModule.TestModule",
"CFCurrObj")
cfcurrobj.Visible = True
Me.Show
cfcurrobj.object.CompletelySetupControl
Me.SetFocus

End Sub


Inside the OCX there is code that will fire events which calls the
cfcurrobj_ObjectEvent method in the child form.

Maybe something like:
RaiseEvent MainControlEvent

New OCX's are created all the time for the VB6 Client so we do not
early bind them. The VB client is for one quite large so cannot easily
be converted to C# or VB.net and for another cannot be changed since
the code is not ours so we are stuck with the late binding and dynamic
instantiation. All of this works fine if everything is VB6 Client and
OCXs.

But now we want to start coding out servers in C#. We have tested a C#
dll and all works exepts the events. The C# object is registered for
com interop and we can call the methods fine but when events fire the
cfcurrobj_ObjectEvent method does not fire in the VB6 client. Here is
the C# server code I am using. This is probably way off now since I
have been trying a lot of alternatives to find a solution.

using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Text;
using System.Reflection;
using Microsoft.Win32;


namespace testwepmodule
{

public enum MainEvents {done,busy,notbusy,error};

[Guid("397F2AEE-1E73-4f9e-99EB-20703DD65D66")]
public interface WepInterface
{
[DispId(1)]
void CompletelySetupControl();
[DispId(2)]
void MainControlEventFire(MainEvents evt,string strParam,string
objParam3, string objParam4);
[DispId(3)]
void ParentCalling(string strFunctionName, object objParam1, object
objParam2, object objParam3);
}

public delegate void MainControlEventHandler(string strParam1,object
objParam2,object objParam3, object objParam4);

[Guid("A727D071-D7B3-40de-B336-0036CFB170AB"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch )]
public interface IWepEvents
{
[DispId(4)]
event MainControlEventHandler MainControlEvent;
[DispId(5)]
void MainControlEventFire(string strParam1,object objParam2,object
objParam3, object objParam4);
}

[Guid("1E2607D4-F912-4b3d-AD2C-3C4D55D416BD"),
ClassInterface(ClassInterfaceType.AutoDispatch),
ProgId("TestWepModule.TestModule"),
ComSourceInterfaces(typeof(IWepEvents))]
public class TestWepControl :
System.Windows.Forms.UserControl,WepInterface
{
private System.Windows.Forms.Button mbtnEvent;
private System.Windows.Forms.Button mbtnEvent2;

private System.ComponentModel.Container components = null;

public event MainControlEventHandler MainControlEvent;

public TestWepControl()
{
InitializeComponent();
}


public void ParentCalling(string strFunctionName, object objParam1,
object objParam2, object objParam3)
{
MessageBox.Show("Function passed: " + strFunctionName);
}

public void CompletelySetupControl()
{
MessageBox.Show("completelysetupcontrol");
}

[ComVisible(true)]
public void MainControlEventFire(MainEvents evt,string Message,string
strParam3, string strParam4)
{
MessageBox.Show("this is the passed param: " + Message);
object[] objectargs = new object[4];
objectargs[0] = evt.ToString();
objectargs[1] = Message;
objectargs[2] = strParam3;
objectargs[3] = strParam4;

if (MainControlEvent != null)
MainControlEvent(evt.ToString(),Message,strParam3,strParam4);
else
MessageBox.Show("MainControlEvent is null");
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}

#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mbtnEvent = new System.Windows.Forms.Button();
this.mbtnEvent2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// mbtnEvent
//
this.mbtnEvent.Location = new System.Drawing.Point(224, 216);
this.mbtnEvent.Name = "mbtnEvent";
this.mbtnEvent.Size = new System.Drawing.Size(104, 32);
this.mbtnEvent.TabIndex = 0;
this.mbtnEvent.Text = "Call Event";
this.mbtnEvent.Click += new
System.EventHandler(this.mbtnEvent_Click);
//
// mbtnEvent2
//
this.mbtnEvent2.Location = new System.Drawing.Point(360, 216);
this.mbtnEvent2.Name = "mbtnEvent2";
this.mbtnEvent2.Size = new System.Drawing.Size(88, 32);
this.mbtnEvent2.TabIndex = 1;
this.mbtnEvent2.Text = "Another Event";
this.mbtnEvent2.Click += new
System.EventHandler(this.mbtnEvent2_Click);
//
// TestWepControl
//
this.Controls.Add(this.mbtnEvent2);
this.Controls.Add(this.mbtnEvent);
this.Name = "TestWepControl";
this.Size = new System.Drawing.Size(712, 320);
this.Load += new System.EventHandler(this.UserControl1_Load);
this.ResumeLayout(false);

}
#endregion

private void UserControl1_Load(object sender, System.EventArgs e)
{

}

[ComRegisterFunction()]
public static void RegisterClass ( string key )
{
StringBuilder sb = new StringBuilder ( key ) ;
sb.Replace(@"HKEY_CLASSES_ROOT\","") ;

RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);

RegistryKey ctrl = k.CreateSubKey ( "Control" ) ;
ctrl.Close ( ) ;

RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true
) ;
inprocServer32.SetValue ( "CodeBase" ,
Assembly.GetExecutingAssembly().CodeBase ) ;
inprocServer32.Close ( ) ;
k.Close ( ) ;
}

[ComUnregisterFunction()]
public static void UnregisterClass ( string key )
{
StringBuilder sb = new StringBuilder ( key ) ;
sb.Replace(@"HKEY_CLASSES_ROOT\","") ;

RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);

k.DeleteSubKey ( "Control" , false ) ;

RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true
) ;

k.DeleteSubKey ( "CodeBase" , false ) ;

k.Close ( ) ;
}

private void mbtnEvent_Click(object sender, System.EventArgs e)
{
object objParam3 = "nothing";
object objParam4 = "nothing";
MainControlEventFire(MainEvents.busy,"Just Clicked A
button",(string)objParam3, (string)objParam4);
}

private void mbtnEvent2_Click(object sender, System.EventArgs e)
{
object objParam3 = "nothing";
object objParam4 = "nothing";
MainControlEventFire(MainEvents.done,"Finished My
Event",(string)objParam3, (string)objParam4);
}

private void TestWepControl_MainControlEvent(string strParam1, object
objParam2, object objParam3, object objParam4)
{
MessageBox.Show("parameter passed is: " + strParam1);
}
}
}

From: Michael B. Johnson on
On 27 Dec 2005 13:11:27 -0800, cms0007(a)cs.unt.edu wrote:

>I have seen a lot of discussion about this topic but not a solution.
>If I missed it please let me know.
>
>Essentially my problem is that I have a VB6 client that is dynamically
>instantiating OCXs on a Child form inside an MDI object using
>VBControlExtender. Here is the code in the child form.
>
>Dim WithEvents cfcurrobj As VBControlExtender
>
>Private Sub cfcurrobj_ObjectEvent(Info As EventInfo)
> 'Dim objEvent As New testwepmodule.TestWepControl
> 'objEvent.CompletelySetupControl
> MsgBox Info.Name
>
>
>End Sub
>
>Private Sub Form_Load()
> Set cfcurrobj = Me.Controls.Add("TestWepModule.TestModule",
>"CFCurrObj")
> cfcurrobj.Visible = True
> Me.Show
> cfcurrobj.object.CompletelySetupControl
> Me.SetFocus
>
>End Sub
>
>
>Inside the OCX there is code that will fire events which calls the
>cfcurrobj_ObjectEvent method in the child form.
>
>Maybe something like:
>RaiseEvent MainControlEvent
>
>New OCX's are created all the time for the VB6 Client so we do not
>early bind them. The VB client is for one quite large so cannot easily
>be converted to C# or VB.net and for another cannot be changed since
>the code is not ours so we are stuck with the late binding and dynamic
>instantiation. All of this works fine if everything is VB6 Client and
>OCXs.
>
>But now we want to start coding out servers in C#. We have tested a C#
>dll and all works exepts the events. The C# object is registered for
>com interop and we can call the methods fine but when events fire the
>cfcurrobj_ObjectEvent method does not fire in the VB6 client. Here is
>the C# server code I am using. This is probably way off now since I
>have been trying a lot of alternatives to find a solution.

.....And you're using COM interop to communicate between the client and the
server? Have you tried alternative communication mechanisms like mail slots,
message queues, SQL Server tables or TCP/IP winsock, since the C#.NET server
isn't playing nice?

Finally, *IF* none of those are satisfactory or none are possible, what is the
underlying rationale for moving the server to C# if the /client/ isn't going to
move?
_______________________
Michael B. Johnson
From: cms0007 on
First off sorry for posing in this group. I thought I was in the C#
group. But thanks for responding.

Yes it is Com Interop.

All of our other developement is in C#. We code a lot of other types
of projects as well and would like to move as much of our coding under
one language as possible. C# seems to afford us many benefits and
creating C# servers instantiated in a VB6 client seems like it should
be an easy thing to code. This event problem is the only problem I
have come across so far. And I expect someone has done this before.
It is not an unusual thing to want and infact I see from similar posts
many people of tried to find out how to do it before, I just never see
a solution or a difinitive, NO THIS CANNOT BE DONE BECAUSE.... The
other mechanisms you list do not seem to be efficient or ideal for a
online application. As well, it would take a lot of research, which is
what I am doing now to with the C# server idea and would also require
the client to change.