Ian Branch
Members-
Content Count
1352 -
Joined
-
Last visited
-
Days Won
3
Everything posted by Ian Branch
-
How to get the version of Delphi that the App is built with?
Ian Branch posted a topic in General Help
Hi Team, At the moment I use a variable to indicate the Delphi version for an About box in Apps. This looks like this: Delphi Athens 12.2 Patch 2. Is there some meaans within Delphi to return this information, or a reasonable semblance, so I don't have to manually update the About box? Regards & TIA, Ian -
How to get the version of Delphi that the App is built with?
Ian Branch replied to Ian Branch's topic in General Help
As could I, but I was hoping for something more informative from Delphi. That 'uniquely identifying number' is applicable to Delphi 12.0, 12.1, 12.2, 12.2 Patch 1 & 12.2 Patch 2. Never mind. I will stick with manual updates as required. -
How to get the version of Delphi that the App is built with?
Ian Branch replied to Ian Branch's topic in General Help
That will only return 36. Call it a personal preference, I like to have the information in the About dialog. Saying the Application was built with 'Delphi v 36' isn't as informative as 'Delphi Athens v 12.2 Patch 2'. -
Putting Delphi Application inside web page
Ian Branch replied to Robert Gilland's topic in Delphi Third-Party
I agree with your comments. I suspect it is a visibility/awareness issue. I have spoken with many of my peers and they were not aware of it. I also think that developers are focussing on Apple & Android for Apps on thos devices rather than what can be done within the PC realm. -
Ah Ha! Tks. All good now. Never heard of the 'unblock' 'feature'...
-
Win 11, 4k monitor. Hmm. Downloaded OK, Opened OK. Left Pane works fine, nothing shows in the main pane. π
-
Thank you one and all. For the record, I have it working with the following code: unit Unit20; interface uses Winapi.Windows, Winapi.TlHelp32, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls; type TForm20 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form20: TForm20; implementation {$R *.dfm} type PTOKEN_USER = ^TOKEN_USER; // function IsFileOpen(const FileName: string): Boolean; var HFile: THandle; begin // Try to open the file with exclusive access (no sharing allowed) HFile := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); // Check if the file handle is invalid, which indicates an error if HFile = INVALID_HANDLE_VALUE then // Check if the error is due to a sharing violation Result := GetLastError = ERROR_SHARING_VIOLATION else begin // If the file was successfully opened, it means thereβs no sharing violation Result := False; CloseHandle(HFile); // Close the handle if we managed to open the file end; // end; function GetUserNameForProcess(ProcessID: DWORD): string; var hProcess: THandle; TokenHandle: THandle; //TokenUser: PTOKENUSER; ptiUser: PTOKEN_USER; ReturnLength: DWORD; Name: array[0..255] of Char; NameLength: DWORD; Domain: array[0..255] of Char; DomainLength: DWORD; Use: SID_NAME_USE; begin // Result := 'Unknown'; hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessID); // if hProcess <> 0 then begin if OpenProcessToken(hProcess, TOKEN_QUERY, TokenHandle) then try GetTokenInformation(TokenHandle, TokenUser, nil, 0, ReturnLength); ptiUser := AllocMem(ReturnLength); try if GetTokenInformation(TokenHandle, TokenUser, ptiUser, ReturnLength, ReturnLength) then begin NameLength := SizeOf(Name); DomainLength := SizeOf(Domain); if LookupAccountSid(nil, ptiUser.User.Sid, Name, NameLength, Domain, DomainLength, Use) then Result := Format('%s\%s', [Domain, Name]); end; finally FreeMem(ptiUser); end; finally CloseHandle(TokenHandle); end; CloseHandle(hProcess); end; // end; procedure ScanForDBiFiles(const Directory: string; var Results: TStringList); var SearchRec: TSearchRec; ProcessEntry: TProcessEntry32; Snapshot: THandle; FileName: string; begin // Results.Clear; // if FindFirst(IncludeTrailingPathDelimiter(Directory) + 'DBi*.exe', faAnyFile, SearchRec) = 0 then begin try repeat FileName := IncludeTrailingPathDelimiter(Directory) + SearchRec.Name; // Check if the file is open if IsFileOpen(FileName) then begin // Enumerate processes to find the one using this file Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if Snapshot <> INVALID_HANDLE_VALUE then begin ProcessEntry.dwSize := SizeOf(TProcessEntry32); if Process32First(Snapshot, ProcessEntry) then begin repeat // Check if the process has the same file name as the one we're looking for if SameText(ExtractFileName(ProcessEntry.szExeFile), SearchRec.Name) then begin // Results.Add(Format('File: %s, User: %s', [FileName, GetUserNameForProcess(ProcessEntry.th32ProcessID)])); Results.Add(Format('File: %-17s User: %s', [ExtractFileName(FileName), GetUserNameForProcess(ProcessEntry.th32ProcessID)])); // Break; end; until not Process32Next(Snapshot, ProcessEntry); end; CloseHandle(Snapshot); end; end; until FindNext(SearchRec) <> 0; finally FindClose(SearchRec); end; end; // end; procedure TForm20.Button1Click(Sender: TObject); var Results: TStringList; begin // Results := TStringList.Create; try ScanForDBiFiles('E:\DBiWorkflow', Results); Memo1.Lines.Assign(Results); // This line adds the results to Memo1 finally Results.Free; end; // end; end. My thanks to all for your input. Appreciated. Ian
-
Win 11, D12.2 P1. 32 bit App. I asked ChatGPT to write a unit that would scan a given drive/directory for all instances of a .exe file starting with 'DBi', and return the name of the file(s) that were currently in use and the name of the User(s). ChatGPT gave me this: uses System.SysUtils, System.Classes, Windows, TlHelp32, PsAPI, JclSysInfo; function IsFileOpen(const FileName: string): Boolean; var HFile: THandle; begin HFile := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); Result := (HFile = INVALID_HANDLE_VALUE); if not Result then CloseHandle(HFile); end; function GetUserNameForProcess(ProcessID: DWORD): string; var hProcess: THandle; TokenHandle: THandle; TokenUser: PTOKEN_USER; ReturnLength: DWORD; Name: array[0..255] of Char; NameLength: DWORD; Domain: array[0..255] of Char; DomainLength: DWORD; Use: SID_NAME_USE; begin Result := 'Unknown'; hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessID); if hProcess <> 0 then begin if OpenProcessToken(hProcess, TOKEN_QUERY, TokenHandle) then try GetTokenInformation(TokenHandle, TokenUser, nil, 0, ReturnLength); TokenUser := AllocMem(ReturnLength); try if GetTokenInformation(TokenHandle, TokenUser, ReturnLength, ReturnLength) then begin NameLength := SizeOf(Name); DomainLength := SizeOf(Domain); if LookupAccountSid(nil, TokenUser.User.Sid, Name, NameLength, Domain, DomainLength, Use) then Result := Format('%s\%s', [Domain, Name]); end; finally FreeMem(TokenUser); end; finally CloseHandle(TokenHandle); end; CloseHandle(hProcess); end; end; procedure ScanForDBiFiles(const Directory: string; var Results: TStringList); var SearchRec: TSearchRec; ProcessEntry: TProcessEntry32; Snapshot: THandle; FileName: string; begin Results.Clear; if FindFirst(IncludeTrailingPathDelimiter(Directory) + 'DBi*.exe', faAnyFile, SearchRec) = 0 then begin try repeat FileName := IncludeTrailingPathDelimiter(Directory) + SearchRec.Name; // Check if the file is open if IsFileOpen(FileName) then begin // Enumerate processes to find the one using this file Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if Snapshot <> INVALID_HANDLE_VALUE then begin ProcessEntry.dwSize := SizeOf(TProcessEntry32); if Process32First(Snapshot, ProcessEntry) then begin repeat // Check if the process has the same file name as the one we're looking for if SameText(ExtractFileName(ProcessEntry.szExeFile), SearchRec.Name) then begin Results.Add(Format('File: %s, User: %s', [FileName, GetUserNameForProcess(ProcessEntry.th32ProcessID)])); Break; end; until not Process32Next(Snapshot, ProcessEntry); end; CloseHandle(Snapshot); end; end; until FindNext(SearchRec) <> 0; finally FindClose(SearchRec); end; end; end; procedure TForm1.Button1Click(Sender: TObject); var Results: TStringList; begin Results := TStringList.Create; try ScanForDBiFiles('C:\YourDirectory', Results); ShowMessage(Results.Text); finally Results.Free; end; end; Whilst most of it is OK, Delphi balks immediately at "TokenUser: PTOKEN_USER;". π Seems it doesn't know about PTOKEN_USER. ?? I think it is part of Windows but I can't pin it down. I would really appreciate any and all help in getting this going. Regards & TIA, Ian
-
Putting Delphi Application inside web page
Ian Branch replied to Robert Gilland's topic in Delphi Third-Party
This is a Web Page one of my Customers has. It is a generic page created by TF. -
Putting Delphi Application inside web page
Ian Branch replied to Robert Gilland's topic in Delphi Third-Party
As a Developer I use it to create Apps and test them. Not daily but regularly. Win 11, 64GB RAM, D12.2, 32 bit apps. My Customers have it running 24/7 so their own staff as well as their Customers can access respective Apps. IIRC, they are using a Windows Server 2012 R2 PC. 2 running an Intel Xeon X3450. 2 x HDD in Raid 1. 16GB RAM. Up to 15 Users att but that may increase soon. RAM usage has got close a couple of times but never got in the road. -
My thanks to all. This is clearly all out of my league. π I will drop this idea. Thanks again to all for your input/advice. Ian
-
Noted. Tks. A minor aspect I can resolve later. Delphi gives me this: [dcc32 Error] Unit20.pas(58): E2010 Incompatible types: 'TTokenInformationClass' and 'PTokenUser'
-
Tks Lajos. Appreciated. That solved that issue but unfortunately I don't understand enough about using Windows stuff to understand why GetTokenInformation(TokenHandle, TokenUser, nil, 0, ReturnLength); and if GetTokenInformation(TokenHandle, TokenUser, ReturnLength, ReturnLength) then are not hapy in this context. π I perceive it is probably to do with the use of TokenUser.
-
Feature enhancement request - Filter DFM properties
Ian Branch replied to pyscripter's topic in GExperts
Ditto.- 11 replies
-
Putting Delphi Application inside web page
Ian Branch replied to Robert Gilland's topic in Delphi Third-Party
Sorry, no idea what the current pricing is. I got it when it was at KickStarter stage way back in 2014. π Cost is based on what options you select and how many Users. I have the Developer Pro version but my Customers have the Standard version with 15 Users. IIRC my renewal was around US$30. Drop a line to Cybele and ask. Ian -
Putting Delphi Application inside web page
Ian Branch replied to Robert Gilland's topic in Delphi Third-Party
Yep. Use it all the time. So do my Customers. It means that I only need to maintain one App and it can be accessed via LAN, WAN, RDP or WEB. It is accessed on the WEB via any Browser. The only issues I have had was more of issues with portable devices/tablets and some compatabilities that need to be accepted or worked around. Particularly mousing. -
My experience today is that if the Library installs or updates by building its .bpl, .dcp & .dcu files than they need to be rebuilt with D12.2 p1. This I suspect is due to the binary incompatability that occurred with D12.2. Now rectified.
-
It is also a breaking change for all those 3rd Party libraries that you get their source code for and install by building their files. I have spent a couple of hours rebuilding libraries I had the source for that needed to be re-installed as, presumably, their existing .bpl/.dcp/.dcu files were no longer compatible. Also the existing installed plug-ins - GExperts, Eurekalog, MMX & cnWizards won't load. I rebuilt GExperts and is OK but I will have to wait for the other 3.
-
Broke the current MMX & cnWizards. π
-
FWIW I can recommend the landrix suite, it is based on anders' suite.
-
In which version of Delphi were the uses unit's qualifiers like Vcl. & System. introduced?
-
Perish the thought. π Excellent. Tks.
-
Tks Dave. I didn't realise it was that 'long' ago. ;-) Cheers.
-
Tks Remy. I suspect the answer is there. I have forwarded the reference to the Developer.