2009-10-19 37 views
45

Điều này liên quan đến các quy trình của Windows XP.C++, Cách xác định xem một tiến trình Windows có đang chạy không?

Tôi có một quy trình đang chạy, hãy gọi nó là Process1. Process1 tạo ra một quy trình mới, Process2 và lưu id của nó.

Bây giờ, tại một số điểm Process1 muốn Process2 làm điều gì đó, vì vậy trước tiên nó cần đảm bảo rằng Process2 vẫn còn sống và người dùng đã không giết nó.

Làm cách nào để kiểm tra xem quá trình này vẫn đang chạy? Vì tôi đã tạo nó, tôi có ID tiến trình, tôi nghĩ rằng có một số chức năng thư viện dọc theo dòng IsProcessIDValid (id) nhưng tôi không thể tìm thấy nó trên MSDN

+0

DCOM đã làm tất cả những thứ này miễn phí, tại sao bạn lại phát minh ra bánh xe? –

+1

Kế hoạch này có vẻ bị hỏng do điều kiện chủng tộc vốn có. Người dùng có thể giết Process2 sau khi bạn kiểm tra xem Process2 vẫn còn hoạt động hay không và trước khi bạn yêu cầu nó thực hiện công việc bạn cần (hoặc trước khi nó hoàn thành công việc bạn cần). Bạn nên tắt lệnh cho Process2 để thực hiện công việc và sau đó chờ xác nhận rằng nó đã được hoàn thành.Trong khi chờ đợi, bạn có thể nhận thấy nếu Process2 biến mất. –

Trả lời

3

Bạn không bao giờ có thể kiểm tra và xem quy trình đang chạy, bạn chỉ có thể kiểm tra xem liệu một quá trình đang chạy tại một số điểm trong quá khứ gần đây. Quá trình là một thực thể không được kiểm soát bởi ứng dụng của bạn và có thể thoát ra bất kỳ lúc nào. Không có cách nào để đảm bảo rằng một quá trình sẽ không thoát ra giữa các kiểm tra để xem nếu nó đang chạy và hành động tương ứng.

Cách tiếp cận tốt nhất là chỉ thực hiện hành động bắt buộc và bắt ngoại lệ sẽ bị ném nếu quá trình này không chạy.

+0

@Michael, ý định ở đây rõ ràng. OP đặc biệt nói rằng họ muốn kiểm tra xem liệu Process2 có còn sống để họ có thể làm điều gì đó với nó hay không. – JaredPar

+1

Một vấn đề khác là PID có thể được tái sử dụng nhanh chóng. Vì vậy, nếu quá trình 2 chết, và PID được tái chế, bạn có thể nghĩ rằng quá trình của bạn vẫn đang chạy khi nó không phải là. –

34

Xử lý quy trình sẽ được báo hiệu nếu nó thoát.

Vì vậy, sau đây sẽ làm việc (lỗi xử lý loại bỏ cho ngắn gọn):

BOOL IsProcessRunning(DWORD pid) 
{ 
    HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid); 
    DWORD ret = WaitForSingleObject(process, 0); 
    CloseHandle(process); 
    return ret == WAIT_TIMEOUT; 
} 

Lưu ý rằng ID quá trình có thể được tái chế - nó tốt hơn để bộ nhớ cache xử lý được trả về từ cuộc gọi CreateProcess.

Bạn cũng có thể sử dụng API của threadpool (SetThreadpoolWait trên Vista +, RegisterWaitForSingleObject trên các nền tảng cũ hơn) để nhận cuộc gọi lại khi quá trình thoát.

EDIT: Tôi đã bỏ lỡ phần "muốn làm điều gì đó cho quá trình" của câu hỏi gốc. Bạn có thể sử dụng kỹ thuật này nếu nó là ok để có dữ liệu cũ có khả năng cho một số cửa sổ nhỏ hoặc nếu bạn muốn thất bại một hoạt động mà không cần thử nó. Bạn sẽ vẫn phải xử lý trường hợp hành động không thành công vì quá trình đã thoát.

+3

Điều này nên có tiêu đề WasProcessRunning, đó là một sai tên gọi IsProcessRunning – JaredPar

+0

Mã rất cẩu thả. Và nơi nào bạn kiểm tra xem HANDLE trong biến 'process' có phải là NULL không? – Elmue

58

Bạn có thể sử dụng GetExitCodeProcess. Nó sẽ trở lại STILL_ACTIVE() nếu quá trình này vẫn chạy (hoặc nếu nó xảy ra để thoát với mã thoát :().

+1

+1 cho việc sử dụng 'GetExitCodeProcess', cho rằng Process1 của OP có thể lưu xử lý của Process2 sau khi nó gọi' CreateProcess' (một điểm bị bỏ qua bởi tất cả những người khác đã trả lời ở đây) và xử lý đó có thể được đưa vào 'GetExitCodeProcess' – vladr

+0

wow Tốt hơn là sử dụng OpenProcess (PROCESS_QUERY_INFORMATION thanks! – rogerdpack

+0

Câu trả lời hay nhất – dns

1

gọi EnumProcesses() và kiểm tra xem PID là trong danh sách.

http://msdn.microsoft.com/en-us/library/ms682629%28VS.85%29.aspx

+5

Nếu quá trình 2 đã chết, PID có thể được tái chế. –

+1

http://stackoverflow.com/questions/2384022/winsdk-determining-whether-an-arbitrary -pid-identification-a-running-process-on-win có câu trả lời ith một ví dụ về vòng lặp qua, nếu đó là hữu ích – rogerdpack

1

JaredPar là đúng ở chỗ bạn không thể biết nếu quá trình đang chạy. bạn chỉ có thể biết nếu quá trình đang chạy tại thời điểm bạn kiểm tra. Nó có thể đã chết trong thời gian trung bình.

bạn cũng phải nhận thức được các PID có thể được recy bám khá nhanh. Vì vậy, chỉ vì có một quá trình ở đó với PID của bạn, nó không có nghĩa rằng đó là quá trình của bạn.

Có các quá trình chia sẻ GUID. (Quy trình 1 có thể tạo GUID và chuyển nó cho Quy trình 2 trên dòng lệnh.) Quy trình 2 nên tạo một mutex có tên với GUID đó.Khi Process 1 muốn kiểm tra, nó có thể thực hiện WaitForSingleObject trên mutex với thời gian chờ là 0. Nếu Process 2 đã biến mất, mã trả về sẽ cho bạn biết rằng mutex đã bị hủy bỏ, nếu không bạn sẽ bị hết thời gian chờ.

6

Một cách khác để giám sát một đứa trẻ quá trình là tạo ra một sợi công nhân đó sẽ:

  1. gọi CreateProcess()
  2. gọi WaitForSingleObject() // tại các sợi nhân sẽ đợi cho đến khi từ trẻ quá trình kết thúc thực hiện. có thể lấy mã trả về (từ hàm main()).
6

Tôi thấy điều này ngày hôm nay, đó là từ năm 2003. Nó tìm thấy một quá trình theo tên, bạn thậm chí không cần 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; 

} 
0

Bạn có thể tìm thấy nếu một quá trình (được đặt tên hoặc PID của nó) đang chạy hay không bằng cách duyệt qua các tiến trình đang chạy chỉ đơn giản bằng cách lấy một bản chụp của tiến trình đang chạy qua CreateToolhelp32Snapshot, và bằng cách sử dụng Process32First và Process32Next kêu gọi rằng ảnh chụp nhanh.

Sau đó, bạn có thể sử dụng trường th32ProcessID hoặc trường szExeFile của kết quả PROCESSENTRY32 tùy thuộc vào việc bạn muốn tìm kiếm theo PID hay tên thực thi. Việc triển khai đơn giản có thể được tìm thấy here.

+0

Chỉ cần câu trả lời liên kết được coi là không hữu ích, nó sẽ là tốt nhất nếu bạn có thể mở rộng câu trả lời của bạn. Có thể với một lời giải thích ngắn gọn về những gì chúng ta có thể tìm thấy trong bài viết. – madth3

16
#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; 
} 
+1

bạn có thể xem xét thêm ngắt khi tồn tại được đặt thành true để tăng tốc độ lên một chút –

+1

Chu trình làm trong khi() sẽ tốt hơn ở đây vì mục nhập do Process32First tìm thấy có thể là đúng. –

1

Khi viết công cụ theo dõi, tôi đã thực hiện một cách tiếp cận hơi khác.

Nó cảm thấy một chút lãng phí để quay lên một sợi chỉ để sử dụng WaitForSingleObject hoặc thậm chí RegisterWaitForSingleObject (mà làm điều đó cho bạn). Vì trong trường hợp của tôi tôi không cần phải biết chính xác ngay lập tức một quá trình đã đóng cửa, chỉ là nó thực sự đã đóng cửa.

Tôi đang sử dụng GetProcessTimes() thay vì:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx

GetProcessTimes() sẽ trả về một struct FILETIME cho ExitTime của quá trình chỉ khi quá trình này đã thực sự kết thúc. Vì vậy, chỉ là vấn đề kiểm tra nếu cấu trúc ExitTime được điền và nếu thời gian không phải là 0;

Giải pháp này NÊN giải thích trường hợp quá trình đã bị giết nhưng PID của nó đã được sử dụng lại bởi một quy trình khác. GetProcessTimes cần một xử lý cho quá trình, không phải là PID. Vì vậy, các hệ điều hành nên biết rằng xử lý là một quá trình đang chạy tại một số điểm, nhưng không phải bất kỳ chi tiết, và cung cấp cho bạn thời gian xuất cảnh.

Dựa vào ExitCode cảm thấy bị bẩn:/

+0

Theo MSDN, "Nếu quá trình chưa thoát, nội dung của cấu trúc này là không xác định" nơi "cấu trúc này" đang đề cập đến 'FILETIME'. –

0

Đây là giải pháp mà tôi đã sử dụng trong quá khứ. Mặc dù ví dụ ở đây là trong VB.net - Tôi đã sử dụng kỹ thuật này với c và C++. Nó bỏ qua tất cả các vấn đề với ID tiến trình & Xử lý quy trình và mã trả lại. Windows rất trung thành trong việc phát hành mutex cho dù Process2 đã kết thúc như thế nào. Tôi hy vọng nó hữu ích cho ai đó ...

**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 
Các vấn đề liên quan