注册本站  论坛  繁體中文

电脑技巧
手机 | MP3 | MP4 | 显卡 | 主板 | 显示器 | 光存储 | 笔记本 | 网络设备 | 移动存储 | 数码相机
键鼠 | CPU | 音箱 | GPS | 电视 | 服务器 | 投影机 | 机箱电源 | 品牌电脑 | 办公打印 |
| 网站首页 | Cisco | Windows | Linux | Java | Dotnet | Oracle | 网页设计 | 平面设计 | 安全 | 软件应用 | 电脑维修 | 办公维修 |
您现在的位置: 电脑技巧 >> Dotnet >> C# >> Dotnet正文

“扫雷”游戏地幕后2

文章来源:中国IT实验室收集整理 作者:佚名 更新时间:2008-6-28 20:38:52 【 】 【加入收藏

    IntPtr lpBaseAddress,

        [In, Out] byte[] buffer,

        UInt32 size,

        out IntPtr lpNumberOfBytesRead

        );

 

    [DllImport(\"kernel32.dll\")] public static extern Int32 CloseHandle(

        IntPtr hObject

        );

    如果你想知道在c++和c#之间有关类型转换的更多信息,我建议你从msdn.microsoft.com站点搜索此话题:“Marshaling Data with Platform Invoke”。 基本上, 如果你把逻辑上是正确的程序搁在那儿, 它便能运行, 但有时还需要一点点的调整。

        在声明了这些函数之后,我要做的是用一个简单的类把它们包装起来,并使用这个类。我把声明放在一个叫做ProcessMemoryReaderApi的类中,这样做更有条有理。主要的实用类称为ProcessMemoryReade。这个类有一个ReadProcess属性,它源于System.Diagnostics.Process类型,用于存放你要读取其内存的进程。类中有一个方法,用来以读模式打开进程。

    public void OpenProcess()

 

    {

        m_hProcess = ProcessMemoryReaderApi.OpenProcess(

                             ProcessMemoryReaderApi.PROCESS_VM_READ, 1,

                             (uint)m_ReadProcess.Id);

 

    }

    PROCESS_VM_READ 常量告诉系统以读模式打开进程, 而m_ReadProcess.Id 声明了我要打开的是什么进程。

        在该类中最重要的是一个方法,它从进程中读取内存:

    public byte[] ReadProcessMemory(IntPtr MemoryAddress, uint bytesToRead,

                                    out int bytesReaded)

    {

        byte[] buffer = new byte[bytesToRead];

 

        IntPtr ptrBytesReaded;

        ProcessMemoryReaderApi.ReadProcessMemory(m_hProcess,MemoryAddress,buffer,

                                                 bytesToRead,out ptrBytesReaded);

 

        bytesReaded = ptrBytesReaded.ToInt32();

 

        return buffer;

 

    }

    这个函数以所请求的大小声明一个字节数组,并使用API读取内存。就这么简单!

 

    最后,下面这个方法关闭了进程。

 

 

    public void CloseHandle()

 

    {

        int iRetValue;

        iRetValue = ProcessMemoryReaderApi.CloseHandle(m_hProcess);

        if (iRetValue == 0)

            throw new Exception(\"CloseHandle failed\");

 

    }

 

 

    第三步 – 使用类

        现在轮到了有趣的部分。使用这个类就是为了读取“扫雷”的内存并揭开布雷图。要使用类,需要先对其进行初始化:

    ProcessMemoryReaderLib.ProcessMemoryReader pReader

                       = new ProcessMemoryReaderLib.ProcessMemoryReader();

       接着,必须设置你想要读取其内存的进程。以下是如何获得“扫雷”进程的例子,这个进程一旦被装入,就被设置为ReadProcess属性:

    System.Diagnostics.Process[] myProcesses
    ;                 = System.Diagnostics.Process.GetProcessesByName(\"winmine\");

    pReader.ReadProcess = myProcesses[0];

 

        我们现在需要做的是:打开进程,读取内存,并在完成后关闭它。下面还是有关操作的例子,它读取代表布雷图宽度的地址。


    pReader.OpenProcess();

 

    int iWidth;

    byte[] memory;

    memory = pReader.ReadProcessMemory((IntPtr)0x1005334,1,out bytesReaded);

    iWidth = memory[0];

 

    pReader.CloseHandle();

       简单吧!

 

         在结论部分,我列出了显示布雷图的完整代码。别忘了,我要访问的所有内存位置就是在本文第一部分中所找到位置。

    // 布雷图的资料管理器

    System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));

 

    ProcessMemoryReaderLib.ProcessMemoryReader pReader

                       = new ProcessMemoryReaderLib.ProcessMemoryReader();

 

    System.Diagnostics.Process[] myProcesses

                   = System.Diagnostics.Process.GetProcessesByName(\"winmine\");
                   // 获得“扫雷”进程的第一个实列

    if (myProcesses.Length == 0)

    {

        MessageBox.Show(\"No MineSweeper process found!\");

        return;

    }

    pReader.ReadProcess = myProcesses[0];

 

    // 以读内存模式打开进程

    pReader.OpenProcess();

 

    int bytesReaded;

    int iWidth, iHeight, iMines;

    int iIsMine;

    int iCellAddress;

    byte[] memory;

 

    memory = pReader.ReadProcessMemory((IntPtr)0x1005334,1,out bytesReaded);

    iWidth = memory[0];

    txtWidth.Text = iWidth.ToString();

 

    memory = pReader.ReadProcessMemory((IntPtr)0x1005338,1,out bytesReaded);

    iHeight = memory[0];

    txtHeight.Text = iHeight.ToString();

 

    memory = pReader.ReadProcessMemory((IntPtr)0x1005330,1,out bytesReaded);

    iMines = memory[0];

    txtMines.Text = iMines.ToString();

    // 删除以前的按钮数组

    this.Controls.Clear();

    this.Controls.AddRange(MainControls);

 

    // 创建一个按钮数组, 用于画出布雷图的每一格

    ButtonArray = new System.Windows.Forms.Button[iWidth,iHeight];

 

    int x,y;

    for (y=0 ; y<iHeight ; y++)

        for (x=0 ; x<iWidth ; x++)

        {

            ButtonArray[x,y] = new System.Windows.Forms.Button();

            ButtonArray[x,y].Location = new System.Drawing.Point(20 + x*16, 70 + y*16);

            ButtonArray[x,y].Name = \"\";

            ButtonArray[x,y].Size = new System.Drawing.Size(16,16);

 

            iCellAddress = (0x1005340) + (32 * (y+1)) + (x+1);

            memory = pReader.ReadProcessMemory((IntPtr)iCellAddress,1,out bytesReaded);

            iIsMine = memory[0];

 

            if (iIsMine == 0x8f)//如果有雷,则画出地雷位图

                ButtonArray[x,y].Image = ((System.Drawing.Bitmap)

                                         (resources.GetObject(\"button1.Image\")));

 

            this.Controls.Add(ButtonArray[x,y]);

        }

 

    // 关闭进程句柄

    pReader.CloseHandle();

    就是这些,希望你能学到新的东西。

  • 上一篇Dotnet:

  • 下一篇Dotnet:
  • 最 新 热 门
     web.config配置文件中的 元素
     为网站添加业务层
     用SqlDataSource实现DataList嵌套DataList
     Visual Studio 2003插件的编写
     千条DOS命令收藏
     IIS 常见问题
     IIS需要的最小NTFS权限
     优化 .NET的性能
     设计模式与VB .net代码 外观模式,合成模式
     VB.net中介者模式
    最 新 推 荐
     Windows via C/C++ —进程(一)
     C#邮件发送程序
     扩展 ASP.NET 的客户端验证
     实现DataGridView中行的上下移动
     C#中的委托和事件
     与IDE相关的Attribute属性
     C#中using关键字的使用介绍
     C#FileStream复制大文件
     C#实用技巧:轻松实现对文件的操作
     C#实现所有经典排序算法
    相 关 文 章

    “扫雷”游戏的幕后

    | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站公告

     

    Copyright 2006-2008 pcjx.com All Rights Reserved
    电脑技巧 版权所有 粤ICP备06059145号 地图
    本网站所有内容未经许可不得转载或做其他使用