注册 登录
编程论坛 汇编论坛

现场直憋:从零开始学习 使用win32汇编写一个屏幕截图 截屏 小程序 长期更新

信箱有效 发布于 2012-10-11 00:56, 2947 次点击
发奋win32汇编也有不少天了,都是在看书,感觉还是大部分能看的明白。
可一想自己写。。。就发现完全不会咧
能看懂离自己会写这简直差了十万八千里。so 我要千里之行 始于足下,我要勇敢的迈出第一步
开始写一个屏幕截图小程序,有木有要一起写的哥哥姐姐弟弟妹妹.

这个帖子我要坚持写下去 ,不再开新贴咧。

---------------------------------------------
使用匈牙利表示法
子程序前加下划线
参数前加下划线
局部变量前加@
尽量封装成子程序
尽量少的使用全局变量
...

---------------------------------------------


[ 本帖最后由 信箱有效 于 2012-10-14 01:45 编辑 ]
30 回复
#2
小习小习2012-10-11 09:47
向上学习了
#3
zklhp2012-10-11 12:18
win32汇编写windows程序可能是开发windows程序比较麻烦的一种方法了 不过如果能写一些东西会对windows的很多原理性的东西有一定的认识

不过现在开发都讲究快 研究这个有没有意义呢 呵呵 我也不知道
#4
有容就大2012-10-11 14:04
恭喜楼主勇敢地迈出了第一步
强烈帮顶
#5
zhu2240392012-10-11 15:11
回帖无意义,都没问题分可拿 楼主小气了
#6
hu9jj2012-10-11 22:21
楼主的第一步是第几次开始迈了?
#7
信箱有效2012-10-12 00:38
首先取得当前系统的分辨率
填BITMAPINFO
屏幕DC
内存DC
截图拷贝到内存DC
这是第一步。先写成一个子程序。

#8
有容就大2012-10-12 12:33
截屏程序真心不懂 求代码 雪袭、
#9
信箱有效2012-10-12 21:35
首先将屏幕截图,然后将图继续显示在屏幕上,鼠标变色,鼠标选择区域,保存。

看书的时候感觉不难都能看懂,一到下手写了,脑子一片空白,不知道从什么地方开始。古人说的好哇 看千遍不如写一遍。

复习一下相关知识
程序代码:
位图                存放在内存中 马上就可以使用的位图  颜色深度跟当前设备对应

设备无关位图DIB     色彩表和位图数据合在一起

位图文件BMP文件     以BMP为扩展名保存在磁盘上,包括一个bitmap文件头和DIB数据 ,
                    bitmap文件头,可验证BMP文件的有效性
使用BMP文件方式:
一 打开bmp文件 读入DIB部分的数据,然后用函数将DIB数据转换成位图数据。
二 在资源文件中定义位图资源,在程序中装入使用。

获取hDC:

当绘图对象是窗口时
WM_PAINT中BeginPaint后返回得到hDC,对应为无效区域,仅在WM_PAINT消息中有效
invoke    GetDC,    hWnd
对应为整个窗口客户区,也是需要在一条消息中使用,然后必须ReleaseDC

当绘图对象是设备时

invoke CreateDC,lpszDriver,lpszDevice,lpszOutput,lpInitData  
lpszDriver为设备名。
invoke CreateCompatibleDC,hDC
创建一个兼容DC,显示表面仅存在于内存中
不使用时都要DeleteDC

#10
信箱有效2012-10-13 00:22
结构之困惑:

看书的时候,bmp的几个结构还算搞的明白,但是越来越糊涂了 2种结构 又出来个BITMAPINFO结构

现在要发奋把这个bmp结构搞清楚


typedef struct tagBITMAPFILEHEADER {
  WORD    bfType;
  DWORD   bfSize;
  WORD    bfReserved1;
  WORD    bfReserved2;
  DWORD   bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;

首先是位图文件头BITMAPFILEHEADER。


typedef struct tagBITMAPINFOHEADER{
  DWORD  biSize;
  LONG   biWidth;
  LONG   biHeight;
  WORD   biPlanes;
  WORD   biBitCount;
  DWORD  biCompression;
  DWORD  biSizeImage;
  LONG   biXPelsPerMeter;
  LONG   biYPelsPerMeter;
  DWORD  biClrUsed;
  DWORD  biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
然后是位图信息头BITMAPINFOHEADER结构。





typedef struct tagRGBQUAD {
  BYTE    rgbBlue;
  BYTE    rgbGreen;
  BYTE    rgbRed;
  BYTE    rgbReserved;

} RGBQUAD;
再然后是色彩表RGBQUAD结构。



最后就是位图的像素数据了。



=====================================================================

BITMAPINFO结构
typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;
它是将位图信息头和色彩表合在一起的一个结构。



这样一个完整的bmp文件就是这样构成:
BITMAPFILEHEADER
BITMAPINFO
位图像素数据

原来以为多复杂。。。实际就是这样简单。


----------------------------------------------------------
----------------------------------------------------------
另外还有一种OS/2兼容的bmp格式,它使用了BITMAPCOREINFO结构。
bmp构成为:
BITMAPFILEHEADER
BITMAPCOREINFO
位图像素数据
其中BITMAPCOREINFO结构为:
typedef struct _BITMAPCOREINFO {
  BITMAPCOREHEADER  bmciHeader;
  RGBTRIPLE         bmciColors[1];
} BITMAPCOREINFO, *PBITMAPCOREINFO;
这种格式一般用的不多,不过要操作一个已有的BMP文件时,最好判断一下是哪种。
#11
信箱有效2012-10-13 12:16
相关函数(随时补充):

int SetDIBitsToDevice(
  HDC hdc,                 // handle to DC
  int XDest,               // x-coord of destination upper-left corner
  int YDest,               // y-coord of destination upper-left corner
  DWORD dwWidth,           // source rectangle width
  DWORD dwHeight,          // source rectangle height
  int XSrc,                // x-coord of source lower-left corner
  int YSrc,                // y-coord of source lower-left corner
  UINT uStartScan,         // first scan line in array
  UINT cScanLines,         // number of scan lines
  CONST VOID *lpvBits,     // array of DIB bits
  CONST BITMAPINFO *lpbmi, // bitmap information
  UINT fuColorUse          // RGB or palette indexes
);


函数功能:该函数使用DIB位图和颜色数据对与目标设备环境相关的设备上的指定矩形中的像素进行设置。
lpvBits:指向存储DIB颜色数据的字节类型数组的指针。
lpbmi:指向BITMAPINFO结构的指针,该结构包含有关DIB的信息。
fuColorUse:DIB_PAL_COLORS表示颜色表由16位的索引值数组组成,利用这些值可对当前
                          选中的逻辑调色板进行索引。   
            DIB_RGB_COLORS表示颜色表包含原义的RGB值。

HBITMAP CreateDIBSection(
  HDC hdc,                 // handle to DC
  CONST BITMAPINFO *pbmi,  // bitmap data
  UINT iUsage,             // data type indicator
  VOID **ppvBits,          // bit values
  HANDLE hSection,         // handle to file mapping object
  DWORD dwOffset           // offset to bitmap bit values
);

函数功能:该函数创建应用程序可以直接写入的、与设备无关的位图(DIB)。该函数提供一个指针,该指针指向位图位数据值的地方。可以给文件映射对象提供句柄,函数使用文件映射对象来创建位图,或者让系统为位图分配内存。

hdc:设备环境句柄。如果iUsage的值是DIB_PAL_COLORS,那么函数使用该设备环境的逻辑调色板对与设备无关位图的颜色进行初始化。
pbmi:指向BITMAPINFO结构的指针,该结构指定了与设备无关位图的各种属性,其中包括位图的维数和颜色。
iUsage:指定由pbmi参数指定的BITMAPINFO结构中的成员bmiColors数组包含的数据类型(要么是逻辑调色板索引值,要么是原文的RGB值)。
ppvBits:指向一个变量的指针,该变量接收一个指向DIB位数据值的指针。
hSection:文件映射对象的句柄。函数将使用该对象来创建DIB(与设备无关位图)。该参数可以是NULL。

#12
TonyDeng2012-10-13 12:36
BMP本身都有很多种不同的格式编码,何况还有很多不是BMP的图像格式,你这样逐个弄,弄得完吗?
#13
newdos2012-10-13 12:42
读你千遍也不厌倦。。。。。呵呵,恭喜楼主的第一步。
GetDesktopWindow也可以获得桌面句柄。
单色BMP, 256色BMP, 真彩色的BMP,行程压缩的bmp,要分清BMP中的各种格式,够你喝一壶了。

[ 本帖最后由 newdos 于 2012-10-13 12:43 编辑 ]
#14
信箱有效2012-10-13 13:50
以下是引用TonyDeng在2012-10-13 12:36:22的发言:

BMP本身都有很多种不同的格式编码,何况还有很多不是BMP的图像格式,你这样逐个弄,弄得完吗?
bmp是windows直接支持的标准图片格式,很多情况下首选也是唯一的选择就是用bmp,理解文件结构,能根据需要自己构造一个bmp,这个应该是基本要求。
写屏幕截图,最重要的就是生成BMP。
#15
TonyDeng2012-10-13 13:53
嘿嘿
#16
有容就大2012-10-13 14:05
来 网 吧 帮 楼 主 顶 贴
#17
madfrogme2012-10-13 14:07
回复 16楼 有容就大
现在是不是网吧生意越来越不好了吧
#18
有容就大2012-10-13 14:10
以下是引用madfrogme在2012-10-13 14:07:56的发言:

现在是不是网吧生意越来越不好了吧
NO 星期六 N多小学生初中生来排队。。。
而且要求双座连 三座连 ,,,
#19
madfrogme2012-10-13 14:15
回复 18楼 有容就大
人家好不容易星期天上个网,你还要过去和人家抢位置
#20
有容就大2012-10-13 14:27
回复 19楼 madfrogme
虽然是小学生 。。。但是人多势众。
#21
信箱有效2012-10-14 12:09
;因为是一点点的慢慢写,所以全局变量和局部变量没办法刚开始就都定义好,只能用
;的时候再定义,这个是获取屏幕上显示的内容子程序。

_GetDisPlayBmp proc uses ebx esi edi
    LOCAL @bmi:BITMAPINFO
    LOCAL @hDc
    LOCAL @MemDc
    invoke      RtlZeroMemory,addr @bmi,sizeof @bmi   
    mov         ebx,sizeof BITMAPINFO
    mov         @bmi.bmiHeader.biSize,ebx
    invoke      GetSystemMetrics,SM_CXSCREEN
    mov         @bmi.bmiHeader.biWidth,eax
    invoke      GetSystemMetrics,SM_CYSCREEN
    mov         @bmi.bmiHeader.biHeight,eax
    mov         @bmi.bmiHeader.biPlanes,1
    mov         @bmi.bmiHeader.biBitCount,24
以上是定义一个bitmapinfo结构,初始化其中的bitmapinfoheader结构的几个重要字段

    invoke      GetDC,NULL
    mov         @hDc,eax
    invoke      CreateCompatibleDC,@hDc
    mov         @MemDc,eax
获取屏幕DC,然后在内存中创建一个对应该设备环境的兼容DC名字为@MemDc
#22
信箱有效2012-10-14 13:08
invoke     CreateDIBSection,@MemDc,addr @bmi,DIB_RGB_COLORS,addr @bmpData,NULL,0
   
mov        hBmp,eax
再定义一个@bmpData,MSDN上说:[out] Pointer to a variable that receives a pointer to the location of the DIB bit values.
createdibsection执行后,该变量里是个指针 指向DIB数据。

再定义个全局变量hBmp,它是一个位图句柄,指向刚刚由CreateDIBSection创建的与设备无关位图的句柄。而@bmpData则指向其中的位数据。


    invoke     SelectObject,@MemDc,hBmp
    invoke     BitBlt,@MemDc,   0,   0,   @bmi.bmiHeader.biWidth, @bmi.bmiHeader.               biHeight,@hDc,   0,   0,   SRCCOPY

    invoke     ReleaseDC,NULL,   @hDc
    invoke     DeleteDC,@MemDc  
    xor        eax,eax
               ret
_GetDisPlayBmp endp
CreateDIBSection创建的虽然是DIB块,但是是可以直接被操作的,选入@MemDc,将屏幕内容拷贝进去。  这个子程序最后的结果就是获得了一个和屏幕内容一样的位图句柄hBmp。

#23
有容就大2012-10-14 14:43
信箱哥 你被位图Dog了。
#24
有容就大2012-10-14 19:58
是哦 这个应该给个颜色啊 怎么忘了 呵呵。。。
#25
zklhp2012-10-14 20:06
来学习了 搬砖真辛苦啊 没心情看了 纯支持了
#26
水哥2012-10-19 20:09
copy DC
#27
信箱有效2012-10-20 02:38
以下是引用水哥在2012-10-19 20:09:22的发言:

copy DC
大家都知道是copy DC。
#28
Alar302012-10-20 20:54
现场版的啊
不错不错。。
#29
信箱有效2012-10-21 23:24
本来还在想着怎么才能存成BMP文件呢。。。
MSDN真是个好东西,居然有C源码例子,学习一下,改成汇编。
程序代码:
int CaptureAnImage(HWND hWnd)
{
    HDC hdcScreen;
    HDC hdcWindow;
    HDC hdcMemDC = NULL;
    HBITMAP hbmScreen = NULL;
    BITMAP bmpScreen;

    // Retrieve the handle to a display device context for the client
    // area of the window.
    hdcScreen = GetDC(NULL);
    hdcWindow = GetDC(hWnd);

    // Create a compatible DC which is used in a BitBlt from the window DC
    hdcMemDC = CreateCompatibleDC(hdcWindow);

    if(!hdcMemDC)
    {
        MessageBox(hWnd, L"CreateCompatibleDC has failed",L"Failed", MB_OK);
        goto done;
    }

    // Get the client area for size calculation
    RECT rcClient;
    GetClientRect(hWnd, &rcClient);

    //This is the best stretch mode
    SetStretchBltMode(hdcWindow,HALFTONE);

    //The source DC is the entire screen and the destination DC is the current window (HWND)
    if(!StretchBlt(hdcWindow,
               0,0,
               rcClient.right, rcClient.bottom,
               hdcScreen,
               0,0,
               GetSystemMetrics (SM_CXSCREEN),
               GetSystemMetrics (SM_CYSCREEN),
               SRCCOPY))
    {
        MessageBox(hWnd, L"StretchBlt has failed",L"Failed", MB_OK);
        goto done;
    }
   
    // Create a compatible bitmap from the Window DC
    hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
   
    if(!hbmScreen)
    {
        MessageBox(hWnd, L"CreateCompatibleBitmap Failed",L"Failed", MB_OK);
        goto done;
    }

    // Select the compatible bitmap into the compatible memory DC.
    SelectObject(hdcMemDC,hbmScreen);
   
    // Bit block transfer into our compatible memory DC.
    if(!BitBlt(hdcMemDC,
               0,0,
               rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
               hdcWindow,
               0,0,
               SRCCOPY))
    {
        MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
        goto done;
    }

    // Get the BITMAP from the HBITMAP
    GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
   
    BITMAPFILEHEADER   bmfHeader;   
    BITMAPINFOHEADER   bi;
   
    bi.biSize = sizeof(BITMAPINFOHEADER);   
    bi.biWidth = bmpScreen.bmWidth;   
    bi.biHeight = bmpScreen.bmHeight;
    bi.biPlanes = 1;   
    bi.biBitCount = 32;   
    bi.biCompression = BI_RGB;   
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;   
    bi.biYPelsPerMeter = 0;   
    bi.biClrUsed = 0;   
    bi.biClrImportant = 0;

    DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

    // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
    // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
    // have greater overhead than HeapAlloc.
    HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
    char *lpbitmap = (char *)GlobalLock(hDIB);   

    // Gets the "bits" from the bitmap and copies them into a buffer
    // which is pointed to by lpbitmap.
    GetDIBits(hdcWindow, hbmScreen, 0,
        (UINT)bmpScreen.bmHeight,
        lpbitmap,
        (BITMAPINFO *)&bi, DIB_RGB_COLORS);

    // A file is created, this is where we will save the screen capture.
    HANDLE hFile = CreateFile(L"captureqwsx.bmp",
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);  
   
    // Add the size of the headers to the size of the bitmap to get the total file size
    DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    //Offset to where the actual bitmap bits start.
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
   
    //Size of the file
    bmfHeader.bfSize = dwSizeofDIB;
   
    //bfType must always be BM for Bitmaps
    bmfHeader.bfType = 0x4D42; //BM  

    DWORD dwBytesWritten = 0;
    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
   
    //Unlock and Free the DIB from the heap
    GlobalUnlock(hDIB);   
    GlobalFree(hDIB);

    //Close the handle for the file that was created
    CloseHandle(hFile);
      
    //Clean up
done:
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(NULL,hdcScreen);
    ReleaseDC(hWnd,hdcWindow);

    return 0;
}


#30
无敌小默然2012-11-07 10:18
你喜欢。
#31
蜀山野鬼2012-11-15 00:46
围观
1