| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2932 人关注过本帖, 2 人收藏
标题:在VC中直接写屏的方法
取消只看楼主 加入收藏
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
结帖率:100%
收藏(2)
已结贴  问题点数:100 回复次数:14 
在VC中直接写屏的方法
为兼容vc6和C,以下代码用纯C旧语法:

程序代码:
#include <Windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <conio.h>

int main(void)
{
    HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
    const char* str = "Hello, 欢迎你进入编程论坛!";
    int length = strlen(str);
    CHAR_INFO* text = NULL;
    SMALL_RECT region;
    COORD bufferSize;
    COORD bufferCoord;
    int index;

    region.Top = 5;
    region.Left = 5;
    region.Bottom = region.Top + 4;
    region.Right = region.Left + 20;

    bufferSize.X = region.Right - region.Left + 1;
    bufferSize.Y = region.Bottom - region.Top + 1;

    bufferCoord.X = 0;
    bufferCoord.Y = 0;

    text = (CHAR_INFO*)calloc(bufferSize.X * bufferSize.Y, sizeof(CHAR_INFO));
    for (index = 0; index < bufferSize.X * bufferSize.Y; ++index)
    {
        if (index < length)
        {
            text[index].Char.AsciiChar = str[index];
            text[index].Attributes = (8 + (index + 1) % 6) + (4 << 4);
        }
        else
        {
            text[index].Char.AsciiChar = ' ';
            text[index].Attributes = 4 << 4;
        }
    }
    WriteConsoleOutputA(output, text, bufferSize, bufferCoord, &region);
    delete[] text;
    
    _getch();
    return EXIT_SUCCESS;
}


运行效果:
图片附件: 游客没有浏览图片的权限,请 登录注册

请留意:
1.画面中光标是没动的
2.文本有折行
3.中文可以半个字符变色

[ 本帖最后由 TonyDeng 于 2015-7-9 09:38 编辑 ]
2015-07-09 09:28
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
以下是引用边小白在2015-7-9 09:44:54的发言:


直接写屏是不是等于直接操作显存?这样就太强大了。

相当于DOS下直接操作显存。Windows与DOS不同,通常的程序是不允许直接操作硬件的(除非是写硬件驱动程序),这是调用Win32 API的方法,其实与DOS时代的调用中断差不多,不是直接写显存(Windows下不同显卡和显示模式下设备的显示内存入口不一定相同,是无法找到通用的显卡入口的),但却是在Windows下写控制台输出最快的方法。

授人以渔,不授人以鱼。
2015-07-09 09:50
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
下面是封装为函数的代码:

程序代码:
    // 功能:在指定矩形框中用默認屬性輸出ansi編碼文本(可折行)
    // 參數:text   - 輸出的文本字符串
    //       region - 輸出的矩形框
    // 返回:操作成功返回真否則為假
    bool MyConsole::OutputText(const std::string text, SMALL_RECT region)
    {
        WORD attr = GetTextAttribute();     // 獲取當前文本屬性

        // 屏幕塊的範圍
        COORD bufferSize;
        bufferSize.X = region.Right - region.Left + 1;
        bufferSize.Y = region.Bottom - region.Top + 1;

        // 輸出起始位置,為相對於bufferSize的左上角偏移量
        COORD bufferCoord;
        bufferCoord.X = 0;
        bufferCoord.Y = 0;

        BOOL success = FALSE;
        size_t length = bufferSize.X * bufferSize.Y;
        CHAR_INFO* const textBuffer = new CHAR_INFO[length];
        if (textBuffer)
        {
            for (size_t index = 0; index < length; ++index)
            {
                textBuffer[index].Char.AsciiChar = (index < text.size()) ? text[index] : ' ';
                textBuffer[index].Attributes = attr;
            }
            success = WriteConsoleOutputA(_output, textBuffer, bufferSize, bufferCoord, &region);
            delete[] textBuffer;
        }

        return (success == TRUE);
    }


这个抛去了字符自由变色的便利,只能用同一种属性。也可以用另一种封装方法,即在外面填写好textBuffer,再传参给函数。无论如何,都是以1楼的测试代码为基础的,搞明白了1楼的原理,想怎么做都可以。

授人以渔,不授人以鱼。
2015-07-09 10:01
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
以下是引用边小白在2015-7-9 10:06:07的发言:

学习了!
想当年为糊口,帮人管理网吧,师傅反复叮咛我要为打游戏的升级directx,我问为什么,师傅说win不能直接操作显存,装direct可访问,提高游戏速度。后来拆装机多了,知道显存就是显卡上的一块块长方块,我还专门砸开看,什么都没发现。

现在DirectX升级到12版了,只能在Win10下运行。

授人以渔,不授人以鱼。
2015-07-09 10:14
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
控制台下的颜色值:
程序代码:
            static enum TextColor
            {
                Black = 0,              // 黑色
                Blue = 1,               // 藍色
                Green = 2,              // 綠色
                Cyan = 3,               // 青色
                Red = 4,                // 紅色
                Megenta = 5,            // 洋紅色
                Yellow = 6,             // 黃色
                White = 7,              // 白色
                Gray = 8,               // 灰色
                LightBlue = 9,          // 亮藍色
                LightGreen = 10,        // 亮綠色
                LightCyan = 11,         // 亮青色
                LightRed = 12,          // 亮紅色
                LightMegenta = 13,      // 亮洋紅色
                LightYellow = 14,       // 亮黃色
                LightWhite = 15         // 亮白色
            };


在控制台下,文本仅有16色(这是文本模式的规定,不同于图形态有256色以上直至真彩色,是文本模式与图形模式的本质区别,所谓文本程序,是指基于这种输出特点而言)。其用法是:属性(attribute)是8位整数,高4位为背景,低4位为前景,分别是上列的16色组合(2的4次方是16)。

授人以渔,不授人以鱼。
2015-07-09 10:29
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
以下是引用TAAAAB在2015-7-9 11:21:51的发言:

收藏中,总有一天会看明白的

这些代码,在语法上并不难,也没什么高深的技术,无非是相关的系统知识,也就是我一向说的“专业”。调用Win32 API不属于C/C++语言的范畴,同样调用标准库也不是(其实标准库和Win32 API对于C/C++语言的作用是一样,都是外部写好的工具库)。之前有人感叹,说出来后,总是学各种各样的API,没有意思、没有激情,那是错误理解语言了。语言本身很简单,学它用不了多少时间,终身要学的,正是专业。举个例子,比如在这里,若不知道文本模式的颜色是怎么构造的,则无论你把C/C++语言学得多精深,都是不会,因为是不知道相关的专业知识,而不是不懂语言和编程。

还有人说,C只能在黑乎乎的控制台窗口中写程序,殊不知控制台下的文本程序也可以是多姿多彩的,凡是从DOS时代过来的人都知道那时候的程序,比如Turbo C的IDE,就是纯粹的文本模式界面,当时的程序员写程序,很多是按照那样的效果做的,有下拉菜单、响应热键、弹出式窗口、窗口也有阴影等等,都是以这里的写屏手段为基础。说C写不了好用的程序,是假的,自己有没有用心去做而已,也不一定非要用图形态的MFC编程才是(其实C++和面向对象编程,也是在DOS时代就兴起的,那个时候哪有什么Windows窗口,在DOS下也要面向对象)。不了解这些历史,很多荒唐的说法,是驳不胜驳,在这里只是顺便吐一下罢了,再遇到,我也不会说。

[ 本帖最后由 TonyDeng 于 2015-7-9 11:55 编辑 ]

授人以渔,不授人以鱼。
2015-07-09 11:39
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
回复 13楼 wfoo
写驱动程序有特殊的授权,可以访问和控制硬件。我说的普通的程序不能那样做,保护模式的操作系统必须禁止这种动作,放滥了就是DOS那样的结果,各种死机。其实Linux那样的,只是假定程序员有自觉性,他们考虑系统内同时运行的各种程序有无冲突,与C的设计理念一致,即责任由程序员自己承担,而不是由系统主动保护。这样的理念,写程序当然好写,有最大的自由度,可是也同样有最大的风险。所谓Unix/Linux安全,其实是寄托在没多少人使用和懂这种系统上,像Windows那样普及,被研究的透,集中攻击的自然也多,苹果的iOS在其手机泛滥之后,也暴露出大量的漏洞和遭受破解,道理是一样的。至于开源,也是理想主义,源代码公开了,还有不清楚工作原理遭攻击的?无非是你的源代码太庞大和复杂,普通人和一般有心者不愿去看和研究全部源代码而已(Linux的维护,多年来就那么一两个人在承包,那个心脏漏洞,大家都拥有源代码,却是谁都没看出来,结果透露是只有一个人在维护的)。拿开源的代码做实际工作,你不加上开源之外的私货,敢出来用?开源迷信,也是早破早好,开源社区拥有最多目空一切的自大狂,也是事实,制造神话营造宗教氛围而已。

[ 本帖最后由 TonyDeng 于 2015-7-9 11:59 编辑 ]

授人以渔,不授人以鱼。
2015-07-09 11:54
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
返回正题。在Windows控制台下,最好只处理ansi编码的中文,即GBK的,用其他的会遇到较多的麻烦,尤其是在按键的控制上(写文字编辑功能用)。所以,1楼的代码,用的是CHAR_INFO结构中的AsciiChar段,而不是UnicodeChar段,輸出的API也是用A版本。

授人以渔,不授人以鱼。
2015-07-09 12:52
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
回复 18楼 wfoo
那种是系统允许的,实际上通过系统调用(Windows是主动式系统),它放了一些权限出来,比如实际上可以在程序中绕过UAC提高权限而不用用户干预之类。看看在Windows编程中写串口通讯就知道了,以前在DOS,只要直接对串行端口in、out即可读写,但在Windows下要用Winsock协议才行,这虽然也算得上是操控硬件,但不是以前那种直接操控。我这里调用API输出,跟这个道理是一样的。操作系统给程序什么权,是既定的,无非是我们知道多少,却不可能超越限制,像以前那样直接读写磁盘扇区的,现在根本不可能。CIH病毒可以破坏硬件,就是因为Windows95/98/Me的内核是DOS或与DOS兼容,到了NT内核,这种病毒就无效了。

授人以渔,不授人以鱼。
2015-07-09 17:25
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
Windows的System用户不可以直接操纵硬件,驱动程序可以。我们对虚拟设备操作,模拟操纵硬件,但是要被Windows接管的。事实上在Windows NT内核下,由于是主动式的系统,程序的所有机器码都是由操作系统在适当时候主动调用的,链接出的可执行文件与DOS下的完全不同(所以我一向说现在研究DOS下汇编和旧PE机制的是浪费时间精力),这里是片段式的,系统剪取一段执行,程序的执行时机不由自己控制。主动抢截式的系统机制,完全把握了用户程序的一切动作,对系统定义为危险的行为,不会给你执行的机会。Linux下的,我也不清楚,但它是分时系统,也应该是保护模式,原理上不会直接操纵硬件,也是对虚拟设备和虚拟地址操作,可能它的保护套超薄。

直接操纵硬件在多用户多任务环境中的危害,是访问冲突,硬件的响应总是单一的,不能同时响应,这一点就决定了用户独立操控硬件是不可行的。DOS是单用户实时系统,它可以,哪怕是多任务,也是单用户,勉强可以。

授人以渔,不授人以鱼。
2015-07-09 21:03
快速回复:在VC中直接写屏的方法
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.022468 second(s), 11 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved