找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 1631|回复: 0

让Win32窗口程序拥有控制台窗口

[复制链接]

7

主题

4

回帖

5154

积分

用户组: 技术宅的结界VIP成员

UID
641
精华
1
威望
13 点
宅币
5111 个
贡献
1 次
宅之契约
0 份
在线时间
11 小时
注册时间
2015-1-28
发表于 2017-7-31 22:08:46 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 略游 于 2017-7-31 22:13 编辑

让Win32窗口程序拥有控制台窗口
    首先,为什么我们有了普通窗口后还要控制台窗口呢?因为我们可以用它方便的输出调试信息,而且普通玩家看到了也会觉得很高端。如果他会输几条命令,可能他会以为自己就是黑客了。
示例效果:
    WinMain作为入口函数后,手动创建了控制台窗口,然后创建了普通窗口,输出了一些信息到控制台窗口。

1.png



具体实现:
    为什么我不用main作为入口函数,再创建普通窗口呢?因为用户不可以选择关闭控制台窗口。如果强行实现就是先找到窗口句柄然后再调用ShowWindow隐藏掉窗口。但实际还是会闪一下,其实大家可以发现有一些比较low的病毒双击后就会闪一下。
    要创建一个控制台窗口,首先调用AllocConsole创建一个。但此时调用cout或者printf都不能正常输出文字到窗口(包括输入流cin和scanf)。所以需要如下重定向输入输出流:

  1. AllocConsole();
  2. FILE* stream;
  3. freopen_s(&stream, "CON", "r", stdin);//重定向输入流
  4. freopen_s(&stream, "CON", "w", stdout);//重定向输入流
复制代码


    如果我们需要用到控制台窗口句柄,可以调用FindWindow取得:
  1. HWND _consoleHwnd;
  2. SetConsoleTitle(DEFAULT_CONSOLE_TITLE);//设置窗口名
  3. for (int i = 0; i < 100; i++)
  4. {
  5.         _consoleHwnd = FindWindow(NULL, DEFAULT_CONSOLE_TITLE);
  6.         if (_consoleHwnd)
  7.                 break;
  8.         Sleep(100);
  9. }
复制代码

    然后还需要输出流句柄:
  1. HANDLE _handleOutput;
  2. _handleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
复制代码

    在不需要的时候请调用FreeConsole释放控制台窗口:
  1. FreeConsole();
复制代码

    完成以上工作后,就能够创建一个控制台窗口,并能够使用cout标准输出流输出文字到其上。这里我们用wcout为例,并给文字添加上颜色:
  1. void DebuggerConsole::Write(const String& str, int level)
  2. {
  3.         switch(level)
  4.         {
  5.         case DebugLevel::BLANK://空白
  6.                 SetConsoleTextAttribute(_handleOutput,
  7.                                 FOREGROUND_INTENSITY |
  8.                                 BACKGROUND_INTENSITY);
  9.                 break;
  10.         case DebugLevel::TIME://时间(白色)
  11.                 SetConsoleTextAttribute(_handleOutput,
  12.                                 BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE |
  13.                                 BACKGROUND_INTENSITY);
  14.                 break;
  15.         case DebugLevel::INFO://信息(白色蓝底)
  16.                 SetConsoleTextAttribute(_handleOutput,
  17.                         FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE |
  18.                         BACKGROUND_BLUE |
  19.                         FOREGROUND_INTENSITY);
  20.                 break;
  21.         case DebugLevel::NOTICE://提示(绿色)
  22.                 SetConsoleTextAttribute(_handleOutput,
  23.                         FOREGROUND_GREEN |
  24.                         BACKGROUND_GREEN |
  25.                         FOREGROUND_INTENSITY);
  26.                 break;
  27.         case DebugLevel::WARN://警告(黄色)
  28.                 SetConsoleTextAttribute(_handleOutput,
  29.                         FOREGROUND_GREEN | FOREGROUND_RED |
  30.                         BACKGROUND_GREEN | BACKGROUND_RED |
  31.                         FOREGROUND_INTENSITY);
  32.                 break;
  33.         case DebugLevel::ERR://错误(红色)
  34.                 SetConsoleTextAttribute(_handleOutput,
  35.                         FOREGROUND_RED |
  36.                         BACKGROUND_RED |
  37.                         FOREGROUND_INTENSITY);
  38.                 break;
  39.         }
  40.         std::wcout << str.GetWcs();//获取字符串WCHAR数组版本
  41. }
复制代码

    其中SetConsoleTextAttribute设置了输出文本的颜色,第一个参数是前面取得的输出句柄,第二个参数是宏的值组合。FOREGROUND前缀代表前景色,BACKGROUND代表背景色。RED、GREEN、BLUE是三原色分量,INTENSITY代表颜色加强(变得更亮)。
    最后再提一句,wcout不能直接输出中文,需要提前调用一句(至于为什么我也不知道^_^):
     
  1.   locale::global((locale("")));
复制代码

        
作者:略游
日期:17-07-31
QQ:1339484752


回复

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-3-29 02:47 , Processed in 0.036487 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表