WindowsAPI编程核心技术-基础扫盲 预备知识 常见参数说明符前缀:
1 2 3 4 5 6 7 8 9 10 11 12 b BOOL 布尔值 g_ Global 全局的 h Handle 句柄 hwnd HWND类型 i Integer 整数 l Long 长整数 lp Long-pointer 长指针 n Short-int 短整型 p Pointer 指针 sz Zero-terminated-String 以0结尾的字符串 u Unsigned-int 无符号整数 w WORD 无符号短整数
常用参数类型:
1 2 3 4 5 6 7 8 9 10 11 HWND 窗口句柄 HINSTANCE 实例句柄 HANDLE 句柄 INT_PTR 约等于int LPARAM 不好说,一般传地址 LPSTR 字符串指针 LPTSTR 定义了_T宏的同上 LPCTSTR 常量,同上 UINT 32位无符号整型 VOID 等于void WPARAM 不好说,一般传各种参数
常用宏定义:
1 2 3 4 WINAPI/APIENTRY/CALLBACK __stdcall _In_ 输入参数,不会改变其值 _In_opt_ 可选的输入参数,不会改变其值 _Out_ 不关心本身内容,写入数据
控制台程序写法:
1 2 3 4 5 6 #include <iostream> #include <windows.h> #include <tchar.h> INT _tmain(INT argc,PTCHAR argv[]){ return 0 ; };
Windows窗口程序写法:
1 2 3 4 #include <windows.h> INT_PTR WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevinstance, LPSTR lpCmdLine, INT nCmdShow) { return 0 ; };
API后缀:
1 2 3 4 A 使用ANSI编码作为标准输入输出流 W 使用Unicode作为编码 Ex 拓展一些参数之类的 ExA ExW 略
基础技术 运行单一实例 CreateMutex 1 2 3 4 5 6 7 8 HANDLE WINAPI CreateMutex ( _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, _In_ BOOL bInitialOwner, _In_opt_ LPCTSTR lpName )
例子 1 2 3 4 5 6 7 8 BOOL IsAlreadyRun (VOID) { HANDLE hMutex = NULL ; hMutex = ::CreateMutex (NULL , FALSE, L"TEST" ); if (hMutex) if (ERROR_ALREADY_EXISTS == ::GetLastError ()) return TRUE; return FALSE; };
DLL延时加载 工程属性->配置属性->链接器->输入->延迟加载的DLL。
资源释放 从解决方案资源管理器中直接导入即可。
FindResource 确定指定类型和名称的资源所在位置。
1 2 3 4 5 6 7 8 HRSRC FindResource ( _In_ HMODULE hModule, _In_ LPCWSTR lpName, _In_ LPCWSTR lpType )
SizeofResource 获取指定资源的字节数。
1 2 3 4 5 6 DWORD SizeofResource ( _In_ HMODULE hModule, _In_ HRSRC hResInfo )
LoadResource 装载指定资源到全局存储器。
1 2 3 4 5 6 HGLOBAL LoadResource ( _In_ HMODULE hModule, _In_ HRSRC hResInfo )
LockResource 锁定资源并得到资源在内存中第一个字节的指针,防止其他程序访问。
1 2 3 4 LPVOID LockResource ( _In_ hResData )
例子 新版SDK在FindResource
的参数_In_ LPCWSTR lpType
不能由PCHAR
转换而来,可以用`PWCHAR*传参。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <cstdio> BOOL FreeMyResource (UINT uiResourceName, PWCHAR lpszResourceType, PCHAR lpszSaveFileName) { HRSRC hRsrc = ::FindResource (NULL , MAKEINTRESOURCE (uiResourceName), lpszResourceType); if (NULL == hRsrc) return FALSE; DWORD dwSize = ::SizeofResource (NULL , hRsrc); if (0 >= dwSize) return FALSE; HGLOBAL hGlobal = ::LoadResource (NULL , hRsrc); if (NULL == hGlobal) return FALSE; LPVOID lpVoid = ::LockResource (hGlobal); if (NULL == lpVoid) return FALSE; PFILE fp = NULL ; fopen_s (&fp, lpszSaveFileName, "wb+" ); if (NULL == fp) return FALSE; fwrite (lpVoid, sizeof (char ), dwSize, fp); fclose (fp); return TRUE; }; int main (int argc,char * argv[]) { return 0 ; };
服务 服务程序编写 服务程序在Vista之后进入Session 0运行,所以普通的对话框UI在Session 0看不到,这里用WTSSendMessage
搞一个对话框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <Windows.h> #include <WtsApi32.h> #include <tchar.h> #pragma comment(lib, "WtsApi32.lib" ) WCHAR g_szServiceName[MAX_PATH] = TEXT ("MyServiceTest" ); SERVICE_STATUS g_ServiceStatus = { 0 }; SERVICE_STATUS_HANDLE g_ServiceStatusHandle = { 0 }; VOID APIENTRY ServiceCtrlHandle (DWORD dwOperateCode) { switch (dwOperateCode) { case SERVICE_CONTROL_PAUSE: { g_ServiceStatus.dwCurrentState = SERVICE_PAUSED; break ; }; case SERVICE_CONTROL_CONTINUE: { g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; break ; }; case SERVICE_CONTROL_STOP: { g_ServiceStatus.dwWin32ExitCode = 0 ; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwCheckPoint = 0 ; g_ServiceStatus.dwWaitHint = 0 ; ::SetServiceStatus (g_ServiceStatusHandle, &g_ServiceStatus); break ; }; case SERVICE_CONTROL_INTERROGATE: break ; default : break ; }; return ; }; VOID APIENTRY ServiceMain (DWORD dwArgc, PCHAR lpszArgv) { g_ServiceStatus.dwServiceType = SERVICE_WIN32; g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; g_ServiceStatus.dwWin32ExitCode = 0 ; g_ServiceStatus.dwServiceSpecificExitCode = 0 ; g_ServiceStatus.dwCheckPoint = 0 ; g_ServiceStatus.dwWaitHint = 0 ; g_ServiceStatusHandle = ::RegisterServiceCtrlHandler (g_szServiceName, ServiceCtrlHandle); g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; g_ServiceStatus.dwCheckPoint = 0 ; g_ServiceStatus.dwWaitHint = 0 ; ::SetServiceStatus (g_ServiceStatusHandle, &g_ServiceStatus); TCHAR szTitle[] = TEXT ("ttestabc" ); TCHAR szContent[] = TEXT ("ttestabc" ); DWORD dwResponse = 0 ; DWORD dwSessionId = ::WTSGetActiveConsoleSessionId (); ::WTSSendMessage (WTS_CURRENT_SERVER_HANDLE, dwSessionId, szTitle, ::lstrlen (szTitle) << 1 , szContent, ::lstrlen (szContent) << 1 , 0 , 0 , &dwResponse, FALSE); return ; }; int _tmain(_In_ DWORD argc, _In_ PTCHAR argv[]) { UNREFERENCED_PARAMETER (argc); UNREFERENCED_PARAMETER (argv); SERVICE_TABLE_ENTRY stDispatchTable[] = { {g_szServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},{NULL ,NULL } }; ::StartServiceCtrlDispatcher (stDispatchTable); return 0 ; };
服务控制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include <Windows.h> #include <cstdio> #include <tchar.h> #include <Shlwapi.h> #pragma comment(lib,"shlwapi.lib" ) BOOL SystemServiceOperate (PWCHAR lpszExePath, DWORD iOperateType) { BOOL bRet = TRUE; WCHAR szName[MAX_PATH] = { 0 }; ::lstrcpyA ((LPSTR)szName, (LPSTR)lpszExePath); ::PathStripPath (szName); SC_HANDLE shOSCM = NULL , shCS = NULL ; SERVICE_STATUS ss = { 0 }; DWORD dwErrorCode = 0 ; BOOL bSuccess = FALSE; shOSCM = ::OpenSCManager (NULL , NULL , SC_MANAGER_ALL_ACCESS); if (!shOSCM) return FALSE; if (0 != iOperateType) shCS = ::OpenService (shOSCM, szName, SERVICE_ALL_ACCESS); switch (iOperateType) { case 0 : { shCS = ::CreateService (shOSCM, szName, szName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, lpszExePath, NULL , NULL , NULL , NULL , NULL ); if (!shCS) bRet = FALSE; break ; }; case 1 : { if (!::StartService (shCS, 0 , NULL )) bRet = FALSE; break ; }; case 2 : { if (!::DeleteService (shCS)) bRet = FALSE; break ; }; default : break ; }; if (shCS) { ::CloseServiceHandle (shCS); shCS = NULL ; }; if (shOSCM) { ::CloseServiceHandle (shOSCM); shOSCM = NULL ; }; return bRet; }; int _tmain(_In_ DWORD argc, _In_ PTCHAR argv[]) { UNREFERENCED_PARAMETER (argc); UNREFERENCED_PARAMETER (argv); BOOL bRet = FALSE; WCHAR szExePath[] = TEXT ("D:\\tmp.exe" ); bRet = SystemServiceOperate (szExePath, 0 ); if (bRet) printf ("INSTALL OK\n" ); else printf ("INSTALL FAIL\n" ); bRet = SystemServiceOperate (szExePath, 1 ); if (bRet) printf ("START OK\n" ); else printf ("START FAIL\n" ); bRet = SystemServiceOperate (szExePath, 2 ); if (bRet) printf ("STOP OK\n" ); else printf ("STOP FAIL\n" ); bRet = SystemServiceOperate (szExePath, 3 ); if (bRet) printf ("UNISNTALL OK\n" ); else printf ("UNINSTALL FAIL\n" ); return 0 ; };
字符串 获取字符串长度 1 2 3 #include <tchar.h> TCHAR szStr[] = TEXT ("你好" ); _tprintf(TEXT ("_tcslen(szStr)=%d\n" ), _tcslen(szStr));
查找字符串中出现指定字符 1 2 3 4 5 6 7 #include <tchar.h> #include <locale.h> TCHAR szStr[] = TEXT ("xxx" ); LPTSTR lp = _tcschr(szStr, TEXT ('x' )); setlocale (LC_ALL, "chs" ); _tprintf(TEXT ("szStr地址%p\nlp地址%p\n" ), szStr, lp); _tprintf(TEXT ("szStr:%s\nlp:%s\n" ), szStr, lp);
字符串中查找另一字符串 1 2 3 TCHAR szStr[] = TEXT ("xxx" ); TCHAR szStrSearch[] = TEXT ("xxx" ); _tprintf(TEXT ("%s\n" ), _tcsstr(szStr, szStrSearch));
字符串中查找另一字符串上任一字符 1 2 3 4 5 6 7 8 TCHAR szStr[] = TEXT ("xxx" ); TCHAR szStrCharset[] = TEXT ("xxx" ); LPTSTR lpSearch = NULL ; lpSearch = _tcspbrk(szStr, szStrCharset); _tprintf(TEXT ("%s\n" ), lpSearch); lpSearch++; lpSearch = _tcspbrk(lpSearch, szStrCharset); _tprintf(TEXT ("%s\n" ), lpSearch);
大小写转换 1 2 3 4 _tsetlocale(LC_ALL, TEXT (".UTF8" )); TCHAR szStr[] = TEXT ("xxx" ); _tcslwr_s(szStr, _countof(szStr)); _tcsupr_s(szStr, _countof(szStr));
还有字符大小写转换的,分别是totupper
和totlower
。
字符串拼接 1 2 3 4 5 _tsetlocale(LC_ALL, TEXT (".UTF8" )); TCHAR szStrDest[64 ] = TEXT ("xxx" ); TCHAR szStrSour[] = TEXT ("xxx" ); _tcscat_s(szStrDest, _countof(szStrDest), szStrSour); _tprintf(TEXT ("%s\n" ), szStrDest);
字符串比较 比较ASCII码值。如果需要比较汉字时,本地环境改为chs,并将_tcscmp
直接替换为_tcscoll
。
1 2 3 4 5 6 7 8 9 10 _tsetlocale(LC_ALL, TEXT (".UTF8" )); TCHAR szStr1[] = TEXT ("xxx" ); TCHAR szStr2[] = TEXT ("xxx" ); DWORD n = _tcscmp(szStr1, szStr2); if (n > 0 ) _tprintf(TEXT ("szStr1 大于 szStr2\n" )); else if (n<0 ) _tprintf(TEXT ("szStr1 小于 szStr2\n" )); else _tprintf(TEXT ("szStr1 等于 szStr2\n" ));
字符串分割 1 2 3 4 5 6 7 8 9 TCHAR strToken[] = TEXT ("xxx" ); TCHAR strDelimit[] = TEXT (", \t" ); LPTSTR lpToken = NULL ; LPTSTR lpTokenNext = NULL ; lpToken = _tcstok_s(strToken, strDelimit, &lpTokenNext); while (lpToken != NULL ) { _tprintf(TEXT ("%s\n" ), lpToken); lpToken = _tcstok_s(NULL , strDelimit, &lpTokenNext); };
字符串快速排序 1 2 3 4 5 6 7 8 9 10 11 int CALLBACK compare (LPCVOID arg1, LPCVOID arg2) { return _tcscoll(*(LPTSTR*)arg1, *(LPTSTR*)arg2); }; LPCTSTR arrStr[] = { TEXT ("xxx" ), TEXT ("xxx" ), TEXT ("xxx" ) }; qsort (arrStr, _countof(arrStr), sizeof (LPTSTR), compare);for (int i = 0 ; i < _countof(arrStr); i++) _tprintf(TEXT ("%s " ), arrStr[i]);
二分查找用bsearch
函数。
字符串与数值型互转 字符串转数值时,转double用_ttof
,转int用_ttoi
,转int64/long long用_ttoi64
或_ttoll
。一般这些会跳过开头空格并在非数值处停止,如果字符串开头就不是数字则直接不转换返回0。有安全版本,需要指定缓冲区大小和要转换的进制数(2、8、10、16进制),这里不讲。
1 2 3 4 5 6 7 8 9 #include <stdint.h> TCHAR str1[] = L"123.45" ; double num1 = _ttof(str1);TCHAR str2[] = L"123" ; int num2 = _ttoi(str2);TCHAR str3[] = L"123456789012345" ; int64_t num3 = _ttoi64(str3);TCHAR str4[] = L"1234567890123456789" ; long long num4 = _ttoll(str4);
数值型转字符串:
1 2 3 4 5 6 7 8 9 10 11 12 int num1 = 123 ;TCHAR str1[10 ]; _itow(num1, str1, 10 ); wprintf (TEXT ("str1: %ls" ), str1);int64_t num2 = 123456789012345 ;TCHAR str2[20 ]; _i64tow(num2, str2, 20 ); wprintf (TEXT ("str2: %ls" ), str2);uint64_t num3 = 1234567890123456789 ;TCHAR str3[20 ]; _ui64tow(num3, str3, 20 ); wprintf (TEXT ("str3: %ls" ), str3);
字符串格式化 1 2 3 4 5 6 7 8 9 10 11 #include <strsafe.h> TCHAR szName[] = TEXT ("xxx" ); TCHAR szSchool[] = TEXT ("xxx" ); int age = 21 ;TCHAR szBuf[128 ] = { 0 }; HRESULT hResult = E_FAIL; hResult = StringCchPrintf (szBuf, _countof(szBuf), TEXT ("xxx%sxxx%sxxx%d\n" ), szName,szSchool,age); if (SUCCEEDED (hResult)) else