Reputation: 43417
I see plenty of tutorials and articles showing me how to make a simple windows program, which is great but none of them show me how to make multiple windows.
Right now I have working code that creates and draws a layered window and I can blit stuff using GDI to draw anything I want on it, drag it around, even make it transparent, etc.
But I wanted a second rectangular area that I can draw to, drag around, etc. In other words, a second window. Probably want it to be a child window. Question is, how do I make it?
Also, if anybody knows any good resources (online preferably) like articles or tutorials for window management in the Windows API, please share.
Upvotes: 16
Views: 38492
Reputation: 458
I know this has already been answered, but I was just writing a program that opens an arbitrary number of windows via a for loop.
Here is my version. Basically, it reuses the same class generator to build multiple windows. You can create as many as you want. Just make sure to adjust your HWND[] and WNDCLASSEX wc[] arrays accordingly.
Note 1: This piece of code uses a global ApplicationInstance, which is derived from WinMain function. In your WinMain, assign received hInstance to ApplicationInstance which, in this example is assumed to be available globally. This is your primary application window instance.
Note 2: Of course, you have to have WinProc routine already pre-written, and included somewhere in another header file, or just above (not shown in this example.) In this code, it is referenced to as WinProc, when it's passed to PopulateClass(WNDPROC process)
Note 3: SpawnWindow supports "centered" and "maximized" flags. What they do is self-explanatory.
Also, window class name is auto-generated, so you never have to worry about naming it, just assign it a good base name.
int WindowCounter = 0;
WNDCLASSEX wc[1000];
HWND hwnd[1000];
char class_name[256]; // for auto class name generation
void PopulateClass(WNDPROC process) {
ZeroMemory(&wc[WindowCounter], sizeof(WNDCLASSEX));
wc[WindowCounter].cbSize = sizeof(WNDCLASSEX);
wc[WindowCounter].style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
wc[WindowCounter].lpfnWndProc = process;
wc[WindowCounter].cbClsExtra = 0;
wc[WindowCounter].cbWndExtra = 0;
wc[WindowCounter].hInstance = ApplicationInstance;
wc[WindowCounter].hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wc[WindowCounter].hCursor = LoadCursor(nullptr, IDC_ARROW);
wc[WindowCounter].hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc[WindowCounter].lpszMenuName = nullptr;
sprintf(class_name, "WindowClass%d", WindowCounter);
wc[WindowCounter].lpszClassName = class_name;
wc[WindowCounter].hIconSm = nullptr;
}
Now, let's put it all together by providing a SpawnWindow function!
HWND SpawnWindow(int x,
int y,
int width,
int height,
bool centered = false,
bool maximized = false) {
PopulateClass(WinProc);
RegisterClassEx(&wc[ WindowCounter ]);
int config_style = WS_OVERLAPPEDWINDOW;
if (maximized) { width = GetSystemMetrics(SM_CXFULLSCREEN); height = GetSystemMetrics(SM_CYFULLSCREEN); config_style = WS_OVERLAPPEDWINDOW | WS_MAXIMIZE; }
if (centered) { x = (GetSystemMetrics(SM_CXFULLSCREEN) / 2) - (width / 2); y = (GetSystemMetrics(SM_CYFULLSCREEN) / 2) - (height / 2); }
hwnd[WindowCounter] = CreateWindowEx(NULL,
wc[WindowCounter].lpszClassName,
config.namever(),
WS_OVERLAPPEDWINDOW,
x,
y,
width,
height,
nullptr,
nullptr,
ApplicationInstance,
nullptr);
HWND returnID = hwnd[WindowCounter];
ShowWindow(hwnd[WindowCounter++], SW_SHOW);
return returnID;
}
Finally, create as many windows as you want with just a single line of code each:
void CreateWindows() {
HWND PrimaryWindow1 = SpawnWindow(500, 500, 250, 250);
HWND PrimaryWindow2 = SpawnWindow(500, 500, 250, 250, true);
HWND PrimaryWindow3 = SpawnWindow(500, 500, 250, 250, true, true);
HWND PrimaryWindow4 = SpawnWindow(100, 100, 150, 150);
HWND PrimaryWindow5 = SpawnWindow(450, 500, 350, 150);
}
Call CreateWindows() from your WinMain, before entering main loop.
Hope this helps someone out there.
Using a single WinProc for all windows
Note, this will require additional modification to the above code. In particular, passing a custom class name to the SpawnWindow function, representing each window. For example: "WindowClass_App", where "WindowClass_" can be a static part of the name, and actual identifier would be just: "App", "Toolbox", "Sidebar", "AnotherCustomWindow", etc. First define them:
#define WindowClass_App 0
#define WindowClass_Layers 2
#define WindowClass_OpenGL 3
/* ...etc... */
I wrote a function that converts a string to an int ID. This ID will be used to branch out within the single WinProc function, based on which window class the message has been received:
int IdentifyWindowClassID(const char *lpClassName) {
int WindowClassID = -1;
// Convert string names to integers, because C++ switch does not support strings
if (strcmp(lpClassName, "WindowClass_App") == 0) WindowClassID = WindowClass_App;
if (strcmp(lpClassName, "WindowClass_Layers") == 0) WindowClassID = WindowClass_Layers;
if (strcmp(lpClassName, "WindowClass_OpenGL") == 0) WindowClassID = WindowClass_OpenGL;
/* etc */
return WindowClassID;
}
And finally, the WinProc itself:
long __stdcall WinProc(HWND hwnd, unsigned int msg, WPARAM wparam, LPARAM lparam)
{
char lpClassName[128];
GetClassName(hwnd, lpClassName, 128);
int WindowClassID = IdentifyWindowClassID( lpClassName );
switch (WindowClassID)
{
/* 1.) Main application window */
case WindowClass_App: {
switch (msg) {
case WM_CREATE: {
/* ...code... */
}
/* ...code... */
}
/* 2.) Layers window */
case WindowClass_Layers: {
switch (msg) {
case WM_CREATE: {
/* ...code... */
}
/* ...code... */
}
/* 3.) OpenGL view window... */
...
This is the basic pattern. Of course, you can craft it in any way you want, this is just how I did it, it's simple and it works for me.
Upvotes: 3
Reputation: 243
To create more than one window, repeat all the steps that you did when you created the first window to create a second window. A good way to do this is the copy and paste all the code from the first window. Then do search and replaces in which you replace all the names of the first window with unique names for the second window. The code in which I do just that is below.
The most important thing to note is that the windows class for the second window should have a unique name at the code line "windowclassforwindow2.lpszClassName="window class2". If it doesn't have a unique name, the windows registration will fail.
#include <windows.h>
LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow2,UINT message,WPARAM wParam,LPARAM lParam);
bool window1closed=false;
bool window2closed=false;
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
bool endprogram=false;
//create window 1
WNDCLASSEX windowclassforwindow1;
ZeroMemory(&windowclassforwindow1,sizeof(WNDCLASSEX));
windowclassforwindow1.cbClsExtra=NULL;
windowclassforwindow1.cbSize=sizeof(WNDCLASSEX);
windowclassforwindow1.cbWndExtra=NULL;
windowclassforwindow1.hbrBackground=(HBRUSH)COLOR_WINDOW;
windowclassforwindow1.hCursor=LoadCursor(NULL,IDC_ARROW);
windowclassforwindow1.hIcon=NULL;
windowclassforwindow1.hIconSm=NULL;
windowclassforwindow1.hInstance=hInst;
windowclassforwindow1.lpfnWndProc=(WNDPROC)windowprocessforwindow1;
windowclassforwindow1.lpszClassName=L"windowclass 1";
windowclassforwindow1.lpszMenuName=NULL;
windowclassforwindow1.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&windowclassforwindow1))
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window class creation failed",
L"Window Class Failed",
MB_ICONERROR);
}
HWND handleforwindow1=CreateWindowEx(NULL,
windowclassforwindow1.lpszClassName,
L"Parent Window",
WS_OVERLAPPEDWINDOW,
200,
150,
640,
480,
NULL,
NULL,
hInst,
NULL /* No Window Creation data */
);
if(!handleforwindow1)
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window creation failed",
L"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(handleforwindow1,nShowCmd);
// create window 2
WNDCLASSEX windowclassforwindow2;
ZeroMemory(&windowclassforwindow2,sizeof(WNDCLASSEX));
windowclassforwindow2.cbClsExtra=NULL;
windowclassforwindow2.cbSize=sizeof(WNDCLASSEX);
windowclassforwindow2.cbWndExtra=NULL;
windowclassforwindow2.hbrBackground=(HBRUSH)COLOR_WINDOW;
windowclassforwindow2.hCursor=LoadCursor(NULL,IDC_ARROW);
windowclassforwindow2.hIcon=NULL;
windowclassforwindow2.hIconSm=NULL;
windowclassforwindow2.hInstance=hInst;
windowclassforwindow2.lpfnWndProc=(WNDPROC)windowprocessforwindow2;
windowclassforwindow2.lpszClassName=L"window class2";
windowclassforwindow2.lpszMenuName=NULL;
windowclassforwindow2.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&windowclassforwindow2))
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window class creation failed for window 2",
L"Window Class Failed",
MB_ICONERROR);
}
HWND handleforwindow2=CreateWindowEx(NULL,
windowclassforwindow2.lpszClassName,
L"Child Window",
WS_OVERLAPPEDWINDOW,
200,
150,
640,
480,
NULL,
NULL,
hInst,
NULL);
if(!handleforwindow2)
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window creation failed",
L"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(handleforwindow2,nShowCmd);
SetParent(handleforwindow2,handleforwindow1);
MSG msg;
ZeroMemory(&msg,sizeof(MSG));
while (endprogram==false) {
if (GetMessage(&msg,NULL,0,0));
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (window1closed==true && window2closed==true) {
endprogram=true;
}
}
MessageBox(NULL,
L"Both Windows are closed. Program will now close.",
L"",
MB_ICONINFORMATION);
return 0;
}
LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY: {
MessageBox(NULL,
L"Window 1 closed",
L"Message",
MB_ICONINFORMATION);
window1closed=true;
return 0;
}
break;
}
return DefWindowProc(handleforwindow,msg,wParam,lParam);
}
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY: {
MessageBox(NULL,
L"Window 2 closed",
L"Message",
MB_ICONINFORMATION);
window2closed=true;
return 0;
}
break;
}
return DefWindowProc(handleforwindow,msg,wParam,lParam);
}
A more complex example-using functions to create windows.
Creating each window without a function can be make the code cluttered-especially if it is in if statements. The code below uses a separate function to create each window. The first three windows have a create window button to create the next window.
#include <Windows.h>
LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow3(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow4(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
#define createwindowbuttoninwindow1 101
#define createwindowbuttoninwindow2 201
#define createwindowbuttoninwindow3 301
bool window1open,window2open,window3open,window4open=false;
bool windowclass1registeredbefore,windowclass2registeredbefore,
windowclass3registeredbefore,windowclass4registeredbefore=false;
enum windowtoopenenumt {none,window2,window3,window4};
windowtoopenenumt windowtoopenenum=none;
void createwindow2(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd);
void createwindow3(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd);
void createwindow4(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd);
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
bool endprogram=false;
WNDCLASSEX windowclassforwindow2;
WNDCLASSEX windowclassforwindow3;
WNDCLASSEX windowclassforwindow4;
HWND handleforwindow2;
HWND handleforwindow3;
HWND handleforwindow4;
//create window 1
MSG msg;
WNDCLASSEX windowclassforwindow1;
ZeroMemory(&windowclassforwindow1,sizeof(WNDCLASSEX));
windowclassforwindow1.cbClsExtra=NULL;
windowclassforwindow1.cbSize=sizeof(WNDCLASSEX);
windowclassforwindow1.cbWndExtra=NULL;
windowclassforwindow1.hbrBackground=(HBRUSH)COLOR_WINDOW;
windowclassforwindow1.hCursor=LoadCursor(NULL,IDC_ARROW);
windowclassforwindow1.hIcon=NULL;
windowclassforwindow1.hIconSm=NULL;
windowclassforwindow1.hInstance=hInst;
windowclassforwindow1.lpfnWndProc=(WNDPROC)windowprocessforwindow1;
windowclassforwindow1.lpszClassName=L"window class 1";
windowclassforwindow1.lpszMenuName=NULL;
windowclassforwindow1.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&windowclassforwindow1))
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window class creation failed",
L"Window Class Failed",
MB_ICONERROR);
}
HWND handleforwindow1=CreateWindowEx(NULL,
windowclassforwindow1.lpszClassName,
L"Window 1",
WS_OVERLAPPEDWINDOW,
200,
150,
640,
480,
NULL,
NULL,
hInst,
NULL /* No Window Creation data */
);
if(!handleforwindow1)
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window creation failed",
L"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(handleforwindow1,nShowCmd);
bool endloop=false;
while (endloop==false) {
if (GetMessage(&msg,NULL,0,0));
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (windowtoopenenum !=none) {
switch (windowtoopenenum) {
case window2:
if (window2open==false) {
createwindow2(windowclassforwindow2,handleforwindow2,hInst,nShowCmd);
}
break;
case window3:
if (window3open==false) {
createwindow3(windowclassforwindow3,handleforwindow3,hInst,nShowCmd);
}
break;
case window4:
if (window4open==false) {
createwindow4(windowclassforwindow4,handleforwindow4,hInst,nShowCmd);
}
break;
}
windowtoopenenum=none;
}
if (window1open==false && window2open==false && window3open==false && window4open==false)
endloop=true;
}
MessageBox(NULL,
L"All Windows are closed. Program will now close.",
L"Message",
MB_ICONINFORMATION);
}
void createwindow2(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd) {
if (windowclass2registeredbefore==false) {
ZeroMemory(&wc,sizeof(WNDCLASSEX));
wc.cbClsExtra=NULL;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=NULL;
wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hIcon=NULL;
wc.hIconSm=NULL;
wc.hInstance=hInst;
wc.lpfnWndProc=(WNDPROC)windowprocessforwindow2;
wc.lpszClassName=L"wc2";
wc.lpszMenuName=NULL;
wc.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&wc))
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window class creation failed",
L"Window Class Failed",
MB_ICONERROR);
}
else
windowclass2registeredbefore=true;
}
hwnd=CreateWindowEx(NULL,
wc.lpszClassName,
L"Window 2",
WS_OVERLAPPEDWINDOW,
200,
170,
640,
480,
NULL,
NULL,
hInst,
NULL /* No Window Creation data */
);
if(!hwnd)
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window creation failed",
L"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(hwnd,nShowCmd);
}
void createwindow3(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd) {
if (windowclass3registeredbefore==false) {
ZeroMemory(&wc,sizeof(WNDCLASSEX));
wc.cbClsExtra=NULL;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=NULL;
wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hIcon=NULL;
wc.hIconSm=NULL;
wc.hInstance=hInst;
wc.lpfnWndProc=(WNDPROC)windowprocessforwindow3;
wc.lpszClassName=L"window class 3";
wc.lpszMenuName=NULL;
wc.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&wc))
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window class creation failed",
L"Window Class Failed",
MB_ICONERROR);
}
else
windowclass3registeredbefore=true;
}
hwnd=CreateWindowEx(NULL,
wc.lpszClassName,
L"Window 3",
WS_OVERLAPPEDWINDOW,
200,
190,
640,
480,
NULL,
NULL,
hInst,
NULL /* No Window Creation data */
);
if(!hwnd)
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window creation failed",
L"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(hwnd,nShowCmd);
}
void createwindow4(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd) {
if (windowclass4registeredbefore==false) {
ZeroMemory(&wc,sizeof(WNDCLASSEX));
wc.cbClsExtra=NULL;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=NULL;
wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hIcon=NULL;
wc.hIconSm=NULL;
wc.hInstance=hInst;
wc.lpfnWndProc=(WNDPROC)windowprocessforwindow4;
wc.lpszClassName=L"window class 4";
wc.lpszMenuName=NULL;
wc.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&wc))
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window class creation failed",
L"Window Class Failed",
MB_ICONERROR);
}
else
windowclass4registeredbefore=true;
}
hwnd=CreateWindowEx(NULL,
wc.lpszClassName,
L"Window 4",
WS_OVERLAPPEDWINDOW,
200,
210,
640,
480,
NULL,
NULL,
hInst,
NULL /* No Window Creation data */
);
if(!hwnd)
{
int nResult=GetLastError();
MessageBox(NULL,
L"Window creation failed",
L"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(hwnd,nShowCmd);
}
// windows process functions
LRESULT CALLBACK windowprocessforwindow1(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
switch(message) {
case WM_CREATE:
window1open=true;
CreateWindowEx(NULL,
L"BUTTON",
L"Open Window 2",
WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_DEFPUSHBUTTON,
50,
220,
150,
24,
hwnd,
(HMENU)createwindowbuttoninwindow1,
GetModuleHandle(NULL),
NULL);
break;
case WM_DESTROY:
window1open=false;
break;
case WM_COMMAND:
switch LOWORD(wParam) {
case createwindowbuttoninwindow1:
windowtoopenenum=window2;
break;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK windowprocessforwindow2(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
switch(message) {
case WM_CREATE:
window2open=true;
CreateWindowEx(NULL,
L"BUTTON",
L"Open Window 3",
WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_DEFPUSHBUTTON,
50,
220,
150,
24,
hwnd,
(HMENU)createwindowbuttoninwindow2,
GetModuleHandle(NULL),
NULL);
break;
case WM_DESTROY:
window2open=false;
break;
case WM_COMMAND:
switch LOWORD(wParam) {
case createwindowbuttoninwindow2:
windowtoopenenum=window3;
break;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK windowprocessforwindow3(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
switch(message) {
case WM_CREATE:
window3open=true;
CreateWindowEx(NULL,
L"BUTTON",
L"Open Window 4",
WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_DEFPUSHBUTTON,
50,
220,
150,
24,
hwnd,
(HMENU)createwindowbuttoninwindow3,
GetModuleHandle(NULL),
NULL);
break;
case WM_DESTROY:
window3open=false;
break;
case WM_COMMAND:
switch LOWORD(wParam) {
case createwindowbuttoninwindow3:
windowtoopenenum=window4;
break;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK windowprocessforwindow4(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
switch(message) {
case WM_DESTROY:
window4open=false;
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
What if you close and reopen a window?
If you click on the close button and reopen that same window, note the following. When the window is closed after the close button is closed, it will be destroyed. But destroying a window does not destroy the windows class. It only destroys the window from the createwindow function. This makes it necessary for the if statement in the above program that only creates the Windows class if it is the first time the window has been displayed.
Some side notes
You could create multiple windows using just one windows class. But the problem with that is that you have one windows process function to deal with more than one window. That would work fine in this simple example. But the more heterogeneous the windows are the more would be the need to create a separate windows class for each window.
Also the multiple createwindow functions could have been combined into one function. Note that the only difference between them was the wc.lpszClassName code line. But Windows are likely to be different from each other so combining the functions into one is not necessary-it is more of a preference of just not having code repeating things.
Further Reading
The link at the website with the domain functionx has more details about the concepts in windows design. The link is here
The home page at functionx.com has good programming learning resources. Especially important is this page which has programming reference material for things such as changing the windows class, creating listboxes and other windows controls. It is also a good resource for win32 programming learning in general. functionx.com win32 programming
functionx.com win32 programming
Upvotes: 16
Reputation: 12980
You can hit CreateWindow() more than once if you want. The message loop in your WinMain will pass events to all the windows that WinMain creates. You can even create two overlapped windows and set the parent window of the 2nd one to be the handle of the 1st one if you want.
Upvotes: 13
Reputation: 4587
You can create as many windows as you want using CreateWindow/CreateWindowEx, with the relationship between them as you desire (owner/child).
You can make a window "owned" by other with:
SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR) hwndParent);
To convert a window to child, use SetParent
.
Note that the SetWindowLongPtr
call with GWLP_HWNDPARENT
does not behave as SetParent (MSDN is wrong on this I think). GWLP_HWNDPARENT
does not convert a window to "child", but to "owned".
Upvotes: 2
Reputation: 180787
It sounds like you want a Multiple Document Interface. Here is an example of one:
http://www.codeproject.com/KB/winsdk/Sigma.aspx
Upvotes: 3