之前整理过一篇《WinCE6.0中应用程序如何直接访问物理空间》的短文,文中介绍的方法突破了WinCE6.0系统本身的限制,使应用程序能够直接读写指定的内存地址,如访问系统显存。在WinCE中,使用托管代码编写应用程序直接访问物理空间,之前也曾简单介绍过,当时是基于VB.NET实现的,请参考《WinCE下VB.NET程序的开发》。今天再凑一篇基于C#的。
原理之前两篇都已经讲过了,这里不再赘述。实现方法与VB.NET类似,首先用C++编写一个动态链接库,实现所需功能,并导出相应的函数。在托管代码中调用这些函数读写指定的物理空间。闲话不再多说,直接附上参考代码。
SysApi.h代码如下:
1 #ifndef __SYSAPI_H__
2 #define __SYSAPI_H__
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8 #ifdef _WINDLL
9 #ifdef SYSAPI_EXPORTS
10 #define CLASS_DECLSPEC __declspec (dllexport)
11 #else
12 #define CLASS_DECLSPEC __declspec (dllimport)
13 #endif
14 #else
15 #define CLASS_DECLSPEC
16 #endif
17
18 typedef struct {
19 void* pvDestMem;
20 DWORD dwPhysAddr;
21 DWORD dwSize;
22 } VIRTUAL_COPY_EX_DATA,*PVIRTUAL_COPY_EX_DATA;
23
24 #define IOCTL_VIRTUAL_COPY_EX CTL_CODE (FILE_DEVICE_UNKNOWN,3333,METHOD_BUFFERED,FILE_ANY_ACCESS)
25
26 CLASS_DECLSPEC LPVOID GetVirtual(DWORD dwPhyBaseAddress, DWORD dwSize);
27 CLASS_DECLSPEC VOID FreeVirtual(LPVOID pVirtualAddress);
28 CLASS_DECLSPEC VOID SetVirtual(LPVOID pVirtualAddress, BYTE val, DWORD dwSize);
29
30 #ifdef __cplusplus
31 }
32 #endif
33
34 #endif
SysApi.cpp代码如下:
1 // SysApi.cpp : 定义 DLL 应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include <windows.h>
6 #include <commctrl.h>
7 #include <Pkfuncs.h>
8 #include "SysApi.h"
9
10 BOOL APIENTRY DllMain( HANDLE hModule,
11 DWORD ul_reason_for_call,
12 LPVOID lpReserved
13 )
14 {
15 return TRUE;
16 }
17
18 CLASS_DECLSPEC LPVOID GetVirtual(DWORD dwPhyBaseAddress, DWORD dwSize)
19 {
20 volatile LPVOID pVirtual;
21 VIRTUAL_COPY_EX_DATA vced;
22
23 if(dwPhyBaseAddress & 0xFFF)
24 {
25 return NULL;
26 }
27
28 vced.dwPhysAddr = dwPhyBaseAddress>>8;
29 pVirtual = VirtualAlloc(0, dwSize, MEM_RESERVE, PAGE_NOACCESS);
30 vced.pvDestMem = pVirtual;
31 vced.dwSize = dwSize;
32 KernelIoControl(IOCTL_VIRTUAL_COPY_EX, &vced, sizeof(vced), NULL, NULL, NULL);
33
34 return pVirtual;
35 }
36
37 CLASS_DECLSPEC VOID FreeVirtual(LPVOID pVirtualAddress)
38 {
39 VirtualFree(pVirtualAddress, 0, MEM_RELEASE);
40 }
41
42 CLASS_DECLSPEC VOID SetVirtual(LPVOID pVirtualAddress, BYTE val, DWORD dwSize)
43 {
44 if (pVirtualAddress)
45 {
46 memset(pVirtualAddress, val, dwSize);
47 }
48 }
C#的参考代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Text;
7 using System.Windows.Forms;
8 using System.Runtime.InteropServices;
9
10 namespace SysApp2
11 {
12 public partial class Form1 : Form
13 {
14 [DllImport("SysApi.dll", CharSet = CharSet.Auto)]
15 public static extern IntPtr GetVirtual(uint PhyBaseAddress, uint Size);
16 [DllImport("SysApi.dll", CharSet = CharSet.Auto)]
17 public static extern void FreeVirtual(IntPtr pVirtualAddress);
18 [DllImport("SysApi.dll", CharSet = CharSet.Auto)]
19 public static extern void SetVirtual(IntPtr pVirtualAddress, byte val, uint dwSize);
20
21 private IntPtr pLCDBuf;
22
23 public Form1()
24 {
25 InitializeComponent();
26 }
27
28 private void Black_Click(object sender, EventArgs e)
29 {
30 SetVirtual(pLCDBuf, 0x00, 0x300000);
31 }
32
33 private void White_Click(object sender, EventArgs e)
34 {
35 SetVirtual(pLCDBuf, 0xFF, 0x300000);
36 }
37
38 private void FormClosed(object sender, EventArgs e)
39 {
40 FreeVirtual(pLCDBuf);
41 }
42
43 private void FormLoad(object sender, EventArgs e)
44 {
45 pLCDBuf = GetVirtual(0x4C800000, 0x300000);
46 }
47 }
48 }
以上代码实现了,在C#编写的应用程序中通过写显存的方式将屏幕刷成全黑或者全白。示例代码的完整解决方案下载地址:http://files.cnblogs.com/we-hjb/SysApi.rar