Studying WinForm is one of my personal interests and hobbies, previously done projects, more related to WinForm, however, in the past few years, the project has nothing to do with WinForm, have been converted to ASP. NET MVC and WPF. The question discussed today has been studied in depth, but recently a friend asked this question, and then dug the grave (pit).
First, what is the class name?
Open artifact spy++,vs2013 in the Tools menu:
Before VS2013 vs version, in the "Start Menu":
Open Spy + +, click on the labeled button,
In the open window, drag the Radar button to the window you want to view, you can see its class name, the following is the name of the QQ class:
Then look at the form class name of. NET WinForm:
A bunch of ah, there is no, I do not want this, I want a personality, simple class name, how to do?
Is there a createparams attribute?
As a program ape with years of experience in WinForm development, what's so hard about this is that WinForm controls have a CreateParams attribute? Is it possible to set the window class name inside? Look:
Really, this is not simple, hands, so there is the following code:
public partial class Formmain:form {public formmain () { InitializeComponent (); } protected override CreateParams CreateParams { get { createparams createparams = base. CreateParams; Createparams.classname = "Starts2000.window"; This is the name of the form Class I want. return createparams;}} }
Compile, run, and the result is this:
Peat Ah, this is what ah, turn ~ Wall, a pass Google, the original class name used before all need to register Ah, Microsoft only registered its own class name, I personalized he will not help me to register, then I will register it, Hang Dad's Microsoft AH.
Three, register a window class name bar
Windows API functions are required for registering window class names, P/invoke in C #? Too much trouble, do so many years of WinForm development, I practiced the " Sunflower Treasure (c + +/CLI)", just because no self-palace, so no big, but simple use or can.
Create a C + + Empty Project, set the project properties-Configuration Properties-general, such as:
The following code is then available:
1. FormEx.h
#pragma once#include <Windows.h> #include <vcclr.h> #define Custom_class_name L "Starts2000.window" Namespace Starts2000{namespace windowsclassname{namespace core{using namespace system;using namespace System::Windows :: Forms;using namespace System::runtime::interopservices;private delegate LRESULT WndProc (HWND hwnd, UINT MSG, WPARAM WParam, LPARAM LPARAM);p ublic ref class Formex:p ublic form{public:static Formex (); Formex ();p rivate:static LRESULT WndProc (HWND hwnd, UINT MSG, WPARAM WPARAM, LPARAM LPARAM), static void ProcessExit (Object ^ sender, eventargs^ e);};}}
2. FormEx.cpp
#include "FormEx.h" namespace Starts2000{namespace windowsclassname{namespace core{static Formex::formex () { Wndclassex WC; Starts2000::windowsclassname::core::wndproc ^windowproc =gcnew Starts2000::windowsclassname::core::wndproc (FormEx :: WndProc);p in_ptr<starts2000::windowsclassname::core::wndproc^> pwindowproc = &windowProc; ZeroMemory (&WC, sizeof (wndclassex)); wc.cbsize = sizeof (wndclassex); wc.style = Cs_dblclks;wc.lpfnwndproc = Reinterpret_cast<wndproc> (Marshal::getfunctionpointerfordelegate (WindowProc). ToPointer ()); wc.hinstance = GetModuleHandle (null); wc.hcursor = LoadCursor (null, idc_arrow); wc.hbrbackground = (hbrush ) Color_window; (Hbrush) Getstockobject (hollow_brush); wc.lpszclassname = Custom_class_name; ATOM Classatom = RegisterClassEx (&WC);D Word LastError = GetLastError (); if (Classatom = = 0 && lasterror! = Erro r_class_already_exists) {throw gcnew applicationexception ("Register window CLASS failed!");} System::appdomain::currentdomain->processexit + =Gcnew System::EventHandler (Formex::P rocessexit);} Formex::formex (): Form () {}lresult Formex::wndproc (HWND hwnd, UINT MSG, WPARAM WPARAM, LPARAM LPARAM) {system::windows:: Forms::message Message = System::windows::forms::message::create ((IntPtr) hWnd, (int) msg, (INTPTR) ((void*) wParam), ( INTPTR) ((void*) lParam)); System::D iagnostics::D ebug::writeline (message. ToString ()); return DefWindowProc (HWnd, MSG, WParam, LParam);} void Formex::P rocessexit (object^ sender, eventargs^ e) {unregisterclass (Custom_class_name, GetModuleHandle (NULL));}}}
3. Create a C # WinForm project that references the DLL generated by the C + +/CLI project you created above, the code is not very different from the beginning.
public partial class FormMain:/*form*/Formex {public formmain () { InitializeComponent (); } protected override CreateParams CreateParams { get { createparams createparams = base. CreateParams; Createparams.classname = "Starts2000.window"; This is the name of the form Class I want. return createparams;}} }
Compile, run, and the results are still the same:
Peat, what the hell is Microsoft doing, I just want to get some gadgets, to meet my vanity, you unexpectedly ..., the heart tens of thousands of "alpaca" Pentium.
No way, Microsoft is not all open source, do not need to decompile, directly under the source code to see it.
Four, also do not decompile, directly find the source code to see it
On Microsoft's website (http://referencesource.microsoft.com/) down code, from Form→containercontrol→scrollablecontrol→control, In the control found NativeWindow, and then found in NativeWindow inside Windowclass, in Windowclass found the pit Dad registerclass method, suddenly, there is no, specific look at the code, I added a note.
private void RegisterClass () {nativemethods.wndclass_d wndclass = new Nativemethods.wndclass_d (); if (Userdefwindowproc = = IntPtr.Zero) {string Defproc = (Marshal.systemdefaultcharsize = = 1?) "Defwindowproca": "DEFWINDOWPROCW"); Userdefwindowproc = unsafenativemethods.getprocaddress (new HandleRef (NULL, Unsafenativemethods.getmodulehandle (" User32.dll ")), Defproc); if (Userdefwindowproc = = IntPtr.Zero) {throw new win32exception (); }} string localclassname = ClassName; if (Localclassname = = null) {//See if the custom Classnname is the value we set in CreateParams classname. If we don ' t use a hollow brush here, Windows would "pre paint" us with color_window which//creates a little bit If flicker. This happens even though we is overriding wm_erasebackgnd. Make this hollow to avoid all flicker. Wndclass.hbrbackground = Unsafenativemethods.getstockobject (Nativemethods.hollow_brush); (INTPTR) (NATIVEMETHODS.COlor_window + 1); Wndclass.style = Classstyle; DefWindowProc = Userdefwindowproc; localclassname = "window." + convert.tostring (Classstyle, 16); hashcode = 0; } else {//pit Daddy's right here. Nativemethods.wndclass_i Wcls = new Nativemethods.wndclass_i (); /* Note the following code, pay special attention to NATIVEMETHODS.NULLHANDLEREF,MSDN Description: * BOOL WINAPI getclassinfo (* _in_opt_ Hinsta NCE hinstance, * _in_ lpctstr lpclassname, * _out_ lpwndclass Lpwndclass * ); * HInstance [in, Optional] * type:hinstance * A handle to the instance of the application that CR Eated the class. * To retrieve information on classes defined by the system (such as buttons or list boxes), * set this param Eter to NULL. * That is, when the first parameter of GetClassInfo is NULL (nativemethods.nullhandleref), only the system registered ClassName * will return True, so when we set the Createpar AMS classname value, as long as the set is not the systemThe ClassName of the system register, will * throw behind the win32exception exception, peat ah. */bool OK = Unsafenativemethods.getclassinfo (Nativemethods.nullhandleref, ClassName, WCLS); int error = Marshal.GetLastWin32Error (); if (!ok) {throw new Win32Exception (Error, SR. GetString (SR. Invalidwndclsname)); } Wndclass.style = Wcls.style; Wndclass.cbclsextra = Wcls.cbclsextra; Wndclass.cbwndextra = Wcls.cbwndextra; Wndclass.hicon = Wcls.hicon; Wndclass.hcursor = Wcls.hcursor; Wndclass.hbrbackground = Wcls.hbrbackground; Wndclass.lpszmenuname = Marshal.ptrtostringauto (wcls.lpszmenuname); Localclassname = ClassName; DefWindowProc = Wcls.lpfnwndproc; Hashcode = Classname.gethashcode (); }//Our static data are different for different app domains, so we include the app domain in with//our window Clas s name. This is the static table always matches what Win32 thinks. Windowclassname = getfulLclassname (Localclassname); WindowProc = new Nativemethods.wndproc (this. Callback); Wndclass.lpfnwndproc = WindowProc; Wndclass.hinstance = Unsafenativemethods.getmodulehandle (null); Wndclass.lpszclassname = Windowclassname; Short atom = Unsafenativemethods.registerclass (WNDCLASS); if (atom = = 0) {int err = Marshal.GetLastWin32Error (); if (err = = nativemethods.error_class_already_exists) {//Check to see if the Window CLASS window// Proc points to Defwndproc. If it does, then//The is a class from a rudely-terminated app domain//And we can safely reuse I T. If not, we ' ve got//to throw. Nativemethods.wndclass_i wcls = new Nativemethods.wndclass_i (); bool OK = unsafenativemethods.getclassinfo (new HandleRef (NULL, unsafenativemethods.getmodulehandle (NULL)), Windowclassname, WCLS); if (ok && wcls.lpfnwndproc = = Nativewindow.userdefindowproc) { We can just reuse this class because we had marked it//as being a NOP in another domain. All we need to do are call Setclasslong. Only one problem:setclasslong takes a HWND, which we don ' t have. That's leaves//us with some tricky business. First, try the "easy" and see/if we can simply unregister and re-register the class. This might//work because the other domain shutdown would has posted wm_close to all//th E windows of the class. if (Unsafenativemethods.unregisterclass (Windowclassname, new HandleRef (NULL, Unsafenativemethods.getmodulehandle ( NULL))) {atom = Unsafenativemethods.registerclass (WNDCLASS); If This fails, we'll always raise the first err above. No sense exposing our twiddling. } else {//This is a little harder. We cannot reuse the class BecausE It's//already in use. We must create a new class. We bump our domain qualifier//Here's account for this, so we have only does this expensive search once for The//domain. do {domainqualifier++; Windowclassname = Getfullclassname (localclassname); Wndclass.lpszclassname = Windowclassname; Atom = Unsafenativemethods.registerclass (WNDCLASS); } while (atom = = 0 && marshal.getlastwin32error () = = nativemethods.error_class_already_exists); }}} if (atom = = 0) {WindowProc = null; throw new Win32Exception (ERR); }} registered = TRUE;}
One, to scare the urine! DIY, clothed
See Microsoft's source code, can only express urine, it is not possible to inherit the form to implement a custom class name, then do their own, clothed bar, remember the above C + +/CLI code bar, simply add some content, you can implement our custom window class name wish, the code is as follows:
1. CustomForm.h
#pragma once#include <Windows.h> #include <vcclr.h> #define Custom_class_name L "Starts2000.window" Namespace Starts2000{namespace windowsclassname{namespace core{using namespace system;using namespace System::Windows :: Forms;using namespace System::runtime::interopservices;private delegate LRESULT WndProc (HWND hwnd, UINT MSG, WPARAM WParam, LPARAM LPARAM);p ublic ref class Customform{public:static customform (); Customform (); Customform (String ^caption); ~customform (); void Create (); void Show ();p rivate:string ^_caption; HWND _hwnd;static GCHandle _windowprochandle;static LRESULT WndProc (HWND hwnd, UINT MSG, WPARAM WPARAM, LPARAM LPARAM); STA tic void ProcessExit (object^ sender, eventargs^ e);};}}
2. customform.cpp
#include "CustomForm.h" namespace Starts2000{namespace windowsclassname{namespace core{static customform::customform () {Wndclassex WC; Starts2000::windowsclassname::core::wndproc ^windowproc =gcnew Starts2000::windowsclassname::core::wndproc ( CUSTOMFORM::WNDPROC); _windowprochandle = Gchandle::alloc (WindowProc); ZeroMemory (&WC, sizeof (wndclassex)); wc.cbsize = sizeof (wndclassex); wc.style = Cs_dblclks;wc.lpfnwndproc = Reinterpret_cast<wndproc> (Marshal::getfunctionpointerfordelegate (WindowProc). ToPointer ()); wc.hinstance = GetModuleHandle (null); wc.hcursor = LoadCursor (null, idc_arrow); wc.hbrbackground = (hbrush ) Color_window; (Hbrush) Getstockobject (hollow_brush); wc.lpszclassname = Custom_class_name; ATOM Classatom = RegisterClassEx (&WC);D Word LastError = GetLastError (); if (Classatom = = 0 && lasterror! = Erro r_class_already_exists) {throw gcnew applicationexception ("Register window CLASS failed!");} System::appdomain::currentdomain->processexit + = gcnew System::EventHandler(customform::P rocessexit);} Customform::customform (): _caption ("Starts2000 Custom ClassName window") {}customform::customform (String ^caption): _ Caption (caption) {}customform::~customform () {if (_hwnd) {DestroyWindow (_hwnd);}} void Customform::create () {DWORD Styleex = 0x00050100;dword style = 0x17cf0000;pin_ptr<const wchar_t> caption = PtrT Ostringchars (_caption); _hwnd = CreateWindowEx (Styleex, Custom_class_name, caption, Style,cw_usedefault, CW_ Usedefault, Cw_usedefault, cw_usedefault,null, NULL, GetModuleHandle (NULL), NULL), if (_hwnd = = NULL) {throw gcnew ApplicationException ("Create window failed! Error code: "+ GetLastError ());}} void Customform::show () {if (_hwnd) {ShowWindow (_hwnd, Sw_normal);}} LRESULT Customform::wndproc (HWND hwnd, UINT MSG, WPARAM WPARAM, LPARAM LPARAM) {System::windows::forms::message Message = System::windows::forms::message::create ((INTPTR) hWnd, (int) msg, (INTPTR) ((void*) wParam), (INTPTR) ((void*) lParam)) ; System::D iagnostics::D ebug::writeline (message. ToString ()); IF (msg = = Wm_destroy) {postquitmessage (0); return 0;} Return DefWindowProc (HWnd, MSG, WParam, LParam);} void Customform::P rocessexit (object^ sender, eventargs^ e) {unregisterclass (Custom_class_name, GetModuleHandle (NULL) if (customform::_windowprochandle.isallocated) {customform::_windowprochandle.free ();}}}}}
In the end, we still invoke the familiar C #:
Using system;using system.windows.forms;using Starts2000.windowsclassname.core;namespace starts2000.windowclassname.demo{ Static Class Program {///<summary>// The main entry point of the application. // </summary> [STAThread] static void Main () { //application.enablevisualstyles (); Application.setcompatibletextrenderingdefault (false); Application.Run (New FormMain ()); Customform form = new Customform (); Form. Create (); Form. Show (); Application.Run ();}}}
Compile, run, take out the artifact Spy + + to look at:
The goal was finally reached.
Finally, all the code is downloaded (the project uses VS2013 compilation, debugging, and does not guarantee that other versions vs can compile properly): Bash me.
How difficult is the. NET Windows form to change the form class name?