380 lines
11 KiB
ObjectPascal
380 lines
11 KiB
ObjectPascal
|
{GENERAL METHODS USED BY TWAIN DELPHI}
|
|||
|
{december 2001<30>, made by Gustavo Daud}
|
|||
|
|
|||
|
{This unit contains general methods used by Delphi}
|
|||
|
{Twain component. Some of the methods bellow aren't}
|
|||
|
{directly related to Twain, but are pieces needed}
|
|||
|
{to implement the component.}
|
|||
|
|
|||
|
unit DelphiTwainUtils;
|
|||
|
|
|||
|
{$INCLUDE DELPHITWAIN.INC}
|
|||
|
|
|||
|
interface
|
|||
|
|
|||
|
uses
|
|||
|
Twain;
|
|||
|
|
|||
|
type
|
|||
|
{Kinds of directories to be obtained with GetCustomDirectory}
|
|||
|
TDirectoryKind = (dkWindows, dkSystem, dkCurrent, dkApplication, dkTemp);
|
|||
|
|
|||
|
{Class to store a list of pointers}
|
|||
|
TPointerList = class
|
|||
|
private
|
|||
|
{Stores pointer to the allocated data}
|
|||
|
Data: Pointer;
|
|||
|
{Contains number of additional items allocated every time}
|
|||
|
{it needs more data to store}
|
|||
|
fAdditionalBlock: Integer;
|
|||
|
{Contains the number of items in the list}
|
|||
|
fCount: Integer;
|
|||
|
{Contains number of allocated items}
|
|||
|
fAllocated: Integer;
|
|||
|
{Allocate/deallocate memory to have enough memory}
|
|||
|
{to hold the new number of items}
|
|||
|
procedure SetAllocated(const Value: Integer);
|
|||
|
{Sets the AdditionalBlock property}
|
|||
|
procedure SetAdditionalBlock(const Value: Integer);
|
|||
|
{Set the number of items in the list}
|
|||
|
procedure SetCount(const Value: Integer);
|
|||
|
function GetItem(Index: Integer): Pointer;
|
|||
|
procedure PutItem(Index: Integer; const Value: Pointer);
|
|||
|
public
|
|||
|
{Add a new item}
|
|||
|
procedure Add(Value: Pointer);
|
|||
|
{Clear all the items in the list}
|
|||
|
procedure Clear;
|
|||
|
{Object being created or destroyed}
|
|||
|
constructor Create;
|
|||
|
destructor Destroy; override;
|
|||
|
{Returns/sets an item value}
|
|||
|
property Item[Index: Integer]: Pointer read GetItem write PutItem; default;
|
|||
|
{Returns the number of items}
|
|||
|
property Count: Integer read fCount write SetCount;
|
|||
|
{Number of allocated items}
|
|||
|
property Allocated: Integer read fAllocated write SetAllocated;
|
|||
|
{Additional items to alloc when it needs more memory}
|
|||
|
property AdditionalBlock: Integer read fAdditionalBlock write
|
|||
|
SetAdditionalBlock;
|
|||
|
end;
|
|||
|
|
|||
|
{Returns custom Microsoft Windows<77> directories}
|
|||
|
function GetCustomDirectory(const DirectoryKind: TDirectoryKind): String;
|
|||
|
{Returns the last error string from Microsoft Windows<77>}
|
|||
|
function GetLastErrorText(): String;
|
|||
|
{Returns if the directory exists}
|
|||
|
function DirectoryExists(const Directory: String): Boolean;
|
|||
|
{Returns if the file exists}
|
|||
|
function FileExists(const FilePath: String): Boolean;
|
|||
|
{Extracts the file directory part}
|
|||
|
function ExtractDirectory(const FilePath: String): String;
|
|||
|
{Convert from integer to string}
|
|||
|
{$IFDEF DONTUSEVCL}function IntToStr(Value: Integer): String;{$ENDIF}
|
|||
|
{$IFDEF DONTUSEVCL}function StrToIntDef(Value: String;
|
|||
|
Default: Integer): Integer;{$ENDIF}
|
|||
|
{$IFDEF DONTUSEVCL}function CompareMem(P1, P2: pChar;
|
|||
|
Size: Integer): Boolean;{$ENDIF}
|
|||
|
{Convert from twain Fix32 to extended}
|
|||
|
function Fix32ToFloat(Value: TW_FIX32): Extended;
|
|||
|
{Convert from extended to Fix32}
|
|||
|
function FloatToFix32 (floater: extended): TW_FIX32;
|
|||
|
|
|||
|
implementation
|
|||
|
|
|||
|
{Units used bellow}
|
|||
|
uses
|
|||
|
Windows;
|
|||
|
|
|||
|
{$IFDEF DONTUSEVCL}
|
|||
|
function CompareMem(P1, P2: pChar; Size: Integer): Boolean;
|
|||
|
var
|
|||
|
i: Integer;
|
|||
|
begin
|
|||
|
{Default result}
|
|||
|
Result := TRUE;
|
|||
|
{Search each byte}
|
|||
|
FOR i := 1 TO Size DO
|
|||
|
begin
|
|||
|
{Compare booth bytes}
|
|||
|
if P1^ <> P2^ then
|
|||
|
begin
|
|||
|
Result := FALSE;
|
|||
|
Exit;
|
|||
|
end; {if P1^ <> P2^}
|
|||
|
{Move to next byte}
|
|||
|
Inc(P1); Inc(P2);
|
|||
|
end {FOR i}
|
|||
|
end {function};
|
|||
|
{$ENDIF}
|
|||
|
|
|||
|
{$IFDEF DONTUSEVCL}
|
|||
|
function IntToStr(Value: Integer): String;
|
|||
|
begin
|
|||
|
Str(Value, Result);
|
|||
|
end;
|
|||
|
{$ENDIF}
|
|||
|
|
|||
|
{$IFDEF DONTUSEVCL}
|
|||
|
function StrToIntDef(Value: String; Default: Integer): Integer;
|
|||
|
var Code: Integer;
|
|||
|
begin
|
|||
|
{Try converting from string to integer}
|
|||
|
Val(Value, Result, Code);
|
|||
|
{If any error ocurred, returns default value}
|
|||
|
if Code <> 0 then Result := Default;
|
|||
|
end;
|
|||
|
{$ENDIF}
|
|||
|
|
|||
|
|
|||
|
{Convert from extended to Fix32}
|
|||
|
function FloatToFix32 (floater: extended): TW_FIX32;
|
|||
|
var
|
|||
|
fracpart : extended;
|
|||
|
begin
|
|||
|
//Obtain numerical part by truncating the float number
|
|||
|
Result.Whole := trunc(floater);
|
|||
|
//Obtain fracional part by subtracting float number by
|
|||
|
//numerical part. Also we make sure the number is not
|
|||
|
//negative by multipling by -1 if it is negative
|
|||
|
fracpart := floater - result.Whole;
|
|||
|
if fracpart < 0 then fracpart := fracpart * -1;
|
|||
|
//Multiply by 10 until there is no fracional part any longer
|
|||
|
while FracPart - trunc(FracPart) <> 0 do fracpart := fracpart * 10;
|
|||
|
//Return fracional part
|
|||
|
Result.Frac := trunc(fracpart);
|
|||
|
end;
|
|||
|
|
|||
|
{Convert from twain Fix32 to extended}
|
|||
|
function Fix32ToFloat(Value: TW_FIX32): Extended;
|
|||
|
begin
|
|||
|
Result := Value.Whole + (Value.Frac / 65536.0);
|
|||
|
end;
|
|||
|
|
|||
|
{Returns the last position for any of the characters in the parameter}
|
|||
|
function LastPosition(const Text, characters: String): Integer;
|
|||
|
var
|
|||
|
x, y: Integer; {For loop variables}
|
|||
|
begin
|
|||
|
Result := Length(Text); {Initial result}
|
|||
|
|
|||
|
{Search each character in the text}
|
|||
|
FOR x := 1 TO Length(Text) DO
|
|||
|
begin
|
|||
|
{Test for each character}
|
|||
|
FOR y := 1 TO Length(characters) DO
|
|||
|
if Text[x] = characters[y] then
|
|||
|
Result := x;
|
|||
|
end {for x}
|
|||
|
end;
|
|||
|
|
|||
|
{Extracts the file directory}
|
|||
|
function ExtractDirectory(const FilePath: String): String;
|
|||
|
begin
|
|||
|
{Searches for the last \ or : characters}
|
|||
|
{ex: c:\windows\system32\yfile.ext or c:autoexec.bat}
|
|||
|
Result := Copy(FilePath, 1, LastPosition(FilePath, '\:'));
|
|||
|
end;
|
|||
|
|
|||
|
{Returns if the file exists}
|
|||
|
function FileExists(const FilePath: String): Boolean;
|
|||
|
var
|
|||
|
FindData : TWin32FindData;
|
|||
|
FindHandle: THandle;
|
|||
|
begin
|
|||
|
{Searches for the file}
|
|||
|
FindHandle := FindFirstFile(PChar(FilePath), FindData);
|
|||
|
Result := (FindHandle <> INVALID_HANDLE_VALUE);
|
|||
|
{In case it found, closes the FindFirstFile handle}
|
|||
|
if Result then FindClose(FindHandle);
|
|||
|
end;
|
|||
|
|
|||
|
{Returns if the directory exists}
|
|||
|
function DirectoryExists(const Directory: String): Boolean;
|
|||
|
var
|
|||
|
Attr: DWORD;
|
|||
|
begin
|
|||
|
{Calls GetFileAttributes to verify}
|
|||
|
Attr := GetFileAttributes(PChar(Directory));
|
|||
|
Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY <> 0);
|
|||
|
end;
|
|||
|
|
|||
|
{Makes an language identifier using the two ids}
|
|||
|
function MAKELANGID(p, s: WORD): DWORD;
|
|||
|
begin
|
|||
|
Result := (s shl 10) or p;
|
|||
|
end;
|
|||
|
|
|||
|
{Returns the last error string from Microsoft Windows<77>}}
|
|||
|
function GetLastErrorText(): String;
|
|||
|
var
|
|||
|
Buffer: Array[Byte] of Char;
|
|||
|
Len : DWORD;
|
|||
|
begin
|
|||
|
{Calls format message to translate from the error code ID to}
|
|||
|
{a text understandable error}
|
|||
|
Len := Windows.FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
|
|||
|
FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, GetLastError(),
|
|||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), Buffer, sizeof(Buffer), nil);
|
|||
|
{Remove this chars from the ending of the result}
|
|||
|
while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
|
|||
|
{Fills result}
|
|||
|
SetString(Result, Buffer, Len);
|
|||
|
end;
|
|||
|
|
|||
|
{Includes a trailing backslash in the end of the directory; if necessary}
|
|||
|
procedure IncludeTrailingBackslash(var Directory: String);
|
|||
|
begin
|
|||
|
{If there isn't already a backslash, add one}
|
|||
|
if Directory[Length(Directory)] <> '\' then
|
|||
|
Directory := Directory + '\'
|
|||
|
end;
|
|||
|
|
|||
|
{Returns custom Microsoft Windows<77> directories}
|
|||
|
function GetCustomDirectory(const DirectoryKind: TDirectoryKind): String;
|
|||
|
const
|
|||
|
{Default maximum size for directories}
|
|||
|
DEF_DIRLEN = MAX_PATH;
|
|||
|
|
|||
|
{Calls appropriate method and returns necessary size}
|
|||
|
function CallDirectoryMethod(Buffer: Pointer; Size: UINT): UINT;
|
|||
|
begin
|
|||
|
{Test the directory needed by the parameter}
|
|||
|
case DirectoryKind of
|
|||
|
{Windows directory}
|
|||
|
dkWindows: Result := Windows.GetWindowsDirectory(Buffer, Size);
|
|||
|
{System directory}
|
|||
|
dkSystem : Result := Windows.GetSystemDirectory(Buffer, Size);
|
|||
|
{Current directory}
|
|||
|
dkCurrent: Result := Windows.GetCurrentDirectory(Size, Buffer);
|
|||
|
{Application directory}
|
|||
|
dkApplication: Result := Windows.GetModuleFileName(0, Buffer, Size);
|
|||
|
{Temp directory}
|
|||
|
dkTemp : Result := Windows.GetTempPath(Size, Buffer);
|
|||
|
{Unknown directory}
|
|||
|
else Result := 0;
|
|||
|
end {case}
|
|||
|
end;
|
|||
|
|
|||
|
var
|
|||
|
DirectoryLen: UINT;
|
|||
|
begin
|
|||
|
{Set length of the resulting buffer to MAX_PATH to try to hold}
|
|||
|
{windows directory}
|
|||
|
SetLength(Result, DEF_DIRLEN + 1);
|
|||
|
{Tries to obtain the windows directory and stores the size}
|
|||
|
DirectoryLen := CallDirectoryMethod(@Result[1], DEF_DIRLEN);
|
|||
|
|
|||
|
{In case it was not enough to hold windows directory, enlarge}
|
|||
|
if DirectoryLen > DEF_DIRLEN then
|
|||
|
begin
|
|||
|
{Try again, now with the right size}
|
|||
|
SetLength(Result, DirectoryLen + 1);
|
|||
|
CallDirectoryMethod(@Result[1], DirectoryLen);
|
|||
|
end
|
|||
|
else {Otherwise, adjust the result to excluded unused data}
|
|||
|
SetLength(Result, DirectoryLen);
|
|||
|
|
|||
|
{In case the user searched for the application directory}
|
|||
|
{extracts just the directory part}
|
|||
|
if DirectoryKind = dkApplication then
|
|||
|
Result := ExtractDirectory(Result);
|
|||
|
{Add a trailing backslash to end of the directory name}
|
|||
|
IncludeTrailingBackslash(Result);
|
|||
|
end;
|
|||
|
|
|||
|
{ TPointerList object implementation }
|
|||
|
|
|||
|
{Add a new item}
|
|||
|
procedure TPointerList.Add(Value: Pointer);
|
|||
|
begin
|
|||
|
{Increase number of items and update new item}
|
|||
|
Count := Count + 1;
|
|||
|
Item[Count - 1] := Value;
|
|||
|
end;
|
|||
|
|
|||
|
{Clear all the items in the list}
|
|||
|
procedure TPointerList.Clear;
|
|||
|
begin
|
|||
|
{Set number of items to 0 and initialize again allocated items}
|
|||
|
Count := 0;
|
|||
|
Allocated := AdditionalBlock;
|
|||
|
end;
|
|||
|
|
|||
|
{TPointerList being created}
|
|||
|
constructor TPointerList.Create;
|
|||
|
begin
|
|||
|
{Let ancestor receive the call}
|
|||
|
inherited Create;
|
|||
|
|
|||
|
{Allocate a number of items}
|
|||
|
fAdditionalBlock := 10;
|
|||
|
fAllocated := fAdditionalBlock;
|
|||
|
GetMem(Data, (fAllocated * sizeof(Pointer)));
|
|||
|
end;
|
|||
|
|
|||
|
{TPointerList being destroyed}
|
|||
|
destructor TPointerList.Destroy;
|
|||
|
begin
|
|||
|
{Deallocate data}
|
|||
|
FreeMem(Data, (fAllocated * sizeof(Pointer)));
|
|||
|
|
|||
|
{Let ancestor receive and finish}
|
|||
|
inherited Destroy;
|
|||
|
end;
|
|||
|
|
|||
|
{Returns an item from the list}
|
|||
|
function TPointerList.GetItem(Index: Integer): Pointer;
|
|||
|
begin
|
|||
|
{Check item bounds and return item}
|
|||
|
if Index in [0..Count - 1] then
|
|||
|
Longint(Result) := pLongint(Longint(Data) + (Index * sizeof(Pointer)))^
|
|||
|
else Result := nil; {Otherwise returns nil}
|
|||
|
end;
|
|||
|
|
|||
|
{Sets an item from the list}
|
|||
|
procedure TPointerList.PutItem(Index: Integer; const Value: Pointer);
|
|||
|
begin
|
|||
|
{Check item bounds and sets item}
|
|||
|
if Index in [0..Count - 1] then
|
|||
|
pLongint(Longint(Data) + (Index * sizeof(Pointer)))^ := Longint(Value);
|
|||
|
end;
|
|||
|
|
|||
|
{Sets the AdditionalBlock property}
|
|||
|
procedure TPointerList.SetAdditionalBlock(const Value: Integer);
|
|||
|
begin
|
|||
|
{Value must be a positive number greater than 0}
|
|||
|
if (Value > 0) then
|
|||
|
fAdditionalBlock := Value;
|
|||
|
end;
|
|||
|
|
|||
|
{Allocate/deallocate memory to have enough memory to hold}
|
|||
|
{the new number of items}
|
|||
|
procedure TPointerList.SetAllocated(const Value: Integer);
|
|||
|
begin
|
|||
|
{Must be always greater than 0 the number of allocated items}
|
|||
|
{And it also should not be smaller than count}
|
|||
|
if (Value > 0) and (Value <= Count) then
|
|||
|
begin
|
|||
|
{Just realloc memory and update property variable}
|
|||
|
ReallocMem(Data, (Value * sizeof(Pointer)));
|
|||
|
fAllocated := Value;
|
|||
|
end {if (Value <> 0)}
|
|||
|
end;
|
|||
|
|
|||
|
{Set the number of items in the list}
|
|||
|
procedure TPointerList.SetCount(const Value: Integer);
|
|||
|
begin
|
|||
|
{Value must be 0 or greater}
|
|||
|
if (Value >= 0) then
|
|||
|
begin
|
|||
|
{If there is no more memory to hold data, allocate some more}
|
|||
|
while (Value > fAllocated) do
|
|||
|
Allocated := Allocated + fAdditionalBlock;
|
|||
|
{Update property}
|
|||
|
fCount := Value;
|
|||
|
end {if (Value >= 0)}
|
|||
|
end;
|
|||
|
|
|||
|
end.
|