

PeterPanettone
Members-
Content Count
1360 -
Joined
-
Last visited
-
Days Won
5
PeterPanettone last won the day on August 2 2021
PeterPanettone had the most liked content!
Community Reputation
167 ExcellentTechnical Information
-
Delphi-Version
Delphi 12 Athens
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
Compiler directives for line number?
PeterPanettone replied to PeterPanettone's topic in RTL and Delphi Object Pascal
My CPU can afford this 😉 However, I've simplified the CodeSite statement and avoided calling GetLocationInfo twice by using a with statement (without using a record): function GetLocPrefix: string; begin CodeSite.Send('GetLocPrefix: '); // this is called only once! // Directly get the location of the caller (Button1Click), skipping the need for _Loc here with JclDebug.GetLocationInfo(ReturnAddress) do Result := ProcedureName + ' (Line#: ' + IntToStr(LineNumber) + '): '; end; procedure TForm1.Button1Click(Sender: TObject); begin // 1. At design time, insert the CodeSite statement with CTRL+SHIFT+# by using this CnWizards Source Template: // CodeSite.Send(GetLocPrefix + X, X); // 2. Then, replace X with the desired expression, then get the Procedure Name and the current line Number at runtime: CodeSite.Send(GetLocPrefix + 'Sender.ClassName', Sender.ClassName); // 3. The CodeSite result in the CodeSite Live Viewer rsults as: TForm1.Button1Click (Line#: 51): Sender.ClassName = TButton end; -
Compiler directives for line number?
PeterPanettone replied to PeterPanettone's topic in RTL and Delphi Object Pascal
No need to use a record: uses CodeSiteLogging, JCLDebug; function _Loc: JclDebug.TJclLocationInfo; begin Result := JclDebug.GetLocationInfo(ReturnAddress); end; procedure TForm1.Button1Click(Sender: TObject); begin // 1. At design time, insert the CodeSite statement with CTRL+SHIFT+# by using this CnWizards Source Template: // CodeSite.Send(_Loc.ProcedureName + ' (Line#: ' + IntToStr(_Loc.LineNumber) + '): X', X); // 2. Then, replace X with the desired expression to get the Procedure Name and the current line Number at runtime: CodeSite.Send(_Loc.ProcedureName + ' (Line#: ' + IntToStr(_Loc.LineNumber) + '): Sender.ClassName', Sender.ClassName); // 3. The CodeSite result in the CodeSite Live Viewer rsults as: TForm1.Button1Click (Line#: 39): Sender.ClassName = TButton end; -
Compiler directives for line number?
PeterPanettone replied to PeterPanettone's topic in RTL and Delphi Object Pascal
Thanks for the hint. Currently, the procedure name is automatically inserted at design time by the CnWizards Source Template macro %CurrProcName%. However, I plan to create a separate IDE plugin (along with other features) - if Thomas has not already picked up the idea - where a CodeSite editor replaces the CnWizards Source Template macro. That would make it very flexible and independent of the CodeSite statement location. -
Compiler directives for line number?
PeterPanettone replied to PeterPanettone's topic in RTL and Delphi Object Pascal
GREAT! This function solves my inspecting problem: function LN: string; begin Result := IntToStr(JclDebug.GetLocationInfo(ReturnAddress).LineNumber); end; I now use this CnWizards Source Template: 1. I press CTRL+SHIFT+# which inserts this code: CodeSite.Send('TForm1.Button1Click, Line Number: ' + LN + ': ', E); 2. I insert the desired expression I want to inspect, for example, Sender.ClassName CodeSite.Send('TForm1.Button1Click, Line Number: ' + LN + ': Sender.ClassName', Sender.ClassName); 3. And then, in the CodeSite Live Viewer at runtime, I get the desired inspection result: TForm1.Button1Click, Line Number: 40: Sender.ClassName = TButton Happy inspecting! -
It seems that Delphi does not have a built-in compiler directive or "magic word" equivalent to __LINE__ or $LINE for directly accessing the current source code line number, as seen in languages like C/C++. Free Pascal (which shares compatibility with Delphi) does support special tokens like %LINE% and %FILE% within the {$INCLUDE} directive to insert the current line number or file name as text. Is there a way to make Delphi support this (e.g., with custom pre-processors)?
-
Refactoring suggestion: Move current procedure to new separate unit
PeterPanettone posted a topic in MMX Code Explorer
Moving the current procedure to a new separate unit is a common desire when a unit starts to grow too large, and you realize a specific feature set could be broken out into its own module. It would be fantastic if MMX could have a ONE-STEP refactoring to achieve this. The Cumbersome, Manual, Tool-Assisted Refactoring Process: Let's assume you have UnitA.pas and you want to move ProcedureA and all its helper functions into a new UnitB.pas: Step 1: Create the New Unit First, create your new, empty unit. Go to File > New > Unit - Delphi. Save it as UnitB.pas. Decide on the structure. Will UnitB contain a class (TMyFeatureManager) or will it be a collection of standalone procedures? For this example, let's assume you're creating a new class, as that's the most common and robust approach. // In UnitB.pas: unit UnitB; interface type TMyFeatureManager = class private // Fields that were in UnitA's form will go here public procedure ProcedureA; // ... other public methods will go here end; implementation { TMyFeatureManager } procedure TMyFeatureManager.ProcedureA; begin // Code will go here end; end. Step 2: Use the "Find Usages" and "Go to Definition" Tools In UnitA.pas, right-click on ProcedureA and select Search For Usages. This will show you every place where ProcedureA is called. Inside ProcedureA, right-click on every single procedure it calls (e.g., Helper1, Helper2) and use Go to Definition (Ctrl+Click) to jump to their source. This helps you identify all the "connected procedures" you need to move. Make a list of all the procedures, functions, and private fields/variables that are part of this feature set. Step 3: Use the "Move" Refactoring (Safest Method) The Move refactoring is your best friend here. It will automatically update all references to the moved member. Move the Procedures: In UnitA.pas, right-click on a helper procedure (e.g., Helper1) that you want to move. Select Refactor > Move.... The "Move" dialog will appear. In the "Target Scope" or "Destination" field, select your new TMyFeatureManager class in UnitB. Click OK. What happens: Delphi will physically move the code for Helper1 into UnitB.pas, make it a method of TMyFeatureManager, and automatically add UnitB to the uses clause of UnitA if needed. It will also update any calls inside UnitA to correctly reference the method in the new class. Move the Fields: Do the same for any private fields from UnitA's form that are only used by these procedures. Right-click the field, choose Refactor > Move..., and select TMyFeatureManager as the destination. Repeat this process for every single procedure and field on your list. This is a painstaking but very safe process, as the IDE is managing all the references for you. Step 4: Handle Dependencies After moving the code, you will likely have some compiler errors. These are usually dependency-related. UnitA depends on UnitB: The Move refactoring should have already added UnitB to UnitA's uses clause. UnitB depends on UnitA (or other units): Your new TMyFeatureManager class will likely need to reference components or methods from the original form in UnitA. The Wrong Way (Causes Circular References): Do NOT add UnitA to the uses clause in the interface section of UnitB. This will almost certainly cause a circular unit reference. The Right Way: Add UnitA to the uses clause in the implementation section of UnitB. Pass a reference to the form from UnitA into your new class's constructor. Example of the Correct Dependency Handling: // In UnitB.pas: unit UnitB; interface uses Vcl.Forms; // Or whatever base class your form has type // Forward declare the form class from UnitA TFormA = class; TMyFeatureManager = class private FOwnerForm: TFormA; // A reference to the form that owns this manager public constructor Create(AOwnerForm: TFormA); procedure ProcedureA; end; implementation uses UnitA; // Now we can add the full unit reference here { TMyFeatureManager } constructor TMyFeatureManager.Create(AOwnerForm: TFormA); begin FOwnerForm := AOwnerForm; end; procedure TMyFeatureManager.ProcedureA; begin // Now you can safely access components on the original form FOwnerForm.Button1.Caption := 'Done'; end; end. // In UnitA.pas: procedure TFormA.FormCreate(Sender: TObject); begin // Create an instance of the manager and give it a reference to ourselves FMyFeatureManager := TMyFeatureManager.Create(Self); end; procedure TFormA.Button1Click(Sender: TObject); begin // Call the procedure in the new, separate unit FMyFeatureManager.ProcedureA; end; -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
This is indeed very strange. I have also discovered that when I use my previous code version: const {$IFNDEF PROCESS_QUERY_LIMITED_INFORMATION} PROCESS_QUERY_LIMITED_INFORMATION = $1000; {$ENDIF} ...then I can compile/build my app, but when I run it from the IDE, I get F2084 Internal Error: AV50A9A35E(509E0000)-R00000000-0 shown in the Structure view (without affecting my app at runtime). So I now simply declare the variable without any compiler conditionals, which resolves all compiler problems. -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
Delphi 12.2. -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
Your code creates a compiler error: {$IF NOT DECLARED(PROCESS_QUERY_LIMITED_INFORMATION)}// [dcc32 Error] Common.pas(382): E2070 Unknown directive: '' const PROCESS_QUERY_LIMITED_INFORMATION = $1000; {$IFEND} -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
Hello Remy Lebeau, Thank you for your answer. However, the Delphi 12.2 compiler seems to accept this as a conditional compilation: The code compiles without errors. -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
Ah, I've found it here: C:\Users\<username>\Documents\Embarcadero\Studio\23.0\CatalogRepository\WindowsAPIfromWinMD-1.0\Windows.System.Threading.pas Very nice! Unfortunately, the GetIt installer does not add WindowsAPIfromWinMD-1.0 to the Library Path. -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
Hello DelphiUdIT, Thanks for the hint. How would you reference PROCESS_QUERY_LIMITED_INFORMATION from WinMD? I need to use it in this context: hProcess := Winapi.Windows.OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, // cannot be retrieved from Winapi.Windows False, ProcessID ); So I implemented it as a local constant: const {$IFNDEF PROCESS_QUERY_LIMITED_INFORMATION} PROCESS_QUERY_LIMITED_INFORMATION = $1000; {$ENDIF} -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone replied to PeterPanettone's topic in Windows API
Doesn't Winapi.Windows pull this constant from Winapi.WinNT.pas? But Winapi.WinNT.pas is also missing. -
Winapi.Windows.PROCESS_QUERY_LIMITED_INFORMATION not found
PeterPanettone posted a topic in Windows API
In my Delphi 12.2 Winapi.Windows.pas unit in Windows 11, the declaration for PROCESS_QUERY_LIMITED_INFORMATION ($1000) constant is missing. Does this mean that my Winapi.Windows.pas unit is potentially corrupted? -
Unfortunately, Delphi does not natively support having separate persistent editor tab sets for each project inside a project group. Delphi’s Project Group (.groupproj) by default shares a single editor tab layout across all projects in the group — which can be frustrating when switching between projects in a Project Group. Is there a custom way to AUTOMATICALLY switch between separate tab sets when switching between projects in a Project Group?