最近实在是忙的……上班太忙,下班回来不想写东西,光想玩游戏,我彻底成程序员了?而且为什么我这个本来想做游戏关卡设计师的人会和进程现程句柄死磕上了呢……郁闷死我了,这就是要自己承担未来的条件吗? 废话再少也多,贴代码……
更新的附带一提
在新写的MfcLayout的程序里面有这套Utils源代码了。http://blog.sina.com.cn/u/4070692f010002ob
//******* Utils.h *******//
#pragma once
//////////////////////////////////////////////////////////////////////////
// 类名: Utils
// 工具包类
//////////////////////////////////////////////////////////////////////////
class Utils
{
public:
// 查找当前是否有指定文件名的进程, 返回0表示未找到
static DWORD FindProcessByName(CString& strFileName);
// 根据指定进程ID和参考名字查找主窗口句柄
static HWND FindWindowByPID( DWORD dwProcessId, CString& strCaption );
// 杀死指定ID进程
static BOOL KillProcessByPID( DWORD dwProcessId );
// 获得硬盘卷序列号(逻辑分区的"软"序列号,每次格式化后都会变!)
static DWORD GetVolumnSerial( const char cVolumn = 'c' );
//////////////////////////////////////////////////////////////////////////
// 说明: 读取Ini配置文件的工具函数
static void LoadIni( CString& strSection, CString& strKey, INT* pN, CString& strFileName, CString& strDefault = CString("0") );
static void LoadIni( CString& strSection, CString& strKey, LONG* pL, CString& strFileName, CString& strDefault = CString("0") );
static void LoadIni( CString& strSection, CString& strKey, FLOAT* pF, CString& strFileName, CString& strDefault = CString("0.0") );
static void LoadIni( CString& strSection, CString& strKey, CString* pS, CString& strFileName, CString& strDefault = CString("") );
//////////////////////////////////////////////////////////////////////////
protected:
// 枚举窗口保存结果的结构
struct EnumWindowsResultStruct
{
BOOL bResult; // [out]返回比较结果
HWND hWnd; // [out]枚举的窗口句柄
DWORD dwProcId; // [in]要和当前窗口进程ID比较的目标进程ID
CString strCaption; // [in]窗口标题参考文字
EnumWindowsResultStruct()
{
bResult = FALSE; // [out]返回比较结果
hWnd = NULL; // [out]枚举的窗口句柄
dwProcId = 0; // [in]要和当前窗口进程ID比较的目标进程ID
}
void Init(void)
{
bResult = FALSE; // [out]返回比较结果
hWnd = NULL; // [out]枚举的窗口句柄
dwProcId = 0; // [in]要和当前窗口进程ID比较的目标进程ID
strCaption.Empty();
}
};
// 遍历窗口回调函数
static BOOL CALLBACK EnumProc(HWND hWnd, LPARAM lParam);
// 枚举用虚函数
static BOOL OnEnumProc(HWND hWnd, EnumWindowsResultStruct* pewrsInOut);
};
//******* Utils.cpp *******//
#include "stdafx.h"
#include <atlbase.h>
#include <atlwin.h>
#include "Utils.h"
#include <tlhelp32.h>
//////////////////////////////////////////////////////////////////////////
// 命名空间: Utils
// 工具包
//////////////////////////////////////////////////////////////////////////
// 查找当前是否有指定文件名的进程
DWORD Utils::FindProcessByName(CString& strFileName)
{
HANDLE hProcSnap = NULL; // 进程快照句柄
PROCESSENTRY32 pe32 = {0}; // 系统信息
// 创建系统快照
hProcSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcSnap == INVALID_HANDLE_VALUE )
return FALSE;
// 在使用PROCESSENTRY32结构前必须填充尺寸
pe32.dwSize = sizeof(PROCESSENTRY32);
// 遍历进程快照, 查找指定文件名
if( Process32First( hProcSnap, &pe32 ) )
{
do
{
// 比较进程名字和传进来的文件名
CString strExe( pe32.szExeFile );
//LogFormatedMsg( "C:\list.txt", "%s", strExe ); // debug code
DWORD dwProcessID = pe32.th32ProcessID; // 遍历列表的进程ID
// 有相同名字的进程, 并且不同于当前程序ID, 才是前一个运行中的实例
if( strExe.CompareNoCase( strFileName ) == 0
&& dwProcessID != GetCurrentProcessId() )
return dwProcessID;
}
while( Process32Next( hProcSnap, &pe32 ) );
}
// 退出前要清理快照对象
CloseHandle( hProcSnap );
return FALSE;
}
// 根据指定进程ID查找主窗口句柄
HWND Utils::FindWindowByPID( DWORD dwProcessId, CString& strCaption )
{
//LogFormatedMsg( "C:\list.txt", "目标进程ID: %l", dwProcessId );
// EnumWindows是自动重复回调的, 外面不用循环了
EnumWindowsResultStruct ewrsProc;
ewrsProc.dwProcId = dwProcessId; // 比较的目标进程ID
ewrsProc.strCaption = strCaption; // 比较的目标窗口名称
//------------------------------------------------
// EnumWindows找到窗口(枚举)时, 就会返回非0值;
// 回调函数里因为返回是BOOL, 找到窗口会返回FALSE
// , 而枚举完毕也会返回FALSE。所以我们处理当返回
// FALSE时候, 判断结构里面的比较值和窗口句柄是否
// 有效来区分是枚举完毕还是找到窗口。
//------------------------------------------------
if( !EnumWindows(EnumProc, (LPARAM)&ewrsProc) )
{
// 这里只是正确枚举到了一个窗口, 还需要根据枚举结果来判断
if( ewrsProc.bResult && ewrsProc.hWnd )
{
// 这里才是真正比较到了正确的进程ID
return ewrsProc.hWnd;
}
}
return NULL;
}
// 杀死指定ID进程
BOOL Utils::KillProcessByPID( DWORD dwProcessId )
{
BOOL bRet = FALSE;
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwProcessId );
if( hProcess )
{
bRet = TerminateProcess( hProcess, 0 );
}
CloseHandle( hProcess );
return bRet;
}
// 获得硬盘卷序列号(逻辑分区的"软"序列号,每次格式化后都会变!)
DWORD Utils::GetVolumnSerial( const char cVolumn )
{
// 合成卷标
CString strVolume;
strVolume.Format( "%c:", toupper(cVolumn) );
DWORD dwSerial = 0;
TCHAR szName[MAX_PATH];
GetVolumeInformation( strVolume, szName, MAX_PATH, &dwSerial, NULL, NULL, NULL, NULL );
return dwSerial;
}
// 遍历窗口回调函数
BOOL CALLBACK Utils::EnumProc(HWND hWnd, LPARAM lParam)
{
////return ((Utils*)lp)->OnEnumProc(hWnd);
// 通过结构来传递所需的结果和数据, 所以直接返回就可以了
return OnEnumProc( hWnd, (EnumWindowsResultStruct*)lParam );
}
// 枚举用虚函数
BOOL Utils::OnEnumProc(HWND hWnd, EnumWindowsResultStruct* pewrsInOut)
{
if( hWnd )
{
// 每次都先清空这两个输出值, 让外面能判断是枚举完了还是找到进程了(都返回FALSE)
pewrsInOut->bResult = FALSE;
pewrsInOut->hWnd = NULL;
DWORD dwProcId, dwThreadId;
// 返回的是线程ThreadID,参数里获得的才是进程ProcessID
dwThreadId = GetWindowThreadProcessId( hWnd, &dwProcId );
//// DebugCode
//TCHAR szTemp[MAX_PATH];
//GetWindowText( hWnd, szTemp, MAX_PATH );
//LogFormatedMsg( "C:\list.txt", "Thr: %l|Prc: %l t"%s" -->HWND: %l", dwThreadId, dwProcId, szTemp, hWnd ); // debug code
// 处理比较结果成功的清空
if( dwProcId == pewrsInOut->dwProcId )
{
// 一个进程会有N多窗口...只好尝试取第一个有标题的认为是主窗口了
TCHAR szBuff[MAX_PATH];
int nTitleLen = GetWindowText( hWnd, szBuff, MAX_PATH );
// 窗口没标题的就不理了
if( nTitleLen > 0 )
{
CString strBuff(szBuff);
LPTSTR szCaption = pewrsInOut->strCaption.GetBuffer();
int iPos = strBuff.Find( szCaption );
pewrsInOut->strCaption.ReleaseBuffer();
// 再比较窗口标题和传入的参考文字
if( iPos != -1 )
{
pewrsInOut->bResult = TRUE;
pewrsInOut->hWnd = hWnd; // 传出去窗口句柄
return FALSE; // 默认成功TRUE会一直循环回调...只有用FALSE来完结了
}
}
}
}
return TRUE;
}
// 说明: 读取Ini配置文件的工具函数
void Utils::LoadIni( CString& strSection, CString& strKey, INT* pN, CString& strFileName, CString& strDefault )
{
char pStr[MAX_PATH];
GetPrivateProfileStringA( strSection, strKey, strDefault, pStr, MAX_PATH, strFileName );
*pN = atoi( pStr );
}
void Utils::LoadIni( CString& strSection, CString& strKey, LONG* pL, CString& strFileName, CString& strDefault )
{
char pStr[MAX_PATH];
GetPrivateProfileStringA( strSection, strKey, strDefault, pStr, MAX_PATH, strFileName );
*pL = atol( pStr );
}
void Utils::LoadIni( CString& strSection, CString& strKey, FLOAT* pF, CString& strFileName, CString& strDefault )
{
char pStr[MAX_PATH];
GetPrivateProfileStringA( strSection, strKey, strDefault, pStr, MAX_PATH, strFileName );
DOUBLE temp = atof( pStr );
*pF = (FLOAT)temp;
}
void Utils::LoadIni( CString& strSection, CString& strKey, CString* pS, CString& strFileName, CString& strDefault )
{
char pStr[MAX_PATH];
GetPrivateProfileStringA( strSection, strKey, strDefault, pStr, MAX_PATH, strFileName );
*pS = pStr;
}