How to step into RTL/VCL? - delphi

When debugging using the Delphi 7 IDE how can I step into code in the program files/borland/delphi7/source folder?
Sounds like a dumb question, but inquiring minds want to debug. (not that I think anything is wrong with the source, I just want to know why for the 9000th time I can't assign a TJpegImage to a TjpegImage).

Make sure you have the "Use debug dcus" option enabled in the Project Options, and the VCL source folder is in the Debugger's Source path.
As for why you cannot assign a TJPEGImage to a TJPEGImage, that would normally only happen if you are trying to pass a TJPEGImage object across a DLL boundary without the use of runtime packages, thus the app and DLL are doing internal comparisons against different copies of the RTL, causing the is operator (ie: ASource is TJPEGImage) to return False where it would normally report True instead.

Did you added the RTL/VCL source path to debug units path? Also, my Delphi 7 asks me to provide location of source file I want to step into if it's not in the path ... so should yours do :)

Related

Decompiling Delphi .dcu to .pas

I'm running RAD Studio Delphi XE2. Something strange appears to have been done to one of my .pas files. Many of the lines from my unit1.pas have been replaced with simply 'º' and others are missing. I am left with a small section of code from somewhere in the middle of my original file. Can I get the original unit1.pas back by somehow decompiling unit1.dcu?
Also, why would this happen? Have you heard of this before? The code runs but, obviously, I can't edit anything I can't see.
Even if you could decompile it, it would likely be an unmaintainable mess compared to your original.
Instead, try looking in the __History folder for your project. You should find older versions of your code. Pick the newest one ;-)
why would this happen?
Any number of reasons. Bug in the IDE? Bug in an IDE plugin or a custom component? Bug in your code that overwrites a source file, maybe?
You cannot decompile a .dcu file to the original source. Information is lost in the translation from source code to executable code. Type declarations, variable names, method names, code layout and so on are simply not present in the compiler's output. Compilation is a one way process.
If you use revision control, you'll just be able to pull the latest version from the repository. If you don't use revision control, you've just learnt a lesson the hard way and you will never again attempt to perform software development without revision control.

How to avoid Delphi fatal error F2051 when not all programmers have access to complete source

In our team new programmers does not get access to all the source of our application.
As long as they have to access program forms that depend only classes they can access the source, all is ok. When they have to use other classes from units they have only the .dcu, they get the F2051 error when the classes in the dcu change their interface.
Is there a clean way to get both ?
possibility to hide part of the source from new programmers
avoid the F2051 error when the classes in the "hidden" units change
I searched for a way to compile the Delphi code to a intermediate representation the way to hide the sources but to permit compilation, but I did not find anything.
You have to compile the code after the interface changes, and distribute the new .dcu to each programmer that needs to use it without source, and then they need to rebuild their applications. There is absolutely no other way to do it; the compiler requires it if there are changes in the interface.
For those "hidden" units, put the .dcu in the source control along with the .pas and make sure they are updated and in sync.
The "authorized" developers will fetch the new .pas, while the underlings will only see and fetch the .dcu.
If you really want to go that route of having 2nd class programmers, you have to do the management work that go with it.
That being said I'm personally more often that not stepping into the VCL source code when chasing a bug and trying to understand what's going on.
And I really don't like not having it (like with some low level Delphi SKU)
If you really want to create a stable binary unit that you can share with people you don't trust to read your source code, why don't you put the "secret" bits into a DLL and then load that DLL from the rest of the code.
It's called an "Application Binary Interface", either done natively with plain old pascal procedures exported from a DLL, or with COM Interfaces and a COM type-library.
Delphi has both DLL and BPL technology, to help you create something that isn't source code, but which has a stable ABI, and which will help you avoid whatever crazy little mess it sounds like you've got on your hands right now.

How to change VCL code?

I need (to make some quick and dirty tests) to modify the code of Variants and SysUtils.
What I need to do to "compile" the changes?
I can of course open those units in the IDE, but if I change them and I buoild a project again I don't see those units recompiled.
What is needed to be done?
The problem is you would need to compile ALL of the RTL/VCL against the 'new' units.
Instead modify a copy of the units in question and add them to your project when you want to use them. Delphi should use these over those in the RTL/VCL.
Unless you do not change the interface part of the unit (that is, you only modify the implementation side), you can make your own version of the RTL units (only exception is System.pas and SysInit.pas, but this is not in your scope - see our blog site for some enhancements of those units).
What you need is to put your own version of Variants.pas and SysUtils.pas in the search path of your project. They will be taken in account instead of the default RTL.
But be aware that you may easily break anything.
For testing purpose, this is OK, but if you want to use those modifications, you shall better use some automated regression tests, and know explicitly what you are doing.
Please note that you can use the "debug" version of the RTL units (from the project options), then step with the debugger within the official source code. It may help finding issues without touching the source.
If you change the interface part of the unit, you'll have to recompile all units which call the modified unit - for SysUtils and Variants, this is almost all RTL.
Delphi runtime DCUs are precompiled. It would be a waste of time to compile them at every build.
If the code you are trying to modify is a method of a built-in class, then a class helper may help:
http://docwiki.embarcadero.com/RADStudio/en/Class_and_Record_Helpers
So the question is which part of code do you want to modify in the runtime?
If you really wish to recompile the RTL you can do so (Make a backup first!). Versions of Delphi prior to Delphi 2010 had a makefile in the source folder that could be run from the command line to rebuild the rtl/vcl. I don't know for sure (I'm still using D2009) but from what I've heard this file is no longer present in newer versions. Hopefully there is an alternative. Otherwise you would wind up wasting a lot of time trying to guess that the compiler settings for each unit.
If you wish to "patch" a bug in the rtl for your project only you can copy the unit you want to modify into your project's folder and make your change. If the unit your modifying is used throughout the RTL/VCL you may find yourself copying quite a few dependent units into your project folder in order for it to compile.
If this significantly slows down the compile time for your project you can always do your initial compile then remove the "patched" units, leaving behind the compiled dcus.

How to recompile a specific unit from the VCL?

I want to apply a fix from QC to a Delphi 2009 unit (DBClient as it happens). I know I need to copy the unit to another directory and make the change to the copy. How do I then get Delphi to compile that unit and use it in favour of the DCU that already exists?
If you don't want to modify the original .Pas file, I do this by copy the .Pas file into my application folder, then choose built project, it will create new dcu file in my application folder, which will be used instead of the original one.
It's kind of a last resort (and not supported by CodeGear), but I do something similar to Mohammed when necessary. Except instead of putting any modified units into the application folder, I put them into their own folder with the rest of my library code and include this folder in my library path where it will be used by all of my projects. It also prevents me from having multiple (possibly slightly different) copies hanging around.
I also make a point of checking any updates to see what has changed so I can either remove the modified units or re-apply the changes to the newer (and presumably better) units from CodeGear.
I've never did this myself but there are projects in {RAD}\source\rtl along with batch build script. I believe this makes recompiling RTL functions easy. Other units should be recompiled easier.
If the changes you want to do are local and the units aren't widely used by other RTL/VCL units, the simplest way is to place copies of modified units separately from their standard place.
Another option is run-time patching aka detouring.

Delphi 2007 and {$IFDEF...} directive, fails to see our conditional

We have the following in our codebase, in a component file:
{$IFDEF ADO}
FDatabase : TADODatabase;
{$ELSE}
FDatabase : TODBCDatabase;
{$ENDIF}
The reason is that for various legacy applications, one or the other type of database connection and set of classes is to be used.
However, while configuring a new machine, it seems that our conditionals aren't taken into account. In the project settings, it says "ADO;DEBUG", and yet it compiles the above code with the odbc type instead.
The odd thing is that it isn't consistent. Two different units built as part of the same project uses separate settings. In other words, in one place our conditional is visible, in another it is not.
The file that compiles wrong does not have any {$UNDEF or similar directives, nor does it include any files.
What am I missing here?
Solved (ugh): Right, Delphi is just being boneheaded, or whatnot.
We found these:
I get “F1026 File not found”, OR some compiler options are not passed to the compiler from the IDE.
Configuration='Debug' Platform='BNB'
Which both mention the "Platform=BNB" setting. By enabling the diagnostic output, we see that exact value. So we try to override it per the articles, no luck, still BNB. Then we go to the project settings, turns out it can be overriden there as well, so we do that too, still no luck.
Turns out the Delphi installer, or whatnot, has added a "Platform=BNB" environment variable on operating system level, removing that, restarting Delphi, and all is well.
Well, as well as can be expected. We still have to use Delphi though.
You should always make a "build all" when you change those conditions.
It could be that one unit is actually not re-compiled. Check the following:
Is the .pas file included into the project?
Is there another file (.pas or .dcu) with the same name in the search path? It's possible the IDE sees a different file than the compiler.
Is the file actually compiled? Compare the timestamps of the .pas and the .dcu file.
Do you compile for another platform? Some compiler options are not passed unless the platform is "AnyCPU".
Whenever I encounter problems like this I brute-force delete every .dcu file in my project and component folders just in case the "Build all" doesn't remove all stale .dcus. The following recompile either solves the problem or reveals if any wrong .dcu was used.

Resources