指定したアプリケーションが起動中か調べる

通常、アプリケーションが起動中かどうかはCreateProcess()で起動し
プロセスハンドルを保持して起動中か判断しますが
CreateProcess()で起動しないとプロセスハンドルを得ることが出来ません。
そこでアプリケーションのパスからそのアプリケーションが起動中か
調べる方法を紹介します。

まずは以下の関数を作成します。


#include <tlhelp32.h>             // 追加する
#pragma comment(lib, "th32.lib")  // 追加する

BOOL fCheckExistProcess95(LPCTSTR pszExeName)
{
    PROCESSENTRY32 pe32 = {0};
    BOOL fOK;
    BOOL fFind = FALSE;

    HANDLE hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(!hSnapshot)
        return FALSE;

    pe32.dwSize = sizeof(pe32);
    if(!::Process32First(hSnapshot, &pe32))
        return FALSE;

    do{
        if(lstrcmpi(pe32.szExeFile, pszExeName) == 0)
        {
            fFind = TRUE;
            continue;
        }
        fOK = ::Process32Next(hSnapshot, &pe32);
    } while(fOK && (!fFind));

    ::CloseHandle(hSnapshot);

    return fFind;
}

ハイ、長いですね。
実は私はこれが何をやっているかは分かりませんので詳しい説明は出来ません。(^^;
某掲示板に有ったソースをちょっと見やすく書き直しただけです。

この関数は引数に実行ファイルのパスを渡すと戻り値で
そのアプリケーションが起動中ならTRUEが戻ってきます。

しかしこの関数は名前からみても分かるようにWin95系でしか使えません。
WinNT系では以下の方法で判断できます。


#include <winperf.h>  // 追加する

BOOL fCheckExistProcessNT(LPCTSTR pszExeName)
{
    const LPTSTR c_szRegKeyPerf =
        _T("software\\microsoft\\windows nt\\currentversion\\perflib");
    const LPTSTR c_szRegSubkeyCounters = _T("Counters");  // COUNTERサブキー
    const LPTSTR c_szProcessCounter = _T("process");
    const LPTSTR c_szProcessIdCounter = _T("id process");
    const DWORD c_dwInitialSize = 51200L;
    const DWORD c_szExtendSize = 25600L;
    DWORD dwNumTasks;  // 最大タスク数
    HKEY hKeyNames;
    CString cstrKey, cstrSubKey;
    LANGID lid;
    LPBYTE p;
    LPBYTE p2;
    DWORD dwProcessIdTitle;
    DWORD dwSize,dwType;
    PPERF_DATA_BLOCK pPerf;
    PPERF_OBJECT_TYPE pObj;
    PPERF_INSTANCE_DEFINITION pInst;
    PPERF_COUNTER_BLOCK pCounter;
    PPERF_COUNTER_DEFINITION pCounterDef;
    DWORD i;
    DWORD dwProcessIdCounter;
    LPBYTE buf = NULL;
    CString cstrProcessName;
    DWORD dwValueSize;
    long lRet;
    int iRet;
    BOOL fOK = FALSE;

    // 日本語
    lid = MAKELANGID(LANG_JAPANESE, SUBLANG_NEUTRAL);
    cstrKey.Format(_T("%s\\%03x"), c_szRegKeyPerf, lid);

    if(ERROR_SUCCESS != ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cstrKey,
                                       0, KEY_READ, &hKeyNames))
        goto exit;

    // get the buffer size for the counter names
    if(ERROR_SUCCESS != ::RegQueryValueEx(hKeyNames, c_szRegSubkeyCounters,
                                          NULL, &dwType, NULL, &dwSize))
        goto exit;

    // allocate the counter names buffer
    buf = new BYTE [dwSize];
    if(buf == NULL)
        goto exit;

    memset(buf, 0, dwSize);
    // read the counter names from the registry
    if(ERROR_SUCCESS != ::RegQueryValueEx(hKeyNames, c_szRegSubkeyCounters,
                                          NULL, &dwType, buf, &dwSize))
        goto exit;

    p = buf;
    while(*p){
        if(p > buf)
            for(p2 = p - 2; isdigit(*p2); p2--);

        if(::lstrcmpi((LPSTR)p, c_szProcessCounter) == 0 )
        {
            // look backwards for the counter number
            for(p2 = p - 2; isdigit(*p2); p2--);
            cstrSubKey = p2 + 1;
        }
        else if(::lstrcmpi((LPSTR)p, c_szProcessIdCounter) == 0)
        {
            // look backwards for the counter number
            for(p2 = p - 2; isdigit(*p2); p2--);
            dwProcessIdTitle = atol((LPSTR)(p2+1));
        }
        // next string
        p += (lstrlen((LPSTR)p) + 1);
    }
    // free the counter names buffer
    if(buf)
        delete [] buf;

    // allocate the initial buffer for the performance data
    dwSize = c_dwInitialSize;
    buf = new BYTE[dwSize];
    if(buf == NULL)
        goto exit;

    memset(buf, 0, dwSize);
    while(TRUE)
    {
        dwValueSize = dwSize;
        lRet = ::RegQueryValueEx(HKEY_PERFORMANCE_DATA,
                                 cstrSubKey.GetBuffer(128), NULL, NULL,
                                 buf, &dwValueSize);
        cstrSubKey.ReleaseBuffer();
        pPerf = (PPERF_DATA_BLOCK) buf;
        // perfデータプロックのシグニチャチェック
        if((lRet == ERROR_SUCCESS) &&
           (dwSize > 0) &&
           (pPerf)->Signature[0] == (WCHAR)'P' &&
           (pPerf)->Signature[1] == (WCHAR)'E' &&
           (pPerf)->Signature[2] == (WCHAR)'R' &&
           (pPerf)->Signature[3] == (WCHAR)'F')
            break;

        // 領域の拡大
        if(lRet == ERROR_MORE_DATA)
        {
            dwSize += c_szExtendSize;
            delete [] buf;
            buf = new BYTE[dwSize];
            if(buf == NULL)
                goto exit;

            memset(buf, 0, dwSize);
        }
        else
            goto exit;
    }

    // perf_object_type ポインタセット
    pObj = (PPERF_OBJECT_TYPE)((DWORD)pPerf + pPerf->HeaderLength);

    // loop thru the performance counter definition records looking
    // for the process id counter and then save its offset
    pCounterDef = (PPERF_COUNTER_DEFINITION)((DWORD)pObj + pObj->HeaderLength);
    for(i = 0; i < (DWORD)pObj->NumCounters; i++)
    {
        if(pCounterDef->CounterNameTitleIndex == dwProcessIdTitle)
        {
            dwProcessIdCounter = pCounterDef->CounterOffset;
            break;
        }
        pCounterDef++;
    }

    dwNumTasks = (DWORD)pObj->NumInstances;

    pInst = (PPERF_INSTANCE_DEFINITION)((DWORD)pObj + pObj->DefinitionLength);

    // パフォーマンスインスタンスデータよりプロセス名サーチ
    for(i = 0 ; i < dwNumTasks ; i++)
        {
        // プロセス名へのポインタ
        p = (LPBYTE)((DWORD)pInst + pInst->NameOffset);
        cstrProcessName.Empty();
        if(!::IsBadStringPtr((LPSTR)p, MAX_PATH))
        {
            // Unicode から asciiに変換
            iRet = ::WideCharToMultiByte(CP_ACP,
                                         0,
                                         (LPCWSTR)p,
                                         -1,
                                         cstrProcessName.GetBuffer(MAX_PATH),
                                         MAX_PATH,
                                         NULL,
                                         NULL);
            cstrProcessName.ReleaseBuffer();
            cstrProcessName += _T(".exe");
            if(iRet > 0)
            {
                CString cstrName;
                LPSTR pszFilePart;
                ::GetFullPathName(pszExeName, MAX_PATH,
                                  cstrName.GetBuffer(MAX_PATH), &pszFilePart);
                cstrName.ReleaseBuffer();
                cstrName = pszFilePart;
                if(0 == cstrProcessName.CompareNoCase(cstrName))
                {
                    fOK = TRUE;
                    break;
                }
            }
        }
        pCounter = (PPERF_COUNTER_BLOCK)((DWORD)pInst + pInst->ByteLength);
        // next process
        pInst = (PPERF_INSTANCE_DEFINITION)((DWORD)pCounter + pCounter->ByteLength);
    }

exit:

    ::RegCloseKey(hKeyNames);
    ::RegCloseKey(HKEY_PERFORMANCE_DATA);
    if(buf)
        delete [] buf;

    return fOK;
}

ハイ、ものすごく長いですね。(笑)
当然なにをやってるかなんてサッパリです。
ただこの関数も引数にアプリケーションのパスを渡すと
戻り値で起動中ならTRUEを返してきます。

さてこれをWin95系とNT系に対応しなければなりませんが
それには使用しているOSが何かを調べる必要があります。
GetVersionEx()というAPIでOSのバージョンを調べられるのでそれを利用します。


// 95系かNT系かを調べる。
OSVERSIONINFO osInfo;
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osInfo);
BOOL res;
char lpCommandLine[] = _T("アプリケーションのパス");

if(osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
    res = fCheckExistProcess95(lpCommandLine);
else
    res = fCheckExistProcessNT(lpCommandLine);

// 状態の表示
if(res)
    AfxMessageBox(_T("起動しています。"));
else
    AfxMessageBox(_T("起動していません。"));

と、こんな感じで判断してそれに合った関数を呼び出せばOKでしょう。

GetVersionEx()の引数のOSVERSIONINFO構造体にOSの情報が格納されます。
この構造体のdwPlatformIdVER_PLATFORM_WIN32_WINDOWSならWin95系で
VER_PLATFORM_WIN32_NTならWinNT系です。

それからGetVersionEx()を呼び出す前にOSVERSIONINFO構造体の
dwOSVersionInfoSizeメンバをsizeof(OSVERSIONINFO)で初期化する必要があります。

以上で終わりですが起動チェックの関数はマジで分かりません。
もし不具合が有っても直す事は不可能でしょう。(^^;

< 戻る << HOME ©1999-2001 by Akky, All right reserved.