【发布时间】:2015-08-24 13:56:53
【问题描述】:
您好,我正在尝试使用纯 Win32 API 开发一个 c++ MDI 程序(因为我需要该程序是可移植的,即甚至可以从 USB 运行,尽可能仅使用 .exe 文件)。
这个 MDI 程序有 2 种类型(类)的子窗口,“MdiPrinterChild”和“MdiStationChild”。一旦创建主窗口的客户区,“MdiStationChild”窗口就会自动创建并显示(只能创建一个“Station”窗口)。 “MdiPrinterChild”窗口仅在用户从菜单中选择“新打印机”时创建,并且实际上可以创建多个“打印机”子窗口。当“打印机”子窗口处于活动状态时,可以触发“全部关闭”菜单,据说会关闭所有“打印机”窗口(仅)。问题是,它也关闭了“站”窗口。如果单击主窗口的“x”,也会发生同样的事情。我尝试通过在“CloseEnumProc”内部使用子窗口的类名(if 语句)来选择性地关闭子窗口,但这一次问题是,应用程序本身永远无法关闭。菜单中的“退出”同样不会响应。
下面是 CloseEnumProc 的 codef,但是如果这个代码真的不可行,谁能给我一个示例代码如何做到这一点。谢谢。
#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;
}
}
【问题讨论】:
-
您应该添加
WinMain和程序的其余部分以获得最低工作版本。 -
嗨,巴马克,谢谢。我已经添加了winmain。有点乱,但我希望它会有所帮助。总结 - 具有两类子窗口的 MDI。第一个子窗口(站)将立即打开(但只允许 1 个窗口并且禁用“x”按钮),第二个子窗口(打印机)可以通过菜单打开,但最多只能打开 3 个窗口。 “全部关闭”应该只关闭“打印机”窗口。在此先感谢大家。
-
您的代码包含很多与问题无关的内容并阻止编译代码。以备将来参考,请将其取出。
-
嗨,巴马克,非常感谢!以应有的方式工作。对不起,混乱的,不相关的代码。它实际上是 MDI 上的 Petzold 示例代码,然后慢慢更改为我需要的。现在它的工作。好样的!谢谢!
标签: c++ winapi mdichild childwindow