I am just learning to create a gui using the winapi, but i have run into an issue. I can create a window like this
#include "stdafx.h"
#include <windows.h>
int main()
{
HWND hwnd = CreateWindow(L"STATIC",NULL,WS_VISIBLE|WS_SYSMENU|WS_CAPTION,0,0,600,600,NULL,NULL,NULL,NULL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_gettch();
}
But the windows will not close when the close button is clicked, and the window can not be dragged around or moved. I was wondering how i would enable these features of the window.
Static windows are not there for normal windows, you should try and look up how to register and handle your own class with RegisterWindowEx then use the same class name to create a window. You have to have your own window procedure in order to handle messages.
All window classes registered by the system run their own default window procudure and as far as I know none of them handle WM_CLOSE ( that is the close button ) this is why you can't close it.
For you main windows always use something like WS_OVERLAPPEDWINDOW so it'll be clear if it's okay or not and from that eliminate the flags you don't need.
How you set it up :
WNDCLASSEX wndcls;
HWND hMainWnd;
// Register your own window class
ZeroMemory(&wndcls,sizeof(WNDCLASSEX));
wndcls.cbSize=sizeof(WNDCLASSEX);
wndcls.style=CS_VREDRAW+CS_HREDRAW;
wndcls.lpfnWndProc=&appWndFunc;
wndcls.hInstance=hInstance;
wndcls.hIcon=hMainIcon; // or just LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN_ICON))
wndcls.hIconSm=hMainIcon;
wndcls.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW);
wndcls.hbrBackground=(HBRUSH)COLOR_APPWORKSPACE;
wndcls.lpszClassName="myWndClass";
if (RegisterClassEx(&wndcls)==0)
{
// failed to register class name
return false;
}
// Create window with your own class
hMainWnd=CreateWindowEx(0,\
"myWndClass","widnow title",\
WS_OVERLAPPEDWINDOW|WS_VISIBLE,\
0,\
0,\
250,\
250,\
hMainWnd,NULL,hInstance,NULL);
if (hMainWnd==(HWND)NULL)
{
// failed to create main window
return false;
}
Then your main loop :
bool bAppMainLoop=false
while(!bAppMainLoop)
{
WaitMessage();
while(PeekMessage(&emsg,NULL,0,0,PM_NOREMOVE))
{
if(GetMessage(&emsg,NULL,0,0)==0)
{
bAppMainLoop=true;
break;
}
TranslateMessage(&emsg);
DispatchMessage(&emsg);
}
}
This is a bit more than usual setup, so let me explain , in order to not burn CPU, you wait for a message with WaitMessage, it'll block until something happens, like move window, click, paint etc. PeekMessage will return true if there is a message so calling it in a while loop will make sure it drains the message quene, GetMessage will obtain the message if it returns 0 it means that your app called the PostQuitMessage(0) so a WM_QUIT arrived was found in the message loop that means it's time to break out from the message loop. The rest Translate and Dispatch does what it name says.
Finally you need your own window procedure :
LRESULT CALLBACK appWndFunc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (uMsg==WM_CLOSE)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
DefWindowProc is essential that handles all commonly occurring messages from the system, thus you don't need to handle those here. You simply respond to the WM_CLOSE message which is sent when you want to close the window and post a quit message into the message loop that you will catch and exit.
Additional info :
It's not required to release your stuff since windows does that for you so it wont be locked the next time you start your program , but it's a good practice to at least Unregister your window class after your main loop.
Btw that is the wrong main function : WinMain that is the correct one. Plus to avoid even more bugs make sure you compile a windows GUI application.
Related
I'm an electrical engineer and am creating my first C++ Windows 10 application in Visual Studio.
When I start the app that I've created, and my application window starts with its menus, I can open a file and start processing that file. This processing takes several minutes and
can't be interrupted for too long (less than a millisecond - hopefully).
The problem I'm having is that when the file processing is underway my window's menus don't respond. This is tolerable when I'm running under the Visual Studio IDE, but when I run the standalone app's .exe file then the app's graphics soon stops rendering and Windows posts a "Not responding" error message.
Can someone please point me in the right direction to solve these related problems. There must be a simple way to temporarily give control back to WinMain or window_callback.
Here's a simplified structure of the code:
LRESULT CALLBACK window_callback(HWND hwnd, UINT uMsg, ...) {
switch (uMsg) {
case WM_CREATE:
AddMenus(hwnd);
break;
case MY_FILE_OPEN:
open_file(hwnd);
break;
...
}
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, ...) {
// Create Window Class
...
// Register Class
...
// Create Window
HWND window = CreateWindow(window_class.lpszClassName, L"My Window NAME", ...);
hdc = GetDC(window);
// My application's initialization code
...
while (running) {
MSG message;
while (PeekMessage(&message, window, ...) {
TranslateMessage(&message);
DispatchMessage(&message);
}
}
}
void open_file(HWND hwnd) {
here's where I call the file processing code (a several-minute loop);
}
If your application is not running the main message processing loop of PeekMessage, TranslateMessage, and DispatchMessage then it will become completely non-responsive as you have noticed. That's the nature of message-driven event loops such as used by Windows.
You either need to run open_file in a different thread, or segment it in some way that it can process a small piece at a time and return and get called again to process another piece.
E.g.
while (running) {
MSG message;
while (PeekMessage(&message, window, ...) {
TranslateMessage(&message);
DispatchMessage(&message);
}
open_file_piece();
}
Basically I created a simple Dll injection code with a basic Dll that shows a message box and my question is how can I now use the Dll file to make it write text into the Notepad while its running and it hasn't been saved/is temporary?
Is there a way to find a path to the file?
(i don't think so because its still writing into the ram and is untitled so doesn't have a save on any drives)
Or is there a stream i can write into?
Like Timo said in the comment, you can get the handle to the Notepad's Window, and then use it to write text into it, and it even wouldn't require from you to inject your DLL into the Notepad Process.
In Windows, every window is receiving messages from the Operating System (or from other programs, like what you're going to try out), those messages tell the window what action was made, for instance - Pressing down a key, or pressing a mouse button. That way, the program controlling the Window will know what kind of action it's supposed to do.
You can use the Spy++ Tool (spyxx.exe, comes builtin in every Visual Studio) to track what Windows does when you press a key down the keyboard into the Notepad's Window.
You can read further about the topic of window messages here:
https://learn.microsoft.com/en-us/windows/win32/learnwin32/window-messages
And working with Spy++ here:
https://learn.microsoft.com/en-us/visualstudio/debugger/introducing-spy-increment?view=vs-2019
Opening Spy++, we can see all the Windows in the our session, and we look for the Notepad's:
how it looks
Small POC I made for searching the appropriate Window, according to what found by Spy++ (forgive me for the globals, and make sure you are aware of what I did here):
HWND notepad_window;
HWND notepad_edit;
BOOL CALLBACK GetEditWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
if (0 != GetClassNameW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Edit"))
{
std::wcout << "Found it" << text << std::endl;
notepad_edit = hWnd;
return false;
}
}
return true;
}
BOOL CALLBACK GetNotepadWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
// Fun fact - The GetWindowTextW also posts a window message to the window, the WM_GETTEXT message
if (0 != GetWindowTextW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Notepad"))
{
std::wcout << "Found it" << text << std::endl;
notepad_window = hWnd;
return false;
}
}
return true;
}
int wmain()
{
EnumWindows(GetNotepadWindow, 0);
EnumChildWindows(notepad_window, GetEditWindow, 0);
}
After you have the HWND, you can start dealing with the message posting. You can use Spy++ again to 'tap' on the Notepad's Edit Window, and see every Window Message sent when pressing down a key, you will see the WM_KEYDOWN, followed by a WM_KEYUP most likely.
Then, you can use the PostMessage WinAPI function to post your own WM_KEYDOWN/KEYUP messages to the Notepad Window, hence controlling the input it gets.
I have a multithreaded application and on certain threads, I'm creating windows using ATL's CWindowImpl<>. I have a static method that I'm using as the thread procedure. I need to create a window on the thread, because I need some of my communication with the thread to be synchronous, and PostThreadMessage() is expressly asynchronous. When my window receives the WM_DESTROY message (handler defined by the MESSAGE_HANDLER macro), it calls PostQuitMessage(), as shown in this method:
LRESULT MyATLWindowClass::OnDestroy(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled) {
::PostQuitMessage(0);
return 0;
}
I'm using a custom message to the thread using PostThreadMessage() to indicate to the thread that it's time to terminate itself. Handling that custom message, I call the CWindowImpl::DestroyWindow() method, which does appear to properly destroy the window, as my OnDestroy message handler is getting called. However, it doesn't appear that the owning thread ever receives a WM_QUIT message for processing. Included below is a simplified version of my thread procedure.
unsigned int WINAPI MyATLWindowClass::ThreadProc(LPVOID lpParameter) {
// Initialize COM on the thread
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// Create the window using ATL
MyATLWindowClass new_window;
HWND session_window_handle = new_window.Create(
/* HWND hWndParent */ HWND_MESSAGE,
/* _U_RECT rect */ CWindow::rcDefault,
/* LPCTSTR szWindowName */ NULL,
/* DWORD dwStyle */ NULL,
/* DWORD dwExStyle */ NULL,
/* _U_MENUorID MenuOrID */ 0U,
/* LPVOID lpCreateParam */ NULL);
// Initialize the message pump on the thread.
MSG msg;
::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// Run the message loop
BOOL get_message_return_value;
while ((get_message_return_value = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
if (get_message_return_value == -1) {
// GetMessage handling logic taken from MSDN documentation
break;
} else {
if (msg.message == WD_SIGNAL_THREAD_SHUTDOWN) {
// Requested thread shutdown, so destroy the window
new_window.DestroyWindow();
} else if (msg.message == WM_QUIT) {
// Process the quit message and exit the message loop
// to terminate the thread
break;
} else {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
// Uninitialize COM on the thread before exiting
::CoUninitialize();
return 0;
}
Note that it doesn't seem to matter if I call DestroyWindow() or if I send a WM_CLOSE message to the window. The thread's message pump is not receiving WM_QUIT in either case. Should the owning thread's message pump be receiving such a message? Where is my misunderstanding about how the thread's message pump and the window's message pump interact? Or what am I missing about how ATL's window classes create and manage windows?
GetMessage() never returns WM_QUIT. That message forces it to return 0 instead, designed to terminate your message loop.
Beware of the considerable hazards of using PostThreadMessage(). It should never be used on a thread that also displays windows, like the one you are using. The issue is that it doesn't take a HWND argument. So only your message loop can see the message, it won't be delivered to any window with DispatchMessage(). This goes wrong when a modal message loop is entered, the kind that are outside of your control. Like the modal loop that makes MessageBox work. Or the one that Windows uses to allow the user to resize a window. Or the one that DialogBox() uses. Etcetera. Always use PostMessage(), use your own message number.
Some late additional thoughts. You could probably safely terminate your message loop as soon as you have discovered WD_SIGNAL_THREAD_SHUTDOWN:
if (msg.message == WD_SIGNAL_THREAD_SHUTDOWN) {
// Requested thread shutdown, so destroy the window
new_window.DestroyWindow();
break; // exit the message loop
}
DestroyWindow is a synchronous call, the window will be fully destroyed before it returns and you can exit the loop. So, posting WM_QUIT would be redundant.
Also, you could use message-only window, if the windows is invisible and its only purpose is to process messages.
How can I test if a button is being pressed ?
I am using EnumChildWindows() to enumerate the child windows of a given window, and one of the child window is a button, I want to test if that specific button is being pressed.
My code until know is:
BOOL CALLBACK MyEnumProc(HWND hwnd, LPARAM lParam)
{
char buffer[256];
GetWindowText(hwnd, buffer, sizeof(buffer));
cout << buffer << endl;
return true;
}
int main()
{
HWND hwnd = FindWindow(0, "Window to find");
EnumChildWindows(hwnd, MyEnumProc, 0);
return 0;
}
You can send the BM_GETSTATE message to the button control, if it is pressed the result will be
BST_PUSHED.
You need to inject a DLL into the process space, hook the window message loop (like you used to hand code a subclassed window in native Win32 API C code, Window Proc) (google-able) and listen to the actual messages.
All of this is ancient stuff for me, and I'm afraid that recent Windows versions (hopefully) made this a little bit more difficult to do.
That said, if you can get the application trusted with the right level of permissions, you should still be able to do this
I'm programming a little game, and I set the lpfnWndProc to DefWindowProc
and after that, I made a loop in that way:
MSG lastMessage;
while (true)
{
if (PeekMessage(
&lastMessage,
this->getWindow(),
0, 0,
PM_REMOVE))
{
TranslateMessage(&lastMessage);
DispatchMessage(&lastMessage);
}
}
So how do I handle the Close Window event in that case?
First of all, this is not how you write a message loop: it will take 100% CPU while waiting for messages, and won't remove messages for other windows from the queue. It will also never terminate. See here for an example of a message loop.
About closing windows: DefWindowProc will handle WM_CLOSE automatically and destroy your window. If you want your application to terminate when the window is closed, you need to handle WM_DESTROY and call PostQuitMessage(0) from it. This means you will need your own window procedure instead of DefWindowProc.
If you want WindowProc to be handled by a class, you do something like
class CWindow
{
static LRESULT WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
CWindow* self;
if(uMsg == WM_CREATE)
{
self = (CWindow*)((LPCREATESTRUCT)lParam)->lplpCreateParams;
}
else
self = GetWindowLong(hwnd,GWL_USERDATA);
if(self){
switch(uMsg){
case WM_CREATE:
return self->OnCreate(hwnd,(LPCREATESTRUCT)lParam);
case WM_CLOSE:
self->OnClose();
return 0;
// etc.
}
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int OnCreate(HWND hwnd,LPCREATESTRUCT lpcs)
{
m_hwnd = hwnd;
SetWindowLong(m_hwnd,GWL_USERDATA,this);
return 0;
}
}
Making sure of course to pass 'this' as the last parameter to CreateWindow(Ex).
Next, In your message loop, you MUST check for WM_QUIT messages and use that as a cue to exit the loop. Also, NEVER do a filter on hwnd as that will prevent your application loop from dispatching messages for other windows on your thread. And many windows libraries create message windows on threads to facilitate inter process (and thread) comms. If you dont process all windows messages then (a) your game will eventually run out of memory, and (b) the entire system may start to act funny as your application will make IPC messages deadlock, or time out.
Also, WM_CLOSE is (usually) sent via SendMessage, not PostMessage. Sent messages are delivered straight to the window proc and can't be filtered in the app loop.