How to configure FastMM to detect memory leak in a dll - delphi

I can't figure out how to detect memory leaks in a statically or even dynamically linked dll. I just want to detect the leaks in the dll, and I don't want to share the memory manager between the dll, and the app. Additionally the dll is linked with runtime packages
My sample dll looks like this:
library dll;
uses
fastmm4,
System.SysUtils,
System.Classes;
{$R *.res}
procedure MyInit; stdcall;
Begin
TObject.Create;
End;
exports MyInit;
begin
end.
application dpr:
program app;
uses
//fastmm4,
Vcl.Forms,
main in 'main.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Note: If I uncomment fastmm4, than I can detect the memleak caused by the application (TStringList.Create), but not the leak in the dll.
And in the application main unit:
unit main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
LDLLHandle: HModule;
LShowProc: TProcedure;
end;
var
Form1: TForm1;
{$ifdef static}
procedure MyInit; stdcall; external 'dll.dll';
{$endif}
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
TStringList.Create;
{$ifdef static}
MyInit;
{$else}
LDLLHandle := LoadLibrary('dll.dll');
if LDLLHandle <> 0 then
begin
try
LShowProc := GetProcAddress(LDLLHandle, 'MyInit');
if Assigned(LShowProc) then
LShowProc;
finally
FreeLibrary(LDLLHandle);
end;
end;
{$endif}
end;
end.
I expect from FastMM to generate a report when FreeLibrary is called, or on program exit, if the dll is statically loaded, but nothing happens.
In the FastMM4Options.inc I additionally just set FullDebugMode and ClearLogFileOnStartup, and the FastMM_FullDebugMode.dll is in the output directory.
I created a repository on github. What am I missing?

The reason that your DLL is not reporting leaks stems from this code in the FastMM shutdown:
CheckBlocksOnShutdown(
{$ifdef EnableMemoryLeakReporting}
True
{$ifdef RequireIDEPresenceForLeakReporting}
and DelphiIsRunning
{$endif}
{$ifdef RequireDebuggerPresenceForLeakReporting}
and ((DebugHook <> 0)
{$ifdef PatchBCBTerminate}
or (Assigned(pCppDebugHook) and (pCppDebugHook^ <> 0))
{$endif PatchBCBTerminate}
)
{$endif}
{$ifdef ManualLeakReportingControl}
and ReportMemoryLeaksOnShutdown
{$endif}
{$else}
False
{$endif}
);
In your options, RequireDebuggerPresenceForLeakReporting is defined. What's more, in the DLL, DebugHook is equal to 0, presumably because you are debugging the application rather than the DLL. This means that you call CheckBlocksOnShutdown passing False. And that False disables reporting of leaks.
You can resolve this by undefining RequireDebuggerPresenceForLeakReporting.

I just test it with version Fast Memory Manager 4.97 on Delphi2010 - win7
FastMM4 is the first unit in the 'uses' clause of the .dpr (project and dll)
'ShareMM' option is enabled
'AttemptToUseSharedMM' option is enabled
'EnableMemoryLeakReporting' option is enabled
Add FastMM_FullDebugMode.dll in the folder of the exe
There is also a test demo 'Dynamically Loaded DLL'
This demo is without the ShareMem.
I must set the option 'ShareMM' and 'AttemptToUseSharedMM' enabled and add the FastMM_FullDebugMode.dll to have a leak report of FastMM.

Related

Having own library units in the same build config as the project

How can I setup Delphi library folders so I can have both Debug and Release versions of my units library when I work on a project ? Until now I compiled my library in Release mode once is finished. But I encountered situations when I work on a project and I need to follow the debugging steps even in the compiled units. But if they are compiled as Release, it won't let me. And if I compile them as Debug, it puts the debuging code in the Release version of the project, which is not normal. I would like that when I switch between Debug and Release in my project, the units also switch. Can it be done ? If I put both Debug and Releas folders in Delphi library path, it will know when to choose te right one ?
I finally managed to understand how it works: the key is $(Platform) and $(Config).
I made a test unit with a function that tells me what configuration I'm using:
unit Test;
interface
function GetConfig: String;
implementation
function GetConfig: String;
begin
{$IFDEF RELEASE} Result:= 'Release'; {$ENDIF}
{$IFDEF DEBUG} Result:= 'Debug'; {$ENDIF}
end;
end.
I compiled it in Debug and Release mode and saved .dcu files in D:\Delphi\MyLIB\Win32 \Release and \Debug. And the .pas in the D:\Delphi\MySRC. Then I go to Tools > Options > Language > Delphi > Library and I added D:\Delphi\MyLIB\$(Platform)\$(Config) to Library Path section and 'D:\Delphy\MySRC' to Browsing Path.
Now, if I make a new project and use that unit, the correct version is selected according to Buid Configuration. And if I switch to Debug and do a Trace Into (F7) over that function, I can debug inside it.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Test;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Caption:= GetConfig;
end;
end.
Thanks to Oleksandr Morozevych comment !

TaskDialog not working in my Delphi Program

I am using Delphi 10.4. This is a Windows VCL Application.
I wanted to convert all my ShowMessage, MessageDlg and MessageBox calls to TaskDialogs in my program. When I tried to do that, I couldn't get TaskDialog to display anything.
So what I did was create a new minimal VCL application, simply added a button and a TaskDialog to it:
This was my code:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
TaskDialog1: TTaskDialog;
procedure MyMessageBox;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; 
var
Form1: TForm1;
implementation
procedure TForm1.MyMessageBox;
begin
Form1.TaskDialog1.Caption := 'My Application';
Form1.TaskDialog1.Title := 'Hello World!';
Form1.TaskDialog1.Text := 'I am a TTaskDialog, that is, a wrapper for the Task Dialog introduced ' +
'in the Microsoft Windows Vista operating system. Am I not adorable?';
Form1.TaskDialog1.CommonButtons := [tcbClose];
Form1.TaskDialog1.Execute;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
MyMessageBox;
end;
{$R *.dfm}
begin
Application.Run;
end.
That worked fine. When running it and pressing Button1, I get:
So now I go to my application. I add a button to my main form, and set the MyMessageBox procedure to this:
procedure TLogoAppForm.MyMessageBox;
begin
ShowMessage('ShowMessage ......................................');
Application.MessageBox('Application.MessageBox ...........................', 'Error', 0);
MessageDlg('MessageDlg ................................', mtWarning, [mbOk], 0);
LogoAppForm.TaskDialog1.Caption := 'My Application';
LogoAppForm.TaskDialog1.Title := 'Hello World!';
LogoAppForm.TaskDialog1.Text := 'I am a TTaskDialog, that is, a wrapper for the Task Dialog introduced ' +
'in the Microsoft Windows Vista operating system. Am I not adorable?';
LogoAppForm.TaskDialog1.CommonButtons := [tcbClose];
LogoAppForm.TaskDialog1.Execute;
end;
Pressing the button in my application correctly brings up each of the ShowMessage, MessageBox and MessageDlg windows in sequence, but after closing the MessageDlg window, nothing at all appears for the TaskDialog.
Does anyone know what might be causing TaskDialog to not work in my application and how I might fix this?
You must enable runtime themes for the VCL TTaskDialog to work. Go to Project/Options/Application/Manifest to do so.

How display a background image and center a panel in a dll Form?

I want load a image that will be the background of a maximized Form that stays in a dll.
The dll is called from a Vcl Form Application but have a trouble where not is possible load the background image on Form, the dll always crashes.
Thank you by you help.
===========================================================================
Executable
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm2 = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
end;
var
Form2: TForm2;
implementation {$R *.dfm}
procedure LoadDLL;
type
TShowformPtr = procedure; stdcall;
var
HDLL: THandle;
Recv: TShowformPtr;
begin
HDLL := LoadLibrary('lib.dll');
if HDLL <> 0 then
begin
#Recv := GetProcAddress(HDLL, 'Recv');
if #Recv <> nil then
Recv;
end;
//FreeLibrary(HDLL);
end;
procedure TForm2.btn1Click(Sender: TObject);
begin
LoadDLL;
end;
end.
Dll
Main:
library Project2;
uses
SysUtils, Classes, Unit1, Unit2;
{$R *.res}
procedure Recv; stdcall;
begin
showform;
end;
exports
Recv;
begin
end.
Unit1 (Form):
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
img1: TImage;
pnl1: TPanel;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
procedure CreateParams(var Params: TCreateParams); override;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.WndParent:= Application.Handle;
Params.ExStyle := Params.ExStyle or WS_EX_TOPMOST or WS_EX_TRANSPARENT;
Params.ExStyle := WS_EX_TRANSPARENT or WS_EX_TOPMOST;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
brush.Style := bsclear;
img1.Picture.LoadFromFile(IncludeTrailingBackslash(GetCurrentDir) + 'background.bmp');
SetWindowPos(Form1.handle, HWND_TOPMOST, Form1.Left, Form1.Top, Form1.Width,
Form1.Height, 0);
ShowWindow(Application.handle, SW_HIDE);
pnl1.Top := (self.Height div 2) - (pnl1.Height div 2);
pnl1.Left := (self.Width div 2) - (pnl1.Width div 2);
end;
end.
Unit2:
unit Unit2;
interface
Uses
windows,
Unit1,
SysUtils;
procedure showform;
implementation
procedure showform;
begin
Form1 := TForm1.Create(Form1);
sleep(100);
Form1.Show;
Form1.Pnl1.Visible := True;
end;
end.
Your question has a lot of problems, so I would try to answer it as best I can, considering the lack of details.
You are using forms so you are building a VCL application. You need to let the IDE assign the VCL framework to your project.
This line is terribly wrong:
Form1 := TForm1.Create(Form1);
In rare circumstances show a from own itself. I would go and say that most probably this is why your application crashes. See this for details about forms in DLLs.
If you cannot properly debug your application put a beep before that line and one after (make a delay between them).
I think your question should be rather called "how to debug a Delphi project".
What you need to do is to get the exact line on which the program crashes. This will give you an insight of why the error/crash (by the way, you never shown the exact error message) appears.
Go check HadShi (recommended) or EurekaLog (buggy) or Smartinspect (I never tried it. Price is similar to the other two). Make sure that you are running in debug mode, the Integrated debugger is on (see IDE options) and that the debug information is present in your EXE/DLL.
PS: you can still debug your app without have one of the three loggers shown above. Just configure your project properly to run in Debug mode!
To debug the DLL see the 'Run->Parameters' menu. Define there a host application that will load your DLL. If the error is the DLL, the debugger will take control and put the cursor to the line of code that generated the crash.
I don't know what the final purpose/what is that you want to achieve. Because of this I must warn you that you might need to take into consideration these questions:
Do you need to use ShareMM?
Why are you building this as a DLL? Can't the application be written as a single EXE? Or two EXEs that communicate with each other?

Firemonkey app fail when calling FreeLibrary

I have a simple Firemonkey app, that loads a DLL, call a procedure within that DLL, which just calls ShowMessage('Dialog from DLL ...'); and returns
That all OK, but the calling application fails, when FreeLibrary has been called and I try closing the main app ?
If I leave out the FreeLibrary call, the application closes without error.
Anybody seen this before, and why ?
I'm using Delphi 10.1 Berlin, but Delphi 10 Seattle also fails on Windows 7.
The application code:
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
uses
Winapi.Windows;
type
TTest = procedure (); stdcall;
procedure TForm2.Button1Click(Sender: TObject);
var
LibHandle: NativeUInt;
Test: TTest;
begin
LibHandle:= LoadLibrary('.\TESTDLL.DLL');
if LibHandle > 32 then try
#Test:= GetProcAddress(LibHandle, 'Test');
if #Test <> nil then
Test;
finally
FreeLibrary(LibHandle);
end;
end;
And the DLL code:
library TESTDLL;
uses
System.SysUtils,
System.Classes,
FMX.Dialogs
;
{$R *.res}
procedure Test; stdcall;
begin
ShowMessage('Dialog from DLL ...');
end;
exports
Test name 'Test';
begin
end.
If the dll procedure don't contain any calls related to display things, the app behaves as expected.
Any hints help or suggestions, greatly appreciated.
Edit: Included the complete code from main app.

godex ez2250i delphi cant print

I have a label printer GoDex EZ2250i and i found some samples with delphi but none seems to works for me i try to compile with couple of dll's and the program doesnt even launch does anyone have experience on printing with this printer with delphi? thanks in advance, also the OS should be supported Windows7 and Windows 8.
the code that i tried:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
TestLib = 'Ezio64.dll'; // tried with Ezio32.dll same result
procedure openport(port:PChar); stdcall; external TestLib ;
procedure setup(a, b, c, d, e, f:Integer); stdcall; external TestLib;
procedure sendcommand(command:PChar); stdcall; external TestLib;
procedure intloadimage(filename, image_name, image_type:PChar); stdcall; external TestLib;
procedure extloadimage(filename, image_name, image_type:PChar); stdcall; external TestLib;
procedure ecTextOut(x:Integer; y:Integer; b:Integer; c:PChar; d:PChar); stdcall; external TestLib;
procedure closeport; stdcall; external TestLib;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
openport('0'); // 0-> LPT1; 1-> COM1; 2->COM2
setup(30, 7, 2, 1, 0, 0);
sendcommand('W70');
sendcommand('^P1');
sendcommand('^L');
sendcommand('AC,20,60,1,1,1,0,TEST');
ecTextOut(20, 10, 34, 'Ariel', 'Windows font - Ariel');
sendcommand('E');
closeport();
end;
end.
The program doesn't even launch.
This is symptomatic of a loader failure. For some reason, under the Delphi debugger, loader failures are not reported.
A loader failure typically occurs when:
A dependent DLL cannot be found, or,
A dependent DLL is found, but cannot be loaded, or,
A dependent DLL is loaded, but the imported functions cannot be found within.
To get more diagnostics run the executable outside of the debugger. Quite possibly you are trying to load 64 bit DLLs into your 32 bit process.
If diagnosis proves tricky, go back to the documentation for the library. Make sure you have installed all pre-requisites. Another common failure mode is a missing C++ runtime.
As a last resort, use Dependency Walker. Use the 32 bit version, and execute you program under Profile mode. This will pin-point the dependency failure.

Resources