Showing posts with label Delphi. Show all posts
Showing posts with label Delphi. Show all posts

Tuesday, October 14, 2008

Restoring missing Build Events in Delphi 2007

If you have a Delphi 2007 project that was ported from Delphi 2006, then you may be missing the build event project options.  The .dproj file that Delphi 2006 creates is does not have a final XML element named PropertyGroup that Delphi 2007 uses.  Without that final PropertyGroup, Delphi 2007 will not enable Build Events as an option.  If you manually edit your .dproj file, just the following lines:

<PropertyGroup>
</PropertyGroup>


So that the .dproj files looks like this at the end of the file:



<PropertyGroup>
</PropertyGroup>
</Project>


After making that change, the next time you open that project with Delphi 2007 and select Options from the Project menu, you’ll see Build Events listed.  This only appears to happen if you migrate a Delphi 2006 project over to Delphi 2007.  If you create the project from scratch, you’ll see Build Events list.  That’s how I was able to determine what was missing, I just created a new project and compared the .dproj files.

Thursday, August 21, 2008

Refreshing a SOAP WSDL import file with Delphi

I’m consuming a web service from a Delphi desktop app and both the web service and the desktop app are being developed at the same time.   Because the WSDL generated by the web service can change, I need to refresh the service interface code that the Delphi code uses to access the web service.  It corresponds to the web references class that a .NET app would use to consume a web service.

You typically create the web service interface code by bringing up the WSDL Import Wizard from the File->New->Other menu in Delphi.  You get a dialog that prompts you for the location of the WSDL file or URL.  From the WSDL, it generates a unit with interfaces defined for the classes and objects exposed by the web service.  It creates the file with the name of the service, plus “.pas”.

It works pretty well, but if you need to refresh that file due to changes in the web service, you don’t need to use that wizard to update the file.  There is a command line tool that will generate a new output file from a specificied WSDL.  This tool is named WSDLImp.exe, and is located in the bin folder of your Delphi installation.

The typical syntax is

WSDLImp.exe -P http://localhost/somefolder/someservice.asmx?WSDL




That will generate a file named someservice.pas.  If you want to specify a different name for the file, you can use the “-=” command line parameter like this"





WSDLImp.exe -P -= http://localhost/somefolder/someservice.asmx?WSDL=myservice.pas




That will create the file myservice.pas.  Very handy if you want to use a different name than the default.  Now when you update the service interface, you can just run WSDLImp to reimport the web service interface.

Wednesday, August 13, 2008

Using Delphi in a team

I was just reading

Thursday, August 07, 2008

How to log the TIDSmtp component

I have some Delphi code that needs to send a quick mail message so I was using the Indy 10 TIdSmtp component.  The code was working just fine for a few months, but this week it would fail with an EIdSMTPReplyError exception.  The message property of the exception was a empty string, not terribly useful.  After a bit of googling, I found references to using one of the Indy TIdLogXXXX components.  Sure enough, there is a TIdLogFile component that will log messages to a file.  That sounded like what I needed, but the help file did not make it clear on how to hook up a TIdLogFile to a TIdSmtp component.

I did some searching and found a blog post by Marshall Fryman on his Ruminated Rumblings blog that a great example of how to hook up one of the Indy logging components.  What I needed to do was to create an instance of the TIdSmtp’s IOHandler property and assign the TIdLogFile to the IOHandler.Intercept property.  He also recommended assigning the IOHandler.OnStatus event to TIdLogFile.OnStatus event

The way my code ended up was something like this:

      try
        try
          IdLogFile.Active := true;
          fsmtp.IOHandler := TIdIOHandler.MakeDefaultIOHandler(fsmtp);
          fsmtp.IOHandler.Intercept := IdLogFile;
          fsmtp.IOHandler.OnStatus  := fsmtp.OnStatus;
          fSMTP.Connect;
          fSMTP.Send(fMessage);
        except
          on e: exception do begin
            MessageDlg('Error sending message: ' + e.Message, mtError, [mbOK], 0);
          end;
        end;
      finally
        if fSMTP.Connected then
          fSMTP.Disconnect(true);
        IdLogFile.Active := false;
      end;

Tuesday, July 29, 2008

Delphi Win32 gets a TStringBuilder class

The next version of Delphi, code named “Tiburon”, is getting some cool new features.  One of these will be the TStringBuilder class and Andreano Lanusse (a CodeGeart Evangelist Leader) blogged about it.  Basically, it’s a Delphi implementation of the .NET StringBuilder class.  Only it’s available in the managed and unmanaged versions of Tiburon.  Why is this cool?  If you have code that does a lot of string manipulation, using the string class gets expensive, performance-wise.  If you are building up a string piece by piece, each time you add or modify a string, the previous version of the string is discarded and a new string is created.

The StringBuilder class pre-allocates the memory so that you avoid the constant creating and freeing up of string objects.  If you have code running in aloop, you can get real performance benefits by using StringBuilder.  I’m looking forward to getting Tiburon when it’s released.

Friday, July 25, 2008

How to shoot yourself in the foot with regular expressions

I had some Delphi code that is used a user entered text string as a key. After the user entered in the text, my code would force it to uppercase and strip out any characters outside of A-Z and 0-9. This was for a very specialized task and the following Delphi code did the job.

function GetStrippedValue(const value: string): string;
var
i: integer;
begin
result := '';

// strip punctuation out of the name and force to uppercase
for i := 1 to length(value) do
if value[i] in ['A'..'Z', 'a'..'z', '0'..'9'] then
result := result + Uppercase(value[i]);
end;

Nothing elegant, and performance wasn’t an issue as it was rarely used. I wrote that code in the spring of 2000 and it hasn’t been touched much since then. I now have a C# application that needs to work with the same data, so I to perform the same functionality using C#. Since C# does not have the set operators that Delphi has, I had to strip out the characters in a different way. I figured that I could use a simple regular expression and match the characters that way. I should have remembered that old quote attributed to Jamie Zawinski:


Some people, when confronted with a problem, think “I know, I'll use regular expressions.”

Now they have two problems.

I had decided to make the expression as simple as possible. I used the following function to accomplish what I had done years earlier in Delphi:

private string GetStrippedValue(string value)
{
string pattern = @"[^\w]";

string result = Regex.Replace(value.Trim().ToUpper(), pattern, "");

return result;
}
What I am doing here is to replace any text that matches the Regex expression with an empty string. The “^” caret character negates the expression, in other words replace anything that doesn’t match the “\w” token with an empty string. I had found the “\w” documented to match any non-word character, but I didn’t look too closely to the definition. I was using the syntax defined at www.regular-expressions.info, where it is documented which matches letters ,digits and whitespace. That turned out to be different from the definition used by .NET and Python.

With .NET, that pattern allows alphanumeric characters, PLUS the ”_” underscore character. A slight, but fatal flaw on my part. I didn’t catch it when I wrote because my sample data didn’t have any underscores in them. I found it today while adapting that code for a new task, where the data can have underscores.

Einstein put it best, “Everything should be made as simple as possible, but not simpler.”. My attempt to write the least amount of code was flawed. What I should have done was to use the following syntax:
private string GetStrippedValue(string value)
{
string pattern = @"(?i)[^A-Z0-9]";

string result = Regex.Replace(value.Trim().ToUpper(), pattern, "");

return result;
}
This way, I am explicitly defining the allowable characters and now I’m getting the results that I wanted. Since I am passing in a string that is being forced to uppercase, I don’t need to test for lowercase letters (“a-z”). An alternative version that produces the same results would be:
private string GetStrippedValue(string value)
{
string pattern = @"[^A-Z0-9]";

string result = Regex.Replace(value.Trim().ToUpper(), pattern, "",System.Text.RegularExpressions.RegexOptions.IgnoreCase);

return result;
}
I’m not sure if one way is better than the other. The “(?i)” is equivalent to the System.Text.RegularExpressions.RegexOptions.IgnoreCase RegexOption. For this project the performance of the code is not an issue, it only gets called a few times.

The moral of this story is if you need to use regular expressions, check the syntax for the implementation that you are using.

Tuesday, July 08, 2008

Still time to enter the Darwin Race of Languages

Do you think that hand tweaked C code runs circles around managed code (C#, Java, VB.NET)?  Or do you think that your Just In Time compiled managed code gets the job done more securely than those bit sniffing dinosaurs?  Anxious to prove that Delphi is still relevant?  Want to win some cutting edge component libraries from DevExpress?

If you answered “yes” to any of those questions, there is still time to enter the Darwin Race of Languages.  The brainchild of Sevensteps CTO Bart Roozendaal, the Darwin Race is pitting a slate of challengers using the compiler and IDE of their choice to write a utility that will solve one of three problems.  The projects are the following:

  • Temperatures and CPU load
    A utility that will measure CPU temperatures and CPU load on remote computers
  • Multi clipboard utility
    The utility should hold several entries that were place on the clipboard earlier. In effect it should replace the clipboard.
  • GUI to a command line program
    A GUI front end for the gbak database command line driven program for the Firebird database.

Each entry will be judged on the software itself and how you documented the design and development of the application.  The goal is not to see which development is best tool, but to see what tools are the best for different types of jobs.  To see where the strengths are and where are the weaknesses of each tool, using real world types of the problems.  The documentation part will share the development process and show how different people come up with solutions for similar problems.

There are already a bunch of sponsors lined up.  DevExpress will be giving away a a license for DXperience Enterprise or the VCL Subscription.  If you wint, you get to pick one of them.  I have DXperience and most of the VCL components, you can’t go wrong with either one of them.

The race is on already, but there is still time to join.  There are a bunch of participants already signed up, covering C#, Delphi, VB, and something on the Mac platform.  Java is not yet represented, does someone out there want to pick up the Java gauntlet?

Monday, June 30, 2008

Fix for endless registration loop with Delphi 2006

With the acquisition, our login accounts are being migrated to a new domain.  We are doing this in multiple parts, with the first part changing our existing domain logins from using our last name plus first initial (millerc) to what is referred as the User Principal Name (basically our email addresses).  Of course, when I say “we”, I refer to our IT manager.  I’m just along for the ride and to make witty comments when it breaks.  That part went smoothly, the second step occurred last Sunday night when said IT Manager changed our logins (pre Windows 2000 format) from last name plus first initial to last name “.” first name (chris.miller).

When we logged in this morning and started up Borland Developer Studio 2006 (aka Delphi 2006), something broke.  We would get errors like



The license manager reported the following error:

License storage c:\documents and settings\millerc\.borland\borlands.lic does not apply to current user or host machine.


Please register your Borland products(s).(7006).



Do you want to run the registration wizard?



or



Fatal error validating license for Borland Developer Studio 2006

The license manager reported the following error:


Missing activation file.  Please register again. (7029).



Do you want to run the registration wizard?



Just what I wanted to see first thing on a Monday morning.  Thank you, sir. May I have another?



Each time we would run the registration wizard, we would go through all of the steps to register Delphi and it would report that it was successfully registered.  After closing the wizard, we would get the same error message again.  Not a good sign.



I ran the registration wizard one more time and selected register by phone and called the number for US support.  The support representative was friendly but had no clue for what was happening.  The only thing she could was to open a support case.  I tried a few more times after completing the call and found out that you could only register 10 times, after that your registration code has been used up.  I was somewhat less than thrilled when I found that little gem.



After four hours had passed, I decided to call that support number again.  The support representative that answered this time was much more helpful.  He immediately contacted a support engineer, who knew what the problem was and referred to it as “an endless registration loop”.  They emailed me a list of instructions and I was able to get Delphi 2006 up and running again.  He also updated my account to accept two more registrations.



The funny part for me was that I had migrated all of my projects to Delphi 2007, which was not affected by the change in user id’s.  I jumped in to help out the other developement team, who were still on Delphi 2006. 



The following is a slightly edited version of the steps that CodeGear support had sent to me.




Sometimes the registration information on a machine can become corrupted and cause an endless registration loop. This also happens when the user login name is changed or if a machine is changed to log in to a Domain. The following steps should help to resolve the problem.



WARNING: These step will remove registration information for other Borland IDE products as well.




  1. Close down Delphi and the Registration Wizard if they are running


  2. Browse to the .borland directory in your user home directory. For Windows 2000 and XP this will be located at c:\documents and Settings\<username>\.borland


  3. Open the file registry.dat and copy the SerialNumber and AuthorizationKey values stored under "[Delphi 2006]", this save you the step of trying to remember where you had stored that information. Also make a note of either the UserName or EmailAddress values stored under "user". You will need these values when you register Delphi.


  4. Delete the borland.lic and registry.dat files in the .borland directory. You may also want to move those files to another location that is not on the path


  5. Remove the .<Random#A> directories from your User Home (directory name will start with a . and contain 6 or 7 random numbers and letters)


  6. Remove the .<Random#>.slip files from your User Home file name will start with a . and contain 6 or 7 random numbers followed by .slip)


  7. Remove any activation files that you saved in your User Home. These will by default be in the format of reg*.txt


  8. Launch BDS 2006 which will activate the Registration Wizard.


  9. Cancel completely out of the Registration Wizard (This is an important step and will write new correct default information to your User Home).


  10. Launch BDS 2006 a second time and this time register the product when the Registration Wizard comes up.


  11. If you ran the registration wizard too many times, your serial number will get locked out. You are limited to 10 installations. If you exceed this count, you will need to call CodeGear (800-523-7070 for the US) and asked for that count to be raised. They can raise the count limit by two each time that you request it.




This worked for me, but the usual YMMV caveats apply.  I added steps 3 and 11.  Once you delete the registry.dat file, you will have deleted the cached copy of your serial number and authorization key.  By making a copy of them, it becomes one less this to have to lookup.  If you already have Delphi 2007 or RAD Studio 2007 installed, these steps will not affect them.

Thursday, June 26, 2008

A new user to Delphi reports on his annoyances

Branden Tanga posted a list of annoyances with Delphi on his blog.  While there are some legitimate complaints you can make about Delphi (the borked help system), his complaints largely stem from being unfamiliar with the IDE. I’m going to paraphrase his complaints to just list the gist of complaint and my responses.  Other people have commented on his complaints, but I did want to note that his first one has some value.

  • “Can’t indent a block of text”  You can indent by pressing Shift+CTRL+i and unindent with Shift+Ctrl+u.  You would never know by looking the IDE.  Those actions could have been listed on the “Edit” menu.  I searched the help and could not find it.  If you are new to Delphi, there is no way you would have know how to do this with asking someone.  I had to go back the Delphi 7 help system and search on “Block commands”.  I hope that Nick Hodges is following this.  And there is a free plugin named DDevExtensions that (among other things) will give you the ability to use the Tab/Shift+Tab for indent/unindent.
  • “Weird bug where RAD will crash”  Hmm, can’t say much without knowing what he was trying to do at the time.  The obvious question is did he have all of the updates and hotfixes installed?
  • “If you launch your application from within RAD, it must be managed within RAD”  That’s because you are running it from within the debugger.  And you can stop it from the debugger.
  • “You have to pay 3rd parties for extra widgets. That makes absolutely no sense to me. Visual Studio and the Windows API provide me all the widgets I could want….Delphi developers like to make their own widgets and sell them to each other.”  That one made me stop and say “Huh?”  Out of the box, you get more components with Delphi than with VS.  Delphi has Project JEDI and their huge library of controls and other functionality.  There is nothing quite like that in the Microsoft ecosystem.   Is Branden aware of the huge market of 3rd party components for Visual Studio Telerik, DevExpress, Infragistics, etc)?  I just don’t see how he came up this complaint.
  • “There is no free version of CodeGear RAD”  Actually there is a version, it’s called Turbo Delphi.  It’s not the current version of Delphi (Delphi 2006 based), but it’s current enough to introduce you to the product.  I hope that the new owner of Delphi, Embarcadero, will release new versions of the Turbo line.  it’s fine line that they will need to walk.  Having the Turbo Editions allow people to get a taste for Delphi without having a large expense, but they don’t want to take away from sales of the full product.  it is a commercial product, sales revenues pay for the continued development of the tool.
  • “You can only write Delphi code using RAD, which costs money to own.”  That’s negated my previous comment about Turbo Delphi.  The whole idea of doing application development with Delphi is that it’s a RAD tool.  Why would you want to do app development with notepad anyway?
  • ”There are properties and objects that are COMPLETELY HIDDEN from the developer, and the only way to access them is through RAD's wysiwyg editor.”  The visual properties and objects are stored in the .dfm files, which are text based.  If you embed graphics into a component, the image will be streamed as series of hex values, but you would get the same type of stream with images embedded in .NET components.

Out of all of those complaints, only the one with any value is the blocking indenting issue.  And that’s a help/documentation issue as Delphi has a full set of block commands, they just are not documented anymore.  I work in both VS 2008 and Delphi 2007, they both have their strengths and they both have their weaknesses.  I am curious about how much time Branden spent with Delphi before composing his list.

Tuesday, June 24, 2008

Good help (Delphi programmers) is hard to find

I was just reading a post on Bart Roozendaal's Sevensteps blog titled "Are Delphi programmersa dying breed?".  The title pretty much sums up Bart's point, it's getting harder and harder hire programmers with Delphi experience.  It took a long time for us to find our last two Delphi hires.  Here in Albany, we never had a huge talent pool to pick from, and these days you just can't find the Delphi talent.

Whenever I posted for open positions on the Borland jobs newsgroup, the only responses were from outsourcing companies.  That was something we just didn't want to pursue.  The domain knowledge in getting up to speed with our products can be a little steep, we prefer to keep that knowledge in house and make a long term investment in our development staff.

So where did they all go?  At my last place of employment (nearly 9 years ago), I was on a team of 7 programmers, all using Delphi.  Right after I was hired, we bought by a company that had no use for Delphi and decided that we would be the Java team (minus the tools and the training).  To make a short story long, within 6 months the team all departed to other local companies.  Of that group, I'm the only one still using Delphi.  And I'm not even full time Delphi, it's 50% Delphi and 50% C# (and the Delphi percentage is trending down).

For the other 6, two of them went the Java route, just not at that company.  Another went back to his AS/400 and DB2 roots, the rest bounced around with VB and ASP and eventually ended up in .NET.  I'm betting that's happening to a lot of the Delphi programmers.  A lot of the work out there is for web based applications.  For that market, the Microsoft stack is much stronger than the web based development tools that Delphi provides.

This has to be hitting the companies that still do desktop applications with Delphi pretty hard.  I still think that Delphi is a better choice for desktop applications and services than .NET.  The problem is finding people that still want to work with Delphi.  We are fully staffed now, but it too a long time to get the last two.

Is anyone taking up Delphi anymore?  if you are a fresh new programmer, Delphi probably isn't going to be something you will take up on your own.  I don't know how Embarcadero is going to deal with this.  They just bought a powerful development tool in Delphi, but will they get people to take it up?  Without fresh blood coming in, the Delphi talent pool is going to continue to shrink.

Tuesday, June 17, 2008

Migrating Delphi versions with DevExpress

I usually run on the latest version of Delphi while the other Delphi developers in our department run a version or two back.  I’m the pretty much the sole Delphi developer on our .NET projects and I switch between VS 2008 and Delphi 2007 as needed.  The core Delphi team is on Delphi 2006 because of how our product development and testing cycles work.  We don’t switch compiler versions without coordinating with our QA department.

The core team is moving up to Delphi 2007 later this year for the next release cycle.  The current version of the product will stay in Delphi 2006 and the versions of the 3rd party components will be locked.  While development on the next release goes on, we may need to release updates to the current version.  So we lock the 3rd party components so that QA only needs to test the code specific to the update, plus general regression across the application.

With some component vendors, this makes upgrading more challenging.  We use the Developer Express components for Delphi Win32 and for .NET.  DevExpress has wonderful components, but they use monolithic installers that install everything for each compiler per platform.  If I install the latest version of the DevExpress components for Delphi 2007, I’m also going to get the latest version for Delphi 2006.  You can’t install them separately, not without seriously confusing their installer.  Installer technology is scary enough, the last thing you want to is mess areound with the installer.  I wanted something robust, hand tweaking my system to manipulate the installer would be to fragile to have an entire team try it.

After a few emails with DevExpress support, I came with another method.  I wrote a Delphi app that would manually downgrade a DevExpress install for a specific compiler.  You would run this app after running the DevExpress installer and it would rip out the DevExpress current installed bits and replace them with a cached copy of the version that we need to stay at.  It does the following steps:

  1. Check to see if Delphi 2006 is running and stop with a warning message if it’s running.  Here’s how to check to see if Delphi 2006 is running:
    function IsDephi2006Running: boolean;
    var
    handler: THandle;
    data: TProcessEntry32;
    Delphi2006IsRunning: boolean;
    function GetName: string;
    var
    i: byte;
    s: string;
    begin
    result := '';
    i := 0;
    while data.szExeFile[i] <> '' do begin
    result := result + data.szExeFile[i];

    if uppercase(result) = 'BDS.EXE' then begin
    s := uppercase(ProcessFileName(data.th32ProcessID));

    Delphi2006IsRunning := pos('BDS\4.0\BIN\BDS.EXE', s) > 0;
    end;
    inc(i);
    end;
    end;
    begin
    Delphi2006IsRunning := false;
    handler := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);

    if Process32First(handler, data) then begin
    GetName();
    while Process32Next(handler, data) do begin
    if Delphi2006IsRunning then
    break;
    GetName();
    end;
    end;

    result := Delphi2006IsRunning;
    end;




  2. See if the Package Cache key, HKEY_CURRENT_USER\Software\Borland\BDS\4.0\Package Cache, exists in the registry.  If it does rename it.


  3. Deregister the DevExpress components from the IDE. 
    In Delphi 2006, the component packages are registered in HKEY_CURRENT_USER\Software\Borland\BDS\4.0\Known Packages.  The rollback program has a list of list of every DevExpress 5 and 6 package.  My code rips them all out. Before they are removed, their location is cached as this is the folder where the compiled library files are located.  For Delphi 2006, this defaults to “C:\Program Files\Developer Express.VCL\Library\Delphi10”.


  4. Using the location the library folder for the DevExpress compiled units, we delete all of the files in that folder.  If you want to be extra cautious, you could just rename that folder and create a new one with the original name.


  5. Copy the cached copy of the rollback version of the DevExpress compiled units to the library folder.  I keep a clean copy of the library folder in a protected location on our network.  If you need to rollback your DevExpress components, you’ll want to cache those fiels before doing anything else.  You will also need to cache the list of packages to install.


  6. Register the rollback packages into the Known Packages key used in step 3.


  7. Copy the runtime packages to the bin folder.  You can get the location of the bin folder by reading the value of RootDir in HKEY_CURRENT_USER\Software\Borland\BDS\4.0.  I keep a cached set of the runtime packages in the same folder that I keep the cached library files.



This process goes on the assumption that the DevExpress source code is not your Delphi search paths.  We typically leave the source code of the 3rd party components off the search path and just use the compiled units.  You get a faster compile and you don’t have to see other vendors compiler hint and warning messages.  If you want the source code on the search path, the you will need to cache all of the source code files.  At that point, it would be easier to cache the entire “\Program Files\Developer Express.VCL” folder.  And that’s how we upgrade selcted portions of our development environment.

Tuesday, May 06, 2008

Dealing with the Duplicate Resource: Type 24 when enabling theme support in Delphi 2007

I was writing a little utility in Delphi 2007 to make it easy to work with data stored as the XML data type in SQL Server. While I have been using Delphi 2007 since it was released last fall, this was the first desktop app that I had written from scratch. I threw some components up on the form and I did a quick compile to see how the visual elements looked at runtime. I got the following error message:

[DCC Error] E2161 Warning: Duplicate resource: Type 24 (user-defined), ID 1; File C:\dev\RawDataQuery\RawDataQuery.res resource kept; file c:\program files\codegear\rad studio\5.0\lib\WindowsXP.res resource discarded.

I was dragging and dropping components from an app that I had originally written in Delphi 7 and one of the components was a TXPManifest component. The TXPManifest is component that only appears at designtime. When your code is compiled, it includes the WindowsXP.res resource file, which contains the manifest resource needed to enable XP style themes. In Delphi 2007, you can enable theme support in the project options. It's a checkbox labeled "Enable runtime themes" on the Application page of the Project Options dialog.

You can't have both "Enable runtime themes" checked and an instance of TXPManifest in your application. They both try to pull in WindowsXP.res and the second attempt will FAIL. The fix for this is easy. You can disable the "Enable runtime themes" setting or remove the TXPManifest component from your form and remove the reference to xpman in that form's uses clause.

My personal preference is to remove the component and unit references and just use the project setting. When there are two methods of doing the same thing, I tend to pick the simpler solution. The fewer the number of moving parts, the less likely it is for something to break.

Monday, April 07, 2008

Fun with CoInitialize

I was tracking down a error in one of the command line apps that I use to save web.config settings over upgrades.  It was a strange error, If I stepped through the code, everything executed correctly, but I would get an access violation when I left a specific method call.  The fun part was that all of the code in that method call executed normally.  The app is written in Delphi 2007 and is Win32 unmanaged code.  The code looked something like this:

function TSaveConfig.UpdateWebConfig(const srcfile, destfile: string): boolean;
var
fsrcDoc, fDestDoc: IXMLDocument;
begin
CoInitialize(nil);

result := true;

fsrcDoc := LoadXMLDocument(srcFile);
fDestDoc := LoadXMLDocument(DestFile);

UpdateNode(fsrcDoc, fDestDoc, 'configuration\system.web\httpRuntime', 'executionTimeout', '', '');
UpdateNode(fsrcDoc, fDestDoc, 'configuration\system.web\sessionState', 'timeout', '', '');

if fDestdoc.Modified then begin
fDestdoc.SaveToFile(DestFile);
end;

CoUninitialize;
end;



Not much to it.  My Spidey sense started tingling at the calls to CoInitialize/CoUninitialize.  CoInitialize is needed to initialize the COM library on the current thread.  And COM is needed because I am using MS XML COM objects to work with the web.config files.  I was initializing COM, using COM, then uninitializing COM.  The problem was that I was using interfaces to the COM objects and Delphi is managing the lifetime of interfaces.  At the end of the method call, those objects go out of scope and Delphi calls their cleanup code.  In my case this happens after the the call to CoUninitialize.  My IXMLDocument interfaces were being garbage collected by the Delphi runtime and they were referencing a COM library that had been already closed.


In this case, the fix was easy.  I just moved the calls to CoInitialize/CoUninitialize to the code that calls UpdateWebConfig.  Once I did that, my odd little access violation was fixed.  That's one of those bugs that seems obvious after you fix it.  What clued me in to what was going on was a post by Chris Bensen that explained it all.  Thanks Chris!

Friday, March 28, 2008

When will the Visual Studio IDE catchup to the Delphi IDE?

Sometimes it just the little things that annoy you.  If I add a button to a Delphi form, by default it is named Button1.  If I double click on Button1, a Click event handler is added and is named Button1Click and wires it up to the button's OnClick event.  Visual Studio does pretty much the same thing.  Where they is differ is when you edit the button's name.

If I renamed Button1 to something more meaningful like DestroyAllMonsters, the Delphi IDE will rename the event handler to DestroyAllMonstersClick.  When you rename the button in the Visual Studio IDE, it doesn't touch the event handler.  That's annoying.

Another difference is how Delphi handles event handlers when your delete the code or never add the code.  When you double click on the button and get the new event handler automagically created and wired up to the control, that event handler has no code.  If you save that file, Delphi removes the event handler.  it does under the assumption that you didn't mean to have that event handler and it will clean up the code for you.  Like wise, if you delete the code out of the handler and save the file, Delphi will remove the handler. 

This makes it easy to cleanup code when you remove a control that you didn't really want or need any more.  Visual Studio doesn't do that for you, or least not in C#.  When you spend your day working in both IDE's at the same time, those types of annoyances really can be annoying.

Tuesday, March 20, 2007

Notes on installing Delphi 2007

I got the email yesterday from CodeGear. It was a link to download the newly released Delphi 2007. I will be getting the DVD from CodeGear as part of the Software Assurance that I have, but I wanted to try the new installer. This is their first release using installer technology from InstallAware. As it happens, I'm considering switching from Wise For Windows Installer (WFWI) to InstallAware, so it's a good oppourtunity to see their installer in action.

The installer is a minimal (4MB) installer. It grabs the bits that it needs from the Internet from the bits that it needs and the bits that you want. It took a while to download the installer. There were three options, HTTP, FTP, and Galileo. From my office, none of them worked. Once again, our SonicWall firewall has safely protected me from downloading stuff that I need. After a few attempts, I went to Plan B. That was my home PC. I remoted into that box, immediately downloaded the installer without any grief and copied the file back to my office PC.

Once I had the installer, I ran it on my Vista box. The Vista box is my backup PC and I just put Vista in it to test our apps under a hostile environment. The first thing installer did (after I answered "Continue" to the ever present UAC) was to announce that it needed the .NET 2.0 SDK and it was going out to get them. It transferred about 360MB or so of .NET parts and then installed them.

After about 30 minutes or so, I got the "Welcome to the InstallAware Wizard for RAD Studio Setup" page in the setup dialog. Which led to the EULA and registration pages. Oddly enough, it defaulted to "CodeGear" as the company name. Come on folks, that value can be read from the registry. The "Next" button flickered as I typed into each field. I don't know that that's Vista, Windows Installer, or InstallAware. I'm guessing it's Vista's non-support for my ancient NVIDIA TNT2 card that it treats as a standard VGA device.

Then I was prompted for what features to install. I have the Enterprise version, there were many features. It wanted about 1GB and called itself "CodeGear RAD Studio". After one more confirmation prompt, the installer went back to the mothership to download the bits it needed.

It was done after 90 minutes. Now comes the fun part. How many of the Delphi 2006 components will work as advertised?