Another type of WINDOW SUBCLASING (one)

zhaozj2021-02-11  236

Another type of WINDOW SUBCLASING (one)

The so-called Window Subclassing, Chinese usually translated as window subclass, simply, is the technology that intercepts and handles the window process. Maybe many programmers have already understood this technology, and more or less use it in their own procedures. In Microsoft's MFC class library, a large number of Window Subclassing methods used to say "MFC IS About Subclassing". Even if you haven't used it, at least you should have heard of it. The so-called alternative, there is no common sense, eclectic meaning. I am here to describe it can be said to be some "left" application, but maybe you have a new feeling.

My first application is the so-called "dialog box for delay automatically". The Messagebox function used to display information in Windows is very simple and convenient, but it has a fatal defect, unless the user presses a button, the execution of the entire program will hang. This is unacceptable for unattended automation programs. If it is compared to a time-dependent application (such as multi-thread programs or timer-based applications), MessageBox may also seriously interfere with the execution process of the entire program. In order to solve this problem, you define a new one, the dialog that can be automatically closed is of course the most intuitive practice, but I found that this is also a good place to apply Subclass, because we don't need to spend what work on the UI, the only need What to do is to add a WM_TIMER message to the dialog and the corresponding handler.

Although the idea is simple, there is a little trouble that realizes it. First, point out: To implement Subclass, the only full essential condition is that we need to get a handle of a particular window. It is this simple requirement, but it is tricky for MessageBox, because it is a modal dialog box, the window is built after calling MessageBox, and it has been revoked when MessageBox returned. How do we get this window?

The key here is that while calling MessageBox, the system will hang the main thread of the application, and then the control is returned after the MessageBox returns, so we did not get this window. Since I know the crux, the solution is coming: the main thread hangs, but I can use the child thread, see if you can nail me?

Methods have been found, the next implementation can be said to be a bold bamboo. First, declare the types and variables that must be:

Type

TWINDOWPROC = Function (awnd: hwnd; umsg: uint; wp: wparam; lp: lparam): longint; stdcall;

VAR

OldProc: twindowproc = nil;

Since we are subclass, we can't write a window process yourself. The only thing that needs to be processed is the WM_TIMER message, and close the dialog box when receiving this message:

Function newProc (awnd: hwnd; umsg: uint; wp: wparam; lp: lparam): longint; stdcall;

Begin

Result: = 0;

Case UMSG of

WM_TIMER:

Begin

Killtimer (awnd, 1);

Postmessage (awnd, wm_command, idcancel, 0);

END;

END;

IF assigned (oldproc) THEN

Result: = OldProc (AWND, UMSG, WP, LP);

END;

Then you need to generate a thread object and modify its execution method as follows:

Procedure TMSGTHREAD.EXECUTE; VAR

WND, WNDDESKTOP: HWND;

Classname: array [0..80] of char;

Begin

WaitForinputIdle (getcurrentProcess (), Infinite;

WNDDESKTOP: = getDesktopWindow ();

Wnd: = getWindow (wnddesktop, gw_child);

While Iswindow (WND) DO BEGIN

GetClassName (WND, ClassName, 80);

IF (LSTRCMPI (ClassName, '# 32770') = 0)

AND (getParent (WND) = Application.mainform.Handle) THEN Begin

OldProc: = TwindowProc (getWindowlong (WND, GWL_WNDPROC);

SetWindowlong (WND, GWL_WNDPROC, Longint (@newproc);

SetTimer (WND, 1, 3000, NIL);

Break;

END;

Wnd: = getWindow (WND, GW_HWNDNEXT);

END;

END;

Please note that WaitForInputIdle calls because thread objects must be called first on MessageBox, so we must wait for the operating system to complete the initialization work of the dialog, do the following action, otherwise lookup Messagebox window tasks will fail. In addition, the window class of the information box is # 32770, it is special!

The test code is simpler:

Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);

VAR

Msgthread: TMSGTHREAD;

Begin

Msgthread: = TMSGTHREAD.CREATE (FALSE);

Try

MessageBox (Handle, 'Test Msg', 'Testdlg', MB_OK);

Finally

Msgthread.free;

END;

END;

Our work will report a paragraph. Of course, you can also encapsulate all of the above code into a component, like OpenDialog or FontDialog, add an Execute method. This work is left to interested readers to complete.

转载请注明原文地址:https://www.9cbs.com/read-3830.html

New Post(0)