how to accept multi thread's connection request in FD_ACCEPT? - c

If I have n Client connect the Server,how to accept it in FD_ACCEPT and how to receive it in FD_READ and how to send it in FD_WRITE and not use like this form
e.p.
while(1){
ClientSocket=accept(ListenSocket,0,0);
if(ClientSocket!=INVALID_SOCKET)
_beginthreadex();
}
how to achieve it in this form
case WM_SERVER_SOCKET:
wEvent = WSAGETSELECTEVENT(lParam);//LOWORD
switch (wEvent) {
case FD_ACCEPT:
ClientSocket=accept(ListenSocket, nullptr, nullptr);
break;
case FD_READ:
break;
case FD_WRITE:
break;
case FD_CLOSE:
break;
}
break;
or this form just can handle one Client connection?
is it necessary do it in this form?
I want use it for a simple chat application

WSAAsyncSelect() is what you are looking for, eg:
WNDCLASS cls = {0};
cls.lpfnWndProc = &SocketWndProc;
cls.hInstance = ...;
cls.lpszClassName = TEXT("MySocketWnd");
RegisterClass(&cls);
HWND hWnd = CreateWindowEx(0, cls.lpszClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, cls.hInstance, nullptr);
SOCKET ListenSocket = socket(...);
bind(ListenSocket, ...);
listen(ListenSocket, ...);
WSAAsyncSelect(ListenSocket, hWnd, WM_SERVER_SOCKET, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
closesocket(ListenSocket);
DestroyWindow(hWnd);
LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg != WM_SERVER_SOCKET)
return DefWindowProc(hWnd, uMsg, wParam, lParam);
SOCKET sckt = (SOCKET) wParam;
WORD wEvent = WSAGETSELECTEVENT(lParam);
WORD wError = WSAGETSELECTERROR(lParam);
if (wError != 0)
{
// wEvent on sckt failed, do something ...
return 0;
}
switch (wEvent)
{
case FD_ACCEPT:
{
// sckt has a pending client...
SOCKET ClientSocket = accept(sckt,...);
// do something with new client (add it to a tracking list, etc) ...
break;
}
case FD_READ:
{
// sckt has pending data...
int numBytes = recv(sckt, ...);
// process data as needed...
break;
}
case FD_WRITE:
{
// sckt can receive data, send any pending data ...
break;
}
case FD_CLOSE:
{
// sckt has disconnected, do something (remove it from list, etc)...
break;
}
}
return 0;
}

Related

Message queue for two cpp file with windows API

To send the message in the Queue from one source file and get the message in another source file.I read the docs from Microsoft and try to implement as below
test2.c - post the message
main.c - get the Message
Testing1: If i execute the same code in single file that get executed and i receive the data
Testing : Same code is written in two separate file "if (msg.message == WM_YOUR_MESSAGE)" these statement does not get satisfied.
test2.h
typedef struct
{
int SomeData1;
int SomeData2;
int SomeDataN;
} MessageData;
/* Unique IDs for Window messages to exchange between the worker and the
GUI thread. */
#define WM_YOUR_MESSAGE ( WM_USER + 3 )
void __cdecl ThreadProc(void* aArg);
test2.c
#include <windows.h>
#include <process.h>
#include "malloc.h"
#include <stdio.h>
#include <test2.h>
volatile DWORD ThreadID_GUI;
void __cdecl ThreadProc(void* aArg)
{
MessageData* data;
for (;; )
{
Sleep(500);
/* Allocate memory for a new message data structure */
data = (MessageData*)malloc(sizeof(*data));
/* Initialize the message data structure with some information to transfer
to the GUI thread. */
data->SomeData1 = 1234;
data->SomeData2 = 4567;
data->SomeDataN = 7894;
PostThreadMessage(ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data);
}
}
main.c
#include <windows.h>
#include <tchar.h>
#include <process.h>
#include "malloc.h"
#include "stdio.h"
#include<test2.h>
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
ThreadID_GUI = GetCurrentThreadId();
/* Start some background thread */
_beginthread(ThreadProc, 0, 0);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_TESTMESSAGEQUEUE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTMESSAGEQUEUE));
MSG msg;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
/* STEP 3: React on the message sent from the foreign thread */
if (msg.message == WM_YOUR_MESSAGE)
{
MessageData* tmp = (MessageData*)msg.lParam;
if (tmp->SomeData1 == 1234) {
printf("someData\n");
}
/* Free the data structure associated to the message */
free(tmp);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance,
MAKEINTRESOURCE(IDI_CLIENTMQ));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_CLIENTMQ);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance,
MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance,
nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd,
About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM
lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
After filling all the missing information in your source, and removing useless code, I have your code working.
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include "test2.h"
HINSTANCE hInst;
LPCWSTR szWindowClass = L"Piu";
LPCWSTR szTitle = L"Title";
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
/*
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd,
About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
*/
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
ZeroMemory(&wcex, sizeof(wcex));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
/*
wcex.hIcon = LoadIcon(hInstance,
MAKEINTRESOURCE(IDI_CLIENTMQ));
wcex.hIconSm = LoadIcon(wcex.hInstance,
MAKEINTRESOURCE(IDI_SMALL));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_CLIENTMQ);
*/
wcex.lpszClassName = szWindowClass;
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance,
NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
ThreadID_GUI = GetCurrentThreadId();
/* Start some background thread */
_beginthread(ThreadProc, 0, 0);
// Initialize global strings
// LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
// LoadStringW(hInstance, IDC_TESTMESSAGEQUEUE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
// HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTMESSAGEQUEUE));
MSG msg;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
/* STEP 3: React on the message sent from the foreign thread */
if (msg.message == WM_YOUR_MESSAGE)
{
MessageData* tmp = (MessageData*)msg.lParam;
if (tmp->SomeData1 == 1234) {
printf("someData\n");
}
/* Free the data structure associated to the message */
free(tmp);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
test2.c:
#include <Windows.h>
#include "test2.h"
volatile DWORD ThreadID_GUI;
void __cdecl ThreadProc(void* aArg)
{
MessageData* data;
for (;; )
{
Sleep(500);
/* Allocate memory for a new message data structure */
data = (MessageData*)malloc(sizeof(*data));
/* Initialize the message data structure with some information to transfer
to the GUI thread. */
data->SomeData1 = 1234;
data->SomeData2 = 4567;
data->SomeDataN = 7894;
PostThreadMessage(ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data);
}
}
test2.h
typedef struct
{
int SomeData1;
int SomeData2;
int SomeDataN;
} MessageData;
/* Unique IDs for Window messages to exchange between the worker and the
GUI thread. */
#define WM_YOUR_MESSAGE ( WM_USER + 3 )
void __cdecl ThreadProc(void* aArg);
extern volatile DWORD ThreadID_GUI;
I removed menu and icons so there is no .rc file.

Custom WM_APP message isn't posted in the message queue

I am trying to send a custom message (WM_APP + 1) when WM_SIZE is send to the window procedure. I want to be able to catch it from an other function using PeekMessage and do somethings. But when I test it the messages seem to not be send to the queue. Adding some printf statements shows me that it goes to the window procedure. The weird thing is that when I step through the code in the debugger it works fine but when I'm running normally, it goes back to not working.
Working example program with the problem, resize the window to test:
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")
#define OBG_EVENT_QUIT 0
#define OBG_EVENT_RESIZE 1
#define OBG_EVENT_NO -1
#define OBG_EVENT_UNKNOWN -2
//user defined event
#define OBG_WM_RESIZE (WM_APP + 1)
typedef union
{
int type;
struct
{
int type;
int width;
int height;
} resizeEvent;
} obg_event;
LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch(message)
{
case WM_CLOSE:
{
PostMessageA(window, WM_QUIT, 0, 0);
} break;
//this should be handled by OBGGetEvent
case OBG_WM_RESIZE:
{
printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
} break;
case WM_SIZE:
{
PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
} break;
default:
{
result = DefWindowProc(window, message, wParam, lParam);
} break;
}
return result;
}
int OBGGetEvent(obg_event *event)
{
int moreMessages = 0;
MSG message;
if(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
{
moreMessages = 1;
switch(message.message)
{
case WM_QUIT:
{
event->type = OBG_EVENT_QUIT;
} break;
case OBG_WM_RESIZE:
{
event->type = OBG_EVENT_RESIZE;
event->resizeEvent.type = OBG_EVENT_RESIZE;
event->resizeEvent.width = LOWORD(message.lParam);
event->resizeEvent.height = HIWORD(message.lParam);
} break;
default:
{
event->type = OBG_EVENT_UNKNOWN;
TranslateMessage(&message);
DispatchMessage(&message);
} break;
}
}
else
{
event->type = OBG_EVENT_NO;
}
return moreMessages;
}
int main()
{
HINSTANCE instance = GetModuleHandleA(0);
WNDCLASSEX windowClass = {0};
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = obgpf_DefaultWindowCallback;
windowClass.hInstance = instance;
windowClass.lpszClassName = "testClass";
windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
windowClass.hCursor = LoadCursorA(0, IDC_ARROW);
HWND window;
if(RegisterClassEx(&windowClass))
{
window = CreateWindowEx(0,
windowClass.lpszClassName,
"test window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
300,
0,
0,
instance,
0);
if(window)
{
int appIsRunning = 1;
obg_event event = {0};
event.type = -1;
while(appIsRunning)
{
while(OBGGetEvent(&event))
{
if(event.type == OBG_EVENT_QUIT)
{
printf("event quit\n");
appIsRunning = 0;
break;
}
else if(event.type == OBG_EVENT_RESIZE)
{
printf("window resized: width %d height %d\n", event.resizeEvent.width, event.resizeEvent.height);
}
}
Sleep(33);
}
}
else
{
printf("window error\n");
}
}
else
{
printf("windowClass error\n");
}
return 0;
}
I tried doing this with SendMessage instead of PeekMessage but the same thing happened. Not sure what I'm missing or misunderstanding but any help is appreciated!
EDIT: added a complete working program that reproduces the problem
Thank you for the example code.
The behaviour you're seeing is because when the window is being resized using the mouse, the OS enters a modal message loop to process mouse input. During this loop, your message loop doesn't run - which means your PeekMessage() and the special message handling doesn't run either. Instead, messages are simply dispatched as normal to your window procedure.
There are two solutions that come to mind immediately but how you deal with this really depends on the design of your program and why you want to process size events in this way.
The first idea I had is to keep track of whether you're in a modal sizing loop or not, and defer posting the notification message until the loop is finished. An example of how to do that using your provided window procedure is below.
The second solution is to simply call your resize event handler directly whenever you get WM_SIZE (or, if you must go through the event system, put the handler for it in the window procedure rather than using PostMessage).
Example code for the first suggestion:
LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
static bool fResized = false;
static bool fInSizeLoop = false;
switch(message)
{
case WM_CLOSE:
{
PostMessageA(window, WM_QUIT, 0, 0);
} break;
//this should be handled by OBGGetEvent
case OBG_WM_RESIZE:
{
printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
} break;
case WM_SIZE:
{
if (fInSizeLoop) // in modal size loop, defer notification
fResized = true;
else
PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
} break;
case WM_ENTERSIZEMOVE:
fInSizeLoop = true; // begin modal size loop
break;
case WM_EXITSIZEMOVE:
fInSizeLoop = false; // left modal size loop
// post resize notification now
if (fResized) {
RECT rc;
GetClientRect(window, &rc);
PostMessageA(window, OBG_WM_RESIZE, 0, MAKELPARAM(rc.right - rc.left, rc.bottom - rc.top));
fResized = false;
}
break;
default:
{
result = DefWindowProc(window, message, wParam, lParam);
} break;
}
return result;
}
(sorry, this is C++ code and I just noticed you had tagged as C - but the principle is the same).

how to handle WM_NCHITTEST in a naked event loop?

I'm playing with Windows API trying to understand how it behaves, and I realized that I can remove WNDPROC altogether and handle things with a naked event loop, like this:
#include <Windows.h>
static struct {
HWND desktop;
HWND window;
} global;
int main(int argc, char **argv)
{
/* anonymous scope: register window class */
{
WNDCLASSEXW wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = DefWindowProc;
wcx.cbClsExtra = sizeof(void *);
wcx.cbWndExtra = sizeof(void *);
wcx.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = L"MyWindow";
wcx.hIconSm = wcx.hIcon;
RegisterClassExW(&wcx);
}
global.desktop = GetDesktopWindow();
global.window = CreateWindowExW (
0,
L"MyWindow",
NULL,
WS_POPUPWINDOW | WS_VISIBLE,
0,
0,
320,
200,
global.desktop,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL
);
/* anonymous scope, event loop */
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
if(msg.hwnd == global.window) {
if (msg.message == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(msg.hwnd, &ps);
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Rectangle(hdc, 0, 0, 320, 200);
EndPaint(msg.hwnd, &ps);
} else {
DispatchMessage(&msg);
}
} else {
DispatchMessage(&msg);
}
}
}
return 0;
}
I wanted to go one step further and try making this window moveable using this technique, and got confused because I can't "return" from a message loop in the way i'm used to(the statement return hit;) does not make sense in this context.
Here is how I started, and got confused:
#include <Windows.h>
static struct {
HWND desktop;
HWND window;
} global;
int main(int argc, char **argv)
{
/* anonymous scope: register window class */
{
WNDCLASSEXW wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = DefWindowProc;
wcx.cbClsExtra = sizeof(void *);
wcx.cbWndExtra = sizeof(void *);
wcx.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = L"MyWindow";
wcx.hIconSm = wcx.hIcon;
RegisterClassExW(&wcx);
}
global.desktop = GetDesktopWindow();
global.window = CreateWindowExW (
0,
L"MyWindow",
NULL,
WS_POPUPWINDOW | WS_VISIBLE,
0,
0,
320,
200,
global.desktop,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL
);
/* anonymous scope, event loop */
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
if(msg.hwnd == global.window) {
if (msg.message == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(msg.hwnd, &ps);
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Rectangle(hdc, 0, 0, 320, 200);
EndPaint(msg.hwnd, &ps);
} else if (msg.message == WM_NCHITTEST) {
LRESULT hit = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
if (hit == HTCLIENT) {
hit = HTCAPTION;
}
// return hit; // makes no sense here
} else {
DispatchMessage(&msg);
}
} else {
DispatchMessage(&msg);
}
}
}
return 0;
}
How can I simulate returning "hit" from the WM_NCHITTEST condition so that it moves the window like in the solution here: https://stackoverflow.com/a/7773941/2012715 ?
PS: I know that it's better to use a map(like std::unordered_map) rather than a long if/switch for scalability and readability, but I wanted to keep the example more direct.
You can't.
The code you have shown will NEVER work, because (Get|Peek)Message() returns only QUEUED messages. You cannot reply to a queued message, because the sender is not waiting for a reply, it put the message in the queue and moved on to other things. Only NON-QUEUED messages that are sent with the SendMessage...() family of functions can be replied to. (Get|Peek)Message() will NEVER return a sent message, but will internally dispatch it to the target window's message procedure (only messages sent from another thread will be dispatched, messages sent to a window by the same thread that owns the window will bypass the message queue completely).
WM_PAINT is a queued message, so your event loop sees it. But WM_NCHITTEST is not queued, so your message loop will NEVER see it directly, it can only be seen in a message procedure.
What you have shown is NOT the right way to handle a Windows UI message loop. Since you are creating a UI window, you MUST provide it with a message procedure (if not by RegisterClass/Ex(), then by SetWindowLong/Ptr(GWL_WNDPROC) or SetWindowSubclass()). But DO NOT use DefWindowProc() for that procedure if you need to process messages manually. Provide your own message procedure that calls DefWindowProc() (or CallWindowProc() in the case of GWL_WNDPROC, or DefSubclassProc() in the case of SetWindowSubclass()) for any unhandled messages, eg:
LRESULT WINAPI MyWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Rectangle(hdc, 0, 0, 320, 200);
EndPaint(hwnd, &ps);
return 0;
}
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hwnd, uMsg, wParam, lParam);
if (hit == HTCLIENT) {
hit = HTCAPTION;
}
return hit;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int main(int argc, char **argv)
{
/* anonymous scope: register window class */
{
WNDCLASSEXW wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = MyWndProc; // <--
wcx.cbClsExtra = sizeof(void *);
wcx.cbWndExtra = sizeof(void *);
wcx.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = L"MyWindow";
wcx.hIconSm = wcx.hIcon;
RegisterClassExW(&wcx);
}
global.desktop = GetDesktopWindow();
global.window = CreateWindowExW (
0,
L"MyWindow",
NULL,
WS_POPUPWINDOW | WS_VISIBLE,
0,
0,
320,
200,
global.desktop,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL
);
/* anonymous scope, event loop */
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}

Memory increases every time I resize the window

I have created a simple Win32 Application and try to fill the Client Area with a Color. When the line "Clear RenderTarget" is included I see that the memory increases a few KB every time I resize the window.
My WindowProc:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
{
if (pRenderTarget != NULL)
{
RECT rc;
GetClientRect(globalWindowHandle, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
pRenderTarget->Resize(size);
InvalidateRect(globalWindowHandle, NULL, FALSE);
}
return 0;
}
break;
case WM_CREATE:
{
HRESULT dx = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory);
if (FAILED(dx))
{
MessageBox(globalWindowHandle, "Error creating D2D1Factory", "Error", MB_ICONERROR);
return -1;
}
return 0;
}
break;
case WM_KEYDOWN:
{
int ret = HandleKeyboardInput(uMsg, wParam, lParam);
if (ret == 0)
{
return 0;
}
}
break;
case WM_PAINT:
{
HRESULT hr = CreateGraphicsResources();
if (SUCCEEDED(hr))
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
pRenderTarget->BeginDraw();
// Clear RenderTarget
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
hr = pRenderTarget->EndDraw();
if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
{
pRenderTarget->Release();
pSolidBrush->Release();
pRenderTarget = NULL;
pSolidBrush = NULL;
}
EndPaint(hwnd, &ps);
return 0;
}
}
break;
case WM_CLOSE:
{
int box = MessageBox(hwnd, "Would you like to close the editor ?", "Question", MB_OKCANCEL);
if (box == IDOK)
{
DestroyWindow(hwnd);
}
return 0;
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
default:
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
break;
}
return 0;
}
CreateGraphicsResources
HRESULT CreateGraphicsResources()
{
HRESULT hr = S_OK;
if (pRenderTarget == NULL)
{
RECT rc;
GetClientRect(globalWindowHandle, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
hr = pFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(globalWindowHandle, size),
&pRenderTarget);
if (SUCCEEDED(hr))
{
const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 1.0f, 0);
hr = pRenderTarget->CreateSolidColorBrush(color, &pSolidBrush);
if (SUCCEEDED(hr))
{
}
}
}
return hr;
}
Globals:
BOOL ctrlPressed = FALSE;
HWND globalWindowHandle;
ID2D1Factory *pFactory;
ID2D1SolidColorBrush *pSolidBrush;
ID2D1HwndRenderTarget *pRenderTarget;
Do I miss something to free up memory or what could be the reason? If I resize the window e.g. 5 sec the memory goes from 4KB up to 22KB.
My OS is Windows 10 x64
The issue seems to be solved. In fact the memory did not go up much more so it seems the OS assigns the other memory.

My Win32 application won't exit the main loop

This is my main loop:
while(TRUE)
{
PeekMessage(&msg,hWnd,0,0,PM_REMOVE);
if (msg.message==WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
and this is my callback procedure:
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg1,WPARAM wParam,LPARAM lParam)
{
switch(msg1)
{
case WM_DESTROY :
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd,msg1,wParam,lParam);
}
I found out that when I press Close button WM_NCLBUTTONDOWN will be returned by the PeekMessage function in the next loop, and no WM_QUIT!
The correct way to do a message loop is
BOOL bRet;
MSG msg;
while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
You can use PeekMessage if you really need to... but why are you ignoring the return value?
Also, note that this is specific to a window. I believe PostQuitMessage is for a thread... I don't remember it off the top of my head, but you might need to pass NULL instead of hWnd.
If you have any other windows, that may hijack their message loop as well -- I don't think it's usually an issue, but it might potentially be one; keep that in mind.
Here's some code I found. It should give you something to work with.
// Main message loop:
do
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Run game code here.
gTradeApp->ExecuteNextAction();
}
while (msg.message != WM_QUIT);
and the WndProc
LRESULT CALLBACK WndProc(HWND aHWnd, UINT aMessage, WPARAM aWParam, LPARAM aLParam)
{
switch (aMessage)
{
case WM_COMMAND:
return HandleCommand(aHWnd, aMessage, aWParam, aLParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(aHWnd, aMessage, aWParam, aLParam);
}
return 0;
}
I recommend sticking with this, to ensure errors (-1) returned by GetMessage can be handled properly:
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
Also, another error is not handling WM_CLOSE properly. Try this instead to make your program actually listen to WM_CLOSE (the close button):
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch(Message) {
case WM_CLOSE: {
DestroyWindow(hwnd); // this
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}

Resources