3

当我启动我的应用程序时,我会尝试弄清楚该应用程序是否还有另一个进程。我还试图弄清楚它是否在不同的用户会话中运行。

到目前为止一切顺利,这就是它在 C# 中的样子:

    private static bool isThereAnotherInstance() {
        string name = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
        Process[] pAll = Process.GetProcessesByName(name);
        Process pCurrent = Process.GetCurrentProcess();
        foreach (Process p in pAll) {
            if (p.Id == pCurrent.Id) continue;
            if (p.SessionId != pCurrent.SessionId) continue;
            return true;
        }
        return false;
    }

但是要求已经改变,我需要使用普通 WinAPI 的 C++ 中的这段代码。

到目前为止,我可以通过使用 , 等找到具有相同可执行路径的CreateToolhelp32Snapshot进程OpenProcess

缺少的部分是如何获取进程的会话 ID(当前和其他进程,以及当前和其他会话)
如何做到这一点?

4

3 回答 3

3

ProcessIdToSessionId函数将进程 ID 映射到会话 ID。

您注意到这似乎需要 .Net 不需要的过多权限。

.Net 确实从注册表中的 HKEY_PERFORMANCE_DATA 获取了一些进程数据,但这不包括会话 ID。使用NtQuerySystemInformation返回结构数组获取会话 ID SYSTEM_PROCESS_INFORMATION。这个结构没有很好的记录,但是会话 ID 紧跟在句柄计数之后(即,它是当前声明为 的字段BYTE Reserved4[4];)。Microsoft 不保证这将在未来的 Windows 版本中继续存在。

于 2013-10-17T16:03:08.857 回答
1

列出所有 PID、SID、EXE 的代码(“ala”任务管理器,有点)适用于我(Windows 7 64b)VS2012 Express

#include <stdio.h>
#include <tchar.h>

#include <Windows.h>
#include <Winternl.h>

#pragma comment( lib, "ntdll.lib" )

typedef LONG KPRIORITY; // Thread priority
typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    LARGE_INTEGER SpareLi1;
    LARGE_INTEGER SpareLi2;
    LARGE_INTEGER SpareLi3;
    LARGE_INTEGER CreateTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER KernelTime;
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    HANDLE UniqueProcessId;
    ULONG InheritedFromUniqueProcessId;
    ULONG HandleCount;
    BYTE Reserved4[4];
    PVOID Reserved5[11];
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD;

int _tmain(int argc, _TCHAR* argv[]) {

    SYSTEM_PROCESS_INFORMATION aSPI[ 1024 ];
    // could ask for actual needed size size and malloc (with few extra new processes bonus...)
    NTSTATUS nts = NtQuerySystemInformation( SystemProcessInformation, aSPI, sizeof( aSPI ), NULL );
    if ( NT_ERROR( nts ) ) return -1;

    char * pSPI = reinterpret_cast<char*>( &aSPI[ 0 ] );
    while ( true ) {
        SYSTEM_PROCESS_INFORMATION_DETAILD * pOneSPI = reinterpret_cast<SYSTEM_PROCESS_INFORMATION_DETAILD*>( pSPI );
        WCHAR * pwch = pOneSPI->ImageName.Buffer;
        if ( pwch == 0 || pOneSPI->ImageName.Length == 0 ) pwch = TEXT( "Unknown" );
        _tprintf( TEXT( "PID %d - SID %d EXE %s\n" ), pOneSPI->UniqueProcessId, *reinterpret_cast<LONG*>( &pOneSPI->Reserved4 ), pwch );
        if ( pOneSPI->NextEntryOffset ) pSPI += pOneSPI->NextEntryOffset;
        else break;
    } 

    return 0;
}

非常感谢@Oleg 在此处提供关于 SO 的 SPI 结构的文档

于 2013-10-18T15:31:16.570 回答
1

正如arx所提到的,ProcessIdToSessionId应该做这项工作。
但不幸的是,就我而言,它告诉我ACCESS_DENIED我感兴趣的流程。
它为当前流程工作。

所以这是我的解决方案,使用NtQuerySystemInformation.
.NETsProcess类在内部使用相同的功能。

typedef struct _SYSTEM_PROCESS_INFORMATION_BUG {
    //...
}

typedef NTSTATUS (WINAPI *PNtQuerySystemInformation) (
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    );

#ifndef NT_ERROR
#define NT_ERROR(Status) ((ULONG)(Status) >> 30 == 3)
#endif

#define PROCESSINFO_BUFFERSIZE (256*1024)

DLL_EXPORT int GetProcessIdFromPath2(char *exePath, int flags) {
    char exe[MAX_PATH], *exeName, file[MAX_PATH], *fileName;
    DWORD pidCurrent, sessionIdCurrent;
    int ret=-1;

    strcpy(exe, exePath);
    strupr(exe);
    exeName=getFileName(exe);

    pidCurrent = GetCurrentProcessId();
    if (!ProcessIdToSessionId(pidCurrent, &sessionIdCurrent)) sessionIdCurrent=0;
    HMODULE hNT = LoadLibrary("Ntdll.dll");
    if (hNT) {
        PNtQuerySystemInformation pNtQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(hNT, "NtQuerySystemInformation");
        if (pNtQuerySystemInformation) {
            SYSTEM_PROCESS_INFORMATION_BUG* processInfo;
            char *buffer = (char*)malloc(PROCESSINFO_BUFFERSIZE);
            if (!buffer) {
                ret=-3;
            }
            else {
                char *current=buffer;
                DWORD len;
                int count=0;
                NTSTATUS s = pNtQuerySystemInformation(SystemProcessInformation, buffer, PROCESSINFO_BUFFERSIZE, &len);
                if (NT_ERROR(s)) {
                    ret=-2;
                }
                else {
                    ret=0;
                    while(1) {
                        processInfo = (SYSTEM_PROCESS_INFORMATION_BUG*)current;
                        if (processInfo->ImageName.Buffer!=NULL){
                            wcstombs(file, processInfo->ImageName.Buffer, MAX_PATH-1);
                            strupr(file);
                            fileName=getFileName(file);
                            if (strcmp(fileName, exeName)==0) {
                                if (processInfo->UniqueProcessId!=pidCurrent) {
                                    if (processInfo->SessionId==sessionIdCurrent) {
                                        ret = processInfo->UniqueProcessId;
                                    }
                                }
                            }
                        }
                        if (processInfo->NextEntryOffset==0) break;
                        current+=processInfo->NextEntryOffset;
                        count++;
                    }
                }
                free(buffer);
                buffer=NULL;
            }
        }
        FreeLibrary(hNT);
    }
    return ret;
}
于 2013-10-18T14:19:53.197 回答