-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathrpdeltwainutils.pas
379 lines (337 loc) · 11.2 KB
/
rpdeltwainutils.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
{GENERAL METHODS USED BY TWAIN DELPHI}
{december 2001®, 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 rpdeltwainutils;
{$INCLUDE rpdeltwain.INC}
interface
uses
rptwain;
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® directories}
function GetCustomDirectory(const DirectoryKind: TDirectoryKind): String;
{Returns the last error string from Microsoft Windows®}
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®}
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® 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.