これは、Windows XPプロセスに関するものです。
実行中のプロセスがあります。Process1と呼びましょう。 Process1は、新しいプロセスProcess2を作成し、そのIDを保存します。
さて、ある時点でProcess1はProcess2に何かをしたいので、まずProcess2がまだ生きており、ユーザーがそれを殺していないことを確認する必要があります。
このプロセスがまだ実行されていることを確認するにはどうすればよいですか?私はそれを作成したので、プロセスIDを持っています、IsProcessIDValid(id)の行に沿っていくつかのライブラリ関数があると思いますが、MSDNでそれを見つけることができません
GetExitCodeProcess
を使用できます。プロセスがまだ実行中の場合(またはその終了コード:()で終了した場合)STILL_ACTIVE
(259)を返します。
プロセスハンドルは、終了すると通知されます。
したがって、次のように動作します(簡潔にするためにエラー処理は削除されました)。
BOOL IsProcessRunning(DWORD pid)
{
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
DWORD ret = WaitForSingleObject(process, 0);
CloseHandle(process);
return ret == WAIT_TIMEOUT;
}
プロセスIDはリサイクルできることに注意してください-CreateProcess呼び出しから返されるハンドルをキャッシュすることをお勧めします。
スレッドプールAPI(Vista +ではSetThreadpoolWait、古いプラットフォームではRegisterWaitForSingleObject)を使用して、プロセスの終了時にコールバックを受け取ることもできます。
編集:私は元の質問の「プロセスに何かをしたい」部分を見逃しました。何らかの小さなウィンドウで潜在的に古いデータを使用しても問題ない場合、または操作を試行せずに操作を失敗させたい場合、この手法を使用できます。プロセスが終了したためにアクションが失敗するケースを処理する必要があります。
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
/*!
\brief Check if a process is running
\param [in] processName Name of process to check if is running
\returns \c True if the process is running, or \c False if the process is not running
*/
bool IsProcessRunning(const wchar_t *processName)
{
bool exists = false;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry))
while (Process32Next(snapshot, &entry))
if (!wcsicmp(entry.szExeFile, processName))
exists = true;
CloseHandle(snapshot);
return exists;
}
子プロセスを監視する別の方法は、次のことを行うワーカースレッドを作成することです。
私はこれを今日見つけました、それは2003年からです。名前でプロセスを見つけます、あなたはpidさえ必要としません。
\#include windows.h
\#include tlhelp32.h
\#include iostream.h
int FIND_PROC_BY_NAME(const char *);
int main(int argc, char *argv[])
{
// Check whether a process is currently running, or not
char szName[100]="notepad.exe"; // Name of process to find
int isRunning;
isRunning=FIND_PROC_BY_NAME(szName);
// Note: isRunning=0 means process not found, =1 means yes, it is found in memor
return isRunning;
}
int FIND_PROC_BY_NAME(const char *szToFind)
// Created: 12/29/2000 (RK)
// Last modified: 6/16/2003 (RK)
// Please report any problems or bugs to [email protected]
// The latest version of this routine can be found at:
// http://www.neurophys.wisc.edu/ravi/software/killproc/
// Check whether the process "szToFind" is currently running in memory
// This works for Win/95/98/ME and also Win/NT/2000/XP
// The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE"
// will both work (for szToFind)
// Return codes are as follows:
// 0 = Process was not found
// 1 = Process was found
// 605 = Unable to search for process
// 606 = Unable to identify system type
// 607 = Unsupported OS
// 632 = Process name is invalid
// Change history:
// 3/10/2002 - Fixed memory leak in some cases (hSnapShot and
// and hSnapShotm were not being closed sometimes)
// 6/13/2003 - Removed iFound (was not being used, as pointed out
// by John Emmas)
{
BOOL bResult,bResultm;
DWORD aiPID[1000],iCb=1000,iNumProc,iV2000=0;
DWORD iCbneeded,i;
char szName[MAX_PATH],szToFindUpper[MAX_PATH];
HANDLE hProc,hSnapShot,hSnapShotm;
OSVERSIONINFO osvi;
HINSTANCE hInstLib;
int iLen,iLenP,indx;
HMODULE hMod;
PROCESSENTRY32 procentry;
MODULEENTRY32 modentry;
// PSAPI Function Pointers.
BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * );
BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *,
DWORD, LPDWORD );
DWORD (WINAPI *lpfGetModuleBaseName)( HANDLE, HMODULE,
LPTSTR, DWORD );
// ToolHelp Function Pointers.
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ;
BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ;
BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ;
BOOL (WINAPI *lpfModule32First)(HANDLE,LPMODULEENTRY32) ;
BOOL (WINAPI *lpfModule32Next)(HANDLE,LPMODULEENTRY32) ;
// Transfer Process name into "szToFindUpper" and
// convert it to upper case
iLenP=strlen(szToFind);
if(iLenP<1 || iLenP>MAX_PATH) return 632;
for(indx=0;indx<iLenP;indx++)
szToFindUpper[indx]=toupper(szToFind[indx]);
szToFindUpper[iLenP]=0;
// First check what version of Windows we're in
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bResult=GetVersionEx(&osvi);
if(!bResult) // Unable to identify system version
return 606;
// At Present we only support Win/NT/2000 or Win/9x/ME
if((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) &&
(osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS))
return 607;
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT)
{
// Win/NT or 2000 or XP
// Load library and get the procedures explicitly. We do
// this so that we don't have to worry about modules using
// this code failing to load under Windows 95, because
// it can't resolve references to the PSAPI.DLL.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
return 605;
// Get procedure addresses.
lpfEnumProcesses = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))
GetProcAddress( hInstLib, "EnumProcesses" ) ;
lpfEnumProcessModules = (BOOL(WINAPI *)(HANDLE, HMODULE *,
DWORD, LPDWORD)) GetProcAddress( hInstLib,
"EnumProcessModules" ) ;
lpfGetModuleBaseName =(DWORD (WINAPI *)(HANDLE, HMODULE,
LPTSTR, DWORD )) GetProcAddress( hInstLib,
"GetModuleBaseNameA" ) ;
if( lpfEnumProcesses == NULL ||
lpfEnumProcessModules == NULL ||
lpfGetModuleBaseName == NULL)
{
FreeLibrary(hInstLib);
return 605;
}
bResult=lpfEnumProcesses(aiPID,iCb,&iCbneeded);
if(!bResult)
{
// Unable to get process list, EnumProcesses failed
FreeLibrary(hInstLib);
return 605;
}
// How many processes are there?
iNumProc=iCbneeded/sizeof(DWORD);
// Get and match the name of each process
for(i=0;i<iNumProc;i++)
{
// Get the (module) name for this process
strcpy(szName,"Unknown");
// First, get a handle to the process
hProc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
aiPID[i]);
// Now, get the process name
if(hProc)
{
if(lpfEnumProcessModules(hProc,&hMod,sizeof(hMod),&iCbneeded) )
{
iLen=lpfGetModuleBaseName(hProc,hMod,szName,MAX_PATH);
}
}
CloseHandle(hProc);
// Match regardless of lower or upper case
if(strcmp(_strupr(szName),szToFindUpper)==0)
{
// Process found
FreeLibrary(hInstLib);
return 1;
}
}
}
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
{
// Win/95 or 98 or ME
hInstLib = LoadLibraryA("Kernel32.DLL");
if( hInstLib == NULL )
return FALSE ;
// Get procedure addresses.
// We are linking to these functions of Kernel32
// explicitly, because otherwise a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in the Kernel 32.
lpfCreateToolhelp32Snapshot=
(HANDLE(WINAPI *)(DWORD,DWORD))
GetProcAddress( hInstLib,
"CreateToolhelp32Snapshot" ) ;
lpfProcess32First=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32First" ) ;
lpfProcess32Next=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32Next" ) ;
lpfModule32First=
(BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32))
GetProcAddress( hInstLib, "Module32First" ) ;
lpfModule32Next=
(BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32))
GetProcAddress( hInstLib, "Module32Next" ) ;
if( lpfProcess32Next == NULL ||
lpfProcess32First == NULL ||
lpfModule32Next == NULL ||
lpfModule32First == NULL ||
lpfCreateToolhelp32Snapshot == NULL )
{
FreeLibrary(hInstLib);
return 605;
}
// The Process32.. and Module32.. routines return names in all uppercase
// Get a handle to a Toolhelp snapshot of all the systems processes.
hSnapShot = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS, 0 ) ;
if( hSnapShot == INVALID_HANDLE_VALUE )
{
FreeLibrary(hInstLib);
return 605;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bResult=lpfProcess32First(hSnapShot,&procentry);
// While there are processes, keep looping and checking.
while(bResult)
{
// Get a handle to a Toolhelp snapshot of this process.
hSnapShotm = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPMODULE, procentry.th32ProcessID) ;
if( hSnapShotm == INVALID_HANDLE_VALUE )
{
CloseHandle(hSnapShot);
FreeLibrary(hInstLib);
return 605;
}
// Get the module list for this process
modentry.dwSize=sizeof(MODULEENTRY32);
bResultm=lpfModule32First(hSnapShotm,&modentry);
// While there are modules, keep looping and checking
while(bResultm)
{
if(strcmp(modentry.szModule,szToFindUpper)==0)
{
// Process found
CloseHandle(hSnapShotm);
CloseHandle(hSnapShot);
FreeLibrary(hInstLib);
return 1;
}
else
{ // Look for next modules for this process
modentry.dwSize=sizeof(MODULEENTRY32);
bResultm=lpfModule32Next(hSnapShotm,&modentry);
}
}
//Keep looking
CloseHandle(hSnapShotm);
procentry.dwSize = sizeof(PROCESSENTRY32);
bResult = lpfProcess32Next(hSnapShot,&procentry);
}
CloseHandle(hSnapShot);
}
FreeLibrary(hInstLib);
return 0;
}
プロセスが実行されているかどうかを確認したり確認したりすることはできません。最近の過去のある時点でプロセスwasが実行されているかどうかを確認することしかできません。プロセスは、アプリケーションによって制御されないエンティティであり、いつでも終了できます。プロセスが実行中かどうかを確認するチェックと対応するアクションの間にプロセスが終了しないことを保証する方法はありません。
最善のアプローチは、必要なアクションを実行し、プロセスが実行されていない場合にスローされる例外をキャッチすることです。
監視ツールを書いている間、私は少し異なるアプローチを取りました。
WaitForSingleObjectまたはRegisterWaitForSingleObject(これを行う)を使用するためだけに余分なスレッドをスピンアップするのは少しもったいないと感じました。私の場合、プロセスが閉じた正確な瞬間を知る必要はないので、プロセスが実際に閉じたというだけです。
代わりにGetProcessTimes()を使用しています。
https://msdn.Microsoft.com/en-us/library/windows/desktop/ms683223(v = vs.85).aspx
GetProcessTimes()は、プロセスが実際に終了した場合にのみ、プロセスのExitTimeのFILETIME構造体を返します。したがって、ExitTime構造体に値が設定されているかどうか、および時間が0でないかどうかを確認するだけです。
このソリューションは、プロセスが強制終了されたが、PIDが別のプロセスによって再利用された場合を考慮すべきです。 GetProcessTimesには、PIDではなくプロセスへのハンドルが必要です。そのため、OSは、ハンドルが特定の時点で実行されていたプロセスに対するものであることを認識しますが、それ以上ではなく、終了時間を提供します。
ExitCodeに依存すると、汚い感じがしました:/
@ user152949によって提供される解決策 は、解説に記載されているように、最初のプロセスをスキップし、「exists」がtrueに設定されている場合に中断しません。修正版を提供させてください:
#include <windows.h>
#include <tlhelp32.h>
bool IsProcessRunning(const wchar_t* const processName) {
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) {
CloseHandle(snapshot);
return false;
}
do {
if (!_wcsicmp(entry.szExeFile, processName)) {
CloseHandle(snapshot);
return true;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return false;
}
EnumProcesses()
を呼び出して、PIDがリストにあるかどうかを確認します。
http://msdn.Microsoft.com/en-us/library/ms682629%28VS.85%29.aspx
JaredParは、プロセスが実行中かどうかわからないという点で正しいです。チェックした時点でプロセスが実行されていたかどうかのみを知ることができます。それはその間に死んだかもしれない。
また、PIDは非常に迅速にリサイクルできることに注意する必要があります。したがって、PIDを使用したプロセスがあるからといって、それがプロセスであることを意味するわけではありません。
プロセスでGUIDを共有します。 (プロセス1は、GUIDを生成し、コマンドラインでプロセス2に渡すことができます。)プロセス2は、そのGUIDで名前付きミューテックスを作成する必要があります。プロセス1は、タイムアウトが0のmutexのWaitForSingleObject
プロセス2がなくなった場合、戻りコードはmutexが破棄されたことを通知し、そうでない場合はタイムアウトになります。
これは私が過去に使用したソリューションです。この例はVB.netにありますが、この手法はcおよびc ++で使用しました。プロセスIDとプロセスハンドル、およびリターンコードに関するすべての問題を回避します。 Windowsは、Process2の終了方法に関係なく、mutexのリリースに非常に忠実です。私はそれが誰かに役立つことを願っています...
**PROCESS1 :-**
Randomize()
mutexname = "myprocess" & Mid(Format(CDbl(Long.MaxValue) * Rnd(), "00000000000000000000"), 1, 16)
hnd = CreateMutex(0, False, mutexname)
' pass this name to Process2
File.WriteAllText("mutexname.txt", mutexname)
<start Process2>
<wait for Process2 to start>
pr = WaitForSingleObject(hnd, 0)
ReleaseMutex(hnd)
If pr = WAIT_OBJECT_0 Then
<Process2 not running>
Else
<Process2 is running>
End If
...
CloseHandle(hnd)
EXIT
**PROCESS2 :-**
mutexname = File.ReadAllText("mutexname.txt")
hnd = OpenMutex(MUTEX_ALL_ACCESS Or SYNCHRONIZE, True, mutexname)
...
ReleaseMutex(hnd)
CloseHandle(hnd)
EXIT
CreateToolhelp32Snapshot で実行中のプロセスのスナップショットを取得し、その上でProcess32FirstおよびProcess32Next呼び出しを使用することで、実行中のプロセスを反復処理することで、プロセス(名前またはPIDが与えられている)が実行中かどうかを確認できますスナップショット。
次に、PIDまたは実行可能名のどちらで検索するかによって、結果のPROCESSENTRY32構造体のth32ProcessIDフィールドまたはszExeFileフィールドを使用できます。簡単な実装があります here 。