鼠标指针含义:深入认识指针的真正含义

要学好C语言,就必须要学好指针,而对于初学者来说,很多人对指针的含义很模糊,以至越学越糊涂。这里将从内存的角度分析指针的真正含义。
1.5.1 指针的真正本质什么是指针?所谓指针其实就是一个变量或一个函数在计算机内存中的地址。也许把指针直接称为“地址”更为确切,更容易被人理解。
在C语言中,任何变量在使用前都必须先要进行定义,否则就会编译出错,这是因为需要给这个变量在内存中申请一个地址空间。有了一个内存地址空间后,这个变量值就可以存放在这个地址上。比如说一间房子,那么这个房子的地址就是“指针”,其名称则是“指针”值,而房子里面的东西就是“变量值”。
对于一个变量,如何才能获得它的地址呢?C语言中提供了一种能够获取变量地址的方法,也就是获得某个变量指针的方法。例如:
l
int x
int *y
x=10;
*y=20;
l
在上面的代码中,变量x和*y在定义时就在内存中申请到一个地址。在C编译时,编译器将给这两个变量各分配一个地址代码;在Windows系统中,它为一个虚地址。用操作&x可以得到变量x的虚地址代码值,而y就是变量*y的虚地址代码值。也就是,&x和y分别是变量x和*y变量的指针。
当这两个变量分别申请到一个内存地址空间后,就可以分别给它们赋值了,即上面代码x=10和 *y=20的语句。
在申请变量地址时,所申请到的变量地址代码值与该变量在程序代码中的相对位置有关。有兴趣的话可以做实验来认识这一点。如果能够获得一个应用程序中某个变量的地址代码值,就可以在另外一个应用程序中通过内存访问操作来改变这个变量值。
1.5.2 用指针进行应用程序之间的通信以下通过一个实例来说明用指针如何进行应用程序间的通信。这里将给出两个应用程序,其中一个为服务程序,另一个为控制程序。先在服务程序中获得某个变量的指针,然后在控制程序中通过ReadProcessMemory()和WriteProcessMemory()这两个函数来对这个指针地址的内容进行读和写。当然这个指针值也可以通过一个DEBUG工具,如 Ollydbg等软件来获得。
两个应用程序之间用指针进行通信的方法如图1.4所示。 对话框TestServer由CTestServerDlg类建立,它为一个服务程序,而对话框TestCtrl由CTestCtrlDlg类建立,它是一个控制程序。
用指针进行通信的TestServerTestCtrl应用程序
在实际操作时,先在CTestServerDlg对象中获得m_dwValue的指针(如本实例0x12fee8),并且给m_dwValue赋值。在CTestServerDlg类中,使用Timer时间控制器更新窗口界面。
(1)创建TestServer应用程序同样用MFC AppWizard来创建应用程序TestServer,其窗口类型为对话框。在CTestServerDlg类的头文件中,字符串m_strPointer用来存放变量m_dwValue的指针,即内存地址值。当m_dwValue的值发生改变时,用OnTimer函数来更新它在TestServer对话框上的显示。在应用程序TestServer编译后,m_strValue的地址是固定的。CTestServerDlg类的头文件代码如下:
l
// TestServerDlg.h : 头文件
//
#if !defined(AFX_TESTSERVERDLG_H__INCLUDED_)
#define AFX_TESTSERVERDLG_H__INCLUDED_
//////////////////////////////////////////////////////////////////////
// CTestServerDlg dialog
class CTestServerDlg : public CDialog
{
// Construction
public:
CTestServerDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTestServerDlg)
enum { IDD = IDD_TESTSERVER_DIALOG };
CString m_strPointer;
CString m_strValue;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestServerDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
DWORD m_dwValue;
// Generated message map functions
//{{AFX_MSG(CTestServerDlg)
virtual BOOL OnInitDialog();
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#endif // !defined(AFX_TESTSERVERDLG_H__INCLUDED_)
l
在下面的CTestServerDlg::OnInitDialog函数中,调用SetTimer()以使OnTimer()起作用,其中给变量m_dwValue赋一个初值;在CTestServerDlg::OnTimer()中,先计算变量m_dwValue的指针,并把m_dwValue类型变成字符串m_strValue。最后,调用UpdateData()使字符串能在窗口界面上显示。这些成员函数的源代码如下:
l
BOOL CTestServerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 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
SetTimer(1,900,NULL);
m_dwValue=20060901;

return TRUE; // return TRUE unless you set the focus to a control.
}
void CTestServerDlg::OnTimer(UINT nIDEvent)
{
m_strPointer.Format("0x%x",&m_dwValue);
m_strValue.Format("%d",m_dwValue);
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
l
(2)创建TestCtrl应用程序同样,程序TestCtrl用MFC AppWizard 来创建,其窗口类型也为对话框。要对TestServer程序地址0x12fee8上的内容进行读或取,TestCtrl程序需要获得TestServer程序的进程句柄。这就要求TestServer程序在TestCtrl程序之前先运行起来,否则寻找TestServer程序进程操作将会失败。在CTestCtrlDlg类头文件中增加了读和写字符串,相应地定义了读和写函数。CTestCtrlDlg类头文件的代码如下:
l
// TestCtrlDlg.h: 头文件
//
#if !defined(AFX_TESTCTRLDLG_H__INCLUDED_)
#define AFX_TESTCTRLDLG_H__INCLUDED_
//////////////////////////////////////////////////////////////////////
// CTestCtrlDlg dialog
class CTestCtrlDlg : public CDialog
{
// Construction
public:
CTestCtrlDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTestCtrlDlg)
enum { IDD = IDD_TESTCTRL_DIALOG };
CString m_strRead;
CString m_strWrite;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestCtrlDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CTestCtrlDlg)
virtual BOOL OnInitDialog();
afx_msg void OnRead();
afx_msg void OnWrite();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#endif // !defined(AFX_TESTCTRLDLG_H__INCLUDED_)
l
在下面函数中,用FindWindow()函数查找到TestServer窗口后,得到其进程的句柄,然后用ReadProcessMemory()或WriteProcessMemory()函数来读取或改变TestServer程序地址0x12fee8上的内容。
l
void CTestCtrlDlg::OnRead()
{
DWORD pid;
HWND hWnd = ::FindWindow (NULL,TEXT("TestServer"));
if(!hWnd)
{
AfxMessageBox("没有找到TestServer进程.");
return;
}
::GetWindowThreadProcessId(hWnd, &pid );
HANDLE hProcess = ::OpenProcess (PROCESS_ALL_ACCESS,FALSE,pid);
LPVOID lpBaseAddress=(LPVOID)0x12fee8;
DWORD dwValue;
if(!::ReadProcessMemory(hProcess ,
lpBaseAddress,(void*)&dwValue,sizeof(DWORD),0)) return;
m_strRead.Format("%d",dwValue);
UpdateData(FALSE);
}
void CTestCtrlDlg::OnWrite()
{
DWORD pid;
HWND hWnd = ::FindWindow (NULL,TEXT("TestServer"));
if(!hWnd)
{
AfxMessageBox("没有找到TestServer进程.");
return;
}
::GetWindowThreadProcessId(hWnd, &pid );
HANDLE hProcess = ::OpenProcess (PROCESS_ALL_ACCESS,FALSE,pid);
LPVOID lpBaseAddress=(LPVOID)0x12fee8;
UpdateData();
DWORD dwValue=atoi(m_strWrite);
if(!::WriteProcessMemory(
Tags:  鼠标指针含义

延伸阅读

最新评论

发表评论