使用標準win32 api,檢測多個用戶的最佳方法是登錄?我有一個升級到我們的軟件產品,當多個用戶登錄時無法運行。(我知道這是因爲惱人的因素需要避免的,但是產品非常複雜,您必須相信我,當我說真的沒有其他解決方案時。)謝謝。通過win32檢測多個登錄用戶
回答
爲了讓多個用戶立即登錄,必須啓用終端服務或快速用戶切換。由於使用終端服務實現了快速用戶切換,因此首先需要確定操作系統是否啓用了該功能。您可以使用GetVersionEx和OSVERSIONINFOEX。檢查VER_SUITE_SINGLEUSERTS和VER_SUITE_TERMINAL標誌。
如果啓用了TS,則可以使用WTSEnumerateSessions來確定有多少用戶已登錄。這僅在「終端服務」服務啓動時纔有效。
如果機器不支持終端服務(或者服務未啓動),那麼您只能有一個用戶登錄。
這是不正確的,通過快速用戶切換,> 1個用戶可以同時運行進程。 – 2008-12-15 16:08:41
@Paul Betts:如果您使用快速用戶切換,則WTSEnumerateSessions將返回所有當前登錄的會話,無論它們是否處於活動狀態。 – 2008-12-15 16:10:09
這可能是一種迂迴的方式,但是運行流程列表並查看流程所有者是誰。
這實際上是一個很好的方法。枚舉所有進程:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682623%28v=vs.85%29.aspx然後從每個進程獲取用戶名:http:// stackoverflow。 com/questions/2686096/c-get-username-from-process/2686150#2686150 – Itaypk 2014-02-02 11:53:32
這是一個適用於XP,Server 2003,Vista和Server 2008的解決方案。請注意,這不適用於Windows 2000,因爲「LsaEnumerateLogonSessions」在Windows 2000上不可用。此代碼從Delphi-PRAXIS post 。
爲了編譯這個,在窗體上創建一個帶有TButton和TMemo的新VCL應用程序。然後複製並粘貼這段代碼,它應該編譯。我在XP和Vista上測試過,效果很好。它將返回交互式和遠程用戶。
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
WTS_CURRENT_SERVER_HANDLE = 0;
type
PTOKEN_USER = ^TOKEN_USER;
_TOKEN_USER = record
User: TSidAndAttributes;
end;
TOKEN_USER = _TOKEN_USER;
USHORT = word;
_LSA_UNICODE_STRING = record
Length: USHORT;
MaximumLength: USHORT;
Buffer: LPWSTR;
end;
LSA_UNICODE_STRING = _LSA_UNICODE_STRING;
PLuid = ^LUID;
_LUID = record
LowPart: DWORD;
HighPart: LongInt;
end;
LUID = _LUID;
_SECURITY_LOGON_TYPE = (
seltFiller0, seltFiller1,
Interactive,
Network,
Batch,
Service,
Proxy,
Unlock,
NetworkCleartext,
NewCredentials,
RemoteInteractive,
CachedInteractive,
CachedRemoteInteractive);
SECURITY_LOGON_TYPE = _SECURITY_LOGON_TYPE;
PSECURITY_LOGON_SESSION_DATA = ^SECURITY_LOGON_SESSION_DATA;
_SECURITY_LOGON_SESSION_DATA = record
Size: ULONG;
LogonId: LUID;
UserName: LSA_UNICODE_STRING;
LogonDomain: LSA_UNICODE_STRING;
AuthenticationPackage: LSA_UNICODE_STRING;
LogonType: SECURITY_LOGON_TYPE;
Session: ULONG;
Sid: PSID;
LogonTime: LARGE_INTEGER;
LogonServer: LSA_UNICODE_STRING;
DnsDomainName: LSA_UNICODE_STRING;
Upn: LSA_UNICODE_STRING;
end;
SECURITY_LOGON_SESSION_DATA = _SECURITY_LOGON_SESSION_DATA;
_WTS_INFO_CLASS = (
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType);
WTS_INFO_CLASS = _WTS_INFO_CLASS;
_WTS_CONNECTSTATE_CLASS = (
WTSActive, // User logged on to WinStation
WTSConnected, // WinStation connected to client
WTSConnectQuery, // In the process of connecting to client
WTSShadow, // Shadowing another WinStation
WTSDisconnected, // WinStation logged on without client
WTSIdle, // Waiting for client to connect
WTSListen, // WinStation is listening for connection
WTSReset, // WinStation is being reset
WTSDown, // WinStation is down due to error
WTSInit); // WinStation in initialization
WTS_CONNECTSTATE_CLASS = _WTS_CONNECTSTATE_CLASS;
function LsaFreeReturnBuffer(Buffer: pointer): Integer; stdcall;
function WTSGetActiveConsoleSessionId: DWORD; external 'Kernel32.dll';
function LsaGetLogonSessionData(LogonId: PLUID;
var ppLogonSessionData: PSECURITY_LOGON_SESSION_DATA): LongInt; stdcall;
external 'Secur32.dll';
function LsaNtStatusToWinError(Status: cardinal): ULONG; stdcall;
external 'Advapi32.dll';
function LsaEnumerateLogonSessions(Count: PULONG; List: PLUID): LongInt;
stdcall; external 'Secur32.dll';
function WTSQuerySessionInformationA(hServer: THandle; SessionId: DWORD;
WTSInfoClass: WTS_INFO_CLASS; var pBuffer: Pointer;
var pBytesReturned: DWORD): BOOL; stdcall; external 'Wtsapi32.dll';
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function LsaFreeReturnBuffer; external 'secur32.dll' name 'LsaFreeReturnBuffer';
procedure GetActiveUserNames(var slUserList : TStringList);
var
Count: cardinal;
List: PLUID;
sessionData: PSECURITY_LOGON_SESSION_DATA;
i1: integer;
SizeNeeded, SizeNeeded2: DWORD;
OwnerName, DomainName: PChar;
OwnerType: SID_NAME_USE;
pBuffer: Pointer;
pBytesreturned: DWord;
sUser : string;
begin
//result:= '';
//Listing LogOnSessions
i1:= lsaNtStatusToWinError(LsaEnumerateLogonSessions(@Count, @List));
try
if i1 = 0 then
begin
i1:= -1;
if Count > 0 then
begin
repeat
inc(i1);
LsaGetLogonSessionData(List, sessionData);
//Checks if it is an interactive session
sUser := sessionData.UserName.Buffer;
if (sessionData.LogonType = Interactive)
or (sessionData.LogonType = RemoteInteractive)
or (sessionData.LogonType = CachedInteractive)
or (sessionData.LogonType = CachedRemoteInteractive) then
begin
//
SizeNeeded := MAX_PATH;
SizeNeeded2:= MAX_PATH;
GetMem(OwnerName, MAX_PATH);
GetMem(DomainName, MAX_PATH);
try
if LookupAccountSID(nil, sessionData.SID, OwnerName,
SizeNeeded, DomainName,SizeNeeded2,
OwnerType) then
begin
if OwnerType = 1 then //This is a USER account SID (SidTypeUser=1)
begin
sUser := AnsiUpperCase(sessionData.LogonDomain.Buffer);
sUser := sUser + '\';
sUser := sUser + AnsiUpperCase(sessionData.UserName.Buffer);
slUserList.Add(sUser);
// if sessionData.Session = WTSGetActiveConsoleSessionId then
// begin
// //Wenn Benutzer aktiv
// try
// if WTSQuerySessionInformationA
// (WTS_CURRENT_SERVER_HANDLE,
// sessionData.Session, WTSConnectState,
// pBuffer,
// pBytesreturned) then
// begin
// if WTS_CONNECTSTATE_CLASS(pBuffer^) = WTSActive then
// begin
// //result:= sessionData.UserName.Buffer;
// slUserList.Add(sessionData.UserName.Buffer);
// end;
// end;
// finally
// LSAFreeReturnBuffer(pBuffer);
// end;
//end;
end;
end;
finally
FreeMem(OwnerName);
FreeMem(DomainName);
end;
end;
inc(List);
try
LSAFreeReturnBuffer(sessionData);
except
end;
until (i1 = Count-1);// or (result <> '');
end;
end;
finally
LSAFreeReturnBuffer(List);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
slUsers : TStringList;
begin
slUsers := TStringList.Create;
slUsers.Duplicates := dupIgnore;
slUsers.Sorted := True;
try
GetActiveUserNames(slUsers);
Memo1.Lines.AddStrings(slUsers);
finally
FreeAndNil(slUsers)
end;
end;
end.
- 1. 檢測用戶通過Google Analytics登錄
- 2. 如何檢測在Linux中通過GUI登錄的用戶
- 3. Rails檢測用戶是否從多個設備登錄
- 4. 通過twitteroauth登錄到多個用戶的twitter應用程序
- 5. 檢測用戶是否已登錄
- 6. Rails設計不檢測用戶登錄
- 7. 檢測用戶是否登錄到Facebook
- 8. 檢測用戶從Windows服務登錄
- 9. 檢索在線用戶通過登錄和註銷記錄
- 10. 檢查通過Wordpress登錄Pligg CMS用戶帳戶
- 11. 登錄多個用戶
- 12. ASP.net多個用戶登錄
- 13. 登錄多個用戶
- 14. Json登錄多個用戶登錄在一個登錄頁面
- 15. WIN32 - 最後一位用戶登錄
- 16. 谷歌API檢測多個帳戶登錄
- 17. Facebook登錄 - 檢測用戶登錄時沒有PHP-SDK
- 18. 通過多個社交網絡登錄
- 19. 通過PHP處理多個登錄?
- 20. UWP,如何檢測用戶之前登錄過?
- 21. 在登錄過程中檢測未確認的用戶
- 22. Django用戶通過api登錄
- 23. 登錄用戶通過編程JAAS
- 24. 通過OpenID登錄用戶到Magento
- 25. 通過htaccess強制https登錄用戶
- 26. 通過phpbb3登錄用戶名到phpfreechat
- 27. 讓用戶通過URL登錄
- 28. Symfony2:通過用戶或IP登錄
- 29. 創建一個頁面,可以在登錄時檢測多個用戶名.PHP
- 30. 在Selenium中通過前端登錄用戶水豚Rspec測試
那麼,我認爲你希望這可以在Windows 2000,XP,Vista和Windows 7上工作。你有興趣知道人們是否通過終端服務登錄? – Mick 2008-12-15 15:41:06