Back to index

lightning-sunbird  0.9+nobinonly
process.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2003
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Sean Su <ssu@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "process.h"
00039 #include "extern.h"
00040 #include "extra.h"
00041 #include "dialogs.h"
00042 #include <tlhelp32.h>
00043 #include <winperf.h>
00044 
00045 #define INDEX_STR_LEN               10
00046 #define PN_PROCESS                  TEXT("Process")
00047 #define PN_PROCESS_ID               TEXT("ID Process")
00048 #define PN_THREAD                   TEXT("Thread")
00049 
00050 /* CW: Close Window */
00051 #define CW_CLOSE_ALL               0x00000001
00052 #define CW_CLOSE_VISIBLE_ONLY      0x00000002
00053 #define CW_CHECK_VISIBLE_ONLY      0x00000003
00054 
00055 typedef PERF_DATA_BLOCK             PERF_DATA,      *PPERF_DATA;
00056 typedef PERF_OBJECT_TYPE            PERF_OBJECT,    *PPERF_OBJECT;
00057 typedef PERF_INSTANCE_DEFINITION    PERF_INSTANCE,  *PPERF_INSTANCE;
00058 typedef BOOL   (WINAPI *NS_ProcessWalk)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
00059 typedef HANDLE (WINAPI *NS_CreateSnapshot)(DWORD dwFlags, DWORD th32ProcessID);
00060 
00061 TCHAR   INDEX_PROCTHRD_OBJ[2*INDEX_STR_LEN];
00062 DWORD   PX_PROCESS;
00063 DWORD   PX_PROCESS_ID;
00064 DWORD   PX_THREAD;
00065 
00066 BOOL _FindAndKillProcessNT4(LPSTR aProcessName,
00067                          BOOL aKillProcess);
00068 BOOL KillProcess(char *aProcessName, HWND aHwndProcess, DWORD aProcessID);
00069 DWORD GetTitleIdx(HWND hWnd, LPTSTR Title[], DWORD LastIndex, LPTSTR Name);
00070 PPERF_OBJECT FindObject (PPERF_DATA pData, DWORD TitleIndex);
00071 PPERF_OBJECT NextObject (PPERF_OBJECT pObject);
00072 PPERF_OBJECT FirstObject (PPERF_DATA pData);
00073 PPERF_INSTANCE   NextInstance (PPERF_INSTANCE pInst);
00074 PPERF_INSTANCE   FirstInstance (PPERF_OBJECT pObject);
00075 DWORD   GetPerfData    (HKEY        hPerfKey,
00076                         LPTSTR      szObjectIndex,
00077                         PPERF_DATA  *ppData,
00078                         DWORD       *pDataSize);
00079 BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM aParam);
00080 
00081 typedef struct _CAWOWH
00082 {
00083   DWORD cwState;
00084   DWORD processID;
00085 } CAWOWH;
00086 
00087 typedef struct _kpf
00088 {
00089   NS_CreateSnapshot pCreateToolhelp32Snapshot;
00090   NS_ProcessWalk    pProcessWalkFirst;
00091   NS_ProcessWalk    pProcessWalkNext;
00092 } kpf;
00093 
00094 BOOL _FindAndKillProcess(kpf *kpfRoutines, LPSTR aProcessName, BOOL aKillProcess);
00095 
00096 
00097 
00098 
00099 /* Function: FindAndKillProcess()
00100  *
00101  *       in: LPSTR aProcessName: Name of process to find and kill
00102  *           BOOL  aKillProcess: Indicates whether to kill the process
00103  *                               or not.
00104  *  purpose: To find and kill a given process name currently running.
00105  */
00106 BOOL FindAndKillProcess(LPSTR aProcessName, BOOL aKillProcess)
00107 {
00108   HANDLE hKernel       = NULL;
00109   BOOL   bDoWin95Check = TRUE;
00110   kpf    kpfRoutines;
00111 
00112   if((hKernel = GetModuleHandle("kernel32.dll")) == NULL)
00113     return(FALSE);
00114 
00115   kpfRoutines.pCreateToolhelp32Snapshot = (NS_CreateSnapshot)GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
00116   kpfRoutines.pProcessWalkFirst         = (NS_ProcessWalk)GetProcAddress(hKernel,    "Process32First");
00117   kpfRoutines.pProcessWalkNext          = (NS_ProcessWalk)GetProcAddress(hKernel,    "Process32Next");
00118 
00119   if(kpfRoutines.pCreateToolhelp32Snapshot && kpfRoutines.pProcessWalkFirst && kpfRoutines.pProcessWalkNext)
00120     return(_FindAndKillProcess(&kpfRoutines, aProcessName, aKillProcess));
00121   else
00122     return(_FindAndKillProcessNT4(aProcessName, aKillProcess));
00123 }
00124 
00125 /* Function: KillProcess()
00126  *
00127  *       in: LPSTR aProcessName: Name of process to find and kill
00128  *           BOOL  aKillProcess: Indicates whether to kill the process
00129  *                               or not.
00130  *  purpose: To find and kill a given process name currently running.
00131  */
00132 BOOL KillProcess(char *aProcessName, HWND aHwndProcess, DWORD aProcessID)
00133 {
00134   BOOL rv = FALSE;
00135   HWND hwndProcess;
00136 
00137   hwndProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, aProcessID);
00138   if(!hwndProcess)
00139     return(rv);
00140 
00141   if(!TerminateProcess(hwndProcess, 1))
00142   {
00143     char errorMsg[MAX_BUF];
00144 
00145     if(GetPrivateProfileString("Messages", "ERROR_TERMINATING_PROCESS", "", errorMsg, sizeof(errorMsg), szFileIniUninstall))
00146     {
00147       char buf[MAX_BUF];
00148 
00149       wsprintf(buf, errorMsg, aProcessName);
00150       PrintError(buf, ERROR_CODE_SHOW);
00151     }
00152   }
00153   else
00154     rv = TRUE;
00155 
00156   CloseHandle(hwndProcess);
00157   return(rv);
00158 }
00159 
00160 // Windows callback function that processes each window found to be running.
00161 // This function will close all the visible and invisible windows that
00162 // match a processes passed in from aParam.
00163 BOOL CALLBACK EnumWindowsProc(HWND aHwnd, LPARAM aParam)
00164 {
00165   BOOL   rv = TRUE;
00166   DWORD  processID;
00167   CAWOWH *closeWindowInfo = (CAWOWH *)aParam;
00168 
00169   GetWindowThreadProcessId(aHwnd, &processID);
00170   if(processID == closeWindowInfo->processID)
00171   {
00172     switch(closeWindowInfo->cwState)
00173     {
00174       case CW_CLOSE_ALL:
00175         SendMessageTimeout(aHwnd, WM_CLOSE, (WPARAM)1, (LPARAM)0, SMTO_NORMAL, WM_CLOSE_TIMEOUT_VALUE, NULL);
00176         break;
00177 
00178       case CW_CLOSE_VISIBLE_ONLY:
00179         // only close the windows that are visible
00180         if(GetWindowLong(aHwnd, GWL_STYLE) & WS_VISIBLE)
00181           SendMessageTimeout(aHwnd, WM_CLOSE, (WPARAM)1, (LPARAM)0, SMTO_NORMAL, WM_CLOSE_TIMEOUT_VALUE, NULL);
00182         break;
00183 
00184       case CW_CHECK_VISIBLE_ONLY:
00185         /* Check for visible windows.  If there are any, then the previous
00186          * call to close all visible windows had failed (most likely due
00187          * to user canceling a save request on a window) */
00188         if(GetWindowLong(aHwnd, GWL_STYLE) & WS_VISIBLE)
00189           rv = FALSE;
00190         break;
00191     }
00192   }
00193 
00194   return(rv); // Returning TRUE will continue with the enumeration!
00195               // it will automatically stop when there's no more
00196               // windows to process.
00197               // Returning FALSE will stop immediately.
00198 }
00199 
00200 
00201 /* Function: CloseAllWindowsOfWindowHandle()
00202  *
00203  *       in: HWND aHwndWindow: Handle to the process window to close.
00204  *           char *aMsgWait  : Message to show while closing the windows.
00205  *
00206  *  purpose: To quit an application by closing all of its vibible and
00207  *           invisible windows.  There are 3 states to closing all windows:
00208  *            1) Close all visible windows
00209  *            2) Check to make sure all visible windows have been closed.
00210  *               The user could be in editor and not want to close that
00211  *               particular window just yet.
00212  *            3) Close the rest of the windows (invisible or not) if 2)
00213  *               passed.
00214  */
00215 BOOL CloseAllWindowsOfWindowHandle(HWND aHwndWindow, char *aMsgWait)
00216 {
00217   CAWOWH closeWindowInfo;
00218   BOOL  rv = TRUE;
00219 
00220   assert(aHwndWindow);
00221   assert(aMsgWait);
00222   if(*aMsgWait != '\0')
00223     ShowMessage(aMsgWait, TRUE);
00224 
00225   GetWindowThreadProcessId(aHwndWindow, &closeWindowInfo.processID);
00226 
00227   /* only close the visible windows */
00228   closeWindowInfo.cwState = CW_CLOSE_VISIBLE_ONLY;
00229   EnumWindows(EnumWindowsProc, (LPARAM)&closeWindowInfo);
00230 
00231   /* only check to make sure that the visible windows were closed */
00232   closeWindowInfo.cwState = CW_CHECK_VISIBLE_ONLY;
00233   rv = EnumWindows(EnumWindowsProc, (LPARAM)&closeWindowInfo);
00234   if(rv)
00235   {
00236     /* All visible windows have been closed.  Close all remaining windows now */
00237     closeWindowInfo.cwState = CW_CLOSE_ALL;
00238     EnumWindows(EnumWindowsProc, (LPARAM)&closeWindowInfo);
00239   }
00240   if(*aMsgWait != '\0')
00241     ShowMessage(aMsgWait, FALSE);
00242 
00243   return(rv);
00244 }
00245 
00246 /* Function: _FindAndKillProcess()
00247  *
00248  *       in: LPSTR aProcessName: Name of process to find and kill
00249  *           BOOL  aKillProcess: Indicates whether to kill the process
00250  *                               or not.
00251  *  purpose: To find and kill a given process name currently running. This
00252  *           function only works under Win9x, Win2k, and WinXP systems.
00253  */
00254 BOOL _FindAndKillProcess(kpf *kpfRoutines, LPSTR aProcessName, BOOL aKillProcess)
00255 {
00256   BOOL            rv              = FALSE;
00257   HANDLE          hCreateSnapshot = NULL;
00258   PROCESSENTRY32  peProcessEntry;
00259   
00260   hCreateSnapshot = kpfRoutines->pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
00261   if(hCreateSnapshot == (HANDLE)-1)
00262     return(rv);
00263 
00264   peProcessEntry.dwSize = sizeof(PROCESSENTRY32);
00265   if(kpfRoutines->pProcessWalkFirst(hCreateSnapshot, &peProcessEntry))
00266   {
00267     char  szBuf[MAX_BUF];
00268 
00269     do
00270     {
00271       ParsePath(peProcessEntry.szExeFile, szBuf, sizeof(szBuf), PP_FILENAME_ONLY);
00272       
00273       /* do process name string comparison here */
00274       if(lstrcmpi(szBuf, aProcessName) == 0)
00275       {
00276         rv = TRUE;
00277         if(aKillProcess)
00278           KillProcess(aProcessName, NULL, peProcessEntry.th32ProcessID);
00279         else
00280           break;
00281       }
00282 
00283     } while(kpfRoutines->pProcessWalkNext(hCreateSnapshot, &peProcessEntry));
00284   }
00285 
00286   CloseHandle(hCreateSnapshot);
00287   return(rv);
00288 }
00289 
00290 //
00291 // The functions below were copied from MSDN 6.0:
00292 //
00293 //   \samples\vc98\sdk\sdktools\winnt\pviewer
00294 //
00295 // They were listed in the redist.txt file from the cd.
00296 // Only _FindAndKillProcessNT4() was modified to accomodate the setup needs.
00297 //
00298 /******************************************************************************\
00299  * *       This is a part of the Microsoft Source Code Samples.
00300  * *       Copyright (C) 1993-1997 Microsoft Corporation.
00301  * *       All rights reserved.
00302 \******************************************************************************/
00303 BOOL _FindAndKillProcessNT4(LPSTR aProcessName, BOOL aKillProcess)
00304 {
00305   BOOL          bRv;
00306   HKEY          hKey;
00307   DWORD         dwType;
00308   DWORD         dwSize;
00309   DWORD         dwTemp;
00310   DWORD         dwTitleLastIdx;
00311   DWORD         dwIndex;
00312   DWORD         dwLen;
00313   DWORD         pDataSize = 50 * 1024;
00314   LPSTR         szCounterValueName;
00315   LPSTR         szTitle;
00316   LPSTR         *szTitleSz;
00317   LPSTR         szTitleBuffer;
00318   PPERF_DATA    pData;
00319   PPERF_OBJECT  pProcessObject;
00320 
00321   bRv   = FALSE;
00322   hKey  = NULL;
00323 
00324   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
00325                   TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\perflib"),
00326                   0,
00327                   KEY_READ,
00328                   &hKey) != ERROR_SUCCESS)
00329     return(bRv);
00330 
00331   dwSize = sizeof(dwTitleLastIdx);
00332   if(RegQueryValueEx(hKey, TEXT("Last Counter"), 0, &dwType, (LPBYTE)&dwTitleLastIdx, &dwSize) != ERROR_SUCCESS)
00333   {
00334     RegCloseKey(hKey);
00335     return(bRv);
00336   }
00337     
00338 
00339   dwSize = sizeof(dwTemp);
00340   if(RegQueryValueEx(hKey, TEXT("Version"), 0, &dwType, (LPBYTE)&dwTemp, &dwSize) != ERROR_SUCCESS)
00341   {
00342     RegCloseKey(hKey);
00343     szCounterValueName = TEXT("Counters");
00344     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
00345                     TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"),
00346                     0,
00347                     KEY_READ,
00348                     &hKey) != ERROR_SUCCESS)
00349       return(bRv);
00350   }
00351   else
00352   {
00353     RegCloseKey(hKey);
00354     szCounterValueName = TEXT("Counter 009");
00355     hKey = HKEY_PERFORMANCE_DATA;
00356   }
00357 
00358   // Find out the size of the data.
00359   //
00360   dwSize = 0;
00361   if(RegQueryValueEx(hKey, szCounterValueName, 0, &dwType, 0, &dwSize) != ERROR_SUCCESS)
00362     return(bRv);
00363 
00364 
00365   // Allocate memory
00366   //
00367   szTitleBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, dwSize);
00368   if(!szTitleBuffer)
00369   {
00370     RegCloseKey(hKey);
00371     return(bRv);
00372   }
00373 
00374   szTitleSz = (LPTSTR *)LocalAlloc(LPTR, (dwTitleLastIdx + 1) * sizeof(LPTSTR));
00375   if(!szTitleSz)
00376   {
00377     if(szTitleBuffer != NULL)
00378     {
00379       LocalFree(szTitleBuffer);
00380       szTitleBuffer = NULL;
00381     }
00382 
00383     RegCloseKey(hKey);
00384     return(bRv);
00385   }
00386 
00387   // Query the data
00388   //
00389   if(RegQueryValueEx(hKey, szCounterValueName, 0, &dwType, (BYTE *)szTitleBuffer, &dwSize) != ERROR_SUCCESS)
00390   {
00391     RegCloseKey(hKey);
00392     if(szTitleSz)
00393       LocalFree(szTitleSz);
00394     if(szTitleBuffer)
00395       LocalFree(szTitleBuffer);
00396 
00397     return(bRv);
00398   }
00399 
00400   // Setup the TitleSz array of pointers to point to beginning of each title string.
00401   // TitleBuffer is type REG_MULTI_SZ.
00402   //
00403   szTitle = szTitleBuffer;
00404   while(dwLen = lstrlen(szTitle))
00405   {
00406     dwIndex = atoi(szTitle);
00407     szTitle = szTitle + dwLen + 1;
00408 
00409     if(dwIndex <= dwTitleLastIdx)
00410       szTitleSz[dwIndex] = szTitle;
00411 
00412     szTitle = szTitle + lstrlen(szTitle) + 1;
00413   }
00414 
00415   PX_PROCESS    = GetTitleIdx (NULL, szTitleSz, dwTitleLastIdx, PN_PROCESS);
00416   PX_PROCESS_ID = GetTitleIdx (NULL, szTitleSz, dwTitleLastIdx, PN_PROCESS_ID);
00417   PX_THREAD     = GetTitleIdx (NULL, szTitleSz, dwTitleLastIdx, PN_THREAD);
00418   wsprintf(INDEX_PROCTHRD_OBJ, TEXT("%ld %ld"), PX_PROCESS, PX_THREAD);
00419   pData = NULL;
00420   if(GetPerfData(HKEY_PERFORMANCE_DATA, INDEX_PROCTHRD_OBJ, &pData, &pDataSize) == ERROR_SUCCESS)
00421   {
00422     PPERF_INSTANCE pInst;
00423     DWORD          i = 0;
00424 
00425     pProcessObject = FindObject(pData, PX_PROCESS);
00426     if(pProcessObject)
00427     {
00428       LPSTR szPtrStr;
00429       int   iLen;
00430       char  szProcessNamePruned[MAX_BUF];
00431       char  szNewProcessName[MAX_BUF];
00432 
00433       if(sizeof(szProcessNamePruned) < (lstrlen(aProcessName) + 1))
00434       {
00435         if(hKey)
00436           RegCloseKey(hKey);
00437         if(szTitleSz)
00438           LocalFree(szTitleSz);
00439         if(szTitleBuffer)
00440           LocalFree(szTitleBuffer);
00441 
00442         return(bRv);
00443       }
00444 
00445       /* look for .exe and remove from end of string because the Process names
00446        * under NT are returned without the extension */
00447       lstrcpy(szProcessNamePruned, aProcessName);
00448       iLen = lstrlen(szProcessNamePruned);
00449       szPtrStr = &szProcessNamePruned[iLen - 4];
00450       if((lstrcmpi(szPtrStr, ".exe") == 0) || (lstrcmpi(szPtrStr, ".dll") == 0))
00451         *szPtrStr = '\0';
00452 
00453       pInst = FirstInstance(pProcessObject);
00454       for(i = 0; i < (DWORD)(pProcessObject->NumInstances); i++)
00455       {
00456         *szNewProcessName = '\0';
00457         if(WideCharToMultiByte(CP_ACP,
00458                                0,
00459                                (LPCWSTR)((PCHAR)pInst + pInst->NameOffset),
00460                                -1,
00461                                szNewProcessName,
00462                                MAX_BUF,
00463                                NULL,
00464                                NULL) != 0)
00465         {
00466           if(lstrcmpi(szNewProcessName, szProcessNamePruned) == 0)
00467           {
00468             if(aKillProcess)
00469               KillProcess(aProcessName, NULL, PX_PROCESS_ID);
00470             bRv = TRUE;
00471             break;
00472           }
00473         }
00474 
00475         pInst = NextInstance(pInst);
00476       }
00477     }
00478   }
00479 
00480   if(hKey)
00481     RegCloseKey(hKey);
00482   if(szTitleSz)
00483     LocalFree(szTitleSz);
00484   if(szTitleBuffer)
00485     LocalFree(szTitleBuffer);
00486 
00487   return(bRv);
00488 }
00489 
00490 
00491 //*********************************************************************
00492 //
00493 //  GetPerfData
00494 //
00495 //      Get a new set of performance data.
00496 //
00497 //      *ppData should be NULL initially.
00498 //      This function will allocate a buffer big enough to hold the
00499 //      data requested by szObjectIndex.
00500 //
00501 //      *pDataSize specifies the initial buffer size.  If the size is
00502 //      too small, the function will increase it until it is big enough
00503 //      then return the size through *pDataSize.  Caller should
00504 //      deallocate *ppData if it is no longer being used.
00505 //
00506 //      Returns ERROR_SUCCESS if no error occurs.
00507 //
00508 //      Note: the trial and error loop is quite different from the normal
00509 //            registry operation.  Normally if the buffer is too small,
00510 //            RegQueryValueEx returns the required size.  In this case,
00511 //            the perflib, since the data is dynamic, a buffer big enough
00512 //            for the moment may not be enough for the next. Therefor,
00513 //            the required size is not returned.
00514 //
00515 //            One should start with a resonable size to avoid the overhead
00516 //            of reallocation of memory.
00517 //
00518 DWORD   GetPerfData    (HKEY        hPerfKey,
00519                         LPTSTR      szObjectIndex,
00520                         PPERF_DATA  *ppData,
00521                         DWORD       *pDataSize)
00522 {
00523 DWORD   DataSize;
00524 DWORD   dwR;
00525 DWORD   Type;
00526 
00527 
00528     if (!*ppData)
00529         *ppData = (PPERF_DATA) LocalAlloc (LMEM_FIXED, *pDataSize);
00530 
00531 
00532     do  {
00533         DataSize = *pDataSize;
00534         dwR = RegQueryValueEx (hPerfKey,
00535                                szObjectIndex,
00536                                NULL,
00537                                &Type,
00538                                (BYTE *)*ppData,
00539                                &DataSize);
00540 
00541         if (dwR == ERROR_MORE_DATA)
00542             {
00543             LocalFree (*ppData);
00544             *pDataSize += 1024;
00545             *ppData = (PPERF_DATA) LocalAlloc (LMEM_FIXED, *pDataSize);
00546             }
00547 
00548         if (!*ppData)
00549             {
00550             LocalFree (*ppData);
00551             return ERROR_NOT_ENOUGH_MEMORY;
00552             }
00553 
00554         } while (dwR == ERROR_MORE_DATA);
00555 
00556     return dwR;
00557 }
00558 
00559 
00560 
00561 
00562 //*********************************************************************
00563 //
00564 //  FirstInstance
00565 //
00566 //      Returns pointer to the first instance of pObject type.
00567 //      If pObject is NULL then NULL is returned.
00568 //
00569 PPERF_INSTANCE   FirstInstance (PPERF_OBJECT pObject)
00570 {
00571     if (pObject)
00572         return (PPERF_INSTANCE)((PCHAR) pObject + pObject->DefinitionLength);
00573     else
00574         return NULL;
00575 }
00576 
00577 //*********************************************************************
00578 //
00579 //  NextInstance
00580 //
00581 //      Returns pointer to the next instance following pInst.
00582 //
00583 //      If pInst is the last instance, bogus data maybe returned.
00584 //      The caller should do the checking.
00585 //
00586 //      If pInst is NULL, then NULL is returned.
00587 //
00588 PPERF_INSTANCE   NextInstance (PPERF_INSTANCE pInst)
00589 {
00590 PERF_COUNTER_BLOCK *pCounterBlock;
00591 
00592     if (pInst)
00593         {
00594         pCounterBlock = (PERF_COUNTER_BLOCK *)((PCHAR) pInst + pInst->ByteLength);
00595         return (PPERF_INSTANCE)((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
00596         }
00597     else
00598         return NULL;
00599 }
00600 
00601 //*********************************************************************
00602 //
00603 //  FirstObject
00604 //
00605 //      Returns pointer to the first object in pData.
00606 //      If pData is NULL then NULL is returned.
00607 //
00608 PPERF_OBJECT FirstObject (PPERF_DATA pData)
00609 {
00610     if (pData)
00611         return ((PPERF_OBJECT) ((PBYTE) pData + pData->HeaderLength));
00612     else
00613         return NULL;
00614 }
00615 
00616 
00617 
00618 
00619 //*********************************************************************
00620 //
00621 //  NextObject
00622 //
00623 //      Returns pointer to the next object following pObject.
00624 //
00625 //      If pObject is the last object, bogus data maybe returned.
00626 //      The caller should do the checking.
00627 //
00628 //      If pObject is NULL, then NULL is returned.
00629 //
00630 PPERF_OBJECT NextObject (PPERF_OBJECT pObject)
00631 {
00632     if (pObject)
00633         return ((PPERF_OBJECT) ((PBYTE) pObject + pObject->TotalByteLength));
00634     else
00635         return NULL;
00636 }
00637 
00638 //*********************************************************************
00639 //
00640 //  FindObject
00641 //
00642 //      Returns pointer to object with TitleIndex.  If not found, NULL
00643 //      is returned.
00644 //
00645 PPERF_OBJECT FindObject (PPERF_DATA pData, DWORD TitleIndex)
00646 {
00647 PPERF_OBJECT pObject;
00648 DWORD        i = 0;
00649 
00650     if (pObject = FirstObject (pData))
00651         while (i < pData->NumObjectTypes)
00652             {
00653             if (pObject->ObjectNameTitleIndex == TitleIndex)
00654                 return pObject;
00655 
00656             pObject = NextObject (pObject);
00657             i++;
00658             }
00659 
00660     return NULL;
00661 }
00662 
00663 //********************************************************
00664 //
00665 //  GetTitleIdx
00666 //
00667 //      Searches Titles[] for Name.  Returns the index found.
00668 //
00669 DWORD GetTitleIdx(HWND hWnd, LPTSTR Title[], DWORD LastIndex, LPTSTR Name)
00670 {
00671   DWORD Index;
00672 
00673   for(Index = 0; Index <= LastIndex; Index++)
00674     if(Title[Index])
00675       if(!lstrcmpi (Title[Index], Name))
00676         return(Index);
00677 
00678   MessageBox(hWnd, Name, TEXT("Setup cannot find process title index"), MB_OK);
00679   return 0;
00680 }
00681