Annoying assembly codes in Delphi XE4 after method calls - delphi

What option should I check out to disable the assembly code tracing after every method call in Delphi XE4?
If you trace (F7) the call of TMyClass.foo, the set of the result cause an assembly tracing.
type
TMyClass = class
public
function foo : string;
end;
function TMyClass.foo : string;
begin
result := 'x';
end;

It sounds like you should set the checkbox "use debug DCUs" on the RHS of the Debugging section of Delphi's Project Options pop-up, under Delphi Compiler | Compiling.

Related

How to look into generic tList during Delphi debugging

I use Delphi 10.3.1 COMMUNITY version and can't look into generic tList while I debug the project.
I know the latest version of Delphi doesn't support the old-typed debug feature which allows to look into generic tList. So I used tList.List in the following code to evaluate the tList.
In tList<tRecord>.List I can look into it but can't do it in tList<Integer>.List.
type
tRecord = record
Field: Integer;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
_Record: tRecord;
_List1: TList<tRecord>;
_List2: TList<Integer>;
i: Integer;
begin
_List1 := TList<tRecord>.Create;
_List2 := TList<Integer>.Create;
for i := 0 to 4 do
begin
_Record.Field := i;
_List1.Add(_Record);
_List2.Add(i);
end;
Caption := IntToStr(_List1.List[0].Field) + IntToStr(_List2.List[0]);
_List1.Free;
_List2.Free;
end;
How can I look into tList<Integer> during the debugging?
Usually it should be possible to see the lists contained array over the List property. Internally there is only a field of type Pointer unlike before 10.3 when it was of type TArray<T>.
This is what I see when I put a breakpoint into the line where it assigns to Caption and put those two entries into my watches:
Update: It looks like the Linker is responsible for the issue you are experiencing here. When you uncheck the option to "allow side effects and function calls" in the watch
the watch window will show this:
I have seen this behavior before when using generics that are only specified in the implementation part of the unit (FWIW when I tried to repro this the first time I did not put the code you posted into a VCL project but into a console dpr and that one does not have an implementation part so I did not see this behavior).
To force the linker to not to remove the symbol or the debugger to actually see it (because even if I disable inlining to force the GetList method to stay the watch window will tell me that it got removed) you can simply put some dummy type into the interface part of this or any other unit.
type TDummy = TList<Integer>;
This will cause the debugger to see the symbol and see the values in the watches window.

Delphi 10.2 Tokyo - Casting object provided by interface

I'm trying to convert my aplliction from Delphi XE8 to 10.2 Tokyo. I'm getting strange runtime exeptions with casting objects provided by interfafce acrocss packages ( bpl's). when I try to cast objects with "as" keyword I'm getting
this exception during runtime:
Project Project1.exe raised exception class EInvalidCast with message
'Invalid class typecast'
Here is the code :
Interface in a separte package Plugin_interface.bpl :
unit MainIntf;
interface
Type IMainInft = interface
['{FE08C4A2-069C-4B8C-BB1B-445348CAB6A0}']
function GetForm : TObject;
end;
implementation
end.
Interface implamentation provided in Project1.exe :
unit MainImpl;
interface
uses MainIntf;
Type TMain = class(TInterfacedObject,IInterface,IMainInft)
function GetForm : TObject;
end;
implementation
uses unit1;
function TMain.GetForm: TObject ;
begin
result:=Form1; // interafce is implemented on the main form so Form1 is rechable form here
end;
end.
And finally in another package "plugin.bpl" I'm trying to obtain object from interface :
unit Plugin_main;
interface
uses Mainintf, Vcl.Forms;
type TPlugin = class (Tobject)
IIMyRefernceToMianIntf: IMainInft;
end;
function RegisterPlugin(AMainIntf: IMainInft): TForm ; export;
procedure UnRegisterPlugin; export;
exports
RegisterPlugin,
UnRegisterPlugin;
var
Plugin_obj: TPlugin;
implementation
uses vcl.Dialogs,System.Classes ;
function RegisterPlugin(AMainIntf: IMainInft): TForm ;
var
MyForm : TForm ;
begin
Plugin_obj:=TPlugin.Create;
Plugin_obj.IIMyRefernceToMianIntf:=AMainIntf;
if AMainIntf.GetForm is TForm then
Showmessage ('Great it is a Tform') // will not happen
else
Showmessage ('Sorry it is not Tform'); // will happen
if TComponent (AMainIntf.GetForm).Classname='TForm1' then
Showmessage ('What ?? It is TForm1 decsendant from TForm so is it TForm after all ?!'); // will happen
// result:= AMainIntf.GetForm as TForm -- This will rise na exception
result:= TForm( AMainIntf.GetForm) ; // this will work
end;
procedure UnRegisterPlugin;
begin
Plugin_obj.Free;
end;
end.
Why cant I use "as" and "is" keyword .
Only hard catsing will do, but i hate to do it .
on XE8 compiler everything worked as expected - problem exists on XE 10.2 tokyo compiler
The "is" keyword checks the actual objects to see it is of the type you are asking. So, checking for this:
if AMainIntf.GetForm is TForm then
Showmessage ('Great it is a Tform') // will not happen
does not happen because GetForm returns TObject and not TForm. Checking with "is" means, also, that you are checking for castability, i.e. the ability to use the "as" keyword. Since, the "is" check fails, that command fails as well:
result:= AMainIntf.GetForm as TForm;
Your next option here is to hard-cast GetForm the way you do it:
TForm(AMainIntf.GetForm);
which works because this casting does not check whether GetForm is of TForm type. Since you return a form in TMain, this hard-casting is safe bet for you.
Having said that, however, why don't you return TForm directly rather than TObject? Do you use IMainInft in other classes that return other types than TForm?

Why does the compiler say "Too many actual parameters" when I think I've provided the correct number?

I've declared the following function:
function next(current, next: string): Integer;
begin
form1.Label1.Caption := next;
form1.Label2.Caption := current;
form1.label3.Caption := clipboard.AsText+inttostr(c);
Result:=1;
end;
I try to execute it with this code:
if label1.Caption = '' then res := next('current', 'next');
I am getting the following error:
[Error] Unit1.pas(47): E2034 Too many
actual parameters
I think all parameters are good, so why am I getting that error?
I just tried your code on both Delphi 7 and Delphi 2010. If it works on those two, it should also work on Delphi 2005.
Conclusion: Delphi wants to use a different version of the "next" routine, because of code scope/visibility. Try ctrl+click-ing on "next" in "res := next();" and see where Delphi takes you. Alternatively post more code so we can tell you why Delphi is not choosing your version of the "next" routine. Ideally you should post a whole unit, starting from "unit name" to the final "end."
As specified by Cosmin Prund, the problem is because of the visibility.
TForm has a procedure with name Next which wont accept any parameters.
Your function uses the same name and as you are calling the function in TForm1 class implementation, compiler is treating the call as TForm1.Next and hence it was giving error.
To solve the problem, precede the unit name before the function name i.e., Unit1.Next().
So this should be your code
if label1.Caption = '' then res := Unit1.next('current', 'next');

BPL File needs Run-Time Packages !

I have created a Package and i want to use the BPL File of my Package ...
My Package have VCL.dcp and RTL.dcp as Required libraries , i load this Package in my application without any errors but when i want to unload it , an Access Violation shown !
If i Build my Application with Run-Time Packages ( "vcl" and "rtl" ) , Access Violation not shown !
What is this mean ?! My Application need VCL and RTL Libraries to Load BPLs ?! I want to Load my Package like a DLL File , is there any solution ?
I`m using Delphi 2010
thanks a lot ...
Your BPL requires the RTL and VCL packages. If your Application doesn't require them, then that means the RTL and VCL units are compiled into your EXE file. When your EXE loads your BPL, you now have two copies of the RTL and VCL units — one set of copies comes from within the EXE, and the second copies come from the RTL and VCL packages that your package implicitly causes to be loaded.
Delphi isn't intended to accommodate that situation. It's possible that you have memory that was allocated by one RTL and attempted to get freed by the other RTL. Or there might be function pointers in the EXE that refer to functions that were in the VCL package.
I see three options for you:
Compile your EXE to use packages. Specifically, it should require the same RTL and VCL packages that your BPL requires.
Make your BPL not require any other packages. If it doesn't require RTL and VCL, then any RTL and VCL units that your package uses will get compiled into your BPL. You'll end up with two separate copies again, but it should work better since neither copy will think it's supposed to be shared.
Load your package like a real DLL instead of like a package. You said you wanted to use it like a DLL, so do that. Use LoadLibrary, and then use GetProcAddress to get whatever functions you want to call. If you go this route, it's probably better to not make your code be a package at all. Make it a DLL, and export functions that only use parameter types that you'd expect to find in other DLLs, like integers, character pointers, and record pointers, not strings or objects.
It should be clear that the first option is the easiest. The second could probably work, and it sounds like that's the way you'd prefer, but I expect it will generate more headaches before it finally works. The third option is best if you'll ever have to use other development environments during the lifetime of this project.
What have your package inside?
What work do you do with it?
How do you charge and discharge? What's in it?
What do you do with the package before unload it?
When you Unload it, all the objects/forms/components/... that yo've used is released?
ADDED: I Think that you are using anything of the package when you try to Onload. This is the reason of AV.
In an EXE compiled without runtime package, I load the package:
OutputDebugString(PChar('Loading the package'));
hand := LoadPackage('r:\rrrrrrr\Package1.bpl');
I Unload the package with this code:
OutputDebugString(PChar('Ready to Unload Package'));
UnloadPackage(hand);
OutputDebugString(PChar('Unloaded'));
The package has a unit with a form (form1) and a unit Init.pas, for initialization like this:
unit Init;
interface
// prototipos
procedure Start_P;
procedure Finish_P;
implementation
uses
Unit1, Windows;
procedure Finish_P();
begin
OutputDebugString(PChar('Finish_P form free'));
Form1.Free;
end;
procedure Start_P();
begin
OutputDebugString(PChar('Start_P Creating form'));
Form1 := TForm1.Create(nil);
Form1.Show;
end;
Initialization;
Start_P();
Finalization;
Finish_P();
end.
The package is loaded and the form visualized without problems, and the same with the operation of Close and Unload. The project is compiled with "Build with rutime packages" unchecked.
Can you post any code.
The result of OutputDebugString is this (no AV error):
[2644] Loading the package
[2644] Start_P Creating form
[2644] Ready to Unload Package
[2644] Finish_P form free
[2644] Unloaded
Regards.
Thanks for your helps ...
I put an example of my package and my Application here to Find what is the problem !
We have a package without requiring to Run-Time Packages like VCL and RTL , in other words i removed all libraries from the Requires section in my package :
my package contains a form with code below :
unit MyUnit;
interface
uses
Windows, Forms, StdCtrls, Buttons, Controls, Classes, Dialogs;
type
TMyForm = class(TForm)
MyLabel: TLabel;
MyEdit: TEdit;
PostBtn: TBitBtn;
procedure PostBtnClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MyForm: TMyForm;
implementation
{$R *.dfm}
function ShowForm(FCaption, LCaption : String) : String;
var
F : TMyForm;
begin
F := TMyForm.Create(nil);
try
F.Caption := FCaption;
F.MyLabel.Caption := LCaption;
F.ShowModal;
finally
Result := F.MyEdit.Text;
F.Free;
end;
end;
procedure TMyForm.PostBtnClick(Sender: TObject);
begin
if MyEdit.Text <> '' then
Close
else
ShowMessage('Please Enter Value !');
end;
exports
ShowForm;
end.
I Load this Package and Call ShowForm Function and then Unload package :
var
ShowF : function(FCaption, LCaption : String) : String;
MyPkg : HMODULE;
FC, LC : String;
begin
MyPkg := LoadPackage(ExtractFilePath(Application.ExeName)+'MyPackage.bpl');
FC := 'Enter Value ... ';
LC := 'Value : ';
if MyPkg <> 0 then
begin
try
#ShowF := GetProcAddress(MyPkg, 'ShowForm');
if Assigned(ShowF) then
Edit1.Text := ShowF(FC, LC)
else
ShowMessage('Function not found !');
finally
UnloadPackage(MyPkg);
end;
end;
end;
After the Procedure above done , the AV Shows !
#Neftalí : If I just do loading and unloading the Package , no AV Shows , but i think that is because i don`t call some routines or objects or ... that they need VCL or RTL Libraries , if i use objects and functions and ... of this package , after using them i will get an AV ...
is it true ?!
If I Build my application with Run-Time package ( VCL and RTL ) no AV will shown !
I`m confusing !! , I want to use an BPL package without any Run-Time package needed ...
thanks a lot ...
Yes, if you want to use runtime packages in your application you have to build it with runtime packages, and then it requires them (links statically with them).
The solution to your problem depends on what the problem actually is (which is unclear at the moment).
Ohhhhh, great oversight/neglect (mine).
With the code that you have posted, made a simple change a test it (use PChar).
function ShowForm(FCaption, LCaption : String) : PChar;
...
Result := PChar(F.MyEdit.Text);
...
The same when you define the sitaxis of the function:
ShowF : function(FCaption, LCaption : String):PChar;
Test it and say the result.
Regards.

Returning a string from a BPL function

have a function, simplified below, that is exported from a BPL
function DoA(amount: currency; var Info: string): Currency; stdcall;
begin
result := amount * 19;
Info:= 'Some Text about the result';
end;
its loaded from the main program with LoadPackage, and GetProcAddress which works fine for the other functions.
but this one brings up many errors when its called;
BPL Is used with (simplified)
bplhandle: HModule;
BPLDoA: function (amount: currency; var Info: string): Currency; stdcall;
intoStr : string;
.
begin
bplhandle:=LoadPackage('test.bpl');
if bplhandle <> 0 then
begin
#BPLDoA:=GetProcAddress(bplhandle,'DoA');
if assigned(BPLDoA) then
result := BPLDoA(123, intoStr);
end;
end;
the exception that seems to happen at the end of the Procedure,
but the corrected text is returned into intoStr (viewed with a break point)
would the error have anything to do with the Info param being a var and/or a string?
The Error message is
Project Project1.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'
thanks
more info>
another function from the same bpl/unit works fine
function DoB(amount: currency): Currency; stdcall;
result := amount * 19;
end;
Mad Except>
exception class : EInvalidPointer
exception message : Invalid pointer operation.
main thread ($1b7c):
0040276f +013 Project1.exe System #FreeMem
00404650 +01c Project1.exe System #LStrClr
00483814 +15c Project1.exe Unit1 97 +11 TForm1.Button3Click
00462430 +064 Project1.exe Controls TControl.Click
0045a870 +01c Project1.exe StdCtrls TButton.Click
You haven't configured your EXE project to "build with run-time packages." Find that in the "packages" section of your project options. (Documentation)
The EInvalidPointer exception comes when a memory manager tries to free something that it didn't allocate. That suggests you have two different memory managers active. Your BPL is using the one from the RTL package, which appears on your package's "requires" list. Your EXE, on the other hand, is using the memory manager compiled into the EXE module.
Fix that by telling your EXE to use run-time packages, and then make sure the RTL package is on the list of required packages.
Does your import declaration exactly match the exported function's signature?
Must be like this:
DoAProc: function (amount: currency; var Info: string): Currency; stdcall;
Another option if you don't want to be required to ship additional BPLs (which you will now that your main exe is using runtime BPLs), is to include the ShareMem unit in your project. Check out the "Sharing Memory" topic in the Delphi help file.
ms-help://embarcadero.rs2010/rad/Sharing_Memory.html

Resources