How to become aware of WM_DEVICECHANGE arrival?
WndProc's overwritten. I catch the whole bunch of messages but none of them are of type WM_DEVICECHANGE. RegisterDeviceNotification makes the linker to complain that it can't find the function! So I'm stuck in this voodoo magic. Kindly help.
P.S.: of course I have been googling and stackoverflowing (lol) all this stuff for about 8 hours.
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
LPTSTR lolclassname = "lolclass";
WNDCLASS lolclass;
HWND lolwindow;
MSG lolmsg;
UINT msgstatus;
lolclass.style = CS_VREDRAW;
lolclass.lpfnWndProc = &lol_wnd_proc;
lolclass.cbClsExtra = 0;
lolclass.cbWndExtra = 0;
lolclass.hInstance = hInstance;
lolclass.hIcon = NULL;
lolclass.hCursor = NULL;
lolclass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
lolclass.lpszMenuName = NULL;
lolclass.lpszClassName = lolclassname;
if(!RegisterClass(&lolclass)) fail("RegisterClassEx");
lolwindow = CreateWindow("lolclass", NULL, WS_MINIMIZE, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
HWND_MESSAGE, NULL, hInstance, NULL);
if(lolwindow == NULL) fail("CreateWindowEx");
/*ShowWindow(lolwindow, nCmdShow);
UpdateWindow(lolwindow);*/
do {
/* if(!SetWindowPos(lolwindow, HWND_TOPMOST, 1, 1, 1, 1,
SWP_HIDEWINDOW))
fail("SetWindowPos");*/
msgstatus = GetMessage(&lolmsg, lolwindow, 0, 0);
if(!msgstatus) break;
if(msgstatus == - 1) fail("GetMessage");
TranslateMessage(&lolmsg);
DispatchMessage(&lolmsg);
Sleep(1000);
} while(1);
return lolmsg.wParam;
}
lol_wnd_proc is executed but never when it supposed to (on device change of course, am I clear?)
The problem is that you are creating a message-only window which does not receive broadcasts:
A message-only window enables you to send and receive messages. It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.
So, you cannot use a message-only window and instead need to make a top-level window that is never shown. That's trivial to achieve — stop passing HWND_MESSAGE to CreateWindow and make sure that you never call ShowWindow.
As an aside, Sleep(1000) in the middle of a message loop is going to be a disaster. You need to pump messages in a timely fashion, not fall asleep on the job. You must get rid of that Sleep. Note that GetMessage will block if the queue is empty, so you don't need to worry about your application running hot.
Your message loop should look like this:
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Related
I am searching for the fastest possible way in C to determine if any key on the keyboard has been pressed.
I am not looking for how to determine if a specific key is pressed (in that case, GetAsyncKeyState() would work).
Also, it needs to work in the background, so without the program window having focus (the program will be running in the background).
EDIT: The program will react on every keypress with a sound output. I want it to output a sound everytime I type something (like in Word and such). That's also why it needs to run in the background. I want it to be fast, so I can minimize the delay between keypress and sound output.
EDIT2: I am searching for something else than Windows Hooks. While it does work for getting key presses in the background, I am looking for something that is faster (least delay possible).
For example: GetAsyncKeyState() works for reacting on specific keypresses, while the program window doesn't have focus. I am looking for something like that, but with the ability to react on any key press, not a specific one.
As comment, you could use RegisterRawInputDevices as this sample.
Create a Message-Only Window.
Set RAWINPUTDEVICE.hwndTarget to the window create in step 1, so that you don't need to focus on the window.
Call GetRawInputData to get the input data.
Sample(removed the error checking):
#include <windows.h>
#include <iostream>
using namespace std;
LRESULT CALLBACK WindProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_INPUT)
{
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
RAWINPUT input = { 0 };
UINT size = sizeof(input);
GetRawInputData(hRawInput, RID_INPUT,&input,&size,sizeof(RAWINPUTHEADER));
printf("vkey: %x, flag: %d\n",input.data.keyboard.VKey, input.data.keyboard.Flags);
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
int main()
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("RawInputClass");
RegisterClassEx(&wcx);
HWND hWnd = CreateWindowEx(0, TEXT("RawInputClass"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
RAWINPUTDEVICE rid = { 0 };
rid.usUsagePage = 0x01;
rid.usUsage = 0x06; //keyboard
rid.dwFlags = RIDEV_INPUTSINK;
rid.hwndTarget = hWnd;
RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE));
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
The following is taken from the Remarks section of the MoveWindow() documentation:
If the bRepaint parameter is TRUE, the system sends the WM_PAINT
message to the window procedure immediately after moving the window
(that is, the MoveWindow function calls the UpdateWindow function).
So I assumed that when I call MoveWindow() with bRepaint set to TRUE, the window procedure will be called immediately and passed a WM_PAINT message, but this is what my testing shows:
When MoveWindow() is called, the window procedure is called
immediately, but a WM_ERASEBKGND message is passed to it and not a
WM_PAINT message.
The region is still invalid and so when I go back to the message loop and no messages are in the message queue, a WM_PAINT message is sent.
Did I interpret the documentation wrong?
Note: I am talking about calling the MoveWindow() method on the parent window object.
Edit:
This is my test code:
/* Left mouse click on the window to call MoveWindow() */
#include <Windows.h>
HWND hEdit;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_LBUTTONDOWN:
MoveWindow(hWnd, 200, 200, 700, 700, TRUE);
// Do not go back to message loop immediately
Sleep(3000);
break;
case WM_ERASEBKGND:
{
SendMessage(hEdit, WM_CHAR, (WPARAM)'e', 0);
}
break;
case WM_PAINT:
{
SendMessage(hEdit, WM_CHAR, (WPARAM)'p', 0);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(0, "WinClass", "", WS_OVERLAPPEDWINDOW, 261, 172, 594, 384, NULL, NULL, hInstance, NULL);
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, 0, 0, 400, 21, hWnd, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Did I interpret the documentation wrong?
Basically, yes. You discovered a little fact about MSDN documentation on winapi functions that is very, very important to know. It is not written to be a tutorial. It assumes a basic understanding of how the winapi works, the kind of knowledge you get from reading Petzold's "Programming Windows" book.
That book can teach you that the Windows painting cycle always includes WM_ERASEBKGND. So the background is painted first, what ever you draw on top of it with WM_PAINT is next.
Several reasons why such implementation details are skipped in the MSDN documentation. First off, there is a lot of it and including everything just makes it hard to plow through the article. Next, it is pretty unusual to actually write a message handler for WM_ERASEBKGND. You normally just pass it on to DefWindowProc(). Which uses the WNDCLASSEX.hbrBackground you selected, 99% of the time good enough to get the job done. Note how your window looks screwed up because that's what you did not do. Since you wrote a message handler, it is now your job to take care of it. Easy to do, just call DefWindowProc() yourself.
Finally, MSDN documentation omits details because nailing them down makes it very difficult to ever improve the way Windows works. There's another implementation detail that you can see from your test program. Quite often, calling MoveWindow with bPaint = TRUE does not paint anything at all. Easy to see by moving the window by dragging it with the title bar after you first clicked it. Note how clicking again makes the window jump back but you get neither WM_ERASEBKGND nor WM_PAINT.
That's an optimization at work, making Windows work better. And not mentioned in the MSDN article. If the window didn't move off the screen and back and the size of the window did not change then it can take a shortcut. It simply copies the pixels in the video frame buffer from the old position to the new position. Much more efficient than letting the app repaint everything. If you run with Aero enabled then it is even more optimized, it doesn't have to copy the pixels at all.
Last but not least, while writing code like this to reverse-engineer Windows is pretty educational and recommended, you don't have to. It is much easier to use the Spy++ utility.
What probably happens is that MoveWindow sends WM_ERASEBKGND using SendMessage (which will call the WndProc callback immediately and wait for its processing) but WM_PAINT via PostMessage (which will just put the message in the queue, so it will be processed after sleeping, when DispatchMessage is called).
I don't know if it's just a test or you're really processing something after using MoveWindow which blocks the message queue. If so, then you should consider moving that work to another thread!
Hope it helps.
Did I interpret the documentation wrong?
Yes and no.
No - the documentation is pretty clear on this.
Yes - like Hans Passant said, you just can't rely on such details from MSDN.
There are many WinAPI functions that have "gotchas", undocumented behaviour or expected environment state (incl. timing) and such. It could be that it did behave as specified in some version of Windows. Maybe it still does, under some circumstances.
In practice, MS will test a lot of applications to see if they work after making a change like this. In this case, since you generally process the WM_PAINT "when it happens", and do only painting then, it is easy to see how in most applications this change would not affect the end-user result.
So, always take MSDN as a "general description". Use your own testing and other sources to get the actual behaviour details. Be happy that you're working with the windows-related API, if you ever work some less used APIs, you'll be far worse off (I suffered a lot with the USB / HID related APIs).
i didn't want to override rony's provided test code so i decided to post my alternative, which i think is better suited to debug Windows Message, the only requirement an external tools to view the debug message DebugView. this of course can be replaced by a listbox if some one wishes.
#include <Windows.h>
/*
get DebugView from here https://download.sysinternals.com/files/DebugView.zip
*/
/*___________________________________________________________________________________
*/
void __cdecl DebugPrint(TCHAR *fmt,...){
va_list args = NULL;
va_start(args, fmt);
static TCHAR _buff[512]="";
TCHAR buff[512];
wvsprintf(buff,fmt,args);
va_end(args);
if(lstrcmp(buff,_buff))
OutputDebugString(buff);
lstrcpy(_buff,buff);
return ;
}
/*___________________________________________________________________________________
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_RBUTTONDOWN:
MoveWindow(hWnd, 200, 200, 700, 700, TRUE);
break;
case WM_MOVE:
DebugPrint("WM_MOVE");
break;
case WM_SIZE:
DebugPrint("WM_SIZE");
break;
case WM_ERASEBKGND:
DebugPrint("WM_ERASEBKGND");
break;
case WM_PAINT:
DebugPrint("WM_PAINT");
if(1){
PAINTSTRUCT ps;
TCHAR buff[]="Right mouse click on the window to call MoveWindow()";
HFONT hf=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
HDC hdc = BeginPaint(hWnd, &ps);
hf=SelectObject(hdc,hf);
TextOut(hdc,8,12,buff, sizeof(buff)-sizeof(TCHAR));
hf=SelectObject(hdc,hf);
EndPaint(hWnd, &ps);
}else{
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
/*___________________________________________________________________________________
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(0, "WinClass", "",WS_OVERLAPPEDWINDOW|WS_VISIBLE,
261, 172, 594, 384, NULL, NULL, hInstance, NULL);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
I looking for a method for forcing windows to set the program I launch with ShellExecuteEx() in first in z order.
The base of the problem is an issue with a machine (only one) and Google Chrome
When I launch Chrome from ShellExecuteEx() with this parameters :
http://www.google.fr --kiosk --fast-start --chrome-frame
It doesn't display the window, but I see the Chrome icon flashing in the bar.
I've tried to force the window by using EnumWindows() and BringWindowToTop() then SetWindowPos() with *HWND_TOPMOST* flag but this doesn't work for all programs I've tried.
Actualy I get a HWND by comparing pids
BOOL CALLBACK SetWindowToTopFromhProcess(HWND hwnd, LPARAM lParam)
{
HANDLE hProcess = (HANDLE)lParam;
DWORD win_pid = 0;
DWORD pid = 0;
char buf[512];
pid = GetProcessId(hProcess);
GetWindowThreadProcessId(hwnd, &win_pid);
if (pid == win_pid && pid != 0 && win_pid != 0)
{
//SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
BringWindowToTop(hwnd);
memset(&buf, 0, sizeof(buf));
GetWindowText(hwnd, buf, sizeof(buf));
printf("%s\n", buf);
return (FALSE);
}
return (TRUE);
}
int my_function()
{
SHELLEXECUTEINFO ExecuteInfo;
...
ExecuteInfo.nShow = SW_SHOWNORMAL;
...
if (ShellExecuteEx(&ExecuteInfo))
EnumWindows(SetWindowToTopFromhProcess, (LPARAM)ExecuteInfo.hProcess);
...
}
By the way, I've realized that the window handle I getting from the pid is not always the handle I want. For example with mspaint.exe the window name I retrieve is "GDI+ Window", so it's not the good window because it's not the good pid.
I've also tried a lot of nShow flags in the SHELLEXECUTEINFO structure who doesn't work.
So how to get the good window handle ? Is there another way to force the program I run to display its main window?
Or any idea ?
First of all, sorry for my ignorance of the window creation process. Today is actually the first day of my experimenting with it.
I started to code a text based game a few days ago and I have the main menu, and 3 or 4 different functions that control various things with text. I was then advised to look into Windows API and create a window for the program. I have created the window which can be seen here:
#include <Windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PWSTR nCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"WindowClass";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = CLASS_NAME;
wc.hInstance = hInstance;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx( //This creats a new instance of a window
0,
CLASS_NAME,
L"MyFirstWindow",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
NULL,
NULL,
hInstance,
NULL);
if(hwnd == 0)
return 0;
ShowWindow(hwnd,nCmdShow);
nCmdShow = 1;
MSG msg = { };
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY:PostQuitMessage(0); return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
FillRect(hdc,&ps.rcPaint,(HBRUSH)(COLOR_WINDOW+5));
EndPaint(hwnd, &ps);
}return 0;
case WM_CLOSE:
{
if(MessageBox(hwnd,L"Do you want to exit?",L"Exit",MB_OKCANCEL)==IDOK)
DestroyWindow(hwnd);
} return 0;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
This looks a bit messy, but you probably will not need it anyway.
So at this point I have my original program and this program that creates a window. My question is how, or even where, do I put my original program's code so that it can be incorporated into the window.
If you are reading this and thinking I'm a total moron for doing it this way, I'm open to ideas that are a lot simpler than what I'm doing right now.
Your code is the standard boilerplate for creating a window using c and win32 API functions. I recommend that you modify the message pump (it's the while loop in middle calling GetMessage). Instead do this:
Run an infinite loop
Peek a message
If the message is not there, execute your code
Else process messages including the quit message
Here's what the code should look like:
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//Your game code
}
}
I also want to point, that while learning game programming using C and calling Win32 API is a worthy goal, you might want to look at XNA game studio.
The reason I am recommending it is because it is easier to learn and you can make much more interesting games faster. Here are a few links to get you started if you are interested.
http://joshua-w-wise78.livejournal.com/
http://www.krissteele.net/blogdetails.aspx?id=72
http://www.codeproject.com/KB/game/xna1.aspx
http://msdn.microsoft.com/en-us/library/bb203894.aspx
If your original program was a console app, that read input and printed output, then you will probably want to get input from your window to implement your game.
Instead of looking at it from the perspective of read user input from stdin then generate output to stdout, you have to think of it from the view of window messaging. So you need to process the WM_KEYDOWN messages, you can then use DrawText() to show the user input in your client area, or you could use a c++ RichEdit control. Once you process the WM_KEYDOWN messages you know what the user has pressed and then your program can do it's thing (maybe being triggered to process an accumalated buffer of characters whenever the WM_KEYDOWN key is equal to the enter key?) and write the output to your client area using DrawText() or send WM_KEYDOWN messages to your richedit window using SendMessage().
I think this is what you meant by a text based game, anyway, you just have to start thinking of doing everything by monitoring windows messages. Anything that the user does to your window, Windows will send a message to it to let it know.
I have a method to set up a window in Windows, written in C. It uses the standard code which looks like this:
WNCDCLASS w1 = {0};
w1.lpszClassName = TEXT( "the_window" );
w1.lpfnWndProc = methodIWantOnItsOwnThread;
// snip
Now, I have been multithreading with the <process.h> threads in a method such as:
HANDLE h;
h = (HANDLE) _beginthread(methodIWantOnItsOwnThread, 0, 0);
How can I multithread like this in the windows callback function, such as with w1.lpfnWndProc = methodIWantOnItsOwnThread;?
More code.
HWND SetupWindow(int device)
{
HWND hwnd;
WNDCLASS w1 = {0};
if (device == 1)
{
w1.lpszClassName = TEXT( "window 1" );
w1.lpfnWndProc = methodIWantThreaded;
}
else
{
w1.lpszClassName = TEXT( "window 2" );
w1.lpfnWndProc = otherMethodIWantThreaded;
}
w1.hInstance = 0;
w1.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
w1.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&w1);
hwnd = CreateWindow( w1.lpszClassName, TEXT("The Window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 520, 650, 520, NULL, NULL, 0, NULL);
SetTimer(hwnd, 0,30,NULL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
return hwnd;
}
You're going about this backward, and it isn't going to work.
You should be having each window create a thread, not each thread creating a window. Then you simply create multiple instances of the WNDCLASS classname, and each has its own thread that can post and receive messages.
This also gives you a window handle that your main thread's window can use to send and receive messages, allowing you to communicate things to the threads (and vice versa).
Why do you want to do that?
The window proc runs on the thread that created the window handle. Of course, by extension, every thread that creates window handles must have a message loop.