魔兽贱队 发表于 2014-9-9 10:12:56

在程序中设置[硬件加速级别]

【详细过程】
最近由于项目的需求,需要在项目中禁用显卡的硬件加速,在网上一遍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:
6D78169E |. 0F84 >je deskperf.6D781C95
6D7816A4 |. 51 push ecx
6D7816A5 |. FF75 >push
6D7816A8 |. 890D >mov dword ptr ds:, ecx
6D7816AE |. E8 D1>call deskperf.6D781484 ; 设置窗口上的信息提示。//当拖动滑竿时,会不断调用这里来设置界面提示。
6D7816B3 |. 56 push esi
6D7816B4 |. FF75 >push
6D7816B7 |. 68 68>push 468
6D7816BC |. FF75 >push ; /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:, bx
6D7816D6 |. 0F85 >jnz deskperf.6D781C95
6D7816DC |. 53 push ebx ; /ButtonID => CD (205.)
6D7816DD |. FF75 >push ; |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,
6D7817A1 |. 50 push eax
6D7817A2 |. 57 push edi
6D7817A3 |. 8975 >mov , 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:, si
6D7817BA 8DBD >lea edi, dword ptr ss:
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 , ebx
6D7814D8 |> 33D2 xor edx, edx
6D7814DA |. 3955 >cmp , edx
6D7814DD |. 75 7E jnz short deskperf.6D78155D
6D7814DF |. 33C0 xor eax, eax
6D7814E1 |. B9 D2>mov ecx, 0D2
6D7814E6 |. 8DBD >lea edi,
6D7814EC |. F3:AB rep stos dword ptr es:
6D7814EE |. 52 push edx ; /Flags => 0
6D7814EF |. 8D85 >lea eax, ; |
6D7814F5 |. 50 push eax ; |pDisplayDevice
6D7814F6 |. 53 push ebx ; |DeviceNo
6D7814F7 |. 52 push edx ; |Reserved => 0
6D7814F8 |. C785 >mov , 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 ; /String2
6D781511 |. 8D85 >lea eax, ; |
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,
6D781528 |. 50 push eax ; /String
6D781529 |> FF15 >call dword ptr ds:[<&KERNEL32.lstrlenW>; \lstrlenW
6D78152F |. 33C9 xor ecx, ecx
6D781531 |. 3B45 >cmp eax,
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,
6D781543 |. 50 push eax ; /String2
6D781544 |. FF75 >push ; |String1
6D781547 |. FF15 >call dword ptr ds:[<&KERNEL32.lstrcpyW>; \lstrcpyW
6D78154D |. C745 >mov , 1
6D781554 |> 43 inc ebx
6D781555 |. 85F6 test esi, esi
6D781557 |.^ 0F85 >jnz deskperf.6D7814D8
6D78155D |> 8B45 >mov eax,
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:
6D7817C7 50 push eax
6D7817C8 FF15 >call dword ptr ds:[<&msvcrt.towupper>] ; msvcrt.towupper  
6D7817CE 66:89>mov word ptr ds:, ax
6D7817D1 |. 47 |inc edi
6D7817D2 |. 47 |inc edi
6D7817D3 |. 66:39>|cmp word ptr ds:, si
6D7817D6 |. 59 |pop ecx
6D7817D7 |.^ 75 E9 \jnz short deskperf.6D7817C2
6D7817D9 |> 8D85 >lea eax,
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,
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 , 1 ; |
6D78180F |. 8975 >mov , 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,
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:, 1
6D78183C |> 3975 >cmp , esi
6D78183F |. 74 4C je short deskperf.6D78188D
6D781841 |. 8D45 >lea eax,
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 ; |hKey
6D781854 |. C745 >mov , 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,
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 , 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 ; |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 , 1
6D781AFB |> FF75 >push ; /hKey
6D781AFE |. FF15 >call dword ptr ds:[<&ADVAPI32.RegClose>; \RegCloseKey
6D781B04 |. 3975 >cmp , esi
6D781B07 |. 0F84 >je deskperf.6D781C30
6D781B0D |. F645 >test byte ptr ss:, 1
6D781B11 |. A1 00>mov eax, dword ptr ds:
6D781B16 |. A3 04>mov dword ptr ds:, 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={0};

char regDevicePath={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)
{
dv.DeviceKey=toupper(dv.DeviceKey);
}

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 ;
}
// 以下是测试代码:)
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 of WideChar;
DeviceString: array of WideChar;
StateFlags: DWORD;
end;

// VC
typedef struct _DISPLAY_DEVICEA {
DWORD cb;
CHAR DeviceName;
CHAR DeviceString;
DWORD StateFlags;
CHAR DeviceID;
CHAR DeviceKey;
} DISPLAY_DEVICEA, *PDISPLAY_DEVICEA, *LPDISPLAY_DEVICEA;

这是什么原因 ? 明白的大虾给个指点 ^_^ 。
页: [1]
查看完整版本: 在程序中设置[硬件加速级别]