zoukankan      html  css  js  c++  java
  • 基于visual c++之windows核心编程代码分析(34)WinIo驱动级模拟按键的实现

    WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保护机制。
      WinNT/2000/XP下,WinIO函数库只允许被具有管理者权限的应用程序调用。如果使用者不是以管理者的身份进入的,则WinIO.DLL不能够被安装,也不能激活WinIO驱动器。通过在管理者权限下安装驱动器软件就可以克服这种限制。然而,在这种情况下,ShutdownWinIo函数不能在应用程序结束之前被调用,因为该函数将WinIO驱动程序从系统注册表中删除。
      该函数库提供8个函数功能调用:
      bool _stdcall InitializeWinIo();
      本函数初始化WioIO函数库。
      必须在调用所有其它功能函数之前调用本函数。
      如果函数调用成功,返回值为非零值。
      如果调用失败,则返回值为0。
      void _stdcall ShutdownWinIo();
      本函数在内存中清除WinIO库
      本函数必须在中止应用函数之前或者不再需要WinIO库时调用,
      bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
      使用此函数从一个输入或输出端口读取一个字节/字/双字数据。
      参数:
      wPortAddr – 输入输出端口地址
      pdwPortVal – 指向双字变量的指针,接收从端口得到的数据。
      bSize – 需要读的字节数,可以是1 (BYTE), 2 (WORD) or 4 (DWORD).
      如果调用成功,则返回非零值。
      如果函数调用失败,则函数返回值为零。
      bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
      使用本函数将一个字节/字/双字的数据写入输入或输出接口。
      参数:
      wPortAddr – 输入输出口地址
      dwPortVal – 要写入口的数据
      bSize – 要写的数据个数,可以是 1 (BYTE), 2 (WORD) or 4 (DWORD).
      如果调用成功,则返回非零值。
      如果函数调用失败,则函数返回值为零。
      PBYTE _stdcall MapPhysToLin(PBYTE pbPhysAddr, DWORD dwPhysSize, HANDLE *pPhysicalMemoryHandle)
      使用此函数将物理内存的一部分映射到一个32位应用程序的线性地址空间。
      下面是一个例子:
      PBYTE pbLinAddr;
      HANDLE PhysicalMemoryHandle;
      pbLinAddr = MapPhysToLin(0xA0000, 65536, &PhysicalMemoryHandle);
      该函数将把物理地址范围为0xA0000 - 0xAFFFF的地址空间映射到与应用程序对应的线性地址空间。 返回值为一个与物理地址0xA0000相关的线性地址。如果出现错误,则返回值为NULL。
      参数:
      pbPhysAddr – 指向物理地址的指针
      dwPhysSize – 需要映射的字节数
      pPhysicalMemoryHandle – 变量指针,如果调用成功,负责接收物理内存句柄。随后本句柄在调用UnmapPhysicalMemory函数时作为其第一个参数。
      bool _stdcall UnmapPhysicalMemory(HANDLE PhysicalMemoryHandle, PBYTE
      pbLinAddr)
      使用本函数解除原先使用MapPhysToLin函数映射的一段线性物理内存区域,该区域被映射到应用程序所属的线性地址空间。
      Windows 9x 应用程序不需要调用此函数。
      参数:
      PhysicalMemoryHandle – 物理内存区域所属的句柄,此参数由对MapPhysToLin函数的调用返回。
      pbLinAddr – MapPhysToLin函数调用返回的线性地址。
      bool _stdcall GetPhysLong(PBYTE pbPhysAddr, PDWORD pdwPhysVal);
      从指定的物理地址读取一个双字数据。
      参数:
      pbPhysAddr – 指向物理地址的指针。
      pdwPhysVal – 指向一个双字变量的指针,接收从物理内存中传来的数据。
      如果此函数调用成功,返回一个非零值。
      如果函数调用失败,则返回一个零值。
      bool _stdcall SetPhysLong(PBYTE pbPhysAddr, DWORD dwPhysVal);
      将一个双字型数据写入指定的物理地址。
      参数:
      pbPhysAddr – 指向物理地址的指针。
      pdwPhysVal – 指定待写入物理内存地址出的双字型数据。
      如果此函数调用成功,返回一个非零值。
      如果函数调用失败,则返回一个零值。

    我们代码实现WinIO虚拟实现按键。

    #include "stdafx.h"
    #include "Winio模拟按键.h"
    #include "Winio模拟按键Dlg.h"
    #include "WinIo.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CAboutDlg dialog used for App About
    
    class CAboutDlg : public CDialog
    {
    public:
    	CAboutDlg();
    
    // Dialog Data
    	//{{AFX_DATA(CAboutDlg)
    	enum { IDD = IDD_ABOUTBOX };
    	//}}AFX_DATA
    
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CAboutDlg)
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    	//}}AFX_VIRTUAL
    
    // Implementation
    protected:
    	//{{AFX_MSG(CAboutDlg)
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    	//{{AFX_DATA_INIT(CAboutDlg)
    	//}}AFX_DATA_INIT
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	//{{AFX_DATA_MAP(CAboutDlg)
    	//}}AFX_DATA_MAP
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    	//{{AFX_MSG_MAP(CAboutDlg)
    		// No message handlers
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CWinioDlg dialog
    
    CWinioDlg::CWinioDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CWinioDlg::IDD, pParent)
    {
    	//{{AFX_DATA_INIT(CWinioDlg)
    		// NOTE: the ClassWizard will add member initialization here
    	//}}AFX_DATA_INIT
    	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CWinioDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	//{{AFX_DATA_MAP(CWinioDlg)
    		// NOTE: the ClassWizard will add DDX and DDV calls here
    	//}}AFX_DATA_MAP
    }
    
    BEGIN_MESSAGE_MAP(CWinioDlg, CDialog)
    	//{{AFX_MSG_MAP(CWinioDlg)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
    	ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
    	ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
    	ON_BN_CLICKED(IDC_BUTTON4, OnButton4)
    	ON_WM_DESTROY()
    	ON_WM_CLOSE()
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CWinioDlg message handlers
    
    BOOL CWinioDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    
    	// Add "About..." menu item to system menu.
    
    	// IDM_ABOUTBOX must be in the system command range.
    	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    	ASSERT(IDM_ABOUTBOX < 0xF000);
    
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		CString strAboutMenu;
    		strAboutMenu.LoadString(IDS_ABOUTBOX);
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    
    	// Set the icon for this dialog.  The framework does this automatically
    	//  when the application's main window is not a dialog
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    	
    	// TODO: Add extra initialization here
    	
    	//初始化WinIo库
    	InitializeWinIo();
    
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    void CWinioDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    	{
    		CAboutDlg dlgAbout;
    		dlgAbout.DoModal();
    	}
    	else
    	{
    		CDialog::OnSysCommand(nID, lParam);
    	}
    }
    
    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.
    
    void CWinioDlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // device context for painting
    
    		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
    
    		// Center icon in client rectangle
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// Draw the icon
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialog::OnPaint();
    	}
    }
    
    // The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CWinioDlg::OnQueryDragIcon()
    {
    	return (HCURSOR) m_hIcon;
    }
    
    void CWinioDlg::OnOK() 
    {
    	// TODO: Add extra validation here
    	
    	CDialog::OnOK();
    }
    
    void KBCWait4IBE()
    {
    	DWORD dwRegVal=0;
    	do
    	{ 
    		GetPortVal(0x64,&dwRegVal,1);
    	}
    	while(dwRegVal & 0x2);
    }
    
    
    void MyKeyDown(DWORD KCode)
    {
    	Sleep(2000);	//休息2秒
    	
    	KBCWait4IBE(); //等待键盘缓冲区为空
    	SetPortVal( 0X64, 0xD2, 1 ); //发送键盘写入命令
    	Sleep(10);
    	KBCWait4IBE();
    	SetPortVal( 0X60, MapVirtualKey(KCode, 0), 1 ); //写入按键信息,按下键
    }
    
    void MyKeyUp(DWORD KCode)
    {
    	Sleep(10);
    	KBCWait4IBE(); //等待键盘缓冲区为空
    	SetPortVal(0X64, 0xD2, 1 ); //发送键盘写入命令
    	Sleep(10);
    	KBCWait4IBE();
    	SetPortVal(0X60, (MapVirtualKey(KCode, 0) | 0x80), 1); //写入按键信息,释放键
    }
    
    void CWinioDlg::OnButton1() 
    {
    	// TODO: Add your control notification handler code here
    	MyKeyDown(VK_F1); //按下F1
    	MyKeyUp(VK_F1);	  //释放F1
    
    }
    
    
    void CWinioDlg::OnButton2() 
    {
    	// TODO: Add your control notification handler code here
    	MyKeyDown(VK_BACK); //按下退格
    	MyKeyUp(VK_BACK);	//释放退格
    }
    
    
    void CWinioDlg::OnButton3() 
    {
    	// TODO: Add your control notification handler code here
    	MyKeyDown(65); //按下A键
    	MyKeyUp(65);	//释放A键
    }
    
    void CWinioDlg::OnButton4() 
    {
    	// TODO: Add your control notification handler code here
    	MyKeyDown(66); //按下B键
    	MyKeyUp(66);	//释放B键
    }
    
    void CWinioDlg::OnClose() 
    {
    	// TODO: Add your message handler code here and/or call default
    	ShutdownWinIo();
    	CDialog::OnClose();
    }
    


     

  • 相关阅读:
    lilntcode-508-摆动排序
    lintcode-501-迷你推特
    lintcode-496-玩具工厂
    lintcode-491-回文数
    lintcode-488-快乐数
    lintcode-480-二叉树的所有路径
    lintcode-248-统计比给定整数小的数的个数
    ubuntu 镜像站部署
    [转发]以我的亲身经历为例,告诉大家写简历和面试的技巧(面向高级开发和架构师)
    镜像站nginx
  • 原文地址:https://www.cnblogs.com/new0801/p/6177790.html
Copyright © 2011-2022 走看看