2018年7月9日 星期一

在Win32視窗程式中開啟console視窗

在Win32視窗程式中開啟console視窗

前言

  用Win32視窗程式寫出來的測試程式一直以來有個麻煩,就是切換測試項目(如測試光、測試影子...等)時會需要終止程式後,修改部分的code後再run一次,如果能有個debug的工具可以在不關閉程式的狀況下修改程式特定的參數不是很好嗎?可是如果自己了視窗的控件再交由C++來控制的話,成本實在有點高,如果有個console視窗可以輸入命令和輸出結果就可以解決上述的問題。在此把學習的過程做個紀錄。

內容

  使用的示範如下
  //Open console...
  AllocConsole();
  std::wstring strW = L"Dev Console";
  SetConsoleTitle( strW.c_str() );
  DrawMenuBar(GetConsoleWindow());
  //
  //call ReadConsole() or WriteConsole() to control console
  //...
  //Close console...
  FreeConsole();

開啟console視窗後,用ReadConsole()與WriteConsole()來控制輸入與輸出,但這兩個funciton的參數不是很用,如果可以將輸出入的結果導到stdin與stdout的話,就可以直接使用C++的IO function(scanf、printf...等),這樣用起來比較直接也比較好懂,所以導到stdin與stdout的範例如下
  //Open console...
  AllocConsole();
  std::wstring strW = L"Dev Console";
  SetConsoleTitle( strW.c_str() );
  DrawMenuBar(GetConsoleWindow());
  //Redirection IO to stdin and stdout 
  freopen( "CON", "r", stdin ) ;
  freopen( "CON", "w", stdout ) ;
  //call c++ IO function to control console
  //...
  //Close console...
  FreeConsole();

上述的範例如果要搭配Win32視窗程式使用的話,需要自己產生一個thread去控制輸入,為什麼呢?因為IO的輸入是block funciton,如果使用主thread去取得IO的輸入的話,整個程式都會停頓下來,這點請務必注意!
  接著還有一個麻煩是要將控制輸入的thread停下來的問題,當企圖停下一個thread時的標準做法是用WaitForSingleObject()來等待結束,可是scanf()或std::cin並不會自己中斷等待,所以需要給"假的"輸入來中斷IO的等待,範例如下

  //abort console inpurt
  HWND hWndConsole=GetConsoleWindow();
  INPUT ip[2];
  ip[0].type = INPUT_KEYBOARD;
  ip[0].ki.wVk = 0x41;;
  ip[0].ki.wScan = 0;
  ip[0].ki.dwFlags = 0;
  ip[0].ki.time = 0;
  ip[0].ki.dwExtraInfo = 0;
  ip[1].type = INPUT_KEYBOARD;
  ip[1].ki.wVk = VK_RETURN;
  ip[1].ki.wScan = 0;
  ip[1].ki.dwFlags = 0;
  ip[1].ki.time = 0;
  ip[1].ki.dwExtraInfo = 0;
  SendInput(2, ip, sizeof(INPUT) );

在範例中是輸入"a"和"enter"去中止console的blocking,要注意指輸入一個"enter"是無法中止blocking,必須要有一個有效的字元!

後記

  如果有看微軟的console使用說明Consoles的話,會發現還有其他的控制function可以使用,但由於本次的需求不需要用到所以都沒提到,有機會再來研究研究。

參考資料

Creation of a Console
Create window console inside main win32 window
Consoles

沒有留言:

張貼留言