Friday, December 21, 2007

Delphi and C++Builder IDE Tip of the Day

One of the most useful features and I believe least used is CTRL + F12. This brings up a list of all the units in the project manager, allows you to type one in and open it. Very handy. It turns out that the little down arrow on the right side of the edit view also has a shortcut key, CTRL + ALT + F12. This allows you to quickly view the open units, especially useful if there are more units than can be shown on the screen at once.

So there you have it, a quick tip before the Christmas break. I won't be posting here again until the new year so everyone have a great Holiday, Christmas and New Years!

Reading Info From a Package Part IV

Well this week really became package week. I posed part I here, part II here and part III here.

For this version I wrapped up the previous package cracking code into a class for easy consumption by any program. Notice I used the previously unused second parameter on GetPackageInfo which is just passed to PackageInfoProc via the Param parameter. This allows us to pass the Self pointer to remove globals. I also added error checking and removed some hard coded constants readers had commented on.


program pdump;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes;

type
TPackageProducer = (ppOld, ppUndefined, ppBCB, ppDelphi);
TPackageConsumer = (pcCompat, pcDelphi, pcBCB);

TPackage = class
private
FProducer: TPackageProducer;
FConsumer: TPackageConsumer;
FRequiresList: TStrings;
FImplicitUnits: TStrings;
FContainsList: TStrings;
FNeverBuild: Boolean;
FDesignOnly: Boolean;
FRunOnly: Boolean;
public
constructor Create;
destructor Destroy; override;
function LoadFromFile(const FileName: string): Boolean;

property RequiresList: TStrings read FRequiresList;
property ImplicitUnits: TStrings read FImplicitUnits;
property ContainsList: TStrings read FContainsList;
property Producer: TPackageProducer read FProducer;
property Consumer: TPackageConsumer read FConsumer;
property NeverBuild: Boolean read FNeverBuild;
property DesignOnly: Boolean read FDesignOnly;
property RunOnly: Boolean read FRunOnly;
end;

procedure WriteStrings(Strings: TStrings);
var
Index: Integer;
begin
for Index := 0 to Strings.Count - 1 do
WriteLn(Strings[Index]);
end;

procedure PackageInfoProc(const Name: string;
NameType: TNameType; Flags: Byte;
Param: Pointer);
begin
if NameType = ntContainsUnit then
begin
TPackage(Param).ContainsList.Add(Name);

if (Flags and ufImplicitUnit <> 0) and
(Flags and ufWeakPackageUnit = 0) then
begin
TPackage(Param).ImplicitUnits.Add(Name);
end;
end
else if NameType = ntRequiresPackage then
TPackage(Param).RequiresList.Add(Name);
end;

{ TPackage }

constructor TPackage.Create;
begin
FRequiresList := TStringList.Create;
FImplicitUnits := TStringList.Create;
FContainsList := TStringList.Create;
end;

destructor TPackage.Destroy;
begin
FRequiresList.Free;
FImplicitUnits.Free;
FContainsList.Free;
inherited;
end;

function TPackage.LoadFromFile(const FileName: string): Boolean;
var
Module: HMODULE;
Flags: Longint;
begin
Result := False;
Module := LoadPackage(FileName);

try
if Module <> 0 then
begin
GetPackageInfo(Module, Self, Flags, PackageInfoProc);

FNeverBuild := (Flags and pfNeverBuild) <> 0;
FDesignOnly := (Flags and pfDesignOnly) <> 0;
FRunOnly := (Flags and pfRunOnly) <> 0;

case Flags and pfProducerMask of
pfV3Produced: FProducer := ppOld;
pfProducerUndefined: FProducer := ppUndefined;
pfBCB4Produced: FProducer := ppBCB;
pfDelphi4Produced: FProducer := ppDelphi;
else
FProducer := ppUndefined;
end;

case Flags and pfConsumerMask of
pfConsumerDelphi: FConsumer := pcDelphi;
pfConsumerBCB: FConsumer := pcBCB;
else
if FProducer <> ppBCB then
FConsumer := pcCompat
else
FConsumer := pcBCB;
end;

Result := True;
end;
finally
UnloadPackage(Module);
end;
end;

var
Package: TPackage;
FileName: string;
begin
if ParamCount <> 1 then
begin
WriteLn('Usage: PDUMP [PackageFileName]');
Exit;
end;

FileName := ParamStr(1);

if not FileExists(FileName) then
begin
WriteLn(Format('File %s does not exist.', [FileName]));
Exit;
end;

Package := TPackage.Create;

try
if Package.LoadFromFile(FileName) then
begin
if Package.NeverBuild then
WriteLn('Never Build');

if Package.DesignOnly then
WriteLn('Design Only');

if Package.RunOnly then
WriteLn('Run Only');

case Package.Producer of
ppOld: WriteLn('Old Producer');
ppUndefined: WriteLn('Undefined Producer');
ppBCB: WriteLn('BCB Producer');
ppDelphi: WriteLn('Delphi Producer');
end;

case Package.Consumer of
pcCompat: WriteLn('Compat Consumer');
pcBCB: WriteLn('BCB Consumer');
pcDelphi: WriteLn('Delphi Consumer');
end;

if Package.RequiresList.Count > 0 then
begin
WriteLn(#13#10 + 'Requires List:');
WriteStrings(Package.RequiresList);
end;

if Package.ImplicitUnits.Count > 0 then
begin
WriteLn(#13#10 + 'Implicit Uses:');
WriteStrings(Package.ImplicitUnits);
end;

if Package.ContainsList.Count > 0 then
begin
WriteLn(#13#10 + 'Contains List:');
WriteStrings(Package.ContainsList);
end;
end;
finally
Package.Free;
end;
end.

Thursday, December 20, 2007

Reading Info From a Package Part III

This week became package week. I posed part I here and part II here for reading the information contained within a package. Today I'll continue to grow the program and add the ability to read the remaining information contained in the Flags which is is what language built the package and which language the package is designed for. So there you have it, a small utility that can read the information contained in a package.


program pdump;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes;

var
RequiresList: TStrings;
ImplicitUnits: TStrings;
ContainsList: TStrings;

procedure PackageInfoProc(const Name: string;
NameType: TNameType; Flags: Byte;
Param: Pointer);
begin
if NameType = ntContainsUnit then
begin
ContainsList.Add(Name);

if (Flags and $10 <> 0) and (Flags and $06 = 0) then
ImplicitUnits.Add(Name);
end
else if NameType = ntRequiresPackage then
RequiresList.Add(Name);
end;

procedure WriteStrings(Strings: TStrings);
var
Index: Integer;
begin
for Index := 0 to Strings.Count - 1 do
WriteLn(Strings[Index]);
end;

type
TPackageProducer = (ppOld, ppUndefined, ppBCB, ppDelphi);
TPackageConsumer = (pcCompat, pcDelphi, pcBCB);

var
Module: HMODULE;
Flags: Longint;
Producer: TPackageProducer;
Consumer: TPackageConsumer;
begin
RequiresList := TStringList.Create;
ImplicitUnits := TStringList.Create;
ContainsList := TStringList.Create;

Module := LoadPackage(ParamStr(1));

try
if Module <> 0 then
begin
GetPackageInfo(Module, nil, Flags, PackageInfoProc);

if (Flags and pfNeverBuild) <> 0 then
WriteLn('Never Build');

if (Flags and pfDesignOnly) <> 0 then
WriteLn('Design Only');

if (Flags and pfRunOnly) <> 0 then
WriteLn('Run Only');

case Flags and pfProducerMask of
pfV3Produced: Producer := ppOld;
pfProducerUndefined: Producer := ppUndefined;
pfBCB4Produced: Producer := ppBCB;
pfDelphi4Produced: Producer := ppDelphi;
else
Producer := ppUndefined;
end;

case Producer of
ppOld: WriteLn('Old Producer');
ppUndefined: WriteLn('Undefined Producer');
ppBCB: WriteLn('BCB Producer');
ppDelphi: WriteLn('Delphi Producer');
end;

case Flags and pfConsumerMask of
pfConsumerDelphi: Consumer := pcDelphi;
pfConsumerBCB: Consumer := pcBCB;
else
if Producer <> ppBCB then
Consumer := pcCompat
else
Consumer := pcBCB;
end;

case Consumer of
pcCompat: WriteLn('Compat Consumer');
pcBCB: WriteLn('BCB Consumer');
pcDelphi: WriteLn('Delphi Consumer');
end;

WriteLn('Requires List');
WriteStrings(RequiresList);
WriteLn(#13#10 + 'Implicit Uses');
WriteStrings(ImplicitUnits);
WriteLn(#13#10 + 'Contains List');
WriteStrings(ContainsList);
end;
finally
UnloadPackage(Module);
RequiresList.Free;
ImplicitUnits.Free;
ContainsList.Free;
end;
end.

Wednesday, December 19, 2007

Reading Info From a Package Part II

Yesterday I posted a small program to read some information from a Package. There is more information to get from the package, so here is and updated version with a bit of information you get get from the Flags. Specifically Never Build, Design Only and Run Only.


program pdump;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes;

var
RequiresList: TStrings;
ImplicitUnits: TStrings;
ContainsList: TStrings;

procedure PackageInfoProc(const Name: string;
NameType: TNameType; Flags: Byte;
Param: Pointer);
begin
if NameType = ntContainsUnit then
begin
ContainsList.Add(Name);

if (Flags and $10 <> 0) and (Flags and $06 = 0) then
ImplicitUnits.Add(Name);
end
else if NameType = ntRequiresPackage then
RequiresList.Add(Name);
end;

procedure WriteStrings(Strings: TStrings);
var
Index: Integer;
begin
for Index := 0 to Strings.Count - 1 do
WriteLn(Strings[Index]);
end;

var
Module: HMODULE;
Flags: Longint;
begin
RequiresList := TStringList.Create;
ImplicitUnits := TStringList.Create;
ContainsList := TStringList.Create;

Module := LoadPackage(ParamStr(1));

try
if Module <> 0 then
begin
GetPackageInfo(Module, nil, Flags, PackageInfoProc);

if (Flags and pfNeverBuild) <> 0 then
WriteLn('Never Build');

if (Flags and pfDesignOnly) <> 0 then
WriteLn('Design Only');

if (Flags and pfRunOnly) <> 0 then
WriteLn('Run Only');

WriteLn('Requires List');
WriteStrings(RequiresList);
WriteLn(#13#10 + 'Implicit Uses');
WriteStrings(ImplicitUnits);
WriteLn(#13#10 + 'Contains List');
WriteStrings(ContainsList);
end;
finally
UnloadPackage(Module);
RequiresList.Free;
ImplicitUnits.Free;
ContainsList.Free;
end;
end.

Tuesday, December 18, 2007

Reading Info From a Package

If you've ever wanted to find out what packages a package depends on (without using tdump.exe), or implicit units a package has or the units the package contains, then take a look at the code below.


program pdump;

{$APPTYPE CONSOLE}

uses
SysUtils,
Classes;

var
RequiresList: TStrings;
ImplicitUnits: TStrings;
ContainsList: TStrings;

procedure PackageInfoProc(const Name: string;
NameType: TNameType; Flags: Byte;
Param: Pointer);
begin
if NameType = ntContainsUnit then
begin
ContainsList.Add(Name);

if (Flags and $10 <> 0) and (Flags and $06 = 0) then
ImplicitUnits.Add(Name);
end
else if NameType = ntRequiresPackage then
RequiresList.Add(Name);
end;

procedure WriteStrings(Strings: TStrings);
var
Index: Integer;
begin
for Index := 0 to Strings.Count - 1 do
WriteLn(Strings[Index]);
end;

var
Module: HMODULE;
Flags: Longint;
begin
RequiresList := TStringList.Create;
ImplicitUnits := TStringList.Create;
ContainsList := TStringList.Create;

Module := LoadPackage(ParamStr(1));

try
if Module <> 0 then
begin
GetPackageInfo(Module, nil, Flags, PackageInfoProc);

WriteLn('Requires List');
WriteStrings(RequiresList);
WriteLn(#13#10 + 'Implicit Uses');
WriteStrings(ImplicitUnits);
WriteLn(#13#10 + 'Contains List');
WriteStrings(ContainsList);
end;
finally
UnloadPackage(Module);
RequiresList.Free;
ImplicitUnits.Free;
ContainsList.Free;
end;
end.

RAD Studio 2007 Update

RAD Studio 2007 is live on the website. Problem is the website appears to be experiencing technical difficulties.

Friday, December 14, 2007

Sysinternals


A while back I listed the tools that I use and then listed the tools that readers use. Of all the tools listed, only one was from Sysinternals. But in reality I actually use many more when the need arises.

"The Sysinternals web site was created in 1996 by Mark Russinovich and Bryce Cogswell to host their advanced system utilities and technical information. Microsoft acquired Sysinternals in July, 2006. Whether you’re an IT Pro or a developer, you’ll find Sysinternals utilities to help you manage, troubleshoot and diagnose your Windows systems and applications. If you have a question about a tool or how to use them, please visit the Sysinternals Forum for answers and help from other users and our moderators."

The tools available at Sysinternals are some of the most useful tools available for developers and they've only gotten better since being acquired by Microsoft. Check out Mark Russinovich blog for some interesting low level reading.

Friday, December 7, 2007

Suggestion Box

Welcome to the Chris Bensen blog suggestion box. Post suggestions for future topics here in the comments. The comments will be read and emptied periodically so don't be surprised if your suggestions vanishes. Suggestions are just that suggestions and I am under no obligation to accept any suggestion.

Since this is a blog focused on things I'm interested in keep the suggestions along those lines:

Delphi programming.
Programming topics.
My personal hobbies.
Issues of general interest.

Keep your suggestion short and to the point.

You can always find a link back here from the sidebar on the right.

Buying A Car

The Missus and I just bought a new car today from CarsDirect and it was the best car buying experience I have ever had. If you are buying a car seriously consider going through these guys. I had a great experience and imagine you would too.

YouTube needs Parental Ratings

My daughter loves kitty cats. When we go on walks around the neighborhood she looks under everything for them. When she spots one she signs cat and say's "mow mow". She loves my photos of animals too. Any animal is good, but cats are her favorite. She say's she's a cat. One day I searched YouTube for cats and I found the dancing kitty cat below.



In my search, I came across some things that I didn't want her to watch so we don't play that game until I've already had time to view them first. Obviously some sort of parental rating system would be really nice to have at YouTube. Maybe there is something I'm just not aware of.

Friday, November 30, 2007

Upgrading Delphi

Yesterday in the CodeRage II public chat for the vendor reception there were some comments about upgrading from Delphi 6 to Delphi 2007 by Cass McNutt. I think these comments are great because we need to make sure Delphi is as easy as possible to upgrade. I love constructive feedback like this.

First you have to understand how I use Delphi on a daily basis is completely different than how you use it. We develop Delphi in Delphi. Our version control system contains nearly every line of code that goes into the product. So for me upgrading between versions isn't as much of an issue. Plus there is an entire team of Delphi developers to help out. So I'm trying to put myself in your shoes here.

The main piece of the puzzle you depend on is the IDE, compiler, RTL and VCL. If these change you need to change your code. That's why backwards compatibility of the compiler, RTL and VCL are so important. If something breaks your code you may choose to stick with the current version.

My perception is that 3rd party components and IDE plugins are your biggest concern. If a 3rd party component doesn't support the latest version and the source isn't available you might choose to continue using the current version. This is the same problem when upgrading any complex system such as an OS. This is the same reason I'm not upgrading my Mac at home to Leopard.

My understanding is that there are a lot of developers still on Delphi 7 or earlier. There are many reasons such as the help, IDE performance, IDE requiring .NET, component palette changes, installer, and SDI IDE.

A smaller but equally important upgrading issue seems to be user preferences such editor colors. I think the installer should be able to detect a previous install and migrate appropriate settings to the new install if desired.

So am I missing any other concerns or pitfalls about upgrading Delphi?

Update: I find it interesting and worthy of a note that today in borland.public.delphi.non-technical there is a post titled "Upgrading a program from Delphi 6 to 2007 - What's nessicary". Obviously this is a common problem.

Update: I changed some of the wording above. It was pointed out that I was insinuating that you shouldn't upgrade Delphi. This is not the case and if anyone reads this into my comment above you are reading a sentence out of context. I am simply trying to put myself in the Delphi customer's shoes. So, some rewording has been done to be more neutral.

Thursday, November 29, 2007

Epson Printer Compatibility with Leopard

A while back I talked about why I'm not upgrading to Leopard just yet and one of the big road blocks for me is the lack of printer support. Epson announced today via a FAQ that can be read here that they will be releasing a driver for most of the Epson professional printers including my Epson 4800. You can download a beta of the driver here. That's great news but I have a few friends that have the very expensive Epson 7600 that will not get an updated driver. I'm surprised at Epson considering how much one of these printers cost. I'll think twice the next time I recommend an Epson printer to anyone. Considering the fact that I've had two Epson 2200 printers die and my 4800 has firewire problems I'll think twice about buying another Epson myself. I continue hear great things about the latest generation of HP and Canon printers.