Decompiling Delphi .dcu to .pas - delphi

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.

Related

Same code, missing qtintf70.dll

Compiling some old code, my application will no longer run. Newly compiled exe-file won't start "because qtintf70.dll is missing from your computer".
Strange thing: an older exe file compiled from exact same code runs just fine. Both exe files tested on same system, but compiled on different Delphi installations (both Delphi 7 running on VirtualBox).
Googling, someone suggested "You have pulled in Clx somehow. Clx apps require the QT library. Look for units in your uses clauses that start with Q." but again: this is the exact same code. I've checked and can't find anything.
Suggestions?
In D7, the only source code units which reference qtintf70.dll are QForms.Pas and Qt.Pas.
So, what you need to do is to
Move all instances of these two files and their corresponding .DCU files to somewhere not on your project's search paths. Use a utility like SwiftSearch to make sure you find all of them.
Do a full build of the project.
The build should grind to a halt somewhere with a complaint that the compiler can't find one or other of these units. The source unit that is being compiled at the time is the one which contains a reference to one or other of them.

Delphi "remembers" old DCU dependency

I'm moving development of an application from one machine (same version of Delphi). The original version of the application used a TMoneyEdit component from the TMS pack. While moving the project I'd like to remove the dependency on that product. So, in the source, I removed the TMoneyEdit component and replaced it with one of my own. I also removed the MoneyEdit reference from the unit's USING clause.
However, Delphi still will not compile my application, giving the error File not found MoneyEdit.DCU.
If I search all files in the project for "moneyedit" I find nothing. I've even searched across my hard disk, and the only references to moneyedit are in the original TMS component files (and I have no references to TMS in my project, either).
Obviously, there's still a dependency stored somewhere. Can anyone tell me where?
When moving from one computer to another did you take any DCU's from your current project with you? I may be that one of your projects DCU's are out dated and sill using the old code base. If that is the case doing a full clean and build should solve it.

How do I solve "Two different CRTLDLLs are loaded" when using packages in C++ Builder 2010?

We are trying to split up our monolithic EXE into a combination of an EXE and several packages. So far, we have one package that we're trying to use, and when running the EXE Codeguard shows the following error on startup:
CG Error
Two different CRTLDLLs are loaded. CG might report false errors
(C:\Windows\system32\CC32100MT.DLL)
(D:\Projects\Foo\Bar.bpl)
OK
I read this as two different runtime libraries being loaded - one, the correct one (CC32100MT.dll), one incorrect, which is the package we're trying to use.
Continuing to run the program shows odd errors, especially casting between classes or passing a pointer to a class as a parameter in a method that crosses the EXE/DLL boundary. Codeguard itself doesn't show any other errors at all though. Edit: This is now resolved, and wasn't related. The program appears to run correctly, but the warning Codeguard shows is still worrying.
How do we solve this?
Some more details
We've looked at as many things as we (the developer working on this and I) can collectively think of:
Each project is built using runtime packages. The EXE host lists Bar in its package list.
Each project is set to compile with dynamic RTL. However, changing this does not solve the problem.
The package is linked to the EXE via its BPI file, but linking via a LIB makes no difference either.
The EXE and BPL are compiled with the same project settings, where the same options exist for both types of project. We think, anyway :)
There is only one copy of the BPL and BPI on the system: it's definitely linking to the right one.
Examining the EXE and BPL with Depends and TDump show they are both using C:\Windows\system32\CC32100MT.DLL. They should both be using the one RTL.
Creating a new project (a plain VCL forms application) and linking to the BPL (via its BPI) works fine. Something in the process of adding all the files and LIBs that make our EXE contain the code it needs to changes this, but we haven't been able to figure out what.
The LIBs all either correspond to DLLs we use (flat C interface, usually look as though they were built with MSVC) or are simple projects with lots of related files, compiled to a lib for the purpose of linking into the EXE - these correspond roughly to the areas of the program we want to split to BPLs, by the way. There don't seem to be project options for the LIB projects that would affect RTL linking, unless we've missed them.
I have exhaustively hunted through Depends and looked at all RTL and CC32*.dll files the EXE and every single DLL references. All are identical: rtl140.bpl and CC32100MT.DLL. Fully qualified paths show they are the same files, too. Everything should be using the one same run-time library.
Edit: The final EXE is complex, built with several libs, several DLLs, etc. All these, when built with C++Builder, are built with the current version. Is it possible there's something in one of these DLLs or LIBs that could cause a problem? I don't know enough about how the RTL is linked in to be sure about where to look... my (naive?) assumption is that the linker would normally link in one set of RTL functions, but that of course doesn't seem to be happening... and I don't know how things change when using packages. Is it possible this error has always existed and Codeguard has not flagged it before, because we haven't used something dynamic like a package?
Perhaps another question is, Why would a package have its own RTL anyway, or what would make it count as 'a RTL DLL' to Codeguard?
We're stumped. Absolutely stumped. We've had other problems using BPLs (they seem to be surprisingly tricky things, especially using C++) but have managed to solve them all. This one we've had no luck at all and we'd really appreciate any insights :)
We're using C++Builder 2010 (as part of RAD Studio actually, but with little Delphi code apart from components.)
Edit: Started a bounty. I'd really like to solve this!
Edit 2: Thanks to David Dean for his help (marked as answered below.) Via email, he pointed out this issue was reproduced in a simple test case by someone else, and is logged in Embarcadero QC as report 86335. Currently there is no fix, but the warning does not appear to indicate a genuine problem (ie, it's probably a spurious error, and while it's a pity to have to click past the dialog when you run, hopefully there's nothing in the error to worry about.)
Since one of these is coming from a .bpl, did you try turning off "Build with runtime packages" in the project options?
We had a similar problem. We tracked it down to a (non VCL) .cbproj that was created without the "Multithreaded" option.
As far as I can tell, the only time you get chance to set this option is when you create a new .cbproj, it cannot be changed afterwards using the GUI. We ended up "hacking" the .cbproj to include the following:
<Multithreaded>true</Multithreaded>
To determine which dll is causing the issue, it should be the last dll loaded in the output window just before you see the CG message.
Did you check if you use _TCHAR as char. We had some similar problems with RAD Studio and we found a workaround using _TCHAR as char. As soon as one DLL or BPL Project is compiled with wchar_t, this code guard error appears.
We also figured out, that EXE projects can be compiled with TCHAR = wchar_t without any problem (the main function will be WIDE).
The settings does not affect the GUI being able to handle UNICODE.
A customer logged a similar case in our public bug tracking system and the bug has been identified and fixed in the latest release.

How to keep forms and frames compilable in Delphi 6 - 2007?

We recently converted our long-running Delphi project to Open Source. Multiple people have contributed patches already, which is great, but unfortunately forms and frames when saved with Delphi 2006 (and later) contain new properties in the .dfm that are not handled by older versions. Forms are handled quite gracefully by the IDE ("ignore propery?"), but frames are loaded at runtime and result in errors. Not an option, as far as I'm concerned.
I now removed those properties from the .dmf files by hand, but I am really wondering if there is a more elegant solution. There is no way to save in a backwards compatible format from the new IDE's, is there? Are there existing tools to strip the nonsupported properties from the .dfm's ? Any other elegant solution I am missing?
Normally, with a commercial project, I'd just upgrade the project to the most recent version applicable... but as this is open source I really don't want to loose out on those developers still working on Delphi 7. That includes myself, actually.
The JEDI JVCL project uses a little utility dc.exe (delphi cleaner) and a list of properties in DFMs that are not present in older versions of delphi, mine contains the following text:
*.PopupMode
*.PopupParent
*.ExplicitLeft
*.ExplicitTop
*.ExplicitWidth
*.ExplicitHeight
*.BevelKind
*.BufferDocument
*.DoubleBuffered
*.ParentDoubleBuffered
*.DisableHyperlinks
*.AlwaysEnquoteFloats
*.PixelsPerInch
I run this dc.exe utility from a batch file which cleans my dfms before I commit
changes to subversion. The syntax in my batch file for this is:
dc.exe -s -fd10.txt *.dfm -i
You can grab my stuff at:
http://sites.google.com/site/warrenpostma/files
You can try Andy's DFMCheck. It can automatically open and close all forms and frames in a project, which makes the IDE remove unknown properties (as Marco wrote).
Well, for sake of completeness:
Open the dfms in the oldest Delphi supported, let it remove all unknown properties, change a property and save.
For your purposes, Warren's solution is better, but it can be a workaround. I did it for a while when we were dual D7-D2006ing.

Can I recompile the .PAS files used by the Delphi IDE?

I am familiar with Jeff Atwood's article about how errors are always the programmer's fault, but I believe I have really and truly found a bug in a Delphi .pas file.
Specifically, I'm using Delphi 2007, and the error is on line 955 of the DBCommon.pas file, which on my machine is located here:
C:\program files\codegear\rad studio\5.0\source\Win32\db\DBCommon.pas
And the code is this:
...
FieldIndex := StrToInt(Token);
if DataSet.FieldCount >= FieldIndex then
LastField := DataSet.Fields[FieldIndex-1].FieldName else
...
If "Token" has a value of zero, then we try to access index -1 of DataSet.Fields, resulting in a list index out of bounds error.
This error is not raised to the user, because it is handled before it gets that high up, but it is enormously irritating to have the debugger break in every time this happens.
I could "Ignore this exception type" but Index out of bounds errors are common enough that I don't want to universally ignore them.
The situation that causes FieldIndex to be zero is when you have a SELECT statement whose ORDER BY contains a function, as in:
ORDER BY
CASE WHEN FIELD1 = FIELD3 THEN 1 ELSE 2 END
,CASE WHEN FIELD2 = FIELD4 THEN 1 ELSE 2 END
I can fix the bug in DBCommon.pas, but Delphi will not recompile itself, and my change does not take effect. If I rename the .DCU file, then it just complains that "DBCommon.dcu" cannot be found.
So (finally) my question is: Can I recompile DBCommon.pas with my fix, and if so, how?
You can probably put dbcommon.pas in youre project directory. It will then be compiled along with the rest of the project.
See previous answers for how to create the situation where you can recompile modified VCL source. I would however add that you seriously consider managing your changes in your change control system, using the "Vendor Branch" SCM pattern.
In simple terms (using SVN as a reference):
Create a "vendor source" copy of the original vendor supplied files. This is your "pristine" reference copy.
Create a branch representing that pristine copy (e.g. "2009" for the Delphi 2009 version of the VCL)
create a further branch into a separate "vendor library" folder. THIS is the copy of the library that you should reference in your projects
any modifications to the vendor source are made in the "vendor library" branch.
when the vendor provides a new version of the library you check the new version in to the "vendor source" project and create a new branch for the new version.
you can then easily diff the vendor revisions. But more importantly (with SubVersion, and possibly othe SCM systems) you should also be able to simply merge (i.e. automatically) the new vendor source with your "vendor library" branch to easily incorporate vendor changes with your own modifications.
This is all described far better than I just did in the excellent O'Reilly book: "Version Control with SubVersion"
NOTE however that the "loaddirs" utility mentioned in that book is no longer supported due to copyright issues, so updating "vendor drops" is currently a manual exercise, but this occurs only infrequently and is not a major burden.
We are using this pattern ourselves, although in the case of the VCL we do not maintain a complete copy of the entire VCL source tree in our "vendor source" or "vendor library", but instead only track changed and dependent units. For other libraries managed under a vendor branch we typically do maintain complete copies but decided this wasn't necessary for the VCL.
We've only just implemented this pattern however, so we may yet decide that we need to take a more comprehensive approach with the VCL too.
ymmv
You can, but often you don't have to. Recompiling a VCL unit sometime means recompiling all the rest of the VCL units either because you've changed the interface of a unit or because the compiler gets confused and thinks you've changed the interface. Recompiling a VCL unit also rules out the possibility of using most run-time packages because you can't recompile Delphi's run-time packages.
Instead of recompiling, you can use run-time patching. I've used the method in the TNT Unicode controls, but Madshi also provides a way to replace a function with your own implementation. If you copy the implementation of DBCommon.GetIndexForOrderBy into your own unit and make your fixes, you can use this command to patch the VCL version with your own:
var
Old_GetIndexForOrderBy: Pointer;
HookCode(#DBCommon.GetIndexForOrderBy,
#Fixed_GetIndexForOrderBy,
Old_GetIndexForOrderBy,
0);
With the Tnt Unicode library, find the OverwriteProcedure routine in the TntSystem unit. It's not public, so you'll need to either declare it in the unit interface or copy it into your own unit. Then you can call it much like the Madshi code above:
var
Old_GetIndexForOrderBy_Data: TOverwrittenData;
OverwriteProcedure(#DBCommon.GetIndexForOrderBy,
#Fixed_GetIndexForOrderBy,
#Old_GetIndexForOrderBy_Data);
We have a folder under our project source tree called VCL, into which we place copies of the VCL source that we wish to modify slightly.
Your example is a good candidate for doing the same thing.
You will need to modify the search path for your project so that "your" VCL folder is earlier on your path than the "Source" folders under your Delphi installation.
You may also find that if you copy one VCL source unit out and modify it, you will have to also copy other VCL source units out into "your" folder which may be dependencies.
Our reason for doing this is that we want our builds to have zero compiler hints and warnings. There are some parts of the VCL source that are not hint/warning free.
"I am familiar with Jeff Atwood's article about how errors are always the programmer's fault, but I believe I have really and truly found a bug in a Delphi .pas file"
Are you joking me? With Delphi you always blame Borland first :)
Something is weird, go Google it and see if it is a Delphi bug. Only if cannot find any similar reports you site down and check your code line by line.
After I reinstall Delphi I have to patch the original PAS files in 6 (six) places. There are tons of bugs that appear on a fresh Delphi installation and can be easily reproduced. Delphi (the one that we all love) is full of bugs. There is an entire history created around this.
There are so many people releasing external patches (such as http://andy.jgknet.de/blog/?page_id=288) and Borland/Imprise/GoGear/Embarcadero keep ignoring them. It is a true wonder they included FastMM in their release.
Anyway, I have recompiled those PAS files and now I replace the original DCUs with the patched ones.
Simply - Yes. Using one of the above answers [By Tom or Connor]. Copy DBCommon.pas to your project folder rather than edit the original. This leaves other projects and compilations unaffected because it won't be on the path.
You can set:
DataSetProvider.Option.poRetainServerOrder = True

Resources