RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

[Shy request] Class name

Arya

Wanderer
[Shy request] Class name

I know this isn't a request forum, but I have received feedback from users who would like to use Pandora's Box with the Krrios Client. Do you think you could register a class name for it in a future release (last I checked it uses a standard windows form class name which changes with each instance). If not possible, I'll resort to enumerating processes but it's laggy when executed the first time and FindWindow is more efficient anyway.

Thank you for considering!
 

krrios

Administrator
This is something that I would love to do. Whenever I've tried, however, I was just unable to do it. Performing the logical override of CreateParams always seemed to crash.

If you've experience in this area and could provide some tips then I'll give it another shot.
 

Arya

Wanderer
I honestly don't have much experience in dealing with the windows API but I know a person who might have a better clue, so I'll do some research and get back to you if I find anything useful.
 

Ceday

Page
i am not really familiar with Win API's but this is my guess:
Probably, its not enough to override CreateParams if you want to change ClassName since it has to be registered. However, the other properties should work.

Have you tried RegisterClass/Ex and UnregisterClass API's?
 

Arya

Wanderer
I've been playing around with RegisterClass for the last few days. You indeed have to register your window before setting the name in the CreateParams. My problem is that I can succesfully register the class using RegisterClass (function returns an atom > 0) but I can't retrieve it through GetClassInfo (which I guess is what's causing the Invalid Class Name Win32Exception in .NET code). When I get back home I'll post my code so maybe someone more experienced will be able to point out whatever I'm doing wrong.
 

Arya

Wanderer
Here's what I'm using to test this out:

Code:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace RegisterClassName
{
	public class Form1 : System.Windows.Forms.Form
	{
		[ DllImport("kernel32") ]
		private static extern IntPtr GetModuleHandle(string modName);

		[ DllImport( "user32.dll" ) ]
		private static unsafe extern int RegisterClass( WNDCLASS wnd );

		[ DllImport( "gdi32.dll" ) ]
		private static extern IntPtr GetStockObject( int fnObject );

		[DllImport( "User32" )]
		private static extern IntPtr FindWindow(string lpszClassName, string lpszWindowName);

		[ StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
		public class WNDCLASS
		{
			public int style;

			[ MarshalAs( UnmanagedType.FunctionPtr ) ]
			public WndProcDelegate lpfnWndProc;

			public int cbClsExtra;
			public int cbWndExtra;

			public IntPtr hInstance;
			public IntPtr hIcon;
			public IntPtr hCursor;
			public IntPtr hbrBackground;

			public string lpszMenuName;
			public string lpszClassName;
		}

		public delegate IntPtr WndProcDelegate( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
		private WndProcDelegate m_Delegate;
		private WNDCLASS wndclass;

		private void Register()
		{
			wndclass = new WNDCLASS();

			wndclass.style = CreateParams.ClassStyle;

			// Window procedure
			m_Delegate = new WndProcDelegate( MyWndProc );
			wndclass.lpfnWndProc = m_Delegate;

			wndclass.cbClsExtra = 0;
			wndclass.cbWndExtra = 0;

			// This gets the hInstance for the module being executed
			wndclass.hInstance = GetModuleHandle( null );

			wndclass.hIcon = this.Icon.Handle;
			wndclass.hCursor = this.Cursor.Handle;

			// This gets a gray brush
			wndclass.hbrBackground = GetStockObject( 2 );

			wndclass.lpszMenuName = null;
			wndclass.lpszClassName = "My Test Window";

			// Atom is 0 if registration fails
			int atom = RegisterClass( wndclass );

			MessageBox.Show( atom.ToString() );
		}

		private IntPtr MyWndProc( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam )
		{
			Message m = Message.Create( hwnd, msg, wParam, lParam );
			
			WndProc( ref m );

			return m.Result;
		}

		private System.Windows.Forms.Button button1;
		private System.ComponentModel.Container components = null;

		public Form1()
		{
			InitializeComponent();

			Register();
			this.CreateParams.ClassName = "My Test Window";
		}

		/// <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 Windows Form 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.button1 = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// button1
			// 
			this.button1.Location = new System.Drawing.Point(48, 16);
			this.button1.Name = "button1";
			this.button1.Size = new System.Drawing.Size(96, 23);
			this.button1.TabIndex = 0;
			this.button1.Text = "Find Window";
			this.button1.Click += new System.EventHandler(this.button1_Click);
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(192, 54);
			this.Controls.Add(this.button1);
			this.Name = "Form1";
			this.Text = "Form1";
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new Form1());
		}

		private void button1_Click(object sender, System.EventArgs e)
		{
			IntPtr ptr = FindWindow( "My Test Window", null );
			MessageBox.Show( ptr.ToInt32().ToString() );
		}
	}
}

I can confirm that even if the registration seems succesful, GetClassInfo doesn't seem to be able to retrieve the WNDCLASS object for the registered class. If you try to use "BUTTON" as class name, for instance, the process will go on properly and the class name of the form will be WindowsForms10.Button.app3 (apparently the framework adds the winforms version and the app3 bit to the actual class name and performs yet another registration).

I'm pretty much stuck here, the marshalling seems correct and the window procedure should correctly use the form's WndProc(), still it doesn't work :confused:
 
Top