• 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.
    
  • 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 );

     

  • 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 );
    
    
  • 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!

  • Gnu Gettext for Delphi and Woll2Woll

    We use GNU Gettext for translation in our Delphi 6 application. We also use the Woll2Woll data-aware components. In our forms we add the following to the OnCreate event:

    TranslateComponent( Self );
    

    We also have set up the typical ignores but we still had a problem with the Woll2Wol TwwDBComboBox that was not being populated properly and we could not set it getting the error: “True is not a valid Boolean value”. Turns out that the resourcestrings in DBConsts for the ‘True’ and ‘False’ values had been translated but the ‘Items’ property of the TwwDBComboBox that mapped ‘Yes’ to ‘True’ wasn’t being translated because the string was ‘Yes’#9’True’.

    I’ve added the following function to translate the items in the wwDBComboBox so that they map correctly:

    uses
      Wwstr,
      gnugettext;
    
    {-------------------------------------------------------------------------------
      Procedure: Translate_wwDBCustomComboBox
      Author:    bvonfintel
      DateTime:  2013.09.12
      Arguments: const AComponent: TwwDBCustomComboBox
      Result:    None
    -------------------------------------------------------------------------------}
    procedure Translate_wwDBCustomComboBox( const AComponent: TwwDBCustomComboBox );
    var
      LIndex      : Integer;
      LTokenIndex : Integer;
      LToken1     : string;
      LToken2     : string;
    begin
      for LIndex := 0 to AComponent.Items.Count - 1 do begin
        LTokenIndex := 1;
        LToken1     := _( strGetToken( AComponent.Items[LIndex], #9, LTokenIndex ) );
        LToken2     := _( strGetToken( AComponent.Items[LIndex], #9, LTokenIndex ) );
    
        AComponent.Items[LIndex] := LToken1 + #9 + LToken2;
      end;
    end;
    
  • TMethodList for Pre-Generics Delphi

    While in the later versions of Delphi we can simply use a generic TList<TMethod> in the earlier versions of Delphi (like Delphi 6 which I am using) we need to override the base TList class to accommodate the methods and implement a TMethodList container. This method list is based on the multicast event handler outlined here: http://delphi.about.com/library/weekly/aa051005a.htm

    The most important part of the class is assigning the TMethod to a pointer.

    First we create a pointer to a TMethod

    type
      PMethod = ^TMethod;
    

    When adding the TMehod to the list we copy the .Data and .Code to the newly created Pointer

      Result := New( PMethod );
      Result^.Code := AItem.Code;
      Result^.Data := AItem.Data;
    

    Later we will need to Dispose of the memory

      if ( Action = lnDeleted ) then begin
        Dispose( Ptr );
      end;
    

    The whole class:

    {******************************************************************************}
    {                                                                              }
    {  Unit: ssMethodList.pas                                                      }
    {  Summerswell Core                                                            }
    {                                                                              }
    {  Copyright (C) 2013 Summerswell                                              }
    {                                                                              }
    {  Author     : bvonfintel                                                     }
    {  Original   : 2013/09/13 11:23:02 AM                                         }
    {                                                                              }
    {******************************************************************************}
    unit ssMethodList;
    
    interface
    
    uses
      Classes;
    
    type
      // *** -------------------------------------------------------------------------
      // *** CLASS: TssMethodList
      // *** -------------------------------------------------------------------------
      TssMethodList = class( TList )
        protected
          procedure Put( AIndex: Integer; AItem: TMethod );
          function  Get( AIndex: Integer ): TMethod;
          procedure Notify(Ptr: Pointer; Action: TListNotification); override;
        public
          function  Add( AItem: TMethod ): Integer;
          property Items[Index: Integer]: TMethod read Get write Put; default;
      end;
    
    implementation
    
    type
      PMethod = ^TMethod;
    
    {-------------------------------------------------------------------------------
      Procedure: CreatePMethod
      Author:    bvonfintel
      DateTime:  2013.09.13
      Arguments: AItem: TMethod
      Result:    PMethod
    -------------------------------------------------------------------------------}
    function CreatePMethod( AItem: TMethod ): PMethod;
    begin
      Result := New( PMethod );
      Result^.Code := AItem.Code;
      Result^.Data := AItem.Data;
    end;
    
    { TssMethodList }
    
    {-------------------------------------------------------------------------------
      Procedure: TssMethodList.Add
      Author:    bvonfintel
      DateTime:  2013.09.13
      Arguments: AItem: TMethod
      Result:    Integer
    -------------------------------------------------------------------------------}
    function TssMethodList.Add(AItem: TMethod): Integer;
    begin
      Result := inherited Add( CreatePMethod( AItem ) );
    end;
    
    {-------------------------------------------------------------------------------
      Procedure: TssMethodList.Get
      Author:    bvonfintel
      DateTime:  2013.09.13
      Arguments: AIndex: Integer
      Result:    TMethod
    -------------------------------------------------------------------------------}
    function TssMethodList.Get(AIndex: Integer): TMethod;
    begin
      Result := TMethod( inherited Get( AIndex )^ );
    end;
    
    {-------------------------------------------------------------------------------
      Procedure: TssMethodList.Notify
      Author:    bvonfintel
      DateTime:  2013.09.13
      Arguments: Ptr: Pointer; Action: TListNotification
      Result:    None
    -------------------------------------------------------------------------------}
    procedure TssMethodList.Notify(Ptr: Pointer; Action: TListNotification);
    begin
      inherited;
      if ( Action = lnDeleted ) then begin
        Dispose( Ptr );
      end;
    end;
    
    {-------------------------------------------------------------------------------
      Procedure: TssMethodList.Put
      Author:    bvonfintel
      DateTime:  2013.09.13
      Arguments: AIndex: Integer; AItem: TMethod
      Result:    None
    -------------------------------------------------------------------------------}
    procedure TssMethodList.Put(AIndex: Integer; AItem: TMethod);
    begin
      inherited Put( AIndex, CreatePMethod( AItem ) );
    end;
    
    end.
    
  • CodeIgniter: Check Authentication and Fail

    Very often, when developing a site using CodeIgniter, I use a base Controller to check common functions such as authentication. This is easiest to do in the Controller’s __construct method. Usually you can simply use a redirect to your login page:

    [code lang=”php”]
    redirect( "/user/login" );
    [/code]

    But sometimes you simply want to stop the Controller and output the fact that they are not authorised or that a certain error has occurred. I was just doing this with a REST API on a site, and simply wanted to fail if the wrong API Key was passed. I’ve found it’s easiest to do via a “show_error” call:

    [code lang=”php”]
    show_error(‘Not authorized’, 401 );
    [/code]