Ian Branch
Members-
Content Count
1360 -
Joined
-
Last visited
-
Days Won
3
Everything posted by Ian Branch
-
Doh! Well, isn't that counter intuitive... Speaks volumes about how we 'journalise' when we read.. Thank you. All sorted now. Regards, Ian
-
Hi Team, Delphi 12.2. I have the following line: ShowMessage('State: ' + System.TypeInfo.GetEnumName(TypeInfo(TDataSetState), Ord(APD.State)) + '. Job # = ' + IntToStr(APD.JobNo)); I tried adding System.TypeInfo to the uses clause but Delphi complains it can't compile it. The issue I have here with this line of code is that Delphi tells me it expects a '(' but found a ',' after the TypeInfo. I checked the code at https://docwiki.embarcadero.com/CodeExamples/Athens/en/TypInfoGetEnumName_(Delphi) and I am consistant with it. Have I missed something or is this a bug? Regards & TIA, Ian
-
Hi Team, Further issues/changes have been identified/adressed in PasZip as a follow on to my initial issue. The current PasZip can be downloaded from https://github.com/synopse/mORMot Regards, Ian
-
Hi Team, I recently started to play in 64 bit. Normally I was 32 bit exclusive. I ran up against an issue with paszip.pas, used in a couple of places in various 3rd Party libraries. I kept geting an error at line 4341 or thereabouts: file_ := INVALID_HANDLE_VALUE; Tracing, I found variable file_ was defined at line around 3963 as a DWORD: file_: dword; This is fine in 32bit but problematic in 64bit. The solution was to change the declaration to: file_: THandle; Now paszip.pas builds without issue in both 32 & 64 bit. HTH in some way.. Regards, Ian
-
Hi Team, My Customer, and I, really like the Emerald Light Slate style, with the exception that shades of Blue would be better than the shades of Green. If you can, how do you change the colours of the Style? In this case in particular the buttons. Regards & TIA, Ian
-
Resolved. It turns out that Aqua Light Slate is the one that I needed/wanted all along.
-
Hi Gord, Thank you for your input. I see what you are suggesting with the Onyx Blue but regrettably it isn't practical. 31+ projects, hundreds of forms in the suite.... I had a play with the Delphi Style Designer but it seems the colors are defined in a bitmap or similar file and I couldn't figure out how to change them.
-
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.