C++ MDI 选择性子 Window 关闭
C++ MDI Selective Child Window Closing
您好,我正在尝试使用纯 Win32 API 开发一个 C++ MDI 程序(因为我需要该程序是可移植的,即 运行 甚至可以从 USB,尽可能多.exe 文件)。
此 MDI 程序有 2 种类型(classes)子 windows、"MdiPrinterChild" 和 "MdiStationChild." "MdiStationChild" window一旦主 window 的客户区被创建(只能创建一个 'Station' window),就会自动创建并显示。 "MdiPrinterChild" window 仅在用户从菜单中选择 "New Printer" 时创建,实际上可以创建多个 'printer' 子 windows。当 'printer' 子 window 处于活动状态时,可以触发 "close all" 菜单,据说可以关闭所有 'printer' windows(仅)。问题是,它还关闭了 'station' window。如果单击主要 window 的 'x',也会发生同样的事情。我尝试通过在 "CloseEnumProc" 中使用子 window 的 class 名称(if 语句)来选择性关闭子 windows,但这次的问题是,应用程序本身可以永远不会关闭。 'Exit' 来自菜单同样不会响应。
下面是 CloseEnumProc 的代码,但如果这段代码真的不可行,谁能给我一个示例代码如何做。谢谢
#include <windows.h>
#include <Winuser.h>
#include <Winbase.h>
#include "shlwapi.h"
#include "CommCtrl.h"
#include <tchar.h>
#include "resource.h"
#include "printer.h"
#define INIT_MENU_POS 0
#define PRINTER_MENU_POS 2
#define IDM_FIRSTCHILD 50000
#define BUFSIZE MAX_PATH
//prototypes
LRESULT CALLBACK FrameWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK CloseEnumProc (HWND, LPARAM);
LRESULT CALLBACK PrinterWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK SetupStationDlgProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK StationWndProc (HWND, UINT, WPARAM, LPARAM);
//global variables
TCHAR szAppName[] = TEXT ("VentureOEp");
TCHAR szFrameClass[] = TEXT ("MdiFrame");
TCHAR szPrinterClass[] = TEXT ("MdiPrinterChild");
TCHAR szStationClass[] = TEXT ("MdiStationChild");
HINSTANCE hInst, hInstStation;
HMENU hMenuInit, hMenuPrinter;
HMENU hMenuInitWindow, hMenuPrinterWindow;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//locals to WinMain
HWND hwndFrame;
HWND hwndClient;
MSG msg;
WNDCLASSEX wc;
HACCEL hAccel;
hInst = hInstance ;
/*=====================*/
//get current directory of this process and check if definition files are complete
TCHAR filePath[BUFSIZE] ;
DWORD dwRet ;
dwRet = GetCurrentDirectory(BUFSIZE, filePath) ;
if( dwRet == 0 )
{
sprintf(filePath,"GetCurrentDirectory failed (%d)\n", GetLastError()) ;
MessageBox(NULL,LPCSTR(filePath),LPCSTR("Get Current Directory Error!"),MB_ICONEXCLAMATION|MB_OK) ;
return 0 ;
}
else
{
//check if definition files exists
char *exactPath ;
exactPath = (LPSTR)(filePath) ;
strcat(exactPath, "\") ;
strcat(exactPath, "Definition Files\printer.xml") ;
if(!PathFileExists(exactPath))
{
MessageBox(NULL,_T("printer.xml not found"),_T("File check"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
}
/*=====================*/
//check file access over network and copy to current process directory
int bFileExists = 0;
char buffer_1[]= "G:\Notebooks and Projects\Dev C++\Venture pOE\Definition Files_Source\printer.xml";
char* fileToCopy ;
const char *fileCopyTo ;
fileToCopy = buffer_1 ;
fileCopyTo = "G:\Notebooks and Projects\Dev C++\Venture pOE\Definition Files\printer.xml" ;
if(!PathFileExists(fileToCopy))
{
MessageBox(NULL,_T("Network Access Failed"),_T("Access Check"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
if (!CopyFile(fileToCopy, fileCopyTo,FALSE))
{
MessageBox(NULL,_T("File update failed"),_T("Definitions update"),MB_ICONEXCLAMATION|MB_OK) ;
return 0 ;
}
/*=====================*/
//register frame window class
memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpfnWndProc = FrameWndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = NULL; //MAKEINTRESOURCE(IDR_MAINMENU);
wc.lpszClassName = szFrameClass;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = NULL; //HICON(LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 16,
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("Frame Window Registration Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//register child (printer) window class (not the client window which is already pre-registered)
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_NOCLOSE;
wc.lpfnWndProc = PrinterWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szPrinterClass;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("Printer Window Registration Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//register child (window) window class (not the client window which is already pre-registered)
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
wc.lpfnWndProc = StationWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szStationClass;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("Station Window Registration Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//Obtain handles of menus
hMenuInit = LoadMenu (hInstance, TEXT ("MdiMenuInit")) ;
hMenuPrinter = LoadMenu (hInstance, TEXT ("MdiMenuPrinter")) ;
//Obtain handles of positions of submenu "Window"
hMenuInitWindow = GetSubMenu (hMenuInit, INIT_MENU_POS) ;
hMenuPrinterWindow = GetSubMenu (hMenuPrinter, PRINTER_MENU_POS) ;
//Load accelerator table
hAccel = LoadAccelerators (hInstance, szAppName) ;
//create frame window
//menu is loaded here
hwndFrame = CreateWindowEx(
WS_EX_CLIENTEDGE,
szFrameClass,
_T("Venture Day Walker"),
WS_CLIPCHILDREN|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
hMenuInit,
hInstance,
NULL);
if(hwndFrame == NULL)
{
MessageBox(NULL, _T("Main Window Creation Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//get handle of the client window(as child of main window)
hwndClient = GetWindow(hwndFrame,GW_CHILD);
//Display the window
ShowWindow(hwndFrame, nCmdShow);
UpdateWindow (hwndFrame);
// Enter the modified message loop (due to use of accelerators)
while (GetMessage (&msg, NULL, 0, 0))
{
if (!TranslateMDISysAccel (hwndClient, &msg) &&
!TranslateAccelerator (hwndFrame, hAccel, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
// Clean up by deleting unattached menus
DestroyMenu (hMenuPrinter) ;
//end of WinMain
return msg.wParam;
}
/*=====================*/
//main window proc
LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient ;
CLIENTCREATESTRUCT clientcreate ;
HWND hwndChild, hwndChildStation ;
MDICREATESTRUCT mdicreate ;
switch (message)
{
case WM_CREATE:
// Create the client window
clientcreate.hWindowMenu = hMenuInitWindow ;
clientcreate.idFirstChild = IDM_FIRSTCHILD ;
hwndClient = CreateWindowEx (
WS_EX_CLIENTEDGE,
TEXT("MDICLIENT"),
NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
0, 0, 0, 0,
hwnd,
(HMENU) 1,
hInst,
(PSTR) &clientcreate) ;
// Create a station child window
//provide values 1st for the MDICREATESTRUCT
mdicreate.szClass = szStationClass;
mdicreate.szTitle = TEXT ("Station Details");
mdicreate.hOwner = hInstStation;
mdicreate.x = CW_USEDEFAULT;
mdicreate.y = CW_USEDEFAULT;
mdicreate.cx = CW_USEDEFAULT;
mdicreate.cy = CW_USEDEFAULT;
mdicreate.style = 0; //WS_HSCROLL | WS_VSCROLL ;
mdicreate.lParam = 0;
//sendmessage to create the child window using WM_MDICREATE and
hwndChildStation = (HWND) SendMessage (hwndClient,
WM_MDICREATE, 0,
(LPARAM) (LPMDICREATESTRUCT) &mdicreate);
break ;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_STATION_SETUP:
DialogBox(hInst, TEXT("IDD_SETUPSTATION"), hwnd, SetupStationDlgProc);
InvalidateRect (hwnd, NULL, TRUE) ;
break ;
case IDM_PRINTER_NEW:
// Create a printer child window
mdicreate.szClass = szPrinterClass ;
mdicreate.szTitle = TEXT ("Serial Number + Model No.") ;
mdicreate.hOwner = hInst ;
mdicreate.x = CW_USEDEFAULT ;
mdicreate.y = CW_USEDEFAULT ;
mdicreate.cx = CW_USEDEFAULT ;
mdicreate.cy = CW_USEDEFAULT ;
mdicreate.style = WS_HSCROLL | WS_VSCROLL ; //or '0' for just frames
mdicreate.lParam = 0 ;
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDICREATE, 0,
(LPARAM) (LPMDICREATESTRUCT) &mdicreate);
break ;
case IDM_PRINTER_CLOSE:
// Close the active printer window
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDIGETACTIVE, 0, 0) ;
if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))
SendMessage (hwndClient, WM_MDIDESTROY, (WPARAM) hwndChild, 0) ;
break ;
case IDM_APP_EXIT:
// Exit the program
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
break ;
// messages for arranging windows
case IDM_WINDOW_TILE:
SendMessage (hwndClient, WM_MDITILE, 0, 0) ;
break ;
case IDM_WINDOW_CASCADE:
SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;
break ;
case IDM_WINDOW_CLOSEALL: // Attempt to close all children
EnumChildWindows (hwndClient, CloseEnumProc, 0) ;
break ;
case IDM_ABOUT:
// About menu
MessageBox(NULL, _T("Thank You LORD!"),_T("Glory To GOD"),MB_ICONEXCLAMATION|MB_OK);
break ;
default:
// Pass to active child...
hwndChild = (HWND) SendMessage (hwndClient, WM_MDIGETACTIVE, 0, 0) ;
if (IsWindow (hwndChild))
SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
return 0 ; // ...and then to DefFrameProc
}
break ;
case WM_PAINT:
break ;
case WM_QUERYENDSESSION:
case WM_CLOSE: //frame
// Attempt to close all children
SendMessage (hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0) ;
//mark: if NULL, meaning no more child windows
if (NULL != GetWindow (hwndClient, GW_CHILD))
return 0 ;
break ; // i.e., call DefFrameProc
case WM_DESTROY: //frame
PostQuitMessage (0) ;
break ;
}
// Pass unprocessed messages to DefFrameProc (not DefWindowProc)
return DefFrameProc (hwnd, hwndClient, message, wParam, lParam) ;
}
//'printer' window proc=========================================
LRESULT CALLBACK PrinterWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient, hwndFrame;
HDC hdc;
HMENU hMenu;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
// Save some window handles
hwndClient = GetParent(hwnd);
hwndFrame = GetParent(hwndClient);
break;
case WM_COMMAND:
break;
case WM_PAINT:
break;
case WM_MDIACTIVATE:
// Set the Printer menu if gaining focus
if (lParam == (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuPrinter, (LPARAM)hMenuPrinterWindow);
// Set the Init menu if losing focus
if (lParam != (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuInit, (LPARAM)hMenuInitWindow);
DrawMenuBar(hwndFrame);
break;
case WM_QUERYENDSESSION:
case WM_CLOSE: //printer
if (IDOK != MessageBox(hwnd, TEXT("OK to close window?"), TEXT("Printer"), MB_ICONQUESTION | MB_OKCANCEL))
return 0;
break; // i.e., call DefMDIChildProc
case WM_DESTROY: //printer
break;
}
// Pass unprocessed message to DefMDIChildProc
return DefMDIChildProc(hwnd, message, wParam, lParam);
}
//'Station' window proc=============================
LRESULT CALLBACK StationWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient, hwndFrame;
HDC hdc;
HMENU hMenu;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
// Save some window handles
hwndClient = GetParent(hwnd);
hwndFrame = GetParent(hwndClient);
break;
case WM_PAINT:
break;
case WM_MDIACTIVATE:
break;
case WM_DESTROY: //station
break; //return 0 ;
}
// Pass unprocessed message to DefMDIChildProc
return DefMDIChildProc(hwnd, message, wParam, lParam);
}
//'close all' CloseEnumProc =========================================
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
TCHAR className[20];
int numChar = 20;
// Check for icon title
if (GetWindow(hwnd, GW_OWNER))
return TRUE;
GetClassName(hwnd, className, numChar);
if (strcmp(szPrinterClass, className) == 0)
{
//if window is minimized, restore to previous size
SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);
//then send ask to close
if (!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))
return TRUE;
SendMessage(GetParent(hwnd), WM_MDIDESTROY, (WPARAM)hwnd, 0);
return TRUE;
}
}
CloseEnumProc:
更改CloseEnumProc
如下:
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
const int numChar = 50;
TCHAR className[numChar];
GetClassName(hwnd, className, numChar);
if (strcmp(szPrinterClass, className) == 0)
{
SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);
SendMessage(hwnd, WM_CLOSE, 0, 0);
//optional:
//add this line incase there are multiple children,
//and you want to break the message after one CANCEL message
if (IsWindow(hwnd)) return FALSE;
}
return TRUE;
}
检查 SendMessage(hwnd, WM_CLOSE, 0, 0);
的结果没有意义,它应该始终为零。如果有多个childwindows,并且如果用户决定不关闭childwindow,则IsWindow(hwnd)
有效。您可能希望在那时打破循环。
FrameWndProc:
关闭主 window 时,您正在检查是否所有 children 在 IDM_WINDOW_CLOSEALL
消息后被销毁。但结果总是错误的,因为 "station" window 保持打开状态。
您应该看看是否还有一个以上 child window 剩余。如果只剩下一个child,那么那个child就是站window,你可以关闭它
LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
...
case WM_QUERYENDSESSION:
case WM_CLOSE:
{
SendMessage(hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
int child_count = 0;
HWND hchild = GetWindow(hwndClient, GW_CHILD);
if (hchild)
{
child_count++;
hchild = GetWindow(hchild, GW_HWNDNEXT);
if (hchild)
{
child_count++;
}
}
if (child_count < 2)
{
PostQuitMessage(0);
}
return 0;
}
}
编辑
StationWndProc:
如果站 window 处于活动状态,则 IDM_PRINTER_CLOSE
将关闭 stationWnd。改变这个 stationWnd 过程是你不想要的:
LRESULT CALLBACK StationWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CLOSE:
return 0;
default: break;
}
return DefMDIChildProc(hwnd, message, wParam, lParam);
}
您好,我正在尝试使用纯 Win32 API 开发一个 C++ MDI 程序(因为我需要该程序是可移植的,即 运行 甚至可以从 USB,尽可能多.exe 文件)。
此 MDI 程序有 2 种类型(classes)子 windows、"MdiPrinterChild" 和 "MdiStationChild." "MdiStationChild" window一旦主 window 的客户区被创建(只能创建一个 'Station' window),就会自动创建并显示。 "MdiPrinterChild" window 仅在用户从菜单中选择 "New Printer" 时创建,实际上可以创建多个 'printer' 子 windows。当 'printer' 子 window 处于活动状态时,可以触发 "close all" 菜单,据说可以关闭所有 'printer' windows(仅)。问题是,它还关闭了 'station' window。如果单击主要 window 的 'x',也会发生同样的事情。我尝试通过在 "CloseEnumProc" 中使用子 window 的 class 名称(if 语句)来选择性关闭子 windows,但这次的问题是,应用程序本身可以永远不会关闭。 'Exit' 来自菜单同样不会响应。
下面是 CloseEnumProc 的代码,但如果这段代码真的不可行,谁能给我一个示例代码如何做。谢谢
#include <windows.h>
#include <Winuser.h>
#include <Winbase.h>
#include "shlwapi.h"
#include "CommCtrl.h"
#include <tchar.h>
#include "resource.h"
#include "printer.h"
#define INIT_MENU_POS 0
#define PRINTER_MENU_POS 2
#define IDM_FIRSTCHILD 50000
#define BUFSIZE MAX_PATH
//prototypes
LRESULT CALLBACK FrameWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK CloseEnumProc (HWND, LPARAM);
LRESULT CALLBACK PrinterWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK SetupStationDlgProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK StationWndProc (HWND, UINT, WPARAM, LPARAM);
//global variables
TCHAR szAppName[] = TEXT ("VentureOEp");
TCHAR szFrameClass[] = TEXT ("MdiFrame");
TCHAR szPrinterClass[] = TEXT ("MdiPrinterChild");
TCHAR szStationClass[] = TEXT ("MdiStationChild");
HINSTANCE hInst, hInstStation;
HMENU hMenuInit, hMenuPrinter;
HMENU hMenuInitWindow, hMenuPrinterWindow;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//locals to WinMain
HWND hwndFrame;
HWND hwndClient;
MSG msg;
WNDCLASSEX wc;
HACCEL hAccel;
hInst = hInstance ;
/*=====================*/
//get current directory of this process and check if definition files are complete
TCHAR filePath[BUFSIZE] ;
DWORD dwRet ;
dwRet = GetCurrentDirectory(BUFSIZE, filePath) ;
if( dwRet == 0 )
{
sprintf(filePath,"GetCurrentDirectory failed (%d)\n", GetLastError()) ;
MessageBox(NULL,LPCSTR(filePath),LPCSTR("Get Current Directory Error!"),MB_ICONEXCLAMATION|MB_OK) ;
return 0 ;
}
else
{
//check if definition files exists
char *exactPath ;
exactPath = (LPSTR)(filePath) ;
strcat(exactPath, "\") ;
strcat(exactPath, "Definition Files\printer.xml") ;
if(!PathFileExists(exactPath))
{
MessageBox(NULL,_T("printer.xml not found"),_T("File check"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
}
/*=====================*/
//check file access over network and copy to current process directory
int bFileExists = 0;
char buffer_1[]= "G:\Notebooks and Projects\Dev C++\Venture pOE\Definition Files_Source\printer.xml";
char* fileToCopy ;
const char *fileCopyTo ;
fileToCopy = buffer_1 ;
fileCopyTo = "G:\Notebooks and Projects\Dev C++\Venture pOE\Definition Files\printer.xml" ;
if(!PathFileExists(fileToCopy))
{
MessageBox(NULL,_T("Network Access Failed"),_T("Access Check"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
if (!CopyFile(fileToCopy, fileCopyTo,FALSE))
{
MessageBox(NULL,_T("File update failed"),_T("Definitions update"),MB_ICONEXCLAMATION|MB_OK) ;
return 0 ;
}
/*=====================*/
//register frame window class
memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpfnWndProc = FrameWndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = NULL; //MAKEINTRESOURCE(IDR_MAINMENU);
wc.lpszClassName = szFrameClass;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = NULL; //HICON(LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 16,
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("Frame Window Registration Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//register child (printer) window class (not the client window which is already pre-registered)
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_NOCLOSE;
wc.lpfnWndProc = PrinterWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szPrinterClass;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("Printer Window Registration Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//register child (window) window class (not the client window which is already pre-registered)
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
wc.lpfnWndProc = StationWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szStationClass;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("Station Window Registration Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//Obtain handles of menus
hMenuInit = LoadMenu (hInstance, TEXT ("MdiMenuInit")) ;
hMenuPrinter = LoadMenu (hInstance, TEXT ("MdiMenuPrinter")) ;
//Obtain handles of positions of submenu "Window"
hMenuInitWindow = GetSubMenu (hMenuInit, INIT_MENU_POS) ;
hMenuPrinterWindow = GetSubMenu (hMenuPrinter, PRINTER_MENU_POS) ;
//Load accelerator table
hAccel = LoadAccelerators (hInstance, szAppName) ;
//create frame window
//menu is loaded here
hwndFrame = CreateWindowEx(
WS_EX_CLIENTEDGE,
szFrameClass,
_T("Venture Day Walker"),
WS_CLIPCHILDREN|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
hMenuInit,
hInstance,
NULL);
if(hwndFrame == NULL)
{
MessageBox(NULL, _T("Main Window Creation Failed!"),_T("Error!"),MB_ICONEXCLAMATION|MB_OK);
return 0;
}
//get handle of the client window(as child of main window)
hwndClient = GetWindow(hwndFrame,GW_CHILD);
//Display the window
ShowWindow(hwndFrame, nCmdShow);
UpdateWindow (hwndFrame);
// Enter the modified message loop (due to use of accelerators)
while (GetMessage (&msg, NULL, 0, 0))
{
if (!TranslateMDISysAccel (hwndClient, &msg) &&
!TranslateAccelerator (hwndFrame, hAccel, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
// Clean up by deleting unattached menus
DestroyMenu (hMenuPrinter) ;
//end of WinMain
return msg.wParam;
}
/*=====================*/
//main window proc
LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient ;
CLIENTCREATESTRUCT clientcreate ;
HWND hwndChild, hwndChildStation ;
MDICREATESTRUCT mdicreate ;
switch (message)
{
case WM_CREATE:
// Create the client window
clientcreate.hWindowMenu = hMenuInitWindow ;
clientcreate.idFirstChild = IDM_FIRSTCHILD ;
hwndClient = CreateWindowEx (
WS_EX_CLIENTEDGE,
TEXT("MDICLIENT"),
NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
0, 0, 0, 0,
hwnd,
(HMENU) 1,
hInst,
(PSTR) &clientcreate) ;
// Create a station child window
//provide values 1st for the MDICREATESTRUCT
mdicreate.szClass = szStationClass;
mdicreate.szTitle = TEXT ("Station Details");
mdicreate.hOwner = hInstStation;
mdicreate.x = CW_USEDEFAULT;
mdicreate.y = CW_USEDEFAULT;
mdicreate.cx = CW_USEDEFAULT;
mdicreate.cy = CW_USEDEFAULT;
mdicreate.style = 0; //WS_HSCROLL | WS_VSCROLL ;
mdicreate.lParam = 0;
//sendmessage to create the child window using WM_MDICREATE and
hwndChildStation = (HWND) SendMessage (hwndClient,
WM_MDICREATE, 0,
(LPARAM) (LPMDICREATESTRUCT) &mdicreate);
break ;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_STATION_SETUP:
DialogBox(hInst, TEXT("IDD_SETUPSTATION"), hwnd, SetupStationDlgProc);
InvalidateRect (hwnd, NULL, TRUE) ;
break ;
case IDM_PRINTER_NEW:
// Create a printer child window
mdicreate.szClass = szPrinterClass ;
mdicreate.szTitle = TEXT ("Serial Number + Model No.") ;
mdicreate.hOwner = hInst ;
mdicreate.x = CW_USEDEFAULT ;
mdicreate.y = CW_USEDEFAULT ;
mdicreate.cx = CW_USEDEFAULT ;
mdicreate.cy = CW_USEDEFAULT ;
mdicreate.style = WS_HSCROLL | WS_VSCROLL ; //or '0' for just frames
mdicreate.lParam = 0 ;
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDICREATE, 0,
(LPARAM) (LPMDICREATESTRUCT) &mdicreate);
break ;
case IDM_PRINTER_CLOSE:
// Close the active printer window
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDIGETACTIVE, 0, 0) ;
if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))
SendMessage (hwndClient, WM_MDIDESTROY, (WPARAM) hwndChild, 0) ;
break ;
case IDM_APP_EXIT:
// Exit the program
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
break ;
// messages for arranging windows
case IDM_WINDOW_TILE:
SendMessage (hwndClient, WM_MDITILE, 0, 0) ;
break ;
case IDM_WINDOW_CASCADE:
SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;
break ;
case IDM_WINDOW_CLOSEALL: // Attempt to close all children
EnumChildWindows (hwndClient, CloseEnumProc, 0) ;
break ;
case IDM_ABOUT:
// About menu
MessageBox(NULL, _T("Thank You LORD!"),_T("Glory To GOD"),MB_ICONEXCLAMATION|MB_OK);
break ;
default:
// Pass to active child...
hwndChild = (HWND) SendMessage (hwndClient, WM_MDIGETACTIVE, 0, 0) ;
if (IsWindow (hwndChild))
SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
return 0 ; // ...and then to DefFrameProc
}
break ;
case WM_PAINT:
break ;
case WM_QUERYENDSESSION:
case WM_CLOSE: //frame
// Attempt to close all children
SendMessage (hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0) ;
//mark: if NULL, meaning no more child windows
if (NULL != GetWindow (hwndClient, GW_CHILD))
return 0 ;
break ; // i.e., call DefFrameProc
case WM_DESTROY: //frame
PostQuitMessage (0) ;
break ;
}
// Pass unprocessed messages to DefFrameProc (not DefWindowProc)
return DefFrameProc (hwnd, hwndClient, message, wParam, lParam) ;
}
//'printer' window proc=========================================
LRESULT CALLBACK PrinterWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient, hwndFrame;
HDC hdc;
HMENU hMenu;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
// Save some window handles
hwndClient = GetParent(hwnd);
hwndFrame = GetParent(hwndClient);
break;
case WM_COMMAND:
break;
case WM_PAINT:
break;
case WM_MDIACTIVATE:
// Set the Printer menu if gaining focus
if (lParam == (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuPrinter, (LPARAM)hMenuPrinterWindow);
// Set the Init menu if losing focus
if (lParam != (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuInit, (LPARAM)hMenuInitWindow);
DrawMenuBar(hwndFrame);
break;
case WM_QUERYENDSESSION:
case WM_CLOSE: //printer
if (IDOK != MessageBox(hwnd, TEXT("OK to close window?"), TEXT("Printer"), MB_ICONQUESTION | MB_OKCANCEL))
return 0;
break; // i.e., call DefMDIChildProc
case WM_DESTROY: //printer
break;
}
// Pass unprocessed message to DefMDIChildProc
return DefMDIChildProc(hwnd, message, wParam, lParam);
}
//'Station' window proc=============================
LRESULT CALLBACK StationWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient, hwndFrame;
HDC hdc;
HMENU hMenu;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
// Save some window handles
hwndClient = GetParent(hwnd);
hwndFrame = GetParent(hwndClient);
break;
case WM_PAINT:
break;
case WM_MDIACTIVATE:
break;
case WM_DESTROY: //station
break; //return 0 ;
}
// Pass unprocessed message to DefMDIChildProc
return DefMDIChildProc(hwnd, message, wParam, lParam);
}
//'close all' CloseEnumProc =========================================
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
TCHAR className[20];
int numChar = 20;
// Check for icon title
if (GetWindow(hwnd, GW_OWNER))
return TRUE;
GetClassName(hwnd, className, numChar);
if (strcmp(szPrinterClass, className) == 0)
{
//if window is minimized, restore to previous size
SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);
//then send ask to close
if (!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))
return TRUE;
SendMessage(GetParent(hwnd), WM_MDIDESTROY, (WPARAM)hwnd, 0);
return TRUE;
}
}
CloseEnumProc:
更改CloseEnumProc
如下:
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
const int numChar = 50;
TCHAR className[numChar];
GetClassName(hwnd, className, numChar);
if (strcmp(szPrinterClass, className) == 0)
{
SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);
SendMessage(hwnd, WM_CLOSE, 0, 0);
//optional:
//add this line incase there are multiple children,
//and you want to break the message after one CANCEL message
if (IsWindow(hwnd)) return FALSE;
}
return TRUE;
}
检查 SendMessage(hwnd, WM_CLOSE, 0, 0);
的结果没有意义,它应该始终为零。如果有多个childwindows,并且如果用户决定不关闭childwindow,则IsWindow(hwnd)
有效。您可能希望在那时打破循环。
FrameWndProc:
关闭主 window 时,您正在检查是否所有 children 在 IDM_WINDOW_CLOSEALL
消息后被销毁。但结果总是错误的,因为 "station" window 保持打开状态。
您应该看看是否还有一个以上 child window 剩余。如果只剩下一个child,那么那个child就是站window,你可以关闭它
LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
...
case WM_QUERYENDSESSION:
case WM_CLOSE:
{
SendMessage(hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
int child_count = 0;
HWND hchild = GetWindow(hwndClient, GW_CHILD);
if (hchild)
{
child_count++;
hchild = GetWindow(hchild, GW_HWNDNEXT);
if (hchild)
{
child_count++;
}
}
if (child_count < 2)
{
PostQuitMessage(0);
}
return 0;
}
}
编辑
StationWndProc:
如果站 window 处于活动状态,则 IDM_PRINTER_CLOSE
将关闭 stationWnd。改变这个 stationWnd 过程是你不想要的:
LRESULT CALLBACK StationWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CLOSE:
return 0;
default: break;
}
return DefMDIChildProc(hwnd, message, wParam, lParam);
}