(* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower OnGuard * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1996-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Andrew Haines andrew@haines.name {AH.01} * conversion to CLX {AH.01} * December 30, 2003 {AH.01} * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* TurboPower String Resource Support: SRMGR.PAS 1.03 *} {* Copyright (c) TurboPower Software Co 1996-1998 *} {* All rights reserved. *} {*********************************************************} {* SRMGR: TurboPower string resource runtime manager *} {*********************************************************} { -------------------------------------------------------------------- Notes: Loads string resources created by SRMC.EXE and BRCC[32]. See the comments in SRMC.PAS for additional information. Both Create() and ChangeResource take an instance (module) handle and a resource name. The resource from the module is then loaded. If the resource is not found an ETpsStringResourceError is raised. If you wish to alter our products' string resources to translate the strings into a different language then you have two choices. In an application written in Delphi 1 or Delphi 2 or Delphi 3 without packages then you can alter the .TXT files containing the strings, recompile them with our 32-bit SRMC utility to create an STR file, and then recompile the RC resource files (which 'include' the STR file) with Delphi's BRCC[32] program. Relink your application and it will then have strings in your language of preference. For an application created with Delphi 3 using packages, then the product packages cannot be recompiled and hence the string resources in those packages cannot be changed. This is where the ChangeResource method comes in. Create a whole new resource (it must have a different name than the one we use) in the manner described above. It will be linked into your application. Now in your application, say before the Application.Run call in your project, call ChangeResource for the string resource object you want to change and pass it the HInstance value of the application and the name of your new resource. From now on that string resource object will use your string resource instead of the original. GetWideChar(), available in 32-bit applications only, returns a UNICODE string directly from the resource. GetAsciiZ() converts the UNICODE (32-bit) or DBCS (16-bit) string from the resource into a DBCS null-terminated string using the default code page. GetString(), or the default Strings[] array property, also converts the string to a DBCS or SBCS string using the default code page. When the ReportError property is true, requesting a string whose identifier is not found causes an ETpsStringResourceError exception. When ReportError is false, no exception is generated but an empty string is returned. Based on TPSRES.PAS by Lee Inman. Written by Kim Kokkonen. -------------------------------------------------------------------- } {$IFDEF Win32} {include the resource compiled using BRCC32.EXE and SRMC.EXE} {$R OGSRMGR.R32} {$ELSE} {$IFNDEF LINUX} {include the resource compiled using BRCC.EXE and SRMC.EXE} {$R OGSRMGR.R16} {$ELSE} {$R OGSRMGR.R32} {$ENDIF} {$ENDIF} {$R-,S-,I-} {$IFDEF Win32} {$H+} {Long strings} {!!.02} {$ENDIF} {For BCB 3.0 package support.} {$IFDEF VER110} {$ObjExportAll On} {$ENDIF} {$IFNDEF VER80} {Delphi 1} {$IFNDEF VER90} {Delphi 2} {$IFNDEF VER93} {BCB 1} {$DEFINE VERSION3} { Delphi 3.0 or BCB 3.0 or higher } {$ENDIF} {$ENDIF} {$ENDIF} unit ogsrmgr; interface uses {$IFDEF MSWINDOWS} {AH.01} Windows, {AH.01} {$ENDIF} {AH.01} {$IFDEF UsingCLX} {AH.01} Types, {AH.01} {$ENDIF} {AH.01} {$IFDEF LINUX} {AH.01} Libc, {AH.01} {$ENDIF} {AH.01} Classes, SysUtils; const DefReportError = False; {id at start of binary resource; must match SRMC} ResID : array[0..3] of char = 'STR0'; type ETpsStringResourceError = class(Exception); {$IFDEF Win32} TInt32 = Integer; {$ELSE} TInt32 = LongInt; {$ENDIF} PIndexRec = ^TIndexRec; TIndexRec = record id : TInt32; ofs: TInt32; len: TInt32; end; TIndexArray = array[0..(MaxInt div SizeOf(TIndexRec))-2] of TIndexRec; PResourceRec = ^TResourceRec; TResourceRec = record id : array[0..3] of char; count : LongInt; index : TIndexArray; end; TOgStringResource = class private {property variables} FReportError : Boolean; {true to raise exception if string not found} {internal variables} srHandle : THandle; {handle for TPStrings resource} srP : PResourceRec; {pointer to start of resource} {internal methods} procedure srCloseResource; function srFindIdent(Ident : TInt32) : PIndexRec; procedure srLock; procedure srLoadResource(Instance : THandle; const ResourceName : string); procedure srOpenResource(Instance : THandle; const ResourceName : string); procedure srUnLock; public constructor Create(Instance : THandle; const ResourceName : string); virtual; destructor Destroy; override; procedure ChangeResource(Instance : THandle; const ResourceName : string); function GetAsciiZ(Ident : TInt32; Buffer : PChar; BufChars : Integer) : PChar; function GetString(Ident : TInt32) : string; property Strings[Ident : TInt32] : string read GetString; default; {$IFDEF Win32} function GetWideChar(Ident : TInt32; Buffer : PWideChar; BufChars : Integer) : PWideChar; {$ENDIF} property ReportError : Boolean read FReportError write FReportError; end; var TpsResStrings : TOgStringResource; {error strings for this unit} {====================================================================} implementation {*** TOgStringResource ***} procedure TOgStringResource.ChangeResource(Instance : THandle; const ResourceName : string); begin srCloseResource; if ResourceName <> '' then srOpenResource(Instance, ResourceName); end; constructor TOgStringResource.Create(Instance : THandle; const ResourceName : string); begin inherited Create; FReportError := DefReportError; ChangeResource(Instance, ResourceName); end; destructor TOgStringResource.Destroy; begin srCloseResource; inherited Destroy; end; {$IFDEF Win32} procedure WideCopy(Dest, Src : PWideChar; Len : Integer); begin while Len > 0 do begin Dest^ := Src^; inc(Dest); inc(Src); dec(Len); end; Dest^ := #0; end; function TOgStringResource.GetWideChar(Ident : TInt32; Buffer : PWideChar; BufChars : Integer) : PWideChar; var OLen : Integer; P : PIndexRec; begin srLock; try P := srFindIdent(Ident); if P = nil then Buffer[0] := #0 else begin OLen := P^.len; if OLen >= BufChars then OLen := BufChars-1; WideCopy(Buffer, PWideChar(PChar(srP)+P^.ofs), OLen); end; finally srUnLock; end; Result := Buffer; end; function TOgStringResource.GetAsciiZ(Ident : TInt32; Buffer : PChar; BufChars : Integer) : PChar; var P : PIndexRec; Src : PWideChar; Len, OLen : Integer; begin srLock; try P := srFindIdent(Ident); if P = nil then OLen := 0 else begin Src := PWideChar(PChar(srP)+P^.ofs); Len := P^.len; {see if entire string fits in Buffer} OLen := WideCharToMultiByte(CP_ACP, 0, Src, Len, nil, 0, nil, nil); while OLen >= BufChars do begin {reduce length to get what will fit} dec(Len); OLen := WideCharToMultiByte(CP_ACP, 0, Src, Len, nil, 0, nil, nil); end; {copy to buffer} OLen := WideCharToMultiByte(CP_ACP, 0, Src, Len, Buffer, BufChars, nil, nil) end; finally srUnLock; end; {null terminate the result} Buffer[OLen] := #0; Result := Buffer; end; function TOgStringResource.GetString(Ident : TInt32) : string; var P : PIndexRec; Src : PWideChar; Len, OLen : Integer; begin srLock; try P := srFindIdent(Ident); if P = nil then Result := '' else begin Src := PWideChar(PChar(srP)+P^.ofs); Len := P^.len; OLen := WideCharToMultiByte(CP_ACP, 0, Src, Len, nil, 0, nil, nil); SetLength(Result, OLen); WideCharToMultiByte(CP_ACP, 0, Src, Len, PChar(Result), OLen, nil, nil); end; finally srUnLock; end; end; {$ELSE} function TOgStringResource.GetAsciiZ(Ident : TInt32; Buffer : PChar; BufChars : Integer) : PChar; var OLen : Integer; P : PIndexRec; begin srLock; try P := srFindIdent(Ident); if P = nil then Buffer[0] := #0 else begin OLen := P^.len; if OLen >= BufChars then OLen := BufChars-1; StrLCopy(Buffer, PChar(srP)+P^.ofs, OLen); Buffer[OLen] := #0; end; finally srUnLock; end; Result := Buffer; end; function TOgStringResource.GetString(Ident : TInt32) : string; var OLen : Integer; Src : PChar; P : PIndexRec; begin srLock; try P := srFindIdent(Ident); if P = nil then Result := '' else begin OLen := P^.len; if OLen > 255 then OLen := 255; {$IFDEF MSWINDOWS} Result[0] := Char(OLen); Src := PChar(srP)+P^.ofs; move(Src^, Result[1], OLen); {$ELSE} Result := Src; {$ENDIF} end; finally srUnLock; end; end; {$ENDIF} procedure TOgStringResource.srCloseResource; begin while Assigned(srP) do srUnLock; if srHandle <> 0 then begin FreeResource(srHandle); srHandle := 0; end; end; function TOgStringResource.srFindIdent(Ident : TInt32) : PIndexRec; var L, R, M : TInt32; begin {binary search to find matching index record} L := 0; R := srP^.count-1; while L <= R do begin M := (L+R) shr 1; Result := @srP^.index[M]; if Ident = Result^.id then exit; if Ident > Result^.id then L := M+1 else R := M-1; end; {not found} Result := nil; if FReportError then raise ETpsStringResourceError.CreateFmt(TpsResStrings[1], [Ident]); end; procedure TOgStringResource.srLock; begin srP := LockResource(srHandle); if not Assigned(srP) then raise ETpsStringResourceError.Create(TpsResStrings[2]); end; procedure TOgStringResource.srLoadResource(Instance : THandle; const ResourceName : string); var H : THandle; Buf : array[0..255] of Char; begin StrPLCopy(Buf, ResourceName, SizeOf(Buf)-1); {$IFDEF VERSION3} { resource DLL mechanism started in D3 } {if not ModuleIsPackage then } {!!.04} Instance := FindResourceHInstance(Instance); { get loaded Resource DLL if any } {$ENDIF} H := FindResource(Instance, Buf, RT_RCDATA); { attempt to load resource } if H = 0 then begin { not found } {$IFDEF VERSION3} {!!.04} Instance := HInstance; {!!.04} H := FindResource(Instance, Buf, RT_RCDATA); { try to find it in the main binary } {!!.04} if H = 0 then { still not found?} {$ENDIF} {!!.04} raise ETpsStringResourceError.CreateFmt(TpsResStrings[3], [ResourceName]); { whine } end; srHandle := LoadResource(Instance, H); if srHandle = 0 then raise ETpsStringResourceError.CreateFmt(TpsResStrings[4], [ResourceName]); end; procedure TOgStringResource.srOpenResource(Instance : THandle; const ResourceName : string); begin {find and load the resource} srLoadResource(Instance, ResourceName); {confirm it's in the correct format} srLock; try if srP^.id <> ResId then raise ETpsStringResourceError.Create(TpsResStrings[5]); finally srUnLock; end; end; procedure TOgStringResource.srUnLock; begin if not UnLockResource(srHandle) then srP := nil; end; procedure FreeTpsResStrings; far; begin TpsResStrings.Free; end; initialization TpsResStrings := TOgStringResource.Create(HInstance, 'OGSRMGR_STRINGS');{!!.01} {$IFDEF Win32} finalization FreeTpsResStrings; {$ELSE} {$IFNDEF LINUX} AddExitProc(FreeTpsResStrings); {$ELSE} FreeTpsResStrings; {$ENDIF} {$ENDIF} end.