unit GDIPenable;

//------------------------------------------------------------------------------
// Allows application to use DLLs that contain calls to the Windows GDI+ API.
//
// by: blert ( http:\\blertdiscorporated.com )
// ver: 1.3
// last update: September 26, 2005
//
// To do:
// - do something with Hook and Debug callbacks
//
// Change log:
// v 1.3
//  - reorganized everything
//  - changed Enabled property (published, boolean, read only)
//  - added StartupStatus property (published, TStatus, read only)
//  - added ReInitGDIP and ShutdownGDIP procedures (published)
// v 1.2
//  - wrapped both calles to the external functions in 'try's,
//  - added Enabled property (public, boolean, read only),
//    if the call to GdiplusStartup does not throw an exception then Enabled
//    is set to true, if the call fails then 'Enable' is set to false
// v 1.1
//  - removed Token property as it is not needed
// v 1.0
//  - fit for use
//------------------------------------------------------------------------------

interface

uses
  Windows, Classes;

type
  TStatus = (
    Ok,
    GenericError,
    InvalidParameter,
    OutOfMemory,
    ObjectBusy,
    InsufficientBuffer,
    NotImplemented,
    Win32Error,
    WrongState,
    Aborted,
    FileNotFound,
    ValueOverflow,
    AccessDenied,
    UnknownImageFormat,
    FontFamilyNotFound,
    FontStyleNotFound,
    NotTrueTypeFont,
    UnsupportedGDIPlusVersion,
    GdiplusNotInitialized,
    PropertyNotFound,
    PropertyNotSupported
  );

  TDebugEventLevel = (
    DebugEventLevelFatal,
    DebugEventLevelWarning
  );
  TDebugEventProc = procedure(Level: TDebugEventLevel; Message: pchar); stdcall;

  TGdiplusStartupInput = packed record
    GdiplusVersion : cardinal;
    DebugEventCallback : TDebugEventProc;
    SuppressBackgroundThread: longbool;
    SuppressExternalCodecs : longbool;
  end;
  PGdiplusStartupInput = ^TGdiplusStartupInput;

  TNotificationHookProc = function(out Token: cardinal): TStatus; stdcall;
  TNotificationUnhookProc = procedure(Token: cardinal); stdcall;
  TGdiplusStartupOutput = packed record
    NotificationHook : TNotificationHookProc;
    NotificationUnhook: TNotificationUnhookProc;
  end;
  PGdiplusStartupOutput = ^TGdiplusStartupOutput;

  TGDIPenable = Class(TComponent)
  private
    fToken: cardinal;
    fEnabled: boolean;
    fStartupStatus: TStatus;
    procedure InitGDIP;
  protected
    { none }
  public
    constructor Create(aOwner: TComponent); override;
    destructor Destroy; override;
  published
    procedure ReInitGDIP;
    procedure ShutdownGDIP;
    property Enabled: boolean read fEnabled;
    property StartupStatus: TStatus read fStartupStatus;
  end;

  function GdiplusStartup(out Token: cardinal; Input: PGdiplusStartupInput; Output: PGdiplusStartupOutput): TStatus; stdcall; external 'gdiplus.dll' name 'GdiplusStartup';
  procedure GdiplusShutdown(Token: cardinal); stdcall; external 'gdiplus.dll' name 'GdiplusShutdown';
  procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('blert Tools', [TGDIPenable]);
end;

{ TGDIPenable }

constructor TGDIPenable.Create(aOwner: TComponent);
begin
  inherited;
  InitGDIP;
end;

destructor TGDIPenable.Destroy;
begin
  ShutdownGDIP;
  inherited;
end;

procedure TGDIPenable.InitGDIP;
var
  StartupInput: PGdiplusStartupInput;
  StartupOutput: PGdiplusStartupOutput;
begin
  New(StartupInput);
  StartupInput.GdiplusVersion := 1;
  StartupInput.DebugEventCallback := nil;
  StartupInput.SuppressBackgroundThread := true;
  StartupInput.SuppressExternalCodecs := false;
  New(StartupOutput);
  StartupOutput.NotificationHook := nil;
  StartupOutput.NotificationUnhook := nil;
  try
    fStartupStatus := GdiplusStartup(fToken, StartupInput, StartupOutput);
  except
    fStartupStatus := GdiplusNotInitialized;
  end;
  if fStartupStatus = Ok then fEnabled := true else fEnabled := false;
  Dispose(StartupInput);
  Dispose(StartupOutput);
end;

procedure TGDIPenable.ReInitGDIP;
begin
  if fEnabled then Exit;
  InitGDIP;
end;

procedure TGDIPenable.ShutdownGDIP;
begin
  try GdiplusShutdown(fToken); except end;
end;

end.
