Sunday, January 18, 2009

How to create a debug version of VCL Package

Delphi ship the following VCL libraries:

  1. DCU: Both debug and non-debug version
  2. DCP: non-debug version only
  3. BPL: non-debug version only

The only reason we need to build our application with debug version of libraries is we want to debug application in the powerful Delphi IDE.  We can trace from the "Call Stack Window" to know our current program location was derived from which lines or code in which unit:

2

These libraries are enough if we only build standalone application (non-package and only a single .EXE file).  However, if we compile and deploy our application with package, we will have problem perform the debugging activities as how the standalone .EXE does.  Delphi didn't ship debug version of DCP/BPL files.  We are unable to compile our packaged application that will show the debug information we want.  This cause the debugging operation particularly hard and difficult.

1

To overcome this problem, we can create our own debug version of VCL libraries manually.  We may use the following code to extract the files in VCL packages (.BPL files) that can be found in "%windir\system32":

procedure ShowInfoProc(const Name: String; NameType: TNameType; Flags: Byte;
  Param: Pointer);
begin
  if (Name = 'System') or (Name = 'SysInit') then Exit;
  if Flags and ufMainUnit <> 0 then Exit;

  case NameType of
    ntRequiresPackage: 
      ShowMessage(Name);
    ntContainsUnit:
      ShowMessage(Name);
    ntDcpBpiName:
      ShowMessage(Name);
  end;
end;

procedure TPackageInfo2.ExtractInfo(const aPackage: string);
var NeedFreeLibrary: boolean;
    M: HModule;
    Flags: Integer;
begin
  // Extract description
  FDescription := GetPackageDescription(PChar(aPackage));

  // Extract DcpBpiName, requires and contains clause
  NeedFreeLibrary := True;
  M := LoadResourceModule(PChar(aPackage));
  if M = 0 then begin
    M := GetModuleHandle(PChar(aPackage));
    if M = 0 then
      M := LoadLibraryEx(PChar(aPackage), 0, LOAD_LIBRARY_AS_DATAFILE + DONT_RESOLVE_DLL_REFERENCES)
    else
      NeedFreeLibrary := False;

    if M = 0 then raise Exception.Create('Package Error !');
  end;

  GetPackageInfo(M, Self, Flags, ShowInfoProc);

  if NeedFreeLibrary then FreeLibrary(M);
end;

Once you know the contains clause and requires clause for the package file, you may assemble your package file as follow:

  1. Start Delphi IDE
  2. Create a new package
  3. Edit the contains and requires clauses to add the files your found in the package using above code.
  4. Click Project |Option... to bring out project option window
  5. In "Description" page:
    1. make the package as "Runtime Only"
    2. Set Build Control to "Explicit rebuild"
    3. Enter the Lib Suffix value (e.g.: 100 for Delphi 2007 package, 120 for Delphi 2009 package)
  6. In Compiler page, Set "Use Debug DCU" and turn off "Optimization"
  7. In Directories/Conditional page, set the Output, Unit output and DCP output directory of your choice
  8. Save the package file as the name of the VCL package.  For example, VCL100.bpl will save as VCL.dpk
  9. Build the package
  10. It will produce 2 important files: Debug version of DCP and BPL files.

The above steps finish the creation of debug version of DCP and BPL files.

The next steps is how to make use of both the DCP/BPL files:

  1. Open your application that you build with VCL packages
  2. Click Project | Options...
  3. In Directories/Conditional page, add the path of debug version of DCP files to "Search Path"
  4. Compile all packages of your application
  5. Copy the debug version of BPL files to the output folder of your application
  6. Try to run your application in debug mode and you may start enjoying the powerful Delphi IDE debugging for your package built application.

Reference:

  1. Creating a debug version of the vcl package (CodeGear TeamB Blogs: Dave Nottage)

No comments: