È davvero possibile. Il problema principale che si ha è che Windows dovrebbe essere visto come un server terminal e una sessione utente come una sessione remota. Il servizio dovrebbe essere in grado di avviare un processo eseguito nella sessione remota che appartiene all'utente.
A proposito, se si scrive un servizio che gira sotto Windows XP che non viene aggiunto a un dominio e si attiva la commutazione rapida utente, è possibile avere gli stessi problemi per avviare un processo in esecuzione sul secondo (terzo e così via) desktop degli utenti registrati.
Spero che tu abbia un token utente, che ricevi ad esempio per quanto riguarda la rappresentazione o hai un dwSessionId
di sessione. Se non lo avete potete provare utilizzare alcuni WTS-funzione (Servizi Desktop remoto API http://msdn.microsoft.com/en-us/library/aa383464.aspx, ad esempio WTSEnumerateProcesses
o WTSGetActiveConsoleSessionId
) o LSA-API per scoprire la sessione di utenti corrispondente (LsaEnumerateLogonSessions
vedere http://msdn.microsoft.com/en-us/library/aa378275.aspx e LsaGetLogonSessionData
vedere http://msdn.microsoft.com/en-us/library/aa378290.aspx) o ProcessIdToSessionId
(vedi http://msdn.microsoft.com/en-us/library/aa382990.aspx).
È possibile utilizzare GetTokenInformation
funzione con il parametro TokenSessionId
(vedi http://msdn.microsoft.com/en-us/library/aa446671.aspx) per ricevere l'ID di sessione dwSessionId
della sessione utenti se si conosce il gettone utenti hClient
.
BOOL bSuccess;
HANDLE hProcessToken = NULL, hNewProcessToken = NULL;
DWORD dwSessionId, cbReturnLength;
bSuccess = GetTokenInformation (hClient, TokenSessionId, &dwSessionId,
sizeof(DWORD), &cbReturnLength);
bSuccess = OpenProcessToken (GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken);
bSuccess = DuplicateTokenEx (hProcessToken, MAXIMUM_ALLOWED, NULL,
SecurityImpersonation,
TokenPrimary, &hNewProcessToken);
EnablePrivilege (SE_TCB_NAME);
bSuccess = SetTokenInformation (hNewProcessToken, TokenSessionId, &dwSessionId,
sizeof(DWORD));
bSuccess = CreateProcessAsUser (hNewProcessToken, NULL, szCommandToExecute, ...);
Questo codice solo uno schema. EnablePrivilege
è una semplice funzione utilizzata AdjustTokenPrivileges
per abilitare il privilegio SE_TCB_NAME
(vedere http://msdn.microsoft.com/en-us/library/aa446619.aspx come modello). È importante che il processo da cui si avvia un processo disponga del privilegio TCB, ma se il servizio viene eseguito con il Sistema locale si dispone di autorizzazioni sufficienti. A proposito, il frammento di codice seguente funziona non solo con l'account di sistema locale, ma l'account deve avere il privilegio SE_TCB_NAME
per poter cambiare la sessione corrente del server terminal.
Un'altra osservazione. Nel codice sopra iniziamo un nuovo processo con lo stesso account del processo corrente (ad esempio Sistema locale). Si modifica la modifica di un codice per utilizzare un altro account, ad esempio il token utente hClient
. È solo importante avere un primary token
. Se si dispone di un token di rappresentazione, è possibile convertirlo nel token principale esattamente come nel codice sopra.
Nella struttura STARTUPINFO
utilizzato in CreateProcessAsUser
si dovrebbe usare lpDesktop =
WinSta0 \ Default".
dipendono dai requisiti potrebbe essere anche necessario utilizzare CreateEnvironmentBlock
per creare un nuovo blocco di ambiente che si passerà alla nuova processo.
vi consiglio anche di leggere How to ensure process window launched by Process.Start(ProcessStartInfo) has focus of all Forms? dove descrivo come forzare che il processo sarà avviato in primo piano sul desktop degli utenti.
ses Quale dell'utente Sion? –
L'utente interattivo locale è ciò su cui mi sto concentrando. Sono principalmente interessato a bloccare la workstation dal servizio, ma ho la necessità di eseguire anche altri programmi, a seconda di determinate condizioni. – Brad