I am writing a fairly simple windows C++ application in Visual Studio Express 2013, and at startup have a problem where the window hangs for 5-10 seconds due to a DispatchMessage processing a WM_TIMER message. The problem is, I never created a timer, so I'm not sure why I'm getting the message nor why there is this long hang.
enum KRESULT
{
K_OK,
K_FALSE,
K_QUIT
};
HINSTANCE g_hInstance;
HWND g_hWnd;
char* g_winName;
char* g_name;
KRESULT MessagePump( MSG &msg )
{
if( !PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
{
// there weren't any messages
return K_FALSE;
}
else
{
if( msg.message == WM_QUIT )
return K_QUIT;
if( msg.message == WM_CLOSE )
return K_QUIT;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return K_OK;
}
void Run()
{
MSG msg;
bool done = false;
while( !done )
{
KRESULT msgRes = K_OK;
while( msgRes != K_FALSE )
{
msgRes = MessagePump( msg );
if( msgRes == K_QUIT )
{
done = true;
break;
}
done = !DoFrame();
}
}
}
bool DoFrame()
{
// do a bunch of stuff, disabled for debugging.
// returns false if Esc is pressed
return true;
}
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
// Code managing WM_SIZE, WM_ENTERSIZEMOVE, etc that has to do with changing the size of the window.
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
bool bRunDefault = false;
switch( uMsg )
{
// check if the window is being destroyed.
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
// check if the window is being closed.
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
default:
{
bRunDefault = true;
break;
}
}
}
if( bRunDefault )
return MessageHandler(hWnd, uMsg, wParam, lParam);
return 0;
}
void InitWindows()
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
// get the instance of this application
g_hInstance = GetModuleHandle(NULL);
// setup the windows class with some default settings
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_name;
wc.cbSize = sizeof(WNDCLASSEX);
// register the window class
RegisterClassEx(&wc)
// determine the resolution of the client desktop screen
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int wWidth = 1366;
int wHeight = 768;
DWORD styleFlags;
// place it in the middle of the screen
posX = ( screenWidth - wWidth ) / 2;
posY = ( screenHeight - wHeight ) / 2;
styleFlags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
// create the window with the screen settings and get the handle
g_hWnd = CreateWindowEx( WS_EX_APPWINDOW, g_name, g_winName, styleFlags,
posX, posY, wWidth, wHeight, NULL, NULL,
g_hInstance, NULL );
// bring the window up on the screen and set it as main focus
ShowWindow( g_hWnd, SW_SHOW );
SetForegroundWindow( g_hWnd );
SetFocus( g_hWnd );
// mouse cursor options
ShowCursor( true );
}
Sorry about all the code, I wasn't sure how much of it was relevant. Most of these functions are encapsulated in an app class, and my WinMain function creates an instance of the class, calls InitWindows(), and Run(). The place where it hangs is in the MessagePump function, at DispatchMessage(). The WM_TIMER msg is passed twice, each with the following parameters:
hwnd = 0x00000000 <NULL>
message = 275 (WM_TIMER)
wParam = 18876 (this is random, but varies from around 18000 to 22000 or so)
lParam = 1975757148 (this is always the same)
Then, it is passed once with wParam = 1 and lParam = 0. Always in this order, and this group of three WM_TIMER messages are called every few frames.
The hanging only happens once, however, on the first time the message is passed at the beginning.
The hanging is the worst in debug mode of course, but in Release build, it happens as well.
I can add a handler to the MessagePump function, like so:
if( msg.message == WM_TIMER )
return K_OK;
This works to stop the hanging, but then it creates another problem where, when I move the window, my whole OS freezes for about 5-10 seconds.
I have been programming for a while (by no means an expert) but this baffles me. Any help is appreciated. Thanks!
Edit:
I tried building and running on two other machines. No hanging on both. After several restarts of the original machine, removing the startup processes that I felt I didn't need, the problem finally stopped, and has remained OK even after ~50 runs. I wish it was more satisfying to report which process was causing it, but I still haven't figured it out.
There was no process at the address 75C3A95C when looking at the modules window, strangely.
Something I noticed though: on all machines, the WM_TIMER messages are being passed. In addition, even with the default project you can create in VS2013 Exp, Win32Project1, these 3 WM_TIMER messages are being passed. Also, the Win32Project1 did hang as well, so it really had nothing to do with my code, but I guess... some strange interaction with a process running in my machine?
Thanks for everyone's help.
Perhaps another running program is sending yours the WM_TIMER messages, or perhaps a library you are linking in. Try running on on another, clean machine.
Related
I have a standard win32 window, that I draw on with D2D1. Everything is responsive and runs smoothly. My problem is as follows: After the window is created, it calls WM_PAINT once and then gets "stuck" waiting for any user input (ex. mouse move or click in the window area). As it receives the input, it runs without any further problems. While this doesn't necessarily render the program nonfunctional, it seems highly unprofessional and... ugly. Oh, and what I mean by "stuck" is that the background processes still run without problems, so the loop runs as intended - however, the WM_PAINT isn't called for some reason.
Here is the current code:
header file:
#define PROGRAM_FPS 30
#define GWINDOW_STYLE (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
class Application
{
public:
Application();
~Application();
// Register the window class and call methods for instantiating drawing resources
HRESULT Initialize();
// Process and dispatch messages
void RunMessageLoop();
static inline void SafeRelease(IUnknown * _X)
{
if(_X != NULL)
_X->Release();
};
HRESULT SetFullscreen(bool);
private:
// Time (ms) between frames of the application
// Initiation: m_AppFPS_Div( (DWORD)1000.0 / (DWORD)PROGRAM_FPS )
const DWORD m_AppFPS_Div;
// Initialize device-independent resources.
HRESULT CreateDeviceIndependentResources();
// Initialize device-dependent resources.
HRESULT CreateDeviceResources();
// Release device-dependent resource.
void DiscardDeviceResources();
// Draw content.
HRESULT OnRender();
HRESULT LoadBitmapFromFile(
ID2D1RenderTarget*,
PCWSTR,
UINT,
UINT,
ID2D1Bitmap **
);
// The windows procedure.
static LRESULT CALLBACK WndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
);
HWND m_hwnd;
ID2D1Factory * m_pDirect2dFactory;
ID2D1HwndRenderTarget * m_pRenderTarget;
IWICImagingFactory *m_pIWICFactory;
ID2D1SolidColorBrush * m_pWhiteBrush;
ID2D1SolidColorBrush * m_pGrayBrush;
ID2D1LinearGradientBrush * m_pLinearGradientBrush;
ID2D1Bitmap *m_LoadingPicture;
};
parts of the .cpp file
void Application::RunMessageLoop()
{
HACCEL hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_WIN32APP));
DWORD screen_last_refresh = 0;
MSG msg;
for(bool applicationRunning = true; applicationRunning;)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT)
{
applicationRunning = false;
}
if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/*** HERE I RUN VARIOUS BACKGROUND PROCESSES ***/
while((GetTickCount() - screen_last_refresh) < m_AppFPS_Div)
Sleep(2);
InvalidateRect(msg.hwnd, NULL, false);
screen_last_refresh = GetTickCount();
}
}
LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
Application *pApp = (Application *)pcs->lpCreateParams;
::SetWindowLongPtrW(hwnd, GWLP_USERDATA, PtrToUlong(pApp) );
InvalidateRect(hwnd, NULL, false);
result = 1;
}
else
{
Application *pApp = reinterpret_cast<Application *>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
)));
bool wasHandled = false;
if (pApp)
{
switch (message)
{
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
pApp->OnResize(width, height);
}
result = 0;
wasHandled = true;
break;
case WM_DISPLAYCHANGE:
{
InvalidateRect(hwnd, NULL, FALSE);
}
result = 0;
wasHandled = true;
break;
case WM_PAINT:
{
pApp->OnRender();
ValidateRect(hwnd, NULL);
}
result = 0;
wasHandled = true;
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
result = 1;
wasHandled = true;
break;
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
}
return result;
}
HRESULT Application::OnRender()
{
HRESULT hr = S_OK;
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
m_pRenderTarget->BeginDraw();
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
/** HERE I HANDLE THE OPENING ANIMATION **/
hr = m_pRenderTarget->EndDraw();
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
So, I've tested it on 2 computers (both using Win 8.1) with VS 2012 Ultimate and VS 2013 Professional, run debug tests back and forth, stripping certain parts of the program, searched MDSN, Google and StackExchange - to no avail. This freeze also happens when I handle WM_COMMAND of a child window. There was also no such issue when I tried implementing GDI+, but it proved to be highly ineffective, hence the switch to DirectX. Aside from that, the program runs flawlessly. I hope I've provided enough information.
You have not been clear about what you are doing to run "various background processes." That is probably where the "stuck" issue comes from. A suggestion is to move that out of the message loop. Instead, call SetTimer during window initialization and then do a bit of your background process work each time the WM_TIMER message comes in.
And, when you want a WM_PAINT to come in call InvalidateRect().
I have been experimenting with the WINAPI trying to learn it but the window I have created closes instantly. As you see when the W key is pressed or the left button is pressed it will close the program but when running it with no buttons being pressed it still closes.
#include <windows.h>
#include <windowsx.h>
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
// register the window class
RegisterClassEx(&wc);
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Game", // title of the window
WS_OVERLAPPEDWINDOW, // window style
1, // x-position of the window
1, // y-position of the window
1800, // width of the window
1000, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
// enter the main loop:
// this struct holds Windows event messages
MSG msg;
// wait for the next message in the queue, store the result in 'msg'
while (GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch (message)
{
// this message is read when the window is closed
case WM_MOUSEMOVE:
{
// Retrieve mouse screen position
int x = (short)LOWORD(lParam);
int y = (short)HIWORD(lParam);
// Check to see if the left button is held down:
bool leftButtonDown = wParam & MK_LBUTTON;
// Check if right button down:
bool rightButtonDown = wParam & MK_RBUTTON;
if (leftButtonDown == true)
{
//left click
//example lets close the program when press w
PostQuitMessage(0);
return 0;
}
}
case WM_KEYDOWN:
{
switch (wParam)
{
case 'W':
//w pressed
//example lets close the program when press w
PostQuitMessage(0);
return 0;
}
}
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
}
default:
break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
}
You're missing some break statements in your switch, so for example, if you get the WM_MOUSEMOVE message and the leftButtonDown != true, execution will fall through to WM_KEYDOWN, etc.
Eventually you get to case WM_DESTROY:, which will Post you a lovely QuitMessage.
As an aside, this would be very easy to spot by stepping through, statement-by-statement, in a debugger.
There is no break in your switch statement.
You end up exetuting
PostQuitMessage(0);
You could do something like this:
case WM_FOO:
{
if ( bar ) {
return 0;
}
break;
}
Don't detect clicks via the WM_MOUSEMOVE message, use the WM_MOUSEDOWN instead.
The problem is that your code is probably launched by you clicking on something, so when your window gets its first WM_MOUSEMOVE message, the button is still actually pressed. Code runs much faster than fingers..
I made a project that creates a DLL. This project uses the WFS methods and they access some hardware (devices) to get information or execute some commands.
In my project, I first open these devices then register them, I later use other methods to get information or execute.
HRESULT extern WINAPI WFSOpen ( LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion, LPWFSVERSION lpSPIVersion, LPHSERVICE lphService);
HRESULT extern WINAPI WFSRegister ( HSERVICE hService, DWORD dwEventClass, HWND hWndReg);
As you can see, the WFSRegister requires HWND as a parameter. WFSRegister uses this parameter to send events or messages to it.
My project is not an MFC project and I have no windows. I decided to create a window and assign the correct HWND to WFSRegister. I also created WndProc to get the messages that the WFS methods will send to me later.
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WFS_EXECUTE_EVENT:
cout<<"WFS_EXECUTE_EVENT";
break;
case WFS_SERVICE_EVENT:
cout<<"WFS_EXECUTE_EVENT";
break;
case WFS_USER_EVENT:
cout<<"WFS_USER_EVENT";
break;
case WFS_SYSTEM_EVENT:
cout<<"WFS_SYSTEM_EVENT";
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam );
}
void Init_Window()
{
WNDCLASS Wclass;
Wclass.hInstance = gHinstance;
Wclass.cbClsExtra = 0;
Wclass.cbWndExtra = 0;
Wclass.lpszClassName = TEXT("Device_Manager_Class_Name");
Wclass.lpszMenuName = NULL;
Wclass.lpfnWndProc = WndProc;
Wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
Wclass.hCursor = LoadIcon(NULL, IDC_ARROW);
Wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Wclass.style = CS_OWNDC;
if(!RegisterClass(&Wclass))
{
cout<<"Unable to Register Class";
}
ULONG Window_Width;
ULONG Window_Height;
DWORD style;
Window_Width = SCREEN_WIDTH;
Window_Height = SCREEN_HEIGHT;
style = WS_OVERLAPPED|WS_SYSMENU;
gHwnd = CreateWindow(TEXT("Device_Manager_Class_Name")
, TEXT("Device_Manager_Class_Title")
, style
, 0
, 0
, Window_Width
, Window_Height
, GetDesktopWindow()
, NULL
, gHinstance
, NULL);
if(!gHwnd){
cout<<"Unable to create the main window";
}
ShowWindow(gHwnd, SW_SHOW);
UpdateWindow(gHwnd);
SetFocus(gHwnd);
}
Init_Window() Successfully create window, I have no prob here.
When I want to register my device, I call the following code to get the correct HWND:
HWND windows_handle = FindWindow(TEXT("Device_Manager_Class_Name"), 0);
HRESULT result = WFSRegister(wfsRes.hService, WFS_EXECUTE_EVENT || WFS_SERVICE_EVENT || WFS_USER_EVENT || WFS_SYSTEM_EVENT , windows_handle);
result is S_OK(meaning the device registered successfully) and windows_handle refers to the same HWND I created in Init_Window(). For example, both have 0x00100a58 values.
Now I change some property on my devices and I expect to get these message on my WndProc(), but it's not working.
WndProc() working somehow and gets some messages, but not the ones I want (not the ones the devices send to it).
I'm sure the devices send message (as events) because I can see they do by reading their logs.
For example:
2013/09/25 16:46:29 HService : 44 Event WFS_SRVE_SIU_PORT_STATUS Sent for HWND = 330d1c hResult = WFS_SUCCESS
HWND in the log refers to same HWND I created in Init_Window() and windows_handle.
Also, you all got what I want to do. If you have any other solution please feel free to mention it.
I found solution thanks to dear Igor Tandetnik
All i needed to do is to add GetMessage()
MSG msg;
BOOL bRet;
HWND windows_handle = FindWindow(TEXT("Device_Manager_Class_Name"), 0);
while( (bRet = GetMessage( &msg, windows_handle, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg); //<< This line send msg to WndProc()
}
}
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.
Hello I am creating an app in win32 that will display the x, y position(In screen coords) of the mouse whereever the mouse is (inside my app client/NC area & outside).
I am at the stage where I want to detect when the mouse leaves my application completely. I have written a simple win32 app that should detect & notify myself when the mouse leaves my app, BUT its not working, I never receive the messages WM_MOUSELEAVE & WM_NCMOUSELEAVE.
What do you think is wrong? Am I using the wrong win32 functions?
// Track Mouse.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include <windows.h>
#include <vector>
#include <string>
#include <cstdlib>
static HINSTANCE gInstance;
// Globals //
enum MouseStatus { DEFAULT = 50001, LEFT_CLIENT, LEFT_NCLIENT };
static MouseStatus mouseState = DEFAULT;
static COLORREF bkCol = RGB(0,255,255);
// Functions List //
BOOL TrackMouse( HWND hwnd )
{
// Post:
TRACKMOUSEEVENT mouseEvt;
ZeroMemory( &mouseEvt, sizeof(TRACKMOUSEEVENT) );
mouseEvt.cbSize = sizeof(TRACKMOUSEEVENT);
mouseEvt.dwFlags = TME_LEAVE | TME_NONCLIENT;
//mouseEvt.dwHoverTime = HOVER_DEFAULT;
mouseEvt.hwndTrack = hwnd;
return TrackMouseEvent( &mouseEvt );
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
// Track mouse so I can be notified when it leaves my application (Client & NC areas)
BOOL trackSuccess = TrackMouse( hwnd ); // Returns successful, so I correctly track the mouse
if ( trackSuccess == 0 )
{
MessageBoxW( hwnd, L"Failed to track mouse", L"Error", MB_OK|MB_ICONEXCLAMATION );
}
else MessageBoxW( hwnd, L"Tracking mouse", L"Success", MB_OK|MB_ICONEXCLAMATION );
}
break;
case WM_MOUSELEAVE:
{
// I never receive this message
// Detect when the mouse leaves the client area
mouseState = LEFT_CLIENT;
bkCol = RGB(50,50,50);
InvalidateRect( hwnd, NULL, true );
}
break;
case WM_NCMOUSELEAVE :
{
// I never receive this message
// If the mouse has left the client area & then leaves the NC area then I know
// that the mouse has left my app
if ( mouseState == LEFT_CLIENT )
{
mouseState = LEFT_NCLIENT;
BOOL trackSuccess = TrackMouse( hwnd );
if ( trackSuccess == 0 )
{
bkCol = RGB(255,255,0);
MessageBoxW( hwnd, L"On WM_NCMOUSELEAVE: Failed to track mouse", L"Error", MB_OK|MB_ICONEXCLAMATION );
}
else MessageBoxW( hwnd, L"On WM_NCMOUSELEAVE: Tracking mouse", L"Success", MB_OK|MB_ICONEXCLAMATION );
InvalidateRect( hwnd, NULL, true );
}
}
break;
case WM_ACTIVATE:
case WM_MOUSEHOVER:
{
// The mouse is back in my app
mouseState = DEFAULT;
bkCol = RGB(0,255,255);
InvalidateRect( hwnd, NULL, true );
}
break;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint( hwnd, &ps );
SetBkColor( hdc, bkCol );
Rectangle( hdc, 10, 10, 200, 200 );
EndPaint( hwnd, &ps );
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE gInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = gInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(DKGRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"Custom Class";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// if registration of main class fails
if(!RegisterClassEx(&wc))
{
MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"Custom Class",
L"App Name",
WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE|WS_OVERLAPPED|WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 500,
NULL, NULL, gInstance, NULL);
if(hwnd == NULL)
{
MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
The key component your missing is SetCapture(hwnd); which directs all mouse messages to that hwnd until you call ReleaseCapture();
HANDLE_DLGMSG(hwnd, WM_RBUTTONDOWN, SKDemo_OnRButtonDown);
HANDLE_DLGMSG(hwnd, WM_MOUSEMOVE, SKDemo_OnMouseMove);
HANDLE_DLGMSG(hwnd, WM_RBUTTONUP, SKDemo_OnRButtonUp);
void SKDemo_OnRButtonDown (HWND hwnd, BOOL fDbClk, int x, int y, UINT keyFlags)
{
// Force all mouse messages to come to this window.
SetCapture(hwnd);
// Change the mouse cursor to eyes. This provides a visual indication
// to the user that Voyeur is "peering."
SetCursor(LoadCursor(GetWindowInstance(hwnd),
MAKEINTRESOURCE(IDC_POINTER)));
}
void SKDemo_OnMouseMove (HWND hwnd, short x, short y, UINT keyFlags)
{
if( GetCapture() == NULL ) {
return;
}
// do something with the message here
}
void SKDemo_OnRButtonUp (HWND hwnd, int x, int y, UINT keyFlags)
{
ReleaseCapture();
}
I think you need the mouse to be over your window before you all TrackMouseEvent. Try calling whilst you handle a mouse move message.
As written in Win32 documentation, the request expires each time the mouse leaves the window. So you need to call TrackMouseEvent also in your WM_MOUSELEAVE handler. Note also that if the mouse isn't in your window at the time TrackMouseEvent is called, WM_MOUSELEAVE is generated immediately.
The win32 API is more or less ridiculous. It doesn't have a mouse enter/leave. A google search for "MFC mouse enter leave" turned up this:
http://www.codeproject.com/KB/cpp/mouseenterleave.aspx
Note that MFC is just a thin wrapper around win32 proper. You can basically take any member function of a WND and call a C function with the exact same name and HWND as first parameter...the rest being all exactly the same.
Have fun. This kind of crap is why I hate all things win32.