Delphi 7 make complains about files not found - delphi

I've got a BPG file that I've modified to use as a make file for our company's automated build server. In order to get it to work I had to change
Uses * Uses
unit1 in 'unit1.pas' * unit1
unit2 in 'unit2.pas' * unit2
... * ...
in the DPR file to get it to work without the compiler giving me some guff about unit1.pas not found.
This is annoying because I want to use a BPG file to actually see the stuff in my project and every time I add a new unit, it auto-jacks that in 'unitx.pas' into my DPR file.
I'm running make -f [then some options], the DPR's that I'm compiling are not in the same directory as the make file, but I'm not certain that this matters. Everything compiles fine as long as the in 'unit1.pas is removed.

It could come from the fact, that the search path in the IDE and the search path of the command line compiler are not the same. If you change the serach path of the command line compiler you might be able to use the exactely same source code as within the IDE.
One possibility to configure the search path for the command-line compiler is to do it in a file called dcc32.cfg. Take a look at the help, there is a short description of dcc32.cfg in the IDE-help.

Well this work-around worked for me.
//{$define PACKAGE}
{$ifdef PACKAGE}
uses
unit1 in 'unit1.pas'
unit2 in 'unit2.pas'
...
{$else}
uses
unit1
unit2
...
{$endif}
The only problem is whenever you add a new unit, delphi erases your ifdef package at the top.

Every time I have to put conditionals into a project file I do this:
program a;
uses
ACondUnits;
...
unit ACondUnits;
interface
uses
{$IFDEF UseD7MM}
Delphi7MM;
{$ELSE}
FastMM4;
{$ENDIF}
implementation
end.
Maybe this trick works in packages too. Never tried.

Related

Add resource file by code with Delphi

I have a custom res file "myres.res".
In this moment I use it on my application, I have add {$R myres.res} under {$R *.res} line inside my DPR project file and it work very well.
Now I'd like creare a VCL component with a boolean property "UseCustomRes". If I set UseCustomRes=True I'd like add the res file when I compile my project but if I set UseCustomRes=False I don't want use res file when I compile my project.
Is this possible? I don't know if it possible and how it is possible.
Picking a resource at runtime
If you want to use a resource (or not) based on a runtime variable you'll have to compile it in always, otherwise you'll lose the option of using it at runtime.
Whilst running you can access a resource using TResourceStream.
Here's an example:
procedure ExtractResource;
var
rs: TResourceStream;
begin
rs:= TResourceStream.Create(HInstance, 'NameOfResource', RT_RCDATA);
try
rs.Position:= 0;
rs.DoSomethingWithTheResource...
finally
rs.Free;
end;
end;
Here's the online help: http://docwiki.embarcadero.com/Libraries/XE2/en/System.Classes.TResourceStream
Note that the help entry for TResourceStream is a bit broken; it does not show all methods.
The missing methods are here: http://docwiki.embarcadero.com/Libraries/XE2/en/System.Classes.TStream_Methods
Picking a resource at compile time
Note that the {$R *.res} line includes any .res file in the current directory.
If you want to select a specific .res file, you'll have to exclude this line.
Conditional compilation is done using defines, like so:
implementation
{.R *.res} //disable the *.res inclusion.
{$IFDEF GetMyResource}
{$R MyResource.res} //will only be compiled if `GetMyResource` is defined
{$ENDIF}
{$R AlwaysIncludeThisResource.res} //will always be included.
You then define the symbol GetMyResource in the Conditional defines under project options, see here: https://stackoverflow.com/a/4530320/650492
Resources are included by the linker based on the existence of special $RESOURCE directives. These directives cannot be switched based on the value of an object instance's property.
So, with the built in tooling there is now way to achieve what you desire. What you will need to do is to add a post-build step that modifies the output file by adding the resource if needed. A good example of a tool which does exactly this is madExcept.

What to NOT do to prevent Delphi from mangling the uses list and {$*.RES} in a .DPR

Every couple of weeks, I bump into this: when doing an IDE operation on the uses units in a Delphi project, it mangles the .dpr file.
What happens is that it rebuilds the uses list, but gets the position wrong.
I'm wondering what usage pattern to avoid so I won't get into this error again.
I've had this error occur in many Delphi versions. I know it exists in at least Delphi XE2 (it happened there again today), XE, 2007, 2006 and 7.
The mangled fragment usually is structured like this:
ususes
Forms,
..
LastUnitInUses in 'LastUnitInUses.pas';
R *.RES}
and should be corrected by removing one us, and adding a {$:
uses
Forms,
..
LastUnitInUses in 'LastUnitInUses.pas';
{R *.RES}
Example file that went wrong:
program SysUtilsFormatTests;
{
Delphi DUnit Test Project
-------------------------
This project contains the DUnit test framework and the GUI/Console test runners.
Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options
to use the console test runner. Otherwise the GUI test runner will be used by
default.
}
{$IFDEF CONSOLE_TESTRUNNER}
{$APPTYPE CONSOLE}
{$ENDIF}
ususes
Forms,
TestFramework,
GUITestRunner,
TextTestRunner,
SysUtilsFormatUnit in 'SysUtilsFormatUnit.pas';
R *.RES}
begin
Application.Initialize;
if IsConsole then
with TextTestRunner.RunRegisteredTests do
Free
else
GUITestRunner.RunRegisteredTests;
end.
Example of corrected .dpr file:
program SysUtilsFormatTests;
{
Delphi DUnit Test Project
-------------------------
This project contains the DUnit test framework and the GUI/Console test runners.
Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options
to use the console test runner. Otherwise the GUI test runner will be used by
default.
}
{$IFDEF CONSOLE_TESTRUNNER}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
Forms,
TestFramework,
GUITestRunner,
TextTestRunner,
SysUtilsFormatUnit in 'SysUtilsFormatUnit.pas';
{$R *.RES}
begin
Application.Initialize;
if IsConsole then
with TextTestRunner.RunRegisteredTests do
Free
else
GUITestRunner.RunRegisteredTests;
end.
The only thing that I know that works is for you to let the IDE manage the .dpr file.
Don't add comments.
Don't use conditionals like $IFDEF.
Don't modify the code in the .dpr file.
if you do any of these things, expect the IDE to bite back.
Personally I do all of these and fight back at commit time. I use my VCS to defend against bogus IDE changes. It's not ideal, but it's the best option.

Why is this resource directive showing in the list of available forms?

I just stumbled on something very peculiar. Refer to this screenshot:
Why is it showing $R *.res in the list of available forms? This project only has two forms and one additional unit, and here's the project's main file source:
program MyProgram;
uses
Forms,
uMain in 'uMain.pas' {fMain},
uEmail in 'uEmail.pas' {frmEmail},
Vcl.Themes,
Vcl.Styles,
Other.Unit in 'Other.Unit.pas';
{$R *.res}
begin
Application.Initialize;
TStyleManager.TrySetStyle('Iceberg Classico');
Application.Title := 'My Program Title';
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
PS - This is slightly modified code, the only thing that changed was the program name, program title, and the name of one of the units (Other.Unit.pas) which I know is a bad example since Unit is a reserved word. But the original unit name has a namespace prefix such as this one.
UPDATE
I followed the recommendation to move this RES reference to before the uses clause. After dong this (and cleaning all temp files, restarting IDE, etc.), it still shows in the list. But to my surprise, the IDE has actually added this RES reference back!
So now the IDE its self has turned it into:
UpdateUnit in 'UpdateUnit.pas' {$R *.res};
(UpdateUnit is a new name I gave it so I'm not giving internal information away)
So, I opened the DPROJ file and did a search for *.res and sure enough found this:
<ItemGroup>
....
<DCCReference Include="UpdateUnit.pas">
<Form>$R *.res</Form>
</DCCReference>
As written, I could not reproduce this... however if I removed the trailing semicolon (";") after the "Other.Unit in 'Other.unit.pas'" line, the "$R *.res" shows up in the project options.
This isn't a bug, as far as I can see. Since your comments indicate that the presented code isn't the same as what you're using it will be hard to diagnose. I will try and explain what is happening; If you look at the uMain and uEmail units, there is a comment next to each that is the name of the form. Since these units may not actually be open in the IDE, there is no way to know if there is a form associated with that unit. The presence of a uMain.dfm isn't a guarantee that uMain.pas actually has a form (it may be left-over cruft). The IDE places this simple comment within the uses clause for that unit in order to tell the project manager that this unit has a form.
By removing the ";", the parser sees the next comment token as {$R *.res}. It then concludes that Other.Unit.pas must contain a form named "$R *.res". It does no validation of the name nor even tries to open the unit. It merely takes the raw content of that comment and assumes it's a form name.
You can safely move the {$R *.res} before the uses clause so that the project parser doesn't confuse that directive comment as a form.
EDIT: From my comment above:
What has likely happened is this; at some point you may have edited the .dpr file in a manner that confused the parser into thinking that "$R *.res" was the form name. You then saved it while in that state, which also injected that information into the .dproj file. The IDE tries to keep those two things in sync and sometimes will take the .dproj file as being the "master" and will update the .dpr file to match. You should be able to safely remove the $R *.res from the dproj file.
This does not reproduce with Delphi XE2 Update 4 (see below).
More accurately: the code you posted does not reproduce.
But the scenario that you describe in the comments does: if the .dproj is hosed, the IDE will re-add the incorrect information to your .dpr. See below for further explanation.
At the end of this answer an edit that shows you an occurrence at a client: Delphi XE2 can get confused somehow to the internal state gets wrong, and it writes back both a wrong .dproj and .dpr file.
If the code you posted is not the same as the code that fails, please correct your question with the code that fails (and post a comment to my answer so I get a notification and update the QC entry; in the current form your QC entry will be marked as "cannot reproduce" and then closed).
I have seen the IDE being confused in various places (including the project options) after an AV, or when line-endings in the .pas or .dpr files are not CRLF, or when manually editing .DPR files.
Those issues usually disappear when you restart the IDE. Sometimes you even have to clean up some files (with extensions like .DCU, .local, etc).
Worst case is that the IDE got so confused that both the .DPR and .DPROJ contain wrong information (hence my comment), that appears to be the case in your situation (thanks to your edited question). You can manually edit the .DPROJ and .DPR files to resolve this. Make sure to have backups as it is easy to break the XML format of a .DPROJ file
I could reproduce it if I moved the RES declaration before the semicolon: that's the format the IDE expects so it can parse the .DPR for Forms, DataModules and Frames (and potentially other design surfaces):
Unit1 in 'Unit1.pas' {DataModule1: TDataModule},
Unit2 in 'Unit2.pas' {Frame2: TFrame};
Unit3 in 'Unit3.pas' {Form3};
Basically, you should not edit the .DPR file: the IDE owns it and will rewrite it for instance when you add new units to your project, you change the program icon, change the application caption, etc.
Main program that does not reproduce:
program MyProgram;
uses
Vcl.Forms,
uMain in 'uMain.pas' {fMain},
uEMail in 'uEMail.pas' {frmEmail},
Vcl.Themes,
Vcl.Styles,
Other.Module in 'Other.Module.pas';
{$R *.res}
begin
Application.Initialize;
TStyleManager.TrySetStyle('Iceberg Classico');
Application.Title := 'My Program Title';
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
The options dialog:
Main program that does reproduce (note where the RES is):
program MyProgram;
uses
Vcl.Forms,
uMain in 'uMain.pas' {fMain},
uEMail in 'uEMail.pas' {frmEmail},
Vcl.Themes,
Vcl.Styles,
Other.Module in 'Other.Module.pas' {$R *.res};
begin
Application.Initialize;
TStyleManager.TrySetStyle('Iceberg Classico');
Application.Title := 'My Program Title';
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
Edit 20130616
Ran into this at a client below is the diff of the before/after in both the .dpr and the .dproj (some of the names have been anonymized).
Delphi XE2 got confused somehow: it was not an edit in the .dpr that induced this problem.
There are two things I suspect:
an access violation somewhere overwrote some internal state causing the internal project structure to be damaged (the project depends on a lot of 3rd party packages to be installed, all of which are in the same BDS process)
there is lots of code in the .dpr that might have confused the internal project structure
I've refactored all of the .dpr code into a separate module. Hopefully that was the cause and this won't happen again.
Old .dpr fragment:
program Server;
uses
ShareMem,
SysUtils,
Forms,
SvcMgr,
WebReq,
uMain in 'uMain.pas' {fMain},
//...
uDBOrm in 'uDBOrm.pas',
uWinProxySettings in '..\..\..\Server\trunk\Server\uWinProxySettings.pas',
GpStuff in 'GpStuff.pas',
DSiWin32 in 'DSiWin32.pas';
{$R *.res}
function IsServiceApp: Boolean;
begin
//...
end;
begin
if IsServiceApp = True then
begin
//...
end else
begin // GUI Interface
if Assigned(Application) then
FreeAndNil(Application);
Forms.Application.Initialize;
Forms.Application.MainFormOnTaskbar := True;
ReportMemoryLeaksOnShutdown := True;
Forms.Application.CreateForm(TfMain, fMain);
Forms.Application.Run;
end;
end.
New .dpr fragment:
program Server;
uses
ShareMem,
SysUtils,
Forms,
SvcMgr,
WebReq,
uMain in 'uMain.pas' {fMain},
//...
uDBOrm in 'uDBOrm.pas' {$R *.res},
uWinProxySettings in '..\..\..\Server\trunk\Server\uWinProxySettings.pas',
GpStuff in 'GpStuff.pas',
DSiWin32 in 'DSiWin32.pas';
{$R *.res}
function IsServiceApp: Boolean;
begin
//...
end;
begin
if IsServiceApp = True then
begin
//...
end else
begin // GUI Interface
if Assigned(Application) then
FreeAndNil(Application);
Forms.Application.Initialize;
Forms.Application.MainFormOnTaskbar := True;
ReportMemoryLeaksOnShutdown := True;
Forms.Application.CreateForm(TfMain, fMain);
Forms.Application.Run;
end;
end.
Old .dproj fragment:
<DCCReference Include="uDBOrm.pas"/>
<DCCReference Include="..\..\..\Server\trunk\Server\uWinProxySettings.pas"/>
New .dproj fragment:
<DCCReference Include="uDBOrm.pas">
<Form>$R *.res</Form>
</DCCReference>
<DCCReference Include="..\..\..\Server\trunk\Server\uWinProxySettings.pas"/>

How do you deal with IFDEFs in .dpr uses section

Whenever you add a new unit to the project Delphi rebuilds the .dpr file and all the IFDEFs in the uses section are gone.
To work around this I typically use NotePad to create new .pas files, and add it to the .dpr manually. If I need a form I use File->New->Form and then revert the .dpr file to the previous version. Not very RAD if you ask me ;-)
How do you deal with that? Is there a way to add a unit in the IDE while keeping the IFDEFs?
Sometimes I create a unit specifically as a place for all the IFDEFs and other stuff the IDE would mess up if it were in the dpr. This unit typically goes to the top of the dpr's uses clause. This trick doesn't cater for all scenarios but it sometimes saves a lot of tedious work.
I don't put any ifdefs into a dpr file. If I want to use different units/forms in a project, depending on some condition, I split the project in two.
I spent quite a while trying to work that one out,
I ended up have a project file (.dpr) for each build type,
with the Conditions in Project|Project Options|Directories/Conditionals
and only the units i wanted added in to the project
this dose have the down side that if you have custom code in the .dpr, it will have to be manually copied to the other project files when it changes.
as noted by Rob Kennedy, this can handled by putting the custom code into its own unit, which is called by a single procedure. thus minimizing the .dpr code size/changes to be made
Also, another bonus you get is that if you add all your .dpr files to a project group, you can build all your different versions with one click / cmd line
You can add it manually from within the IDE. (Use the "view source" option on the project).
Normally the dpr is "hidden". You are not expected to change anything in there.
And if you do, you better make sure all your changes are manual else you are losing some information.
For forms, datamodules, and other units which contain a single class by which functionaity will be replaced, the solution is rather simple. Just DON'T add the custom units directly to the product, but do save them some place in the search path (or modify the project search path to include thier location).
1) Create a NEW unit, which contains either the parent for all of the other classes, or the interfaces that they all will implement (I generally prefer the later as it allows easier customization) [for example purposes this is called uSpecialParent.pas]
2) Add a class variable which will referenced when you need to create the new functionality. for instance if you just were going to show modal a bunch of forms, so didn't care about any other methods then you could have a variable that looked like the following:
TYPE
TMySpecialFormClass : class of TForm;
VAR
TMySpecialForm : TMySpecialFormClass;
3) Create another unit which will contain all of the IFDEFS. It could look something like the following:
Unit uRegisterSpecialForms;
interface
uses
{$IFDF SPECIAL1}
uSpecial1,
{$ENDIF}
{$IFDEF SPECIAL2}
uSpecial2,
{$ENDIF}
uSpecialParent;
implementation
// no code needed.
initialization
{$IFDEF SPECIAL1}
TMySpecialForm := uSpecial1.TSpecialForm1;
{$ENDIF}
{$IFDEF SPECIAL2}
TMySpecialForm := uSpecial2.TSPecialForm2;
{$ENDIF}
end.
4) To reference this in your code you only need the uSpecialParent added to the unit which will be requesting a special form and then create it dynamically for example to show this modal you could invoke the following:
var
frm : TForm;
begin
frm := TMySpecialForm.Create(nil);
try
frm.showmodal;
finally
frm.free;
end;
end;
And here's the lo-tech approach for completeness' sake:
After the IDE has messed up your uses clause again:
close the project
go to your version control tool of choice and diff the DPR against the latest checked-in
version using a merge-enabled diff tool like WinMerge
revert the IDE changes
save the DPR
get on with it
(Delphi 7)
I've just tried the same.
Take a look at the first code version and at my comments below:
program Project1;
{$IFDEF TESTIFDEF}
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$ELSE}
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$ENDIF TESTIFDEF}
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.Run;
end.
At that point, I've just inserted the 2nd Form and noticed that the corresponding unit (Unit2.pas) was inserted inside the first part of the IFDEF i.e. inside the "TESTIFDEF" labeled part - hence not overriding the second block (after the {$ELSE}).
Thus your solution should be:
define a IFDEF statement like "{$IFDEF DELPHIBASISCONFIGURATION}" in place of my "{$IFDEF TESTIFDEF}" where all the forms will be added.
define as many alternative LABELS for the different configurations you want to work with.
each time you've added a form to the project, copy the inserted line of the first block into the corresponding blocks below - depending on your needs...
activate the required configuration using the define statement or the option dialog
NEVER DEFINE "DELPHIBASISCONFIGURATION" ;)
Hence, it should look like this:
program Project1;
{$DEFINE MYCONFIG1} // THIS ONE IS NOW ACTIVE
{$IFDEF DELPHIBASISCONFIGURATION}
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas' {Form3};
{$ELSE}
// THIS IS A "COMMON TO ALL CONFIG" PART
uses
Forms,
// FIRST CONFIGURATION
{$IFDEF MYCONFIG1}
Unit1 in 'Unit1.pas' {Form1},
Unit3 in 'Unit3.pas' {Form3}
{$ENDIF MYCONFIG1}
// SECOND CONFIGURATION
{$IFDEF MYCONFIG2}
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2}
{$ENDIF MYCONFIG2}
// THIS IS THE "COMMON TO ALL CONFIG" END :)
;
{$ENDIF TESTIFDEF}
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
//Application.CreateForm(TForm3, Form3);
//Application.CreateForm(TForm2, Form2);
Application.Run;
end.
As you can see, I've discarded the calls to Application.CreateForm(...) for Form2 and Form3.
IMHO, it's usually better to dynamically create the supplemental forms at the moment you really need them i.e. not all the forms at program start...

Empty main form in GUI app converted from Delphi to Lazarus

I have converted my 2 GUI apps from Delphi to Lazarus.
Both apps compile for Win32 platform, i386 and with GUI.
Main form were converted using Lazarus tool and can be edited from IDE.
But when I run such application main form does not appear, only blank form without any controls.
I tried to debug this. It runs all code in initialization sections,
and runs code from .lpr project, but something wrong happens in CreateForm() because
it doesn't run code in the main form OnCreate event. In event log I can see all
texts I write to it with '<App.Run' appearing after I close this empty form.
Code in .lpr project:
Application.Initialize;
AddToEventLogInfo('App.CreateForm');
Application.CreateForm(TfrmTst, frmTst);
AddToEventLogInfo('App.Run>');
Application.Run;
AddToEventLogInfo('<App.Run');
I checked that I am able to create simple GUI apps from the Lazarus, but both converted GUI
apps do not work as expected. What can be wrong? Have I missed something?
Maybe one of many warnings and hints Lazarus write is important?
When I run my app Lazarus writes this:
windres: warning: 14: "MAINICON": 1045: duplicate value
windres: warning: 16: 1: 1045: duplicate value
Project "Tst_fpc" successfully built. :)
EDIT:
Lazarus conversion tool converted .dfm -> .lfm, but has some problems with .pas file. I had to manually:
add Lazarus units to uses:
uses
{$IFDEF FPC}
LCLIntf, LResources,
{$ENDIF}
Conditional compile Delphi form {$R *.dfm}:
{$IFNDEF FPC}
{$R *.dfm}
{$ENDIF}
Add .lrs resource in initialization code:
initialization
{$IFDEF FPC} {$i myunit.lrs} {$ENDIF}
I suspect that the mainform unit (I assume it is called utest) doesn't have a {$I utest.lrs} in its initialization section. The .lrs is the lazarus resource file, created from the lfm (dfm) in delphi.
The empty form is the form of for the current project as you used the convert Delphi project from tools which means the current project is active.
Try this:
On the project option close the current project.
On the small main window named as project wizard, use the convert Delphi project option.
I'm sorry I can't give you a straight answer. From what I understand there's a problem a problem with the resource file. In delphi that's the *.res, I don't know what they look like in Lazarus. Use a program like resedit, http://www.resedit.net/, to open the resource file. I tried it and found a "folder" Icon where there was a post MAINICON. I'm guessing you have two. In that case remove one of them.

Resources