I used
PostMessage(NULL,WM_DUCKWND,0,0);
where
#define WM_DUCKWND (WM_USER +4)
to send user-defined msg to all windows in current thread.
DETAILS
this is straight in the main function
(DUCKPROC_CLASS_MSG_NAME and DUCKPROC_WINDOW_MSG_NAME are all user-defined macros)
//create message-only window
WNDCLASS wndc={};
wndc.lpfnWndProc = MsgWindowProc;
wndc.hInstance = hInstance;
wndc.lpszClassName = DUCKPROC_CLASS_MSG_NAME;
RegisterClass(&wndc);
auto hw=CreateWindowEx(NULL, DUCKPROC_CLASS_MSG_NAME, DUCKPROC_WINDOW_MSG_NAME, NULL, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
//post
PostMessage(NULL,WM_DUCKWND,0,0);
//message loop
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
and used WindProc like this
LRESULT CALLBACK MsgWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
{
case WM_DUCKWND:
[BREAKPOINT][BREAKPOINT][BREAKPOINT][BREAKPOINT]
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
However, the breakpoint isn't triggered as supposed.
How's that wrong?
"all windows in current thread."
No, that's not correct. HWND==NULL sends the message to the thread message queue. That's the message queue you process with your GetMessage(HWND==NULL) loop.
DispatchMessage is the function which looks at HWND in msg, and chooses the correct window proc. It does so by looking up the window class of that HWND.
Since HWND==NULL does not have a window class, it does not have a window proc either, and the message is not dispatched to any window.
If you want to send WM_DUCKWND(HWND==NULL) to all your windows, you'll have to dispatch it yourself. In this simple example, that's as simple as setting msg.hWnd=hw for msg.message==WM_DUCKWND && msg.hWnd==NULL.
Side note: it really should be WM_APP+4; the WM_USER range is for messages internal to a window class. The thread message queue is shared by windows, so you shouldn't post WM_USER messages to it.
Related
I'm realize the console win32 app does not quit cleanly so I'm trying to switch to message only windows instead. I'm starting the app from another process and trying to kill it cleanly.
This is the win32 app, it spawns a calc.exe on startup and on clean shutdown, it should kill the calc.exe
LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_USER: PostQuitMessage (0); break;
default: return DefWindowProc (hWnd, message, wParam, lParam);break;
}
return 0;
}
int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int show)
{
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof (WNDCLASSEX);
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"WindowClass1";
RegisterClassEx (&wc);
HWND hWnd = CreateWindowEx (NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
0,
//WS_OVERLAPPEDWINDOW, // window style
300,300,500,400,
HWND_MESSAGE,
//NULL, // parent window, NULL
NULL, hInstance, NULL);
//ShowWindow (hWnd, SW_HIDE);
PROCESS_INFORMATION pi;
CreateWindowProcess (L"calc.exe", pi); // helper class to createprocess
MSG msg = { 0 };
while (true)
{
if (PeekMessage (&msg, 0, 0, 0, PM_REMOVE))
{
if (WM_QUIT == msg.message)
break;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
// terminate the spawn process, this is not called cleanly
TerminateProcess (pi.hProcess, 0);
return (int)msg.wParam;
}
I made a c# program to start/kill the app cleanly (the calc.exe gets destroyed) by sending a WM_QUIT/WM_CLOSE/WM_USER message . The Win32 App does not receive messages unless the window is visible (WS_OVERLAPPED and ShowWindow true). PostMessage WM_QUIT is received but the calc.exe does not get destroyed, meaning it is not a clean exit.
How should I kill it cleanly from C# app?
class Program
{
[DllImport ("user32.dll")]
public static extern bool PostMessage (IntPtr hwnd, uint msg, int wparam, int lparam);
[DllImport ("User32.dll")]
public static extern int SendMessage (IntPtr hWnd, uint uMsg, int wParam, int lParam);
static void Main (string [] args)
{
try
{
Process myProcess;
myProcess = Process.Start ("My.exe");
// Display physical memory usage 5 times at intervals of 2 seconds.
for (int i = 0; i < 3; i++)
{
if (myProcess.HasExited) break;
else
{
// Discard cached information about the process.
myProcess.Refresh ();
Thread.Sleep (4000);
Console.WriteLine ("Sending Message");
const int WM_USER = 0x0400;
const int WM_CLOSE = 0xF060; // Command code for close window
const int WM_QUIT = 0x0012;
// Received only when windows is visible
//int result = SendMessage (myProcess.MainWindowHandle, WM_USER, 0, 0);
// not clean exit
PostMessage (myProcess.MainWindowHandle, WM_QUIT, 0, 0);
// doesn't receive
SendMessage (myProcess.MainWindowHandle, WM_QUIT, 0, 0);
}
}
}
}
}
Processes on Windows do not really have a "MainWindow". Process.MainWindowHandle is C# making a guess, and it guesses by looking to see if the process in question has a window with focus - which will only find visible windows. Use FindWindowEx to find the window handle you want to close.
Next, when a window closes, it does not automatically try to exit the current threads message loop. You need to handle WM_DESTROY to call PostQuitMessage.
In your message loop use GetMessage rather than PeekMessage if you are not doing any other work as PeekMessage returns immediately if there are no messages meaning the application thread will never have an opportunity to sleep.
With these changes in place you should be fine to simply post a WM_CLOSE to the valid window handle as it will be destroyed, post itself a WM-QUIT message to exit the message loop, and terminate the calc process properly.
here is my problem. I'm trying to create a windowless program that still uses trayIcon and Hooks, so I need to use messages (or not?) but when I use them, I don't know how to free my memory when I kill my process. Even classes's destructors aren't called. Here is a test main:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pCmdLine, int nCmdShow)
{
MSG msg;
OutputDebugStringW(L"Start.\n");
while (GetMessageW(&msg, NULL, NULL, NULL) > 0)
{
OutputDebugStringW(L"one.\n");
TranslateMessage(&msg);
OutputDebugStringW(L"two.\n");
DispatchMessage(&msg);
OutputDebugStringW(L"three.\n");
}
OutputDebugStringW(L"end.\n");
return 0;
}
As I saw in the doc, the GetMessage() call should return 0 or less to exit, but when I run it, and then shut it down, I get only the "Start." log, and I don't understand why. And if there is no way to get through this loop, then how can i call my destructors? I do have a window for my trayIcon that doesn't receive any message, maybe i should pass it as parameter to GetMessage()?
PS: my project uses trayIcons and Hooks, and when I run it with the same debug prints, it display once the 4 first strings, but nothing at shutdown, not even the "end." string.
EDIT: my (terrible) trayIcon creation:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
OutputDebugStringW(L"Message!\n");
switch (uMsg)
{
case WM_DESTROY:
OutputDebugStringW(L"Close message received\n");
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
case WM_RBUTTONUP:
{
OutputDebugStringW(L"Trying to open Context menu\n");
POINT const pt = { LOWORD(wParam), HIWORD(wParam) };
break;
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
bool CreateNotifyIcon(HINSTANCE& hInstance)
{
NOTIFYICONDATA notif = {};
static const wchar_t class_name[] = L"ExtendClass";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WindowProc;
wx.hInstance = hInstance;
wx.lpszClassName = class_name;
RegisterClassEx(&wx);
HWND win = CreateWindowEx(0, class_name, L"Windows Extend", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (win == NULL)
OutputDebugStringW(L"failed to create window\n");
ZeroMemory(¬if, sizeof(NOTIFYICONDATA));
notif.cbSize = sizeof(NOTIFYICONDATA);
notif.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
// Need to find a non-busy uID
notif.uID = 44421;
notif.hWnd = win;
StringCchCopy(notif.szTip, ARRAYSIZE(notif.szTip), L"Access Windows Extend options.");
StringCchCopy(notif.szInfo, ARRAYSIZE(notif.szInfo), L"Access Windows Extend options.");
StringCchCopy(notif.szInfoTitle, ARRAYSIZE(notif.szInfoTitle), L"Windows Extend");
notif.hIcon = (HICON)LoadImage(NULL, L"./Luma.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (!Shell_NotifyIcon(NIM_ADD, ¬if))
{
OutputDebugStringW(L"failed to create notifIcon\n");
return false;
}
return true;
}
GetMessage() does not return until it receives a window/thread message, or has a message to synthesis. In the code you have shown, you are not creating any windows, not posting any thread messages to yourself, and not creating any hooks that require a message loop, so there is nothing for GetMessage() to do. It is blocked indefinitely. That is why you are only seeing your start message and nothing else happens until you forcibly kill the program.
Since you intend to display a system tray icon, you need a window for it, even if just a hidden window, in order to receive notifications about user interaction with the icon. Your GetMessage() loop will handle messages for all windows created in the same thread as the loop, since you are setting the hWnd parameter to NULL instead of a specific window. Once you create your tray icon window, the loop will receive messages for it just fine. You can then provide your tray icon with a popup menu that contains an item that will exit your message loop when clicked, thus allowing you to exit from WinMain() gracefully, invoke destructors, etc.
GetMessage returns -1 if an error occurs. So you should do while != 0 generally. But if you are not seeing "end", then your application is probably crashing.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx
For some reason after I close this window my program wont exit and goes into an infinite loop. The solution to this problem seems to be changing GetMessage(&message, handel, 0, 0) to GetMessage(&message, NULL, 0, 0). However I don't understand why this is. Can somebody please explain. Also I don't see why I call UpdateWindow(handel) since the window will show without it.
#include <iostream>
#include <Windows.h>
using namespace std;
LRESULT CALLBACK EventHandler(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, PSTR args, int cmd)
{
MSG message;
HWND handel;
WNDCLASS win_class;
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = 0;
win_class.lpszClassName = "Window";
win_class.hInstance = inst;
win_class.hbrBackground = GetSysColorBrush(COLOR_3DDKSHADOW);
win_class.lpszMenuName = NULL;
win_class.lpfnWndProc = EventHandler;
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClass(&win_class);
handel = CreateWindow(win_class.lpszClassName, "Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 350, 250, NULL, NULL, inst, NULL);
ShowWindow(handel, cmd);
UpdateWindow(handel);
//Loop does not end.
while(GetMessage(&message, handel, 0, 0))
{
cout << "LOOP" << endl;
DispatchMessage(&message);
}
return WM_QUIT;
}
LRESULT CALLBACK EventHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static long long count = 0;
count++;
cout << "CALL #" << count << endl;
if(msg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
WM_QUIT is not sent to any window, just placed in the thread's message queue with no HWND, that's why it doesn't match your filter.
Take a look at GetMessage and PostQuitMessage in MSDN
If the parameter hWnd of GetMessage function is NULL, GetMessage retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
The PostQuitMessage function posts a WM_QUIT message to the thread's message queue, not to the current window.
Here's a good opportunity to exercise your "search-the-MSDN-documentation" abilities:
First, let's look up the documentation for WM_QUIT:
Indicates a request to terminate an application, and is generated when
the application calls the PostQuitMessage function. This message
causes the GetMessage function to return zero.
...
The WM_QUIT message is not associated with a window and therefore will
never be received through a window's window procedure. It is retrieved
only by the GetMessage or PeekMessage functions.
Then, let's look up the documentation for GetMessage():
Retrieves a message from the calling thread's message queue. The
function dispatches incoming sent messages until a posted message is
available for retrieval.
...
hWnd [in, optional] Type: HWND
A handle to the window whose messages are to be retrieved. The window
must belong to the current thread.
If hWnd is NULL, GetMessage retrieves messages for any window that
belongs to the current thread, and any messages on the current
thread's message queue whose hwnd value is NULL (see the MSG
structure). Therefore if hWnd is NULL, both window messages and thread
messages are processed.
Therefore, you want to use NULL as the window handle for GetMessage(), not handel, since WM_QUIT is not associated with any window.
There's plenty more information about how Windows programs typically handle messages also from MSDN.
As the side note, the message for window close events is WM_CLOSE, which in turn causes your window to be destroyed by default. WM_DESTROY means your window is already on it's way to being destroyed. So if you want to intercept the close event (say to ask your user to save any changes), you would handle the WM_CLOSE event.
Also, as shown in the GetMessage() documentation, you should actually have your GetMessage() loop look like this:
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Because GetMessage() can actually return 1, 0, or -1 (despite it returning a BOOL).
Recently I came about a strange difference between the two Win32 API calls "PostMessage" and "SendNotifyMessage" (at least noticed on Win7 64bit SP1):
An owned top-level window of another process seems not to receive messages broadcasted (HWND_BROADCAST) with "PostMessage" while it receives messages broadcasted with "SendNotifyMessage" in its WndProc.
The sent message have been registered with the help of a call to "RegisterWindowMessage".
Even using Spy++, I cannot see the message arriving when using "PostMessage". In addition, I want to mention, that if I send the message directly to the specific HWND with "PostMessage", it arrives as expected. So it looks like the windows-internal implementation of "PostMessage" just skips my window when iterating for execution of the broadcast.
Reading the respective MSDN documentation, I cannot see any statement about this difference and I am wondering if this is a bug in PostMessage or in SendNotifyMessage and if I can rely on SendNotifyMessage to continue to show this behavior in future versions of Windows.
So does someone have a plausible explanation why the both functions treat the broadcasts differently in this situation?
In addition, I would want to ask if there is any way to still use PostMessage to broadcast to an owned top-level window, because I would prefer to post the message because I would prefer to not skip the message queue (which is what SendNotifyMessage does).
In case you are curious why I want to reach a top-level owned window: in WPF, windows are hidden from the taskbar (Window.ShowInTaskbar property) by making them owned top-level windows with a hidden owner window.
Thanks a lot in advance for any ideas or comments on this topic.
Attachment: here a sample showing the behavior ... simply build it, and start it two times ... the second process should make a message show up in the first one.
Here is also a link to the complete solution including a build EXE: Link to the complete VS solution
#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
HWND hwndMain = NULL;
HWND ownerHwnd = NULL;
std::vector<std::string> theOutput;
UINT MyRegisteredMessage1 = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc = NULL;
if (message == MyRegisteredMessage1 && wParam != (WPARAM) hwndMain)
{
if (lParam == (LPARAM) 1)
theOutput.push_back("Got a 'MyRegisteredMessage1' via PostMessage");
if (lParam == (LPARAM) 2)
theOutput.push_back("Got a 'MyRegisteredMessage1' via SendNotifyMessage");
InvalidateRect(hwndMain, NULL, TRUE);
}
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
for(size_t i = 0, pos = 0; i < theOutput.size(); ++i, pos += 20)
TextOutA(hdc, 0, pos, theOutput[i].c_str(), theOutput[i].size());
EndPaint (hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProcHidden(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
BOOL bRet;
WNDCLASSA wc;
UNREFERENCED_PARAMETER(lpszCmdLine);
if (!hPrevInstance)
{
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProcHidden;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);;
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MyOwnerWindowClass";
if (!RegisterClassA(&wc))
return FALSE;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.lpszClassName = "MyOwnedWindowClass";
if (!RegisterClassA(&wc))
return FALSE;
}
ownerHwnd = CreateWindowA("MyOwnerWindowClass", "OwnerWindow",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 400, (HWND) NULL,
(HMENU) NULL, hInstance, (LPVOID) NULL);
hwndMain = CreateWindowA("MyOwnedWindowClass", "OwnedWindow",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 400, ownerHwnd,
(HMENU) NULL, hInstance, (LPVOID) NULL);
// only show the "real" window
ShowWindow(hwndMain, nCmdShow);
UpdateWindow(hwndMain);
MyRegisteredMessage1 = RegisterWindowMessageA("MyRegisteredMessage1");
char infoText[256];
_snprintf_s(infoText, 256,
"HWND = %X, registered message code for 'MyRegisteredMessage1' = %d",
hwndMain, MyRegisteredMessage1);
theOutput.push_back(infoText);
InvalidateRect(hwndMain, NULL, TRUE);
PostMessage(HWND_BROADCAST, MyRegisteredMessage1, (WPARAM) hwndMain, (LPARAM) 1);
Sleep(1000);
SendNotifyMessageA(HWND_BROADCAST, MyRegisteredMessage1, (WPARAM) hwndMain, (LPARAM) 2);
while( (bRet = ::GetMessage( &msg, NULL, 0, 0 )) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
You may need to register your message using RegisterWindowMessage() -- see the Remarks section of this MSDN article
Just adding this here for info..
I was able to get around this issue in c# by registering an IMessageFilter object on the Application level. PreFilterMessage on this object will receive the message and I can handle it from there.
public class FooMessageFilter : IMessageFilter
{
uint UM_FOO = 0;
public event EventHandler OnFoo;
public FooMessageFilter()
{
UM_FOO = Win32.RegisterWindowMessage("UM_FOO");
}
public bool PreFilterMessage(ref Message m)
{
if(m.Msg == UM_FOO)
{
if(OnFoo != null)
OnFoo(this, new EventArgs());
return true;
}
return false;
}
}
I then added this message filter to the Application context in my owned top-level form's constructor.
public partial class Form1 : Form
{
private FooMessageFilter fooFilter = new FooMessageFilter();
public Form1()
{
InitializeComponent();
// Register message filter
Application.AddMessageFilter(fooFilter);
// Subscribe to event
fooFilter.OnFoo += HandleFoo;
}
private void HandleFoo(object o, EventArgs e)
{
MessageBox.Show("Foo!");
}
}
From there it was just a matter of hooking up events in my top-level window to the message filter. This was necessary because of the need to adhere to current architecture, and the message originating from a third party process.
The documentation page(s) for PostMessage() mention that integrity level restrictions apply:
Starting with Windows Vista, message posting is subject to UIPI. The thread of a process can post messages only to message queues of threads in processes of lesser or equal integrity level.
There is no mention of such restrictions on SendNotifyMessage(). Since you don't check the return value of either, you could be running into that, and you wouldn't know it.
The following code works fine. It gives out the message when the user presses a key. But there are certain things I am not aware of. What is the role of Message Loop here ? I read that calling SetWindowsHookEx(...) registers a function with the windows and windows calls the appropriate function automatically when a event of registered type happens. No doubt that i don't see the output if don't give the message loop it's space.
#include<iostream>
#include <windows.h>
using namespace std;
HINSTANCE hinst = NULL;
static HHOOK handleKeyboardHook = NULL;
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
void setWinHook() {
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc,NULL, 0);
if(handleKeyboardHook == NULL) {
cout << "is NULL";
} else {
cout << "is not NULL";
}
cout<<("Inside function setWinHook !");
}
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
cout << ("You pressed a key !\n");
return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
EDIT
Does exiting the program (closing the console window) unregister the hook ?
EDIT 2
what role does Dispatch Message play here ? According to doc it dispatches a message to window procedure,but here even if i exclude that,it doesn't effect the output.
All events in Windows, even the low-level keyboard event used in your example, is sent using the normal message events. So for the program to be able to sense keyboard events, it has to use an event loop processing messages.
Without a loop, the program would exit immediately, and the hook would be removed at once too. You cannot register a hook and exit — the system would become a mess if buggy programs were leaving too many forgotten hooks after them. Once your process dies, the hook is scheduled for removal.
I don't remember about low-level keyboard hook, but callbacks of many other hooks are only called inside GetMessage/PeekMessage, and not on some other thread, so just an infinite loop won't suffice — it has to be a message loop.
"what role does Dispatch Message play here ? According to doc it dispatches a message to window procedure,but here even if i exclude that,it doesn't effect the output."
DispatchMessage is pretty useless cos console window doesnt receive much messages.
Only message received is when window loses focus.