【文章标题】: 在程序中设置[硬件加速 级别]
【文章作者】: FishSeeWater[丰盛辉煌]
【操作平台】: Windows XP
【关 键字】: 硬件加速 VC++ 禁用硬件加速 设置硬件加速
--------------------------------------------------------------------------------
【详细过程】
最近由于项目的需求,需要在项目中禁用显卡的硬件加速,在网上一遍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月22日 16:45:13
作者mail:fishseewater@gmail.com
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fishseewater/archive/2010/10/04/5921610.aspx