C# control causes VB6 application to crash on exit

A

Asaf

Hi,
We have a VB6 application that needs to use a new control written in
..NET v1.1 C#, imported as a COM control.
We have tried adding the C# control to the VB6 control both dynamically
(using Controls.Add) and using the VB6 designer. In both approaches
the behavior was identical: the control was functional and accessible,
but the application crashed on exit with the message <app name> "has
encountered a problem and needs to close. We are sorry for the
inconvenience." etc.

I have searched the web, with no luck. Any ideas will be greatly
appreciated. The C# code is embedded below.

Thanks
Asaf.


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 MyCtrlLib
{
///
/// Summary description for UserControl1.
///
[ GuidAttribute("F321BAC9-5019-4c6f-BADF-8D104A499870") ]
[InterfaceTypeAttribute(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);

[GuidAttribute("03018F99-263B-417e-94F3-F367471F6679"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICSharpCOMEvents
{
[DispId(1)]void EventA();
[DispId(2)]void EventB(int a);
}

[GuidAttribute("E022271B-63C8-4878-8C9E-712E776C4785")]
[ProgIdAttribute("MyCtrlLib.CSharpUserControl")]
//[ComSourceInterfacesAttribute(typeof (ICSharpCOMEvents))]
[ComSourceInterfacesAttribute(typeof(MyCtrlLib.ICSharpCOMEvents))]
[ClassInterfaceAttribute(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 )
{
MessageBox.Show("Dispose");
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 void OnMyEventA()
{
if (EventA != null)
{
this.textBox1.Text = "Event fired!";
EventA();
}
}

protected 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();
}
}


}
 
M

Mark Yudkin

Seems to me that you'd be better off on a C# forum, as the problems seems to
be related to your control rather than to VB6.

BTW I'd be suspicious of any attempt to do manual disposing...

Asaf said:
Hi,
We have a VB6 application that needs to use a new control written in
.NET v1.1 C#, imported as a COM control.
We have tried adding the C# control to the VB6 control both dynamically
(using Controls.Add) and using the VB6 designer. In both approaches
the behavior was identical: the control was functional and accessible,
but the application crashed on exit with the message <app name> "has
encountered a problem and needs to close. We are sorry for the
inconvenience." etc.

I have searched the web, with no luck. Any ideas will be greatly
appreciated. The C# code is embedded below.

Thanks
Asaf.


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 MyCtrlLib
{
///
/// Summary description for UserControl1.
///
[ GuidAttribute("F321BAC9-5019-4c6f-BADF-8D104A499870") ]
[InterfaceTypeAttribute(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);

[GuidAttribute("03018F99-263B-417e-94F3-F367471F6679"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICSharpCOMEvents
{
[DispId(1)]void EventA();
[DispId(2)]void EventB(int a);
}

[GuidAttribute("E022271B-63C8-4878-8C9E-712E776C4785")]
[ProgIdAttribute("MyCtrlLib.CSharpUserControl")]
//[ComSourceInterfacesAttribute(typeof (ICSharpCOMEvents))]
[ComSourceInterfacesAttribute(typeof(MyCtrlLib.ICSharpCOMEvents))]
[ClassInterfaceAttribute(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 )
{
MessageBox.Show("Dispose");
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 void OnMyEventA()
{
if (EventA != null)
{
this.textBox1.Text = "Event fired!";
EventA();
}
}

protected 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();
}
}


}
 
N

Nicholas Paldino [.NET/C# MVP]

Asaf,

Unfortunately, ActiveX controls are not able to be exported from .NET to
automation-compatable clients.

There is an unsupported hack to do this, but I wouldn't recommend it,
since it is not supported in the least.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Asaf said:
Hi,
We have a VB6 application that needs to use a new control written in
.NET v1.1 C#, imported as a COM control.
We have tried adding the C# control to the VB6 control both dynamically
(using Controls.Add) and using the VB6 designer. In both approaches
the behavior was identical: the control was functional and accessible,
but the application crashed on exit with the message <app name> "has
encountered a problem and needs to close. We are sorry for the
inconvenience." etc.

I have searched the web, with no luck. Any ideas will be greatly
appreciated. The C# code is embedded below.

Thanks
Asaf.


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 MyCtrlLib
{
///
/// Summary description for UserControl1.
///
[ GuidAttribute("F321BAC9-5019-4c6f-BADF-8D104A499870") ]
[InterfaceTypeAttribute(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);

[GuidAttribute("03018F99-263B-417e-94F3-F367471F6679"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICSharpCOMEvents
{
[DispId(1)]void EventA();
[DispId(2)]void EventB(int a);
}

[GuidAttribute("E022271B-63C8-4878-8C9E-712E776C4785")]
[ProgIdAttribute("MyCtrlLib.CSharpUserControl")]
//[ComSourceInterfacesAttribute(typeof (ICSharpCOMEvents))]
[ComSourceInterfacesAttribute(typeof(MyCtrlLib.ICSharpCOMEvents))]
[ClassInterfaceAttribute(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 )
{
MessageBox.Show("Dispose");
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 void OnMyEventA()
{
if (EventA != null)
{
this.textBox1.Text = "Event fired!";
EventA();
}
}

protected 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();
}
}


}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top