How to call the GetNativeSystemInfo at Inno Setup iss file? - winapi

I want to call windows API: GetNativeSystemInfo at Inno Setup iss file, so I do not have to call an external DLL to detect ARM processor architecture.
But I don't know how to add it...
Could someone show me how to import and use that functionality in an Inno script???
Thank you!

The API declaration:
type
TSystemInfo = record
wProcessorArchitecture: Word;
wReserved: Word;
dwPageSize: DWORD;
lpMinimumApplicationAddress: Cardinal;
lpMaximumApplicationAddress: Cardinal;
dwActiveProcessorMask: DWORD_PTR;
dwNumberOfProcessors: DWORD;
dwProcessorType: DWORD;
dwAllocationGranularity: DWORD;
wProcessorLevel: Word;
wProcessorRevision: Word;
end;
const
PROCESSOR_ARCHITECTURE_INTEL = 0;
PROCESSOR_ARCHITECTURE_MIPS = 1;
PROCESSOR_ARCHITECTURE_ALPHA = 2;
PROCESSOR_ARCHITECTURE_PPC = 3;
PROCESSOR_ARCHITECTURE_SHX = 4;
PROCESSOR_ARCHITECTURE_ARM = 5;
PROCESSOR_ARCHITECTURE_IA64 = 6;
PROCESSOR_ARCHITECTURE_ALPHA64 = 7;
PROCESSOR_ARCHITECTURE_MSIL = 8;
PROCESSOR_ARCHITECTURE_AMD64 = 9;
PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10;
procedure GetNativeSystemInfo(var lpSystemInformation: TSystemInfo);
external 'GetNativeSystemInfo#Kernel32.dll stdcall';
And use:
var
SystemInfo: TSystemInfo;
begin
GetNativeSystemInfo(SystemInfo);
if SystemInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM then
begin
{ ... }
end;
end;

Related

How to execute "net use" command from Inno Setup installer on Windows 7?

I'm working on an Inno Setup installer, which calls net use to connect to a shared server. The installer can connect to the server, if it's running on Windows XP, but not on Windows 7. I think it's related to UAC as I type the same command, the server is connected on Windows 7, but the setup is running with admin privileges.
I'm using the following net use command through Exec or ShellExec script functions:
/c net use \\servername password /user:username
Actually, here is a part of the script showing the net use command call:
[Code]
var
ErrorCode: Integer;
cmdString: String;
intvalue: Integer;
str: String;
function InitializeSetup(): Boolean;
begin
cmdString := '/c net use \\servername password /USER:username';
ShellExec('', ExpandConstant('{cmd}'), cmdString , '', SW_SHOWNORMAL,
ewWaitUntilTerminated, ErrorCode)
if (ErrorCode = 0) then
begin
MsgBox(ExpandConstant('{cmd}'), mbInformation, MB_OK);
end;
end;
Can anybody suggest how to use net use from Inno Setup on Windows 7? We just want to connect to a server and let user input name and password.
Thank you!
How to connect to a remote resource invoking the credentials dialog?
Using a different view on your question, which is actually as the title of this answer says, I'd suggest you to use the WNetUseConnection function call with CONNECT_INTERACTIVE and CONNECT_PROMPT flags. That will in combination with empty user ID and password parameters invoke the credentials dialog (and that's what you wanted). In Inno Setup script it may look like this:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
NO_ERROR = 0;
ERROR_ACCESS_DENIED = 5;
ERROR_BAD_NET_NAME = 67;
ERROR_ALREADY_ASSIGNED = 85;
ERROR_INVALID_PASSWORD = 86;
ERROR_INVALID_PARAMETER = 87;
ERROR_MORE_DATA = 234;
ERROR_NO_MORE_ITEMS = 259;
ERROR_INVALID_ADDRESS = 487;
ERROR_BAD_DEVICE = 1200;
ERROR_NO_NET_OR_BAD_PATH = 1203;
ERROR_BAD_PROVIDER = 1204;
ERROR_EXTENDED_ERROR = 1208;
ERROR_NO_NETWORK = 1222;
ERROR_CANCELLED = 1223;
RESOURCETYPE_ANY = $00000000;
RESOURCETYPE_DISK = $00000001;
RESOURCETYPE_PRINT = $00000002;
CONNECT_UPDATE_PROFILE = $00000001;
CONNECT_INTERACTIVE = $00000008;
CONNECT_PROMPT = $00000010;
CONNECT_REDIRECT = $00000080;
CONNECT_COMMANDLINE = $00000800;
CONNECT_CMD_SAVECRED = $00001000;
type
TNetResource = record
dwScope: DWORD;
dwType: DWORD;
dwDisplayType: DWORD;
dwUsage: DWORD;
lpLocalName: string;
lpRemoteName: string;
lpComment: string;
lpProvider: string;
end;
TResourceType = (
rtAny,
rtDisk,
rtPrinter
);
function WNetUseConnection(hwndOwner: HWND; const lpNetResource: TNetResource;
lpPassword, lpUserID: string; dwFlags: DWORD; lpAccessName: PAnsiChar;
var lpBufferSize, lpResult: DWORD): DWORD;
external 'WNetUseConnection{#AW}#mpr.dll stdcall';
function UseConnection(const ARemoteName: string;
AResourceType: TResourceType): DWORD;
var
BufferSize: DWORD;
ResultFlag: DWORD;
NetResource: TNetResource;
begin
case AResourceType of
rtAny: NetResource.dwType := RESOURCETYPE_ANY;
rtDisk: NetResource.dwType := RESOURCETYPE_DISK;
rtPrinter: NetResource.dwType := RESOURCETYPE_PRINT;
end;
NetResource.lpLocalName := '';
NetResource.lpRemoteName := ARemoteName;
NetResource.lpProvider := '';
BufferSize := 0;
Result := WNetUseConnection(WizardForm.Handle, NetResource,
'', '', CONNECT_INTERACTIVE or CONNECT_PROMPT, '',
BufferSize, ResultFlag);
end;
procedure UseConnectionButtonClick(Sender: TObject);
var
S: string;
ResultCode: DWORD;
begin
ResultCode := UseConnection('\\MySuperSecret\Place', rtDisk);
case ResultCode of
NO_ERROR: S := 'NO_ERROR';
ERROR_ACCESS_DENIED: S := 'ERROR_ACCESS_DENIED';
ERROR_ALREADY_ASSIGNED: S := 'ERROR_ALREADY_ASSIGNED';
ERROR_BAD_DEVICE: S := 'ERROR_BAD_DEVICE';
ERROR_BAD_NET_NAME: S := 'ERROR_BAD_NET_NAME';
ERROR_BAD_PROVIDER: S := 'ERROR_BAD_PROVIDER';
ERROR_CANCELLED: S := 'ERROR_CANCELLED';
ERROR_EXTENDED_ERROR: S := 'ERROR_EXTENDED_ERROR';
ERROR_INVALID_ADDRESS: S := 'ERROR_INVALID_ADDRESS';
ERROR_INVALID_PARAMETER: S := 'ERROR_INVALID_PARAMETER';
ERROR_MORE_DATA: S := 'ERROR_MORE_DATA';
ERROR_INVALID_PASSWORD: S := 'ERROR_INVALID_PASSWORD';
ERROR_NO_MORE_ITEMS: S := 'ERROR_NO_MORE_ITEMS';
ERROR_NO_NET_OR_BAD_PATH: S := 'ERROR_NO_NET_OR_BAD_PATH';
ERROR_NO_NETWORK: S := 'ERROR_NO_NETWORK';
end;
MsgBox(S, mbInformation, MB_OK);
end;
procedure InitializeWizard;
var
UseConnectionButton: TNewButton;
begin
UseConnectionButton := TNewButton.Create(WizardForm);
UseConnectionButton.Parent := WizardForm;
UseConnectionButton.Left := 8;
UseConnectionButton.Top := WizardForm.ClientHeight - UseConnectionButton.Height - 8;
UseConnectionButton.Width := 155;
UseConnectionButton.Caption := 'Use connection...';
UseConnectionButton.OnClick := #UseConnectionButtonClick;
end;

How to get fully qualified domain name on Windows in Delphi

I need to get a fully qualified domain name for a Windows machine on a domain in Delphi.
I've tried to use LookupAccountSid but it gives me only the netbios domain name,
in my case it is "intranet" but I need the full "intranet.companyname.com"
Any Ideas?
Try the GetUserNameEx Windows API function.
const
NameUnknown = 0;
NameFullyQualifiedDN = 1;
NameSamCompatible = 2;
NameDisplay = 3;
NameUniqueId = 6;
NameCanonical = 7;
NameUserPrincipal = 8;
NameCanonicalEx = 9;
NameServicePrincipal = 10;
NameDnsDomain = 12;
function GetUserNameExString(ANameFormat: DWORD): string;
var
Buf: array[0..256] of Char;
BufSize: DWORD;
GetUserNameEx: function (NameFormat: DWORD; lpNameBuffer: LPSTR;
var nSize: ULONG): BOOL; stdcall;
begin
Result := '';
BufSize := SizeOf(Buf) div SizeOf(Buf[0]);
GetUserNameEx := GetProcAddress(GetModuleHandle('secur32.dll'), 'GetUserNameExA');
if Assigned(GetUserNameEx) then
if GetUserNameEx(ANameFormat, Buf, BufSize) then
Result := Buf;
end;
using the NameDnsDomain format for example, will result www.mydomain.com\user_name if you are logged into "www.mydomain.com" domain.
Since I now implemented this for my own needs in our application, #iPath's comment was quit right. better use GetComputerNameEx, and specify one of the COMPUTER_NAME_FORMAT for your own needs.
A Delphi implementation would look like this (Unicode version):
interface
...
type
COMPUTER_NAME_FORMAT = (
ComputerNameNetBIOS,
ComputerNameDnsHostname,
ComputerNameDnsDomain,
ComputerNameDnsFullyQualified,
ComputerNamePhysicalNetBIOS,
ComputerNamePhysicalDnsHostname,
ComputerNamePhysicalDnsDomain,
ComputerNamePhysicalDnsFullyQualified,
ComputerNameMax);
function GetComputerNameExString(ANameFormat: COMPUTER_NAME_FORMAT): WideString;
implementation
...
function GetComputerNameExW(NameType: COMPUTER_NAME_FORMAT; lpBuffer: LPWSTR;
var nSize: DWORD): BOOL; stdcall; external kernel32 name 'GetComputerNameExW';
function GetComputerNameExString(ANameFormat: COMPUTER_NAME_FORMAT): WideString;
var
nSize: DWORD;
begin
nSize := 1024;
SetLength(Result, nSize);
if GetComputerNameExW(ANameFormat, PWideChar(Result), nSize) then
SetLength(Result, nSize)
else
Result := '';
end;
NetGetJoinInformation should work fine.
MSDN:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa370423(v=vs.85).aspx
Example:
type
PWKSTA_INFO_100 = ^WKSTA_INFO_100;
WKSTA_INFO_100 = packed record
wki100_platform_id: DWord;
wki100_computername: PWChar;
wki100_langroup: PWChar;
wki100_ver_major: DWord;
wki100_ver_minor: DWord;
end;
TNetSetupJoinStatus =
(
NetSetupUnknownStatus,
NetSetupUnjoined,
NetSetupWorkgroupName,
NetSetupDomainName
);
TNetApiBufferFreeFunction = function(ABuffer: Pointer): DWORD; stdcall;
TNetWkstaGetInfoFunction = function(const AServername: PWChar; const ALevel: DWord; const ABufptr: Pointer): DWORD; stdcall;
TNetGetJoinInformationFunction = function(const AServerName: PWChar; out ANameBuffer: PWChar; out ABufferType: TNetSetupJoinStatus): DWORD; stdcall;
const
NERR_SUCCESS = 0;
function GetLocalComputerDomainName: string;
var
NetApiBuffer: Pointer;
NetApi: THandle;
NetApiBufferFree: TNetApiBufferFreeFunction;
NetWkstaGetInfo: TNetWkstaGetInfoFunction;
NetGetJoinInformation: TNetGetJoinInformationFunction;
NetSetupJoinStatus: TNetSetupJoinStatus;
NameBuffer: PWideChar;
begin
Result := '';
NetApi := LoadLibrary('netapi32.dll');
if NetApi <> 0 then
begin
NetApiBufferFree := TNetApiBufferFreeFunction( GetProcAddress(NetApi, 'NetApiBufferFree'));
NetGetJoinInformation := TNetGetJoinInformationFunction(GetProcAddress(NetApi, 'NetGetJoinInformation'));
NetWkstaGetInfo := TNetWkstaGetInfoFunction( GetProcAddress(NetApi, 'NetWkstaGetInfo'));
if #NetApiBufferFree <> nil then
begin
if #NetSetupJoinStatus <> nil then
begin
if NetGetJoinInformation(nil, NameBuffer, NetSetupJoinStatus) = NERR_SUCCESS then
begin
if NetSetupJoinStatus = NetSetupDomainName then
begin
Result := NameBuffer;
end;
NetApiBufferFree(NameBuffer);
end;
end;
end;
FreeLibrary(NetApi);
end;
end;
I tried all of the above, but without success. In the end, I settled for simply grabbing the environment variable.
uses jclSysInfo;
function GetDomain:string;
begin
result:=GetEnvironmentVariable('USERDNSDOMAIN');
end;
Tested on Server 2008 R2 - works fine. Returns "server.home.lan".
Results in an empty string on a Windows 7 non-domain connected PC.
The only correct api to use is DsGetDcName.
Because NetGetJoinInformation is still from the 'lanmanager age' so, the domain is LM compliant.
The code here is C, but you are smart enough to do the same in Delphi :)
PDOMAIN_CONTROLLER_INFOW pdomInfo ;
auto result1 = ::DsGetDcNameW(nullptr, nullptr, nullptr, nullptr, DS_DIRECTORY_SERVICE_PREFERRED | DS_RETURN_DNS_NAME, &pdomInfo);
if (result1 == ERROR_SUCCESS) {
auto retVal = SysAllocString(pdomInfo->DomainName);
::NetApiBufferFree(pdomInfo);
}

Clicking sound in TWebbrowser

From this answer
CoInternetIsFeatureEnabled in Delphi2010
Does anyone know how to stop the clicking sound. That doesn't appear to work in Delphi XE when I drop it into a separate pas file. There is some missing . and other reasons why it wont compile so im a bit stuck.
Here's what I did.
unit untUrlMon;
interface
uses
Windows;
const
GET_FEATURE_FROM_THREAD = $00000001;
GET_FEATURE_FROM_PROCESS = $00000002;
GET_FEATURE_FROM_REGISTRY = $00000004;
GET_FEATURE_FROM_THREAD_LOCALMACHINE = $00000008;
GET_FEATURE_FROM_THREAD_INTRANET = $00000010;
GET_FEATURE_FROM_THREAD_TRUSTED = $00000020;
GET_FEATURE_FROM_THREAD_INTERNET = $00000040;
GET_FEATURE_FROM_THREAD_RESTRICTED = $00000080;
SET_FEATURE_ON_THREAD = $00000001;
SET_FEATURE_ON_PROCESS = $00000002;
SET_FEATURE_IN_REGISTRY = $00000004;
SET_FEATURE_ON_THREAD_LOCALMACHINE = $00000008;
SET_FEATURE_ON_THREAD_INTRANET = $00000010;
SET_FEATURE_ON_THREAD_TRUSTED = $00000020;
SET_FEATURE_ON_THREAD_INTERNET = $00000040;
SET_FEATURE_ON_THREAD_RESTRICTED = $00000080;
type
INTERNETFEATURELIST = (
FEATURE_OBJECT_CACHING,
FEATURE_ZONE_ELEVATION,
FEATURE_MIME_HANDLING,
FEATURE_MIME_SNIFFING,
FEATURE_WINDOW_RESTRICTIONS,
FEATURE_WEBOC_POPUPMANAGEMENT,
FEATURE_BEHAVIORS,
FEATURE_DISABLE_MK_PROTOCOL,
FEATURE_LOCALMACHINE_LOCKDOWN,
FEATURE_SECURITYBAND,
FEATURE_RESTRICT_ACTIVEXINSTALL,
FEATURE_VALIDATE_NAVIGATE_URL,
FEATURE_RESTRICT_FILEDOWNLOAD,
FEATURE_ADDON_MANAGEMENT,
FEATURE_PROTOCOL_LOCKDOWN,
FEATURE_HTTP_USERNAME_PASSWORD_DISABLE,
FEATURE_SAFE_BINDTOOBJECT,
FEATURE_UNC_SAVEDFILECHECK,
FEATURE_GET_URL_DOM_FILEPATH_UNENCODED,
FEATURE_TABBED_BROWSING,
FEATURE_SSLUX,
FEATURE_DISABLE_NAVIGATION_SOUNDS,
FEATURE_DISABLE_LEGACY_COMPRESSION,
FEATURE_FORCE_ADDR_AND_STATUS,
FEATURE_XMLHTTP,
FEATURE_DISABLE_TELNET_PROTOCOL,
FEATURE_FEEDS,
FEATURE_BLOCK_INPUT_PROMPTS,
FEATURE_ENTRY_COUNT
);
function CoInternetIsFeatureEnabled(FeatureEntry: INTERNETFEATURELIST; dwFlags: DWORD): HRESULT; stdcall; external 'urlmon.dll'
implementation
function CoInternetSetFeatureEnabled(FeatureEntry: INTERNETFEATURELIST; dwFlags: DWORD; fEnable: BOOL): HRESULT; stdcall; external 'urlmon.dll'
begin
if CoInternetIsFeatureEnabled(FEATURE_DISABLE_NAVIGATION_SOUNDS, GET_FEATURE_FROM_PROCESS) = S_FALSE then
CoInternetSetFeatureEnabled(FEATURE_DISABLE_NAVIGATION_SOUNDS, SET_FEATURE_ON_PROCESS, True);
end;
I'd imagine you need something like this:
unit untUrlMon;
implementation
uses
Windows;
const
SET_FEATURE_ON_PROCESS = $00000002;
FEATURE_DISABLE_NAVIGATION_SOUNDS = 21;
function CoInternetSetFeatureEnabled(FeatureEntry: DWORD; dwFlags: DWORD; fEnable: BOOL): HRESULT; stdcall; external 'urlmon.dll';
initialization
CoInternetSetFeatureEnabled(FEATURE_DISABLE_NAVIGATION_SOUNDS, SET_FEATURE_ON_PROCESS, True);
end.
If you replace the final "end;" with "end." it should compile.
I believe you also need ";" after the two function declarations (after the "external 'urlmon.dll'" part).
The final "begin/end" is then run automatically in every program you include this unit in.

Creating a function to dig for Windows Handle by Classname(s) Only

So I just got an answer to my question about getting the Skype Chatbox handle.
I am now trying to create a simple function, that digs for a handle. Here is how I am hoping to be able to use it:
MyHWND := DigForHandle(['Notepad','Edit'],['Untitled - Notepad','']);
Params:
1) Array of String: Holds the Class Hierachy.
2) Array of String: Holds the Window Caption Hierachy.
As you see, the 2nd entry in the 2nd parameter is empty, since the Edit Class does not have a Window Caption.
Would it be possible to create such function? :)
Try this
uses
Windows, Messages, TlHelp32, SysUtils;
type
PGetWindowParam = ^TGetWindowParam;
TGetWindowParam = record
ProcID: DWORD;
WindowCaption: string;
Result: HWND;
end;
function DigForHandle(const ProcName, Caption: string; const Hierachy: array of string): HWND;
function FindPID(const ExeFileName: string): DWORD;
implementation
function FindPID(const ExeFileName: string): DWORD;
var
ContinueLoop: BOOL;
ProcessEntry32: TProcessEntry32;
SnapshotHandle: THandle;
TempExeFileName: string;
begin
Result := 0;
SnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if SnapshotHandle <> 0 then
begin
FillChar(ProcessEntry32, SizeOf(ProcessEntry32), 0);
ProcessEntry32.dwSize := Sizeof(ProcessEntry32);
ContinueLoop := Process32First(SnapshotHandle, ProcessEntry32);
while ContinueLoop do
begin
TempExeFileName := ExtractFileName(ProcessEntry32.szExeFile);
if SameText(TempExeFileName, ExeFileName) then
begin
Result := ProcessEntry32.th32ProcessID;
Break;
end;
ContinueLoop := Process32Next(SnapshotHandle, ProcessEntry32);
end;
CloseHandle(SnapshotHandle);
end;
end;
function GetWindow(Wnd: HWND; P: LParam): BOOL; stdcall;
var
Param: PGetWindowParam;
ProcID: DWORD;
WindowTitle: array[0..256] of Char;
begin
Result := True; // assume it doesn't match; keep searching
Param := PGetWindowParam(P);
ProcID := 0;
GetWindowThreadProcessID(Wnd, #ProcID);
if ProcID <> Param^.ProcID then
Exit;
FillChar(WindowTitle, SizeOf(WindowTitle), 0);
if SendMessage(Wnd, WM_GETTEXT, SizeOf(WindowTitle) - SizeOf(Char), LPARAM(#WindowTitle[0])) <= 0 then
Exit;
if AnsiSameStr(WindowTitle, Param^.WindowCaption) then
begin
Param^.Result := Wnd;
Result := False;
end;
end;
function DigForHandle(const ProcName, Caption: string; const Hierachy: array of string): HWND;
var
Param: TGetWindowParam;
I: Integer;
ParentWnd: HWND;
begin
Result := 0;
FillChar(Param, SizeOf(Param), 0);
Param.ProcID := FindPID(ProcName);
if Param.ProcID = 0 then
Exit;
Param.Result := 0;
Param.WindowCaption := Caption;
EnumWindows(#GetWindow, LPARAM(#Param));
if Param.Result = 0 then
Exit;
I := 0;
ParentWnd := Param.Result;
while (ParentWnd <> 0) and (I < Length(Hierachy)) do
begin
Param.Result := 0;
Param.WindowCaption := Hierachy[I];
EnumChildWindows(ParentWnd, #GetWindow, LPARAM(#Param));
if Param.Result = 0 then
Break;
ParentWnd := Param.Result;
Inc(I);
end;
if I >= Length(Hierachy) then
Result := Param.Result;
end;
When I thought about it, I realized that it was actually rather simple - the code I had though, was "confusing" for me, which was why I asked a question here. After trying it out, I found that doing it this way, its a lot easier to read, and not as complicated (IMO).
Function DigForHandle(ClassHierachy, TextHierachy : Array of String):HWND;
Var
Handle : HWND;
I : Integer;
PClass,PText : PChar;
Begin
Result := 0;
I := 0;
while (I <= Length(ClassHierachy)-1) do
begin
PClass := PChar(ClassHierachy[I]);
PText := PChar(TextHierachy[I]);
if PClass = '' then PClass := Nil;
if PText = '' then PText := Nil;
Result := FindWindowEx(Result,0,PClass,PText);
Inc(I);
end;
End;

Detecting multiple logged on users via win32

Using the standard win32 api, what's the best way to detect more than one user is logged on? I have an upgrade to our software product that can't be run when more than one user is logged in. (I know this is something to be avoided because of its annoyance factor, but the product is very complicated. You'll have to trust me when I say there really is no other solution.) Thanks.
In order to have more than one user logged in at once, Terminal Services or Fast User Switching must be enabled. Since Fast User Switching is implemented using Terminal Services, you first need to find out if the OS has it enabled. You can use GetVersionEx with an OSVERSIONINFOEX. Check for the VER_SUITE_SINGLEUSERTS and VER_SUITE_TERMINAL flags.
If TS is enabled, you can use WTSEnumerateSessions to find out how many users are logged on. This only works if the "Terminal Services" service is started.
If the machine doesn't support Terminal Services (or if the service isn't started), then you can only have one user logged on.
Here's a solution that works on XP, Server 2003, Vista, and Server 2008. Note, this won't work on Windows 2000, because "LsaEnumerateLogonSessions" is not available on Windows 2000. This code is modified from a Delphi-PRAXIS post.
To compile this, create a new VCL application with a TButton and a TMemo on the form. Then copy and paste this code and it should compile. I tested on XP and Vista and it works well. It will return interactive and remote users.
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.
This might be a roundabout way, but run down the process list and see who the process owners are.

Resources