/*ScreenToClient 用来转两次把屏幕rect该为clientrect*/
BOOL ScreenToClient(LPRECTlpRect) const throw()
{
ATLASSERT(::IsWindow(m_hWnd));
if(!::ScreenToClient(m_hWnd,(LPPOINT)lpRect))
return FALSE;
return::ScreenToClient(m_hWnd, ((LPPOINT)lpRect)+1);
}
/*******************************************************************
论证上述(LPPOINT)lpRect),((LPPOINT)lpRect)+1转换的正确性,第一次调用是把point(lpRect->left,lpRect->top)转换为客户坐标,第二次转换把point(lpRect-> right, lpRect->bottom)转换为客户坐标,通过两次转换即把一个屏幕rect转换为客户端rect。下面例子通过反汇编来论证。
#include "stdafx.h"
#include <iostream>
using namespace std;
struct A
{
long a;
long b;
};
typedef A* LPA;
struct B
{
long a;
long b;
long c;
long d;
};
typedef B* LPB;
int _tmain(int argc, _TCHAR* argv[])
{
B b = {1, 2, 3,4};
/*
0041417E mov dword ptr [b],1
00414185 mov dword ptr [ebp-10h],2
0041418C mov dword ptr [ebp-0Ch],3
00414193 mov dword ptr [ebp-8],4
*/
LPA a = (LPA)&b; // a地址跟b地址相同,见汇编
/*
0041419A lea eax,[b] //把b的地址赋给eax
0041419D mov dword ptr [a],eax //把eax的地址赋给a
*/
cout<<&b<<"\t"<<a<<endl;
///////////////////////////////////////////
cout<<a->a<<"\t"<<a->b<<endl;
/*
004141F3 mov esi,esp
004141F5 mov eax,dword ptr [__imp_std::endl(41A310h)]
004141FA push eax
004141FB mov edi,esp
004141FD mov ecx,dword ptr [a]
00414200 mov edx,dword ptr [ecx+4] //edx 为2,存储的是a->b的值,a->b地址是a地址加
00414203 push edx
00414204 push offset string "\t" (4177FCh)
00414209 mov ebx,esp
0041420B mov eax,dword ptr [a]
0041420E mov ecx,dword ptr [eax] //ecx 为1,存储的是a->a的值,a->a地址是a地址
00414210 push ecx
00414211 mov ecx,dword ptr [__imp_std::cout(41A30Ch)]
00414217 call dword ptr[__imp_std::basic_ostream<char,std::char_traits<char>>::operator<< (41A300h)]
*/
LPA aa = ((LPA)&b) +1; //aa地址跟b.c地址相同,见汇编
/*
00414258 lea eax,[ebp-0Ch] //[ebp-0Ch] 就是b.c的地址,见行
0041425B mov dword ptr [aa],eax //aa的地址跟b.c地址相同
*/
cout<<aa->a<<"\t"<<aa->b<<endl; //同 cout<<a->a<<"\t"<<a->b<<endl;的反汇编
return 0;
}