【文章标题】: 在程序中设置[硬件加速 级别]
【文章作者】: FishSeeWater
【操作平台】: Windows
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
      最近由于项目的需求,需要在项目中禁用显卡的硬件加速,在网上一遍Google后,全是提问的,没有答案(关键字不对?:))。只能自己动手来丰衣足食了。
  
  先用注册表监视工具查看 开启与关闭硬件加速后注册表的变化:
    开启:
      HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Video\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000\Acceleration.Level
      键值: DWORD: 5 (0x0)
      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000\Acceleration.Level
      键值: DWORD: 5 (0x0)
    关闭:
      HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Video\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000\Acceleration.Level
      键值: DWORD: 5 (0x5)
      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000\Acceleration.Level
      键值: DWORD: 5 (0x5)
  呵呵,原来如此简单。慢着,换台电脑看看是不是也是这样呢?试验结果会大失所望的({E110E3C0-EA6F-4F1F-8043-A3A28571575D}这个值不一样)。
  这就意味着不同的电脑保存硬件加速信息的位置是不同的。
  那我们怎样得到 信息的保存位置呢?本着从windows里来回到windows 中去的精神,将控制面板程序中的"desk.cpl(显示)"跟踪了一遍。
  
  跟踪过程:
    下断点: 移动滑竿时,界面上会根据不同的加速等级做出提示,我们就下SetWindowsTextW吧。
    成功将程序断下,不断ret返回到我们需要的领空“deskperf”。
      这时我们可以大约看到这里应该程序的主要处理流程。经过多跟踪发现,
      “疑难解答”这个选项卡显示 后 程序内在中 “{E110E3C0-EA6F-4F1F-8043-A3A28571575D}”
      这个串就已经有了,我们需要在显示时来找到其处理方法。
  
  6D781698   |.  3B0D >cmp     ecx, dword ptr ds:[6D783800]
  6D78169E   |.  0F84 >je      deskperf.6D781C95
  6D7816A4   |.  51    push    ecx
  6D7816A5   |.  FF75 >push    [arg.1]
  6D7816A8   |.  890D >mov     dword ptr ds:[6D783800], ecx
  6D7816AE   |.  E8 D1>call    deskperf.6D781484                 ;  设置窗口上的信息提示。//当拖动滑竿时,会不断调用这里来设置界面提示。
  6D7816B3   |.  56    push    esi
  6D7816B4   |.  FF75 >push    [arg.1]
  6D7816B7   |.  68 68>push    468
  6D7816BC   |.  FF75 >push    [arg.1]                           ; /hWnd
  6D7816BF   |.  FF15 >call    dword ptr ds:[<&USER32.GetParent>>; \GetParent
  6D7816C5   |.  50    push    eax
  6D7816C6   |.  FFD7  call    edi
  6D7816C8   |.  E9 C8>jmp     deskperf.6D781C95
  6D7816CD   |>  BB CD>mov     ebx, 0CD                          ;  Case 111 (WM_COMMAND) of switch 6D781631
  6D7816D2   |.  66:39>cmp     word ptr ss:[ebp+10], bx
  6D7816D6   |.  0F85 >jnz     deskperf.6D781C95
  6D7816DC   |.  53    push    ebx                               ; /ButtonID => CD (205.)
  6D7816DD   |.  FF75 >push    [arg.1]                           ; |hWnd
  6D7816E0   |.  FF15 >call    dword ptr ds:[<&USER32.IsDlgButto>; \IsDlgButtonChecked
  6D7816E6   |.  F7D8  neg     eax                               ;  点击应用按键  // 当设置完成后,点右下角的“应用按扭”,会在这里开始处理。
  6D7816E8   |.  1BC0  sbb     eax, eax
  .........
  .........
  .........
  ////  以下 “疑难解答”这个选项卡显示 时的事件
  6D781790   |.  FF15 >call    dword ptr ds:[<&KERNEL32.GlobalUn>; \GlobalUnlock
  6D781796   |.  68 04>push    104
  6D78179B   |.  8D85 >lea     eax, [local.203]
  6D7817A1   |.  50    push    eax
  6D7817A2   |.  57    push    edi
  6D7817A3   |.  8975 >mov     [arg.2], esi
  6D7817A6   |.  E8 1C>call    deskperf.6D7814C7                 ;  关键CALL ^_^
  6D7817AB       85C0  test    eax, eax
  6D7817AD       0F84 >je      deskperf.6D78188D
  6D7817B3       66:39>cmp     word ptr ss:[ebp-32C], si
  6D7817BA       8DBD >lea     edi, dword ptr ss:[ebp-32C]
  6D7817C0       74 17 je      short deskperf.6D7817D9
  6D7817C2       33C0  xor     eax, eax
  ===============下面进入 call deskperf.6d7814c7 看看 ============
  6D7814C7   /$  55    push    ebp
  6D7814C8   |.  8BEC  mov     ebp, esp
  6D7814CA   |.  81EC >sub     esp, 34C
  6D7814D0   |.  53    push    ebx
  6D7814D1   |.  56    push    esi
  6D7814D2   |.  33DB  xor     ebx, ebx
  6D7814D4   |.  57    push    edi
  6D7814D5   |.  895D >mov     [local.1], ebx
  6D7814D8   |>  33D2  xor     edx, edx
  6D7814DA   |.  3955 >cmp     [local.1], edx
  6D7814DD   |.  75 7E jnz     short deskperf.6D78155D
  6D7814DF   |.  33C0  xor     eax, eax
  6D7814E1   |.  B9 D2>mov     ecx, 0D2
  6D7814E6   |.  8DBD >lea     edi, [local.211]
  6D7814EC   |.  F3:AB rep     stos dword ptr es:[edi]
  6D7814EE   |.  52    push    edx                               ; /Flags => 0
  6D7814EF   |.  8D85 >lea     eax, [local.211]                  ; |
  6D7814F5   |.  50    push    eax                               ; |pDisplayDevice
  6D7814F6   |.  53    push    ebx                               ; |DeviceNo
  6D7814F7   |.  52    push    edx                               ; |Reserved => 0
  6D7814F8   |.  C785 >mov     [local.211], 348                  ; |
  6D781502   |.  FF15 >call    dword ptr ds:[<&USER32.EnumDispla>; \EnumDisplayDevicesW  //观察 pDisplayevice 的数据。会发现我们需要的信息。
  6D781508   |.  8BF0  mov     esi, eax
  6D78150A   |.  85F6  test    esi, esi
  6D78150C   |.  74 4F je      short deskperf.6D78155D
  6D78150E   |.  FF75 >push    [arg.1]                           ; /String2
  6D781511   |.  8D85 >lea     eax, [local.210]                  ; |
  6D781517   |.  50    push    eax                               ; |String1
  6D781518   |.  FF15 >call    dword ptr ds:[<&KERNEL32.lstrcmpW>; \lstrcmpW
  6D78151E   |.  85C0  test    eax, eax
  6D781520   |.  75 32 jnz     short deskperf.6D781554
  6D781522   |.  8D85 >lea     eax, [local.65]
  6D781528   |.  50    push    eax                               ; /String
  6D781529   |>  FF15 >call    dword ptr ds:[<&KERNEL32.lstrlenW>; \lstrlenW
  6D78152F   |.  33C9  xor     ecx, ecx
  6D781531   |.  3B45 >cmp     eax, [arg.3]
  6D781534   |.  0F9CC>setl    cl
  6D781537   |.  8BF1  mov     esi, ecx
  6D781539   |.  85F6  test    esi, esi
  6D78153B   |.  74 17 je      short deskperf.6D781554
  6D78153D   |.  8D85 >lea     eax, [local.65]
  6D781543   |.  50    push    eax                               ; /String2
  6D781544   |.  FF75 >push    [arg.2]                           ; |String1
  6D781547   |.  FF15 >call    dword ptr ds:[<&KERNEL32.lstrcpyW>; \lstrcpyW
  6D78154D   |.  C745 >mov     [local.1], 1
  6D781554   |>  43    inc     ebx
  6D781555   |.  85F6  test    esi, esi
  6D781557   |.^ 0F85 >jnz     deskperf.6D7814D8
  6D78155D   |>  8B45 >mov     eax, [local.1]
  6D781560   |.  5F    pop     edi
  6D781561   |.  5E    pop     esi
  6D781562   |.  5B    pop     ebx
  6D781563   |.  C9    leave
  6D781564   \.  C2 0C>retn    0C
  可以看的出,“疑难解答”这个选项卡显示 时就是调用系统的API EnumDisplayDevices得到设备在注册表中的键值。
  
  ==============返回===================
  6D7817C4       66:8B>mov     ax, word ptr ds:[edi]
  6D7817C7       50    push    eax
  6D7817C8       FF15 >call    dword ptr ds:[<&msvcrt.towupper>] ;  msvcrt.towupper  
  6D7817CE       66:89>mov     word ptr ds:[edi], ax
  6D7817D1   |.  47    |inc     edi
  6D7817D2   |.  47    |inc     edi
  6D7817D3   |.  66:39>|cmp     word ptr ds:[edi], si
  6D7817D6   |.  59    |pop     ecx
  6D7817D7   |.^ 75 E9 \jnz     short deskperf.6D7817C2
  6D7817D9   |>  8D85 >lea     eax, [local.203]
  6D7817DF   |.  68 F4>push    deskperf.6D7811F4                 ; /wstr2 = "\SYSTEM"
  6D7817E4   |.  50    push    eax                               ; |wstr1 = "\REGISTRY\MACHINE\SYSTEM\CURRENTCONTROLSET\CONTROL\VIDEO\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
  6D7817E5   |.  FF15 >call    dword ptr ds:[<&msvcrt.wcsstr>]   ; \wcsstr
  6D7817EB   |.  59    pop     ecx
  6D7817EC   |.  40    inc     eax
  6D7817ED   |.  59    pop     ecx
  6D7817EE   |.  40    inc     eax
  6D7817EF   |.  50    push    eax                               ; /String2
  6D7817F0   |.  BF F8>mov     edi, deskperf.6D7835F8            ; |UNICODE "SYSTEM\CURRENTCONTROLSET\CONTROL\VIDEO\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
  6D7817F5   |.  57    push    edi                               ; |String1 => deskperf.6D7835F8
  6D7817F6   |.  FF15 >call    dword ptr ds:[<&KERNEL32.lstrcpyW>; \lstrcpyW
  6D7817FC   |.  8D45 >lea     eax, [arg.4]
  6D7817FF   |.  50    push    eax                               ; /pHandle
  6D781800   |.  68 3F>push    0F003F                            ; |Access = KEY_ALL_ACCESS
  6D781805   |.  56    push    esi                               ; |Reserved
  6D781806   |.  57    push    edi                               ; |Subkey => "SYSTEM\CURRENTCONTROLSET\CONTROL\VIDEO\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
  6D781807   |.  53    push    ebx                               ; |hKey
  6D781808   |.  C745 >mov     [arg.2], 1                        ; |
  6D78180F   |.  8975 >mov     [arg.4], esi                      ; |
  6D781812   |.  FF15 >call    dword ptr ds:[<&ADVAPI32.RegOpenK>; \RegOpenKeyExW
  6D781818   |.  85C0  test    eax, eax
  6D78181A   |.  74 20 je      short deskperf.6D78183C
  6D78181C   |.  8D45 >lea     eax, [arg.4]
  6D78181F   |.  50    push    eax                               ; /pHandle
  6D781820   |.  68 19>push    20019                             ; |Access = KEY_READ
  6D781825   |.  56    push    esi                               ; |Reserved
  6D781826   |.  57    push    edi                               ; |Subkey => "SYSTEM\CURRENTCONTROLSET\CONTROL\VIDEO\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
  6D781827   |.  53    push    ebx                               ; |hKey
  6D781828   |.  FF15 >call    dword ptr ds:[<&ADVAPI32.RegOpenK>; \RegOpenKeyExW
  6D78182E   |.  85C0  test    eax, eax
  6D781830   |.  75 5B jnz     short deskperf.6D78188D
  6D781832   |.  C705 >mov     dword ptr ds:[6D783808], 1
  6D78183C   |>  3975 >cmp     [arg.4], esi
  6D78183F   |.  74 4C je      short deskperf.6D78188D
  6D781841   |.  8D45 >lea     eax, [arg.2]
  6D781844   |.  50    push    eax                               ; /pBufSize
  6D781845   |.  68 00>push    deskperf.6D783800                 ; |Buffer = deskperf.6D783800
  6D78184A   |.  56    push    esi                               ; |pValueType
  6D78184B   |.  56    push    esi                               ; |Reserved
  6D78184C   |.  68 CC>push    deskperf.6D7811CC                 ; |ValueName = "Acceleration.Level"
  6D781851   |.  FF75 >push    [arg.4]                           ; |hKey
  6D781854   |.  C745 >mov     [arg.2], 4                        ; |
  6D78185B   |.  FF15 >call    dword ptr ds:[<&ADVAPI32.RegQuery>; \RegQueryValueExW
  6D781861   |.  85C0  test    eax, eax
  6D781863   |.  75 0C jnz     short deskperf.6D781871
  ......... 
  在设置完成后,点击“应用”设置时,其过程如下:
  
  6D781A9F   |.  8D45 >lea     eax, [arg.3]
  6D781AA2   |.  50    push    eax                               ; /pHandle
  6D781AA3   |.  68 3F>push    0F003F                            ; |Access = KEY_ALL_ACCESS
  6D781AA8   |.  56    push    esi                               ; |Reserved
  6D781AA9   |.  68 F8>push    deskperf.6D7835F8                 ; |Subkey = "SYSTEM\CURRENTCONTROLSET\CONTROL\VIDEO\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
  6D781AAE   |.  53    push    ebx                               ; |hKey => HKEY_LOCAL_MACHINE
  6D781AAF   |.  8975 >mov     [arg.2], esi                      ; |
  6D781AB2   |.  FF15 >call    dword ptr ds:[<&ADVAPI32.RegOpenK>; \RegOpenKeyExW
  6D781AB8   |.  85C0  test    eax, eax
  。。。。。。。
  6D781AD6   |.  EB 18 jmp     short deskperf.6D781AF0
  6D781AD8   |>  6A 04 push    4                                 ; /BufSize = 4
  6D781ADA   |.  68 00>push    deskperf.6D783800                 ; |Buffer = deskperf.6D783800
  6D781ADF   |.  6A 04 push    4                                 ; |ValueType = REG_DWORD
  6D781AE1   |.  56    push    esi                               ; |Reserved
  6D781AE2   |.  68 CC>push    deskperf.6D7811CC                 ; |ValueName = "Acceleration.Level"
  6D781AE7   |.  FF75 >push    [arg.3]                           ; |hKey = 260
  6D781AEA   |.  FF15 >call    dword ptr ds:[<&ADVAPI32.RegSetVa>; \RegSetValueExW
  6D781AF0   |> \85C0  test    eax, eax
  6D781AF2   |.  75 07 jnz     short deskperf.6D781AFB
  6D781AF4   |.  C745 >mov     [arg.2], 1
  6D781AFB   |>  FF75 >push    [arg.3]                           ; /hKey
  6D781AFE   |.  FF15 >call    dword ptr ds:[<&ADVAPI32.RegClose>; \RegCloseKey
  6D781B04   |.  3975 >cmp     [arg.2], esi
  6D781B07   |.  0F84 >je      deskperf.6D781C30
  6D781B0D   |.  F645 >test    byte ptr ss:[ebp+14], 1
  6D781B11   |.  A1 00>mov     eax, dword ptr ds:[6D783800]
  6D781B16   |.  A3 04>mov     dword ptr ds:[6D783804], eax
  6D781B1B   |.  74 09 je      short deskperf.6D781B26
  6D781B1D   |.  6A 40 push    40                                ; /Flags = 40
  6D781B1F   |.  56    push    esi                               ; |pDevMode
  6D781B20   |.  FF15 >call    dword ptr ds:[<&USER32.ChangeDisp>; \ChangeDisplaySettingsW
  
  整理一下:
    1、
      程序在启动时 调用 EnumDisplayDevices 得到显示设备在注册表中存放的位置 如下:
       "\Registry\Machine\System\CurrentControlSet\Control\Video\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
      这个串并不是一个标准的注册表格式,接着程序将其处理为标准格式:
      "SYSTEM\CURRENTCONTROLSET\CONTROL\VIDEO\{E110E3C0-EA6F-4F1F-8043-A3A28571575D}\0000"
      也就是将最前的“"\Registry\Machine\”删除掉了,然后root = HKEY_LOCAL_MACHINE 打开并读取键值,并显示在界面上。
    2、
      当我们拖动滑竿时,程序会根据滑竿的位置(5-0)设置界面上显示的提示信息。
    3、
      当我们点击“应用按钮”后,程序先把滑竿的位置(5-0)保存在注册表中(保存位置就是界面显示时获取的),
      然后再调用API ChangeDisplaySettingsW 使当前设置生效。
  
  
  以上分析完成,剩下的工作就是写个程序实现以上过程就可以达到效果了:)
  代码如下:
  
  // SetAccelerationLevel.cpp : 定义 DLL 应用程序的导出函数。
  //
  
  #include "stdafx.h"
  #include <Windows.h>
  
  /*
    作用:  设置 windows 显卡硬件加速的等级。
    参数:  指定新的等级( 5-0,5 禁用, 0 全速)
    返回值:旧的等级。
    作者:  FishSeeWater
  
      FishSeeWater@gmail.com
      2008.08.18
  */
  
  extern "C" __declspec(dllexport) int SetAccelerationLevel(int level)
  {
  
    char originalLevel[10]={0};
  
    char regDevicePath[1024]={0};
    char regDeviceKeyName[]="Acceleration.Level";
    DISPLAY_DEVICE  dv;
    HKEY hKey;
    char *p;
    int i;
  
    ZeroMemory(&dv,sizeof(DISPLAY_DEVICE));
    dv.cb=sizeof(DISPLAY_DEVICE);
    EnumDisplayDevices(0,0,&dv,0);
  
    i=0;
    while(dv.DeviceKey[i])
    {
      dv.DeviceKey[i++]=toupper(dv.DeviceKey[i]);
    }
  
    p=(char *)strstr(dv.DeviceKey,"\\SYSTEM");
    lstrcpy(regDevicePath,p+1);
  
    if(ERROR_SUCCESS== RegOpenKeyEx(HKEY_LOCAL_MACHINE,regDevicePath,0,KEY_ALL_ACCESS,&hKey))
    {
      i=9;
      RegQueryValueEx(hKey,regDeviceKeyName,0,0,(LPBYTE)originalLevel,(LPDWORD)&i);
      RegSetValueEx(hKey,regDeviceKeyName,0,REG_DWORD,(BYTE*)&level,sizeof(level));
      ChangeDisplaySettings(0,0x40);  //0x40 查MSDN没有找到什么意思,这里直接在OD中照搬。
      RegCloseKey(hKey);
    }
    return (int)originalLevel[0] ;
  }
  // 以下是测试代码:)
  int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevinstance,LPSTR lpCmdline,int nShowCmd)
  {
    int i=SetAccelerationLevel(4);
  }
  //=====================
  
  另:请教
  
     原本想用Delphi实现这个功能(项目是Delphi的),但发现
  delphi  DISPLAY_DEVICEW 中的定义 与 VC中相差甚远 ,只好用Dll实现。
  
  // Delphi
    _DISPLAY_DEVICEW = record
      cb: DWORD;
      DeviceName: array[0..31] of WideChar;
      DeviceString: array[0..127] of WideChar;
      StateFlags: DWORD;
    end;
  
  // VC
  typedef struct _DISPLAY_DEVICEA {
      DWORD  cb;
      CHAR   DeviceName[32];
      CHAR   DeviceString[128];
      DWORD  StateFlags;
      CHAR   DeviceID[128];
      CHAR   DeviceKey[128];
  } DISPLAY_DEVICEA, *PDISPLAY_DEVICEA, *LPDISPLAY_DEVICEA;
  
  这是什么原因 ? 明白的大虾给个指点 ^_^ 。
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2010年08月18日 16:45:13

上传的附件 SetAccelerationLevel.rar