Solía realizar esta tarea abriendo el proceso y después usar la la API OpenProcessToken para obtener el SID y usarlo en LookupAccountSid. Pero este sistema no funciona para algunos procesos y no obtiene los de usuarios distintos por problema de privilegios en la API OpenProcessToken.
He implementado una función que evita el problema. Se basa en la enumeración con la poco conocida WTSEnumerateProcesses. El código en delphi es el siguiente:
delphi
type WTS_PROCESS_INFO = record SessionId: DWORD; // session id ProcessId: DWORD; // process id pProcessName: LPSTR; // name of process pUserSid: PSID; // user's SID end; PWTS_PROCESS_INFO = ^WTS_PROCESS_INFO; TA_WTS_PROCESS_INFO = array of WTS_PROCESS_INFO; PTA_WTS_PROCESS_INFO = ^TA_WTS_PROCESS_INFO; function WTSEnumerateProcessesA(hServer: Cardinal; Reserved: DWORD; Version: DWORD; var ppProcessInfo: PWTS_PROCESS_INFO; var pCount: DWORD): BOOL; stdcall external 'Wtsapi32.dll'; procedure WTSFreeMemory(pMemory: Pointer); stdcall external 'Wtsapi32.dll'; implementation function GetUserAndDomainFromPID(ProcessId: Cardinal; var User, Domain: String): boolean; var snu: SID_NAME_USE; pProcessInfo: TA_WTS_PROCESS_INFO; nProc,UserSize, DomainSize: Cardinal; begin Result:= false; nProc:= 0; UserSize:= 0; DomainSize:= 0; if WTSEnumerateProcessesA(0, 0, 1, PWTS_PROCESS_INFO(pProcessInfo), nProc) then begin repeat dec(nProc) until (nProc <= 0) or (ProcessId = pProcessInfo[nProc].ProcessId); LookupAccountSid(nil, pProcessInfo[nProc].pUserSid, nil, UserSize, nil, DomainSize, snu); if (UserSize <> 0) or (DomainSize <> 0) then begin SetLength(User, UserSize); SetLength(Domain, DomainSize); Result:= LookupAccountSid(nil, pProcessInfo[nProc].pUserSid, @User[1], UserSize, @Domain[1], DomainSize, snu); end; WTSFreeMemory(pProcessInfo); end; end;
Con un ejemplo de uso:
delphi
procedure TForm1.Button1Click(Sender: TObject); var User, Domain: String; begin GetUserAndDomainFromPID(StrToInt(Edit1.Text), User, Domain); Label1.Caption:= User; Label2.Caption:= Domain; end;
La versión C/C++ Builder sería como sigue:
cpp
#include <wtsapi32.h> #pragma link "Wtsapi32.lib" bool GetUserAndDomainFromPID(DWORD ProcessId, String &User, String &Domain) { SID_NAME_USE snu; bool Result = false; PWTS_PROCESS_INFO pProcessInfo; DWORD nProc = 0; DWORD UserSize=0, DomainSize=0; if(WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pProcessInfo, &nProc)){ while(--nProc > 0 && ProcessId != pProcessInfo[nProc].ProcessId); LookupAccountSid(NULL, pProcessInfo[nProc].pUserSid, NULL, &UserSize, NULL, &DomainSize, &snu); if(UserSize && DomainSize){ User.SetLength(UserSize); Domain.SetLength(DomainSize); Result = LookupAccountSid(NULL, pProcessInfo[nProc].pUserSid, &User[1], &UserSize, &Domain[1], &DomainSize, &snu); } WTSFreeMemory(pProcessInfo); } return Result; }
Y un ejemplo similar al de delphi:
cpp
void __fastcall TForm1::Button1Click(TObject *Sender) { String User, Domain; GetUserAndDomainFromPID(StrToInt(Edit1->Text), User, Domain); Label1->Caption = User; Label2->Caption = Domain; }
Con esto conseguimos los datos de todos los procesos con una excepción, los que corresponden al proceso con Pid = 0. Todos sabemos que ese proceso es el proceso inactivo del sistema ([System Process]) cuyo usuario es SYSTEM y el dominio NT AUTHORITY
Espero que sea de utilidad.
Saludos.