【问题标题】:Get Session ID of another process in C++在 C++ 中获取另一个进程的会话 ID
【发布时间】:2013-10-17 13:10:07
【问题描述】:

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

到目前为止一切顺利,这就是它在 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++ 中的这段代码。

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

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

【问题讨论】:

    标签: c# c++ winapi session process


    【解决方案1】:

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

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

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

    【讨论】:

    • 对于不同会话的进程,我得到的只是 0,但应该是 2。怎么了?
    • "如果函数失败,返回值为零。要获取扩展的错误信息,请调用GetLastError。"
    • @joe 我想回答你的问题,并使用 EnumProcesses 和 ProcessIdToSessionID 制作了一个小程序,以管理员身份运行(并让另一个用户登录)。它惨败。某些 PID(大多数)无法使用 ACCESS_DENIED 映射到 SessionId(例如:calc.exe,!?!),对于其他(极少数)我得到“2”(例如:winlogon.exe ...)。
    • @manuell:同样的问题。我注意到其他工具(来自 SysInterals 的 ProcessExplorer)可以从另一个用户进程读取会话 ID,而无需提升权限。上面显示的 C# 函数也可以做到这一点,所以必须有办法做到这一点。
    • @joe 也许通过 ntdll API,或者也许通过性能计数器。有什么办法可以看到.net Process 类的源码吗?
    【解决方案2】:

    正如 arx 所说,ProcessIdToSessionId 应该可以胜任。
    但不幸的是,就我而言,它会告诉我 ACCESS_DENIED 我感兴趣的进程。
    它为当前进程完成了它的工作。

    这是我的解决方案,使用NtQuerySystemInformation
    .NETs Process 类在内部使用相同的函数。

    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;
    }
    

    【讨论】:

    • @arx:仍然支持您的答案。关于SYSTEM_PROCESS_INFORMATION 结构的提示非常有用!
    【解决方案3】:

    列出所有 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 here SPI 结构的文档

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-04
      • 2013-03-23
      • 2023-03-11
      • 1970-01-01
      • 2013-02-28
      • 2016-05-08
      • 1970-01-01
      • 2011-07-24
      相关资源
      最近更新 更多