代码实现如下
#include "stdafx.h" //对比数据,找到相同字节集的偏移 int GetInBuffer(const void *pStart, int nLen, const void *pFindBuffer, int nfLen) { for (int i = 0; i < nLen - nfLen; i++) { if (memcmp((void *)((ULONG)pStart + i), pFindBuffer, nfLen) == 0) { return i; } } return -1; } void ReadQQ(DWORD dwProcessId) { //由于QQ是使用Unicode字符集的,所以我们使用wchar_t类型 static wchar_t QQDATA[] = L"Msg2.0.db"; //MsgEx.db,好像以前有个版本的数据库文件是MsgEx.db,用MsgEx来当关键字检索速度会变慢。 //但是QQ2010的是用Msg2.0.db的。 //打开进程 HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, dwProcessId); int nMemLen = 28, nMemStart; void *pMemAddress = NULL; BYTE *bMemBuffer; MEMORY_BASIC_INFORMATION mbi; memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION)); wchar_t szQQnumber[15]; szQQnumber[0] = 0; //寻找进程空间 while (VirtualQueryEx(hProcess, pMemAddress, &mbi, nMemLen) != 0) { if (mbi.Type == MEM_PRIVATE && mbi.Protect == PAGE_READWRITE) { //分配足够的内存空间,存放数据 bMemBuffer = new BYTE[mbi.RegionSize + 1]; bMemBuffer[mbi.RegionSize] = 0; if (ReadProcessMemory(hProcess, pMemAddress, bMemBuffer, mbi.RegionSize, NULL)) { //尝试寻找当前内存空间中是否包含Msg2.0.db nMemStart = GetInBuffer(bMemBuffer, mbi.RegionSize, QQDATA, sizeof(QQDATA)); if (nMemStart != -1) { //向前推一定位置,因为路径是 ..\[QQ号]\Msg2.0.db wchar_t *pQQText = (wchar_t *)&bMemBuffer[nMemStart - 28]; wchar_t *pQQstart = wcsstr(pQQText, L"\\"); if (pQQstart) { pQQstart++; wchar_t *pQQEnd = wcsstr(pQQstart, L"\\"); if (pQQEnd) { lstrcpynW(szQQnumber, pQQstart, pQQEnd - pQQstart + 1); wprintf(L"%s\n", szQQnumber); } } delete[] bMemBuffer; break; } } //销毁刚刚分配的内存空间 delete[] bMemBuffer; } pMemAddress = (void *)((ULONG)pMemAddress + mbi.RegionSize); } CloseHandle(hProcess); } void FindQQ() { DWORD dwProcessId = 0; //进程快照~ HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); PROCESSENTRY32 pl; pl.dwSize=sizeof(PROCESSENTRY32); bool bmore=Process32First(Snapshot, &pl); while(bmore) { if(lstrcmpi(pl.szExeFile, _T("QQ.exe")) == 0) { //读取QQ号 ReadQQ(pl.th32ProcessID); //dwProcessId = pl.th32ProcessID; //循环,读取本地所有登录的QQ号。 //break; 跳出循环 } bmore= Process32Next(Snapshot, &pl); } CloseHandle(Snapshot); // return dwProcessId; } int _tmain(int argc, _TCHAR* argv[]) { FindQQ(); scanf("%*c"); return 0; }
子类继承外观类的所有属性方法,客户端只需要跟外观类进行交流,实现了对所有子类的封装。
没有使用外观类
如图:
应用外观类
如图:
代理模式
个人理解:
代理模式是将原类进行封装,客户端只需要与代理进行交流。代理就是原类的一个替身。简而言之就是用一个对象代表另外一个对象。强调的是个体。
使用中介者模式的场合
1.一组定义良好的对象,现在要进行复杂的通信。
2.定制一个分布在多个类中的行为,而又不想生成太多的子类。
可以看出,中介对象主要是用来封装行为的,行为的参与者就是那些对象,但是通过中介者,这些对象不用相互知道。
使用中介者模式的优点:
1.降低了系统对象之间的耦合性,使得对象易于独立的被复用。
2.提高系统的灵活性,使得系统易于扩展和维护。
使用中介者模式的缺点:
中介者模式的缺点是显而易见的,因为这个“中介“承担了较多的责任,所以一旦这个中介对象出现了问题,那么整个系统就会受到重大的影响。
三者的区别与联系
1,中介者模式:A,B之间的对话通过C来传达。A,B可以互相不认识(减少了A和B对象间的耦合)
2,代理模式:A要送B礼物,A,B互相不认识,那么A可以找C来帮它实现送礼物的愿望(封装了A对象)
3,外观模式:A和B都要实现送花,送巧克力的方法,那么我可以通过一个抽象类C实现送花送巧克力的方法(A和B都继承C)。(封装了A,B子类)
代理模式和外观者模式这两种模式主要不同就是代理模式针对的是单个对象,而外观模式针对的是所有子类。
模仿QtOpenGL例子VowelCube时遇到的三维和Qt绘图引擎QPainter混合问题
《C++GUI Programming with Qt 4, secondedition》这本书介绍了OpenGL三维绘图引擎和QPainter混合例子:VowelCube。让我暗自高兴,我也可以实现一个类似的功能吧?结果测试了晚上和一上午,才弄懂例子的原理。
书上介绍Qt的绘图引擎可以和OpenGL渲染器混合在一个绘图上下文(RenderContext)的,但是需要注意的是,如果使用了这样的混合,那么我们就需要注意正确地切换渲染上下文。虽然书上有了相关的介绍,但我觉得还是有些疏忽——稍微介绍一下就完了,我们还不知道如果不这么做会显示不了图形。
首先要明确一个问题。制作这样混合的程序究竟是使用便利的initializeGL()、resizeGL()、paintGL()函数还是使用QWidget基类的构造函数、paintEvent()函数和resizeEvent()函数?我实验了下,觉得混合着用是最好的。如果大家之前学过了用glut构建OpenGL程序的方式,那么我想你会同意我的。
在构造QGLWidget子类的时候,我的做法是在相关初始化的代码既可以写入构造函数中,又可以写入initializeGL()函数中。随后绘制的部分我认为既然是混合OpenGL和QPainter的应用程序,那么一定要使用paintEvent()函数。因为如果使用paintGL()函数,那么只能绘制OpenGL图形了不是吗。而需要重绘的时候,既可以使用resizeGL()也可以重写resizeEvent(),取决你的需求,但是按照glut的思维,还是重写resizeGL()比较好。不过相信大家的实力还是自己可以写一个resizeGL()函数出来的。