“everything worth doing is worth doing slowly” – Mae West

Sending Bitmap to Epson printer using Delphi and ESC/POS

I have previously tried to use http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/ and the attached Delphi translation to send a TBitmap directly to Epson TM T20, TM T80 and TM88 printers. Unfortunately it never worked.

Recently I needed to print dynamically created QR codes using the printers so it was time to revisit this. I worked directly off the C# sources provided and created a Delphi class to replicate this.

I've added this to a GIT repository on Bitbucket in case anyway needs to use it in future.

Project Home: https://bitbucket.org/bernd_summerswell/delphi_escpos_bitmap/

Example Usage:

This uses the Synaser library from Synapse to send the buffer directly to a COM Port.

uses
  synaser,
  ssESCPOSPrintBitmap;

var
  LBuffer : string;
  LDevice : TBlockSerial;
begin
  LBuffer := #27'@'; // Initialise the printer
  LBuffer := LBuffer + _ESCPosPrintBitmap().RenderBitmap( 'path\to\bitmapfile' );
  LBuffer := #29'V'#1 // Paper cut full

  // Send LBuffer to Printer
  LDevice := TBlockSerial.Create();
    try
      LDevice.Config( 115200, 8, 'N', 1, False, False );
      LDevice.Connect( 'COM7' );
      LDevice.SendString( LBuffer  );
    finally
      LDevice.Free();
    end;
end.
Read More

TDocVariant CRUD Operations

This is based on http://blog.synopse.info/post/2014/02/25/TDocVariant-custom-variant-type and the corresponding forum http://synopse.info/forum/viewtopic.php?id=1631

Create

A TDocVariant custom variant type is declared as a Variant:

var
 LDocVariant : Variant;

The TDocVariant can be created as an object or from a JSON string. You can use the _Obj/_ObjFast, _JSON/_JSONFast and _Arr/_ArrFast methods to create the TDocVariant.

LDocVariant := _ObjFast( [ 'name', 'bernd' ] );
LDocVariant := _JsonFast( '{ "Person": { "First" : { "name" : "bernd" } } }' );
LDocVariant := _ArrFast( [ _ObjFast( [ 'name', 'bernd' ] ),
                           _ObjFast( [ 'name', 'bob' ] ) ] );

Read

You can access items in the TDocVariant variable dynamically:

Writeln( LDocVariant.name );
Writeln( LDocVariant.Person.First.Name )
Writeln( LDocVariant._(0).name );

Each of these will output "bernd".

A TDocVariant will also be cast as JSON string when used in place of a string, for example, using the examples above, calling the following on each respectively:

Writeln( LDocVariant );

will output the following:

{"name":"bernd"}
{"Person":{"First":"bernd"}}
[{"name":"bernd"},{"name":"bob"}]

For arrays you also have _Count so you can iterate through the array:

for LIndex := 0 to LDocVariant._Count - 1 do
  Writeln( LDocVariant._(LIndex).name );

Update

Updating items and properties is really easy:

LDocVariant.name := "Bernd";
LDocVariant.Person.First.name := "Bernd";
LDocVariant._(1).name := "Bob";

You can add objects, array items or values to existing items as well.

LDocVariant.age := 31;
LDocVariant.Person.Next := _ObjFast( ['name','bob'] );
LDocVariant.Person.Next.age = 43;
LDocVariant.Add( _ObjFast( [ 'name', 'ned' ] ) );

Delete

All TDocVariant variables have the Delete method to remove an item from the object or array:

LDocVariant.Delete( 'name' );
LDocVariant.Person.Delete( 'Next' );
LDocVariant.Delete( 1 );

 

Read More

Using TDocVariant for settings

Arnaud from Synopse has just released a great new addition to the mORMot framework. TDocVariant is custom variant type which integrates effortless with JSON.

One area that this can be implemented is for the settings of an application. Usually an INI file is the easiest way to implement settings for an application, especially when it is a small utility. INI files mean that you can quickly edit the settings without needing a special editor. Unfortunately arrays, lists and collections are difficult to store in INI files without some sort of pre-determined structure.

JSON eliminates this problem, and allows a truly flexible structure. Now you can use the TDocVariant class to easily read and write the settings as well as access them in your application.

For the snomSwitcher application, the settings are stored in the following format:

{
"PhoneSettings":{
"IP":"192.168.1.100",
"Username":"admin",
"Password":"admin",
"PhoneType":"Snom 300"
},
"Users":[
{
"DisplayName":"User 1",
"Account":"101",
"Password":"101",
"Registrar":"your.voip.provider"
},
{
"DisplayName":"User 2",
"Account":"102",
"Password":"1234",
"Registrar":"your.voip.provider"
},
{
"DisplayName":"User 3",
"Account":"101",
"Password":"101",
"Registrar":"your.voip.provider"
}
]
}

We can load the the settings from file by calling:

FSettings := _JsonFast(  StringFromFile( FSettingsFilename ) );

We can then access the settings easily from anywhere in code:

Writeln( FSettings.PhoneSettings.IP );
Writeln( FSettings.Users._(1).Username );

Read More

Running two instances of the same Delphi Service

Recently there was a need to run two instances of the same service written in Delphi on the same server. While you can manually changed the service name in the registry or via the "sc" command, the service will not start up correctly unless the service name matches the TService.Name.

To get around this you can pass the name of the service as a parameter to the executable and dynamically set the Name and DisplayName properties when the service is created.

function GetParamValue( const ASwitch: string; var AValue: string ): Boolean;
var
  LIndex : Integer;
begin
  Result := False;
  for LIndex := 1 to ParamCount do
    if ( StartsText( ASwitch, ParamStr( LIndex ) ) ) then begin
      Result := True;
      AValue := ReplaceText( ParamStr( LIndex ), ASwitch, '' );
    end;
end;

procedure TYourService.ServiceAfterInstall(Sender: TService);
var
  LRegistry : TRegistry;
begin
  LRegistry := TRegistry.Create();
  try
    LRegistry.RootKey := HKEY_LOCAL_MACHINE;
    if ( LRegistry.OpenKey( '\SYSTEM\CurrentControlSet\Services\' + Name, False ) ) then begin
      LRegistry.WriteString( 'ImagePath', ParamStr(0) + ' /name=' + Name );
    end;
  finally
    LRegistry.Free();
  end;
end;

procedure TYourService.ServiceCreate(Sender: TObject);
var
  LNewName  : string;
begin
  if ( GetParamValue( '/name=', LNewName ) ) then begin
    Name          := LNewName;
    DisplayName   := LNewName;
  end;
end;

The AfterInstall event makes sure that the /name parameter is passed to the service each time it starts up.

This should make your Delphi Service more flexible!

Read More