How to SendMessage - c++

I have a problem. I want in my program(follow code) have 2 windows: console and empty form to output graphics. And from my func main send messages to form to draw shapes. Input data to console. But func SendMessage() doesn't work. What wrong?
int main()
{
char szClassName[] = "CG_WAPI_Template";
HWND hWnd = GetConsoleWindow();
HINSTANCE hInstance = NULL;
MSG lpMsg;
if(!AllocConsole())
MessageBox(NULL, "Failed to create the console!", "Ошибка", MB_ICONEXCLAMATION|MB_OK);
void *h_inc = GetStdHandle(STD_INPUT_HANDLE);
void *h_out = GetStdHandle(STD_OUTPUT_HANDLE);
WNDCLASS wc;
/*wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
...
*/
if(!RegisterClass(&wc))
{MessageBox(NULL, "Не могу зарегистрировать класс окна!", "Ошибка", MB_OK);
return 0;
}
hWnd = CreateWindow(...);
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
char buf[2];
unsigned long lengh;
ReadConsole(h_inc,buf,1,&lengh,NULL);
SendMessage(hWnd, WM_USER+2, 0, 0);
if(GetMessage(&lpMsg, NULL, 0, 0))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
ReadConsole(h_inc,buf,1,&lengh,NULL);
if (!FreeConsole())
MessageBox(NULL, "Could not free the console!", "Ошибка", MB_OK);
return 0;
}
Thank you.

SendMessage function does not return until the message is processed by the window. You need to have an event loop in order to handle messages. Look fo r a tutorial here.
In your event loop you will have to handle messages for two windows: for the console window and for the GUI winodow. For the console messages you will need to handle the key press events, and send your custom message (WM_USER + X) to the GUI window.

Related

Polling Windows native window events in a separate thread

I need a Windows native window handle for a renderer, but I'm struggling to poll events correctly.
First, I create a window, which works fine on its own:
WNDPROC Window::MakeWindow( LPCWSTR _title, unsigned int _width, unsigned int _height ) {
HINSTANCE hInstance = GetModuleHandle( NULL );
HWND hwnd;
//Step 1: Registering the Window Class
m_WindowClass.cbSize = sizeof(WNDCLASSEX);
m_WindowClass.style = 0;
m_WindowClass.lpfnWndProc = WindowProc;
m_WindowClass.cbClsExtra = 0;
m_WindowClass.cbWndExtra = 0;
m_WindowClass.hInstance = hInstance;
m_WindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
m_WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
m_WindowClass.lpszMenuName = NULL;
m_WindowClass.lpszClassName = (LPCWSTR)g_szClassName;
m_WindowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&m_WindowClass))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
0, // Optional window styles.
(LPCWSTR)g_szClassName, // Window class
_title, // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT,
_width, _height,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if(hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, 1);
UpdateWindow(hwnd);
PollEvents();
return NULL;
}
After creating the window, I want to check for user inputs. In the code snippets I copied, they did it like this:
void PollEvents() {
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
But, since this blocks my code, I tried using a separate thread to do this. So, at the end of my window creation, I create a thread like so:
m_PollThread = new std::thread(PollEvents);
To test if it's working, I wrote this main() function:
int main() {
// poll thread is created here
Window* window = new Window( "Test Window", 1024, 720 );
while (true) {
Sleep(10);
};
// poll thread is closed/awaited here
delete window;
}
But, the window ends up frozen, so just the while loop is executed while the other thread seems to do nothing.
Only the thread that creates a window can receive messages for that window. You cannot create a window in one thread and then receive messages for that window in another thread.
GetMessage() blocks until it receives a message, so your code freezes because you are calling GetMessage() in a thread that has no window to receive messages for, and the thread that created the window is not processing any messages for that window.
So, if you want to poll events periodically, in the creating thread, without blocking your code, use PeekMessage() instead of GetMessage(), eg:
void PollEvents() {
MSG Msg;
while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
Otherwise, you will have to move both the window creation and the event loop into your worker thread.

If a cursor is not defined at window creation, why does Windows load a default cursor only when the user hovers over the frame or titlebar?

Experimenting with attempts to create a Win32 window with minimal code I discovered a strange (perhaps undocumented) behavior. If the programmer omits defining a cursor in the WNDCLASSEX struct or defines the cursor as:
WNDCLASSEX wc
...
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
The window will be displayed but never activate unless the user hovers the mouse over a border or the title bar. I found out that Windows was constantly sending WM_SETCURSOR messages as well as the normal messages expected during application startup and window creation when over the client area. I never noticed this in the past until I created a window that was initially borderless. That window displayed a continuous "wait" cursor (spinning circle). This behaviour can be reproduced with the following code. Since I could not find any explanation on MSDN or other sites, I just wanted to put this out there for others to find. To see this, run this code and make sure the cursor is over the client area when the window is created.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
int main(int argc, char** argv)
{
HINSTANCE hinstance(GetModuleHandleW(0));
WNDCLASSEXW wc({ 0 });
wc.cbSize = sizeof(WNDCLASSEXW);
//wc.style = CS_HREDRAW | CS_VREDRAW;// | CS_OWNDC; // unneeded
wc.lpszClassName = L"classname";
wc.lpfnWndProc = WndProc;
wc.hInstance = hinstance;
//wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1); // unneeded
//wc.hIcon = LoadIconW(0, IDI_APPLICATION); // unneeded
//wc.hIconSm = wc.hIcon; // unneeded
//wc.hCursor = LoadCursorW(hinstance, IDC_ARROW); // will not activate properly
//wc.hCursor = LoadCursorW(0, IDC_ARROW); // needed for proper activation
if (!RegisterClassExW(&wc)) {
DWORD err = GetLastError();
return -1;
}
DWORD style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
HWND handle = CreateWindowExW(0, L"classname", L"Test Window"
, style, CW_USEDEFAULT, CW_USEDEFAULT
, CW_USEDEFAULT, CW_USEDEFAULT, 0
, (HMENU)0, hinstance, 0);
if (!handle)
return -1;
MSG msg;
while (1) {
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
return ((int)msg.wParam);
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return 0;
}

Why is this call to CreateWindow failing, and how can I fix it?

I'm following a tutorial for directx12 and can't even get over the creation of window D: There is an implemented error window which tells me that there was an error when creating the window i actually want to create.
It's supposed to mean that it was "unsuccessful in getting a window handle"...
I don't have anything as much as a clue of what that would mean but i would GREATLY appreciate some help about that.
#include "stdafx.h"
//Handle to the window
HWND hwnd = NULL;
//Name of the window
LPCTSTR WindowName = L"GameEngineApp";
//Title of the window
LPCTSTR WindowTitle = L"My Game Engine";
//Width and height of the window
int Width = 800;
int Height = 600;
//Toggle for fool screen
bool FullScreen = false;
//Toggle for window creation
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd, int width, int height, bool fullscreen);
//Main application loop
void mainLoop()
{
//The message var hold any windows message received through the
//PeekMessage function
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//If there is a message, it is translated
//then dispatched so Windows
//knows the program hasn't stopped working
if (msg.message = WM_QUIT) {
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
//If there is no message the game
//code will run and the loop will continue
}
}
}
}
//Callback function for windows messages
LRESULT CALLBACK WndProc(HWND hWnd,
UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) {
if (MessageBox(0, L"Are you sure you want to exit?",
L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES)
DestroyWindow(hwnd);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,
msg, wParam, lParam);
}
//Main Windows function
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
//Toggle window creation
if (!InitializeWindow(hInstance, nShowCmd, Width, Height, FullScreen))
{
MessageBox(0, L"Window Initialization - Failed",
L"Error", MB_OK);
return 0;
}
mainLoop(); //Call main loop to start
return 0;
}
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd, int width, int height, bool fullscreen)
{
//Check if fullscreen is needed and set to fullscreen if so
if (fullscreen)
{
HMONITOR hmon = MonitorFromWindow(hwnd,
MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(hmon, &mi);
width = mi.rcMonitor.right - mi.rcMonitor.left;
height = mi.rcMonitor.bottom - mi.rcMonitor.top;
}
//Window class structure
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
wc.lpszMenuName = NULL;
wc.lpszClassName = WindowName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
//Registering the window class
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Error registering class",
L"Error", MB_OK | MB_ICONERROR);
return false;
}
//Create the window with the now registered window class
hwnd = CreateWindowEx(NULL,
WindowName,
WindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
NULL,
NULL,
hInstance,
NULL);
//Return error msg if unsuccessful in getting a window handle
if (!hwnd)
{
MessageBox(NULL, L"Error creating window",
L"Error", MB_OK | MB_ICONERROR);
return false;
}
//Removing the style from the window when fullscreen
if (fullscreen)
{
SetWindowLong(hwnd, GWL_STYLE, 0);
}
//Showing and updating the window
ShowWindow(hwnd, ShowWnd);
UpdateWindow(hwnd);
return true;
}
I've tried to change CreateWIndowEx to CreateWindowA and that's really the only thing that seemed to possibly have an effect but i did not see any results.
I've tried printing the error but there is no error.
Creating a window in Windows with the C++ code so i can make a game engine.
Though shalt not abuse global variables.
You're calling DefWndProc in your WndProc with hwnd as the handle argument. But that isn't set until the return of CreateWindowEx, and there are plenty very important messages that are rifled through WndProc during window stand-up. Those messages need the window handle, and you're not passing it along. Instead you're just passing NULL (the startup value of hwnd).
Change all hwnd to hWnd (the parameter name) in your WndProc
The remainder of the problems mentioned in comments I leave for you to address.

Handling the focusing click using Raw Input

I wish to handle mouse clicks in my game with the Raw Input API using the WM_INPUT messages.
I'm only interested in the mouse clicks while my app is active.
When the window is inactive and I click into the window putting it in focus no WM_INPUT message is generated for that click. I can handle every other click except the one that brings my window to focus.
With the RIDEV_INPUTSINK flag I can catch that one missing event but then I would have to somehow ignore every other message that I get while my app is inactive.
Most apps and windowed programs process the "activating click" just like a normal one, they don't ignore it. They probably use the "legacy" messages, as they arrive correctly.
Should I mix raw input with the legacy mouse handling? Should I use INPUTSINK flag and ignore messages selectively? If so, how?
Since Microsoft recommends raw input for games, I hope there is a common solution to this problem that I just couldn't find so far.
Relevant snippet from code:
Registering the raw input device
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = 0; // adds HID mouse
Rid[0].hwndTarget = 0;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]))
For convenience here's a full sample program that showcases my problem.
#include <windows.h>
#include <strsafe.h>
const char g_szClassName[] = "myWindowClass";
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_INPUT:
{
UINT dwSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize,
sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
{
return 0;
}
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize)
OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));
RAWINPUT* raw = (RAWINPUT*)lpb;
size_t const cchDest = 1000;
TCHAR pszDest[cchDest];
if (raw->header.dwType == RIM_TYPEMOUSE && raw->data.mouse.ulButtons)
{
auto hResult = StringCchPrintf(pszDest, STRSAFE_MAX_CCH, TEXT("Mouse: usFlags=%04x ulButtons=%04x usButtonFlags=%04x usButtonData=%04x ulRawButtons=%04x lLastX=%04x lLastY=%04x ulExtraInformation=%04x\r\n"),
raw->data.mouse.usFlags,
raw->data.mouse.ulButtons,
raw->data.mouse.usButtonFlags,
raw->data.mouse.usButtonData,
raw->data.mouse.ulRawButtons,
raw->data.mouse.lLastX,
raw->data.mouse.lLastY,
raw->data.mouse.ulExtraInformation);
if (FAILED(hResult))
{
// TODO: write error handler
}
OutputDebugString(pszDest);
}
delete[] lpb;
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
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_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = 0; // adds HID mouse
Rid[0].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
UPDATE
For now I found a workaround by mixing legacy and raw input. In the WM_ACTIVATE message I check if the wParam is 2. If so it means that the window was activated using a mouse click.
In this case I actually process the next WM_LBUTTONDOWN, but only one time (and the other buttons as well).
This is a terrible hack so I'm still looking for a proper solution.

c++ / application with multiple separate windows

So i have this code that creates two windows:
WNDCLASS wc;
wc.style = CS_BYTEALIGNCLIENT | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = StaticWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = nullptr;
wc.lpszClassName = _T("Move Engine");
RegisterClass(&wc);
m_hWnd = CreateWindow("Move Engine", "Move Engine", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, usWidth, usHeight, nullptr, nullptr, wc.hInstance, this);
// Create the settings window
wc.lpszClassName = _T("Settings");
RegisterClass(&wc);
s_hWnd = CreateWindow("Settings", "Settings", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 20, nullptr, nullptr, wc.hInstance, this);
ShowWindow(m_hWnd, SW_SHOW);
ShowWindow(s_hWnd, SW_SHOW);
The problem is, application terminates each time i close one of the windows. What i need is two separate windows; main application window and the one that gives access to various settings of the application - therefore closing the settings window should not affect the main window. Is there any way to achieve this? Thank you.
P.S. My WinMain function is modified like this:
int WINAPI WinMain(HINSTANCE a_hInstance, HINSTANCE a_hPrevInstance, LPTSTR a_lpCmdLine, int a_iCmdShow)
{
int iReturnCode;
// Initialise the engine.
if (!MyEngine.InitInstance(a_hInstance, a_lpCmdLine, a_iCmdShow)) return 0;
// Begin the gameplay process and return when the application due to exit
iReturnCode = MyEngine.StartEngine();
// Return the correct exit code.
return iReturnCode;
}
and StaticWndProc looks like this:
LRESULT CALLBACK CMoveEngine::StaticWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
// If this is a create message, trap the 'this' pointer passed in and store it within the window.
if (Message == WM_CREATE) SetWindowLong(hWnd, GWL_USERDATA, (LONG)((CREATESTRUCT FAR *)lParam)->lpCreateParams);
// Obtain the correct destination for this message
CMoveEngine *Destination = (CMoveEngine*)GetWindowLong(hWnd, GWL_USERDATA);
// If the hWnd has a related class, pass it through
if (Destination) return Destination->DisplayWndProc(hWnd, Message, wParam, lParam);
// No destination found, defer to system...
return DefWindowProc(hWnd, Message, wParam, lParam);
}
Message loop:
int CMoveEngine::StartEngine()
{
MSG msg;
// Start main loop
while (true)
{
// Did we recieve a message, or are we idling?
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage (&msg);
}
else
{
}
}
return 0;
}
You register both window classes with the same lpfnWndProc. Thus, all the messages (including mouse clicks and keyboard presses) will be directed to the same function, StaticWndProc.
Thus, when this function receives the WM_CLOSE message, it will respond by destroying the window, which stops the message pump and terminates the program. Since both windows have the same message handler function, they will both respond in the same way.
The solution is to define two different WndProc methods, one for each of your windows, or special-case the handling of the WM_CLOSE message, only calling DefWindowProc for the window that you want to allow to close the entire application.
Make your StaticWndProc handle either WM_CLOSE or WM_DESTROY: In that case it should decrement an openedWindows-counter. If that counter reaches zero call PostQuitMessage.