I am kind of biased but I think one of the most useful utilities in the Delphi or C++Builder bin directory is tlibimp.exe. In case you don't know what tlibimp.exe does, it allows you to use COM objects as if they are native interfaces, and .NET objects can be treated as COM objects, so there is a lot of potential here. This is the command line version of the Import Component Wizard, but who wants to use the IDE when we've got command line!
One of the most common problems users of Delphi run into only a few options are available from the IDE. Here is a list of all the options provided by tlibimp:
Borland TLIBIMP Version 11.0
Copyright (c) 1997-2005 Borland Software Corporation
Syntax: TLIBIMP [options]
Files to Generate (Required):
-C- C++ Import file
-P- PASCAL Import file
-Ic- CORBA IDL file
-Ip- PASCAL CORBA stubs & skeletons
Customize code generated:
-Ha+ Create IDE component for Controls
-Hs+ Create IDE component for Servers
-Hr+ Generate component registration
C++ options:
-Cd- Generate dispinterfaces
-Cm- Map disp interfaces to dual
-Cn
-Cs+ declspec(__selectany) for GUIDs
-Ct+ Force the use of a _TLB file
-Cu+ Expose namespace with 'using'
-Cv+ BCB4-style server events
-Cw- Use disp. in Control wrappers
Ignore Flags: -Ya- All special flags,
-Yh- [Hidden]
Debug Build Options:
-G+ Show Debug output
-Gr Read & write out type library
-It
Output File Options:
-D
-Fe
-Ft
-Ce
-Co
-Hpa
-Hps
PASCAL options:
-Ps+ Map dual HRESULT to safecall
-Pt- Map all HRESULT to safecall
MISC options:
-O+ Generate CoClassCreator wrappers
-R+ Process dependent type libraries
-XM- Use MS-style getter/setter
-W+ Emit warnings in files
-Wc+ Emit comments in files
-Yc+ [CanCreate],
-Yp- [Predefined], -Yr- [Restricted]
-Pu Generate Pascal UI file
-Xd+ Generate DispInterfaces
-Yi+ Ignore Standard Type Libraries
That's a lot of options. Some options are obsolete such as the CORBA options but we leave them in case they are being used.
Internally Delphi uses a lot of code generated by tlibimp to communicate to the .NET services such as MSBuild, the .NET designers, and a lot of internal services. The command line we use is:
tlibimp.exe -P+ -Ha- -Hr- -Hs- -R- -D
Wednesday, July 11, 2007
How to Import a Type Library from the Command Line
Posted by
Chris Bensen
at
8:00 AM
3
comments
Tuesday, July 10, 2007
Microsoft Help2 Plugin Feature
There have been a couple of requests for a way to plug third-party help into CodeGear's help. There is actually a very easy way of doing this with the new plug-in feature that Microsoft introduced to the Help2 system in .NET 2.0. All you need to do is register your help to it's own namespace and then there is one line that says plug-in your namespace into ours (borland.bds5). This will make your help show up under our namespace and our IDE will treat it just like it was ours.
If you use h2reg like we do, all you need to add is two lines. For example, if your namespace was called Foo, then add the following line in the "[Reg_Plugin]" section of the ini file:
borland.bds5|_DEFAULT|Foo|_DEFAULT|COL_Master.HxA
The same line goes into the "[UnReg_Plugin]" section.
There is an annoying feature of dexplore.exe (Microsoft's Help2 viewer) that rears its ugly head when you go to register help that you should be aware of. Dexplore doesn't allow you to change any namespace registration while it is running. This wouldn't be a bad thing, except sometimes when you close dexplore, it decides it wants to run in the background without telling you. So check your task manager for it before you change any registration.
If you don't have a registration tool already, you can use our copy of h2reg that we install with our products, but if you do this you cannot redistribute h2reg with your own product. You can buy your own license for $100 dollars.
Posted by
Chris White
at
11:30 AM
0
comments
Labels: Delphi
Guest Bloggers
I have opened up my blog to other CodeGear R&D Engineers. The first guest blogger is Chris White, an R&D Engineer working on the BDS development team at CodeGear. I work closely with Chris White on the Help system.
Posted by
Chris Bensen
at
11:00 AM
1 comments
Delphi Tips And Tricks: Turn Off Code Folding
Every once in a while, like today, I'm working with some very large files (tlibimp generated Office files that are 85,000+ lines if you must know) and the editor is very slow. The first thing I do is narrow the problem down and submit a bug. But at the end of the day I need to get work done like all of you, so I turn off code folding, which brings us to today's Delphi tip. Press CTRL + Shift + K + O and the little icons in the gutter will go away and you'll get back some CPU time. Now this doesn't solve the entire problem, the parser is still being run in the background but the IDE is more usable.
Update: Currently the IDE defaults to a maximum of 10,000 regions. There is a regkey that controls the maximum number of region:
$(HKCU_BDS_ROOT)\Editor\Options
Make a REG_DWORD value called CppMaxStructureRegions and set it to whatever value you want.
Posted by
Chris Bensen
at
10:00 AM
0
comments
Labels: Delphi
Monday, July 9, 2007
More Good Practices When using Version Control
Last week I wrote about only committing one bug fix to the version control system per checkin and to not batch up the changes for later with one large checkin. You can read about it here. Today I want to talk about working on a branch.
When working on a branch, many people batch up their changes and do one huge merge at some later point in time. I don't like to do this. I like to follow a process that lets my brain work on more challenging things, so my process is simple. I fix one bug, check it into the branch I'm working on (as I stated before), then merge that change into the other branch, test it, then commit it to that branch. By doing it this way I complete each task and don't ever think about it again, I reduce human error when performing the merge, and other code that relies on my changes will be easy to merge since all dependencies have already been merged.
Posted by
Chris Bensen
at
12:00 PM
0
comments
Friday, June 29, 2007
Taking a Break this Week

Copyright © 2007 Chris Bensen. All rights reserved.
I will be taking a bit of a break this week to spend with my family. I have updated the photo for this month with a photograph I took at Monterey Bay Aquarium of the Jellyfish. If you ever get a chance to visit Monterey the Monterey Bay Aquarium is a destination worth checking out.
Posted by
Chris Bensen
at
5:00 PM
0
comments
Labels: photo
Good Practices When using Version Control

I have addopted a practice of only committing one bug fix at a time into the version control system (in my case Tortoise SVN). This can take a bit more time but it solves a lot of problems and saves a lot of time later. I find if the code ever needs to be merged it is a lot easier, especially being able to test the bug, merge the code and test that the bug was fixed. If the code ever has problems one can identify exactly what code was changed for a particular bug fix. It is also the cleanest approach because when you checkin your changes you know exactly what you are changing and you won't forget any changes breaking the rest of the team. The trick is human error happens so I like to reduce it when possible.
What practices have you addoped when working with version control systems?
Posted by
Chris Bensen
at
8:00 AM
7
comments
Thursday, June 28, 2007
Plastic in Our Oceans
I came across this video at Patagonia's blog. I really don't have any more to add on the subject that hasn't already been said, I just want to get the information out. So please click here and read the original post "When Plastic is Not So Fantastic".
Posted by
Chris Bensen
at
8:00 AM
0
comments
Wednesday, June 27, 2007
Einstein's Rule Of 72 - Easy Calculation of Compound Interest
The other day I was doing a little bit of investing and needed to do some quick compound interest calculations. As usual when this happened my brain gears came to a halt, but then I remembered something about Einstein and 72 so I looked it up and voila, Einstein's Rule of 72 to calculate compound interest. It is a great little thing to know about and can make you the center of attention at parties.
The rule of 72 says that in order to find the number of years required to double your money at a given interest rate, you can divide the interest rate into 72. For example, if you want to know how long it will take to double your money at twelve percent interest, divide 12 into 72 and get 6 years.
You can also find the interest rate required to double your money in a given number of years. For example, if you want to double your money in nine years, just divide 9 into 72 to find that it will require an interest rate of about 8 percent.
As long as the interest rate is less than twenty percent, the rule of 72 is accurate.
Update: Fix typo in second example when doubling money in nine years.
Posted by
Chris Bensen
at
7:00 AM
4
comments
Tuesday, June 26, 2007
Delphi Tips And Tricks: CoInitialize/CoUninitialize Part III
Previously I talked about using CoInitialize and CoUninitialize in very simple situations, a single threaded console application. If you havn't read those posts you can read Part I here, Part II here and the adendum to Part II here. So for this post I'm going to demonstrate the use of CoInitializeEx and CoUninitialize in a multithreaded environment.
This demo consists of two files, two instances of a thread and a couple loops to give your system enough time to actually allow some processing to happen. Below find the code for this demo:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
MyThread in 'MyThread.pas';
var
Thread1, Thread2: TMyThread;
Success: HResult;
begin
Success := CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
try
Thread1 := TMyThread.Create(False, 'thread1');
Thread2 := TMyThread.Create(False, 'thread2');
try
// Note my implementation could have a
// problem if DoStuff completes too quicly.
DoStuff('main');
Thread1.Wait;
Thread2.Wait;
finally
Thread1.Free;
Thread2.Free;
end;
finally
CoUninit(Success, 'main');
end;
end.
unit MyThread;
interface
uses
Classes, SyncObjs;
type
TMyThread = class(TThread)
private
FLock: TCriticalSection;
FText: string;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; const Text: string);
destructor Destroy; override;
procedure Wait;
end;
procedure CoInitStatus(Success: HResult);
procedure CoUninit(Success: HResult; const Text: string);
procedure DoStuff(const Text: string);
implementation
uses
SysUtils, ActiveX, Windows;
procedure CoInitStatus(Success: HResult);
begin
case Success of
S_OK, S_FALSE: WriteLn('CoInitialize success');
RPC_E_CHANGED_MODE, E_INVALIDARG,
E_OUTOFMEMORY, E_UNEXPECTED: WriteLn('CoInitialize failed');
end;
end;
procedure CoUninit(Success: HResult; const Text: string);
begin
case Success of
S_OK, S_FALSE: CoUninitialize;
end;
end;
procedure DoStuff(const Text: string);
var
Index: Integer;
begin
for Index := 0 to 10000 do
WriteLn(Text + ' ' + IntToStr(Index));
end;
{ TMyThread }
constructor TMyThread.Create(CreateSuspended: Boolean; const Text: string);
begin
FLock := TCriticalSection.Create;
inherited Create(CreateSuspended);
FText := Text;
UniqueString(FText);
end;
destructor TMyThread.Destroy;
begin
FLock.Free;
inherited;
end;
procedure TMyThread.Execute;
var
Success: HResult;
begin
FLock.Acquire;
Success := CoInitializeEx(nil, COINIT_MULTITHREADED);
try
DoStuff(FText);
finally
CoUninit(Success, FText);
FLock.Release;
end;
end;
procedure TMyThread.Wait;
begin
FLock.Acquire;
FLock.Release;
end;
end.
I want to bring your attention to two things. First, notice my use of the return value from CoInitializeEx. And second, the first thread to call CoInitializeEx (located in the main function) is also the last one to call CoUninitialize by use of the the function TMyThread.Wait.
I would talk more about it but I think the code explains everything. So read the source and if you have questions ask.
Update: I have moved the critical section to occur before the constructor to TThread to avoid a race condition and called UniqueString on the string passed to the thread as pointed out by Anders Melander.
Posted by
Chris Bensen
at
8:00 PM
13
comments
Thursday, June 21, 2007
Delphi Tips And Tricks: CoInitialize/CoUninitialize Part IIb
I forgot to mention in Part II that a very simple call stack containing code like this:
CoInitializeEx(nil, COINIT_APARTMENTTHREADED)
CoInitializeEx(nil, COINIT_MULTITHREADED)
CoUninitialize;
CoUninitialize;
will cause one too many calls to CoUninitialize. The second call to CoInitializeEx will return RPC_E_CHANGED_MODE and does not require another call to CoUninitialize because the internal reference counting of CoInitialize didn't increment. The example I provided in Part II demonstrated this but I neglected to mention it specifically.
I just wanted to mention this before I forgot. Next post about CoInitialize will be as requested a multithreaded example.
Posted by
Chris Bensen
at
4:00 PM
0
comments
Photographing At the Zoo

Copyright © 2007 Chris Bensen. All rights reserved.
Last week I took the family to the zoo. Our daughter loves animals and we figured she should see the monkeys in real life and not just stuffed animals and pictures in her books. I figured I'd bring my camera along. I don't typically photograph animals in captivity (it was a hard decision because I don't like seeing the animals in zoos, they don't look very happy and I'd prefer to see them in the wild), but it turns out you can do some pretty good photography at the zoo if you are careful and patient. The one problem is all the man made things like rocks and fences can really get in the way. In the photograph above you can see the fence behind the giraf and the man made rock that the meerkat is standing on below.
Copyright © 2007 Chris Bensen. All rights reserved.
At any rate my wife is a Science Illustrator and she can always use examples of animals to draw so I tried to capture the animals in good poses and ignore the man-mande contraptions. But the important thing is our daughter had a blast!
Posted by
Chris Bensen
at
8:45 AM
3
comments