本章我感觉收获最大的就是后三个例子中的知识点,简单概括在其中Kwindow其实就是作者自己封装了一API显示窗口的程序,感觉确实封装的很有水平,也很方便日后的使用,在这个类中,包括了初始化窗口的基本要素,这是当用户需要按照自己需要创建窗口时,只需要继承一下KWindow类,然后对自己需要的函数进行创建或者重载,在这个类中,调用CreateEx函数,则会按照事件驱动的顺序从而得到自己需要的窗口和显示,这个例子的可贵之处在于让我体会到MFC封装API的大致方法,各个函数我们以前也都见过,但是如何进行合适的封装成类,这个例子给了我们很好的体现和设计思路,估计基本思想是这样的,对于创建一个窗口,头文件是这样给出的,个别函数作用已经注释,相信大家会大体认识到作者是如何封装API的思路:
class KWindow
{
protected:
virtual void OnDraw(HDC hDC)
{
}
virtual void OnKeyDown(WPARAM wParam, LPARAM lParam)
{
}
//窗口函数,负责消息循环,switch case
virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
virtual void GetWndClassEx(WNDCLASSEX & wc);//窗口类的定义
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);//窗口函数,调用WndProc
HRESULT CommonMDIChildProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
HMENU hMenu, int nWindowMenu);
HPALETTE m_hPalette;
int m_nUpdateCount;
virtual LRESULT OnQueryNewPalette(void);
virtual LRESULT OnPaletteChanged(HWND hWnd, WPARAM wParam);
bool m_bMainWindow;
public:
HWND m_hWnd;//If the function succeeds, the return value is a handle to the new window.
KWindow(void)
{
m_hWnd = NULL;
m_hPalette = NULL;
m_nUpdateCount = 0;
m_bMainWindow = false;
}
virtual ~KWindow(void)
{
if ( m_hPalette )
{
DeleteObject(m_hPalette);
m_hPalette = NULL;
}
}
virtual bool CreateEx(DWORD dwExStyle, LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight, HWND hParent, HMENU hMenu, HINSTANCE hInst);//按照事件驱动程序依次调用 //函数,创建窗口
bool RegisterClass(LPCTSTR lpszClass, HINSTANCE hInst);//注册窗口类,调用
//RegisterClass函数,在通过它调用WindowProc,完成整个时间
//使用时一个基本窗口就是执行此类函数
virtual WPARAM MessageLoop(void);
BOOL ShowWindow(int nCmdShow) const
{
return ::ShowWindow(m_hWnd, nCmdShow);
}
BOOL UpdateWindow(void) const
{
return ::UpdateWindow(m_hWnd);
}
};
接着又利用这个这个类,在下例中加入了DirectDraw API函数来改善显卡的特性.在创建窗口后,调用函数,包含想要的函数:首先调用DirectDrawCreate函数创建对象实例,SetDisplayMode,CreateSurface等,然后调用Blend(作者自己写的函数)锁定显示缓冲器,在返回地址直接访问显存.对显存进行自己的操作,看上去DirectDraw函数有点象插件的感觉,只要在合适的地方放入便可,当然在这点实现上在基类上提供了一个指向Kwindow的指针与CWnd实例指针的HWND相关联,在利用DD时,通过m_hwnd通过CreateSurface得到想要初始化的DD接口指针.在对显存操作时,也是调用Lock得到显存地址,然后对显存操作.
部分代码如下:
bool KDDrawWindow::CreateSurface(void)
{
HRESULT hr;
hr = DirectDrawCreate(NULL, &lpdd, NULL);//create an instance of DirectDraw object
//if succeeds return DD_OK
if (hr!=DD_OK)
return false;
hr = lpdd->SetCooperativeLevel(m_hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
if (hr!=DD_OK)
return false;
hr = lpdd->SetDisplayMode(640, 480, 32);
if (hr!=DD_OK)
return false;
DDSURFACEDESC ddsd;
memset(& ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
return lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL)==DD_OK;
}
在对PE文件的操作上,最主要的一步是调用WriteProcessMemory,当然之前要取到PE文件中要替换的函数的位置,不在此详细说了,例子给的很详细,先找DLL,然后再找到dll中的相关函数.得到替换位置.
在这章中还有一些小知识,如STRICT宏,得到整个屏幕时GetDC(NULL),PE文件的格式和组成,Window系统的基本知识在这章都介绍了不少,所以感觉还是很充实的一章,学到了不少知识,而且例子都举的很好,都是很实用,能让人有所收获和心得的程序.