質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1723閲覧

C++WINAPIでどのMDI子ウィンドウが破棄されたかが知る方法を知りたい

tettyA

総合スコア93

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/12/17 09:11

編集2020/12/17 11:15

二つ以上のMDI子ウィンドウから成るMDIアプリケーションに於いて、利用者が自らの手でそのウィンドウを削除したときに、どのMDI子ウィンドウが削除されたかを知る術はありますか。
もしあったら、その方法も教えてださい。

C++

1#include <windows.h> 2#include <commctrl.h> 3 4#include "resource.h" 5#include "common.h" 6 7#pragma comment(lib,"comctl32.lib") 8 9#define TITLE TEXT("MDI") 10#define MDI_FRAME TEXT("FRAMEWINDOW") 11#define MDI_CHILD TEXT("MDICHILD") 12 13HINSTANCE hIns;//現在のインターフェース 14HWND hCHildWndMap; 15HWND hChildWndTil; 16HWND hToolWnd; 17#define ID_CHILDWND 0x100 18LRESULT CALLBACK FrameProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { 19 static HWND hToolbar; 20 static HBITMAP hBitmap; 21 CLIENTCREATESTRUCT ccsClient; 22 static HWND hClientWindow; 23 switch (msg) 24 { 25 case WM_DESTROY: 26 ... 27 return 0; 28 case WM_CREATE: 29 InitCommonControls(); 30 ccsClient.idFirstChild = ID_CHILDWND; 31 32 hClientWindow = CreateWindow(TEXT("MDICLIENT"), NULL, 33 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_CLIPSIBLINGS, 34 0, 0, 0, 0, hWnd, (HMENU)1, ((LPCREATESTRUCT)lp)->hInstance, &ccsClient 35 ); 36 { 37 RECT wndrct; 38 GetWindowRect(hWnd, &wndrct); 39 40 hCHildWndMap = CreateMDIWindow(MDI_CHILD, TEXT("マップ"), 0, 41 0, 0, 42 300, 300, 43 hClientWindow, hIns, 0 44 ); 45 } 46 ... 47 return 0; 48 case WM_SIZE: 49 ... 50 return 0; 51 case WM_PAINT: 52 53 break; 54 case WM_COMMAND: 55 56 switch (LOWORD(wp)) 57 { 58 case IDM_NEWMINIMAP: 59 //チェックがついている 60 if (GetMenuState(GetMenu(hWnd), IDM_NEWMINIMAP, MF_BYCOMMAND) & MFS_CHECKED) { 61 SendMessage(hClientWindow, WM_MDIDESTROY, (WPARAM)hCHildWndMap, 0); 62 CheckMenuItem(GetMenu(hWnd), IDM_NEWMINIMAP, MFS_UNCHECKED); 63 } 64 else {//ついていない 65 hCHildWndMap = CreateMDIWindow(MDI_CHILD, TEXT("マップ"), 0, 66 0, 0, 67 300, 300, 68 hClientWindow, hIns, 0 69 ); 70 CheckMenuItem(GetMenu(hWnd), IDM_NEWMINIMAP, MFS_CHECKED); 71 } 72 break; 73 } 74 } 75 return DefFrameProc(hWnd, hClientWindow, msg, wp, lp); 76} 77int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 78 PSTR lpCmdLine, int nCmdShow) { 79 HWND hWnd; 80 MSG msg; 81 WNDCLASS winc; 82 hIns = hInstance; 83 84 ... 85 86 winc.lpfnWndProc = DefMDIChildProc; 87 winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 88 winc.lpszClassName = MDI_CHILD; 89 90 91 if (!RegisterClass(&winc)) return 1; 92 93 hWnd = CreateWindow( 94 MDI_FRAME, TITLE, 95 WS_OVERLAPPEDWINDOW|WS_MAXIMIZE|WS_VISIBLE|WS_CLIPCHILDREN, 96 CW_USEDEFAULT, CW_USEDEFAULT, 97 CW_USEDEFAULT, CW_USEDEFAULT, 98 NULL, NULL, hInstance, NULL 99 ); 100 101 ... 102 103 return msg.wParam; 104}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/12/17 10:27 編集

さすがにコードを提示しないと回答しづらいと思いますよ。過去質問のこちらのコードが元でしょうか。 [WINAPIでMDI子ウィンドウが存在するのに表示されない] https://teratail.com/questions/303445 子ウィンドウが閉じるときに親ウィンドウへ通知される既定のメッセージは特に無かったと思うので、サブクラス化し、MDI子ウィンドウが終了するWM_DESTROY時にでも親ウィンドウへ独自メッセージをポストして通知すれば良いのでは、という気がします。MDI子ウィンドウで試したことは無いのでできるかどうか分かりませんが。
tettyA

2020/12/17 11:12

コードを追加しておきました。
guest

回答1

0

ベストアンサー

利用者が自らの手でそのウィンドウを削除したときに、どのMDI子ウィンドウが削除されたかを知る術はありますか。

もしあったら、その方法も教えてださい。

質問者さんのオリジナルのコードではMDI子ウィンドウのウィンドウプロシージャとしてDefMDIChildProcを指定していますが、これを自分で実装したウィンドウプロシージャにすることでMDI子ウィンドウへ送信されるメッセージがハンドリングできるので、そうすると良いです。例えばWM_CLOSEで閉じる/閉じない制御をしたり、WM_DESTROYの受信時にフレームウィンドウへ独自メッセージをポストすることでMDI子ウィンドウが閉じられることを伝えることができます。以下はそのようにしてみたサンプルプログラムです。Visual Studio 2019でビルドし、Windows 10で動作確認しました。

尚、質問者さんのコードを補完するために、以下のサイト様の記事とサンプルコードを参考にさせていただいています。
MDI 複数の作業ウィンドウ - Win32 API入門

C++

1// MdiTest1.cpp: 2#include <windows.h> 3#include <commctrl.h> 4 5#include "resource.h" 6//#include "common.h" 7 8#pragma comment(lib,"comctl32.lib") 9 10#define TITLE TEXT("MDI") 11#define MDI_FRAME TEXT("FRAMEWINDOW") 12#define MDI_CHILD TEXT("MDICHILD") 13 14HINSTANCE hIns; 15HWND hChildWndMap; 16HWND hChildWndTil; 17HWND hToolWnd; 18 19#define ID_CHILDWND 0x100 20 21static HWND hFrameWindow = NULL; 22 23// 独自メッセージ 24#define WM_MDICHILDWINDOW1 (WM_APP+10) 25 26LRESULT CALLBACK MyMDIChildProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 27 28LRESULT CALLBACK FrameProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { 29 static HWND hToolbar; 30 static HBITMAP hBitmap; 31 CLIENTCREATESTRUCT ccsClient; 32 static HWND hClientWindow; 33 34 switch (msg) { 35 case WM_DESTROY: 36 PostQuitMessage(0); 37 return 0; 38 39 case WM_CREATE: 40 InitCommonControls(); 41 ccsClient.idFirstChild = ID_CHILDWND; 42 43 hClientWindow = CreateWindow(TEXT("MDICLIENT"), NULL, 44 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_CLIPSIBLINGS, 45 0, 0, 0, 0, hWnd, (HMENU)1, ((LPCREATESTRUCT)lp)->hInstance, &ccsClient 46 ); 47 { 48 RECT wndrct; 49 GetWindowRect(hWnd, &wndrct); 50 51 hChildWndMap = CreateMDIWindow(MDI_CHILD, TEXT("マップ"), 0, 52 0, 0, 53 300, 300, 54 hClientWindow, hIns, 0 55 ); 56 } 57 return 0; 58 59 case WM_COMMAND: 60 switch (LOWORD(wp)) { 61 case IDM_NEWMINIMAP: 62 //チェックがついている 63 if (GetMenuState(GetMenu(hWnd), IDM_NEWMINIMAP, MF_BYCOMMAND) & MFS_CHECKED) { 64 SendMessage(hClientWindow, WM_MDIDESTROY, (WPARAM)hChildWndMap, 0); 65 CheckMenuItem(GetMenu(hWnd), IDM_NEWMINIMAP, MFS_UNCHECKED); 66 } 67 else {//ついていない 68 hChildWndMap = CreateMDIWindow(MDI_CHILD, TEXT("マップ"), 0, 69 0, 0, 70 300, 300, 71 hClientWindow, hIns, 0 72 ); 73 CheckMenuItem(GetMenu(hWnd), IDM_NEWMINIMAP, MFS_CHECKED); 74 } 75 break; 76 } 77 break; 78 79 case WM_MDICHILDWINDOW1: 80 { 81 char s[256]; 82 wsprintfA(s, "WM_MDICHILDWINDOW1 from hwnd=0x%X (hChildWndMap=0x%X)", lp, (UINT_PTR)hChildWndMap); 83 MessageBoxA(hWnd, s, "MDI", MB_OK); 84 HMENU hMenu = GetMenu(hWnd); 85 UINT ret = GetMenuState(hMenu, IDM_NEWMINIMAP, MF_BYCOMMAND); 86 if ((ret & MFS_CHECKED) != 0) { 87 CheckMenuItem(hMenu, IDM_NEWMINIMAP, MFS_UNCHECKED); 88 } 89 // 処理済み 90 return 0L; 91 } 92 93 case WM_MDIDESTROY: 94 OutputDebugStringA("WM_MDIDESTROY\n"); 95 break; 96 } 97 98 return DefFrameProc(hWnd, hClientWindow, msg, wp, lp); 99} 100 101int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 102 _In_opt_ HINSTANCE hPrevInstance, 103 _In_ LPWSTR lpCmdLine, 104 _In_ int nCmdShow) 105{ 106 HWND hWnd; 107 MSG msg; 108 WNDCLASS winc; 109 hIns = hInstance; 110 111 winc.style = CS_HREDRAW | CS_VREDRAW; 112 winc.lpfnWndProc = FrameProc; 113 winc.cbClsExtra = winc.cbWndExtra = 0; 114 winc.hInstance = hInstance; 115 winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 116 winc.hCursor = LoadCursor(NULL, IDC_ARROW); 117 winc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); 118 winc.lpszMenuName = MAKEINTRESOURCE(IDC_MDITEST1); 119 winc.lpszClassName = MDI_FRAME; 120 121 if (!RegisterClass(&winc)) return 1; 122 123 //winc.lpfnWndProc = DefMDIChildProc; 124 // MDI子ウィンドウ用のウィンドウプロシージャで処理 125 winc.lpfnWndProc = MyMDIChildProc; 126 winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 127 winc.lpszClassName = MDI_CHILD; 128 129 if (!RegisterClass(&winc)) return 1; 130 131 hWnd = CreateWindow( 132 MDI_FRAME, TITLE, 133 WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | WS_VISIBLE | WS_CLIPCHILDREN, 134 CW_USEDEFAULT, CW_USEDEFAULT, 135 CW_USEDEFAULT, CW_USEDEFAULT, 136 NULL, NULL, hInstance, NULL 137 ); 138 139 if (hWnd == NULL) return 1; 140 141 // グローバル変数に保存しておく 142 hFrameWindow = hWnd; 143 144 while (GetMessage(&msg, NULL, 0, 0)) { 145 TranslateMessage(&msg); 146 DispatchMessage(&msg); 147 } 148 149 return msg.wParam; 150} 151 152LRESULT CALLBACK MyMDIChildProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 153{ 154 switch (uMsg) { 155 case WM_CLOSE: 156 OutputDebugStringA("WM_CLOSE\n"); 157 { 158 int ret = MessageBoxA(hWnd, "閉じますか?", "MDI", MB_OKCANCEL); 159 if (ret == IDOK) { 160 DestroyWindow(hWnd); 161 } 162 } 163 return 0L; 164 165 case WM_DESTROY: 166 OutputDebugStringA("WM_DESTROY\n"); 167 if (hFrameWindow != NULL) { 168 // フレームウィンドウへ通知 169 PostMessage(hFrameWindow, WM_MDICHILDWINDOW1, 0, (LPARAM)hWnd); 170 } 171 // DefMDIChildProc()による既定の処理を続行 172 break; 173 174 default: 175 break; 176 } 177 178 return DefMDIChildProc(hWnd, uMsg, wParam, lParam); 179}

投稿2020/12/21 02:24

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tettyA

2020/12/26 05:44

ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問