Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Delphi

Patching me and patching you

4.86/5 (6 votes)
1 Jan 2012CPOL5 min read 21.9K   372  
This will show you how to generate and apply your own patches using Delphi.

Introduction

We've all seen it before: applications updating software and allowing you to 'rollback' your changes. This article will show you how this can be accomplished in Delphi using the Microsoft PatchAPI interface. The main object (discussed later) should work straight off the bat without you needing to add in anything with regards to the patching options.

Background

I've always wanted to create my own installation packages and all that stuff. I think everyone has. I always thought it was this magical thing that just 'happened' and you had to use pre-built installation programs that you need to install in order to build them. This article does not show you how to make a full fledged application installer builder, but it will give you insight into it with regards to creating patches between your old and new file versions. This article will also show you how to use DLL files as well.

Unlike my previous articles, I am not going to show very much code, because I commented the source code quite well (I think).

So what's going on in the code?

This article is a lot more higher level than my earlier articles, but if you have a background in development, you should get the gist of it :). You will notice that there will be two DLLs accompanying the source code, namely mspatcha.dll and mspatchc.dll. You shouldn't need any of these DLLs but I added them for convenience's sake. The former concerns applying the patches while the latter involves creating the patches (more on that later). First things first:

PatchAPI

This file contains the main definition for what the original DLL files actually allow you to do. It defines all the constants, functions, and the actual DLL call definitions to the mentioned DLLs. For more information regarding PatchAPI, please read further here.

uPatcher

This is the wrapper class which I generated in order to take away the strain of generating the patch files and applying said patches. It contains Delphi specific set values, custom events, and even a custom exception class. I did my best to comment as much as I could with this unit, so if anyone would like any other explanations with regard to what is happening, please let me know and I will be happy to assist.

Unit1

This obviously is the main screen of the application. It allows you to add/edit/remove files you want to patch as well as creating/applying patches.

Using the code

The object that you want to use mostly is the TPatcher class. It provides the easiest and most effective way of creating and applying your patch files without needing to work with the PatchAPI class. There are four (custom) events which I created which do the following:

  • TOnPatchProgress: Shows you the progress when you create or apply a patch
  • TOnPatchComplete: Occurs when the patch create or apply is complete
  • TOnPatchFileBegin: Occurs when a file is being patched or created
  • TOnPatchFileEnd: Occurs when the end of a file patch or create is complete

Don't worry, the patcher will work fine if you do not implement these events :). In fact, the patcher will work quite fine without you adding in anything more than just patch files that you have added. For your convenience, I have ensured that I implemented all four of the custom events so you can device your own definitions for them. Theoretically, if you create a patch of a file, the patch can actually go both ways. If I am not mistaken, using this article, you can make a file both the old and the new version just by applying the delta the way you see fit. This is how (I think) any installation application works with regards to applying and rolling back a patch.

As a point of interest, I will demonstrate how one of the custom events are defined and implemented:

Delphi
TOnPatchProgress = procedure(
  ASender : TObject;
  const ACurrentPosition : LongWord;
  const AMaximumPosition : LongWord;
  var ACanContinue : LongBool) of object;

This is the definition for the progress of the creating or patching of a file (obviously). So all you will need to do is create a corresponding definition for the event like this (based on my demo application):

Delphi
procedure TPatcherDemo.DoPatcherProgress(ASender : TObject;
  const ACurrentPosition : LongWord;
  const AMaximumPosition : LongWord;
  var ACanContinue : LongBool);
var
  LStr : string;
begin
  if AMaximumPosition <> ProgressBar1.Max then
    ProgressBar1.Max := AMaximumPosition;
  if ACurrentPosition <> ProgressBar1.Position then
    ProgressBar1.Position := ACurrentPosition;

  LStr := 'Complete: ' + FormatFloat('#,##0', ACurrentPosition) + 
          ' of ' + FormatFloat('#,##0', AMaximumPosition);
  mmo1.Lines.Add(LStr);
  Application.ProcessMessages;
end;

When you step through the program, you will see that it fires each time something happens when the patch is created/applied.

I also introduce the concept of constant type arrays. All that basically means is that based on a type definition, you can create a constant array based on the type that you defined. So based on that, I create string definitions based on the type definitions like this:

type
  TPatchApplyOption = (
    paoFailIfExact, // = APPLY_OPTION_FAIL_IF_EXACT
    paoFailIfClose, // = APPLY_OPTION_FAIL_IF_CLOSE
    paoTestOnly, // = APPLY_OPTION_TEST_ONLY
    paoValidFlags // = APPLY_OPTION_VALID_FLAGS
    );
  TPatchApplyOptions = set of TPatchApplyOption;
const
  Descriptions_TPatchApplyOption : array[Low(TPatchApplyOption)..High(TPatchApplyOption)] of string = (
    'If the source file and the target are the same, return a failure and don'#39't create the target.',
    'If the source file and the target differ by only rebase and bind 
     information (that is, they have the same normalized signature), 
     return a failure and don'#39't create the target.',
    'Don'#39't create the target.',
    'The logical OR of all valid patch apply flags.'
    );

You will see in the demo application how this actually works, but you will find out quick enough where I use it :).

This object also allows you to use different kinds of input options but I only used ANSI (mostly) and Unicode (sometimes). The other option is by handle, which I never tested. So if you feel that you want to use it and find issues, please let me know.

Points of interest

I had a bit of trouble with regards to inserting multiple files into a single patch file. The patcher also allows you to use symbol files and anything that Windows has at its disposal. I just haven't had the chance to implement it all. If anyone wants me to add more functionality to this, please let me know and I will be happy to update this article.

Microsoft (currently) uses two forms of patching interfaces, PatchAPI and MSDelta. The former being from XP down and the latter being from Vista upwards. An issue which I found is, if you read the article regarding patching which I linked at the top of the article, PatchAPI works quite nicely in Delphi 7 (I haven't tried it with the later ones), but MSDelta works quite fine with CBuilder, but apparently they are not interchangeable. I will be posting my CBuilder article regarding MSDelta soon, so keep checking :). If anyone can make suggestions regarding building them into either or both, please let me know.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)