Trước hết, tôi xin cảm ơn tất cả những người làm việc trên trang này, họ rất hữu ích cho các nhà phát triển. Đây là khối phát triển đầu tiên của tôi sau 3 ngày. Tôi đã tìm kiếm giải pháp trên Internet nhưng không tìm thấy giải pháp nào cho vấn đề này.
Vì vậy, tôi đã phát triển một dịch vụ phải thực thi một chương trình bên ngoài trên Vista/seven/xp khi người dùng đăng nhập. Một số tính năng của dịch vụ này:
- tự động
- Không có sự tương tác.
- Phát hiện ID phiên của người dùng đã đăng nhập
Chạy ứng dụng GUI bên ngoài với tư cách là người dùng tương tác:
- Để đảm bảo phiên người dùng được mở, tôi đã liệt kê tất cả các quy trình "explorer.exe" và trích xuất Pid và SessionID của chúng bằng hàm msdn ProcessIdToSessionId
- Nếu SessionID của người dùng đã đăng nhập giống với ID phiên của quy trình "explorer.exe" này, thì tôi chắc chắn rằng máy tính để bàn "tốt" đang chạy, vì vậy bây giờ tôi có thể thực thi các chương trình bên ngoài. (Tôi nói máy tính để bàn "tốt" vì như bạn biết, nhiều phiên người dùng có thể được mở trên hệ thống)
Sau đó tôi chạy ứng dụng bằng chức năng này:
hàm RunInteractive(prog_filename: String; sessionID: Cardinal): boolean;
var hToken: THandle;
si: _STARTUPINFOA;
pi: _PROCESS_INFORMATION;
begin
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
SI.lpDesktop := nil;
nếu WTSQueryUserToken(sessionID, hToken)
sau đó bắt đầu
if CreateProcessAsUser(hToken, nil, PChar(prog_filename), nil, nil, False, 0, nil, PChar(ExtractFilePath(prog_filename)), si, pi)
thì kết quả:= đúng
kết quả khác := false;
end
khác Bắt đầu
kết quả := sai;
Kết thúc;
CloseHandle(hToken);
end;
Mã này hoạt động tốt trong hầu hết các trường hợp ngoại trừ một trường hợp: khi tôi thay đổi người dùng. Hãy để tôi giải thích nó bằng 2 người dùng đơn giản (Miền\user1 và Miền\user2):
- Để sạch sẽ, tôi đã cài đặt dịch vụ và khởi động lại hệ thống
- Tôi mở phiên với user1: chương trình bên ngoài được thực thi và tôi có thể thấy biểu mẫu của nó
- 我phiên họp kết thúc và mở phiên với user2: chương trình bên ngoài đã được thực thi và tôi có thể thấy biểu mẫu của nó.
Nếu tôi làm điều này X lần thì kết quả luôn giống nhau, khá tốt... Nhưng nếu tôi làm điều này:
- Tôi đã cài đặt lại dịch vụ và khởi động lại hệ thống
- Tôi mở phiên với user1: chương trình bên ngoài được thực thi và tôi có thể thấy biểu mẫu của nó
- Lần này, tôiphiên không đóng , NhưngThay đổi người dùngĐối với user2: Chương trình bên ngoài đã được thực thi nhưng tôi không thể thấy biểu mẫu và đã xảy ra lỗi: Mã lỗi hệ thống 5: Truy cập bị từ chối.
Có gì đó không ổn nhưng tôi không thể tìm ra giải pháp. Cảm ơn câu trả lời của bạn...
Không cần liệt kê các tiến trình explorer.exe đang chạy, bạn có thể sử dụngWTSGetActiveConsoleSessionId()
Thay vào đó, hãy chuyển SessionId đó cho WTSQueryUserToken()
.Để ý WTSQueryUserToken()
Trả về mã thông báo giả, nhưng CreateProcessAsUser()
Cần có mã thông báo chính, vì vậy hãy sử dụng Trùng lặpTokenEx()
cho việc chuyển đổi này.
Bạn cũng nên sử dụng TạoEnvironmentBlock()
Do đó, quá trình kết quả có môi trường thích hợp cho tài khoản người dùng đang được sử dụng.
Cuối cùng, thiết lập STARTUPINFO.lpDesktop
lĩnh vực để 'WinSta0\Mặc định'
thay vì không
Vì vậy, giao diện người dùng được tạo sẽ hiển thị chính xác.
Tôi đã sử dụng phương pháp này trong nhiều năm mà không gặp vấn đề gì. Ví dụ:
hàm CreateEnvironmentBlock(var lpEnvironment: Pointer; hToken: THandle; bInherit: BOOL): BOOL; stdcall;
hàm DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall bên ngoài 'userenv.dll';
hàm RunInteractive(prog_filename: String): Boolean;
var
hUserToken, hToken: THandle;
si: _STARTUPINFOA;
pi: _PROCESS_INFORMATION;
SessionId: DWORD;
Env: Con trỏ;
begin
Kết quả := Sai;
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
si.lpDesktop := 'WinSta0\Default';
SessionId := WTSGetActiveConsoleSessionId;
nếu SessionId = $FFFFFFFF thì Thoát;
nếu không phải WTSQueryUserToken(SessionID, hToken) thì Thoát;
thử
nếu không phải DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, nil, SecurityIdentification, TokenPrimary, hUserToken) thì Thoát;
finally
CloseHandle(hToken);
end;
thử
nếu không phải CreateEnvironmentBlock(Env, hUserToken, False) thì Thoát;
thử
Kết quả := CreateProcessAsUser(hUserToken, nil, PChar(prog_filename), nil, nil, False, CREATE_UNICODE_ENVIRONMENT, Env, PChar(ExtractFilePath(prog_filename)), si, pi);
nếu Kết quả thì
begin
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
end;
finally
Phá hủyEnvironmentBlock(Env);
end;
finally
CloseHandle(hUserToken);
end;
end;
Tôi là một lập trình viên xuất sắc, rất giỏi!