Windows核心编程笔记之进程

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/qq_38924942/article/details/88729394
  • 改变进程基址,获取进程基址
#include <Windows.h>
#include <iostream>
#include <strsafe.h>
#include <STDLIB.H>
using namespace std;

#pragma comment(linker, "/BASE:0x400000") // 改变进程加载机地址

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WCHAR RouteBuffer[60] = { 0 };
	DWORD res = GetModuleFileName(NULL, RouteBuffer, sizeof(RouteBuffer)); // 获取当前程序的全路径
	WCHAR AfterVersion[130] = { 0 };
	HMODULE EBAddress = GetModuleHandle(TEXT("NpCxyFW.exe")); // 获取当前进程的句柄 / 基址
	StringCchPrintf(AfterVersion, sizeof(AfterVersion) / 2, 
		TEXT("程序全路径: %s\nhInstance获取到的程序基址: %x \nGetModuleHandle获取到的程序基址: %x"), 
		RouteBuffer, hInstance, EBAddress
	);
	INT Box_1 = MessageBox(NULL, AfterVersion, TEXT("测试"), MB_OKCANCEL);
	return 0;
}

在这里插入图片描述

  • 通过 GetCommandLine() 获取命令行参数
#include <Windows.h>
#include <iostream>
#include <strsafe.h>
using namespace std;

int main(int argc, char *argv[])
{ 
	// 通过 GetCommandLine 获取命令行参数
	INT CmdCount = NULL;
	PWSTR *CmdLine = CommandLineToArgvW(GetCommandLine(), &CmdCount);
	for (size_t i = 1; i < CmdCount; i++)
	{	
		WCHAR *BeforeConversion = CmdLine[i]; CHAR AfterConversion[20] = { 0 }; 
		// 将宽字节字符转换为多字节字符
		int res = WideCharToMultiByte(CP_UTF8, NULL, BeforeConversion, -1, AfterConversion, sizeof(AfterConversion), NULL, NULL);
		cout << "参数 " << i << ": "<< AfterConversion << endl;
	}
	return 0;
}

在这里插入图片描述

  • 显示进程环境块
#include <Windows.h>
#include <iostream>
#include <wcschr.h>  
#include <strsafe.h>
using namespace std;

int main(int argc, char *argv[])
{
	PTSTR PEnvBlock = GetEnvironmentStrings();				// 获取进程环境块,也可以使用 int main(TCHAR *env[]) 的方式获取

	TCHAR SzName[MAX_PATH]; TCHAR SzValue[MAX_PATH];
	PTSTR PszCurrent = PEnvBlock;
	HRESULT hr = S_OK; PCTSTR PszPos = NULL; int current = 0;

	while (PszCurrent != NULL) {														
		if (*PszCurrent != TEXT('=')) {													// 若第一个字符不是 '='
			PszPos = _tcschr(PszCurrent, TEXT('='));  PszPos++;							// 查找 '=' 在字符串中的位置
			size_t cbNameLength = (size_t)PszPos - (size_t)PszCurrent - sizeof(TCHAR);  // 获取 Name 字段的长度
			hr = StringCbCopyN(SzName, MAX_PATH, PszCurrent, cbNameLength);             // 将 Name 字段拷贝到 szName 中
			if (FAILED(hr)) break;

			hr = StringCchCopyN(SzValue, MAX_PATH, PszPos, _tcslen(PszPos) + 1);	// 将 '=' 字符之后的内容拷贝至 szValue 中
			if (SUCCEEDED(hr))
			{
				_tprintf(TEXT("[%u] %s=%s\r\n"), current, SzName, SzValue);			// 成功便打印出信息
			}
			else
			{
				if (hr == STRSAFE_E_INSUFFICIENT_BUFFER)							// 错误处理,STRSAFE_E_INSUFFICIENT_BUFFER 缓冲区空间不足
					_tprintf(TEXT("[%u] %s=%s...\r\n"), current, SzName, SzValue);
				else
					_tprintf(TEXT("[%u] %s=???\r\n"), current, SzName); break;
			}
		}
		else {	
			_tprintf(TEXT("[%u] %s\r\n"), current, PszCurrent);  // 若一开始就为 '=' 字符,就直接打印出字符串的内容
		}
		current++;										 // 环境变量的个数加 1
		while (*PszCurrent != TEXT('\0')) PszCurrent++;  // 移动到字符串的结尾
		PszCurrent++;									 // 跳过 '\0'
		if (*PszCurrent == TEXT('\0')) break;			 // 检查它是否不是最后一个字符串
	};
	FreeEnvironmentStrings(PEnvBlock);					 //释放空间
	return 0;
}

  • 获得某个环境变量
#include <Windows.h>
#include <iostream>
#include <strsafe.h>
#include <stdio.h>
using namespace std;

int main(TCHAR *env[])
{
	PWSTR lpBuffer = NULL;
	DWORD Size = GetEnvironmentVariable(TEXT("PATH"), lpBuffer, 0); // 首先判断是否存在 PATH 环境变量
	if (Size != 0)
	{
		DWORD BufferSize = Size * sizeof(TCHAR);
		lpBuffer = (PWSTR)malloc(BufferSize);		// 存在即分配缓冲区空间
		GetEnvironmentVariable(TEXT("PATH"), lpBuffer, BufferSize);
		printf("%ls", lpBuffer);					// 打印 PATH 环境变量的信息
	}
	return 0;
}
  • 获取当前目录
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <versionhelpers.h>
using namespace std;

BOOL CompareOS(INT dwMajorVersion, INT dwMinorVersion);

int main(TCHAR *env[])
{
	// 获取当前目录方法 1
	TCHAR Buffer_1[MAX_PATH] = { 0 };
	DWORD DirLength = GetCurrentDirectory(MAX_PATH, Buffer_1);
	printf("目录: %ls\n", Buffer_1);
	// 获取当前目录方法 2
	TCHAR Buffer_2[MAX_PATH];
	DWORD PathLength = GetFullPathName(TEXT("C:"), MAX_PATH, Buffer_2, NULL);
	printf("目录: %ls\n", Buffer_2);

	return 0;
}

  • 判断系统版本号的两种方法
VOID JudgeOS() // 通过 VerifyVersionInfo 比较判断,准确度一般
{
	if (!CompareOS(10, 0))
		if (!CompareOS(6, 3))
			if (!CompareOS(6, 2))
				if (!CompareOS(6, 1))
					if (!CompareOS(6, 0))
						if (!CompareOS(5, 2))
							if (!CompareOS(5, 1))
								if (!CompareOS(5, 0))
									cout << "未知的操作系统版本" << endl;
								else
									cout << "版本在 Window2000 以上" << endl;
							else
								cout << "版本在 Windows XP 以上" << endl;
						else
							cout << "版本在 Windows XP Professional x64 Edition 以上" << endl;
					else
						cout << "版本在 Windows Vista 或者 Windows Server 2008 以上" << endl;
				else
					cout << "版本在 Windows 7 或者 Windows Server 2008 R2 以上" << endl;
			else
				cout << "版本在 Windows 8 或者 Windows Server 2012 以上" << endl;
		else
			cout << "版本在 Windows 8.1 或者 Windows Server 2012 R2 以上" << endl;
	else
		cout << "版本在 Windows Server 2016 或者 Windows 10 以上" << endl;
}

BOOL CompareOS(INT MajorVersion, INT MinorVersion)
{
	OSVERSIONINFOEX OSinfo = { 0 };
	OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
	OSinfo.dwMajorVersion = MajorVersion; OSinfo.dwMinorVersion = MinorVersion; // 设置比较操作系统版本的区间组合
	
	DWORDLONG dwlConditionMask = 0;			// 设置用于比较操作系统的宏
	VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL); 
	VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL);

	BOOL Res = VerifyVersionInfo(&OSinfo, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask); // 第二个参数为比较位,支持 or 操作
	return Res;		// 函数成功返回非 0 值
}
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <versionhelpers.h>
using namespace std;
// 利用官方的便捷函数进行操作系统的判别
INT JudgeOS();

int main(TCHAR *env[])
{
	JudgeOS(); // 打印操作系统版本的信息
	return 0;
}

INT JudgeOS()
{
	if (IsWindowsServer())
		cout << "操作系统是服务器" << endl;
	else
		if (!IsWindows10OrGreater())
			if (!IsWindows8OrGreater())
				if (!IsWindows7SP1OrGreater())
					if (!IsWindows7OrGreater())
						if (!IsWindowsVistaSP2OrGreater())
							if (!IsWindowsVistaSP1OrGreater())
								if (!IsWindowsVistaOrGreater())
									if (!IsWindowsXPSP3OrGreater())
										if (!IsWindowsXPSP2OrGreater())
											if (!IsWindowsXPSP1OrGreater())
												if (!IsWindowsXPOrGreater())
													cout << "未知的操作系统版本" << endl;
												else
													cout << "当前操作系统版本是否与Windows XP版本匹配或大于Windows XP版本 " << endl;
											else
												cout << "当前操作系统版本是否与Windows XP Service Pack 1(SP1)版本匹配或大于" << endl;
										else
											cout << "当前操作系统版本是否与Windows XP Service Pack 2(SP2)版本匹配或大于" << endl;
									else
										cout << "当前操作系统版本是否与Windows XP Service Pack 3(SP3)版本匹配或大于" << endl;
								else
									cout << "当前操作系统版本是否与Windows Vista版本匹配或大于Windows Vista版本" << endl;
							else
								cout << "当前操作系统版本是否与Windows Vista Service Pack 1(SP1)版本匹配或大于" << endl;
						else
							cout << "当前操作系统版本是否与Windows Vista Service Pack 2(SP2)版本匹配或大于" << endl;
					else
						cout << "当前操作系统版本是否与Windows 7版本匹配或大于Windows 7版本" << endl;
				else
					cout << "当前操作系统版本是否与Windows 7 Service Pack 1(SP1)版本匹配或大于" << endl;
			else
				cout << "当前操作系统版本是否与Windows 8版本匹配或大于Windows 8版本" << endl;
		else
			cout << "指示当前操作系统版本是否与Windows 10版本匹配或大于Windows 10版本" << endl;
	return 0;
}
  • 进程创建
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <versionhelpers.h>
using namespace std;

int main(TCHAR *env[])
{
	DWORD ExitCode = NULL;

	// 创建线程和进程的安全结构体
	SECURITY_ATTRIBUTES ProcessSec = { 0 };  SECURITY_ATTRIBUTES ThreadSec = { 0 };
	ProcessSec.nLength = sizeof(ProcessSec); ThreadSec.nLength = sizeof(ThreadSec);
	ProcessSec.bInheritHandle = TRUE;	     ThreadSec.bInheritHandle = TRUE;			  // 指定线程和进程为可以继承

	STARTUPINFO StartInfo = { sizeof(STARTUPINFO) };
	StartInfo.cb = sizeof(StartInfo);							// STARTUPINFO 结构体用于新进程窗口设置
	StartInfo.dwFlags = STARTF_USEPOSITION;
	StartInfo.dwX = 400; StartInfo.dwY = 400;					// 防止窗口重叠
	PROCESS_INFORMATION ProcessInfo = { 0 };					// 返回进程信息的结构体

	// 创建进程打开 cmd.exe 执行模块
	TCHAR CmdLine[] = L"cmd.exe";
	BOOL res = CreateProcess(NULL, CmdLine, &ProcessSec, &ThreadSec, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &StartInfo, &ProcessInfo); // CREATE_NEW_CONSOLE 用于创建一个新的控制台窗口
	cout << "创建的新进程 ID: " << ProcessInfo.dwProcessId << endl;		// ProcessInfo 结构体包含子进程和线程的 ID
	cout << "创建的新线程 ID: " << ProcessInfo.dwThreadId << endl;

	WaitForSingleObject(ProcessInfo.hThread, INFINITE);		// 等待线程执行完毕
	CloseHandle(ProcessInfo.hThread);						// ProcessInfo 结构体包含子进程和线程的句柄
	WaitForSingleObject(ProcessInfo.hProcess, INFINITE);	// 等待进程执行完毕
	GetExitCodeProcess(ProcessInfo.hProcess, &ExitCode);	// 获取进程退出代码
	cout << ExitCode << endl;
	CloseHandle(ProcessInfo.hProcess);						// 关闭进程句柄

	return 0;
}
  • 手动提升程序权限
#include <Windows.h>
#include <iostream>
#include <strsafe.h>
using namespace std;

void ErrorExit(LPTSTR lpszFunction, DWORD LastError);
int main(int argc, char *argv[], TCHAR *env[])
{
	SHELLEXECUTEINFOW ExeInfo = { sizeof(ExeInfo) }; // 初始化结构体
	ExeInfo.lpVerb = TEXT("runas"); ExeInfo.lpFile = TEXT("cmd.exe"); ExeInfo.nShow = SW_SHOWNORMAL; // 设置操作的文件
	if (!ShellExecuteEx(&ExeInfo))
	{
		DWORD LastError = GetLastError(); 		  // 获取权限失败,保存错误代码
		TCHAR ErrString[10] = L"错误代码";
		ErrorExit(ErrString, LastError);		  // 调用 ErrorExit 函数打印详细信息
	}	
	else
	{
		cout << "调用成功" << endl;
	}
	return 0;
}

void ErrorExit(LPTSTR lpszFunction, DWORD LastError)
{
	// 检索最后错误码的系统错误消息

	LPVOID lpMsgBuf;
	LPVOID lpDisplayBuf;
	DWORD dw = LastError;                      // 模拟错误代码定义为 123

	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | // 函数自动使用 LocalAlloc 函数,来为 lpBuffer 分配内存
		FORMAT_MESSAGE_FROM_SYSTEM |	 // 定义可以使用 GetLastError 的返回值赋给 dw 
		FORMAT_MESSAGE_IGNORE_INSERTS,   // 这个标志表示 Arguments 参数将被忽略
		NULL,							 // 消息所在位置,这个参数类型,根据dwFlags标志来设定
		dw,								 // 消息索引,如果 lpSource 是一个字符串,那么这个参数被忽略
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // 设置为本地默认语言
		(LPTSTR)&lpMsgBuf,				 // 接受消息字符串的内存块
		0,								 // 内存大小
		NULL);							 // 消息中的参数		

	// 显示错误消息并退出进程

	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, // 将内存初始化为 0
		(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); // 为字符串指针区域申请足够大小的内存

	StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf),  // 目标缓冲区和目标缓冲区的大小
		TEXT("%s %d 的含义是: %s"),			 // 格式字符串
		lpszFunction,						 // 参数1
		dw,									 // 参数2
		lpMsgBuf);							 // 参数3

	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

	LocalFree(lpMsgBuf);      // 释放空间
	LocalFree(lpDisplayBuf);
	ExitProcess(dw);		  // 关闭进程
}

  • 查看是否为上下文管理员权限
#include <Windows.h>
#include <iostream>
#include <shlobj.h>
#include <strsafe.h>
using namespace std;

VOID WINAPI ErrorCodeTransformation(DWORD ErrorCode);
DWORD WINAPI GetProcessElevation(TOKEN_ELEVATION_TYPE *pElevationType, BOOL* lsAdmin);

int main(INT argc, CHAR *argv[], TCHAR *env[])
{
	// pElevationType 为令牌的上下文权限类型,IsAdmin 标识是否为管理员权限
	TOKEN_ELEVATION_TYPE pElevationType; BOOL IsAdmin;
	if (GetProcessElevation(&pElevationType, &IsAdmin))
	{
		switch (pElevationType)
		{
		case TokenElevationTypeDefault:
			cout << "[-] 进程以默认用户运行,或者UAC被禁用" << endl; break;
		case TokenElevationTypeFull:
			cout << "[*] 进程的权限被成功提升,而且令牌没有被筛选过" << endl; break;
		case TokenElevationTypeLimited:
			cout << "[*] 进程使用和一个筛选过的令牌对应的受限的权限运行" << endl; break;
		}
		if (IsAdmin) cout << "[*] 进程为管理员权限" << endl;
		else cout << "[-] 进程为普通权限" << endl;
	}
	else
	{
		DWORD ErrorCode = GetProcessElevation(&pElevationType, &IsAdmin);
		ErrorCodeTransformation(ErrorCode);// 打印错误信息
	}
	return 0;
}

DWORD WINAPI GetProcessElevation(TOKEN_ELEVATION_TYPE *pElevationType, BOOL* pIsAdmin)
{
	HANDLE hToken = NULL; DWORD dwSize; DWORD ErrorCode = NULL;
	// OpenProcessToken 用于打开当前进程的令牌,hToken 为令牌的句柄
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
	{
		// 调用失败返回错误代码
		ErrorCode = GetLastError();
		return (ErrorCode);
	}

	BOOL bResult = FALSE;
	// GetTokenInformation 用于获取当前令牌是什么令牌,令牌种类储存在 pElevationType 中
	if (GetTokenInformation(hToken, TokenElevationType, pElevationType, sizeof(TOKEN_ELEVATION_TYPE), &dwSize))
	{
		BYTE adminSID[SECURITY_MAX_SID_SIZE];
		dwSize = sizeof(adminSID);
		// CreateWellKnownSid 定义一个描述符为 WinBuiltinAccessControlAssistanceOperatorsSid 的别名 SID
		// adminSID 中储存的是新的 SID
		CreateWellKnownSid(WinBuiltinAccessControlAssistanceOperatorsSid, NULL, &adminSID, &dwSize);
		// 如果当前进程的令牌被筛选过
		if (*pElevationType == TokenElevationTypeLimited)
		{
			HANDLE hUnfilteredToken = NULL;
			// 获取当前进程未筛选过令牌的句柄,句柄保存在 hUnfilteredToken
			GetTokenInformation(hToken, TokenLinkedToken, (VOID *)&hUnfilteredToken, sizeof(HANDLE), &dwSize);
			// CheckTokenMembership 用于将模拟令牌和创建的安全描述符做比较,判断令牌的上下文访问权限是否为管理员
			if (CheckTokenMembership(hUnfilteredToken, &adminSID, pIsAdmin)) bResult = TRUE;
			CloseHandle(hUnfilteredToken);
		}
		else
		{	// IsUserAnAdmin 函数是 CheckTokenMembership 的包装函数
			// 建议直接调用该函数以确定管理员组状态,而不是调用 IsUserAnAdmin
			*pIsAdmin = IsUserAnAdmin();
			bResult = TRUE;
		}
	}
	CloseHandle(hToken);
	return (bResult);
}

// 如果返回错误,可调用此函数打印详细错误信息
VOID WINAPI ErrorCodeTransformation(DWORD ErrorCode)
{
	LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = ErrorCode;
	// 将错误代码转换为错误信息
	FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
		NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL
	);
	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
	// 格式化打印
	StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf), TEXT("错误代码 %d :  %s"), dw, lpMsgBuf);
	// 输出错误信息
	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
	// 释放资源
	LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); ExitProcess(dw);		  
}
  • 获取系统进程列表,操作进程句柄
#include <Windows.h>
#include <iostream>
#include <shlobj.h>
#include <strsafe.h>
#include <stdio.h>
#include <tlhelp32.h>
using namespace std;

VOID WINAPI ErrorCodeTransformation(DWORD ErrorCode);
DWORD WINAPI ProcessInfo(VOID);
DWORD WINAPI ProcessHandle(DWORD ProcessID);

int main(INT argc, CHAR *argv[], TCHAR *env[])
{
	DWORD ErrorCode = ProcessInfo();
	// 打印详细的错误信息
	ErrorCodeTransformation(ErrorCode); 
	return 0;
}

DWORD WINAPI ProcessInfo(VOID)
{
	// ErrorCode 用于统计错误信息,ProcessCount 用于统计进程数
	DWORD ErrorCode = NULL; INT ProcessCount = 0;
	// 使用 CreateToolhelp32Snapshot 获取当前所有的进程快照
	HANDLE ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_INHERIT | TH32CS_SNAPALL, 0);
	if (ProcessSnapshot == INVALID_HANDLE_VALUE)
	{
		// 调用错误返回错误代码,以便查出详细的错误信息
		ErrorCode = GetLastError();
		return (ErrorCode);
	}
	PROCESSENTRY32W ProcessInfo; ProcessInfo.dwSize = sizeof(ProcessInfo); // 必须初始化结构体大小
	// Process32First 用于获取第一个进程,返回进程信息至 ProcessInfo 结构体
	BOOL DisResult = Process32First(ProcessSnapshot, &ProcessInfo); 
	if (!DisResult)
	{
		// 调用错误返回错误代码,以便查出详细的错误信息
		ErrorCode = GetLastError();
		return (ErrorCode);
	}
	// 进程数量加一
	ProcessCount++;
	cout << "  显示进程 ID:  " << ProcessInfo.th32ProcessID << endl;
	while (DisResult)
	{
		ProcessCount++;
		// 获取下一个进程的详细信息
		DisResult = Process32Next(ProcessSnapshot, &ProcessInfo);
		// 打印进程 ID
		cout << "  ID:  " << ProcessInfo.th32ProcessID;
		// 有关句柄的详细操作
		ProcessHandle(ProcessInfo.th32ProcessID);
		// 打印进程名称
		printf("  进程名: %ls\n  ", ProcessInfo.szExeFile);
	}
	return 0;
}

DWORD WINAPI ProcessHandle(DWORD ProcessID)
{
	DWORD ErrorCode = NULL;
	// OpenProcess 将进程 ID 转换进程句柄,方便对进程进行操作
	HANDLE ProcessHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, ProcessID);
	if (!ProcessHandle)
	{
		// 调用错误返回错误代码,以便查出详细的错误信息
		ErrorCode = GetLastError();
		if (ErrorCode == 5) cout << "  访问状态: 拒绝访问  ";
		return (ErrorCode);
	}
	else
	{
		// 操作进程句柄....
	
	}
	// 关闭句柄
	CloseHandle(ProcessHandle);
	return TRUE;
}

// 如果返回错误,可调用此函数打印详细错误信息
VOID WINAPI ErrorCodeTransformation(DWORD ErrorCode)
{
	LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = ErrorCode;
	// 将错误代码转换为错误信息
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL
	);
	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
	StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf), TEXT("错误代码 %d :  %s"), dw, lpMsgBuf);
	// 弹窗显示错误信息
	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
	LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); ExitProcess(dw);
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38924942/article/details/88729394