C++ How does Allegro or SDL create window? - c++

How does Allegro or SDL create window for Windows and how to do it by myself?
I'm trying to write WinApi wrapper for games, but I'm completly lost, when I see basic WinApi template and want to wrap it to something like this
init();
while()
{
update();
}
exit();

They use CreateWindowEx. A really simple WinAPI app that creates a window looks a little like this:
#include <Windows.h>
// If you're using MSVC, this is the easiest HINSTANCE. Other compilers
// get it from WinMain and pass in to constructor.
extern "C" IMAGE_DOS_HEADER __ImageBase;
HINSTANCE hInstance = (HINSTANCE)&__ImageBase;
class Window {
HWND hWnd;
static LRESULT __stdcall WindowProc(
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (Window* ptr = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA)))
return ptr->DoMessage(hWnd, message, wParam, lParam);
else
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT DoMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
public:
bool DoMessages() {
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
// Translate the message and dispatch it to WindowProc()
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT) {
return false;
}
return true;
}
Window() {
WNDCLASSEX wc;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
RegisterClassEx(&wc);
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Wide::Development", // title of the window
WS_OVERLAPPEDWINDOW, // window style. Always windowed for now.
0, // x-position of the window
0, // y-position of the window
1, // width of the window
1, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL);
ShowWindow(hWnd, SW_MAXIMIZE); // Snap our window to the user's desktop res, minus taskbar etc.
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // Make sure that our WindowLongPtr is updated.
}
};
int main() {
Window window;
while(window.DoMessages()) {
// Do app updates, or sleep() if you're mostly waiting on user input
Sleep(50);
}
// When DoMessages() returns false, the window was destroyed, so return.
}
You can look up the MSDN documentation for more information on what these functions do. Essentially, all it does is create a very simple maximized non-fullscreen window, register for input, and when the window is destroyed, quit the application. You'll notice that I actually forwarded the input to the Window object, so this most basic of all frameworks is object-orientated and you can play with inheritance here if you want, just don't forget that the WindowLongPtr functions use a void* and are not type safe.
It's also worth mentioning that on some compilers like MSVC, if you #include <Windows.h>, they expect for you to use the WinMain entry point, not main().
The game rendering and update code is typically miles more complex and difficult than the WinAPI, so I'd grab a book on DirectX9.0c or DirectX10.

Related

How to handle a button press (Desktop Application)

I am making a desktop application, and I got it to display a button. Now what I am trying to do is somehow handle the button press, but I do not know how. Here is my code so far:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
// Global variables
// The main window class name.
static TCHAR szWindowClass[] = _T("DesktopApp");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("First Desktop Application");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
WNDCLASSEX 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, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// Store instance handle in our global variable
hInst = hInstance;
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
HWND hwndButton = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Test2", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
100, // y position
100, // Button width
20, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Test");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, Windows desktop!"
// in the top left corner.
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
// End application-specific layout section.
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
It is a Windows Desktop Wizard project on Visual Studio 2019. I just want it to do something simple like display some text on the screen or something when the button is pressed.
This is what the window looks like:
When a BUTTON is clicked, it sends a BN_CLICKED notification message to its parent window. You would simply handle that message in your WndProc(), eg:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
...
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED)
{
// LOWORD(wParam) is the button's ID
// HWND(lParam) is the button's HWND
// do something with them as needed...
return 0;
}
break;
}
...
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
This is explained in the BUTTON documentation on MSDN:
Button Messages
Handling Messages from a Button
Notifications from a button are sent as either WM_COMMAND or WM_NOTIFY messages. Information about which message is used can be found on the reference page for each notification.
For more information on how to handle messages, see Control Messages. See also Button Messages.
Notification Messages from Buttons
When the user clicks a button, its state changes, and the button sends notification codes, in the form of WM_COMMAND messages, to its parent window. For example, a push button control sends the BN_CLICKED notification code whenever the user chooses the button. In all cases (except for BCN_HOTITEMCHANGE), the low-order word of the wParam parameter contains the control identifier, the high-order word of wParam contains the notification code, and the lParam parameter contains the control window handle.

C++ Close window not application

I'm trying to create two instances of a window class.
When the primary one is closed it should close the application but when the secondary one is closed it should just close that window.
However when either window is closed the application exits, and I'm not sure why. I've tried comparing the hWnd to check which window is being closed.
// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
//Forgive me now
#define MAX_WINDOWS 1024
HWND hWindows[MAX_WINDOWS];
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
RegisterClassEx(&wc);
hWindows[0] = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
hWindows[1] = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
hWindows[0], // primary window
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
ShowWindow(hWindows[0], nCmdShow);
ShowWindow(hWindows[1], nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch (message)
{
case WM_CLOSE:
{
if (hWnd = hWindows[0]) {
// close the application entirely
PostQuitMessage(0);
}
else {
DestroyWindow(hWnd);
}
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
}
if (hWnd = hWindows[0])
That's assignment. Since hWindows[0] is non-zero, that expression always evaluates true.
You mean:
if (hWnd == hWindows[0])
You should call PostQuitMessage in response to WM_DESTROY. And since the default window procedure calls DestroyWindow in response to WM_CLOSE, you can write it like this:
switch (message)
{
case WM_DESTROY:
{
if (hWnd == hWindows[0]) {
// close the application entirely
PostQuitMessage(0);
}
return 0;
}
break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);

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.

WM_PAINT not being called after window is created

I've been playing around with the Windows api for uni, but I cant get the window messages to call WM_PAINT after the inital creation. It calls it when the window is created but not after.
All Other messages get called! Just cant get the WM_PAINT to be called.
This is part of a game lib we have to make using the Windows api, (the goal is to learn abit of the windows api, rather than the intricacies of making game libs).
From what I gather the UpdateWindow(handle) command calls inititates the WM_PAINT message, but no matter where I put this command (currently in the game loop) I cant get it to call the message.
There's a lot of code, so I've trimmed it a little.
I know I have multiple WM_PAINT cases, they are a result of trying to make sure its getting through.
Window Creation
HWND hwnd;
hwnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
L"FirstWindowClass",
L"Mootlib",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
m_screenWidth,
m_screenHeight,
NULL,
NULL,
WindowsUtilities::windowInstance(),
NULL);
Register the Window
WNDCLASSEX wcex;
wcex.cbSize = sizeof (wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = windowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = WindowsUtilities::windowInstance();
wcex.hIcon = 0;
wcex.hCursor = LoadCursor (NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"FirstWindowClass";
wcex.hIconSm = 0;
RegisterClassEx (&wcex);
Winproc
LRESULT CALLBACK windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LONG_PTR lptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch(message)
{
case(WM_PAINT):
int f = 3;
}
if (lptr)
{
Window* obj = reinterpret_cast<Window*>(lptr);
return obj->handleWindowsMessages(message, wParam, lParam);
}
else
return DefWindowProc(hwnd, message, wParam, lParam);
}
Internal command
LRESULT Window::handleWindowsMessages(UINT message, WPARAM wParam, LPARAM lParam)
{
std::wstring szHello = L"Hello, world!";
PAINTSTRUCT ps;
HDC hdc;
switch(message)
{
case(WM_PAINT):
hdc = BeginPaint(m_handle, &ps);
TextOut(hdc, 0, 0, L"Hello, Windows!", 15);
EndPaint(m_handle, &ps);
return 0;
case(WM_CLOSE):
quitGame();
return 0;
// Move Me!!!
case(WM_KEYDOWN):
case(WM_LBUTTONDOWN):
case(WM_RBUTTONDOWN):
inputManager().addButtonEvent(reinterpret_cast<int&>(wParam), BUTTON_DOWN);
return 0;
// Move Me!!!
case(WM_KEYUP):
case(WM_LBUTTONUP):
case(WM_RBUTTONUP):
inputManager().addButtonEvent(reinterpret_cast<int&>(wParam), BUTTON_UP);
return 0;
}
return DefWindowProc(handle(), message, wParam, lParam);
}
Game Loop
while(IsWindowVisible(handle()))
{
UpdateWindow(handle());
WindowsUtilities::processMessages();
draw();
update();
inputManager().update();
inputManager().clearButtonUpEvents(); // this should be in the input update()
}
Thanks.
First, I really don't like your game loop as its not at all obvious where the windows message pump is.
Somewhere along the line you need to call PeekMessage() or GetMessage() and TranslateMessage() & DispatchMessage() on any messages retrieved. Lots of people unfamiliar with windows will filter the messages, either in a range, or for a window: don't - always pump all messages for all windows on the current thread.
Then you need to call InvalidateRect to mark the areas of the window you want repainted. Games will want to pass FALSE as getting the background painted is just a waste of time when youre painting the entire scene in WM_PAINT.
RedrawWindow is useful for a game if you just want to mark an entire part of the window dirty and repaint it in one step. The advantage of InvalidateRect is that it just adds the rectangle to a dirty region, so if your game consists of just a few small 'active' sprites, as each sprite animates you can mark just the corresponding rect dirty, and windows will collect the dirty rects and paint them in a batch when next you call UpdateWindow, or let the message loop generate a WM_PAINT message.
Here's a snippet from the canonical Windows code, auto-generated when you create a new Win32 project in Visual Studio:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Note what's missing in yours: you forgot to call ShowWindow().
If you want WM_PAINT to be called, you can use RedrawWindow or InvalidateRect.
MSDN states:
The UpdateWindow function updates the
client area of the specified window by
sending a WM_PAINT message to the
window if the window's update region
is not empty.
Your issue is that you haven't set an update region.
You could just do:
SendMessage( handle(), WM_PAINT, 0, 0 );

WS_EX_TOOLWINDOW jumping to background on window destroy

Weird issue:
Open a large notepad window
create a toolwindow (style WS_EX_TOOLWINDOW)
create 2 more windows (normal overlapped) (WS_OVERLAPPED)
close those 2 overlapped windows (child of desktop or the toolwindow)
the toolwindow jumps behind the notepad window
Does anyone know why this is the case? Or what I could be doing wrong? I would say 'bug in windows', but that is rarely the case.
To answer questions:
It is not a dialog window, but a full window. If i make it have correct children (ie: not a child of desktop), the taskbar entry for the children do not appear (probably easily fixable), but either way, the bug still happens.
I have included example code that shows the issue. I am hoping I am just creating the window wrong or required to respond to a message I am not responding to.
In this example, a tool window will open (no task bar entry, which is what is wanted). Then you click on that window, a subwindow will open. You click on the subwindow, another window will open. Then close both new subwindows and the original window, instead of getting focus, jumps immediately to behind other windows (notepad, etc).
Thanks for any help!
Example code to clarify:
// WindowToback.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "WindowToback.h"
// Global Variables:
HINSTANCE g_instance;
HWND g_mainWnd = NULL;
wchar_t *szWindowClass = L"WindowToBackSub";
wchar_t *szWindowClass2 = L"WindowToBackSub2";
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc2(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX 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_WINDOWTOBACK));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINDOWTOBACK);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
wcex.lpfnWndProc = WndProc2;
wcex.lpszClassName = szWindowClass2;
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
g_instance = hInstance;
g_mainWnd = CreateWindowEx(WS_EX_TOOLWINDOW,szWindowClass, szWindowClass,WS_OVERLAPPED,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!g_mainWnd) return FALSE;
ShowWindow(g_mainWnd, nCmdShow);
UpdateWindow(g_mainWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
{
HWND l_hwnd = CreateWindow(szWindowClass2, szWindowClass2, WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g_instance, NULL);
ShowWindow(l_hwnd,SW_SHOW);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
{
HWND l_hwnd = CreateWindow(szWindowClass2, szWindowClass2, WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g_instance, NULL);
ShowWindow(l_hwnd,SW_SHOW);
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
This isn't surprising. In fact, it's exactly the behavior I'd expect.
You're tool window isn't jumping down; rather Notepad is jumping up.
You closed the window that had activation. The system is going to activate the next-highest top-level window in the z-order. Your tool window doesn't a count as a top-level window in this regard (that's part of what being a tool window means). So Notepad gets activated, and it comes to the top.
If you want your tool window to get activated instead, you probably don't really want a tool window.
Are the three windows dialogs to another main window or are they applications in their own right?
If they are dialog windows then I would check that their parent window is correctly assigned.
If they are application windows then I would check that they are appearing in the taskbar.
Without more information about the problem it is hard to give a more meaningful answer.