winapi — C ++ MDI Выборочное закрытие дочернего окна

Привет! Я пытаюсь разработать MDI-программу на c ++, используя исключительно Win32 API (потому что мне нужно, чтобы программа была переносимой, то есть могла запускаться даже с USB, насколько это возможно, только .exe-файл).

Эта программа MDI имеет 2 типа (класса) дочерних окон: «MdiPrinterChild» и «MdiStationChild». Окно «MdiStationChild» создается автоматически и отображается после создания клиентской области главного окна (можно создать только одно окно «Станция»). Окно «MdiPrinterChild» создается только тогда, когда пользователь выбирает «Новый принтер» из меню и фактически может создать несколько дочерних окон «принтера». Когда дочернее окно «принтер» активно, может быть запущено меню «закрыть все», предположительно, чтобы закрыть все окна «принтера» (только). Проблема в том, что он также закрывает окно «станция». То же самое происходит, если нажать «х» в главном окне. Я попытался выборочное закрытие дочерних окон, используя имя класса дочернего окна (оператор if) внутри «CloseEnumProc», но на этот раз проблема, само приложение никогда не может быть закрыто. «Выход» из меню также не будет отвечать.

Ниже приведен код для 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;
}

}

0

Решение

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); это всегда должно быть ноль. Если имеется несколько дочерних окон, и если пользователь решил не закрывать дочернее окно, то IsWindow(hwnd) является действительным. Вы можете разорвать петлю в этой точке.

FrameWndProc:

Закрывая главное окно, вы проверяете, все ли дочерние элементы уничтожены после IDM_WINDOW_CLOSEALL сообщение. Но результат всегда ложный, потому что окно «станция» остается открытым.

Вместо этого вы должны увидеть, осталось ли более одного дочернего окна. Если остается только один дочерний элемент, то этот дочерний элемент является окном станции, и вы можете закрыть его

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:

Если окно станции активно, то IDM_PRINTER_CLOSE закроет станцию Измените это stationWnd proc, если вы этого не хотите:

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);
}
0

Другие решения


По вопросам рекламы [email protected]