Parent and owner windows

First, WS_ A child style window must have a parent window, otherwise it will fail to create and WS_ The child window cannot be dragged alone and needs to move with the parent window.

Next, let's talk about the owner window. When the window is created, if WS is not specified_ Child attribute, and hWndParent also indicates, hWndParent is the owner window of the window. And the window must be displayed above the owner window, that is, the owner window cannot cover the area of the window owned by it.
In addition, if through:: SetParent(hChildWnd, g_hWnd); In addition to the owner window, the new window also has a parent window. The child window must be displayed in the display area of its parent window (more accurately, the customer area). And SetParent does not add ws to the window_ Child property. After setting the parent window, the child window can be dragged in the area of the parent window, and when the parent window is moved, the child window also moves

As shown in the figure below, after clicking the create sub window in the upper left corner of the large window, a red box owner window will appear. The owner window must cover the owner window, and the owner window can move out of the scope of the owner window. When the large window (owner window) moves, the small window (owner window) will not move with it.

As shown in the following figure, it can be seen that the small window has no parent window, but has an owner window.

In this case, the corresponding code is as follows:

// TopmostTest.cpp: defines the entry point for the application.
//

#include "framework.h"
#include "OwnerWndAndParentWnd.h"

#define MAX_LOADSTRING 100

#define IDB_ONE     3301  



HWND g_hWnd = NULL;


// Global variables:
HINSTANCE hInst;                                // Current instance
WCHAR szTitle[MAX_LOADSTRING];                  // Title Block text
WCHAR szWindowClass[MAX_LOADSTRING];            // Main window class name

// Forward declaration of functions contained in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

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.

	// Initialize global string
	LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadStringW(hInstance, IDC_OWNERWNDANDPARENTWND, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance(hInstance, nCmdShow))
	{
		return FALSE;
	}

	HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OWNERWNDANDPARENTWND));

	MSG msg;

	// Main message loop:
	while (GetMessage(&msg, nullptr, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int)msg.wParam;
}



//
//  Function: MyRegisterClass()
//
//  Target: register window class.
//
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_OWNERWNDANDPARENTWND));
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_OWNERWNDANDPARENTWND);
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassExW(&wcex);
}

//
//   Function: InitInstance (hint, int)
//
//   Target: save the instance handle and create the main window
//
//   notes:
//
//        In this function, we save the instance handle in the global variable and
//        Create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	hInst = hInstance; // Store the instance handle in a 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);
	g_hWnd = hWnd;
	//::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);

	UpdateWindow(hWnd);

	return TRUE;
}

//
//  Function: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  Objective: to process messages from the main window.
//
//  WM_COMMAND - process application menu
//  WM_PAINT - draw main window
//  WM_DESTROY - send exit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_COMMAND:
	{
		int wmId = LOWORD(wParam);
		// Analysis menu selection:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		case IDB_ONE:
		{
			///A non topmost child window is created here
			HWND hChildWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME, L"OWNERWNDANDPARENTWND", L"MyClildTitle", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 600, 600, 200, 200, g_hWnd, NULL, hInst, nullptr);
			//HWND hChildWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME, L"TOPMOSTTEST", L"MyClildTitle", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 800, 800, 200, 200, NULL, NULL, hInst, nullptr);
			DWORD err = ::GetLastError();
			//::SetParent(hChildWnd, g_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 using hdc here
		EndPaint(hWnd, &ps);
	}
	break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_CREATE:
	{
		//CreateWindowW(L"Button", L "create non topmost sub window", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 35, 10, 200, 60, hWnd, (HMENU)IDB_ONE, hInst, NULL);
		HWND hChild = CreateWindowW(L"Button", L"Create child window", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 35, 10, 200, 60, hWnd, (HMENU)IDB_ONE, hInst, NULL);
		DWORD err = ::GetLastError();
		int i = 0;
		i++;
	}
	break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for the 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;
}

Then we set the parent window (through SetParent) for this small window. After setting, we will find that the small window can only be displayed inside the large window, and when the large window moves, the small window will move with it.

The corresponding codes are as follows:

// TopmostTest.cpp: defines the entry point for the application.
//

#include "framework.h"
#include "OwnerWndAndParentWnd.h"

#define MAX_LOADSTRING 100

#define IDB_ONE     3301  



HWND g_hWnd = NULL;


// Global variables:
HINSTANCE hInst;                                // Current instance
WCHAR szTitle[MAX_LOADSTRING];                  // Title Block text
WCHAR szWindowClass[MAX_LOADSTRING];            // Main window class name

// Forward declaration of functions contained in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

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.

	// Initialize global string
	LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadStringW(hInstance, IDC_OWNERWNDANDPARENTWND, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance(hInstance, nCmdShow))
	{
		return FALSE;
	}

	HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OWNERWNDANDPARENTWND));

	MSG msg;

	// Main message loop:
	while (GetMessage(&msg, nullptr, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int)msg.wParam;
}



//
//  Function: MyRegisterClass()
//
//  Target: register window class.
//
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_OWNERWNDANDPARENTWND));
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_OWNERWNDANDPARENTWND);
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassExW(&wcex);
}

//
//   Function: InitInstance (hint, int)
//
//   Target: save the instance handle and create the main window
//
//   notes:
//
//        In this function, we save the instance handle in the global variable and
//        Create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	hInst = hInstance; // Store the instance handle in a 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);
	g_hWnd = hWnd;
	//::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);

	UpdateWindow(hWnd);

	return TRUE;
}

//
//  Function: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  Objective: to process messages from the main window.
//
//  WM_COMMAND - process application menu
//  WM_PAINT - draw main window
//  WM_DESTROY - send exit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_COMMAND:
	{
		int wmId = LOWORD(wParam);
		// Analysis menu selection:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		case IDB_ONE:
		{
			///A non topmost child window is created here
			HWND hChildWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME, L"OWNERWNDANDPARENTWND", L"MyClildTitle", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 600, 600, 200, 200, g_hWnd, NULL, hInst, nullptr);
			//HWND hChildWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME, L"TOPMOSTTEST", L"MyClildTitle", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 800, 800, 200, 200, NULL, NULL, hInst, nullptr);
			DWORD err = ::GetLastError();
			::SetParent(hChildWnd, g_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 using hdc here
		EndPaint(hWnd, &ps);
	}
	break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_CREATE:
	{
		//CreateWindowW(L"Button", L "create non topmost sub window", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 35, 10, 200, 60, hWnd, (HMENU)IDB_ONE, hInst, NULL);
		HWND hChild = CreateWindowW(L"Button", L"Create child window", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 35, 10, 200, 60, hWnd, (HMENU)IDB_ONE, hInst, NULL);
		DWORD err = ::GetLastError();
		int i = 0;
		i++;
	}
	break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for the 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;
}

Tags: IDE Visual Studio visualstudio

Posted on Thu, 28 Oct 2021 10:27:12 -0400 by mikelmao