当我启动我的应用程序时,我试图弄清楚是否有另一个应用程序进程。我还试图弄清楚它是否在不同的用户会话中运行。
到目前为止一直很好,这就是它在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(当前和其他进程,当前和其他会话)
怎么做?
答案 0 :(得分:3)
ProcessIdToSessionId
函数将进程ID映射到会话ID。
您注意到这似乎需要.Net不需要的过多权限。
.Net确实从注册表中的HKEY_PERFORMANCE_DATA获取了一些流程数据,但这不包括会话ID。使用NtQuerySystemInformation
获取会话ID以返回SYSTEM_PROCESS_INFORMATION
个结构的数组。此结构没有很好地记录,但会话ID紧跟句柄计数(即,它是当前声明为BYTE Reserved4[4];
的字段)。 Microsoft不保证在未来版本的Windows中这种情况会继续存在。
答案 1 :(得分:1)
如arx所述,ProcessIdToSessionId
应该完成这项工作
但不幸的是,就我而言,它告诉我ACCESS_DENIED
我感兴趣的过程
它完成了当前流程的工作。
所以这是我的解决方案,使用NtQuerySystemInformation
.NET 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;
}
答案 2 :(得分: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 here
上SPI结构的文档