Related
I'm trying to get PIDs of processes which belongs to the current user but I don't know how to check the process owner.
This is my code (the user's checking condition is missing):
uses
TlHelp32, ...;
type
TCardinalArray = array of Cardinal;
function GetCurrentUserPIDs(const AProcessName : string) : TCardinalArray;
var
ContinueLoop: boolean;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
SetLength(Result, 0);
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while(ContinueLoop) do
begin
if(SameText(FProcessEntry32.szExeFile, AProcessName)) then
begin
if((* is this my process? *)) then
begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result) - 1] := FProcessEntry32.th32ProcessID;
end;
end;
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
I found a GetUserAndDomainFromPID function which allows to easily accomplish the task.
As Sertac Akyuz suggested, the function uses OpenProcessToken and GetTokenInformation. It also uses LookupAccountSid:
uses
TlHelp32;
type
PTOKEN_USER = ^TOKEN_USER;
_TOKEN_USER = record
User: TSidAndAttributes;
end;
TOKEN_USER = _TOKEN_USER;
function GetUserAndDomainFromPID(ProcessId: DWORD;
var User, Domain: string): Boolean;
var
hToken: THandle;
cbBuf: Cardinal;
ptiUser: PTOKEN_USER;
snu: SID_NAME_USE;
ProcessHandle: THandle;
UserSize, DomainSize: DWORD;
bSuccess: Boolean;
begin
Result := False;
ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId);
if ProcessHandle <> 0 then
begin
// EnableProcessPrivilege(ProcessHandle, 'SeSecurityPrivilege', True);
if OpenProcessToken(ProcessHandle, TOKEN_QUERY, hToken) then
begin
bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf);
ptiUser := nil;
while (not bSuccess) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do
begin
ReallocMem(ptiUser, cbBuf);
bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf);
end;
CloseHandle(hToken);
if not bSuccess then
begin
Exit;
end;
UserSize := 0;
DomainSize := 0;
LookupAccountSid(nil, ptiUser.User.Sid, nil, UserSize, nil, DomainSize, snu);
if (UserSize <> 0) and (DomainSize <> 0) then
begin
SetLength(User, UserSize);
SetLength(Domain, DomainSize);
if LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), UserSize,
PChar(Domain), DomainSize, snu) then
begin
Result := True;
User := StrPas(PChar(User));
Domain := StrPas(PChar(Domain));
end;
end;
if bSuccess then
begin
FreeMem(ptiUser);
end;
end;
CloseHandle(ProcessHandle);
end;
end;
Then I've written a function for getting the current windows username (It uses GetUserName):
const
UNLEN = 256; // Maximum user name length
function GetWindowsUsername: string;
var
UserName : string;
UserNameLen : Dword;
begin
UserNameLen := UNLEN;
SetLength(UserName, UserNameLen) ;
if GetUserName(PChar(UserName), UserNameLen)
then Result := Copy(UserName, 1, UserNameLen - 1)
else Result := '';
end;
The following function returns an array composed by all ids of processes who belongs to the current user (Note that processes are filtered by process name):
uses
TlHelp32;
type
TCardinalArray = array of Cardinal;
function GetCurrentUserPIDs(const AProcessName : string) : TCardinalArray;
var
ContinueLoop: boolean;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
UserName : string;
DomainName : string;
CurrentUser : string;
begin
CurrentUser := GetWindowsUsername();
SetLength(Result, 0);
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while(ContinueLoop) do
begin
if(SameText(FProcessEntry32.szExeFile, AProcessName)) then
begin
if(GetUserAndDomainFromPID(FProcessEntry32.th32ProcessID, UserName, DomainName)) then
begin
if(UserName = CurrentUser) then
begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result) - 1] := FProcessEntry32.th32ProcessID;
end;
end;
end;
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
I have a program created in Delphi 7 that uses ftp downloading.
How can i insert into that program to check for a server status?
For example if server is online to produce a green image, if server is offline o produce a red image. Here is the code.
unit Download;
interface
uses
Classes, Wininet, Windows, SysUtils, Dialogs, Forms;
type
GFilesThread = class(TThread)
private
LTemp : Longword;
STemp : string;
FilesToGet : TStringList;
FilesSize : Longword;
CBackup : integer;
CRevision : integer;
CForceCheck : boolean;
CSwitch : integer;
UUrl : string;
USelfParam : string;
Dir: string;
FSource: TStream;
protected
procedure Execute; override;
procedure UpdateFileProgress;
procedure SetFileProgressMax;
procedure UpdateStatusLabel;
procedure UpdateFileDecompStat;
procedure UpdateFilesProgress;
procedure CheckFiles(FList : TStringList);
procedure BZProgress(Sender: TObject);
procedure LockFMain;
procedure UNLockFMain;
procedure GetFiles;
procedure SelfUpdate(SelfVal : string);
procedure UpdateRevision;
procedure ModHosts(Lines : TStringList);
procedure DoUncompressStream(ASource, ADest: TStream);
procedure DoUncompress(const ASource, ADest: TFileName);
function HTTPGetFile(const fileURL, FileName: string; sh_progress: boolean): boolean;
public
property CreateBackup : integer write CBackup;
property UpdatesUrl : string write UUrl;
property LocalRevision : integer write CRevision;
property ForceCheck : boolean write CForceCheck;
end;
implementation
uses Launcher, CheckFiles, BZip2, md5, FileList;
// -------- by 667
procedure GFilesThread.UpdateStatusLabel;
begin
FMain.Label3.Caption:=STemp;
end;
procedure GFilesThread.SetFileProgressMax;
begin
if(CSwitch=0) then
FMain.Gauge1.MaxValue:=LTemp;
if(CSwitch=1) then
FMain.Gauge2.MaxValue:=LTemp;
end;
procedure GFilesThread.UpdateFileProgress;
begin
FMain.Gauge1.Progress:=LTemp;
end;
procedure GFilesThread.UpdateFilesProgress;
begin
FMain.Gauge2.Progress:=LTemp;
end;
procedure GFilesThread.UpdateRevision;
begin
FMain.UpdateRevision(IntToStr(CRevision));
end;
procedure GFilesThread.UpdateFileDecompStat;
begin
FMain.Gauge1.Progress:=LTemp;
end;
procedure GFilesThread.BZProgress(Sender: TObject);
begin
LTemp:=FSource.Position;
Synchronize(UpdateFileDecompStat);
end;
procedure GFilesThread.LockFMain;
begin
Fmain.ImgBtn1.Visible:=False;
Fmain.ImgBtn2.Visible:=False;
Fmain.ImgBtn5.Enabled:=False;
end;
procedure GFilesThread.UNLockFMain;
begin
Fmain.ImgBtn1.Visible:=True;
Fmain.ImgBtn2.Visible:=True;
Fmain.ImgBtn5.Enabled:=True;
end;
// --------- by 667
function GFilesThread.HTTPGetFile(const fileURL, FileName: string; sh_progress: boolean): boolean;
const
BufferSize = 1024;
var
hSession, hURL: HInternet;
Buffer: array[1..BufferSize] of Byte;
BufferLen: Longword;
f: file;
sAppName: string;
begin
Result := False;
sAppName := 'L2ClientUpdater';
LTemp:=0;
hSession := InternetOpen(PChar(sAppName),
INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0);
if (hURL <> nil) then begin
try
DeleteUrlCacheEntry(PChar(fileURL));
AssignFile(f, FileName);
Rewrite(f,1);
repeat
InternetReadFile(hURL, #Buffer, SizeOf(Buffer), BufferLen);
BlockWrite(f, Buffer, BufferLen);
if (sh_progress) then
begin
LTemp:=LTemp+BufferLen;
Synchronize(UpdateFileProgress);
end;
until
BufferLen = 0;
CloseFile(f);
Result := True;
finally
InternetCloseHandle(hURL);
end;
end;
finally
InternetCloseHandle(hSession);
end;
LTemp:=0;
Synchronize(UpdateFileProgress);
end;
procedure GFilesThread.DoUncompress(const ASource, ADest: TFileName);
var
Source, Dest: TStream;
begin
Source := TFileStream.Create(ASource, fmOpenRead + fmShareDenyWrite);
try
Dest := TFileStream.Create(ADest, fmCreate);
try
DoUncompressStream(Source, Dest);
finally
Dest.Free;
end;
finally
Source.Free;
DeleteFile(ASource);
end;
end;
procedure GFilesThread.DoUncompressStream(ASource, ADest: TStream);
const
BufferSize = 65536;
var
Count: Integer;
Decomp: TBZDecompressionStream;
Buffer: array[0..BufferSize - 1] of Byte;
begin
FSource := ASource;
LTemp:=FSource.Size;
CSwitch:=0;
Synchronize(SetFileProgressMax);
Decomp := TBZDecompressionStream.Create(ASource);
try
Decomp.OnProgress := BZProgress;
while True do
begin
Count := Decomp.Read(Buffer, BufferSize);
if Count <> 0 then ADest.WriteBuffer(Buffer, Count) else Break;
end;
finally
Decomp.Free;
FSource := nil;
LTemp:=0;
Synchronize(UpdateFileDecompStat);
end;
end;
procedure GFilesThread.CheckFiles(FList : TStringList);
var
i: integer;
FParam: TStringList;
FNameLocal: string;
begin
if(FList.Count>0) and (FList[0]<>'FAIL') and (not terminated) then
begin
STemp:='Checking files';
Synchronize(UpdateStatusLabel);
CSwitch:=1;
LTemp:=FList.Count-1;
Synchronize(SetFileProgressMax);
FParam:=TStringList.Create;
for i:=0 to FList.Count-1 do
begin
LTemp:=i;
Synchronize(UpdateFilesProgress);
FParam:=Tokenize(FList[i],'|');
FNameLocal:=Dir+FParam[2];
STemp:='Checking '+FParam[2];
Synchronize(UpdateStatusLabel);
if (not FileExists(FNameLocal)) then
begin
FilesToGet.Add(FList[i]);
FilesSize:=FilesSize+StrToInt(FParam[0]);
end
else
begin
if (MD5Print(MD5File(FNameLocal))<>FParam[1]) then
begin
FilesToGet.Add(FList[i]);
FilesSize:=FilesSize+StrToInt(FParam[0]);
end;
end;
end;
FParam.Free;
LTemp:=0;
Synchronize(UpdateFilesProgress);
STemp:='';
Synchronize(UpdateStatusLabel);
end;
end;
procedure GFilesThread.SelfUpdate(SelfVal : string);
var
FParam: TStringList;
FNameLocal: string;
F:boolean;
begin
if(SelfVal<>'') then
begin
FParam:=TStringList.Create;
FParam:=Tokenize(SelfVal,'|');
FNameLocal:=Dir+FParam[2];
if (MD5Print(MD5File(FNameLocal))<>FParam[1]) then
begin
FilesSize:=FilesSize+StrToInt(FParam[0]);
F:=HTTPGetFile(UUrl+FParam[2]+'.bz2',FNameLocal+'.bz2',True);
if(F) then begin
try
DoUncompress(FNameLocal+'.bz2',Dir+FParam[2]+'.New');
GenKillerBat(FParam[2]);
RunApp(Dir+'Update.bat');
except
STemp:='Update Failed';
DeleteFile(FNameLocal);
end;
end;
end;
FParam.Free;
end;
end;
procedure GFilesThread.ModHosts(Lines : TStringList);
var
Hosts : textfile;
H, HostsStrings, HostLineParam : TStringList;
HostsPath, temp : string;
i, z, funnyFlag : integer;
WindirP : PChar;
Res : cardinal;
begin
WinDirP := StrAlloc(MAX_PATH);
Res := GetWindowsDirectory(WinDirP, MAX_PATH);
if Res > 0 then
begin
if(FileExists(StrPas(WinDirP)+'\system32\drivers\etc\hosts.msn')) then
HostsPath := StrPas(WinDirP)+'\system32\drivers\etc\hosts.msn'
else
HostsPath := StrPas(WinDirP)+'\system32\drivers\etc\hosts';
AssignFile(Hosts,HostsPath);
Reset(Hosts);
HostsStrings:= TStringList.Create;
H:= TStringList.Create;
H.Add('#-------- Added by L2Updater --------');
while (not Eof(Hosts)) do
begin
ReadLn(Hosts, temp);
HostsStrings.Add(Trim(temp));
end ;
Reset(Hosts);
for i:=0 to Lines.Count-1 do
begin
funnyFlag:=0;
HostLineParam:=Tokenize(Lines[i],'|');
for z:=0 to HostsStrings.Count-1 do
begin
if (StrSearch(1,HostsStrings[z],HostLineParam[0])>0) and (HostsStrings[z][1]<>'#') then
begin
if (StrSearch(1,HostsStrings[z],HostLineParam[1]+#9)= 0) and (StrSearch(1,HostsStrings[z],HostLineParam[1]+' ')= 0 ) then
begin
HostsStrings[z]:= '#'+HostsStrings[z];
funnyFlag:=1;
end
else funnyFlag:=2;
end;
end;
if (funnyFlag=1) or (funnyFlag=0) then
H.Add(HostLineParam[1]+#9+HostLineParam[0]);
end;
H.Add('#-----------------');
if H.Count>2 then
begin
Rewrite(Hosts);
STemp:='Applying changes to Hosts';
Synchronize(UpdateStatusLabel);
for i:=0 to HostsStrings.Count-1 do
begin
WriteLn(Hosts,HostsStrings[i]);
end;
for i:=0 to H.Count-1 do
begin
WriteLn(Hosts,H[i]);
end;
STemp:='Hosts file chamged';
Synchronize(UpdateStatusLabel);
end;
H.Free; HostsStrings.Free; HostLineParam.Free;
CloseFile(Hosts);
end;
end;
procedure GFilesThread.GetFiles;
var
FParam : TStringList;
i : integer;
F, error : boolean;
LocalFile, BakFile: string;
begin
error := False;
if (FilesToGet.Count>0) then
begin
FParam:=TStringList.Create;
LTemp:=FilesToGet.Count-1;
CSwitch:=1;
Synchronize(SetFileProgressMax);
i:=0;
while (i < FilesToGet.Count) and (not terminated) do
begin
FParam:=Tokenize(FilesToGet[i],'|');
LocalFile:= Dir+FParam[2];
STemp:='Downloading '+ FParam[2];
Synchronize(UpdateStatusLabel);
CSwitch:=0;
LTemp:= StrToInt(FParam[0]);
Synchronize(SetFileProgressMax);
if (not DirectoryExists(ExtractFilePath(LocalFile))) then
ForceDirectories(ExtractFilePath(LocalFile));
F:=HTTPGetFile(UUrl+ReplaceStr(FParam[2],'\','/')+'.bz2',LocalFile+'.bz2',True);
if (F) then
begin
try
if (CBackup=1) then
begin
BakFile:=Dir+'backup\'+FParam[2];
if (not DirectoryExists(ExtractFilePath(BakFile))) then
ForceDirectories(ExtractFilePath(BakFile));
CopyFile(PChar(LocalFile),PChar(BakFile),false);
end;
STemp:='Extracting '+ FParam[2];
Synchronize(UpdateStatusLabel);
DoUncompress(LocalFile+'.bz2',Dir+FParam[2]);
except
STemp:='Update Failed';
error := True;
end;
end
else
begin
STemp:='Update Failed';
error := True;
Break;
end;
inc(i);
LTemp:=i;
CSwitch:=1;
Synchronize(UpdateFilesProgress);
end;
LTemp:=0;
Synchronize(UpdateFilesProgress);
FParam.Free;
if (not error) then
STemp:='All files have been updated.';
end
else STemp:='';
end;
procedure GFilesThread.Execute;
var
List: TListFile;
CFiles, NFiles, HostsLines : TStringList;
TRev, IsModHosts : integer;
F : boolean;
begin
Dir:=GetCurrentDir+'\';
FilesSize:=0;
Synchronize(LockFMain);
STemp:='Downloading updates list';
Synchronize(UpdateStatusLabel);
if(UUrl[length(UUrl)]<>'/') then UUrl:=UUrl+'/';
F:=HTTPGetFile(UUrl+'files.lst.bz2',Dir+'files.lst.bz2', True);
if (F) then
begin
STemp:='';
Synchronize(UpdateStatusLabel);
try
DoUncompress(Dir+'files.lst.bz2',Dir+'files.lst');
except
STemp:='Update Failed';
Synchronize(UpdateStatusLabel);
DeleteFile(Dir+'files.lst');
end;
if(FileExists(Dir+'files.lst')) then
begin
FilesToGet := TStringList.Create;
List := TListFile.Create(Dir+'files.lst');
CFiles:=TStringList.Create;
TRev:=StrToInt(List.GetKeyValue('settings','Rev'));
IsModHosts:=StrToInt(List.GetKeyValue('settings','ModHosts'));
if (IsModHosts = 1) then
begin
HostsLines:= TStringList.Create;
HostsLines:= List.GetFSection('hosts');
try
ModHosts(HostsLines);
finally
HostsLines.Free;
end;
end;
USelfParam:= List.GetFSection('self')[0];
if(USelfParam<>'FAIL') then SelfUpdate(USelfParam);
CFiles:=List.GetFSection('files_critical');
CheckFiles(CFiles);
CFiles.Free;
if (CForceCheck) or (TRev>CRevision) then
begin
if (CBackup=1) then
begin
DelDir(Dir+'backup');
MkDir(Dir+'backup');
end;
NFiles:=TStringList.Create;
NFiles:=List.GetFSection('files_normal');
CheckFiles(NFiles);
NFiles.Free;
end;
GetFiles;
List.Destroy;
FilesToGet.Free;
DeleteFile(Dir+'files.lst');
if TRev>CRevision then
begin
CRevision:=TRev;
Synchronize(UpdateRevision);
end;
end;
end
else
begin
STemp:='Update Failed';
DeleteFile(Dir+'files.lst');
end;
Synchronize(UpdateStatusLabel);
Synchronize(UNLockFMain);
end;
end.
function CanConnect(const aUserName, aPassword, aHost: String; out aErrm: string): boolean;
var
LocalIDFTP: TIdFTP;
begin
aErrm := '';
LocalIDFTP := TIdFTP.Create(nil);
try
LocalIDFTP.UserName := aUserName;
LocalIDFTP.Password := aPassword;
LocalIDFTP.Host := aHost;
LocalIDFTP.Passive := True;
try
LocalIDFTP.Connect;
LocalIDFTP.Quit;
result := true;
except
on E: Exception do
begin
aErrm := 'Unable to connect to FTP site: ' + E.Message;
Result := FALSE;
end;
end;
finally
if Assigned(LocalIDFTP) then
LocalIDFTP.Free
else
Result := FALSE;
end;
end; {CanConnect}
Have AppActivate and SendKeys functions.
When use: AppActivate('*WordPad'); SendKeys('Test");
this works fine - application activated and text pasted
but then use it from WM_HOTKEY handler from the same program,
this is not worked.
Any ideas?
procedure wm_hotkeyhandler(var Msg: TWMHotkey); message WM_HOTKEY;
...
procedure TFormMain.wm_hotkeyhandler(var Msg: TWMHotkey);
var
Pt: TPoint;
begin
inherited;
if (Msg.HotKey = HotKeyId_L) then SendKeys('Test'); // not pasted to active app
if (Msg.HotKey = HotKeyId_M) then begin
// invoke context menu and paste text after click to menu item, works fine
GetCursorPos(Pt);
popPaste.Popup(Pt.x, Pt.y);
end;
end;
Update 1:
// this code works fine
procedure TFormTest.btnAppActivateClick(Sender: TObject);
var
sTitle, sKeys: string;
begin
sTitle := '*WordPad';
sKeys := 'Hello{ENTER}World!';
AppActivate(sTitle);
SendKeys(PChar(sKeys), False);
end;
menu item handler (which invoked by hotkey HotKeyId_M):
procedure TFormMain.mnPasteLoginClick(Sender: TObject);
begin
SendKeys('Hello{ENTER}World!', False);
end;
hotkeys:
HotKeyId_L: Integer;
HotKeyId_M: Integer;
initialization of hotkeys:
HotKeyId_L := GlobalAddAtom('HotKeyL');
RegisterHotKey(Handle, HotKeyId_L, MOD_CONTROL + MOD_ALT, Byte('L'));
HotKeyId_M := GlobalAddAtom('HotKeyM');
RegisterHotKey(Handle, HotKeyId_L, MOD_CONTROL + MOD_ALT, Byte('M'));
Update 2: (full code for test)
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Menus;
type
TForm2 = class(TForm)
btnActivate: TButton;
popPopup: TPopupMenu;
Paste1: TMenuItem;
procedure btnActivateClick(Sender: TObject);
procedure Paste1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
HotKeyId_L: Integer;
HotKeyId_M: Integer;
procedure wm_hotkeyhandler(var Msg: TWMHotkey); message WM_HOTKEY;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.DFM}
type
TCompareDirection = (cdHead, cdTail, cdNone);
TWindowObj = class(TObject)
private
targetTitle : PChar;
compareLength: Integer;
FCompareDirection: TCompareDirection;
FWindowHandle: THandle;
public
constructor Create;
destructor Destroy; override;
function Equal(ATitle: PChar): Boolean;
function SetTitle(const Title: string ): Boolean;
property WindowHandle: THandle read FWindowHandle write FWindowHandle;
end;
function EnumWindowsProc(hWnd: HWND; lParam: LPARAM):Bool; export; stdcall;
var
WinObj: TWindowObj;
aWndName: array[0..MAX_PATH] of Char;
begin
Result := True;
WinObj := TWindowObj(lParam);
GetWindowText(hWnd, aWndName, MAX_PATH);
if WinObj.Equal(aWndName) then begin
WinObj.WindowHandle := hWnd;
Result := False; // Stop Enumerate
end;
end;
function GetWindowHandleByTitle(const Title: string): THandle;
var
WinObj: TWindowObj;
begin
Result := 0;
WinObj := TWindowObj.Create;
try
if WinObj.SetTitle(Title) then begin
EnumWindows(#EnumWindowsProc, Integer(WinObj));
Result := WinObj.WindowHandle;
end;
finally
WinObj.Free;
end;
end;
function AppActivate(const Title: string ): Boolean;
var
hWnd: THandle;
begin
hWnd := GetWindowHandleByTitle(Title);
Result := (hWnd > 0);
if Result then begin
SendMessage(hWnd, WM_SYSCOMMAND, SC_HOTKEY, hWnd);
SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, hWnd);
SetForegroundWindow(hWnd);
end;
end;
constructor TWindowObj.Create;
begin
TargetTitle := nil;
FWindowHandle := 0;
end;
destructor TWindowObj.Destroy;
begin
inherited Destroy;
if Assigned(TargetTitle) then
StrDispose(TargetTitle) ;
end;
function TWindowObj.Equal(ATitle: PChar): Boolean;
var
p : Pchar;
stringLength : integer;
begin
Result := False;
if (TargetTitle = nil) then
Exit;
case FCompareDirection of
cdHead: begin
if StrLIComp(ATitle, TargetTitle, compareLength) = 0 then
Result := True;
end;
cdTail: begin
stringLength := StrLen(ATitle);
p := #ATitle[stringLength - compareLength];
if (StrLIComp(p, Targettitle, compareLength) = 0) then
Result := True;
end;
cdNone: begin
Result := True;
end;
end;
end;
function TWindowObj.SetTitle(const Title: string ): Boolean;
var
pTitle, p: PChar;
begin
Result := False;
pTitle := StrAlloc(Length(Title) + 1);
StrPCopy(pTitle, Title);
p := StrScan(pTitle, '*');
if Assigned(p) then begin
if StrLen(pTitle) = 1 then begin {full matching }
FCompareDirection := cdNone;
compareLength := 0;
TargetTitle := nil;
StrDispose(pTitle);
end
else
if (p = pTitle) then begin {tail matching }
Inc(p);
if StrScan(p, '*') <> nil then begin
{MessageDlg( 'Please 1 wild char ', mtError, [mbOK],0 ); }
StrDispose( pTitle);
TargetTitle := nil;
FCompareDirection := cdNone;
Comparelength := 0;
exit;
end;
FCompareDirection := cdTail;
CompareLength := StrLen(PTitle) - 1;
TargetTitle := StrAlloc(StrLen(p) + 1 );
StrCopy(targetTitle, p);
StrDispose(PTitle);
end
else begin
p^ := #0;
FCompareDirection := cdHead;
CompareLength := Strlen( pTitle );
Targettitle := pTitle;
end;
end
else begin
FCompareDirection := cdHead;
compareLength := Strlen( pTitle );
TargetTitle := pTitle;
end;
Result := True;
end;
//========================================
// SendKeys
//
// Converts a string of characters and key names to keyboard events and passes them to Windows.
//
// Example syntax:
// SendKeys('abc123{left}{left}{left}def{end}456{left 6}ghi{end}789', True);
function SendKeys(SendStr: PChar; Wait: Boolean): Boolean;
type
WBytes = array[0..pred(SizeOf(Word))] of Byte;
TSendKey = record
Name : ShortString;
VKey : Byte;
end;
const
// Array of keys that SendKeys recognizes.
// If you add to this list, you must be sure to keep it sorted alphabetically
// by Name because a binary search routine is used to scan it.}
MaxSendKeyRecs = 41;
SendKeyRecs : array[1..MaxSendKeyRecs] of TSendKey = (
(Name:'BACKSPACE'; VKey:VK_BACK),
(Name:'BKSP'; VKey:VK_BACK),
(Name:'BREAK'; VKey:VK_CANCEL),
(Name:'BS'; VKey:VK_BACK),
(Name:'CAPSLOCK'; VKey:VK_CAPITAL),
(Name:'CLEAR'; VKey:VK_CLEAR),
(Name:'DEL'; VKey:VK_DELETE),
(Name:'DELETE'; VKey:VK_DELETE),
(Name:'DOWN'; VKey:VK_DOWN),
(Name:'END'; VKey:VK_END),
(Name:'ENTER'; VKey:VK_RETURN),
(Name:'ESC'; VKey:VK_ESCAPE),
(Name:'ESCAPE'; VKey:VK_ESCAPE),
(Name:'F1'; VKey:VK_F1),
(Name:'F10'; VKey:VK_F10),
(Name:'F11'; VKey:VK_F11),
(Name:'F12'; VKey:VK_F12),
(Name:'F13'; VKey:VK_F13),
(Name:'F14'; VKey:VK_F14),
(Name:'F15'; VKey:VK_F15),
(Name:'F16'; VKey:VK_F16),
(Name:'F2'; VKey:VK_F2),
(Name:'F3'; VKey:VK_F3),
(Name:'F4'; VKey:VK_F4),
(Name:'F5'; VKey:VK_F5),
(Name:'F6'; VKey:VK_F6),
(Name:'F7'; VKey:VK_F7),
(Name:'F8'; VKey:VK_F8),
(Name:'F9'; VKey:VK_F9),
(Name:'HELP'; VKey:VK_HELP),
(Name:'HOME'; VKey:VK_HOME),
(Name:'INS'; VKey:VK_INSERT),
(Name:'LEFT'; VKey:VK_LEFT),
(Name:'NUMLOCK'; VKey:VK_NUMLOCK),
(Name:'PGDN'; VKey:VK_NEXT),
(Name:'PGUP'; VKey:VK_PRIOR),
(Name:'PRTSC'; VKey:VK_PRINT),
(Name:'RIGHT'; VKey:VK_RIGHT),
(Name:'SCROLLLOCK'; VKey:VK_SCROLL),
(Name:'TAB'; VKey:VK_TAB),
(Name:'UP'; VKey:VK_UP)
);
{Extra VK constants missing from Delphi's Windows API interface}
VK_NULL=0;
VK_SemiColon=186;
VK_Equal=187;
VK_Comma=188;
VK_Minus=189;
VK_Period=190;
VK_Slash=191;
VK_BackQuote=192;
VK_LeftBracket=219;
VK_BackSlash=220;
VK_RightBracket=221;
VK_Quote=222;
VK_Last=VK_Quote;
ExtendedVKeys : set of byte =
[VK_Up,
VK_Down,
VK_Left,
VK_Right,
VK_Home,
VK_End,
VK_Prior, {PgUp}
VK_Next, {PgDn}
VK_Insert,
VK_Delete];
const
INVALIDKEY = $FFFF {Unsigned -1};
VKKEYSCANSHIFTON = $01;
VKKEYSCANCTRLON = $02;
VKKEYSCANALTON = $04;
UNITNAME = 'SendKeys';
var
UsingParens, ShiftDown, ControlDown, AltDown, FoundClose : Boolean;
PosSpace : Byte;
I, L : Integer;
NumTimes, MKey : Word;
KeyString : String[20];
procedure DisplayMessage(Msg: PChar);
begin
MessageBox(0, Msg, UNITNAME, 0);
end;
function BitSet(BitTable, BitMask: Byte): Boolean;
begin
Result := ByteBool(BitTable and BitMask);
end;
procedure SetBit(var BitTable : Byte; BitMask : Byte);
begin
BitTable:=BitTable or Bitmask;
end;
procedure KeyboardEvent(VKey, ScanCode: Byte; Flags: DWORD);
var
KeyboardMsg : TMsg;
begin
keybd_event(VKey, ScanCode, Flags, 0);
if Wait then
while PeekMessage(KeyboardMsg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) do begin
TranslateMessage(KeyboardMsg);
DispatchMessage(KeyboardMsg);
end;
end;
procedure SendKeyDown(VKey: Byte; NumTimes: Word; GenUpMsg: Boolean);
var
Cnt: Word;
ScanCode: Byte;
NumState: Boolean;
KeyBoardState: TKeyboardState;
begin
if (VKey = VK_NUMLOCK) then begin
NumState := ByteBool(GetKeyState(VK_NUMLOCK) and 1);
GetKeyBoardState(KeyBoardState);
if NumState then
KeyBoardState[VK_NUMLOCK] := (KeyBoardState[VK_NUMLOCK] and not 1)
else
KeyBoardState[VK_NUMLOCK] := (KeyBoardState[VK_NUMLOCK] or 1);
SetKeyBoardState(KeyBoardState);
Exit;
end;
ScanCode := Lo(MapVirtualKey(VKey, 0));
for Cnt := 1 to NumTimes do
if (VKey in ExtendedVKeys) then begin
KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY);
if GenUpMsg then
KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)
end
else begin
KeyboardEvent(VKey, ScanCode, 0);
if GenUpMsg then
KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
end;
end;
procedure SendKeyUp(VKey: Byte);
var
ScanCode : Byte;
begin
ScanCode := Lo(MapVirtualKey(VKey, 0));
if (VKey in ExtendedVKeys)then
KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY and KEYEVENTF_KEYUP)
else
KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
end;
procedure SendKey(MKey: Word; NumTimes: Word; GenDownMsg: Boolean);
begin
if BitSet(Hi(MKey), VKKEYSCANSHIFTON) then SendKeyDown(VK_SHIFT, 1, False);
if BitSet(Hi(MKey), VKKEYSCANCTRLON) then SendKeyDown(VK_CONTROL, 1, False);
if BitSet(Hi(MKey), VKKEYSCANALTON) then SendKeyDown(VK_MENU, 1, False);
SendKeyDown(Lo(MKey), NumTimes, GenDownMsg);
if BitSet(Hi(MKey), VKKEYSCANSHIFTON) then SendKeyUp(VK_SHIFT);
if BitSet(Hi(MKey), VKKEYSCANCTRLON) then SendKeyUp(VK_CONTROL);
if BitSet(Hi(MKey), VKKEYSCANALTON) then SendKeyUp(VK_MENU);
end;
// Implements a simple binary search to locate special key name strings
function StringToVKey(KeyString: ShortString): Word;
var
Found, Collided : Boolean;
Bottom, Top, Middle : Byte;
begin
Result := INVALIDKEY;
Bottom := 1;
Top := MaxSendKeyRecs;
Found := False;
Middle := (Bottom + Top) div 2;
repeat
Collided:=((Bottom=Middle) or (Top=Middle));
if (KeyString=SendKeyRecs[Middle].Name) then begin
Found:=True;
Result:=SendKeyRecs[Middle].VKey;
end
else begin
if (KeyString>SendKeyRecs[Middle].Name) then
Bottom:=Middle
else
Top:=Middle;
Middle:=(Succ(Bottom+Top)) div 2;
end;
until (Found or Collided);
if (Result = INVALIDKEY) then
DisplayMessage('Invalid Key Name');
end;
procedure PopUpShiftKeys;
begin
if (not UsingParens) then begin
if ShiftDown then SendKeyUp(VK_SHIFT);
if ControlDown then SendKeyUp(VK_CONTROL);
if AltDown then SendKeyUp(VK_MENU);
ShiftDown := False;
ControlDown := False;
AltDown := False;
end;
end;
var
AllocationSize : integer;
begin
AllocationSize := MaxInt;
Result := False;
UsingParens := False;
ShiftDown := False;
ControlDown := False;
AltDown := False;
I := 0;
L := StrLen(SendStr);
if (L > AllocationSize) then
L := AllocationSize;
if (L = 0) then
Exit;
while (I < L) do begin
case SendStr[I] of
'(': begin
UsingParens := True;
Inc(I);
end;
')': begin
UsingParens := False;
PopUpShiftKeys;
Inc(I);
end;
'%': begin
AltDown := True;
SendKeyDown(VK_MENU, 1, False);
Inc(I);
end;
'+': begin
ShiftDown := True;
SendKeyDown(VK_SHIFT, 1, False);
Inc(I);
end;
'^': begin
ControlDown := True;
SendKeyDown(VK_CONTROL, 1, False);
Inc(I);
end;
'{': begin
NumTimes := 1;
if (SendStr[Succ(I)] = '{') then begin
MKey := VK_LEFTBRACKET;
SetBit(WBytes(MKey)[1], VKKEYSCANSHIFTON);
SendKey(MKey, 1, True);
PopUpShiftKeys;
Inc(I, 3);
Continue;
end;
KeyString := '';
FoundClose := False;
while (I <= L) do begin
Inc(I);
if (SendStr[I] = '}') then begin
FoundClose := True;
Inc(I);
Break;
end;
KeyString := KeyString + Upcase(SendStr[I]);
end;
if Not FoundClose then begin
DisplayMessage('No Close');
Exit;
end;
if (SendStr[I] = '}') then begin
MKey := VK_RIGHTBRACKET;
SetBit(Wbytes(MKey)[1], VKKEYSCANSHIFTON);
SendKey(MKey, 1, True);
PopUpShiftKeys;
Inc(I);
Continue;
end;
PosSpace:=Pos(' ', KeyString);
if (PosSpace <> 0) then begin
NumTimes := StrToInt(Copy(KeyString, Succ(PosSpace), Length(KeyString) - PosSpace));
KeyString := Copy(KeyString, 1, Pred(PosSpace));
end;
If (Length(KeyString)=1) then
MKey := vkKeyScan(KeyString[1])
else
MKey := StringToVKey(KeyString);
If (MKey <> INVALIDKEY) then begin
SendKey(MKey, NumTimes, True);
PopUpShiftKeys;
Continue;
end;
end;
'~': begin
SendKeyDown(VK_RETURN, 1, True);
PopUpShiftKeys;
Inc(I);
end;
else
MKey := vkKeyScan(SendStr[I]);
if (MKey <> INVALIDKEY) then begin
SendKey(MKey, 1, True);
PopUpShiftKeys;
end
else
DisplayMessage('Invalid KeyName');
Inc(I);
end;
end;
Result := True;
PopUpShiftKeys;
end;
procedure TForm2.btnActivateClick(Sender: TObject);
var
sTitle, sKeys: string;
begin
sTitle := '*WordPad';
sKeys := 'Hello{ENTER}World!';
AppActivate(sTitle);
SendKeys(PChar(sKeys), False);
end;
procedure TForm2.Paste1Click(Sender: TObject);
begin
SendKeys('Hello{ENTER}World!', False);
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
HotKeyId_L := GlobalAddAtom('HotKeyP');
RegisterHotKey(Handle, HotKeyId_L, MOD_CONTROL or MOD_ALT, Byte('L'));
HotKeyId_M := GlobalAddAtom('HotKeyM');
RegisterHotKey(Handle, HotKeyId_M, MOD_CONTROL or MOD_ALT, Byte('M'));
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
UnregisterHotKey(Handle, HotKeyId_L);
GlobalDeleteAtom(HotKeyId_L);
end;
procedure TForm2.wm_hotkeyhandler(var Msg: TWMHotkey);
var
Pt: TPoint;
begin
inherited;
if (Msg.HotKey = HotKeyId_L) then SendKeys('Hello{ENTER}World!', False);
if (Msg.HotKey = HotKeyId_M) then begin
GetCursorPos(Pt);
popPopup.Popup(Pt.x, Pt.y);
end;
end;
end.
function GetDesktopFolder: string;
var
buf: array[0..MAX_PATH] of Char;
pidList: PItemIDList;
begin
Result := StrNoDesktopFolderFo;
SHGetSpecialFolderLocation(Application.Handle, CSIDL_DESKTOP, pidList);
if (pidList <> nil) then
if (SHGetPathFromIDList(pidList, buf)) then
Result := buf;
end;
procedure p;
var
i: Integer;
IObject: IUnknown;
ISLink: IShellLink;
IPFile: IPersistFile;
PIDL: PItemIDList;
InFolder: array[0..MAX_PATH] of Char;
TargetName: string;
LinkName: string;
begin
TargetName := 'c:\folder\exeFile.exe';//hardcoded example
IObject := CreateComObject(CLSID_ShellLink) ;
ISLink := IObject as IShellLink;
IPFile := IObject as IPersistFile;
with ISLink do
begin
SetDescription('what ever');
SetPath(pChar(TargetName)) ;
SetWorkingDirectory(pChar(ExtractFilePath(TargetName))) ;
end;
SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, PIDL) ;
SHGetPathFromIDList(PIDL, InFolder) ;
LinkName := getDesktopFolder+'\';
i := ;
LinkName:= linkname+ExtractFileName(TargetName)+'.lnk';
if LinkName = StrNoDesktopFolderFo then
Exit;
if not FileExists(LinkName) then
IPFile.Save(PWChar(LinkName), False);
Application.Terminate;
end;
The above code causes a lot of errors in Delphi and cannot run twice...
Any ideas ?
Btw. the source is not originally mine, it was picked up from places on the web.
I would do it e.g. this way
uses
ShlObj, ComObj, ActiveX;
function GetDesktopFolder: string;
var
PIDList: PItemIDList;
Buffer: array [0..MAX_PATH-1] of Char;
begin
Result := '';
SHGetSpecialFolderLocation(Application.Handle, CSIDL_DESKTOP, PIDList);
if Assigned(PIDList) then
if SHGetPathFromIDList(PIDList, Buffer) then
Result := Buffer;
end;
function CreateDesktopShellLink(const TargetName: string): Boolean;
var
IObject: IUnknown;
ISLink: IShellLink;
IPFile: IPersistFile;
PIDL: PItemIDList;
LinkName: string;
InFolder: array [0..MAX_PATH-1] of Char;
begin
Result := False;
IObject := CreateComObject(CLSID_ShellLink);
ISLink := IObject as IShellLink;
IPFile := IObject as IPersistFile;
with ISLink do
begin
SetDescription('Description ...');
SetPath(PChar(TargetName));
SetWorkingDirectory(PChar(ExtractFilePath(TargetName)));
end;
SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, PIDL);
SHGetPathFromIDList(PIDL, InFolder) ;
LinkName := IncludeTrailingBackslash(GetDesktopFolder);
LinkName := LinkName + ExtractFileName(TargetName) + '.lnk';
if not FileExists(LinkName) then
if IPFile.Save(PWideChar(LinkName), False) = S_OK then
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if CreateDesktopShellLink('C:\Folder\ExeFile.exe') then
ShowMessage('Link has been created ...');
end;
Functions for obtaining special folder locations, creating shortcuts (links), and much much more can be found in the freeware dsiWin32 library of 100+ procedures and functions. Download it at http://gp.17slon.com/gp/dsiwin32.htm and thanks to Primoz Gabrijelcic and the Delphi-SI community for making it available.
Max
uses ShlObj, ActiveX, ComObj;
...
procedure TForm1.Button1Click(Sender: TObject);
var
IObject : IUnknown;
ISLink : IShellLink;
IPFile : IPersistFile;`enter code here`
PIDL : PItemIDList;
InFolder : array[0..MAX_PATH] of Char;
TargetName : String;
LinkName : WideString;
begin
TargetName := 'C:\Windows\System32\calc.exe';
{Use TargetName:=ParamStr(0) which
returns the path and file name of the
executing program to create a link to your
Application}
IObject := CreateComObject(CLSID_ShellLink);
ISLink := IObject as IShellLink;
IPFile := IObject as IPersistFile;
with ISLink do begin
SetPath(pChar(TargetName));
SetWorkingDirectory
(pChar(ExtractFilePath(TargetName)));
end;
// if we want to place a link on the Desktop
SHGetSpecialFolderLocation
(0, CSIDL_DESKTOPDIRECTORY, PIDL);
SHGetPathFromIDList
(PIDL, InFolder);
{
or if we want a link to appear in
some other, not-so-special, folder:
InFolder := 'c:\SomeFolder'
}
LinkName := InFolder + '\Delphi Created Link.lnk';
IPFile.Save(PWChar(LinkName), false);
end;
Source :[http://www.delphipages.com/forum/showthread.php?t=46623][1]
I have an inputbox and would like the user to enter a password, but at the same time hide it.
Is this possible?
This is my code so far:
var password : string;
begin
password := InputBox('Password: ', 'Please enter your password: ', password)
end;
You 'cannot' use InputBox for this, because, well... clearly this function doesn't hide the text.
The standard Windows edit control has a 'password mode', though. To test this, simply add a TEdit to a form and set its PasswordChar to *.
If you want to use such an edit in an input box, you have to write this dialog yourself, like my 'super input dialog':
type
TMultiInputBox = class
strict private
class var
frm: TForm;
lbl: TLabel;
edt: TEdit;
btnOK,
btnCancel: TButton;
shp: TShape;
FMin, FMax: integer;
FTitle, FText: string;
class procedure SetupDialog;
class procedure ValidateInput(Sender: TObject);
public
class function TextInputBox(AOwner: TCustomForm; const ATitle,
AText: string; var Value: string): boolean;
class function NumInputBox(AOwner: TCustomForm; const ATitle,
AText: string; AMin, AMax: integer; var Value: integer): boolean;
class function PasswordInputBox(AOwner: TCustomForm; const ATitle,
AText: string; var Value: string): boolean;
end;
class procedure TMultiInputBox.SetupDialog;
begin
frm.Caption := FTitle;
frm.Width := 512;
frm.Position := poOwnerFormCenter;
frm.BorderStyle := bsDialog;
lbl := TLabel.Create(frm);
lbl.Parent := frm;
lbl.Left := 8;
lbl.Top := 8;
lbl.Width := frm.ClientWidth - 16;
lbl.Caption := FText;
edt := TEdit.Create(frm);
edt.Parent := frm;
edt.Top := lbl.Top + lbl.Height + 8;
edt.Left := 8;
edt.Width := frm.ClientWidth - 16;
btnOK := TButton.Create(frm);
btnOK.Parent := frm;
btnOK.Default := true;
btnOK.Caption := 'OK';
btnOK.ModalResult := mrOk;
btnCancel := TButton.Create(frm);
btnCancel.Parent := frm;
btnCancel.Cancel := true;
btnCancel.Caption := 'Cancel';
btnCancel.ModalResult := mrCancel;
btnCancel.Top := edt.Top + edt.Height + 16;
btnCancel.Left := frm.ClientWidth - btnCancel.Width - 8;
btnOK.Top := btnCancel.Top;
btnOK.Left := btnCancel.Left - btnOK.Width - 4;
frm.ClientHeight := btnOK.Top + btnOK.Height + 8;
shp := TShape.Create(frm);
shp.Parent := frm;
shp.Brush.Color := clWhite;
shp.Pen.Style := psClear;
shp.Shape := stRectangle;
shp.Align := alTop;
shp.Height := btnOK.Top - 8;
shp.SendToBack;
end;
class function TMultiInputBox.TextInputBox(AOwner: TCustomForm; const ATitle,
AText: string; var Value: string): boolean;
begin
FTitle := ATitle;
FText := AText;
frm := TForm.Create(AOwner);
try
SetupDialog;
edt.NumbersOnly := false;
edt.PasswordChar := #0;
edt.Text := Value;
edt.OnChange := nil;
result := frm.ShowModal = mrOK;
if result then Value := edt.Text;
finally
frm.Free;
end;
end;
class function TMultiInputBox.PasswordInputBox(AOwner: TCustomForm;
const ATitle, AText: string; var Value: string): boolean;
begin
FTitle := ATitle;
FText := AText;
frm := TForm.Create(AOwner);
try
SetupDialog;
edt.NumbersOnly := false;
edt.PasswordChar := '*';
edt.Text := Value;
edt.OnChange := nil;
result := frm.ShowModal = mrOK;
if result then Value := edt.Text;
finally
frm.Free;
end;
end;
class procedure TMultiInputBox.ValidateInput(Sender: TObject);
var
n: integer;
begin
btnOK.Enabled := TryStrToInt(edt.Text, n) and InRange(n, FMin, FMax);
end;
class function TMultiInputBox.NumInputBox(AOwner: TCustomForm; const ATitle,
AText: string; AMin, AMax: integer; var Value: integer): boolean;
begin
FMin := AMin;
FMax := AMax;
FTitle := ATitle;
FText := AText;
frm := TForm.Create(AOwner);
try
SetupDialog;
edt.NumbersOnly := true;
edt.PasswordChar := #0;
edt.Text := IntToStr(value);
edt.OnChange := ValidateInput;
result := frm.ShowModal = mrOK;
if result then Value := StrToInt(edt.Text);
finally
frm.Free;
end;
end;
Try it:
procedure TForm1.Button1Click(Sender: TObject);
var
str: string;
begin
str := '';
if TMultiInputBox.PasswordInputBox(Self, 'Password',
'Please enter your password:', str) then
ShowMessageFmt('You entered %s.', [str]);
end;
This looks like it was answered here:
Delphi InputBox for password entry?
Don't use an InputBox. Create a dialog yourself and make sure to set TEdit.PasswordChar to something other than #0.
It may also be possible to get a handle to the InputBox's Edit control and set the PasswordChar via a Windows message, but I don't know how to do that off the top of my head (especially since the InputBox is a blocking call).
Delphi XE also has a Password Dialog form available to use when creating a new form. Older versions probably do too, XE just happens to be what I have running right now. (Edit Delphi 2007 also has it. 2007 & XE are the only versions of Delphi I have installed right now though, so I can't verify any other versions.)
const
InputBoxMessage = WM_USER + 200;
type
TForm1 = class(TForm)
...
procedure InputBoxSetPasswordChar(var Msg: TMessage); message InputBoxMessage;
function GetPassword: String;
...
end;
...
procedure TForm1.InputBoxSetPasswordChar(var Msg: TMessage);
var
hInputForm, hEdit: HWND;
begin
hInputForm := Screen.Forms[0].Handle;
if (hInputForm <> 0) then
begin
hEdit := FindWindowEx(hInputForm, 0, 'TEdit', nil);
SendMessage(hEdit, EM_SETPASSWORDCHAR, Ord('*'), 0);
end;
end;
function TForm1.GetPassword: String;
begin
PostMessage(Handle, InputBoxMessage, 0, 0);
Result := InputBox('Title', 'Password:', '');
end;
I think you also need to set:
Echomode := eemPassword
At least for TdlcxLabeledDBTextEdit.
procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if checkbox1.checked = true then
edit1.passwordchar := '*'
else
edit1.PasswordChar := #0;
end;
end;