snippet
大约 3 分钟cpp
获取窗口句柄
// 根据窗口标题获取窗口句柄
HWND caclhWnd = FindWindowA(NULL, "计算器");
// 通过窗口类获取窗口句柄,要通过 spy++ 获取窗口类
HWND caclhWnd = FindWindowA("CalcFrame", NULL);
制作链表
下面代码缓冲区 pServStatus 中保存请求得到的系统服务对象集合,最后通过 for 循环制作链表,并在之后释放缓冲区
CServItem *CServConfig::EnumServList()
{
SC_HANDLE hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
return NULL;
}
DWORD dwBytesNeeded = 0, dwRealBytes = 0, dwCount = 0, hResume = 0;// 返回的服务列表需要的存储空间的字节数量,服务的个数
/*
第一次调用本函数设置第四个参数、第五个参数依次为NULL,0。是为了通过第7,8个参数先取得返回数据需要的长度和数量
之后第二次调用本函数则为第四个参数、第五个参数传入精确的值最终获取准确的返回数据
第四个参数NULL:原本应该传入一个缓冲区地址,用于接收 EnumServicesStatus 返回的数据,这里传入NULL是为了通过第7,8个参数先取得返回数据需要的长度和数量
第五个参数0: 缓冲区长度,设置0是为了通过第7,8个参数先取得返回数据需要的长度和数量
*/
ENUM_SERVICE_STATUS *pServStatus = NULL;// 枚举得到的系统服务都保存该指针指向的内存区域
BOOL bRet = EnumServicesStatus(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded, &dwCount, &hResume);
if (!bRet && GetLastError() == ERROR_MORE_DATA) {
dwRealBytes = dwBytesNeeded;
pServStatus = new ENUM_SERVICE_STATUS[dwRealBytes + 1];// 因为结尾会多出一个 \0,类似字符串的结尾,所以长度多出一个字节
ZeroMemory(pServStatus, dwRealBytes + 1);// 用0填充一块内存区域,初始化内存块
// 再次调用EnumServicesStatus时使用前面初始化好的缓冲区指针以及缓冲区的长度填充4,5参数位置
bRet = EnumServicesStatus(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, pServStatus, dwRealBytes, &dwBytesNeeded, &dwCount, &hResume);
if (!bRet) {// 没有成功获取到服务则要关闭服务管理器句柄,然后返回给用户
CloseServiceHandle(hSCM);
return NULL;
}
}
else {
CloseServiceHandle(hSCM);
return NULL;
}
// 把枚举得到的系统服务构建成为链表
// 下面3个变量依次是:前一个元素的指针,后一个元素的指针,头元素的指针
CServItem *pServPre = NULL, *pServNext = NULL, *pServHeader = NULL;
pServPre = pServNext;
for (DWORD dwIdx = 0; dwIdx < dwCount; dwIdx++)
{
pServNext = new CServItem();
pServNext->m_strServName = pServStatus[dwIdx].lpServiceName;
pServNext->m_strServDispName = pServStatus[dwIdx].lpDisplayName;
pServNext->m_dwServStatus = pServStatus[dwIdx].ServiceStatus.dwCurrentState;
pServNext->m_pNext = NULL;
if (pServHeader == NULL) pServHeader = pServNext;
if (pServPre == NULL) pServPre = pServNext;
else pServPre->m_pNext = pServNext;
pServPre = pServNext;
// 上面3行代码也可以写作如下
// (pServPre == NULL) ? (pServPre = pServNext) : (pServPre->m_pNext = pServNext, pServPre = pServNext);
}
// 释放申请的内存区域(保存系统服务数据的内存区域),并返回链表的头元素
delete [] pServStatus;
return pServHeader;
}
printf
十进制、十六进制
printf("调用技能传入参数:\r\n十进制:a:%d,b:%d\r\n十六进制:a:%X,b:%X\r\n",a,b,a,b);
cout

to_string
#include<sstream>
using namespace std;
// 类 Addr 的成员属性 addr 的数据类型是 UINT_PTR
string Addr::toString() {
return std::to_string(addr);
}
打印函数地址
变量地址压入栈
通过 lea 取地址保存到寄存器,然后将寄存器中的数据压入栈,即实现将变量的地址压入栈
const char* role="player";
__asm {
lea eax, role
push eax
}
寄存器数据赋值变量
采用外平栈的方法,只有一个参数(长度是4字节),下面代码是将执行函数后的返回值(默认填充到 eax 中)赋值到 c++ 变量中
UINT_PTR retVal=0;
__asm {
call 函数地址
add esp,4
mov retVal, eax
}
线程
取当前线程ID
DWORD currentThreadID=GetCurrentThreadId();
创建线程
下面调用的第四个参数 自定义逻辑 是回调函数,需要在前面先定义好
::CreateRemoteThread(当前进程句柄,0,0,自定义逻辑,0,0,0);
硬件相关
主板蜂鸣声
MessageBeep(1);
