首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

兑现在XP中使用Remote Desktop时也能得到ClearType 效果

2012-08-08 
实现在XP中使用Remote Desktop时也能得到ClearType 效果转载请标明是引用于 http://blog.csdn.net/chenyuj

实现在XP中使用Remote Desktop时也能得到ClearType 效果

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家提出意见,一起讨论!

源码请自行到参考文章中下载。

 

参考文章<<http://www.codeproject.com/Articles/20866/ClearType-over-Remote-Desktop-in-Windows-XP>>

 

一、介绍

我所感兴趣的有以下:

1)ClearType字体在XP系统中能光滑;

2)用远程桌面在家里面工作;

3)不运行在Vista;

总结成一句是: 通过在不运行Vista(如XP)系统中用RDP实现远程桌面,并且RDP的效果能达到ClearType的效果。

不幸的是当我们运行RDP来连接到你的XP机器时,用ClearType的字体光滑是无效的。我猜想XP在2001年刚出来时,微软做了决定要让RDP上的ClearType被禁止。

在2007年,然而,百万级带宽非常普遍了,这时不要用户使用ClearType的决定看起来就已经过时了。(虽然后定Vista系统中的RDP支持了ClearType,但XP还是没有)

通过WinDBG,我认为可以通过内核下的bytes来解决这些问题,我决定在XP下使用RDP上的ClearType功能。

二、应用程序概述

 这里有两部分的问题:

1、内核驱动,它在win32k.sys中对一些bytes打补丁;

2、用户模式的应用程序,它载入驱动并告诉它运行和做Patch(打补丁);

内核的部分是容易的。基本上,在win32k.sys中有代码路径像这样的(多亏了WinDBG的反汇编)

bf811387 66393550399abf  cmp     word ptr [win32k!gProtocolType (bf9a3950)],sibf81138e 0f85c2feffff    jne     win32k!LFONTOBJ::ppfeMapFont+0x77 (bf811256)


我发现在我的调试器,gProtocolType变量根据你在控制台或通过RDP访问机器是不一样的。

在控制器时,jne 分支 没有被包含;但RDP时它有。

简单的改变(且有一个是产生期望的结果)仅用来忽略jne组件。取而代之的nops意味着这个分支没有被跟从-----非RDP代码路径将一直是包含的一个。

程序的内核部分(RdpClearType.sys)简单地做了nop 的补丁。

然而,那里有一个警告:看起来好像每次登陆都获得win32k.sys的复制并映射到它的地址空间(在一个叫“Session Space”的空间)。当我安装驱动,并且无论我是

在开机时启动或是通过服务手去去启动它,它都不能工作。我猜是因为驱动没有被服务加载。

我的解决方案是创建一个用户模式的加载程序,它把进程分为两个步骤:

1、通过正常的SCM接口启动驱动(CreateService和StartService)。

在SCM的线程中我的驱动的DriverEntry代码将会被调用并执行它自己的登陆段。

这是为什么我的DriverEntry没有做真实的补丁的原因........它简单的创建了一个设备,此设备对用户模式通过调用\DosDevices\SC_HANDLE hSvc = CreateService(hScm,L"RdpClearType",L"RdpClearType",SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,driverPath.c_str(),NULL,NULL,NULL,NULL,NULL);if (hSvc){SERVICE_STATUS svcStatus = { 0 };if (StartService(hSvc, 0, NULL)){do{Sleep(250);if (!QueryServiceStatus(hSvc, &svcStatus)){ShowMessage(MAKE_STRING(L"RdpClearType: ERROR calling QueryServiceStatus(): " << GetLastError() << endl));break;}}while (svcStatus.dwCurrentState != SERVICE_RUNNING);HANDLE hFile = CreateFileW(L"\\\\.\\RdpClearType",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE){ShowMessage(MAKE_STRING(L"RdpClearType: ERROR opening handle to RdpClearType device: " << GetLastError() << endl));}else{DWORD bytes = 0;BOOL result = DeviceIoControl(hFile,0,NULL,0,NULL,0,&bytes,NULL);if (result){ShowMessage(MAKE_STRING(L"RdpClearType: ClearType should now be working inside of Remote Desktop connections." << endl));ValidateRect(NULL, NULL);retval = 0;}else{ShowMessage(MAKE_STRING(L"RdpClearType: ERROR calling DeviceIoControl: " << GetLastError() << endl));}CloseHandle(hFile);}if (ControlService(hSvc, SERVICE_CONTROL_STOP, &svcStatus)){do{Sleep(250);if (!QueryServiceStatus(hSvc, &svcStatus)){ShowMessage(MAKE_STRING(L"RdpClearType: ERROR calling QueryServiceStatus(): " << GetLastError() << endl));break;}}while (svcStatus.dwCurrentState != SERVICE_STOPPED);}else{ShowMessage(MAKE_STRING(L"RdpClearType: ERROR stopping service: " << GetLastError() << endl));}}else{ShowMessage(MAKE_STRING(L"RdpClearType: ERROR starting service: " << GetLastError() << endl));}DeleteService(hSvc);}else{ShowMessage(MAKE_STRING(L"RdpClearType: ERROR creating service: " << GetLastError() << endl));}


 

2、在驱动已经被加载并启动后,用户模式代码打开\DosDevices\wchar_t buffer[MAX_PATH];ExpandEnvironmentStrings(L"%SystemDrive%", &buffer[0], sizeof(buffer) / sizeof(wchar_t));wstring driverPath = &buffer[0];driverPath.append(L"\\RdpClearType.sys");DeleteFile(driverPath.c_str());if (!SaveResource(IDR_BIN1, driverPath)){ShowMessage(MAKE_STRING(L"RdpClearType: ERROR extracting driver from exe" << endl));return 1;}

// This function will extract one of the embedded PE files in this// executable image and save it to disk.bool SaveResource(WORD resId, wstring destPath){HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(resId), L"BIN");HGLOBAL hLoadedRes = LoadResource(NULL, hRes);char *pRes = static_cast<char*>(LockResource(hLoadedRes));DWORD dwResSize = SizeofResource(NULL, hRes);ofstream outstream(destPath.c_str(), ios::binary);if (!outstream)return false;outstream.write(pRes, dwResSize);outstream.close();return true;}

三、驱动程序概述

很多人下了工程后不知资源中的RDPClearType.sys哪里来的,其实它是由里面的Driver.c文件通过DDK环境编译得来的。

(VS2008+DDK的编译环境可参考我的文章<<NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath){UNICODE_STRING deviceNameUnicodeString;UNICODE_STRING linkNameUnicodeString;NTSTATUS retval = STATUS_SUCCESS;int i;pDriverObject->DriverUnload = OnUnload;RtlInitUnicodeString(&deviceNameUnicodeString, deviceName);RtlInitUnicodeString(&linkNameUnicodeString, linkName);retval = IoCreateDevice(pDriverObject,0,&deviceNameUnicodeString,FILE_DEVICE_UNKNOWN,0,FALSE,&rdpClearTypeDevice);if (retval == STATUS_SUCCESS){DbgPrint("RdpClearType: device created\n");for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++){pDriverObject->MajorFunction[i] = OnStubDispatch;}pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RdpClearTypePatch;retval = IoCreateSymbolicLink(&linkNameUnicodeString, &deviceNameUnicodeString);if (NT_SUCCESS(retval)){DbgPrint("RdpClearType: symbolic link created\n");}else{// Delete the device since the symbolic link didn't takeIoDeleteDevice(rdpClearTypeDevice);DbgPrint("RdpClearType: device deleted\n");rdpClearTypeDevice = NULL;}}else{DbgPrint("RdpClearType: ERROR creating device: %x\n", retval);rdpClearTypeDevice = NULL;}DbgPrint("RdpClearType: DriverEntry done\n");return retval;}
2、给实现ClearType打补丁

它是所有工作的重点,也是实现的难点。(说句心里话真佩服老外的能力,在驱动里加入汇编)

简单地讲是从5个备选的内存中选择1个存在Byte 的地方,并对它填充nop

NTSTATUS RdpClearTypePatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp){int i = 0;char *pPatch1 = (char*)0xBF810BD6;char *pPatch2 = (char*)0xBF81138E;char *pPatch3 = (char*)0xBF810C0E;char *pPatch4 = (char*)0xBF810BF6;char *pPatch5 = (char*)0xBF811251;char *pPatch = 0;pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;DbgPrint("RdpClearType: patch starting\n");if (CheckExistingBytes(pPatch1))pPatch = pPatch1;else if (CheckExistingBytes(pPatch2))pPatch = pPatch2;else if (CheckExistingBytes(pPatch3))pPatch = pPatch3;else if (CheckExistingBytes(pPatch4))pPatch = pPatch4;else if (CheckExistingBytesAlt1(pPatch5))pPatch = pPatch5;if (pPatch){DbgPrint("RdpClearType: applying patch at %08x\n", (int)pPatch);__asm{push eaxmov eax, CR0and eax, 0FFFEFFFFhmov CR0, eaxpop eax}for (i = 0; i < 6; i++){*pPatch = (char)0x90; // noppPatch++;}__asm{push eaxmov eax, CR0or eax, NOT 0FFFEFFFFhmov CR0, eaxpop eax}DbgPrint("RdpClearType: patch has been applied\n");}else{DbgPrint("RdpClearType: didn't find expected bytes in the any target addresses\n");}IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;}