I am currently making a small win32 window wrapper class, but I have a few problem.
If I hit the close(X) button of the window the window closes immediately without sending a quit or destroy message, so I can't for example prevent the window to close or save something before closing the window.
And the second problem/question is,
If I use this small code to use the window, the computer cpu gets strongly used.
But its only a small window.
How I can change/fix this?
int main()
{
glwCreate();
while(true/*Later here comes a method that checks, wether window close is requested*/)
{
glwUpdate();
}
glwDestroy();
return 0;
}
-
#include "glw.h"
#include <windows.h>
#include <iostream>
HINSTANCE instanceHandle;
WNDCLASSEX windowClass;
HWND windowHandle;
LRESULT CALLBACK WindowMessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
std::cout<<uMsg<<'\n';
switch(uMsg)
{
case WM_QUIT:
{
std::cout<<"QUIT\n";
return 0;
}
case WM_DESTROY:
{
std::cout<<"DESTROY\n";
return 0;
}
}
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
void glwCreate()
{
instanceHandle = GetModuleHandle(0);
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WindowMessageHandler;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = instanceHandle;
windowClass.hCursor = LoadCursor(0,IDC_ARROW);
windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
windowClass.lpszClassName = "atomus_window_class";
windowClass.lpszMenuName = "menu_name";
windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
RegisterClassEx(&windowClass);
windowHandle = CreateWindowEx( 0,
"atomus_window_class",
"atomus title",
WS_OVERLAPPEDWINDOW,
0,
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
instanceHandle,
0);
ShowWindow(windowHandle, SW_SHOW);
}
void glwDestroy()
{
DestroyWindow(windowHandle);
windowHandle = 0;
UnregisterClass(windowClass.lpszClassName, instanceHandle);
}
void glwUpdate()
{
MSG message;
while (PeekMessage (&message, 0, 0, 0, PM_REMOVE) > 0) //Or use an if statement
{
TranslateMessage (&message);
DispatchMessage (&message);
}
}
If you add handling for WM_CLOSE you get to control whether your window closes or not. By not providing your own handling for that message you get the default from DefWindowProc which is to destroy your window.
Related
I have my window file (Window.h):
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
class Window
{
private:
HWND hWnd;
HINSTANCE hInstance;
bool running = true;
const char* ID = "WINAPI_JVM64";
public:
Window()
{
init();
}
virtual void draw(Gdiplus::Graphics*) = 0;
void init()
{
hInstance = (HINSTANCE)GetModuleHandle(NULL);
WNDCLASS wc;
wc = {};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MessageHandler;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_HAND);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = ID;
assert(RegisterClass(&wc));
hWnd = CreateWindow(ID, "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
200, 200, 400, 400, NULL, NULL, hInstance, NULL);
ShowCursor(true);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
}
void run()
{
MSG msg;
PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE);
while(running)
{
if(PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT)
running = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Here, the draw function is called.
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics* g = Gdiplus::Graphics::FromHDC(hdc);
draw(g);
EndPaint(hWnd, &ps);
}
}
UnregisterClass(ID, hInstance);
}
};
And the main file (main.cpp):
#include "Window.h"
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
class AppWindow : public Window
{
public:
void draw(Gdiplus::Graphics* g) override
{
Gdiplus::SolidBrush brown_brush(Gdiplus::Color(255, 128, 57, 0));
g->FillRectangle(&brown_brush, 0, 0, 200, 200);
}
};
int main()
{
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
AppWindow w;
w.run();
Gdiplus::GdiplusShutdown(gdiplusToken);
return 0;
}
I have the problem that it just won't draw!
It handles every message, everything is good, but it doesn't draw. Even messages of type WM_PAINT are sent, but nothing happens.
Can you spot the problem?
I just want a window class that has an overridable draw() function with a run() function that handles all events, such as WM_LBUTTONDOWN. All of that works fine, the screen just stays blank.
Also, I can't close the window, when pressing the X button in the top-right corner, the window just stays; only after resizing and quickly pressing X, it closes.
As you can see, I have some pretty weird behaviour, and I don't know what the problem is.
Your drawing logic is in the wrong place. It needs to be inside the MessageHandler when processing a WM_PAINT message. PeekMessage() will generate a WM_PAINT message if the window needs to be drawn and no other messages are pending. You can't draw on the window from outside of a WM_PAINT handler.
Also, you are assigning the wrong value to wc.hbrBackground in init(). If you use a color constant like COLOR_WINDOW, you need to add 1 to it. This is stated as much in the WNDCLASS documentation.
Also, in run(), your 1st PeekMessage() to create the message queue is discarding an initial message if one is pending, that message does not get processed by your dispatch loop. That 1st call should be using the PM_NOREMOVE flag instead.
Also, be aware of the dangers of filtering window messages in your message loop.
With that said, try this instead:
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
class Window
{
private:
HWND hWnd;
HINSTANCE hInstance;
const char* ID = "WINAPI_JVM64";
public:
Window()
{
init();
}
~Window()
{
cleanup();
}
virtual void draw(Gdiplus::Graphics*) = 0;
void init()
{
hInstance = (HINSTANCE)GetModuleHandle(NULL);
WNDCLASS wc{};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = &MessageHandler;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_HAND);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = ID;
assert(RegisterClass(&wc));
hWnd = CreateWindow(ID, "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
200, 200, 400, 400, NULL, NULL, hInstance, this);
assert(hWnd != NULL);
ShowCursor(true);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
}
void cleanup()
{
UnregisterClass(ID, hInstance);
}
void run()
{
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
};
#include "Window.h"
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_NCCREATE:
{
Window *pThis = static_cast<Window*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
break;
}
// DefWindowProc(WM_CLOSE) calls DestroyWindow(),
// WM_CLOSE is not the right place to call PostQuitMessage()...
//case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
Window *pThis = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if (pThis)
{
Gdiplus::Graphics* g = Gdiplus::Graphics::FromHDC(hdc);
pThis->draw(g);
delete g;
}
EndPaint(hWnd, &ps);
return 0;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
class AppWindow : public Window
{
public:
void draw(Gdiplus::Graphics* g) override
{
Gdiplus::SolidBrush brown_brush(Gdiplus::Color(255, 128, 57, 0));
g->FillRectangle(&brown_brush, 0, 0, 200, 200);
}
};
int main()
{
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
AppWindow w;
w.run();
Gdiplus::GdiplusShutdown(gdiplusToken);
return 0;
}
I have simple application with a native winapi window, and a static control on it as a child window. I'd like to draw on the child window with Direct2D.
The drawing happens outside of the WM_PAINT message, so I decided to use ID2D1DCRenderTarget. Everything works except one thing. I can't make the drawing visible when the application starts.
If I do painting in any event (for example in WM_LBUTTONDOWN) the drawing shows up. But if I do painting in WM_CREATE I see nothing on the screen.
Here is my example code:
#include <iostream>
#include <windows.h>
#include <windowsx.h>
#include <d2d1.h>
#pragma comment(lib, "d2d1.lib")
HWND windowHandle = NULL;
HWND childWindowHandle = NULL;
ID2D1Factory* direct2DFactory = nullptr;
ID2D1DCRenderTarget* renderTarget = nullptr;
static void InitDirect2D ()
{
D2D1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, &direct2DFactory);
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
direct2DFactory->CreateDCRenderTarget (&props, &renderTarget);
renderTarget->SetAntialiasMode (D2D1_ANTIALIAS_MODE_ALIASED);
}
static void Paint ()
{
ID2D1SolidColorBrush* blackBrush = nullptr;
renderTarget->CreateSolidColorBrush (
D2D1::ColorF (D2D1::ColorF::Black),
&blackBrush
);
renderTarget->BeginDraw ();
renderTarget->SetTransform (D2D1::Matrix3x2F::Identity ());
renderTarget->Clear (D2D1::ColorF (D2D1::ColorF::LightGray));
D2D1_RECT_F rect = D2D1::RectF (10.0f, 10.0f, 100.0f, 100.0f);
renderTarget->DrawRectangle (&rect, blackBrush);
renderTarget->EndDraw ();
}
static LRESULT CALLBACK ChildWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_CREATE:
{
RECT rc;
GetClientRect (hwnd, &rc);
renderTarget->BindDC (GetDC (hwnd), &rc);
Paint ();
}
break;
case WM_LBUTTONDOWN:
Paint ();
break;
case WM_PAINT:
break;
case WM_SIZE:
{
RECT rc;
GetClientRect (hwnd, &rc);
renderTarget->BindDC (GetDC (hwnd), &rc);
Paint ();
}
break;
case WM_CLOSE:
DestroyWindow (hwnd);
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
break;
}
LRESULT res = DefWindowProc (hwnd, msg, wParam, lParam);
return res;
}
static void CreateChildWindow (HWND parentHandle)
{
WNDCLASSEX windowClass;
memset (&windowClass, 0, sizeof (WNDCLASSEX));
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = 0;
windowClass.lpfnWndProc = ChildWindowProc;
windowClass.style = CS_DBLCLKS;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = NULL;
windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = L"ChildWindowClass";
RegisterClassEx (&windowClass);
childWindowHandle = CreateWindowEx (
0, windowClass.lpszClassName, L"", WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, parentHandle, NULL, NULL, nullptr
);
ShowWindow (childWindowHandle, SW_SHOW);
UpdateWindow (childWindowHandle);
MoveWindow (childWindowHandle, 10, 10, 780, 580, TRUE);
}
static LRESULT CALLBACK MainWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_CREATE) {
CreateChildWindow (hwnd);
InvalidateRect (hwnd, NULL, FALSE);
}
switch (msg) {
case WM_SIZE:
{
int newWidth = LOWORD (lParam);
int newHeight = HIWORD (lParam);
MoveWindow (childWindowHandle, 10, 10, newWidth - 20, newHeight - 20, TRUE);
}
break;
case WM_CLOSE:
DestroyWindow (hwnd);
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
}
return DefWindowProc (hwnd, msg, wParam, lParam);
}
static int CreateMainWindow ()
{
WNDCLASSEX windowClass;
memset (&windowClass, 0, sizeof (WNDCLASSEX));
windowClass.cbSize = sizeof (WNDCLASSEX);
windowClass.style = 0;
windowClass.lpfnWndProc = MainWindowProc;
windowClass.style = CS_DBLCLKS;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = NULL;
windowClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = L"WindowClass";
windowClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
RegisterClassEx (&windowClass);
RECT requiredRect = { 0, 0, 800, 600 };
HWND windowHandle = CreateWindowEx (
WS_EX_WINDOWEDGE, windowClass.lpszClassName, L"Example", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, requiredRect.right - requiredRect.left, requiredRect.bottom - requiredRect.top, NULL, NULL, NULL, nullptr
);
if (windowHandle == NULL) {
return 1;
}
ShowWindow (windowHandle, SW_SHOW);
UpdateWindow (windowHandle);
MSG msg;
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return 0;
}
int main (int argc, char* argv[])
{
InitDirect2D ();
return CreateMainWindow ();
}
Do you have any idea how can I make the drawing visible on application startup?
During WM_CREATE window is not complitely created yet so painting does not work. You should write a proper WM_PAINT (and WM_ERASEBKGND) message handlers and perform all the painting operations there. Then when you need to redraw as a response to any other message (such as WM_LBUTTONDOWN) you need to invalidate window and trigger WM_PAINT instead of immediately calling Paint();.
I want to achieve some kind of event handling for Windows. I have a program, that has a symbol in the Notification Area (System Tray) and I want the programm to show up again, when the user clicks on the Icon. Is there a simple Way to implement that in c++ as an Event? I have only found ways to this in C#.
It is a console Application and I want to change as few things as possible. But there is no WndProc handler for Console Application as far as I can tell.
Why no WndProc? Console application is a perfect win32 application, and it can use anything which non-console application can use.
Here's a simple, but a bit long example.
#include <windows.h>
#include <shellapi.h>
#include <iostream>
#include <cstring>
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
BOOL WINAPI ConsoleRoutine(DWORD dwCtrlType);
LPCWSTR lpszClass = L"__hidden__";
int main()
{
HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASS wc;
HWND hWnd;
MSG msg;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = nullptr;
wc.hCursor = nullptr;
wc.hIcon = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpszClass;
wc.lpszMenuName = nullptr;
wc.style = 0;
RegisterClass(&wc);
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, hInstance, nullptr);
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static NOTIFYICONDATA nid;
switch (iMsg)
{
case WM_CREATE:
std::memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = hWnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_APP + 1;
nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
lstrcpy(nid.szTip, L"con-notify");
Shell_NotifyIcon(NIM_ADD, &nid);
Shell_NotifyIcon(NIM_SETVERSION, &nid);
return 0;
case WM_APP + 1:
switch (lParam)
{
case WM_LBUTTONDBLCLK:
std::cout << "notify dblclk" << std::endl;
break;
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
break;
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nid);
MessageBox(nullptr, L"asdf", L"asdf", MB_OK);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,iMsg,wParam,lParam);
}
You probably want not to mess up your console program with message loop. If so, you can put notification code into another thread.
I've made two simple classes to use for displaying UIs with Awesomium. However creating the Awesomium WebView and setting the parent window to my Win32 window causes the program to hang and the page is never displayed. The classes are simple and creating a window is simple so there isn't much I can think of that could be going wrong. Perhaps there is something else required than what I've done to display a WebView?
To clarify: Creating the Win32 window without creating the WebView works fine, the window functions including the drag code etc... The hang only happens when you call set_parent_window.
UI.h
#pragma once
#include <Windows.h>
#include <windowsx.h>
#include <Awesomium/WebCore.h>
#include <Awesomium/STLHelpers.h>
using namespace Awesomium;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
class UI
{
public:
//Window Variables
HINSTANCE instance;
HWND window;
BOOL drag_window = false;
SHORT mouse_x, mouse_y, mouse_x_prev, mouse_y_prev;
//Awesomium Variables
WebCore* webcore = 0;
WebView* webview;
static HWND InitWindow(INT width, INT height, WNDPROC callback)
{
HWND hwnd;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = callback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyUI";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
hwnd = CreateWindow("MyUI",
"",
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
NULL,
NULL,
GetModuleHandle(0),
NULL);
if (!hwnd)
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
SetTimer(hwnd, 0, 15, NULL);
return hwnd;
}
};
class LoginUI : public UI
{
public:
INT width = 600;
INT height = 600;
INT RunUI()
{
this->window = UI::InitWindow(this->width, this->height, ::LoginUICallback);
if (!this->window)
return 0;
WebConfig config;
this->webcore = WebCore::Initialize(config);
this->webview = this->webcore->instance()->CreateWebView(this->width, this->height, 0, kWebViewType_Window);
this->webview->set_parent_window(this->window);
this->webview->LoadURL(WebURL(WSLit("http://www.google.com")));
MSG msg;
while(GetMessage(&msg, this->window, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WebCore::Shutdown();
return 1;
}
}login_ui;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_TIMER:
break;
case WM_MOUSEMOVE:
{
if (login_ui.drag_window && (wParam & MK_LBUTTON))
{
// code executed when the dialog window is moved around on the screen
RECT win_rect;
GetWindowRect(hWnd, &win_rect);
int x_coord = GET_X_LPARAM(lParam);
int y_coord = GET_Y_LPARAM(lParam);
MoveWindow(hWnd,
win_rect.left + x_coord - login_ui.mouse_x_prev,
win_rect.top + y_coord - login_ui.mouse_y_prev,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
false
);
}
break;
}
case WM_LBUTTONDOWN:
{
login_ui.mouse_x = GET_X_LPARAM(lParam);
login_ui.mouse_y = GET_Y_LPARAM(lParam);
if (login_ui.mouse_y < 41)
{
login_ui.mouse_x_prev = login_ui.mouse_x;
login_ui.mouse_y_prev = login_ui.mouse_y;
SetCapture(hWnd);
login_ui.drag_window = true;
}
break;
}
case WM_LBUTTONUP:
{
if (login_ui.drag_window)
{
login_ui.drag_window = false;
ReleaseCapture();
}
break;
}
case WM_SIZE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_QUIT:
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Main.Cpp
#include "UI.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, char*, int nCmdShow)
{
login_ui.RunUI();
}
Have not used Awesomium but your GetMessage only pumps messages for the WebCore window. So instead you should pass NULL so your message pump dispatches messages for all windows created on that thread.
This code produces simple FindText dialog window and when user clicks top-right X window close button the WM_CLOSE message is send to the hook procedure, but when clicking "cancel" button no message is produced to indicate that window ceased to be.
#include <windows.h>
#include <iostream>
#include <iomanip>
UINT_PTR CALLBACK FRHookProc(HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM /*lParam*/) {
switch (uiMsg) {
case WM_INITDIALOG: {
ShowWindow(hdlg, SW_SHOW);
break;
}
}
using namespace std;
if (uiMsg == WM_CLOSE) cout << "FindTextW window has been closed";
return 0;
}
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int /* nCmdShow*/) {
using namespace std;
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = &MyWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(PVOID);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
wc.lpszMenuName = L"MainMenu";
wc.lpszClassName = L"window";
ATOM class_atom = RegisterClassExW(&wc);
HWND hWnd = CreateWindowExW(
0,
reinterpret_cast<LPCWSTR>(class_atom),
L"window title",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPCHILDREN | WS_THICKFRAME,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
WCHAR szFindWhat[MAX_PATH] = {0};
FINDREPLACEW fr;
ZeroMemory(&fr, sizeof(fr));
fr.lStructSize = sizeof(fr);
fr.hwndOwner = hWnd;
fr.lpstrFindWhat = szFindWhat;
fr.lpfnHook = FRHookProc;
fr.wFindWhatLen = MAX_PATH;
fr.Flags = FR_ENABLEHOOK;
/*HWND hdlg =*/ FindTextW(&fr);
MSG msg;
for (;;) {
GetMessageW(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
Read the documentation more carefully. You took the completely wrong approach to detecting the dialog window being closed.
FindText function:
Before calling FindText, you must call the RegisterWindowMessage function to get the identifier for the FINDMSGSTRING message. The dialog box procedure uses this identifier to send messages when the user clicks the Find Next button, or when the dialog box is closing.
FINDMSGSTRING message:
A Find or Replace dialog box sends the FINDMSGSTRING registered message to the window procedure of its owner window when the user clicks the Find Next, Replace, or Replace All button, or closes the dialog box.
...
You must specify the FINDMSGSTRING constant in a call to the RegisterWindowMessage function to get the identifier for the message sent by the dialog box.
When you create the dialog box, use the hwndOwner member of the FINDREPLACE structure to identify the window to receive FINDMSGSTRING messages.
...
The Flags member of the FINDREPLACE structure includes one of the following flags to indicate the event that caused the message.
FR_DIALOGTERM (0x00000040)
The dialog box is closing. After the owner window processes this message, a handle to the dialog box is no longer valid.
So, with that said, try this instead:
#include <windows.h>
#include <iostream>
#include <iomanip>
static const UINT uFindMsgString = RegisterWindowMessageW(L"commdlg_FindReplace");
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if ((Msg == uFindMsgString) && (Msg != 0))
{
FINDREPLACE *fr = reinterpret_cast<FINDREPLACE*>(lParam);
if (fr->flags & FR_DIALOGTERM)
{
std::cout << "FindTextW window has been closed";
PostQuitMessage(0);
}
// process other dialog notifications as needed...
return 0;
}
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int /* nCmdShow*/)
{
WNDCLASSEXW wc = {0};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = &MyWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(PVOID);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
wc.lpszMenuName = L"MainMenu";
wc.lpszClassName = L"window";
ATOM class_atom = RegisterClassExW(&wc);
HWND hWnd = CreateWindowExW(
0,
wc.lpszClassName,
L"window title",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPCHILDREN | WS_THICKFRAME,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
WCHAR szFindWhat[MAX_PATH] = {0};
FINDREPLACEW fr = {0};
fr.lStructSize = sizeof(fr);
fr.hwndOwner = hWnd;
fr.lpstrFindWhat = szFindWhat;
fr.wFindWhatLen = MAX_PATH;
HWND hdlg = FindTextW(&fr);
MSG msg;
while (GetMessageW(&msg, 0, 0, 0) > 0)
{
if (!IsDialogMessage(hdlg, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
DestroyWindow(hWnd);
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
You should be getting a WM_COMMAND notification for the cancel button's BN_CLICKED message. When 'cancel' is pressed you should get that notification for the IDCANCEL control ID.