Message box breaks owner draw controls in .NET controls used as ActiveX controls (again)

C

Clive Dixon

Further to my previous posting on this, here is a very simple way of
reproducing the problem. Has anyone else come across this and found a
workaround (other than either saying "don't create the owner draw control in
InitializeComponent" or creating the parent before the control)?

Create a windows control library project.

Add an owner draw combo (or other owner draw control) and a button to the
user control.

Add a derived control class to handle the owner draw, modify the IDE
generated code to use this class.

Explicitly create the owner draw combo in InitializeComponent using
CreateControl. (This causes the control to be created with a parent window
of class System.Windows.Forms.Application.ParkingWindow. Even after the
parent control has been created and the owner draw control's parent is
correctly reassigned, owner draw messages continue to be routed through
System.Windows.Forms.Application.ParkingWindow.WndProc.)

Add button click handler that shows a message box.

Add COM attributes to user control class.

Add ComRegister function to register component as ActiveX control.

Set project to register for interop.

Compile.

Add control to tstcon32.exe (or add to MFC app dialog).

Press button on user control to show message box.

Owner draw control is now broken. (MessageBox has destroyed the instance of
System.Windows.Forms.Application.ParkingWindow.)



The owner draw message routing through
System.Windows.Forms.Application.ParkingWindow.WndProc occurs whenever an
owner draw control is created before its parent window.

The message routing only breaks if the control is in a component enabled for
use and used as an ActiveX control.



Here is the C# code to reproduce this:

using System;

using System.Collections;

using System.ComponentModel;

using System.Drawing;

using System.Data;

using System.Runtime.InteropServices;

using System.Windows.Forms;

using Microsoft.Win32;

namespace WindowsControlLibrary2

{

public class OwnerDrawCombo : System.Windows.Forms.ComboBox

{

protected override void OnDrawItem(DrawItemEventArgs e)

{

e.DrawBackground();

if ( e.Index >= 0 && e.Index < this.Items.Count )

{

e.Graphics.DrawString(this.Items[e.Index].ToString(),

e.Font,Brushes.Black,

e.Bounds.Left,e.Bounds.Top);

}

e.DrawFocusRectangle();

}

}

[Guid("BDD17877-B805-4970-B3BB-2F1A2C1E5A38")]

[ProgId("WindowsControlLibrary2.UserControl1")]

[ClassInterface(ClassInterfaceType.AutoDual)]

public class UserControl1 : System.Windows.Forms.UserControl

{

private OwnerDrawCombo comboBox1;

private System.Windows.Forms.Button button1;

private System.ComponentModel.Container components = null;

[ComRegisterFunction]

static void ComRegister(Type t)

{

string keyName = @"CLSID\" + t.GUID.ToString("B");

using (RegistryKey key =
Registry.ClassesRoot.OpenSubKey(keyName,true) )

{

key.CreateSubKey("Control").Close();

}

}

[ComUnregisterFunction]

static void ComUnregister(Type t)

{

string keyName = @"CLSID\" + t.GUID.ToString("B");

Registry.ClassesRoot.DeleteSubKeyTree(keyName);

}

public UserControl1()

{

InitializeComponent();

}

protected override void Dispose( bool disposing )

{

if( disposing )

{

if( components != null )

components.Dispose();

}

base.Dispose( disposing );

}

#region Component Designer generated code

private void InitializeComponent()

{

this.comboBox1 = new OwnerDrawCombo();

this.button1 = new System.Windows.Forms.Button();

this.SuspendLayout();

this.comboBox1.DrawMode =
System.Windows.Forms.DrawMode.OwnerDrawFixed;

this.comboBox1.DropDownStyle =
System.Windows.Forms.ComboBoxStyle.DropDownList;

this.comboBox1.Items.AddRange(new object[] {

"Owner Draw Combo",

"One",

"Two",

"Three"});

this.comboBox1.Location = new System.Drawing.Point(16, 32);

this.comboBox1.Name = "comboBox1";

this.comboBox1.Size = new System.Drawing.Size(121, 21);

this.comboBox1.TabIndex = 0;

this.comboBox1.SelectedIndex = 0;

// Creating the control here causes the combo box

// draw item messaging to go through the parking window,

// and a message box invocation will break the combo.

this.comboBox1.CreateControl();

this.button1.Location = new System.Drawing.Point(32, 80);

this.button1.Name = "button1";

this.button1.TabIndex = 1;

this.button1.Text = "Click Me!";

this.button1.Click += new EventHandler(button1_Click);

this.Controls.Add(this.button1);

this.Controls.Add(this.comboBox1);

this.Name = "UserControl1";

this.ResumeLayout(false);

}

#endregion

void button1_Click(object sender, System.EventArgs e)

{

MessageBox.Show("The owner draw combo box is now broken!\n" +

"Click on the drop down to see.");

}

}

}
 

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