I am using D2007 and am trying to document my source code, using the HelpInsight feature (provided since D2005). I am mainly interested in getting the HelpInsight tool-tips working. From various Web-surfing and experimentation I have found the following:
Using the triple slash (///) comment style works more often than the other documented comment styles. i.e.: {*! comment *} and {! comment }
The comments must precede the declaration that they are for. For most cases this will mean placing them in the interface section of the code. (The obvious exception is for types and functions that are not accessible from outside the current unit and are therefore declared in the implementation block.)
The first comment cannot be for a function. (i.e. it must be for a type - or at least it appears the parser must have seen the "type" keyword before the HelpInsight feature works)
Despite following these "rules", sometimes the Help-insight just doesn't find the comments I've written. One file does not produce the correct HelpInsight tool-tips, but if I include this file in a different dummy project, it works properly.
Does anyone have any other pointers / tricks for getting HelpInsight to work?
I have discovered another caveat (which in my case was what was "wrong")
It appears that the unit with the HelpInsight comments must be explicitly added to the project. It is not sufficient to simply have the unit in a path that is searched when compiling the project.
In other words, the unit must be included in the Project's .dpr / .dproj file. (Using the Project | "Add to Project" menu option)
Related
Where I work we're still using Delphi 2009. I happened to be looking at the Forms unit in the VCL and stumbled upon:
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
function DisableTaskWindows(ActiveWindow: HWnd): TTaskWindowList;
This attribute is clearly the CLR class UIPermissionAttribute but unlike other references to the CLR this attribute is not wrapped in conditional compilation directives.
This surprised me because, AFAIK, in Delphi Win32 versions prior to 2010 brackets were only used for index notation in arrays and collection types, defining sets and assigning GUIDs to interfaces. This doesn't appear to be the case.
I did a regex search and found dozens of examples throughout the RTL/VCL. Some were attributes on types and some on methods.
Are these simply ignored by the compiler or do they serve some purpose in Win32?
I also found syntax that looked like:
[!UnitName]
[!InterfaceName]
Which appears to have something to do with generating source files from a template in an IDE wizard but these weren't in the RTL source folder. They were in the object repository folder.
I had hoped that perhaps attributes were an undocumented feature similar to how class helpers were available for years before they were documented but that doesn't appear to be the case.
I tried a simple test and added attribute notation before a class definition. The compiler didn't choke on it but it did issue a warning that custom attributes aren't supported.
I have two units (SuperPuper.pas and SuperPuper777.pas) in a project (.exe or .dll)
Is it possible to find out at runtime from my code in SuperPuper777.pas that
SuperPuper.pas is listed in project's uses clause;
SuperPuper.pas is first unit in project's uses clause.
The question was heavily edited. I guess that it's practical purpose is to find out if ShareMem.pas unit was declared in right position in project's uses clause.
If you want to enforce the correct declaration of a unit in a project's uses clause I would add a pre-build event to run a regex based Perl/Python/Ruby script. The script would do a simple regex based check of the .dpr file and return an error if it was not as intended. Not fool-proof, but probably the best balance of utility for a small amount of effort.
I realise that your question asks for runtime detection but this is a compile time property and so best attacked at compile time.
You can get a list of all units linked to the executable (i.e. at runtime) from the resources. There is a resource named PACKAGEINFO which contains a list of all units. You can find some reverse information from here. Perhaps you can get this information from enhanced RTTI (available since Delphi 2010).
About how to detect that an unit is first in the .dpr uses clause, I do not see any way of doing it at runtime easily. The list in PACKAGEINFO is not in this order. You can do that at compile time, by parsing the .dpr content and checking its uses clause.
The only way I see to guess which unit was first set is to use a global variable in a common unit:
var LatestUnitSet: (oneUnit, anotherUnit);
Then in the initialization section of each unit:
initialization
LatestUnitSet := OneUnit;
...
initialization
LatestUnitSet := anotherUnit;
...
Then check for LatestUnitSet to see which one was initialized the latest.
It only recognizes top-level non-function value declarations.
e.g. let a = 2
and doesn't produce documentation for functions or type definitions.
I've checked the xml documentation file and it has all the /// comments I put in the source, but none of them (except for the top level values) show up in the resulting html.
Yes, using C#-centric tools for F# documentation generation is usually pretty horrible. We started an alternative project a while ago, but it is not yet as mature as SandCastle: http://bitbucket.org/IntelliFactory/if-doc
Is it possible to unmangle names like these in Delphi?
If so, where do I get more information?
Example of an error message where it cannot find a certain entry in the dbrtl100.bpl
I want to know which exact function it cannot find (unit, class, name, parameters, etc).
---------------------------
myApp.exe - Entry Point Not Found
---------------------------
The procedure entry point #Dbcommon#GetTableNameFromSQLEx$qqrx17System#WideString25Dbcommon#IDENTIFIEROption could not be located in the dynamic link library dbrtl100.bpl.
---------------------------
OK
---------------------------
I know it is the method GetTableNameFromSQLEx in the Dbcommon unit (I have Delphi with the RTL/VCL sources), but sometimes I bump into apps where not all code is available for (yes, clients should always buy all the source code for 3rd party stuff, but sometimes they don't).
But say this is an example for which I do not have the code, or only the interface files (BDE.INT anyone?)
What parameters does it have (i.e. which potential overload)?
What return type does it have?
Is this mangling the same for any Delphi version?
--jeroen
Edit 1:
Thanks to Rob Kennedy: tdump -e dbrtl100.bpl does the trick. No need for -um at all:
C:\WINDOWS\system32>tdump -e dbrtl100.bpl | grep GetTableNameFromSQLEx
File STDIN:
00026050 1385 04AC __fastcall Dbcommon::GetTableNameFromSQLEx(const System::WideString, Dbcommon::IDENTIFIEROption)
Edit 2:
Thanks to TOndrej who found this German EDN article (English Google Translation).
That article describes the format pretty accurately, and it should be possible to create some Delphi code to unmangle this.
Pitty that the website the author mentions (and the email) are now dead, but good to know this info.
--jeroen
There is no function provided with Delphi that will unmangle function names, and I'm not aware of it being documented anywhere. Delphi in a Nutshell mentions that the "tdump" utility has a -um switch to make it unmangle symbols it finds. I've never tried it.
tdump -um -e dbrtl100.bpl
If that doesn't work, then it doesn't look like a very complicated scheme to unmangle yourself. Evidently, the name starts with "#" and is followed by the unit name and function name, separated by another "#" sign. That function name is followed by "$qqrx" and then the parameter types.
The parameter types are encoded using the character count of the type name followed by the same "#"-delimited format from before.
The "$" is necessary to mark the end of the function name and the start of the parameter types. The remaining mystery is the "qqrx" part. That's revealed by the article Tondrej found. The "qqr" indicates the calling convention, which in this case is register, a.k.a. fastcall. The "x" applies to the parameter and means that it's constant.
The return type doesn't need to be encoded in the mangled function name because overloading doesn't consider return types anyway.
Also see this article (in German).
I guess the mangling is probably backward-compatible, and new mangling schemes are introduced in later Delphi versions for new language features.
If you have C++Builder, check out $(BDS)\source\cpprtl\Source\misc\unmangle.c - it contains the source code for the unmangling mechanism used by TDUMP, the debugger and the linker. (C++Builder and Delphi use the same mangling scheme.)
From the Delphi 2007 source files:
function GetTableNameFromSQLEx(const SQL: WideString; IdOption: IDENTIFIEROption): WideString;
This seems to be the same version, since I also have the same .BPL in my Windows\System32 folder.
Source can be found in [Program Files folders]\CodeGear\RAD Studio\5.0\source\Win32\db
Borland/Codegear/Embarcadero has used this encoding for a while now and never gave many details about the .BPL format. I've never been very interested in them since I hate using runtime libraries in my projects. I prefer to compile them into my projects, although this will result in much bigger executables.
I have a set of compiled Delphi dcu files, without source. Is there a way to determine what types are defined inside that dcu?
To find out what's in a unit named FooUnit, type the following in your editor:
unit Test;
interface
uses FooUnit;
var
x: FooUnit.
Press Ctrl+Space at the end, and the IDE will present a list of possible completion values, which should consist primarily, if not exclusively, of type names.
You could have a look at DCU32INT, a Delphi DCU decompiler. It generates an .int file that is somehow readable but not compilable, but if you only want to determine the types defined, this could be enough.
The DCU format is undocumented, last I checked. However, there is a tool I found that might give you some basic info called DCUtoPAS. It's not very well rated on the site, but it might at least extract the types for you. There is also DCU32INT, which might help as well.
Otherwise, you might just have to open the file with a hex editor and dig around for strings.