Solution46
CConsoleMenu.cpp
[詳解]
1 //=============================================================================
2 /// @file
3 /// コンソールメニュークラス実装ファイル
4 ///
5 /// コンソールメニュークラス実装ファイルです。
6 ///
7 /// $Id: CConsoleMenu.cpp 245 2019-03-20 15:03:41Z admin $
8 /// $Date: 2019-03-21 00:03:41 +0900 (2019/03/21 (木)) $
9 /// $Author: admin $
10 ///
11 /// @attention なし
12 
13 #pragma managed( push, off )
14 
15 //=============================================================================
16 // インクルードファイル
17 #include <CConsoleMenu.h>
18 #include <CConsole.h>
19 #include <CSyncAuto.h>
20 #include <LibUtility.h>
21 
22 //=============================================================================
23 // 共通ライブラリ名前空間
24 namespace LibCommon {
25  //=========================================================================
26  // コンソールメニュークラス
27  //=========================================================================
28  // 構築子と解体子
29  //-------------------------------------------------------------------------
30  // コンストラクタ
31  CConsoleMenu::CConsoleMenu( SMenuInfo const* psMenuInfo ) noexcept
32  // 基底クラスコンストラクタ
33  : CMutex()
34  // メンバ変数初期化
35  , m_psMenuInfo( psMenuInfo )
36  , m_cEventRequest()
37  , m_cEventNotify()
38  , m_cEventFinish()
39  , m_cThreadSub()
40  , m_nMenuIndex( 0 )
41  , m_nRepeat( 0 )
42  , m_bRepeat( false )
43  , m_bSubMenu( false )
44  , m_pcSubMenu( nullptr )
45  , m_pcParent( nullptr )
46  {
47  // 処理ブロック
48  do {
49  // ミューテックスを作成する
50  if ( !Create() ) {
51  // 致命的エラー!
53  break;
54  }
55  // 同期処理ブロック
56  else do {
57  CSyncAuto cSyncAuto( *this );
58 
59  // 要求イベントを作成する
60  if ( !m_cEventRequest.Create() ) {
61  // 致命的エラー!
63  break;
64  }
65  // 通知イベントを作成する
66  else if ( !m_cEventNotify.Create() ) {
67  // 致命的エラー!
69  break;
70  }
71  // 終了イベントを作成する
72  else if ( !m_cEventFinish.Create() ) {
73  // 致命的エラー!
75  break;
76  }
77  } while ( false );
78  } while ( false );
79  }
80 
81  //=========================================================================
82  // 公開関数
83  //-------------------------------------------------------------------------
84  // メニュー開始関数
85  bool CConsoleMenu::StartMenu() noexcept {
86  // 処理ブロック
87  bool result = false;
88  do {
89  // メニュー実行状態を調べる
90  if ( IsExecMenu() ) {
91  // 失敗!
92  break;
93  }
94  // 同期処理ブロック
95  else do {
96  CSyncAuto cSyncAuto( *this );
97 
98  // 要求イベントをリセットする
99  if ( !m_cEventRequest.Reset() ) {
100  // 失敗!
101  break;
102  }
103  // 通知イベントをリセットする
104  else if ( !m_cEventNotify.Reset() ) {
105  // 失敗!
106  break;
107  }
108  // 終了イベントをリセットする
109  else if ( !m_cEventFinish.Reset() ) {
110  // 失敗!
111  break;
112  }
113  // サブスレッドを起動する
114  else if ( !m_cThreadSub.Create( SubThreadProc, this ) ) {
115  // 失敗!
116  break;
117  }
118 
119  // 成功!
120  result = true;
121  } while ( false );
122  } while ( false );
123 
124  // 実行結果を返す
125  return result;
126  }
127 
128  //-------------------------------------------------------------------------
129  // メニュー中止要求関数
130  void CConsoleMenu::StopMenu() noexcept {
131  // メニュー実行状態を調べる
132  if ( IsExecMenu() ) {
133  // コンソール入力の中止を要求する
135 
136  // メニュー中止要求フラグをセットする
137  s_bStopMenu = true;
138 
139  // 終了イベントを待機する
141 
142  // 改行する
143  ConsoleNewLine();
144  ConsoleNewLine();
145  ConsoleLine( L"メニューを中止しました。" );
146  ConsoleNewLine();
147  }
148  }
149 
150  //-------------------------------------------------------------------------
151  // メニュー実行関数
152  bool CConsoleMenu::ExecMenu() noexcept {
153  // 処理ブロック
154  bool result = false;
155  do {
156  // メニュー実行状態を調べる
157  if ( !IsExecMenu() ) {
158  // 終了!
159  break;
160  }
161  // 同期処理ブロック
162  else do {
163  CSyncAuto cSyncAuto( *this, 0 );
164 
165  // ロック状態を調べる
166  if ( cSyncAuto.IsLock() ) {
167  // サブメニュー要求フラグとサブメニューポインタを調べる
168  if ( !m_bSubMenu && ( nullptr != m_pcSubMenu ) ) {
169  // サブメニューの実行関数を実行する
171  }
172  // 要求イベントを調べる
173  else if ( m_cEventRequest.Wait( 0 ) ) {
174  // サブメニュー要求フラグを調べる
175  if ( m_bSubMenu ) {
176  // サブメニューポインタを調べる
177  if ( nullptr == m_pcSubMenu ) {
178  // サブメニューを取得する
180 
181  // 親メニューポインタを設定する
182  m_pcSubMenu->m_pcParent = this;
183 
184  // サブメニューを開始する
185  if ( !m_pcSubMenu->StartMenu() ) {
186  // サブメニューを削除する
187  delete m_pcSubMenu;
188  m_pcSubMenu = nullptr;
189 
190  // 失敗!
191  break;
192  }
193  }
194  else {
195  // サブメニューを削除する
196  delete m_pcSubMenu;
197  m_pcSubMenu = nullptr;
198  }
199  }
200  else {
201  // メニューコールバック関数を実行する
203  }
204 
205  // 通知イベントをセットする
206  if ( !m_cEventNotify.Set() ) {
207  // 失敗!
208  break;
209  }
210  }
211  }
212 
213  // 成功!
214  result = true;
215  } while ( false );
216  } while ( false );
217 
218  // 実行結果を返す
219  return result;
220  }
221 
222  //=========================================================================
223  // 限定公開関数
224  //-------------------------------------------------------------------------
225  // サブスレッド実行関数
226  bool CConsoleMenu::ExecSubThread() noexcept {
227  // 同期処理ブロック
228  bool result = false;
229  do {
230  // サブメニュー要求フラグをクリアする
231  m_bSubMenu = false;
232 
233  // 同期処理ブロック
234  do {
235  CSyncAuto cSyncAuto( *this );
236 
237  // リピート実行フラグを調べる
238  if ( m_bRepeat ) {
239  // リピートカウントをインクリメントする
240  ++m_nRepeat;
241 
242  // 事前メニューコールバック関数を実行する
243  if ( MenuCallBackProc( true ) ) {
244  // 成功!
245  result = true;
246  break;
247  }
248  }
249 
250  // リピートカウントをクリアする
251  m_nRepeat = 0;
252 
253  // リピート実行フラグをクリアする
254  m_bRepeat = false;
255 
256  // 巡回する
257  for ( bool bInitialize = true;; ) {
258  // 初期化フラグを調べる
259  if ( bInitialize ) {
260  // 初期化フラグをクリアする
261  bInitialize = false;
262 
263  // メニュー名称を表示する
264  ConsoleLine( L"//=========================================================================" );
265  ConsoleLine( L"// %s", m_psMenuInfo->m_pszName );
266 
267  // メニュー項目を表示する
268  for ( int nIndex = 0; m_psMenuInfo->m_nCount > nIndex; ++nIndex ) {
269  // メニュー項目名称を表示する
270  ConsoleLine( L"%4c: %s", ITEM_KEY_LIST[ nIndex ], m_psMenuInfo->m_psItemInfo[ nIndex ].m_pszItemName );
271  }
272 
273  // 親メニューポインタを調べる
274  if ( nullptr == m_pcParent ) {
275  // 中止項目を表示する
276  ConsoleLine( L" ESC: 終了" );
277  }
278  else {
279  // 戻る項目を表示する
280  ConsoleLine( L" ESC: 戻る" );
281  }
282 
283  // 入力待ちを表示する
284  ConsoleString( L"選択: " );
285  }
286 
287  // 1文字入力する
288  wchar_t ch = L'\0';
289  if ( !ConsoleInputChar( ch ) ) {
290  // 失敗!
291  break;
292  }
293  // メニュー中止要求フラグを調べる
294  else if ( s_bStopMenu ) {
295  // 終了!
296  break;
297  }
298  // 文字コードを調べる
299  else if ( L'\033' == ch ) {
300  // 終了可能か調べる
301  ConsoleLine( L"ESC" );
302  ConsoleNewLine();
303  if ( !CanBeExit() ) {
304  // 初期化フラグをセットする
305  bInitialize = true;
306 
307  // 継続!
308  continue;
309  }
310  // 親メニューポインタを調べる
311  else if ( nullptr == m_pcParent ) {
312  // 確認する
313  if ( !ConsoleYesNo( L"メニューを終了しますか?" ) ) {
314  // 初期化フラグをセットする
315  bInitialize = true;
316 
317  // 継続!
318  ConsoleNewLine();
319  continue;
320  }
321  ConsoleNewLine();
322  }
323 
324  // 終了!
325  break;
326  }
327 
328  // インデックス文字コードを調べる
329  wchar_t const* pszIndex = ::wcschr( ITEM_KEY_LIST, ::towupper( ch ) );
330  if ( nullptr == pszIndex ) {
331  // 継続!
332  continue;
333  }
334 
335  // メニュー項目インデックスを取得する
336  m_nMenuIndex = static_cast< int >( pszIndex - ITEM_KEY_LIST );
337  if ( m_psMenuInfo->m_nCount <= m_nMenuIndex ) {
338  // 継続!
339  continue;
340  }
342  ConsoleNewLine();
343 
344  // サブメニューか調べる
345  if ( m_psMenuInfo->m_psItemInfo[ m_nMenuIndex ].m_bSubMenu ) {
346  // サブメニュー要求フラグをセットする
347  m_bSubMenu = true;
348  break;
349  }
350  else {
351  // メニュー項目タイトルを表示する
352  ConsoleLine( L"//-------------------------------------------------------------------------" );
353  ConsoleLine( L"// %s", m_psMenuInfo->m_psItemInfo[ m_nMenuIndex ].m_pszItemName );
354  ConsoleNewLine();
355 
356  // 事前メニューコールバック関数を実行する
357  if ( !MenuCallBackProc( true ) ) {
358  // 初期化フラグをセットする
359  bInitialize = true;
360 
361  // 継続!
362  continue;
363  }
364  }
365 
366  // 成功!
367  result = true;
368  break;
369  }
370  } while ( false );
371 
372  // サブメニュー要求フラグを調べる
373  if ( m_bSubMenu ) {
374  // 要求イベントをセットする
375  if ( !m_cEventRequest.Set() ) {
376  // 失敗!
377  break;
378  }
379  // 通知イベントを待機する
380  else if ( !m_cEventNotify.Wait() ) {
381  // 失敗!
382  break;
383  }
384 
385  // サブメニュー要求フラグをクリアする
386  m_bSubMenu = false;
387 
388  // サブメニューポインタを調べる
389  if ( nullptr == m_pcSubMenu ) {
390  // 失敗!
391  break;
392  }
393  // サブメニューが終了するまで待機する
394  else if ( !m_pcSubMenu->WaitForMenuFinish() ) {
395  // 失敗!
396  break;
397  }
398  // メニュー中止要求フラグを調べる
399  else if ( s_bStopMenu ) {
400  // 終了!
401  break;
402  }
403 
404  // サブメニュー要求フラグをセットする
405  m_bSubMenu = true;
406 
407  // 要求イベントをセットする
408  if ( !m_cEventRequest.Set() ) {
409  // 失敗!
410  break;
411  }
412  // 通知イベントを待機する
413  else if ( !m_cEventNotify.Wait() ) {
414  // 失敗!
415  break;
416  }
417 
418  // サブメニュー要求フラグをクリアする
419  m_bSubMenu = false;
420 
421  // サブメニューポインタを調べる
422  if ( nullptr != m_pcSubMenu ) {
423  // 失敗!
424  break;
425  }
426 
427  // 成功!
428  result = true;
429  break;
430  }
431  // 実行結果を調べる
432  else if ( !result ) {
433  // 失敗!
434  break;
435  }
436  // 要求イベントをセットする
437  else if ( !m_cEventRequest.Set() ) {
438  // 失敗!
439  break;
440  }
441  // 通知イベントを待機する
442  else if ( !m_cEventNotify.Wait() ) {
443  // 失敗!
444  break;
445  }
446  } while ( false );
447 
448  // 実行結果を返す
449  return result;
450  }
451 
452  //=========================================================================
453  // 静的限定公開関数
454  //-------------------------------------------------------------------------
455  // サブスレッド関数
456  DWORD CConsoleMenu::SubThreadProc( LPVOID lpParam ) noexcept {
457  // 処理ブロック
458  DWORD result = 0;
459  do {
460  // インスタンスポインタを取得する
461  CConsoleMenu*& rpcInstance = reinterpret_cast< CConsoleMenu*& >( lpParam );
462  if ( nullptr == rpcInstance ) {
463  // 致命的エラー!
465  break;
466  }
467  // 巡回する
468  else for ( ;; ) {
469  // サブスレッド実行関数を実行する
470  if ( !rpcInstance->ExecSubThread() ) {
471  // 終了!
472  break;
473  }
474  }
475 
476  // 終了イベントをセットする
477  rpcInstance->m_cEventFinish.Set();
478  } while ( false );
479 
480  // 実行結果を返す
481  return result;
482  }
483 
484  //=========================================================================
485  // 静的限定公開文字列定数
486  wchar_t const* const CConsoleMenu::ITEM_KEY_LIST = L"123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
487 
488  //=========================================================================
489  // 静的限定公開変数
490  bool CConsoleMenu::s_bStopMenu = false;
491 }
492 
493 #pragma managed( pop )
SMenuInfo const * m_psMenuInfo
メニュー定義情報構造体ポインタ
Definition: CConsoleMenu.h:225
CConsoleMenu * m_pcSubMenu
サブメニューポインタ
Definition: CConsoleMenu.h:234
#define NotifyFatalError()
致命的エラー発生通知マクロ
Definition: LibUtility.h:22
static DWORD WINAPI SubThreadProc(LPVOID lpParam) noexcept
サブスレッド関数
virtual bool CanBeExit() const noexcept
終了可能状態取得関数
Definition: CConsoleMenu.h:166
メニュー定義情報構造体
Definition: CConsoleMenu.h:55
コンソールメニュークラスヘッダファイル
virtual bool StartMenu() noexcept
メニュー開始関数
bool m_bRepeat
リピート実行フラグ
Definition: CConsoleMenu.h:232
virtual bool IsExecMenu() noexcept
実行状態取得関数
Definition: CConsoleMenu.h:100
CThread m_cThreadSub
サブスレッド
Definition: CConsoleMenu.h:229
bool m_bSubMenu
サブメニューフラグ
Definition: CConsoleMenu.h:45
#define ConsoleYesNo(...)
確認入力待ちマクロ
Definition: CConsole.h:66
virtual bool WaitForMenuFinish(DWORD dwTime=INFINITE) noexcept
メニュー終了待ち関数
Definition: CConsoleMenu.h:153
#define ConsoleNewLine()
改行出力マクロ
Definition: CConsole.h:29
CConsoleMenu(SMenuInfo const *psMenuInfo) noexcept
コンストラクタ
virtual bool Wait(DWORD dwTime=INFINITE) noexcept
ウェイト関数
Definition: CSync.cpp:59
virtual CConsoleMenu * GetSubMenu() const noexcept
サブメニュー取得関数
Definition: CConsoleMenu.h:177
int const m_nCount
メニュー項目数
Definition: CConsoleMenu.h:57
virtual bool Create(LPTHREAD_START_ROUTINE pfnFunc, LPVOID lpParam) noexcept
作成関数
Definition: CThread.cpp:63
共通ライブラリ名前空間
Definition: CArray.h:23
コンソールメニュークラス
Definition: CConsoleMenu.h:32
CEvent m_cEventRequest
要求イベント
Definition: CConsoleMenu.h:226
int m_nRepeat
リピートカウント
Definition: CConsoleMenu.h:231
ミューテックスクラス
Definition: CMutex.h:30
static wchar_t const *const ITEM_KEY_LIST
項目選択文字リスト
Definition: CConsoleMenu.h:240
int m_nMenuIndex
メニュー項目インデックス
Definition: CConsoleMenu.h:230
自動同期クラス
Definition: CSyncAuto.h:30
virtual bool Set() noexcept
シグナルセット関数
Definition: CEvent.cpp:130
virtual bool IsLock() const noexcept
ロック状態取得関数
Definition: CSyncAuto.h:71
コンソール入出力クラスヘッダコンソール
#define ConsoleString(...)
文字列出力マクロ
Definition: CConsole.h:27
virtual bool Reset() noexcept
シグナルリセット関数
Definition: CEvent.cpp:150
wchar_t const *const m_pszItemName
項目名称
Definition: CConsoleMenu.h:44
CEvent m_cEventNotify
通知イベント
Definition: CConsoleMenu.h:227
virtual void StopMenu() noexcept
メニュー中止要求関数
#define ConsoleLine(...)
ヘッダインデントなし書式設定文字列行出力マクロ
Definition: CConsole.h:34
static bool s_bStopMenu
メニュー中止要求フラグ
Definition: CConsoleMenu.h:245
virtual bool ExecMenu() noexcept
メニュー実行関数
bool m_bSubMenu
サブメニュー要求フラグ
Definition: CConsoleMenu.h:233
自動同期クラスヘッダファイル
SMenuItemInfo const * m_psItemInfo
メニュー項目情報構造体配列ポインタ
Definition: CConsoleMenu.h:58
#define ConsoleInputChar(...)
1文字入力マクロ
Definition: CConsole.h:60
#define ConsoleStopInput()
入力中止要求マクロ
Definition: CConsole.h:67
CConsoleMenu * m_pcParent
親メニューポインタ
Definition: CConsoleMenu.h:235
virtual bool MenuCallBackProc(bool bPreCallBack=false) noexcept
メニューコールバック関数
Definition: CConsoleMenu.h:190
ユーティリティライブラリヘッダファイル
virtual bool ExecSubThread() noexcept
サブスレッド実行関数
wchar_t const *const m_pszName
メニュー名称
Definition: CConsoleMenu.h:56
CEvent m_cEventFinish
終了イベント
Definition: CConsoleMenu.h:228