现在的位置: 首页 > 综合 > 正文

window2000 DDK mirror驱动实现截屏Demo的简单研究

2012年12月05日 ⁄ 综合 ⁄ 共 4283字 ⁄ 字号 评论关闭

原文地址:http://blog.163.com/cgq_i/blog/static/728779232009530112128471/

1、window DDK mirror的安装简单步骤:

下载ddk安装包路径请参考我之前的一篇文章。下载安装window 2000 DDK包后,便可以开始编译mirror的demo程序。安装的时候记得选上sample,这样才会有src的源码。

window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客

安装ddk驱动之后,会安装到以下路径:C:\Program Files\NTDDK,在C:\Program Files\NTDDK\src\video\displays\mirror\dll目录下编译mirror.dll,在C:\Program Files\NTDDK\src\video\miniport\mirror目录下编译mirror.sys,编译时记得是用NTDDK自带的build命令(通过开始-》程序菜单来打开)。编译完这两个玩意之后,参考C:\Program Files\NTDDK\src\video\displays\mirror\app\readme.txt的内容来拷贝它们。ok,编译结束。然后通过手动安装的方式来安装这个驱动(通过控制面板,选择编译好的mirror.dll/mirror.sys)。非window
2000 DDK的编译安装步骤可能有所不同。

  安装好xp的ddk之后,在D:\WINDDK00\src\video\displays目录下有个目录mirror,将其copy到E:\mirror\。打开ddk编译环境的命令行,切换到该目录后执行nmake对mini、disp、app三个目录下的代码进行编译,最后将ddmlapp.exe、mirror.dll、mirror.inf、mirror.reg、mirror.sys等文件copy到E:\mirror\bin目录下。

    需要注意的是驱动的安装不能通过双击inf文件来安装,得在控制面板中运行“添加硬件”来安装。扫描硬件后未发现新硬件,选择已经链接此硬件:

 

    选择“添加新的硬件设备”:
window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客
    选择手动从列表中选择:
window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客
    选择“显示卡”:
window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客
    选择从“磁盘安装”指定路径:
window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客
    安装过程中显示器会闪动,或是关闭又开启,均属正常。最终看到显示器设备中多了mirror设备:
window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客
    最终通过cmd命令行终端进入E:\mirror\bin目录执行ddmlapp.exe,输出mirror驱动相关信息:
window2000 DDK mirror驱动实现截屏Demo的简单研究 - cgq_i - cgq_i的博客

    演示效果看到了,但是这些仅仅是得到了设备信息,并没有任何实质上的效果演示。

以上搞定了mirror驱动的编译和安装,成功安装之后,会在系统硬件设备管理的显示卡处看到多了一个Mirror Driver之类的设备,这就说明安装成功了。

2、mirror的Demo:
成功安装mirror之后,在这个目录下是可以编译一个demo程序的:C:\Program Files\NTDDK\src\video\displays\mirror\app,编译后的程序是C:\Program Files\NTDDK\src\video\displays\mirror\app\objchk\i386\ddmlapp.exe,但是根本没有起到demo的作用,运行之后只显示加载mirror驱动和注册表相关信息,根本没有意义。

所以,来看源代码吧。仔细分析了一下源代码(main.cxx),它的主要流程是:从系统中枚举获取mirror设备,然后修改注册表,把这个值Attach.ToDesktop设成1,即可与系统的屏幕绑定。接下来就是普通的GDI函数调用,通过位图来截取屏幕,因此需要对GDI函数有所了解才行。有所区别的地方是这里是用了mirror的设备,因此可以获取良好的性能(速度快,不会闪屏等):
HDC hdc = CreateDC("DISPLAY", deviceName, NULL, NULL);

这个main.cxx代码中注释了CreateMyWindow("Mirror Sample");这个内容,其实打开注释也没有效果。所以我认为这个sample如果不修改,是根本不可能看到截屏的效果。

3、为了实现mirror这个效果,我对源代码进行了部分修改,并且移到VC6++里面去了,只需要移main.cxx这个文件。我创建了一个Dialog的程序,把main.cxx和新增的main.h加到这个项目中,需要注意要加载include的路径:C:\Program Files\NTDDK\inc,以及动态库的路径:C:\Program Files\NTDDK\libchk\i386\,同时对main.cxx进行了修改,源代码附在后面。在Dialog上加一个button,去调用MirrorApp(0, NULL)就可以看到效果了。需要特别说明的是,这个仅仅是测试mirror的效果,未对程序进行任何合理性的优化,因此如果要用于项目上,需要自行优化。

4、我之前的文章还提到dfmirage这个驱动,其实它就是实现了一个类似mirror的驱动,我在下载安装dfmirage这个驱动之后,把main.cxx代码中与mirror有关的内容修改成dfmirage,效果是一样的。当然它可能做了一些优化处理,我没再仔细研究下去。

5、修改之后的main.cxx代码:
1)main.h
#ifndef _MIRROR_APP_H_
#define _MIRROR_APP_H_
void MirrorApp(int argc, char *agrv[]);
#endif //_MIRROR_APP_H_

2)main.cxx
//
// Generic Windows program template
//

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "C:\\Program Files\\NTDDK\inc\\windows.h"

#define MM_MAX_NUMAXES 

     16
typedef struct tagDESIGNVECTOR
{
    DWORD  dvReserved;
    DWORD  dvNumAxes;
    LONG   dvValues[MM_MAX_NUMAXES];
} DESIGNVECTOR;

#include <winddi.h>

#include <tchar.h>
#include <winbase.h>
#include <winreg.h>

CHAR* programName;      // program name
HINSTANCE appInstance;  // handle to the application instance

HBITMAP hbm;

LPSTR driverName = "Microsoft Mirror Driver";

LPSTR dispCode[7] = {
   "Change Successful",
   "Must Restart",
   "Bad Flags",
   "Bad Parameters",
   "Failed",
   "Bad Mode",
   "Not Updated"};

int   giIndex = 0;

LPSTR GetDispCode(INT code)
{
   switch (code) {
   
   case DISP_CHANGE_SUCCESSFUL: return dispCode[0];
  
   case DISP_CHANGE_RESTART: return dispCode[1];
  
   case DISP_CHANGE_BADFLAGS: return dispCode[2];
  
   case DISP_CHANGE_BADPARAM: return dispCode[3];
  
   case DISP_CHANGE_FAILED: return dispCode[4];
  
   case DISP_CHANGE_BADMODE: return dispCode[5];
  
   case DISP_CHANGE_NOTUPDATED: return dispCode[6];
  
   default:
      static char tmp[MAX_PATH];
      sprintf(&tmp[0],"Unknown code: %08x\n", code);
      return (LPTSTR)&tmp[0];
  
   }
  
   return NULL;   // can't happen
}

//
// Handle window repaint event
//

VOID
DoPaint(
    HWND hwnd
    )

{
    HDC hdc;
    PAINTSTRUCT ps;
   
    hdc = BeginPaint(hwnd, &ps);

    COLORREF red = 0x00FF0000;

    HBRUSH hbr = CreateSolidBrush(red);

    RECT r;
    r.left = ps.rcPaint.left;
    r.top = ps.rcPaint.top;
    r.right = ps.rcPaint.right;
    r.bottom = ps.rcPaint.bottom;

    //FillRect(hdc, &r, hbr);

    HBRUSH dbrush;
    dbrush = CreatePatternBrush(hbm);
    FillRect(hdc, &r, dbrush);

    EndPaint(hwnd, &ps);
}

//
// Window callback procedure
//

LRESULT CALLBACK
MyWindowProc(
    HWND    hwnd,
    UINT    uMsg,
    WPARAM  wParam,
    LPARAM  lParam
    )

{
    switch (uMsg)
    {
    case WM_PAINT:
        //MessageBox(NULL, "Repaint !!", "OK", MB_OK);
        printf("get WM_PAINT msg...\n");
        DoPaint(hwnd);
        break;

    case WM_DISPLAYCHANGE:
       {
        WORD cxScreen = LOWORD(lParam);
        WORD cyScreen = HIWORD(lParam);
        WPARAM format = wParam;
       

抱歉!评论已关闭.