API Hook

ApiHook又叫做API劫持,也就是如果A程序调用了B.cll里面的C函数,我们可以做到当A调用C函数执行的时候,直接执行我们自己事先准备好的函数,之后我们在执行真正的C,当然我们可以不执行C或者更改C的参数等等,实现的核心思路就是:

mov eax, pNewAddr[/size][size=3] jmp eax

解释下具体原理:我们首先获取要劫持函数的地址,然后我们在自己组装一个数据结构,数据结构的内容是 执行汇编:把新函数地址拷到寄存器里,然后再jmp到新函数地址位置执行新函数,然后我们把自己组装这个数据结构拷贝到之前获取的需要劫持的函数地址指向的内存的位置,这样当我们再次调用该函数的时候,程序走到函数地址处发现是执行我们刚刚写好的汇编命令,直接jmp到了我们自己定义的函数地址的位置,也就相当于直接运行了我们自己写好的函数地址了,当然自己写的函数必须要和原函数参数和返回值一样,自己写的函数里面也可以调用原函数(达到过滤的目的),但是前提是调用之前要先关闭劫持,也就是把我们替换的内容给人家替换回去,执行完之后再次替换我们的地址,如果不替换回去我们就会进入无限递归了这个不解释,当然我们也可以修改参数什么的,给调用者进行一个“加工”。还有就是刚开始看的时候有一个地方不理解就是:DLL注入能成功的原理是,某些系统DLL里面的函数所有程序调用都会执行同一个地址,而APIHook中有一步是更改函数地址,但是如果我们更改了某些公用的函数地址,那么并不会影响其他的程序继续调用,这个地方小纠结了一会,后来弄清楚了,A加载了系统B.DLL获取里面的API函数C, A2也同样加载并且获取了里面的API函数C2,C和C2是相等的(当然并不是所有都相等),但是我们在A程序里进行C函数的Hook,并没有影响A2的调用,原因是他们只是指向同一个地址不是就是同一个地址,可以理解成是中间有过度变量。我们修改的只是自己内存那部分”本分而已”,这样的话,我们想要Hook某个继承的某些API的话通常可以采取DLL注入的方式,DLL注入之前我总结过并且上传过相关的实现代码。这里不解释。然后就是在网上找到了一个写的不错的APIHook的代码,分享下(注意,下面代码是方便理解的,可以通过代码好好理解,但是实际开发不要用下面的代码,因为下面没考虑64位等其他问题,我平时开发常用的一个比较稳定的代码我上传在:http://download.csdn.net/detail/u013761036/9603063):

AdHookApi.h
#ifndef __ADHOOKAPI_H__
#define __ADHOOKAPI_H__
#include <windows.h>
#include <tchar.h>
#include <vector>
using namespace std;// class CAdAutoHookApi
class CAdHookApi;
class CAdAutoHookApi
{
public:CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr);virtual ~CAdAutoHookApi();private:CAdHookApi *m_pHookApi;void       *m_pAddr;
};// class CAdAutoHook
class CAdHookApi
{
public:CAdHookApi();virtual ~CAdHookApi();protected:struct HookMap{HANDLE hProcess;void  *pOldAddr;void  *pNewAddr;BYTE   chOldCode[8];BYTE   chNewCode[8];BOOL   bHooked;DWORD  dwData;};
public:HANDLE Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData = 0);HANDLE Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData = NULL, DWORD verifySize = 0, DWORD dwData = 0);BOOL   Remove(HANDLE hHook);BOOL   Begin(HANDLE hHook);BOOL   End(HANDLE hHook);BOOL   Begin2(void *pNewAddr);BOOL   End2(void *pNewAddr);int    BeginAll();int    EndAll();int    GetCount();void  *OldAddr2NewAddr(void *pOldAddr);void  *NewAddr2OldAddr(void *pNewAddr);public:static BOOL VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize);static BOOL PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode, const BYTE *verifyData = NULL, DWORD verifySize = 0);protected:CAdHookApi::HookMap *FromNewAddr(void *pNewAddr);CAdHookApi::HookMap *FromOldAddr(void *pOldAddr);BOOL HasHook(HANDLE hHook);protected:vector<HookMap *> m_obHooks;
};#endif // __ADHOOKAPI_H__AdHookApi.cpp//#include "stdafx.h"
#include "AdHookApi.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <Windows.h>
#include "Common.h"static BOOL gUseAPI = TRUE;static BOOL WINAPI myReadMemory(HANDLE hProcess, LPVOID lpAddress, LPVOID lpBuffer, SIZE_T nSize)
{BOOL bRet = FALSE;DWORD dwOldProtect = 0;bRet = VirtualProtect(lpAddress, nSize, PAGE_READONLY, &dwOldProtect);if(gUseAPI){DWORD dwRead = 0;bRet = ReadProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwRead);}else{memcpy(lpBuffer, lpAddress, nSize);}VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);assert(bRet);return bRet;
}static BOOL WINAPI myWriteMemory(HANDLE hProcess, LPVOID lpAddress, LPCVOID lpBuffer, SIZE_T nSize)
{BOOL bRet = FALSE;DWORD dwOldProtect = 0;bRet = VirtualProtect(lpAddress, nSize, PAGE_READWRITE, &dwOldProtect);if(gUseAPI){DWORD dwWrite = 0;bRet = WriteProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwWrite);}else{memcpy(lpAddress, lpBuffer, nSize);}VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);assert(bRet);return bRet;
}// class CAdAutoHookApi
CAdAutoHookApi::CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr)
{m_pHookApi = pHookApi;m_pAddr    = pAddr;assert(m_pHookApi != NULL);if(m_pHookApi != NULL){m_pHookApi->End2(m_pAddr);}
}CAdAutoHookApi::~CAdAutoHookApi()
{if(m_pHookApi != NULL){m_pHookApi->Begin2(m_pAddr);}
}// class CAdHookApi
CAdHookApi::CAdHookApi()
{
}CAdHookApi::~CAdHookApi()
{EndAll();
}BOOL CAdHookApi::VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize)
{BOOL isPassed = FALSE;if((verifyData != NULL) && (verifySize > 0)){BYTE *addrData = new BYTE[verifySize];if(myReadMemory(GetCurrentProcess(), pAddr, addrData, verifySize)){if(memcmp(addrData, verifyData, verifySize) == 0){isPassed = TRUE;}}delete []addrData;}else{isPassed = TRUE;}return isPassed;
}BOOL CAdHookApi::PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode, const BYTE *verifyData, DWORD verifySize)
{if(!VerifyAddress(pAddr, verifyData, verifySize)){return FALSE;}BOOL bRet = myWriteMemory(GetCurrentProcess(), pAddr, pCode, dwCode);return bRet;
}HANDLE CAdHookApi::Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData)
{HMODULE hModule = LoadLibrary(lpszModule);if(hModule == NULL){return NULL;}void *pOldAddr = (void *)GetProcAddress(hModule, lpcFuncName);if(pOldAddr == NULL){return NULL;}return Add(pOldAddr, pNewAddr, NULL, 0, dwData);
}HANDLE CAdHookApi::Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData, DWORD verifySize, DWORD dwData)
{BOOL bRet = FALSE;HookMap *pHook = new HookMap;do{ZeroMemory(pHook, sizeof(HookMap));pHook->hProcess = GetCurrentProcess();pHook->pOldAddr = pOldAddr;if(pHook->pOldAddr == NULL){break ;}DWORD dwRead = 8;if((verifyData != NULL) && (verifySize > 0) && (verifySize > dwRead)){dwRead = verifySize;}BYTE *addrData = new BYTE[dwRead];if(!myReadMemory(pHook->hProcess, pHook->pOldAddr, addrData, dwRead)){delete []addrData;break ;}if((verifyData != NULL) && (verifySize > 0) && (memcmp(addrData, verifyData, verifySize) != 0)){delete []addrData;break ;}memcpy(pHook->chOldCode, addrData, 8);delete []addrData;DWORD dwTemp = (DWORD)pNewAddr;pHook->pNewAddr = pNewAddr;// mov eax, pNewAddr// jmp eaxpHook->chNewCode[0] = 0xB8;memcpy(pHook->chNewCode + 1, &dwTemp, sizeof(DWORD));pHook->chNewCode[5] = 0xFF;pHook->chNewCode[6] = 0xE0;           pHook->bHooked = FALSE;pHook->dwData = dwData;m_obHooks.push_back(pHook);bRet = TRUE;}while(0);if(!bRet){delete pHook;pHook = NULL;}return (HANDLE)pHook;
}BOOL CAdHookApi::Remove(HANDLE hHook)
{BOOL bRet = FALSE;HookMap *pHook = (HookMap *)hHook;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp == pHook){End((HANDLE)pTemp);delete pHook;m_obHooks.erase(m_obHooks.begin() + i);bRet = TRUE;break ;}}return bRet;
}BOOL CAdHookApi::Begin(HANDLE hHook)
{if(!HasHook(hHook)){return FALSE;}HookMap *pHook = (HookMap *)hHook;if(pHook->bHooked){return TRUE;}DWORD dwWrite = 8;    BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chNewCode, dwWrite);if(bRet){pHook->bHooked = TRUE;}return bRet;
}BOOL CAdHookApi::End(HANDLE hHook)
{if(!HasHook(hHook)){return FALSE;}HookMap *pHook = (HookMap *)hHook;if(!pHook->bHooked){return FALSE;}DWORD dwWrite = 8;BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chOldCode, dwWrite);if(bRet){pHook->bHooked = FALSE;}return bRet;
}BOOL CAdHookApi::Begin2(void *pNewAddr)
{HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return FALSE;}return Begin((HANDLE)pHook);
}BOOL CAdHookApi::End2(void *pNewAddr)
{HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return FALSE;}return End((HANDLE)pHook);
}void *CAdHookApi::OldAddr2NewAddr(void *pOldAddr)
{HookMap *pHook = FromOldAddr(pOldAddr);if(pHook == NULL){return NULL;}return pHook->pNewAddr;
}void *CAdHookApi::NewAddr2OldAddr(void *pNewAddr)
{HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return NULL;}return pHook->pOldAddr;
}CAdHookApi::HookMap *CAdHookApi::FromNewAddr(void *pNewAddr)
{HookMap *pHook = NULL;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp->pNewAddr == pNewAddr){pHook = pTemp;break ;}}return pHook;
}CAdHookApi::HookMap *CAdHookApi::FromOldAddr(void *pOldAddr)
{HookMap *pHook = NULL;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp->pOldAddr == pOldAddr){pHook = pTemp;break ;}}return pHook;
}BOOL CAdHookApi::HasHook(HANDLE hHook)
{BOOL bRet = FALSE;HookMap *pHook = (HookMap *)hHook;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp == pHook){bRet = TRUE;break ;}}return bRet;
}int CAdHookApi::BeginAll()
{int nRet = 0;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];BOOL bRet = Begin((HANDLE)pTemp);if(bRet){nRet ++;}}return nRet;
}int CAdHookApi::EndAll()
{int nRet = 0;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];BOOL bRet = End((HANDLE)pTemp);delete pTemp;if(bRet){nRet ++;}}m_obHooks.clear();return nRet;
}int CAdHookApi::GetCount()
{return (int)m_obHooks.size();
}User1 自己注入自己(测试用)
#include "stdafx.h"
#include "AdHookApi.h"
#include <windows.h>
using namespace std;static CAdHookApi AdHookApi;int WINAPI mYMessageBoxW( __in_opt HWND hWnd, __in_opt LPCWSTR lpText, __in_opt LPCWSTR lpCaption, __in UINT uType)
{//如果是做过滤,记得先关闭掉当前的劫持,然后调用原API(给调用者看,当然这个地方也可以进行参数修改),//然后再改成劫持的地址 也就是 end(a) do happythings begin(a)MessageBoxA(NULL ,"B" ,"B" ,MB_OK);return 0;
}int main()
{AdHookApi.Add(_T("User32.dll") ,"MessageBoxW" ,mYMessageBoxW);::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);AdHookApi.BeginAll();::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);AdHookApi.EndAll();::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);return 0;
}User2 DLL
#include "stdafx.h"
#include "ApiDebugger.h"
#include "AdHookApi.h"
#include <tlhelp32.h>
#include <wincrypt.h>
#include "Common.h"static const char *   gCopyright = "ApiDebugger by CodeLive, email : dongfa@yeah.net";
static CAdHookApi     gHooks;bool gEnableLogOutput = true;extern "C" APIDEBUGGER const char * ApiDebugger()
{return gCopyright;
}///BOOL WINAPI my_IsDebuggerPresent(VOID)
{return FALSE;
}int WINAPI my_CompareStringW(LCID Locale, DWORD dwCmpFlags, PCNZWCH lpString1, int cchCount1, PCNZWCH lpString2,int cchCount2)
{CAdAutoHookApi autoHook(&gHooks, my_CompareStringW);logOutput(formatString("ApiDebugger - CompareStringW.\r\n"));int ret = CompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2);logOutput(formatString("ApiDebugger - CompareStringW(%S, %S).\r\n", lpString1, lpString2));return ret;
}BOOL WINAPI my_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR szContainer, LPCWSTR szProvider, DWORD dwProvType, DWORD dwFlags)
{CAdAutoHookApi autoHook(&gHooks, my_CryptAcquireContextW);BOOL ret = CryptAcquireContextW(phProv, szContainer, szProvider, dwProvType, dwFlags);logOutput(formatString("ApiDebugger - CryptAcquireContextW(0x%08X, %S, %S, 0x%08X, 0x%08X) : %S.\r\n",(int)(*phProv),(szContainer != NULL) ? szContainer : L"NULL",(szProvider != NULL) ? szProvider : L"NULL",dwProvType, dwFlags,ret ? L"TRUE" : L"FALSE"));return ret;
}BOOL WINAPI my_CryptImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey,DWORD dwFlags, HCRYPTKEY *phKey)
{CAdAutoHookApi autoHook(&gHooks, my_CryptImportKey);BOOL ret = CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);string hexData = toHexString((const char *)pbData, dwDataLen);logOutput(formatString("ApiDebugger - CryptImportKey(0x%08X, %s, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",(int)hProv, hexData.c_str(), (int)hPubKey, dwFlags, (int)(*phKey), ret ? L"TRUE" : L"FALSE"));return ret;
}BOOL WINAPI my_CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash)
{CAdAutoHookApi autoHook(&gHooks, my_CryptCreateHash);BOOL ret = CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);logOutput(formatString("ApiDebugger - CryptCreateHash(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",(int)hProv, (int)Algid, (int)hKey, dwFlags, (int)phHash,ret ? L"TRUE" : L"FALSE"));return ret;
}BOOL WINAPI my_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
{CAdAutoHookApi autoHook(&gHooks, my_CryptHashData);BOOL ret = CryptHashData(hHash, pbData, dwDataLen, dwFlags);string hexData = toHexString((const char *)pbData, dwDataLen);logOutput(formatString("ApiDebugger - CryptHashData(0x%08X, %s, 0x%08X) : %S.\r\n",(int)hHash, hexData.c_str(), dwFlags,ret ? L"TRUE" : L"FALSE"));return ret;
}BOOL WINAPI my_CryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey)
{CAdAutoHookApi autoHook(&gHooks, my_CryptDeriveKey);BOOL ret = CryptDeriveKey(hProv, Algid, hBaseData, dwFlags, phKey);logOutput(formatString("ApiDebugger - CryptDeriveKey(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",(int)hProv, (int)Algid, (int)hBaseData, dwFlags, (int)phKey,ret ? L"TRUE" : L"FALSE"));return ret;
}BOOL WINAPI my_CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags,BYTE *pbData, DWORD *pdwDataLen)
{CAdAutoHookApi autoHook(&gHooks, my_CryptDecrypt);string hexData1 = toHexString((const char *)pbData, *pdwDataLen);writeDataToFile("CryptDec_IN.bin", pbData, *pdwDataLen);BOOL ret = CryptDecrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen);string hexData2 = toHexString((const char *)pbData, *pdwDataLen);writeDataToFile("CryptDec_OUT.bin", pbData, *pdwDataLen);logOutput(formatString("ApiDebugger - CryptDecrypt(0x%08X, 0x%08X, %S, 0x%08X, %s=>%s) : %S.\r\n",(int)hKey, (int)hHash, Final ? L"TRUE" : L"FALSE",dwFlags, hexData1.c_str(), hexData2.c_str(), ret ? L"TRUE" : L"FALSE"));return ret;
}typedef int (__cdecl *sub_4026B0_func)(BYTE *pbData);// 004026B0 ;
static int my_sub_4026B0(BYTE *pbData)
{CAdAutoHookApi autoHook(&gHooks, my_sub_4026B0);sub_4026B0_func sub_4026B0 = (sub_4026B0_func)(0x004026B0);string hexData1 = toHexString((const char *)pbData, strlen((const char *)pbData));int ret = sub_4026B0(pbData);string hexData2 = toHexString((const char *)pbData, strlen((const char *)pbData));logOutput(formatString("ApiDebugger - sub_4026B0(%s=>%s)",hexData1.c_str(), hexData2.c_str()));return ret;
}///void ApiDebugferShutdown()
{gHooks.EndAll();logOutput("ApiDebugger Shutdown.\r\n");
}BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:{
//            gHooks.Add(_T("KERNEL32.DLL"),      "IsDebuggerPresent",        my_IsDebuggerPresent);
//            gHooks.Add(_T("KERNEL32.DLL"),      "CompareStringW",           my_CompareStringW);gHooks.Add(_T("ADVAPI32.DLL"),      "CryptAcquireContextW",     my_CryptAcquireContextW);gHooks.Add(_T("ADVAPI32.DLL"),      "CryptImportKey",           my_CryptImportKey);gHooks.Add(_T("ADVAPI32.DLL"),      "CryptCreateHash",          my_CryptCreateHash);gHooks.Add(_T("ADVAPI32.DLL"),      "CryptHashData",            my_CryptHashData);gHooks.Add(_T("ADVAPI32.DLL"),      "CryptDeriveKey",           my_CryptDeriveKey);gHooks.Add(_T("ADVAPI32.DLL"),      "CryptDecrypt",             my_CryptDecrypt);
/*const BYTE verifyData[] = { 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0x2C, 0x01, 0x00, 0x00 };void *addr = (void *)0x004026B0;if(gHooks.Add(addr, my_sub_4026B0, verifyData, sizeof(verifyData), 0) != NULL){logOutput(formatString("ApiDebugger - hook sub_4026B0 ok.\r\n"));}else{logOutput(formatString("ApiDebugger - hook sub_4026B0 failed.\r\n"));}
*/gHooks.BeginAll();logOutput(formatString("ApiDebugger - %s.\r\n", gCopyright));logOutput("ApiDebugger Loaded.\r\n");}break ;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:{}break ;case DLL_PROCESS_DETACH:{ApiDebugferShutdown();logOutput("ApiDebugger Unloaded.\r\n");}break;}return TRUE;
}

windows-API劫持(API-HOOK)相关推荐

  1. Windows平台基于API Hook技术的WinInet网络库HttpDNS实现方案

    一.项目背景 学而思网校直播课堂在线安装程序,是一个独立的应用程序,提供学生端的安装功能,为了减少安装包体积,避免引入第三方网络库,使用的是操作系统的WinInet网络库.为了更好的优化网络,提高网络 ...

  2. Windows核心编程 - API HOOK应用

    #Windows核心编程 - API HOOK应用 如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 目录 文章目录 #Windows核 ...

  3. Hook技术之API拦截(API Hook)

    一.关于API Hook API Hook可以通过Hook指定的消息和API来实现进程隐藏,文件隐藏,端口隐藏等. 通过拦截进程API来隐藏进程,通过拦截文件读写API来隐藏文件,通过拦截网络相关AP ...

  4. HOOK API入门之Hook

    HOOK API入门之Hook自己程序的MessageBoxW http://blog.csdn.net/friendan/article/details/12222651 HOOK所有程序的Mess ...

  5. Windows 8 动手实验系列教程 实验8:Windows应用商店API

    动手实验 实验 8: Windows应用商店API 2012年9月 简介 编写Windows应用商店应用最令人瞩目的理由之一是您可以方便地将它们发布到Windows应用商店.考虑到世界范围内目前有超过 ...

  6. Windows CE Notification API的使用方法

    1 引言      以Windows CE 为操作系统的掌上电脑(如PocketPC或HPC),除具备PC的功能外,还具备很强的自身控制能力.Windows CE API超越微软其他操作系统的 API ...

  7. Windows Mobile Sensors API库的设计

    背景 热烈欢迎 simon_new88 同学加入 Mobile Sensors API - Native unified APIs for Windows Mobile Sensors 项目.为了他更 ...

  8. C语言基础入门48篇_18_使用循环移动游戏人物(屏幕符号运动、while(1){}进行实时响应,if(表达式){},switch(表达式){},windows的API及API进行自行封装使)

    本篇介绍使用循环语句实现指定符号的坐标移动,使用到了while(1){}进行实时响应,if(表达式){},switch(表达式){},windows中封装的API并对API进行自行封装使用. 1.实现 ...

  9. windows剪切板api

    Windows 剪切板API详解 (一) ChangeClipboardChain  将剪贴的连接从一个句柄转到下一个句柄.  BOOL ChangeClipboardChain(  HWND hWn ...

  10. Go 调用 Windows 的系统 API,检测是否锁屏

    Go 调用 Windows 的系统 API,检测是否锁屏 因为应用需要根据当前电脑是否处于活跃状态来执行不同的动作,所以需要获取电脑当前活跃的窗口判断是否处于锁屏 可以通过调用Windows 的库来执 ...

最新文章

  1. 网络配置文件、命令详解
  2. 到底什么是故事点(Story Point)?
  3. 华为harmonyos 2.0,华为王成录博士:HarmonyOS 2.0给消费者不一样的体验
  4. 两大思维,就可以让你轻松完成任意一个目标
  5. [转]2020年4月github上最热门项目-python
  6. redis集群出现JedisNoReachableClusterNodeException异常(No reachable node in cluster)
  7. 单向流动的拓扑结构_只允许数据在传输介质中单向流动的拓扑结构是
  8. C# socket编程TcpClient与TcpListener UdpClient
  9. 2022 年您必须关注的 8 个python数据科学神器
  10. win10专业版激活方法——亲测可行!!!
  11. C++扑克牌随机洗牌抽牌算法
  12. 【MFC】解决窗口大小改变之后,ComboBox当前选项文字出现蓝色背景
  13. 一周上手flutter
  14. 移动办公模式下的业务 微易聊微信管理系统作用显著!
  15. [2015 Springer] Local Image Descriptor: Modern Approaches——3 Intensity Order-Based Local Descriptors
  16. 生产系统功能目标和组织结构
  17. 如何防御网站被ddos攻击 首先要了解什么是流量攻击
  18. ZOJ 3898 Stean 矩形法求积分
  19. python pyecharts用法_pyecharts的简单使用
  20. 战队口号霸气押韵8字_校园运动会加油霸气押韵口号文案 2020最有特色的运动会口号...

热门文章

  1. higtech软件的使用
  2. Python批量下载中国大学MOOC课件
  3. CAPL学习之路-DoIP相关函数
  4. 屏幕录制生成gif文件神器和相关操作 GifCam
  5. Matlab | matpower5.0:最优潮流执行步骤及修改教程
  6. CentOS 安装SVN以及可视化管理工具iF.SVNAdmin
  7. 贝叶斯网络模型基础——R语言
  8. 【android】关于android10-11存储的一些知识
  9. 蓝桥基础练习 杨辉三角形 JAVA
  10. 关于高校房产管理系统中主要管理模块都有哪些