Showing posts with label Delphi. Show all posts
Showing posts with label Delphi. Show all posts
Saturday, 6 March 2010
TLBs and Delphi
We register the capabilities of Delphi applications using TLB files. However, from reading MSDN documentation, "Installation package authors are strongly advised against using the TypeLib table. Instead, they should register type libraries by using the Registry table". Does anyone have any advice on how to do this in a 'Delphi' way for Windows 7?
Saturday, 27 February 2010
Delphi/Surround/Cruisecontrol.net howto (updated)
This is a further draft of what I had to do to get CruiseControl.Net and Delphi to play nicely - I will fill out further the details later!
This I did using the code from the link above, and changed the base UnitTest program code to look like this:
- Configured IIS in Windows (see here)
- Install CruiseControl.Net 3.5 RC1 (see release notes) - Make sure that the user that the CruiseControl.Net is being run by is able to see and use Delphi (i.e. probably not by default)
- Install CCTray
- Set the BDS environment setting to point to where Delphi lives (this may have been done when Delphi was installed)
- Create a definitions.xml file that has all of the required defaults, for accessing Surround, MSBuild, etc.
- Create a project to test. It is difficult to post a real example, as this is code that my company owns, rather than me, but an example could be pulled out and added to this article.
- Setup connection to Seapine Surround. I had a real problem with using Delphi and Surround, as by default the code is checked out as readonly, and Delphi needs to write to the working directory (especially when building typelibraries, etc). I have not spent too much time fiddling with it as I have a patch for the CruiseControl.NET source.
- Setup the MSBuild section to build the application (in the definitions.xml file)
- Setup the configuration to be managed by CruiseControl.NET and Surround, so that the files can be just checked out, modified and then checked in again - this avoids having to access the server machine.
- Each developer now gets emailed whenever a build fails, and we can see the running of tests as well, after each build, see below.
- Modify the DUnit tests to output XML.
This I did using the code from the link above, and changed the base UnitTest program code to look like this:
Other things I have done ...
var
res : TTestResult;
...
if IsConsole then
if ParamCount <> 0 then
if (copy(ParamStr(1), 0, 5) = '/xml=') then
res := XMLTestRunner.RunRegisteredTests(copy(ParamStr(1), 6, length(ParamStr(1)) -5))
else
res := TextTestRunner.RunRegisteredTests
else
res := TextTestRunner.RunRegisteredTests
else
GUITestRunner.RunRegisteredTests;
if (res.ErrorCount <> 0) then
halt (1);
- Modify (legally I'm not sure if I can publish it) the code from Run-Time Systems Cyclomatic Complexity Calculator for Delphi so that it outputs the results as an XML file - it actually does this already internally, but doesn't write the results out.
- Create a task to generate developer documentation using doc-o-matic as a task.
Saturday, 2 January 2010
Sunday, 6 September 2009
Thursday, 16 April 2009
Getting testing working
OK, so I have the source checked out, and then I have built it. I even have a test application, that outputs XML. However, we have a graphical login. So I need to be able to pass in the signon somehow. OK, so I need to think a bit more about this.
Tuesday, 7 April 2009
Cruisecontrol.net howto (draft)
This is a draft of what I had to do to get CruiseControl.Net and Delphi to play nicely - I will fill out the details later!
1. Install Apache 2.
2. Install Mod_ASPDotNet.
3. Install CruiseControl.Net.
4. Install CCTray.
5. Create a project to test.
7. Setup connection to Seapine Surround.
8. Setup the MSBuild section to build the application.
9. Modify the DUnit tests to output XML.
This I did using the entry above, and changed the base UnitTest program code to look like this:
More later!
1. Install Apache 2.
2. Install Mod_ASPDotNet.
3. Install CruiseControl.Net.
4. Install CCTray.
5. Create a project to test.
7. Setup connection to Seapine Surround.
8. Setup the MSBuild section to build the application.
9. Modify the DUnit tests to output XML.
This I did using the entry above, and changed the base UnitTest program code to look like this:
var
res : TTestResult;
...
if IsConsole then
if ParamCount <> 0 then
if (copy(ParamStr(1), 0, 5) = '/xml=') then
res := XMLTestRunner.RunRegisteredTests(copy(ParamStr(1), 6, length(ParamStr(1)) -5))
else
res := TextTestRunner.RunRegisteredTests
else
res := TextTestRunner.RunRegisteredTests
else
GUITestRunner.RunRegisteredTests;
if (res.ErrorCount <> 0) then
halt (1);
More later!
Monday, 6 April 2009
CI Update
Well, after much messing about I now have CI working for Delphi. It checks out the code from Surround (easy to configure), calls MSBuild (again easy), and this then compiles the Delphi source (tricky and required me to mess about and reinstall CruiseControl.NET). It now checks out 5 projects (3 of which compile, 1 fails due to a missed file, and 1 needs an project to be registered), which is about what I expected.
Hurrah!
Hurrah!
Wednesday, 1 April 2009
CI with Delphi
I am trying to get CruiseControl.NET to connect to a Surround SCM system and then check out and build (and then test if possible) projects.
It was simple to install, but it needs as ASP.NET server to work (or so it seems). I've installed Apache and the mod_asp (or whatever it is called), and have got a simple ASP script to work, but can't get the CC.NET dashboard application to run.
More news as it breaks.
Update 1
I now have access to the CC.NET dashboard working. I can't get the command line that CC.NET builds to be correct, the settings seem OK, but I get the following ...
Update 2
Fixed the file locations, and started up the VPN, and now CruiseControl downloads the latest source, and tries to rebuild - the MSBuild process now gives the following error:
So we are getting much closer, and this might be working before I go back to work
It was simple to install, but it needs as ASP.NET server to work (or so it seems). I've installed Apache and the mod_asp (or whatever it is called), and have got a simple ASP script to work, but can't get the CC.NET dashboard application to run.
More news as it breaks.
Update 1
I now have access to the CC.NET dashboard working. I can't get the command line that CC.NET builds to be correct, the settings seem OK, but I get the following ...
Process command: E:\Program Files\Seapine\Surround SCM\sscm.exe cc * -d20090401153253:20090401153326 -r -bXXXX -p"XXXXXX" -x- -zABCABCDABCDEF:4900 -y"XXX:XXX"
Update 2
Fixed the file locations, and started up the VPN, and now CruiseControl downloads the latest source, and tries to rebuild - the MSBuild process now gives the following error:
E:\Documents\Mark\CCBuildDir\SSCMClone\D2009\XXXX\XXXX\XXXXX.dproj (,):
errorMSB4057: The target "Rebuild" does not exist in the project.
So we are getting much closer, and this might be working before I go back to work
Tuesday, 6 January 2009
MVC updated
I have had a small rest over Christmas and have decided that the code below needs to be refactored. I broke down all of the interfaces and implementations of them into different units, and begun to separate out the stuff that is MVC and stuff which used by the model.
Specifically I broke down the command stuff and implemented descendants of TCommand that know what to do to the model - i.e. the model doesn't do anything other than respond to the data changes (or not as is the current state).
This means I have ended up with code like this ..
This is a lot simpler in my view.
However it doesn't solve the problem with how to indicate that a field is invalid?
I might have to register each control with the model, so it knows which fields map to each control. That sounds like a lot to faff, but I don't know how else to do it.
Specifically I broke down the command stuff and implemented descendants of TCommand that know what to do to the model - i.e. the model doesn't do anything other than respond to the data changes (or not as is the current state).
This means I have ended up with code like this ..
TCalculateCommand = class (TCommand)
procedure Run (model : tObject); override;
end;
..
{ TCalculateCommand }
procedure TCalculateCommand.Run (model : tObject);
begin
(model as TDomainModel).Data.Price := self.Params[0].Value;
(model as TDomainModel).Data.Consideration := ((model as TDomainModel).Data.Size *
(model as TDomainModel).Data.Price) + (model as TDomainModel).Data.Charges;
end;
This is a lot simpler in my view.
However it doesn't solve the problem with how to indicate that a field is invalid?
I might have to register each control with the model, so it knows which fields map to each control. That sounds like a lot to faff, but I don't know how else to do it.
Friday, 7 November 2008
MVC Update
In the real world, which I obviously can't post here, I have a problem where the result of the validation request does three things;
1) Validates the input values
2) Returns other information based on the inputs (i.e. Other client, stock details)
3) Set whether a specific field input is valid or not.
1) Validates the input values
2) Returns other information based on the inputs (i.e. Other client, stock details)
3) Set whether a specific field input is valid or not.
Tuesday, 28 October 2008
MVC in Delphi (Part II)
The TCommand is clearly a Command, and should be slightly different, but I will sort that out later.
Monday, 27 October 2008
MVC in Delphi (Part I)
We have a large Delphi software project at work, that has been in development for the last 10 years and is now basically unmaintainable. It uses threads to create conversations with an iSeries I5 (an AS/400 in old money). These threads are unmanaged, interdependant and duplicated throughout the application.
We have been on the point of refactoring many times, but have not had the time or the will-power to actually do it. So, here goes ...
MVC
Basically the MVC pattern looks closest to what I need. A data domain, and dependant views on it, so it "... isolates business logic from user interface considerations..."
The parts of the pattern are ..

Model
This is basically an Observable ...
A default implementation of IObservable is the TObservable class, from which more concrete implementations should descend.
View
This is basically an Observer ...
The IObserver and IObservable pattern is a standard pattern from Design Patterns: Elements of Reusable Object-Oriented Software. It is half way there, with the Observable registering all of the Observer objects that are interested in when it changes. However, there is not a way of interacting with the Observer, in order to make it carry out operations, this is where the Controller comes in.
Controller
The controller is used (in my code at least) register all of the Observers with the Observables, and to marshal commands from the View to the Model. My interface for a Controller looks like this;
This maintains a list of Views (accessed via the Views property), and the Model which they are interested in. The commands are processed via the DoCommand method (this is a bit of a hack I think, and I can't quite think of a way to do this nicely!).
Concrete Example
So the interfaces above describe the basic building blocks of an MVC interface. Lets try and build a concrete example to see how it works.
My example model will be a single extended value, which will be initialised at startup by the Model, and then operations can be carried out on it by the View, via the Controller.
First we define the concrete model ...
As can be seen, we descend from the base class TObservable, which implements all of the IObservable methods, and provides some basic functionality needed by all TObservable objects (see above).
The DoCommand method wraps up the TCommand object (more of that later), and then spawns off a thread to actually do the processing. This hides all of the gubbins of getting data and processing it from the Controller and the View. In the real example this would get stuff from the i5 via the conversation. It would mean that this method of using threads could be changed to use a managed queue, or whatever, without changing the View or the Controller, as they don't need to know HOW the data is fetched, just that it is ready.
In the example below, we just do some very simple maths
I'll finish off this a bit later, and upload the source for the example
We have been on the point of refactoring many times, but have not had the time or the will-power to actually do it. So, here goes ...
MVC
Basically the MVC pattern looks closest to what I need. A data domain, and dependant views on it, so it "... isolates business logic from user interface considerations..."
The parts of the pattern are ..

Model
This is basically an Observable ...
IObservable = interface
procedure RegisterObserver (obs : IObserver);
procedure UnregisterObserver (obs : IObserver);
procedure Notify (const obj : TObject);
procedure ClearObservers ();
procedure DoCommand (cmd : TCommand);
end;
A default implementation of IObservable is the TObservable class, from which more concrete implementations should descend.
///This is the default implementation of IObservable
///IObservable
TObservable = class (TInterfacedObject,
IObservable)
private
FObservers : TClassList;
FCurrent : TObject;
public
constructor Create;
destructor Destroy; override;
procedure SetCurrent (obj: TObject);
procedure RegisterObserver (obs : IObserver);
procedure UnregisterObserver (obs : IObserver);
procedure ClearObservers ();
procedure Notify (const obj : TObject);
procedure DoCommand (cmd : TCommand); virtual;
property Current : TObject read FCurrent write FCurrent;
end;
View
This is basically an Observer ...
IObserver = interface
procedure UpdateView (obj : TObject);
end;
The IObserver and IObservable pattern is a standard pattern from Design Patterns: Elements of Reusable Object-Oriented Software. It is half way there, with the Observable registering all of the Observer objects that are interested in when it changes. However, there is not a way of interacting with the Observer, in order to make it carry out operations, this is where the Controller comes in.
Controller
The controller is used (in my code at least) register all of the Observers with the Observables, and to marshal commands from the View to the Model. My interface for a Controller looks like this;
IController = interface
function GetModel : IObservable;
procedure SetModel (const m : IObservable);
function GetView (index: integer): IObserver;
procedure SetView (index: integer; const v : IObserver);
property Model : IObservable read GetModel write SetModel;
property Views[index: integer]: IObserver read GetView write SetView;
procedure DoCommand (cmd : TCommand);
procedure AddView (v : IObserver);
end;
This maintains a list of Views (accessed via the Views property), and the Model which they are interested in. The commands are processed via the DoCommand method (this is a bit of a hack I think, and I can't quite think of a way to do this nicely!).
Concrete Example
So the interfaces above describe the basic building blocks of an MVC interface. Lets try and build a concrete example to see how it works.
My example model will be a single extended value, which will be initialised at startup by the Model, and then operations can be carried out on it by the View, via the Controller.
First we define the concrete model ...
///A small implementation of the MVC architecture
TDomainModel = class (TObservable)
private
///Underlying data object
FData : extended;
public
///Property that represents the underlying data
property Data : extended read FData write FData;
///Executes the given command
procedure DoCommand (cmd : TCommand); override;
///Creates the underlying data
constructor Create;
///Function that is passed to the CommandThread for execution
///TCommandThread
procedure ExecuteCommand (cmd : TCommand);
end;
As can be seen, we descend from the base class TObservable, which implements all of the IObservable methods, and provides some basic functionality needed by all TObservable objects (see above).
The DoCommand method wraps up the TCommand object (more of that later), and then spawns off a thread to actually do the processing. This hides all of the gubbins of getting data and processing it from the Controller and the View. In the real example this would get stuff from the i5 via the conversation. It would mean that this method of using threads could be changed to use a managed queue, or whatever, without changing the View or the Controller, as they don't need to know HOW the data is fetched, just that it is ready.
In the example below, we just do some very simple maths
procedure TDomainModel.DoCommand (cmd : TCommand);
var
T : TCommandThread;
begin
t := TCommandThread.Create(true);
t.Cmd := cmd;
t.ParamList := cmd.ParamList;
t.Operation := ExecuteCommand;
t.Resume;
end;
procedure TDomainModel.ExecuteCommand (cmd : TCommand);
begin
if cmd.Command = 'HALF' then
begin
FData := FData / 2;
end;
if cmd.Command = 'MULTIPLY' then
begin
FData := FData * 2;
end;
if cmd.Command = 'SET' then
begin
assert (cmd.ParamCount <> -1, 'SET requires a parameter value');
FData := cmd.Params[0].Value;
end;
if cmd.Command = 'ADD' then
begin
assert (cmd.ParamCount <> -1, 'ADD requires a parameter value');
FData := FData + cmd.Params[0].Value;
end;
if cmd.Command = 'ZERO' then
begin
FData := 0.0;
end;
Notify(self);
end;
constructor TDomainModel.Create;
begin
FData := 10.0;
end;
I'll finish off this a bit later, and upload the source for the example
Subscribe to:
Posts (Atom)