2 {*******************************************************} // XCL version of System
\r
3 { } // unit. Created Jun-2000
\r
4 { Borland Delphi Runtime Library } // (C) by Kladov Vladimir
\r
6 { } // purpose: make XCL Delphi
\r
7 { Copyright (C) 1988,99 Inprise Corporation } // programs even smaller.
\r
9 {*******************************************************} // Changes are marked as {X}
\r
11 unit System; { Predefined constants, types, procedures, }
\r
12 { and functions (such as True, Integer, or }
\r
13 { Writeln) do not have actual declarations.}
\r
14 { Instead they are built into the compiler }
\r
15 { and are treated as if they were declared }
\r
16 { at the beginning of the System unit. }
\r
20 { L- should never be specified.
\r
22 The IDE needs to find debug hook (through the C++
\r
23 compiler sometimes) for integrated debugging to
\r
26 ILINK will generate debug info for DebugHook if
\r
27 the object module has not been compiled with debug info.
\r
29 ILINK will not generate debug info for DebugHook if
\r
30 the object module has been compiled with debug info.
\r
32 Thus, the Pascal compiler must be responsible for
\r
33 generating the debug information for that symbol
\r
34 when a debug-enabled object file is produced.
\r
41 { Variant type codes (wtypes.h) }
\r
43 varEmpty = $0000; { vt_empty }
\r
44 varNull = $0001; { vt_null }
\r
45 varSmallint = $0002; { vt_i2 }
\r
46 varInteger = $0003; { vt_i4 }
\r
47 varSingle = $0004; { vt_r4 }
\r
48 varDouble = $0005; { vt_r8 }
\r
49 varCurrency = $0006; { vt_cy }
\r
50 varDate = $0007; { vt_date }
\r
51 varOleStr = $0008; { vt_bstr }
\r
52 varDispatch = $0009; { vt_dispatch }
\r
53 varError = $000A; { vt_error }
\r
54 varBoolean = $000B; { vt_bool }
\r
55 varVariant = $000C; { vt_variant }
\r
56 varUnknown = $000D; { vt_unknown }
\r
60 varByte = $0011; { vt_ui1 }
\r
64 { if adding new items, update varLast, BaseTypeMap and OpTypeMap }
\r
65 varStrArg = $0048; { vt_clsid }
\r
66 varString = $0100; { Pascal string; not OLE compatible }
\r
68 varTypeMask = $0FFF;
\r
72 { TVarRec.VType values }
\r
92 { Virtual method table entries }
\r
99 vmtFieldTable = -56;
\r
100 vmtMethodTable = -52;
\r
101 vmtDynamicTable = -48;
\r
102 vmtClassName = -44;
\r
103 vmtInstanceSize = -40;
\r
105 vmtSafeCallException = -32;
\r
106 vmtAfterConstruction = -28;
\r
107 vmtBeforeDestruction = -24;
\r
109 vmtDefaultHandler = -16;
\r
110 vmtNewInstance = -12;
\r
111 vmtFreeInstance = -8;
\r
114 vmtQueryInterface = 0;
\r
117 vmtCreateObject = 12;
\r
123 TClass = class of TObject;
\r
125 {$EXTERNALSYM HRESULT}
\r
126 HRESULT = type Longint; { from WTYPES.H }
\r
128 {$EXTERNALSYM IUnknown}
\r
129 {$EXTERNALSYM IDispatch}
\r
132 TGUID = packed record
\r
136 D4: array[0..7] of Byte;
\r
139 PInterfaceEntry = ^TInterfaceEntry;
\r
140 TInterfaceEntry = packed record
\r
144 ImplGetter: Integer;
\r
147 PInterfaceTable = ^TInterfaceTable;
\r
148 TInterfaceTable = packed record
\r
149 EntryCount: Integer;
\r
150 Entries: array[0..9999] of TInterfaceEntry;
\r
154 constructor Create;
\r
156 class function InitInstance(Instance: Pointer): TObject;
\r
157 procedure CleanupInstance;
\r
158 function ClassType: TClass;
\r
159 class function ClassName: ShortString;
\r
160 class function ClassNameIs(const Name: string): Boolean;
\r
161 class function ClassParent: TClass;
\r
162 class function ClassInfo: Pointer;
\r
163 class function InstanceSize: Longint;
\r
164 class function InheritsFrom(AClass: TClass): Boolean;
\r
165 class function MethodAddress(const Name: ShortString): Pointer;
\r
166 class function MethodName(Address: Pointer): ShortString;
\r
167 function FieldAddress(const Name: ShortString): Pointer;
\r
168 function GetInterface(const IID: TGUID; out Obj): Boolean;
\r
169 class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
\r
170 class function GetInterfaceTable: PInterfaceTable;
\r
171 function SafeCallException(ExceptObject: TObject;
\r
172 ExceptAddr: Pointer): HResult; virtual;
\r
173 procedure AfterConstruction; virtual;
\r
174 procedure BeforeDestruction; virtual;
\r
175 procedure Dispatch(var Message); virtual;
\r
176 procedure DefaultHandler(var Message); virtual;
\r
177 class function NewInstance: TObject; virtual;
\r
178 procedure FreeInstance; virtual;
\r
179 destructor Destroy; virtual;
\r
182 IUnknown = interface
\r
183 ['{00000000-0000-0000-C000-000000000046}']
\r
184 function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
\r
185 function _AddRef: Integer; stdcall;
\r
186 function _Release: Integer; stdcall;
\r
189 IDispatch = interface(IUnknown)
\r
190 ['{00020400-0000-0000-C000-000000000046}']
\r
191 function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
\r
192 function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
\r
193 function GetIDsOfNames(const IID: TGUID; Names: Pointer;
\r
194 NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
\r
195 function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
\r
196 Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
\r
199 TInterfacedObject = class(TObject, IUnknown)
\r
201 FRefCount: Integer;
\r
202 function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
\r
203 function _AddRef: Integer; stdcall;
\r
204 function _Release: Integer; stdcall;
\r
206 procedure AfterConstruction; override;
\r
207 procedure BeforeDestruction; override;
\r
208 class function NewInstance: TObject; override;
\r
209 property RefCount: Integer read FRefCount;
\r
212 TInterfacedClass = class of TInterfacedObject;
\r
214 TVarArrayBound = packed record
\r
215 ElementCount: Integer;
\r
219 PVarArray = ^TVarArray;
\r
220 TVarArray = packed record
\r
223 ElementSize: Integer;
\r
224 LockCount: Integer;
\r
226 Bounds: array[0..255] of TVarArrayBound;
\r
229 PVarData = ^TVarData;
\r
230 TVarData = packed record
\r
232 Reserved1, Reserved2, Reserved3: Word;
\r
234 varSmallint: (VSmallint: Smallint);
\r
235 varInteger: (VInteger: Integer);
\r
236 varSingle: (VSingle: Single);
\r
237 varDouble: (VDouble: Double);
\r
238 varCurrency: (VCurrency: Currency);
\r
239 varDate: (VDate: Double);
\r
240 varOleStr: (VOleStr: PWideChar);
\r
241 varDispatch: (VDispatch: Pointer);
\r
242 varError: (VError: LongWord);
\r
243 varBoolean: (VBoolean: WordBool);
\r
244 varUnknown: (VUnknown: Pointer);
\r
245 varByte: (VByte: Byte);
\r
246 varString: (VString: Pointer);
\r
247 varAny: (VAny: Pointer);
\r
248 varArray: (VArray: PVarArray);
\r
249 varByRef: (VPointer: Pointer);
\r
252 PShortString = ^ShortString;
\r
253 PAnsiString = ^AnsiString;
\r
254 PWideString = ^WideString;
\r
255 PString = PAnsiString;
\r
257 PExtended = ^Extended;
\r
258 PCurrency = ^Currency;
\r
259 PVariant = ^Variant;
\r
260 POleVariant = ^OleVariant;
\r
263 TDateTime = type Double;
\r
264 PDateTime = ^TDateTime;
\r
266 PVarRec = ^TVarRec;
\r
267 TVarRec = record { do not pack this record; it is compiler-generated }
\r
269 vtInteger: (VInteger: Integer; VType: Byte);
\r
270 vtBoolean: (VBoolean: Boolean);
\r
271 vtChar: (VChar: Char);
\r
272 vtExtended: (VExtended: PExtended);
\r
273 vtString: (VString: PShortString);
\r
274 vtPointer: (VPointer: Pointer);
\r
275 vtPChar: (VPChar: PChar);
\r
276 vtObject: (VObject: TObject);
\r
277 vtClass: (VClass: TClass);
\r
278 vtWideChar: (VWideChar: WideChar);
\r
279 vtPWideChar: (VPWideChar: PWideChar);
\r
280 vtAnsiString: (VAnsiString: Pointer);
\r
281 vtCurrency: (VCurrency: PCurrency);
\r
282 vtVariant: (VVariant: PVariant);
\r
283 vtInterface: (VInterface: Pointer);
\r
284 vtWideString: (VWideString: Pointer);
\r
285 vtInt64: (VInt64: PInt64);
\r
288 PMemoryManager = ^TMemoryManager;
\r
289 TMemoryManager = record
\r
290 GetMem: function(Size: Integer): Pointer;
\r
291 FreeMem: function(P: Pointer): Integer;
\r
292 ReallocMem: function(P: Pointer; Size: Integer): Pointer;
\r
295 THeapStatus = record
\r
296 TotalAddrSpace: Cardinal;
\r
297 TotalUncommitted: Cardinal;
\r
298 TotalCommitted: Cardinal;
\r
299 TotalAllocated: Cardinal;
\r
300 TotalFree: Cardinal;
\r
301 FreeSmall: Cardinal;
\r
304 Overhead: Cardinal;
\r
305 HeapErrorCode: Cardinal;
\r
308 PackageUnitEntry = packed record
\r
309 Init, FInit : procedure;
\r
312 { Compiler generated table to be processed sequentially to init & finit all package units }
\r
313 { Init: 0..Max-1; Final: Last Initialized..0 }
\r
314 UnitEntryTable = array [0..9999999] of PackageUnitEntry;
\r
315 PUnitEntryTable = ^UnitEntryTable;
\r
317 PackageInfoTable = packed record
\r
318 UnitCount : Integer; { number of entries in UnitInfo array; always > 0 }
\r
319 UnitInfo : PUnitEntryTable;
\r
322 PackageInfo = ^PackageInfoTable;
\r
324 { Each package exports a '@GetPackageInfoTable' which can be used to retrieve }
\r
325 { the table which contains compiler generated information about the package DLL }
\r
326 GetPackageInfoTable = function : PackageInfo;
\r
333 advapi32 = 'advapi32.dll';
\r
334 kernel = 'kernel32.dll';
\r
335 user = 'user32.dll';
\r
336 oleaut = 'oleaut32.dll';
\r
338 {X+ moved here from SysInit.pas - by advise of Alexey Torgashin - to avoid
\r
339 creating of separate import block from kernel32.dll : }
\r
340 //////////////////////////////////////////////////////////////////////////
\r
342 function FreeLibrary(ModuleHandle: Longint): LongBool; stdcall;
\r
343 external kernel name 'FreeLibrary';
\r
345 function GetModuleFileName(Module: Integer; Filename: PChar; Size: Integer): Integer; stdcall;
\r
346 external kernel name 'GetModuleFileNameA';
\r
348 function GetModuleHandle(ModuleName: PChar): Integer; stdcall;
\r
349 external kernel name 'GetModuleHandleA';
\r
351 function LocalAlloc(flags, size: Integer): Pointer; stdcall;
\r
352 external kernel name 'LocalAlloc';
\r
354 function LocalFree(addr: Pointer): Pointer; stdcall;
\r
355 external kernel name 'LocalFree';
\r
357 function TlsAlloc: Integer; stdcall;
\r
358 external kernel name 'TlsAlloc';
\r
360 function TlsFree(TlsIndex: Integer): Boolean; stdcall;
\r
361 external kernel name 'TlsFree';
\r
363 function TlsGetValue(TlsIndex: Integer): Pointer; stdcall;
\r
364 external kernel name 'TlsGetValue';
\r
366 function TlsSetValue(TlsIndex: Integer; TlsValue: Pointer): Boolean; stdcall;
\r
367 external kernel name 'TlsSetValue';
\r
369 function GetCommandLine: PChar; stdcall;
\r
370 external kernel name 'GetCommandLineA';
\r
372 {X-}//////////////////////////////////////////////////////////////////////
\r
376 {X} // following two procedures are optional and exclusive.
\r
377 {X} // call it to provide error message: first - for GUI app,
\r
378 {X} // second - for console app.
\r
379 {X} procedure UseErrorMessageBox;
\r
380 {X} procedure UseErrorMessageWrite;
\r
382 {X} // call following procedure to initialize Input and Output
\r
383 {X} // - for console app only:
\r
384 {X} procedure UseInputOutput;
\r
386 {X} // if your app uses FPU, call one of following procedures:
\r
387 {X} procedure FpuInit;
\r
388 {X} procedure FpuInitConsiderNECWindows;
\r
389 {X} // the second additionally takes into consideration NEC
\r
390 {X} // Windows keyboard (Japaneeze keyboard ???).
\r
392 {X} // following variables are converted to a functions:
\r
393 {X} function CmdShow : Integer;
\r
394 {X} function CmdLine : PChar;
\r
396 {X} procedure VarCastError;
\r
397 {X} procedure VarInvalidOp;
\r
399 {X} procedure DummyProc; // empty procedure
\r
401 {X} procedure VariantAddRef;
\r
402 {X} // procedure to refer to _VarAddRef if SysVarnt.pas is in use
\r
403 {X} var VarAddRefProc : procedure = DummyProc;
\r
405 {X} procedure VariantClr;
\r
406 {X} // procedure to refer to _VarClr if SysVarnt.pas is in use
\r
407 {X} var VarClrProc : procedure = DummyProc;
\r
409 {X} procedure WStrAddRef;
\r
410 {X} // procedure to refer to _WStrAddRef if SysWStr.pas is in use
\r
411 {X} var WStrAddRefProc : procedure = DummyProc;
\r
413 {X} procedure WStrClr;
\r
414 {X} // procedure to refer to _WStrClr if SysWStr.pas is in use
\r
415 {X} var WStrClrProc : procedure = DummyProc;
\r
417 {X} procedure WStrArrayClr;
\r
418 {X} // procedure to refer to _WStrArrayClr if SysWStr.pas is in use
\r
419 {X} var WStrArrayClrProc : procedure = DummyProc;
\r
421 {X} // By default, now system memory management routines are used
\r
422 {X} // to allocate memory. This can be slow sometimes, so if You
\r
423 {X} // want to use custom Borland Delphi memory manager, call follow:
\r
424 {X} procedure UseDelphiMemoryManager;
\r
425 {X} function IsDelphiMemoryManagerSet : Boolean;
\r
426 {X} function MemoryManagerNotUsed : Boolean;
\r
428 {X} // Standard Delphi units initialization/finalization uses
\r
429 {X} // try-except and raise constructions, which leads to permanent
\r
430 {X} // usage of all exception handling routines. In this XCL-aware
\r
431 {X} // implementation, "light" version of initialization/finalization
\r
432 {X} // is used by default. To use standard Delphi initialization and
\r
433 {X} // finalization method, allowing to flow execution control even
\r
434 {X} // in initalization sections, include reference to SysSfIni.pas
\r
435 {X} // into uses clause *as first as possible*.
\r
436 {X} procedure InitUnitsLight( Table : PUnitEntryTable; Idx, Count : Integer );
\r
437 {X} procedure InitUnitsHard( Table : PUnitEntryTable; Idx, Count : Integer );
\r
438 {X} var InitUnitsProc : procedure( Table : PUnitEntryTable; Idx, Count : Integer )
\r
439 {X} = InitUnitsLight;
\r
440 {X} procedure FInitUnitsLight;
\r
441 {X} procedure FInitUnitsHard;
\r
442 {X} var FInitUnitsProc : procedure = FInitUnitsLight;
\r
443 {X} procedure SetExceptionHandler;
\r
444 {X} procedure UnsetExceptionHandler;
\r
445 {X} var UnsetExceptionHandlerProc : procedure = DummyProc;
\r
447 {X} var UnloadResProc: procedure = DummyProc;
\r
453 function RaiseList: Pointer; { Stack of current exception objects }
\r
454 function SetRaiseList(NewPtr: Pointer): Pointer; { returns previous value }
\r
455 procedure SetInOutRes(NewValue: Integer);
\r
459 ExceptProc: Pointer; { Unhandled exception handler }
\r
460 ErrorProc: Pointer; { Error handler procedure }
\r
461 ExceptClsProc: Pointer; { Map an OS Exception to a Delphi class reference }
\r
462 ExceptObjProc: Pointer; { Map an OS Exception to a Delphi class instance }
\r
463 ExceptionClass: TClass; { Exception base class (must be Exception) }
\r
464 SafeCallErrorProc: Pointer; { Safecall error handler }
\r
465 AssertErrorProc: Pointer; { Assertion error handler }
\r
466 AbstractErrorProc: Pointer; { Abstract method error handler }
\r
467 HPrevInst: LongWord; { Handle of previous instance - HPrevInst cannot be tested for multiple instances in Win32}
\r
468 MainInstance: LongWord; { Handle of the main(.EXE) HInstance }
\r
469 MainThreadID: LongWord; { ThreadID of thread that module was initialized in }
\r
470 IsLibrary: Boolean; { True if module is a DLL }
\r
471 {X CmdShow: Integer; { CmdShow parameter for CreateWindow - converted to a function X}
\r
472 {X CmdLine: PChar; { Command line pointer - converted to a function X}
\r
473 InitProc: Pointer; { Last installed initialization procedure }
\r
474 ExitCode: Integer; { Program result }
\r
475 ExitProc: Pointer; { Last installed exit procedure }
\r
476 ErrorAddr: Pointer; { Address of run-time error }
\r
477 RandSeed: Longint; { Base for random number generator }
\r
478 IsConsole: Boolean; { True if compiled as console app }
\r
479 IsMultiThread: Boolean; { True if more than one thread }
\r
480 FileMode: Byte {X} = 2; { Standard mode for opening files }
\r
481 Test8086: Byte {X} = 2; { Will always be 2 (386 or later) }
\r
482 Test8087: Byte {X} = 3; { Will always be 3 (387 or later) }
\r
483 TestFDIV: Shortint; { -1: Flawed Pentium, 0: Not determined, 1: Ok }
\r
484 Input: Text; { Standard input }
\r
485 Output: Text; { Standard output }
\r
487 ClearAnyProc: Pointer; { Handler clearing a varAny }
\r
488 ChangeAnyProc: Pointer; { Handler to change any to variant }
\r
489 RefAnyProc: Pointer; { Handler to add a reference to an varAny }
\r
492 Default8087CW: Word = $1332;{ Default 8087 control word. FPU control
\r
493 register is set to this value.
\r
494 CAUTION: Setting this to an invalid value
\r
495 could cause unpredictable behavior. }
\r
497 HeapAllocFlags: Word = 2; { Heap allocation flags, gmem_Moveable }
\r
498 DebugHook: Byte = 0; { 1 to notify debugger of non-Delphi exceptions
\r
499 >1 to notify debugger of exception unwinding }
\r
500 JITEnable: Byte = 0; { 1 to call UnhandledExceptionFilter if the exception
\r
501 is not a Pascal exception.
\r
502 >1 to call UnhandledExceptionFilter for all exceptions }
\r
503 NoErrMsg: Boolean = False; { True causes the base RTL to not display the message box
\r
504 when a run-time error occurs }
\r
507 (* {X-} moved to SysVarnt.pas
\r
509 Unassigned: Variant; { Unassigned standard constant }
\r
510 Null: Variant; { Null standard constant }
\r
511 EmptyParam: OleVariant; { "Empty parameter" standard constant which can be
\r
512 passed as an optional parameter on a dual interface. }
\r
515 AllocMemCount: Integer; { Number of allocated memory blocks }
\r
516 AllocMemSize: Integer; { Total size of allocated memory blocks }
\r
518 { Memory manager support }
\r
520 procedure GetMemoryManager(var MemMgr: TMemoryManager);
\r
521 procedure SetMemoryManager(const MemMgr: TMemoryManager);
\r
522 {X} // following function is replaced with pointer to one
\r
523 {X} // (initialized by another)
\r
524 {X} //function IsMemoryManagerSet: Boolean;
\r
525 var IsMemoryManagerSet : function : Boolean = MemoryManagerNotUsed;
\r
527 function SysGetMem(Size: Integer): Pointer;
\r
528 function SysFreeMem(P: Pointer): Integer;
\r
529 function SysReallocMem(P: Pointer; Size: Integer): Pointer;
\r
531 function GetHeapStatus: THeapStatus;
\r
535 TThreadFunc = function(Parameter: Pointer): Integer;
\r
537 function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
\r
538 ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
\r
539 var ThreadId: LongWord): Integer;
\r
541 procedure EndThread(ExitCode: Integer);
\r
543 { Standard procedures and functions }
\r
545 procedure _ChDir(const S: string);
\r
546 procedure __Flush(var F: Text);
\r
547 procedure _LGetDir(D: Byte; var S: string);
\r
548 procedure _SGetDir(D: Byte; var S: ShortString);
\r
549 function IOResult: Integer;
\r
550 procedure _MkDir(const S: string);
\r
551 procedure Move(const Source; var Dest; Count: Integer);
\r
552 function ParamCount: Integer;
\r
553 function ParamStr(Index: Integer): string;
\r
554 procedure Randomize;
\r
555 procedure _RmDir(const S: string);
\r
556 function UpCase(Ch: Char): Char;
\r
558 { Control 8087 control word }
\r
560 procedure Set8087CW(NewCW: Word);
\r
562 { Wide character support procedures and functions }
\r
564 function WideCharToString(Source: PWideChar): string;
\r
565 function WideCharLenToString(Source: PWideChar; SourceLen: Integer): string;
\r
566 procedure WideCharToStrVar(Source: PWideChar; var Dest: string);
\r
567 procedure WideCharLenToStrVar(Source: PWideChar; SourceLen: Integer;
\r
569 function StringToWideChar(const Source: string; Dest: PWideChar;
\r
570 DestSize: Integer): PWideChar;
\r
572 { OLE string support procedures and functions }
\r
574 function OleStrToString(Source: PWideChar): string;
\r
575 procedure OleStrToStrVar(Source: PWideChar; var Dest: string);
\r
576 function StringToOleStr(const Source: string): PWideChar;
\r
578 { Variant support procedures and functions }
\r
580 procedure _VarClear(var V : Variant);
\r
581 procedure _VarCopy(var Dest : Variant; const Source: Variant);
\r
582 procedure _VarCast(var Dest : Variant; const Source: Variant; VarType: Integer);
\r
583 procedure _VarCastOle(var Dest : Variant; const Source: Variant; VarType: Integer);
\r
584 procedure VarCopyNoInd(var Dest: Variant; const Source: Variant);
\r
585 function VarType(const V: Variant): Integer;
\r
586 function VarAsType(const V: Variant; VarType: Integer): Variant;
\r
587 function VarIsEmpty(const V: Variant): Boolean;
\r
588 function VarIsNull(const V: Variant): Boolean;
\r
589 function VarToStr(const V: Variant): string;
\r
590 function VarFromDateTime(DateTime: TDateTime): Variant;
\r
591 function VarToDateTime(const V: Variant): TDateTime;
\r
593 { Variant array support procedures and functions }
\r
595 function VarArrayCreate(const Bounds: array of Integer;
\r
596 VarType: Integer): Variant;
\r
597 function VarArrayOf(const Values: array of Variant): Variant;
\r
598 procedure _VarArrayRedim(var A : Variant; HighBound: Integer);
\r
599 function VarArrayDimCount(const A: Variant): Integer;
\r
600 function VarArrayLowBound(const A: Variant; Dim: Integer): Integer;
\r
601 function VarArrayHighBound(const A: Variant; Dim: Integer): Integer;
\r
602 function VarArrayLock(const A: Variant): Pointer;
\r
603 procedure VarArrayUnlock(const A: Variant);
\r
604 function VarArrayRef(const A: Variant): Variant;
\r
605 function VarIsArray(const A: Variant): Boolean;
\r
607 { Variant IDispatch call support }
\r
609 procedure _DispInvokeError;
\r
612 VarDispProc: Pointer = @_DispInvokeError;
\r
613 DispCallByIDProc: Pointer = @_DispInvokeError;
\r
615 { Package/Module registration and unregistration }
\r
618 PLibModule = ^TLibModule;
\r
619 TLibModule = record
\r
621 Instance: LongWord;
\r
622 CodeInstance: LongWord;
\r
623 DataInstance: LongWord;
\r
624 ResInstance: LongWord;
\r
628 TEnumModuleFunc = function (HInstance: Integer; Data: Pointer): Boolean;
\r
629 {$EXTERNALSYM TEnumModuleFunc}
\r
630 TEnumModuleFuncLW = function (HInstance: LongWord; Data: Pointer): Boolean;
\r
631 {$EXTERNALSYM TEnumModuleFuncLW}
\r
632 TModuleUnloadProc = procedure (HInstance: Integer);
\r
633 {$EXTERNALSYM TModuleUnloadProc}
\r
634 TModuleUnloadProcLW = procedure (HInstance: LongWord);
\r
635 {$EXTERNALSYM TModuleUnloadProcLW}
\r
637 PModuleUnloadRec = ^TModuleUnloadRec;
\r
638 TModuleUnloadRec = record
\r
639 Next: PModuleUnloadRec;
\r
640 Proc: TModuleUnloadProcLW;
\r
644 LibModuleList: PLibModule = nil;
\r
645 ModuleUnloadList: PModuleUnloadRec = nil;
\r
647 procedure RegisterModule(LibModule: PLibModule);
\r
648 {X procedure UnregisterModule(LibModule: PLibModule); -replaced with pointer to procedure }
\r
649 {X} procedure UnregisterModuleLight(LibModule: PLibModule);
\r
650 {X} procedure UnregisterModuleSafely(LibModule: PLibModule);
\r
651 var UnregisterModule : procedure(LibModule: PLibModule) = UnregisterModuleLight;
\r
652 function FindHInstance(Address: Pointer): LongWord;
\r
653 function FindClassHInstance(ClassType: TClass): LongWord;
\r
654 function FindResourceHInstance(Instance: LongWord): LongWord;
\r
655 function LoadResourceModule(ModuleName: PChar): LongWord;
\r
656 procedure EnumModules(Func: TEnumModuleFunc; Data: Pointer); overload;
\r
657 procedure EnumResourceModules(Func: TEnumModuleFunc; Data: Pointer); overload;
\r
658 procedure EnumModules(Func: TEnumModuleFuncLW; Data: Pointer); overload;
\r
659 procedure EnumResourceModules(Func: TEnumModuleFuncLW; Data: Pointer); overload;
\r
660 procedure AddModuleUnloadProc(Proc: TModuleUnloadProc); overload;
\r
661 procedure RemoveModuleUnloadProc(Proc: TModuleUnloadProc); overload;
\r
662 procedure AddModuleUnloadProc(Proc: TModuleUnloadProcLW); overload;
\r
663 procedure RemoveModuleUnloadProc(Proc: TModuleUnloadProcLW); overload;
\r
665 { ResString support function/record }
\r
668 PResStringRec = ^TResStringRec;
\r
669 TResStringRec = packed record
\r
671 Identifier: Integer;
\r
674 function LoadResString(ResStringRec: PResStringRec): string;
\r
676 { Procedures and functions that need compiler magic }
\r
686 procedure _AbstractError;
\r
687 procedure _Assert(const Message, Filename: AnsiString; LineNumber: Integer);
\r
689 procedure _Assign(var T: Text; S: ShortString);
\r
690 procedure _BlockRead;
\r
691 procedure _BlockWrite;
\r
693 procedure _PStrCat;
\r
694 procedure _PStrNCat;
\r
695 procedure _PStrCpy;
\r
696 procedure _PStrNCpy;
\r
697 procedure _EofFile;
\r
698 procedure _EofText;
\r
701 procedure _FilePos;
\r
702 procedure _FileSize;
\r
703 procedure _FillChar;
\r
704 procedure _FreeMem;
\r
706 procedure _ReallocMem;
\r
710 procedure _PStrCmp;
\r
711 procedure _AStrCmp;
\r
712 procedure _RandInt;
\r
713 procedure _RandExt;
\r
714 procedure _ReadRec;
\r
715 procedure _ReadChar;
\r
716 procedure _ReadLong;
\r
717 procedure _ReadString;
\r
718 procedure _ReadCString;
\r
719 procedure _ReadLString;
\r
720 procedure _ReadExt;
\r
723 procedure _Release;
\r
724 procedure _ResetText(var T: Text);
\r
725 procedure _ResetFile;
\r
726 procedure _RewritText(var T: Text);
\r
727 procedure _RewritFile;
\r
728 procedure _RunError;
\r
729 procedure _Run0Error;
\r
731 procedure _SeekEof;
\r
732 procedure _SeekEoln;
\r
733 procedure _SetTextBuf;
\r
734 procedure _StrLong;
\r
735 procedure _Str0Long;
\r
736 procedure _Truncate;
\r
737 procedure _ValLong;
\r
738 procedure _WriteRec;
\r
739 procedure _WriteChar;
\r
740 procedure _Write0Char;
\r
741 procedure _WriteBool;
\r
742 procedure _Write0Bool;
\r
743 procedure _WriteLong;
\r
744 procedure _Write0Long;
\r
745 procedure _WriteString;
\r
746 procedure _Write0String;
\r
747 procedure _WriteCString;
\r
748 procedure _Write0CString;
\r
749 procedure _WriteLString;
\r
750 procedure _Write0LString;
\r
751 function _WriteVariant(var T: Text; const V: Variant; Width: Integer): Pointer;
\r
752 function _Write0Variant(var T: Text; const V: Variant): Pointer;
\r
753 procedure _Write2Ext;
\r
754 procedure _Write1Ext;
\r
755 procedure _Write0Ext;
\r
756 procedure _WriteLn;
\r
758 procedure __CToPasStr;
\r
759 procedure __CLenToPasStr;
\r
760 procedure __ArrayToPasStr;
\r
761 procedure __PasToCStr;
\r
763 procedure __IOTest;
\r
764 procedure _Flush(var F: Text);
\r
766 procedure _SetElem;
\r
767 procedure _SetRange;
\r
770 procedure _SetIntersect;
\r
771 procedure _SetIntersect3; { BEG only }
\r
772 procedure _SetUnion;
\r
773 procedure _SetUnion3; { BEG only }
\r
775 procedure _SetSub3; { BEG only }
\r
776 procedure _SetExpand;
\r
778 procedure _Str2Ext;
\r
779 procedure _Str0Ext;
\r
780 procedure _Str1Ext;
\r
783 procedure _Real2Ext;
\r
784 procedure _Ext2Real;
\r
786 procedure _ObjSetup;
\r
787 procedure _ObjCopy;
\r
789 procedure _BoundErr;
\r
790 procedure _IntOver;
\r
791 procedure _StartExe;
\r
792 procedure _StartLib;
\r
793 procedure _PackageLoad (const Table : PackageInfo);
\r
794 procedure _PackageUnload(const Table : PackageInfo);
\r
795 procedure _InitResStrings;
\r
796 procedure _InitResStringImports;
\r
797 procedure _InitImports;
\r
798 procedure _InitWideStrings;
\r
800 procedure _ClassCreate;
\r
801 procedure _ClassDestroy;
\r
802 procedure _AfterConstruction;
\r
803 procedure _BeforeDestruction;
\r
804 procedure _IsClass;
\r
805 procedure _AsClass;
\r
807 procedure _RaiseExcept;
\r
808 procedure _RaiseAgain;
\r
809 procedure _DoneExcept;
\r
810 procedure _TryFinallyExit;
\r
812 procedure _CallDynaInst;
\r
813 procedure _CallDynaClass;
\r
814 procedure _FindDynaInst;
\r
815 procedure _FindDynaClass;
\r
817 procedure _LStrClr(var S: AnsiString);
\r
818 procedure _LStrArrayClr{var str: AnsiString; cnt: longint};
\r
819 procedure _LStrAsg{var dest: AnsiString; source: AnsiString};
\r
820 procedure _LStrLAsg{var dest: AnsiString; source: AnsiString};
\r
821 procedure _LStrFromPCharLen(var Dest: AnsiString; Source: PAnsiChar; Length: Integer);
\r
822 procedure _LStrFromPWCharLen(var Dest: AnsiString; Source: PWideChar; Length: Integer);
\r
823 procedure _LStrFromChar(var Dest: AnsiString; Source: AnsiChar);
\r
824 procedure _LStrFromWChar(var Dest: AnsiString; Source: WideChar);
\r
825 procedure _LStrFromPChar(var Dest: AnsiString; Source: PAnsiChar);
\r
826 procedure _LStrFromPWChar(var Dest: AnsiString; Source: PWideChar);
\r
827 procedure _LStrFromString(var Dest: AnsiString; const Source: ShortString);
\r
828 procedure _LStrFromArray(var Dest: AnsiString; Source: PAnsiChar; Length: Integer);
\r
829 procedure _LStrFromWArray(var Dest: AnsiString; Source: PWideChar; Length: Integer);
\r
830 procedure _LStrFromWStr(var Dest: AnsiString; const Source: WideString);
\r
831 procedure _LStrToString{(var Dest: ShortString; const Source: AnsiString; MaxLen: Integer)};
\r
832 function _LStrLen{str: AnsiString}: Longint;
\r
833 procedure _LStrCat{var dest: AnsiString; source: AnsiString};
\r
834 procedure _LStrCat3{var dest:AnsiString; source1: AnsiString; source2: AnsiString};
\r
835 procedure _LStrCatN{var dest:AnsiString; argCnt: Integer; ...};
\r
836 procedure _LStrCmp{left: AnsiString; right: AnsiString};
\r
837 procedure _LStrAddRef{str: AnsiString};
\r
838 procedure _LStrToPChar{str: AnsiString): PChar};
\r
839 procedure _Copy{ s : ShortString; index, count : Integer ) : ShortString};
\r
840 procedure _Delete{ var s : openstring; index, count : Integer };
\r
841 procedure _Insert{ source : ShortString; var s : openstring; index : Integer };
\r
842 procedure _Pos{ substr : ShortString; s : ShortString ) : Integer};
\r
843 procedure _SetLength{var s: ShortString; newLength: Integer};
\r
844 procedure _SetString{var s: ShortString: buffer: PChar; len: Integer};
\r
846 procedure UniqueString(var str: string);
\r
847 procedure _NewAnsiString{length: Longint}; { for debugger purposes only }
\r
849 procedure _LStrCopy { const s : AnsiString; index, count : Integer) : AnsiString};
\r
850 procedure _LStrDelete{ var s : AnsiString; index, count : Integer };
\r
851 procedure _LStrInsert{ const source : AnsiString; var s : AnsiString; index : Integer };
\r
852 procedure _LStrPos{ const substr : AnsiString; const s : AnsiString ) : Integer};
\r
853 procedure _LStrSetLength{ var str: AnsiString; newLength: Integer};
\r
854 procedure _LStrOfChar{ c: Char; count: Integer): AnsiString };
\r
856 procedure _WStrClr(var S: WideString);
\r
857 procedure _WStrArrayClr(var StrArray; Count: Integer);
\r
858 procedure _WStrAsg(var Dest: WideString; const Source: WideString);
\r
859 procedure _WStrFromPCharLen(var Dest: WideString; Source: PAnsiChar; Length: Integer);
\r
860 procedure _WStrFromPWCharLen(var Dest: WideString; Source: PWideChar; Length: Integer);
\r
861 procedure _WStrFromChar(var Dest: WideString; Source: AnsiChar);
\r
862 procedure _WStrFromWChar(var Dest: WideString; Source: WideChar);
\r
863 procedure _WStrFromPChar(var Dest: WideString; Source: PAnsiChar);
\r
864 procedure _WStrFromPWChar(var Dest: WideString; Source: PWideChar);
\r
865 procedure _WStrFromString(var Dest: WideString; const Source: ShortString);
\r
866 procedure _WStrFromArray(var Dest: WideString; Source: PAnsiChar; Length: Integer);
\r
867 procedure _WStrFromWArray(var Dest: WideString; Source: PWideChar; Length: Integer);
\r
868 procedure _WStrFromLStr(var Dest: WideString; const Source: AnsiString);
\r
869 procedure _WStrToString(Dest: PShortString; const Source: WideString; MaxLen: Integer);
\r
870 function _WStrToPWChar(const S: WideString): PWideChar;
\r
871 function _WStrLen(const S: WideString): Integer;
\r
872 procedure _WStrCat(var Dest: WideString; const Source: WideString);
\r
873 procedure _WStrCat3(var Dest: WideString; const Source1, Source2: WideString);
\r
874 procedure _WStrCatN{var dest:WideString; argCnt: Integer; ...};
\r
875 procedure _WStrCmp{left: WideString; right: WideString};
\r
876 function _NewWideString(Length: Integer): PWideChar;
\r
877 function _WStrCopy(const S: WideString; Index, Count: Integer): WideString;
\r
878 procedure _WStrDelete(var S: WideString; Index, Count: Integer);
\r
879 procedure _WStrInsert(const Source: WideString; var Dest: WideString; Index: Integer);
\r
880 procedure _WStrPos{ const substr : WideString; const s : WideString ) : Integer};
\r
881 procedure _WStrSetLength(var S: WideString; NewLength: Integer);
\r
882 function _WStrOfWChar(Ch: WideChar; Count: Integer): WideString;
\r
883 procedure _WStrAddRef{var str: WideString};
\r
885 procedure _Initialize;
\r
886 procedure _InitializeArray;
\r
887 procedure _InitializeRecord;
\r
888 procedure _Finalize;
\r
889 procedure _FinalizeArray;
\r
890 procedure _FinalizeRecord;
\r
892 procedure _AddRefArray;
\r
893 procedure _AddRefRecord;
\r
894 procedure _CopyArray;
\r
895 procedure _CopyRecord;
\r
896 procedure _CopyObject;
\r
899 procedure _Dispose;
\r
901 procedure _DispInvoke; cdecl;
\r
902 procedure _IntfDispCall; cdecl;
\r
903 procedure _IntfVarCall; cdecl;
\r
905 procedure _VarToInt;
\r
906 procedure _VarToBool;
\r
907 procedure _VarToReal;
\r
908 procedure _VarToCurr;
\r
909 procedure _VarToPStr(var S; const V: Variant);
\r
910 procedure _VarToLStr(var S: string; const V: Variant);
\r
911 procedure _VarToWStr(var S: WideString; const V: Variant);
\r
912 procedure _VarToIntf(var Unknown: IUnknown; const V: Variant);
\r
913 procedure _VarToDisp(var Dispatch: IDispatch; const V: Variant);
\r
914 procedure _VarToDynArray(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
\r
916 procedure _VarFromInt;
\r
917 procedure _VarFromBool;
\r
918 procedure _VarFromReal;
\r
919 procedure _VarFromTDateTime;
\r
920 procedure _VarFromCurr;
\r
921 procedure _VarFromPStr(var V: Variant; const Value: ShortString);
\r
922 procedure _VarFromLStr(var V: Variant; const Value: string);
\r
923 procedure _VarFromWStr(var V: Variant; const Value: WideString);
\r
924 procedure _VarFromIntf(var V: Variant; const Value: IUnknown);
\r
925 procedure _VarFromDisp(var V: Variant; const Value: IDispatch);
\r
926 procedure _VarFromDynArray(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
\r
927 procedure _OleVarFromPStr(var V: OleVariant; const Value: ShortString);
\r
928 procedure _OleVarFromLStr(var V: OleVariant; const Value: string);
\r
929 procedure _OleVarFromVar(var V: OleVariant; const Value: Variant);
\r
941 procedure _VarRDiv;
\r
947 procedure _VarCopyNoInd;
\r
949 procedure _VarAddRef;
\r
951 { 64-bit Integer helper routines }
\r
955 procedure __lludiv;
\r
957 procedure __llmulo;
\r
958 procedure __lldivo;
\r
959 procedure __llmodo;
\r
960 procedure __llumod;
\r
962 procedure __llushr;
\r
963 procedure _WriteInt64;
\r
964 procedure _Write0Int64;
\r
965 procedure _ReadInt64;
\r
966 function _StrInt64(val: Int64; width: Integer): ShortString;
\r
967 function _Str0Int64(val: Int64): ShortString;
\r
968 function _ValInt64(const s: AnsiString; var code: Integer): Int64;
\r
970 { Dynamic array helper functions }
\r
972 procedure _DynArrayHigh;
\r
973 procedure _DynArrayClear(var a: Pointer; typeInfo: Pointer);
\r
974 procedure _DynArrayLength;
\r
975 procedure _DynArraySetLength;
\r
976 procedure _DynArrayCopy(a: Pointer; typeInfo: Pointer; var Result: Pointer);
\r
977 procedure _DynArrayCopyRange(a: Pointer; typeInfo: Pointer; index, count : Integer; var Result: Pointer);
\r
978 procedure _DynArrayAsg;
\r
979 procedure _DynArrayAddRef;
\r
980 procedure DynArrayToVariant(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
\r
981 procedure DynArrayFromVariant(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
\r
983 procedure _IntfClear(var Dest: IUnknown);
\r
984 procedure _IntfCopy(var Dest: IUnknown; const Source: IUnknown);
\r
985 procedure _IntfCast(var Dest: IUnknown; const Source: IUnknown; const IID: TGUID);
\r
986 procedure _IntfAddRef(const Dest: IUnknown);
\r
988 function _VarArrayGet(var A: Variant; IndexCount: Integer;
\r
989 Indices: Integer): Variant; cdecl;
\r
990 procedure _VarArrayPut(var A: Variant; const Value: Variant;
\r
991 IndexCount: Integer; Indices: Integer); cdecl;
\r
993 procedure _HandleAnyException;
\r
994 procedure _HandleOnException;
\r
995 procedure _HandleFinally;
\r
996 procedure _HandleAutoException;
\r
998 procedure _FSafeDivide;
\r
999 procedure _FSafeDivideR;
\r
1001 procedure _CheckAutoResult;
\r
1003 procedure FPower10;
\r
1005 procedure TextStart;
\r
1007 function CompToDouble(acomp: Comp): Double; cdecl;
\r
1008 procedure DoubleToComp(adouble: Double; var result: Comp); cdecl;
\r
1009 function CompToCurrency(acomp: Comp): Currency; cdecl;
\r
1010 procedure CurrencyToComp(acurrency: Currency; var result: Comp); cdecl;
\r
1012 function GetMemory(Size: Integer): Pointer; cdecl;
\r
1013 function FreeMemory(P: Pointer): Integer; cdecl;
\r
1014 function ReallocMemory(P: Pointer; Size: Integer): Pointer; cdecl;
\r
1016 (* =================================================================== *)
\r
1023 { Internal runtime error codes }
\r
1026 reOutOfMemory = 1;
\r
1030 reIntOverflow = 5;
\r
1035 reInvalidCast = 10;
\r
1036 reAccessViolation = 11;
\r
1037 reStackOverflow = 12;
\r
1038 reControlBreak = 13;
\r
1039 rePrivInstruction = 14;
\r
1040 reVarTypeCast = 15;
\r
1041 reVarInvalidOp = 16;
\r
1042 reVarDispatch = 17;
\r
1043 reVarArrayCreate = 18;
\r
1044 reVarNotArray = 19;
\r
1045 reVarArrayBounds = 20;
\r
1046 reAssertionFailed = 21;
\r
1047 reExternalException = 22; { not used here; in SysUtils }
\r
1048 reIntfCastError = 23;
\r
1049 reSafeCallError = 24;
\r
1051 { this procedure should be at the very beginning of the }
\r
1052 { text segment. it is only used by _RunError to find }
\r
1053 { start address of the text segment so a nice error }
\r
1054 { location can be shown. }
\r
1056 procedure TextStart;
\r
1060 { ----------------------------------------------------- }
\r
1061 { NT Calls necessary for the .asm files }
\r
1062 { ----------------------------------------------------- }
\r
1065 PMemInfo = ^TMemInfo;
\r
1066 TMemInfo = packed record
\r
1067 BaseAddress: Pointer;
\r
1068 AllocationBase: Pointer;
\r
1069 AllocationProtect: Longint;
\r
1070 RegionSize: Longint;
\r
1076 PStartupInfo = ^TStartupInfo;
\r
1077 TStartupInfo = record
\r
1079 lpReserved: Pointer;
\r
1080 lpDesktop: Pointer;
\r
1086 dwXCountChars: Longint;
\r
1087 dwYCountChars: Longint;
\r
1088 dwFillAttribute: Longint;
\r
1090 wShowWindow: Word;
\r
1091 cbReserved2: Word;
\r
1092 lpReserved2: ^Byte;
\r
1093 hStdInput: Integer;
\r
1094 hStdOutput: Integer;
\r
1095 hStdError: Integer;
\r
1098 TWin32FindData = packed record
\r
1099 dwFileAttributes: Integer;
\r
1100 ftCreationTime: Int64;
\r
1101 ftLastAccessTime: Int64;
\r
1102 ftLastWriteTime: Int64;
\r
1103 nFileSizeHigh: Integer;
\r
1104 nFileSizeLow: Integer;
\r
1105 dwReserved0: Integer;
\r
1106 dwReserved1: Integer;
\r
1107 cFileName: array[0..259] of Char;
\r
1108 cAlternateFileName: array[0..13] of Char;
\r
1114 procedure CloseHandle; external kernel name 'CloseHandle';
\r
1115 procedure CreateFileA; external kernel name 'CreateFileA';
\r
1116 procedure DeleteFileA; external kernel name 'DeleteFileA';
\r
1117 procedure GetFileType; external kernel name 'GetFileType';
\r
1118 procedure GetSystemTime; external kernel name 'GetSystemTime';
\r
1119 procedure GetFileSize; external kernel name 'GetFileSize';
\r
1120 procedure GetStdHandle; external kernel name 'GetStdHandle';
\r
1121 //procedure GetStartupInfo; external kernel name 'GetStartupInfo';
\r
1122 procedure MoveFileA; external kernel name 'MoveFileA';
\r
1123 procedure RaiseException; external kernel name 'RaiseException';
\r
1124 procedure ReadFile; external kernel name 'ReadFile';
\r
1125 procedure RtlUnwind; external kernel name 'RtlUnwind';
\r
1126 procedure SetEndOfFile; external kernel name 'SetEndOfFile';
\r
1127 procedure SetFilePointer; external kernel name 'SetFilePointer';
\r
1128 procedure UnhandledExceptionFilter; external kernel name 'UnhandledExceptionFilter';
\r
1129 procedure WriteFile; external kernel name 'WriteFile';
\r
1131 function CharNext(lpsz: PChar): PChar; stdcall;
\r
1132 external user name 'CharNextA';
\r
1134 function CreateThread(SecurityAttributes: Pointer; StackSize: LongWord;
\r
1135 ThreadFunc: TThreadFunc; Parameter: Pointer;
\r
1136 CreationFlags: LongWord; var ThreadId: LongWord): Integer; stdcall;
\r
1137 external kernel name 'CreateThread';
\r
1139 procedure ExitThread(ExitCode: Integer); stdcall;
\r
1140 external kernel name 'ExitThread';
\r
1142 procedure ExitProcess(ExitCode: Integer); stdcall;
\r
1143 external kernel name 'ExitProcess';
\r
1145 procedure MessageBox(Wnd: Integer; Text: PChar; Caption: PChar; Typ: Integer); stdcall;
\r
1146 external user name 'MessageBoxA';
\r
1148 function CreateDirectory(PathName: PChar; Attr: Integer): WordBool; stdcall;
\r
1149 external kernel name 'CreateDirectoryA';
\r
1151 function FindClose(FindFile: Integer): LongBool; stdcall;
\r
1152 external kernel name 'FindClose';
\r
1154 function FindFirstFile(FileName: PChar; var FindFileData: TWIN32FindData): Integer; stdcall;
\r
1155 external kernel name 'FindFirstFileA';
\r
1157 {X} //function FreeLibrary(ModuleHandle: Longint): LongBool; stdcall;
\r
1158 {X} // external kernel name 'FreeLibrary';
\r
1160 {X} //function GetCommandLine: PChar; stdcall;
\r
1161 {X} // external kernel name 'GetCommandLineA';
\r
1163 function GetCurrentDirectory(BufSize: Integer; Buffer: PChar): Integer; stdcall;
\r
1164 external kernel name 'GetCurrentDirectoryA';
\r
1166 function GetLastError: Integer; stdcall;
\r
1167 external kernel name 'GetLastError';
\r
1169 function GetLocaleInfo(Locale: Longint; LCType: Longint; lpLCData: PChar; cchData: Integer): Integer; stdcall;
\r
1170 external kernel name 'GetLocaleInfoA';
\r
1172 {X} //function GetModuleFileName(Module: Integer; Filename: PChar;
\r
1173 {X} // Size: Integer): Integer; stdcall;
\r
1174 {X} // external kernel name 'GetModuleFileNameA';
\r
1176 {X} //function GetModuleHandle(ModuleName: PChar): Integer; stdcall;
\r
1177 {X} // external kernel name 'GetModuleHandleA';
\r
1179 function GetProcAddress(Module: Integer; ProcName: PChar): Pointer; stdcall;
\r
1180 external kernel name 'GetProcAddress';
\r
1182 procedure GetStartupInfo(var lpStartupInfo: TStartupInfo); stdcall;
\r
1183 external kernel name 'GetStartupInfoA';
\r
1185 function GetThreadLocale: Longint; stdcall;
\r
1186 external kernel name 'GetThreadLocale';
\r
1188 function LoadLibraryEx(LibName: PChar; hFile: Longint; Flags: Longint): Longint; stdcall;
\r
1189 external kernel name 'LoadLibraryExA';
\r
1191 function LoadString(Instance: Longint; IDent: Integer; Buffer: PChar;
\r
1192 Size: Integer): Integer; stdcall;
\r
1193 external user name 'LoadStringA';
\r
1195 {function lstrcat(lpString1, lpString2: PChar): PChar; stdcall;
\r
1196 external kernel name 'lstrcatA';}
\r
1198 function lstrcpy(lpString1, lpString2: PChar): PChar; stdcall;
\r
1199 external kernel name 'lstrcpyA';
\r
1201 function lstrcpyn(lpString1, lpString2: PChar;
\r
1202 iMaxLength: Integer): PChar; stdcall;
\r
1203 external kernel name 'lstrcpynA';
\r
1205 function lstrlen(lpString: PChar): Integer; stdcall;
\r
1206 external kernel name 'lstrlenA';
\r
1208 function MultiByteToWideChar(CodePage, Flags: Integer; MBStr: PChar;
\r
1209 MBCount: Integer; WCStr: PWideChar; WCCount: Integer): Integer; stdcall;
\r
1210 external kernel name 'MultiByteToWideChar';
\r
1212 function RegCloseKey(hKey: Integer): Longint; stdcall;
\r
1213 external advapi32 name 'RegCloseKey';
\r
1215 function RegOpenKeyEx(hKey: LongWord; lpSubKey: PChar; ulOptions,
\r
1216 samDesired: LongWord; var phkResult: LongWord): Longint; stdcall;
\r
1217 external advapi32 name 'RegOpenKeyExA';
\r
1219 function RegQueryValueEx(hKey: LongWord; lpValueName: PChar;
\r
1220 lpReserved: Pointer; lpType: Pointer; lpData: PChar; lpcbData: Pointer): Integer; stdcall;
\r
1221 external advapi32 name 'RegQueryValueExA';
\r
1223 function RemoveDirectory(PathName: PChar): WordBool; stdcall;
\r
1224 external kernel name 'RemoveDirectoryA';
\r
1226 function SetCurrentDirectory(PathName: PChar): WordBool; stdcall;
\r
1227 external kernel name 'SetCurrentDirectoryA';
\r
1229 function WideCharToMultiByte(CodePage, Flags: Integer; WCStr: PWideChar;
\r
1230 WCCount: Integer; MBStr: PChar; MBCount: Integer; DefaultChar: PChar;
\r
1231 UsedDefaultChar: Pointer): Integer; stdcall;
\r
1232 external kernel name 'WideCharToMultiByte';
\r
1234 function VirtualQuery(lpAddress: Pointer;
\r
1235 var lpBuffer: TMemInfo; dwLength: Longint): Longint; stdcall;
\r
1236 external kernel name 'VirtualQuery';
\r
1238 //function SysAllocString(P: PWideChar): PWideChar; stdcall;
\r
1239 // external oleaut name 'SysAllocString';
\r
1241 function SysAllocStringLen(P: PWideChar; Len: Integer): PWideChar; stdcall;
\r
1242 external oleaut name 'SysAllocStringLen';
\r
1244 function SysReAllocStringLen(var S: WideString; P: PWideChar;
\r
1245 Len: Integer): LongBool; stdcall;
\r
1246 external oleaut name 'SysReAllocStringLen';
\r
1248 procedure SysFreeString(const S: WideString); stdcall;
\r
1249 external oleaut name 'SysFreeString';
\r
1251 function SysStringLen(const S: WideString): Integer; stdcall;
\r
1252 external oleaut name 'SysStringLen';
\r
1254 //procedure VariantInit(var V: Variant); stdcall;
\r
1255 // external oleaut name 'VariantInit';
\r
1257 function VariantClear(var V: Variant): Integer; stdcall;
\r
1258 external oleaut name 'VariantClear';
\r
1260 function VariantCopy(var Dest: Variant; const Source: Variant): Integer; stdcall;
\r
1261 external oleaut name 'VariantCopy';
\r
1263 function VariantCopyInd(var Dest: Variant; const Source: Variant): Integer; stdcall;
\r
1264 external oleaut name 'VariantCopyInd';
\r
1266 //function VariantChangeType(var Dest: Variant; const Source: Variant;
\r
1267 // Flags: Word; VarType: Word): Integer; stdcall;
\r
1268 // external oleaut name 'VariantChangeType';
\r
1270 function VariantChangeTypeEx(var Dest: Variant; const Source: Variant;
\r
1271 LCID: Integer; Flags: Word; VarType: Word): Integer; stdcall;
\r
1272 external oleaut name 'VariantChangeTypeEx';
\r
1274 function SafeArrayCreate(VarType, DimCount: Integer;
\r
1275 const Bounds): PVarArray; stdcall;
\r
1276 external oleaut name 'SafeArrayCreate';
\r
1278 function SafeArrayRedim(VarArray: PVarArray;
\r
1279 var NewBound: TVarArrayBound): Integer; stdcall;
\r
1280 external oleaut name 'SafeArrayRedim';
\r
1282 function SafeArrayGetLBound(VarArray: PVarArray; Dim: Integer;
\r
1283 var LBound: Integer): Integer; stdcall;
\r
1284 external oleaut name 'SafeArrayGetLBound';
\r
1286 function SafeArrayGetUBound(VarArray: PVarArray; Dim: Integer;
\r
1287 var UBound: Integer): Integer; stdcall;
\r
1288 external oleaut name 'SafeArrayGetUBound';
\r
1290 function SafeArrayAccessData(VarArray: PVarArray;
\r
1291 var Data: Pointer): Integer; stdcall;
\r
1292 external oleaut name 'SafeArrayAccessData';
\r
1294 function SafeArrayUnaccessData(VarArray: PVarArray): Integer; stdcall;
\r
1295 external oleaut name 'SafeArrayUnaccessData';
\r
1297 function SafeArrayGetElement(VarArray: PVarArray; Indices,
\r
1298 Data: Pointer): Integer; stdcall;
\r
1299 external oleaut name 'SafeArrayGetElement';
\r
1301 function SafeArrayPtrOfIndex(VarArray: PVarArray; Indices: Pointer;
\r
1302 var pvData: Pointer): HResult; stdcall;
\r
1303 external oleaut name 'SafeArrayPtrOfIndex';
\r
1305 function SafeArrayPutElement(VarArray: PVarArray; Indices,
\r
1306 Data: Pointer): Integer; stdcall;
\r
1307 external oleaut name 'SafeArrayPutElement';
\r
1309 function InterlockedIncrement(var Addend: Integer): Integer; stdcall;
\r
1310 external kernel name 'InterlockedIncrement';
\r
1312 function InterlockedDecrement(var Addend: Integer): Integer; stdcall;
\r
1313 external kernel name 'InterlockedDecrement';
\r
1315 var SaveCmdShow : Integer = -1;
\r
1316 function CmdShow: Integer;
\r
1320 if SaveCmdShow < 0 then
\r
1322 SaveCmdShow := 10; { SW_SHOWDEFAULT }
\r
1323 GetStartupInfo(SI);
\r
1324 if SI.dwFlags and 1 <> 0 then { STARTF_USESHOWWINDOW }
\r
1325 SaveCmdShow := SI.wShowWindow;
\r
1327 Result := SaveCmdShow;
\r
1330 { ----------------------------------------------------- }
\r
1331 { Memory manager }
\r
1332 { ----------------------------------------------------- }
\r
1334 procedure Error(errorCode: Byte); forward;
\r
1338 {X- by default, system memory allocation routines (API calls)
\r
1339 are used. To use Inprise's memory manager (Delphi standard)
\r
1340 call UseDelphiMemoryManager procedure. }
\r
1342 MemoryManager: TMemoryManager = (
\r
1343 GetMem: DfltGetMem;
\r
1344 FreeMem: DfltFreeMem;
\r
1345 ReallocMem: DfltReallocMem);
\r
1348 DelphiMemoryManager: TMemoryManager = (
\r
1349 GetMem: SysGetMem;
\r
1350 FreeMem: SysFreeMem;
\r
1351 ReallocMem: SysReallocMem);
\r
1353 procedure UseDelphiMemoryManager;
\r
1355 IsMemoryManagerSet := IsDelphiMemoryManagerSet;
\r
1356 SetMemoryManager( DelphiMemoryManager );
\r
1360 procedure _GetMem;
\r
1364 CALL MemoryManager.GetMem
\r
1368 @@2: MOV AL,reOutOfMemory
\r
1372 procedure _FreeMem;
\r
1376 CALL MemoryManager.FreeMem
\r
1380 @@2: MOV AL,reInvalidPtr
\r
1384 procedure _ReallocMem;
\r
1394 CALL MemoryManager.ReallocMem
\r
1401 MOV AL,reInvalidPtr
\r
1406 CALL MemoryManager.FreeMem
\r
1411 MOV AL,reOutOfMemory
\r
1418 CALL MemoryManager.GetMem
\r
1426 procedure GetMemoryManager(var MemMgr: TMemoryManager);
\r
1428 MemMgr := MemoryManager;
\r
1431 procedure SetMemoryManager(const MemMgr: TMemoryManager);
\r
1433 MemoryManager := MemMgr;
\r
1436 //{X} - function is replaced with pointer to one.
\r
1437 // function IsMemoryManagerSet: Boolean;
\r
1438 function IsDelphiMemoryManagerSet;
\r
1440 with MemoryManager do
\r
1441 Result := (@GetMem <> @SysGetMem) or (@FreeMem <> @SysFreeMem) or
\r
1442 (@ReallocMem <> @SysReallocMem);
\r
1445 {X+ always returns False. Initial handler for IsMemoryManagerSet }
\r
1446 function MemoryManagerNotUsed : Boolean;
\r
1453 RaiseListPtr: pointer;
\r
1454 InOutRes: Integer;
\r
1456 function RaiseList: Pointer;
\r
1458 CALL SysInit.@GetTLS
\r
1459 MOV EAX, [EAX].RaiseListPtr
\r
1462 function SetRaiseList(NewPtr: Pointer): Pointer;
\r
1465 CALL SysInit.@GetTLS
\r
1466 MOV EDX, [EAX].RaiseListPtr
\r
1467 MOV [EAX].RaiseListPtr, ECX
\r
1471 { ----------------------------------------------------- }
\r
1472 { local functions & procedures of the system unit }
\r
1473 { ----------------------------------------------------- }
\r
1475 procedure Error(errorCode: Byte);
\r
1485 MOV AL,byte ptr @@errorTable[EAX]
\r
1487 CALL SysInit.@GetTLS
\r
1488 MOV EAX,[EAX].InOutRes
\r
1493 DB 203 { reOutOfMemory }
\r
1494 DB 204 { reInvalidPtr }
\r
1495 DB 200 { reDivByZero }
\r
1496 DB 201 { reRangeError }
\r
1497 { 210 abstract error }
\r
1498 DB 215 { reIntOverflow }
\r
1499 DB 207 { reInvalidOp }
\r
1500 DB 200 { reZeroDivide }
\r
1501 DB 205 { reOverflow }
\r
1502 DB 206 { reUnderflow }
\r
1503 DB 219 { reInvalidCast }
\r
1504 DB 216 { Access violation }
\r
1505 DB 202 { Stack overflow }
\r
1506 DB 217 { Control-C }
\r
1507 DB 218 { Privileged instruction }
\r
1508 DB 220 { Invalid variant type cast }
\r
1509 DB 221 { Invalid variant operation }
\r
1510 DB 222 { No variant method call dispatcher }
\r
1511 DB 223 { Cannot create variant array }
\r
1512 DB 224 { Variant does not contain an array }
\r
1513 DB 225 { Variant array bounds error }
\r
1514 { 226 thread init failure }
\r
1515 DB 227 { reAssertionFailed }
\r
1516 DB 0 { reExternalException not used here; in SysUtils }
\r
1517 DB 228 { reIntfCastError }
\r
1518 DB 229 { reSafeCallError }
\r
1521 procedure __IOTest;
\r
1526 CALL SysInit.@GetTLS
\r
1527 CMP [EAX].InOutRes,0
\r
1538 procedure SetInOutRes;
\r
1541 CALL SysInit.@GetTLS
\r
1542 POP [EAX].InOutRes
\r
1546 procedure InOutError;
\r
1552 procedure _ChDir(const S: string);
\r
1554 if not SetCurrentDirectory(PChar(S)) then InOutError;
\r
1557 procedure _Copy{ s : ShortString; index, count : Integer ) : ShortString};
\r
1559 { ->EAX Source string }
\r
1562 { [ESP+4] Pointer to result string }
\r
1574 { limit index to satisfy 1 <= index <= Length(src) }
\r
1582 { limit count to satisfy 0 <= count <= Length(src) - index + 1 }
\r
1584 SUB EAX,EDX { calculate Length(src) - index + 1 }
\r
1619 procedure _Delete{ var s : openstring; index, count : Integer };
\r
1621 { ->EAX Pointer to s }
\r
1633 { if index not in [1 .. Length(s)] do nothing }
\r
1640 { limit count to [0 .. Length(s) - index + 1] }
\r
1644 SUB EAX,EDX { calculate Length(s) - index + 1 }
\r
1650 SUB [EDI],CL { reduce Length(s) by count }
\r
1651 ADD EDI,EDX { point EDI to first char to be deleted }
\r
1652 LEA ESI,[EDI+ECX] { point ESI to first char to be preserved }
\r
1653 SUB EAX,ECX { #chars = Length(s) - index + 1 - count }
\r
1663 procedure __Flush( var f : Text );
\r
1664 external; { Assign }
\r
1666 procedure _Flush( var f : Text );
\r
1667 external; { Assign }
\r
1669 procedure _LGetDir(D: Byte; var S: string);
\r
1671 Drive: array[0..3] of Char;
\r
1672 DirBuf, SaveBuf: array[0..259] of Char;
\r
1676 Drive[0] := Chr(D + Ord('A') - 1);
\r
1679 GetCurrentDirectory(SizeOf(SaveBuf), SaveBuf);
\r
1680 SetCurrentDirectory(Drive);
\r
1682 GetCurrentDirectory(SizeOf(DirBuf), DirBuf);
\r
1683 if D <> 0 then SetCurrentDirectory(SaveBuf);
\r
1687 procedure _SGetDir(D: Byte; var S: ShortString);
\r
1695 procedure _Insert{ source : ShortString; var s : openstring; index : Integer };
\r
1697 { ->EAX Pointer to source string }
\r
1698 { EDX Pointer to destination string }
\r
1699 { ECX Length of destination string }
\r
1706 MOV ECX,[ESP+16+4]
\r
1707 SUB ESP,512 { VAR buf: ARRAY [0..511] of Char }
\r
1709 MOV EBX,EDX { save pointer to s for later }
\r
1716 { limit index to [1 .. Length(s)+1] }
\r
1724 DEC EDX { EDX = Length(s) }
\r
1725 { EAX = Pointer to src }
\r
1726 { ESI = EBX = Pointer to s }
\r
1729 { copy index-1 chars from s to buf }
\r
1733 SUB EDX,ECX { EDX = remaining length of s }
\r
1736 { copy Length(src) chars from src to buf }
\r
1738 XCHG EAX,ESI { save pointer into s, point ESI to src }
\r
1739 MOV CL,[ESI] { ECX = Length(src) (ECX was zero after rep) }
\r
1743 { copy remaining chars of s to buf }
\r
1745 MOV ESI,EAX { restore pointer into s }
\r
1746 MOV ECX,EDX { copy remaining bytes of s }
\r
1749 { calculate total chars in buf }
\r
1751 SUB EDI,ESP { length = bufPtr - buf }
\r
1752 MOV ECX,[ESP+512] { ECX = Min(length, destLength) }
\r
1753 { MOV ECX,[EBP-16] }{ ECX = Min(length, destLength) }
\r
1758 MOV EDI,EBX { Point EDI to s }
\r
1759 MOV ESI,ESP { Point ESI to buf }
\r
1760 MOV [EDI],CL { Store length in s }
\r
1762 REP MOVSB { Copy length chars to s }
\r
1780 function IOResult: Integer;
\r
1782 CALL SysInit.@GetTLS
\r
1784 MOV ECX,[EAX].InOutRes
\r
1785 MOV [EAX].InOutRes,EDX
\r
1789 procedure _MkDir(const S: string);
\r
1791 if not CreateDirectory(PChar(S), 0) then InOutError;
\r
1794 procedure Move( const Source; var Dest; count : Integer );
\r
1796 { ->EAX Pointer to source }
\r
1797 { EDX Pointer to destination }
\r
1800 (*{X-} // original code.
\r
1814 SAR ECX,2 { copy count DIV 4 dwords }
\r
1821 REP MOVSB { copy count MOD 4 bytes }
\r
1825 LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
\r
1826 LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest }
\r
1828 SAR ECX,2 { copy count DIV 4 dwords }
\r
1834 AND ECX,03H { copy count MOD 4 bytes }
\r
1835 ADD ESI,4-1 { point to last byte of rest }
\r
1843 //---------------------------------------
\r
1844 (* {X+} // Let us write smaller:
\r
1855 AND ECX,3 { copy count mod 4 dwords }
\r
1862 LEA ESI,[ESI+EAX-1] { point ESI to last byte of source }
\r
1863 LEA EDI,[EDI+EAX-1] { point EDI to last byte of dest }
\r
1868 ADD ECX, 3 { move 3 bytes more to correct pos }
\r
1886 //---------------------------------------
\r
1887 {X+} // And now, let us write speedy:
\r
1901 LEA ESI,[ESI+ECX-1] { point ESI to last byte of source }
\r
1902 LEA EDI,[EDI+ECX-1] { point EDI to last byte of dest }
\r
1925 LEA ESI,[ESI+EAX-4]
\r
1926 LEA EDI,[EDI+EAX-4]
\r
1936 } // let's do it in other order - faster if data are aligned...
\r
1939 LEA ESI,[ESI+EAX-1]
\r
1940 LEA EDI,[EDI+EAX-1]
\r
1945 //JS @@exit // why to test this? but what does PC do?
\r
1955 DEC ECX // the same - loosing 2 tacts... but conveyer!
\r
1975 function GetParamStr(P: PChar; var Param: string): PChar;
\r
1978 Buffer: array[0..4095] of Char;
\r
1982 while (P[0] <> #0) and (P[0] <= ' ') do Inc(P);
\r
1983 if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
\r
1986 while (P[0] > ' ') and (Len < SizeOf(Buffer)) do
\r
1987 if P[0] = '"' then
\r
1990 while (P[0] <> #0) and (P[0] <> '"') do
\r
1992 Buffer[Len] := P[0];
\r
1996 if P[0] <> #0 then Inc(P);
\r
1999 Buffer[Len] := P[0];
\r
2003 SetString(Param, Buffer, Len);
\r
2007 function ParamCount: Integer;
\r
2012 P := GetParamStr(GetCommandLine, S);
\r
2016 P := GetParamStr(P, S);
\r
2017 if S = '' then Break;
\r
2022 function ParamStr(Index: Integer): string;
\r
2025 Buffer: array[0..260] of Char;
\r
2028 SetString(Result, Buffer, GetModuleFileName(0, Buffer, SizeOf(Buffer)))
\r
2031 P := GetCommandLine;
\r
2034 P := GetParamStr(P, Result);
\r
2035 if (Index = 0) or (Result = '') then Break;
\r
2041 procedure _Pos{ substr : ShortString; s : ShortString ) : Integer};
\r
2043 { ->EAX Pointer to substr }
\r
2044 { EDX Pointer to string }
\r
2045 { <-EAX Position of substr in s or 0 }
\r
2051 MOV ESI,EAX { Point ESI to substr }
\r
2052 MOV EDI,EDX { Point EDI to s }
\r
2054 XOR ECX,ECX { ECX = Length(s) }
\r
2056 INC EDI { Point EDI to first char of s }
\r
2058 PUSH EDI { remember s position to calculate index }
\r
2060 XOR EDX,EDX { EDX = Length(substr) }
\r
2062 INC ESI { Point ESI to first char of substr }
\r
2064 DEC EDX { EDX = Length(substr) - 1 }
\r
2065 JS @@fail { < 0 ? return 0 }
\r
2066 MOV AL,[ESI] { AL = first char of substr }
\r
2067 INC ESI { Point ESI to 2'nd char of substr }
\r
2069 SUB ECX,EDX { #positions in s to look at }
\r
2070 { = Length(s) - Length(substr) + 1 }
\r
2075 MOV EBX,ECX { save outer loop counter }
\r
2076 PUSH ESI { save outer loop substr pointer }
\r
2077 PUSH EDI { save outer loop s pointer }
\r
2081 POP EDI { restore outer loop s pointer }
\r
2082 POP ESI { restore outer loop substr pointer }
\r
2084 MOV ECX,EBX { restore outer loop counter }
\r
2088 POP EDX { get rid of saved s pointer }
\r
2093 POP EDX { restore pointer to first char of s }
\r
2094 MOV EAX,EDI { EDI points of char after match }
\r
2095 SUB EAX,EDX { the difference is the correct index }
\r
2102 procedure _SetLength{var s: ShortString; newLength: Integer};
\r
2104 { -> EAX pointer to string }
\r
2105 { EDX new length }
\r
2107 MOV [EAX],DL { should also fill new space, parameter should be openstring }
\r
2111 procedure _SetString{var s: ShortString: buffer: PChar; len: Integer};
\r
2113 { -> EAX pointer to string }
\r
2114 { EDX pointer to buffer }
\r
2126 procedure Randomize;
\r
2132 wDayOfWeek : Word;
\r
2137 wMilliSeconds: Word;
\r
2138 reserved : array [0..7] of char;
\r
2141 LEA EAX,systemTime
\r
2143 CALL GetSystemTime
\r
2144 MOVZX EAX,systemTime.wHour
\r
2146 ADD AX,systemTime.wMinute { sum = hours * 60 + minutes }
\r
2149 MOV DX,systemTime.wSecond
\r
2150 ADD EAX,EDX { sum = sum * 60 + seconds }
\r
2152 MOV DX,systemTime.wMilliSeconds
\r
2153 ADD EAX,EDX { sum = sum * 1000 + milliseconds }
\r
2157 procedure _RmDir(const S: string);
\r
2159 if not RemoveDirectory(PChar(S)) then InOutError;
\r
2162 function UpCase( ch : Char ) : Char;
\r
2164 { -> AL Character }
\r
2176 procedure Set8087CW(NewCW: Word);
\r
2178 MOV Default8087CW,AX
\r
2179 FNCLEX // don't raise pending exceptions enabled by the new flags
\r
2180 FLDCW Default8087CW
\r
2183 { ----------------------------------------------------- }
\r
2184 { functions & procedures that need compiler magic }
\r
2185 { ----------------------------------------------------- }
\r
2187 const cwChop : Word = $1F32;
\r
2197 FSTP st(0) { for now, return 0. result would }
\r
2198 FLDZ { have little significance anyway }
\r
2203 { e**x = 2**(x*log2(e)) }
\r
2205 FLDL2E { y := x*log2e; }
\r
2207 FLD ST(0) { i := round(y); }
\r
2209 FSUB ST(1), ST { f := y - i; }
\r
2210 FXCH ST(1) { z := 2**f }
\r
2214 FSCALE { result := z * 2**i }
\r
2238 FSTP st(0) { for now, return 0. result would }
\r
2239 FLDZ { have little significance anyway }
\r
2258 { -> FST(0) Extended argument }
\r
2259 { <- EDX:EAX Result }
\r
2262 FISTP qword ptr [ESP]
\r
2270 { -> FST(0) Extended argument }
\r
2271 { <- EDX:EAX Result }
\r
2277 FISTP qword ptr [ESP+4]
\r
2285 procedure _AbstractError;
\r
2287 CMP AbstractErrorProc, 0
\r
2288 JE @@NoAbstErrProc
\r
2289 CALL AbstractErrorProc
\r
2296 procedure _Append; external; { OpenText}
\r
2297 procedure _Assign(var t: text; s: ShortString); external; {$L Assign }
\r
2298 procedure _BlockRead; external; {$L BlockRea}
\r
2299 procedure _BlockWrite; external; {$L BlockWri}
\r
2300 procedure _Close; external; {$L Close }
\r
2302 procedure _PStrCat;
\r
2304 { ->EAX = Pointer to destination string }
\r
2305 { EDX = Pointer to source string }
\r
2310 { load dest len into EAX }
\r
2316 { load source address in ESI, source len in ECX }
\r
2323 { calculate final length in DL and store it in the destination }
\r
2332 { calculate final dest address }
\r
2348 INC DL { DL = #chars to truncate }
\r
2349 SUB CL,DL { CL = source len - #chars to truncate }
\r
2350 MOV DL,255 { DL = maximum length }
\r
2354 procedure _PStrNCat;
\r
2356 { ->EAX = Pointer to destination string }
\r
2357 { EDX = Pointer to source string }
\r
2358 { CL = max length of result (allocated size of dest - 1) }
\r
2363 { load dest len into EAX }
\r
2369 { load source address in ESI, source len in EDX }
\r
2376 { calculate final length in AL and store it in the destination }
\r
2388 { calculate final dest address }
\r
2405 MOV AL,CL { AL = final length = maxlen }
\r
2406 SUB CL,[EDI] { CL = length to copy = maxlen - destlen }
\r
2412 procedure _PStrCpy;
\r
2414 { ->EAX = Pointer to dest string }
\r
2415 { EDX = Pointer to source string }
\r
2426 INC ECX { we must copy len+1 bytes }
\r
2442 procedure _PStrNCpy;
\r
2444 { ->EAX = Pointer to dest string }
\r
2445 { EDX = Pointer to source string }
\r
2446 { CL = Maximum length to copy (allocated size of dest - 1) }
\r
2474 MOV [EDI],CL { result length is maxLen }
\r
2475 INC ESI { advance pointers }
\r
2477 AND ECX,0FFH { should be cheaper than MOVZX }
\r
2478 REP MOVSB { copy maxLen bytes }
\r
2484 procedure _PStrCmp;
\r
2486 { ->EAX = Pointer to left string }
\r
2487 { EDX = Pointer to right string }
\r
2503 SUB EAX,EDX { eax = len1 - len2 }
\r
2505 ADD EDX,EAX { edx = len2 + (len1 - len2) = len1 }
\r
2571 procedure _AStrCmp;
\r
2573 { ->EAX = Pointer to left string }
\r
2574 { EDX = Pointer to right string }
\r
2575 { ECX = Number of chars to compare}
\r
2643 procedure _EofFile; external; {$L EofFile }
\r
2644 procedure _EofText; external; {$L EofText }
\r
2645 procedure _Eoln; external; {$L Eoln }
\r
2646 procedure _Erase; external; {$L Erase }
\r
2648 procedure _FSafeDivide; external; {$L FDIV }
\r
2649 procedure _FSafeDivideR; external; { FDIV }
\r
2651 procedure _FilePos; external; {$L FilePos }
\r
2652 procedure _FileSize; external; {$L FileSize}
\r
2654 procedure _FillChar;
\r
2656 { ->EAX Pointer to destination }
\r
2662 MOV EDI,EAX { Point EDI to destination }
\r
2664 MOV CH,CL { Fill EAX with value repeated 4 times }
\r
2673 REP STOSD { Fill count DIV 4 dwords }
\r
2677 REP STOSB { Fill count MOD 4 bytes }
\r
2685 Error(reInvalidPtr);
\r
2688 procedure _RandInt;
\r
2692 IMUL EDX,RandSeed,08088405H
\r
2699 procedure _RandExt;
\r
2700 const two2neg32: double = ((1.0/$10000) / $10000); // 2^-32
\r
2702 { FUNCTION _RandExt: Extended; }
\r
2704 IMUL EDX,RandSeed,08088405H
\r
2711 FILD qword ptr [ESP]
\r
2713 FMULP ST(1), ST(0)
\r
2716 procedure _ReadRec; external; {$L ReadRec }
\r
2718 procedure _ReadChar; external; {$L ReadChar}
\r
2719 procedure _ReadLong; external; {$L ReadLong}
\r
2720 procedure _ReadString; external; {$L ReadStri}
\r
2721 procedure _ReadCString; external; { ReadStri}
\r
2723 procedure _ReadExt; external; {$L ReadExt }
\r
2724 procedure _ReadLn; external; {$L ReadLn }
\r
2726 procedure _Rename; external; {$L Rename }
\r
2728 procedure _Release;
\r
2730 Error(reInvalidPtr);
\r
2733 procedure _ResetText(var t: text); external; {$L OpenText}
\r
2734 procedure _ResetFile; external; {$L OpenFile}
\r
2735 procedure _RewritText(var t: text); external; { OpenText}
\r
2736 procedure _RewritFile; external; { OpenFile}
\r
2738 procedure _Seek; external; {$L Seek }
\r
2739 procedure _SeekEof; external; {$L SeekEof }
\r
2740 procedure _SeekEoln; external; {$L SeekEoln}
\r
2742 procedure _SetTextBuf; external; {$L SetTextB}
\r
2744 procedure _StrLong;
\r
2746 { PROCEDURE _StrLong( val: Longint; width: Longint; VAR s: ShortString );
\r
2749 ECX Pointer to string }
\r
2751 PUSH EBX { VAR i: Longint; }
\r
2752 PUSH ESI { VAR sign : Longint; }
\r
2754 PUSH EDX { store width on the stack }
\r
2755 SUB ESP,20 { VAR a: array [0..19] of Char; }
\r
2759 MOV ESI,EAX { sign := val }
\r
2761 CDQ { val := Abs(val); canned sequence }
\r
2766 XOR EBX,EBX { i := 0; }
\r
2768 @@repeat1: { repeat }
\r
2769 XOR EDX,EDX { a[i] := Chr( val MOD 10 + Ord('0') );}
\r
2771 DIV ECX { val := val DIV 10; }
\r
2775 INC EBX { i := i + 1; }
\r
2776 TEST EAX,EAX { until val = 0; }
\r
2781 MOV byte ptr [ESP+EBX],'-'
\r
2784 MOV [EDI],BL { s^++ := Chr(i); }
\r
2787 MOV ECX,[ESP+20] { spaceCnt := width - i; }
\r
2793 JLE @@repeat2 { for k := 1 to spaceCnt do s^++ := ' '; }
\r
2798 @@repeat2: { repeat }
\r
2799 MOV AL,[ESP+EBX-1] { s^ := a[i-1]; }
\r
2801 INC EDI { s := s + 1 }
\r
2802 DEC EBX { i := i - 1; }
\r
2803 JNZ @@repeat2 { until i = 0; }
\r
2811 procedure _Str0Long;
\r
2814 { EDX Pointer to string }
\r
2821 procedure _Truncate; external; {$L Truncate}
\r
2823 procedure _ValLong;
\r
2825 { FUNCTION _ValLong( s: AnsiString; VAR code: Integer ) : Longint; }
\r
2826 { ->EAX Pointer to string }
\r
2827 { EDX Pointer to code result }
\r
2835 PUSH EAX { save for the error case }
\r
2842 MOV EDI,07FFFFFFFH / 10 { limit }
\r
2883 CMP EAX,EDI { value > limit ? }
\r
2885 LEA EAX,[EAX+EAX*4]
\r
2887 ADD EAX,EBX { fortunately, we can't have a carry }
\r
2903 POP ECX { saved copy of string pointer }
\r
2905 XOR ESI,ESI { signal no error to caller }
\r
2922 JS @@successExit { to handle 2**31 correctly, where the negate overflows }
\r
2972 procedure _WriteRec; external; {$L WriteRec}
\r
2974 procedure _WriteChar; external; { WriteStr}
\r
2975 procedure _Write0Char; external; { WriteStr}
\r
2977 procedure _WriteBool;
\r
2979 { PROCEDURE _WriteBool( VAR t: Text; val: Boolean; width: Longint); }
\r
2980 { ->EAX Pointer to file record }
\r
2981 { DL Boolean value }
\r
2982 { ECX Field width }
\r
2986 MOV EDX,offset @trueString
\r
2989 MOV EDX,offset @falseString
\r
2991 @trueString: db 4,'TRUE'
\r
2992 @falseString: db 5,'FALSE'
\r
2995 procedure _Write0Bool;
\r
2997 { PROCEDURE _Write0Bool( VAR t: Text; val: Boolean); }
\r
2998 { ->EAX Pointer to file record }
\r
2999 { DL Boolean value }
\r
3005 procedure _WriteLong;
\r
3007 { PROCEDURE _WriteLong( VAR t: Text; val: Longint; with: Longint); }
\r
3008 { ->EAX Pointer to file record }
\r
3010 { ECX Field width }
\r
3012 SUB ESP,32 { VAR s: String[31]; }
\r
3017 MOV EAX,EDX { Str( val : 0, s ); }
\r
3029 MOV EDX,ESP { Write( t, s : width );}
\r
3035 procedure _Write0Long;
\r
3037 { PROCEDURE _Write0Long( VAR t: Text; val: Longint); }
\r
3038 { ->EAX Pointer to file record }
\r
3044 procedure _WriteString; external; {$L WriteStr}
\r
3045 procedure _Write0String; external; { WriteStr}
\r
3047 procedure _WriteCString; external; { WriteStr}
\r
3048 procedure _Write0CString; external; { WriteStr}
\r
3050 procedure _WriteBytes; external; { WriteStr}
\r
3051 procedure _WriteSpaces; external; { WriteStr}
\r
3053 procedure _Write2Ext;
\r
3055 { PROCEDURE _Write2Ext( VAR t: Text; val: Extended; width, prec: Longint);
\r
3056 ->EAX Pointer to file record
\r
3057 [ESP+4] Extended value
\r
3059 ECX precision (<0: scientific, >= 0: fixed point) }
\r
3061 FLD tbyte ptr [ESP+4] { load value }
\r
3062 SUB ESP,256 { VAR s: String; }
\r
3067 { Str( val, width, prec, s ); }
\r
3070 FSTP tbyte ptr [ESP] { pass value }
\r
3071 MOV EAX,EDX { pass field width }
\r
3072 MOV EDX,ECX { pass precision }
\r
3073 LEA ECX,[ESP+8+12] { pass destination string }
\r
3076 { Write( t, s, width ); }
\r
3078 POP ECX { pass width }
\r
3079 POP EAX { pass text }
\r
3080 MOV EDX,ESP { pass string }
\r
3087 procedure _Write1Ext;
\r
3089 { PROCEDURE _Write1Ext( VAR t: Text; val: Extended; width: Longint);
\r
3090 -> EAX Pointer to file record
\r
3091 [ESP+4] Extended value
\r
3098 procedure _Write0Ext;
\r
3100 { PROCEDURE _Write0Ext( VAR t: Text; val: Extended);
\r
3101 ->EAX Pointer to file record
\r
3102 [ESP+4] Extended value }
\r
3104 MOV EDX,23 { field width }
\r
3109 procedure _WriteLn; external; { WriteStr}
\r
3111 procedure __CToPasStr;
\r
3113 { ->EAX Pointer to destination }
\r
3114 { EDX Pointer to source }
\r
3116 PUSH EAX { save destination }
\r
3120 MOV CH,[EDX] { ch = *src++; }
\r
3122 TEST CH,CH { if (ch == 0) break }
\r
3124 INC EAX { *++dest = ch; }
\r
3135 procedure __CLenToPasStr;
\r
3137 { ->EAX Pointer to destination }
\r
3138 { EDX Pointer to source }
\r
3142 PUSH EAX { save destination }
\r
3148 MOV BL,[EDX] { ch = *src++; }
\r
3150 TEST BL,BL { if (ch == 0) break }
\r
3152 INC EAX { *++dest = ch; }
\r
3154 DEC ECX { while (--cnt != 0) }
\r
3164 procedure __ArrayToPasStr;
\r
3166 { ->EAX Pointer to destination }
\r
3167 { EDX Pointer to source }
\r
3172 { limit the length to 255 }
\r
3180 { copy the source to destination + 1 }
\r
3187 procedure __PasToCStr;
\r
3189 { ->EAX Pointer to source }
\r
3190 { EDX Pointer to destination }
\r
3203 MOV byte ptr [EDI],CL { Append terminator: CL is zero here }
\r
3209 procedure _SetElem;
\r
3211 { PROCEDURE _SetElem( VAR d: SET; elem, size: Byte); }
\r
3212 { EAX = dest address }
\r
3213 { DL = element number }
\r
3214 { CL = size of set }
\r
3221 XOR EBX,EBX { zero extend set size into ebx }
\r
3223 MOV ECX,EBX { and use it for the fill }
\r
3225 XOR EAX,EAX { for zero fill }
\r
3228 SUB EDI,EBX { point edi at beginning of set again }
\r
3230 INC EAX { eax is still zero - make it 1 }
\r
3232 ROL AL,CL { generate a mask }
\r
3233 SHR ECX,3 { generate the index }
\r
3234 CMP ECX,EBX { if index >= siz then exit }
\r
3236 OR [EDI+ECX],AL{ set bit }
\r
3243 procedure _SetRange;
\r
3245 { PROCEDURE _SetRange( lo, hi, size: Byte; VAR d: SET ); }
\r
3246 { ->AL low limit of range }
\r
3247 { DL high limit of range }
\r
3248 { ECX Pointer to set }
\r
3249 { AH size of set }
\r
3255 XOR EBX,EBX { EBX = set size }
\r
3257 MOVZX ESI,AL { ESI = low zero extended }
\r
3258 MOVZX EDX,DL { EDX = high zero extended }
\r
3267 { prepare for setting the bits }
\r
3269 SUB EDI,EBX { point EDI at start of set }
\r
3270 SHL EBX,3 { EBX = highest bit in set + 1 }
\r
3273 LEA EDX,[EBX-1] { ECX = highest bit in set }
\r
3276 CMP ESI,EDX { if lo > hi then exit; }
\r
3279 DEC EAX { loMask = 0xff << (lo & 7) }
\r
3284 SHR ESI,3 { loIndex = lo >> 3; }
\r
3286 MOV CL,DL { hiMask = 0xff >> (7 - (hi & 7)); }
\r
3291 SHR EDX,3 { hiIndex = hi >> 3; }
\r
3293 ADD EDI,ESI { point EDI to set[loIndex] }
\r
3295 SUB ECX,ESI { if ((inxDiff = (hiIndex - loIndex)) == 0) }
\r
3298 AND AL,AH { set[loIndex] = hiMask & loMask; }
\r
3303 STOSB { set[loIndex++] = loMask; }
\r
3305 MOV AL,0FFH { while (loIndex < hiIndex) }
\r
3306 REP STOSB { set[loIndex++] = 0xff; }
\r
3307 MOV [EDI],AH { set[hiIndex] = hiMask; }
\r
3317 { FUNCTION _SetEq( CONST l, r: Set; size: Byte): ConditionCode; }
\r
3318 { EAX = left operand }
\r
3319 { EDX = right operand }
\r
3320 { CL = size of set }
\r
3337 { FUNCTION _SetLe( CONST l, r: Set; size: Byte): ConditionCode; }
\r
3338 { EAX = left operand }
\r
3339 { EDX = right operand }
\r
3340 { CL = size of set (>0 && <= 32) }
\r
3354 procedure _SetIntersect;
\r
3356 { PROCEDURE _SetIntersect( VAR dest: Set; CONST src: Set; size: Byte);}
\r
3357 { EAX = destination operand }
\r
3358 { EDX = source operand }
\r
3359 { CL = size of set (0 < size <= 32) }
\r
3370 procedure _SetIntersect3;
\r
3372 { PROCEDURE _SetIntersect3( VAR dest: Set; CONST src: Set; size: Longint; src2: Set);}
\r
3373 { EAX = destination operand }
\r
3374 { EDX = source operand }
\r
3375 { ECX = size of set (0 < size <= 32) }
\r
3376 { [ESP+4] = 2nd source operand }
\r
3382 MOV BL,[EDX+ECX-1]
\r
3383 AND BL,[ESI+ECX-1]
\r
3384 MOV [EAX+ECX-1],BL
\r
3392 procedure _SetUnion;
\r
3394 { PROCEDURE _SetUnion( VAR dest: Set; CONST src: Set; size: Byte); }
\r
3395 { EAX = destination operand }
\r
3396 { EDX = source operand }
\r
3397 { CL = size of set (0 < size <= 32) }
\r
3408 procedure _SetUnion3;
\r
3410 { PROCEDURE _SetUnion3( VAR dest: Set; CONST src: Set; size: Longint; src2: Set);}
\r
3411 { EAX = destination operand }
\r
3412 { EDX = source operand }
\r
3413 { ECX = size of set (0 < size <= 32) }
\r
3414 { [ESP+4] = 2nd source operand }
\r
3420 MOV BL,[EDX+ECX-1]
\r
3422 MOV [EAX+ECX-1],BL
\r
3430 procedure _SetSub;
\r
3432 { PROCEDURE _SetSub( VAR dest: Set; CONST src: Set; size: Byte); }
\r
3433 { EAX = destination operand }
\r
3434 { EDX = source operand }
\r
3435 { CL = size of set (0 < size <= 32) }
\r
3447 procedure _SetSub3;
\r
3449 { PROCEDURE _SetSub3( VAR dest: Set; CONST src: Set; size: Longint; src2: Set);}
\r
3450 { EAX = destination operand }
\r
3451 { EDX = source operand }
\r
3452 { ECX = size of set (0 < size <= 32) }
\r
3453 { [ESP+4] = 2nd source operand }
\r
3459 MOV BL,[ESI+ECX-1]
\r
3461 AND BL,[EDX+ECX-1]
\r
3462 MOV [EAX+ECX-1],BL
\r
3470 procedure _SetExpand;
\r
3472 { PROCEDURE _SetExpand( CONST src: Set; VAR dest: Set; lo, hi: Byte); }
\r
3473 { ->EAX Pointer to source (packed set) }
\r
3474 { EDX Pointer to destination (expanded set) }
\r
3475 { CH high byte of source }
\r
3476 { CL low byte of source }
\r
3479 { clear low bytes }
\r
3480 { copy high-low+1 bytes }
\r
3481 { clear 31-high bytes }
\r
3489 MOV EDX,ECX { save low, high in dl, dh }
\r
3493 MOV CL,DL { clear low bytes }
\r
3496 MOV CL,DH { copy high - low bytes }
\r
3500 MOV CL,32 { copy 32 - high bytes }
\r
3508 procedure _Str2Ext; external; {$L StrExt }
\r
3509 procedure _Str0Ext; external; { StrExt }
\r
3510 procedure _Str1Ext; external; { StrExt }
\r
3512 procedure _ValExt; external; {$L ValExt }
\r
3514 procedure _Pow10; external; {$L Pow10 }
\r
3515 procedure FPower10; external; { Pow10 }
\r
3516 procedure _Real2Ext; external; {$L Real2Ext}
\r
3517 procedure _Ext2Real; external; {$L Ext2Real}
\r
3520 ovtInstanceSize = -8; { Offset of instance size in OBJECTs }
\r
3521 ovtVmtPtrOffs = -4;
\r
3523 procedure _ObjSetup;
\r
3525 { FUNCTION _ObjSetup( self: ^OBJECT; vmt: ^VMT): ^OBJECT; }
\r
3526 { ->EAX Pointer to self (possibly nil) }
\r
3527 { EDX Pointer to vmt (possibly nil) }
\r
3528 { <-EAX Pointer to self }
\r
3529 { EDX <> 0: an object was allocated }
\r
3530 { Z-Flag Set: failure, Cleared: Success }
\r
3532 CMP EDX,1 { is vmt = 0, indicating a call }
\r
3533 JAE @@skip1 { from a constructor? }
\r
3534 RET { return immediately with Z-flag cleared }
\r
3538 TEST EAX,EAX { is self already allocated? }
\r
3540 MOV EAX,[EDX].ovtInstanceSize
\r
3544 CALL MemoryManager.GetMem
\r
3549 { Zero fill the memory }
\r
3551 MOV ECX,[EDX].ovtInstanceSize
\r
3557 MOV ECX,[EDX].ovtInstanceSize
\r
3563 MOV ECX,[EDX].ovtVmtPtrOffs
\r
3566 MOV [EAX+ECX],EDX { store vmt in object at this offset }
\r
3568 TEST EAX,EAX { clear zero flag }
\r
3579 CMP EAX,1 { clear zero flag - we were successful (kind of) }
\r
3584 MOV ECX,[EDX].ovtVmtPtrOffs
\r
3587 MOV [EAX+ECX],EDX { store vmt in object at this offset }
\r
3589 XOR EDX,EDX { clear allocated flag }
\r
3590 TEST EAX,EAX { clear zero flag }
\r
3594 procedure _ObjCopy;
\r
3596 { PROCEDURE _ObjCopy( dest, src: ^OBJECT; vmtPtrOff: Longint); }
\r
3597 { ->EAX Pointer to destination }
\r
3598 { EDX Pointer to source }
\r
3599 { ECX Offset of vmt in those objects. }
\r
3608 LEA EAX,[EDI+ECX] { remember pointer to dest vmt pointer }
\r
3609 MOV EDX,[EAX] { fetch dest vmt pointer }
\r
3611 MOV EBX,[EDX].ovtInstanceSize
\r
3613 MOV ECX,EBX { copy size DIV 4 dwords }
\r
3617 MOV ECX,EBX { copy size MOD 4 bytes }
\r
3621 MOV [EAX],EDX { restore dest vmt }
\r
3630 { FUNCTION _Fail( self: ^OBJECT; allocFlag:Longint): ^OBJECT; }
\r
3631 { ->EAX Pointer to self (possibly nil) }
\r
3632 { EDX <> 0: Object must be deallocated }
\r
3636 JE @@exit { if no object was allocated, return }
\r
3642 function GetKeyboardType(nTypeFlag: Integer): Integer; stdcall;
\r
3643 external user name 'GetKeyboardType';
\r
3645 function _isNECWindows: Boolean;
\r
3647 KbSubType: Integer;
\r
3650 if GetKeyboardType(0) = $7 then
\r
3652 KbSubType := GetKeyboardType(1) and $FF00;
\r
3653 if (KbSubType = $0D00) or (KbSubType = $0400) then
\r
3658 procedure _FpuMaskInit;
\r
3660 HKEY_LOCAL_MACHINE = $80000002;
\r
3661 KEY_QUERY_VALUE = $00000001;
\r
3663 FPUMASKKEY = 'SOFTWARE\Borland\Delphi\RTL';
\r
3664 FPUMASKNAME = 'FPUMaskValue';
\r
3666 phkResult: LongWord;
\r
3667 lpData, DataSize: Longint;
\r
3669 lpData := Default8087CW;
\r
3671 if RegOpenKeyEx(HKEY_LOCAL_MACHINE, FPUMASKKEY, 0, KEY_QUERY_VALUE, phkResult) = 0 then
\r
3673 DataSize := Sizeof(lpData);
\r
3674 RegQueryValueEx(phkResult, FPUMASKNAME, nil, nil, @lpData, @DataSize);
\r
3676 RegCloseKey(phkResult);
\r
3679 Default8087CW := (Default8087CW and $ffc0) or (lpData and $3f);
\r
3682 procedure FpuInit;
\r
3683 //const cwDefault: Word = $1332 { $133F};
\r
3687 FLDCW Default8087CW
\r
3690 procedure FpuInitConsiderNECWindows;
\r
3692 if _isNECWindows then _FpuMaskInit;
\r
3696 procedure _BoundErr;
\r
3698 MOV AL,reRangeError
\r
3702 procedure _IntOver;
\r
3704 MOV AL,reIntOverflow
\r
3708 function TObject.ClassType: TClass;
\r
3713 class function TObject.ClassName: ShortString;
\r
3716 { EDX Pointer to result string }
\r
3720 MOV ESI,[EAX].vmtClassName
\r
3729 class function TObject.ClassNameIs(const Name: string): Boolean;
\r
3735 MOV EAX,[EAX].vmtClassName
\r
3754 class function TObject.ClassParent: TClass;
\r
3756 MOV EAX,[EAX].vmtParent
\r
3763 class function TObject.NewInstance: TObject;
\r
3766 MOV EAX,[EAX].vmtInstanceSize
\r
3770 JMP TObject.InitInstance
\r
3773 procedure TObject.FreeInstance;
\r
3781 MOV EDX,[ESI].vmtInitTable
\r
3782 MOV ESI,[ESI].vmtParent
\r
3785 CALL _FinalizeRecord
\r
3796 class function TObject.InstanceSize: Longint;
\r
3798 MOV EAX,[EAX].vmtInstanceSize
\r
3801 constructor TObject.Create;
\r
3805 destructor TObject.Destroy;
\r
3809 procedure TObject.Free;
\r
3815 CALL dword ptr [ECX].vmtDestroy
\r
3819 class function TObject.InitInstance(Instance: Pointer): TObject;
\r
3827 MOV ECX,[EBX].vmtInstanceSize
\r
3838 @@0: MOV ECX,[EBX].vmtIntfTable
\r
3842 @@1: MOV EBX,[EBX].vmtParent
\r
3850 MOV ECX,[EBX].TInterfaceTable.EntryCount
\r
3852 @@4: MOV ESI,[EBX].TInterfaceEntry.VTable
\r
3855 MOV EDI,[EBX].TInterfaceEntry.IOffset
\r
3857 @@4a: ADD EBX,TYPE TInterfaceEntry
\r
3867 procedure TObject.CleanupInstance;
\r
3875 MOV EDX,[ESI].vmtInitTable
\r
3876 MOV ESI,[ESI].vmtParent
\r
3879 CALL _FinalizeRecord
\r
3889 function InvokeImplGetter(Self: TObject; ImplGetter: Integer): IUnknown;
\r
3895 JB @@isStaticMethod
\r
3897 { the GetProc is a virtual method }
\r
3898 MOVSX ECX,CX { sign extend slot offs }
\r
3899 ADD ECX,[EAX] { vmt + slotoffs }
\r
3900 JMP dword ptr [ECX] { call vmt[slot] }
\r
3913 function TObject.GetInterface(const IID: TGUID; out Obj): Boolean;
\r
3915 InterfaceEntry: PInterfaceEntry;
\r
3917 InterfaceEntry := GetInterfaceEntry(IID);
\r
3918 if InterfaceEntry <> nil then
\r
3920 if InterfaceEntry^.IOffset <> 0 then
\r
3921 Pointer(Obj) := Pointer(Integer(Self) + InterfaceEntry^.IOffset)
\r
3923 IUnknown(Obj) := InvokeImplGetter(Self, InterfaceEntry^.ImplGetter);
\r
3924 if Pointer(Obj) <> nil then
\r
3926 if InterfaceEntry^.IOffset <> 0 then IUnknown(Obj)._AddRef;
\r
3933 Pointer(Obj) := nil;
\r
3938 class function TObject.GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
\r
3943 @@1: MOV EAX,[EBX].vmtIntfTable
\r
3946 MOV ECX,[EAX].TInterfaceTable.EntryCount
\r
3948 @@2: MOV ESI,[EDX].Integer[0]
\r
3949 CMP ESI,[EAX].TInterfaceEntry.IID.Integer[0]
\r
3951 MOV ESI,[EDX].Integer[4]
\r
3952 CMP ESI,[EAX].TInterfaceEntry.IID.Integer[4]
\r
3954 MOV ESI,[EDX].Integer[8]
\r
3955 CMP ESI,[EAX].TInterfaceEntry.IID.Integer[8]
\r
3957 MOV ESI,[EDX].Integer[12]
\r
3958 CMP ESI,[EAX].TInterfaceEntry.IID.Integer[12]
\r
3960 @@3: ADD EAX,type TInterfaceEntry
\r
3963 @@4: MOV EBX,[EBX].vmtParent
\r
3973 class function TObject.GetInterfaceTable: PInterfaceTable;
\r
3975 MOV EAX,[EAX].vmtIntfTable
\r
3979 procedure _IsClass;
\r
3981 { -> EAX left operand (class) }
\r
3982 { EDX VMT of right operand }
\r
3983 { <- AL left is derived from right }
\r
3990 MOV EAX,[EAX].vmtParent
\r
4000 procedure _AsClass;
\r
4002 { -> EAX left operand (class) }
\r
4003 { EDX VMT of right operand }
\r
4004 { <- EAX if left is derived from right, else runtime error }
\r
4012 MOV ECX,[ECX].vmtParent
\r
4016 { do runtime error }
\r
4017 MOV AL,reInvalidCast
\r
4024 procedure GetDynaMethod;
\r
4025 { function GetDynaMethod(vmt: TClass; selector: Smallint) : Pointer; }
\r
4027 { -> EAX vmt of class }
\r
4028 { BX dynamic method index }
\r
4029 { <- EBX pointer to routine }
\r
4030 { ZF = 0 if found }
\r
4031 { trashes: EAX, ECX }
\r
4039 MOV EDI,[EBX].vmtDynamicTable
\r
4042 MOVZX ECX,word ptr [EDI]
\r
4049 MOV EBX,[EBX].vmtParent
\r
4057 SUB EAX,ECX { this will always clear the Z-flag ! }
\r
4058 MOV EBX,[EDI+EAX*2-4]
\r
4064 procedure _CallDynaInst;
\r
4069 CALL GetDynaMethod
\r
4076 JMP _AbstractError
\r
4080 procedure _CallDynaClass;
\r
4084 CALL GetDynaMethod
\r
4091 JMP _AbstractError
\r
4095 procedure _FindDynaInst;
\r
4100 CALL GetDynaMethod
\r
4105 JMP _AbstractError
\r
4110 procedure _FindDynaClass;
\r
4114 CALL GetDynaMethod
\r
4119 JMP _AbstractError
\r
4124 class function TObject.InheritsFrom(AClass: TClass): Boolean;
\r
4126 { -> EAX Pointer to our class }
\r
4127 { EDX Pointer to AClass }
\r
4128 { <- AL Boolean result }
\r
4135 MOV EAX,[EAX].vmtParent
\r
4145 class function TObject.ClassInfo: Pointer;
\r
4147 MOV EAX,[EAX].vmtTypeInfo
\r
4151 function TObject.SafeCallException(ExceptObject: TObject;
\r
4152 ExceptAddr: Pointer): HResult;
\r
4154 Result := HResult($8000FFFF); { E_UNEXPECTED }
\r
4158 procedure TObject.DefaultHandler(var Message);
\r
4163 procedure TObject.AfterConstruction;
\r
4167 procedure TObject.BeforeDestruction;
\r
4171 procedure TObject.Dispatch(var Message);
\r
4181 CALL GetDynaMethod
\r
4191 JMP dword ptr [ECX].vmtDefaultHandler
\r
4195 class function TObject.MethodAddress(const Name: ShortString): Pointer;
\r
4197 { -> EAX Pointer to class }
\r
4198 { EDX Pointer to name }
\r
4206 @@outer: { upper 16 bits of ECX are 0 ! }
\r
4209 MOV ESI,[EAX].vmtMethodTable
\r
4212 MOV DI,[ESI] { EDI := method count }
\r
4214 @@inner: { upper 16 bits of ECX are 0 ! }
\r
4215 MOV CL,[ESI+6] { compare length of strings }
\r
4218 @@cont: { upper 16 bits of ECX are 0 ! }
\r
4219 MOV CX,[ESI] { fetch length of method desc }
\r
4220 ADD ESI,ECX { point ESI to next method }
\r
4224 MOV EAX,[EAX].vmtParent { fetch parent vmt }
\r
4227 JMP @@exit { return NIL }
\r
4230 MOV BL,[EDX] { restore BL to length of name }
\r
4233 @@cmpChar: { upper 16 bits of ECX are 0 ! }
\r
4234 MOV CH,0 { upper 24 bits of ECX are 0 ! }
\r
4236 MOV BL,[ESI+ECX+6] { case insensitive string cmp }
\r
4237 XOR BL,[EDX+ECX+0] { last char is compared first }
\r
4240 DEC ECX { ECX serves as counter }
\r
4253 class function TObject.MethodName(Address: Pointer): ShortString;
\r
4255 { -> EAX Pointer to class }
\r
4257 { ECX Pointer to result }
\r
4268 MOV ESI,[EAX].vmtMethodTable { fetch pointer to method table }
\r
4281 MOV EAX,[EAX].vmtParent
\r
4301 function TObject.FieldAddress(const Name: ShortString): Pointer;
\r
4303 { -> EAX Pointer to instance }
\r
4304 { EDX Pointer to name }
\r
4312 PUSH EAX { save instance pointer }
\r
4315 MOV EAX,[EAX] { fetch class pointer }
\r
4316 MOV ESI,[EAX].vmtFieldTable
\r
4319 MOV DI,[ESI] { fetch count of fields }
\r
4322 MOV CL,[ESI+6] { compare string lengths }
\r
4326 LEA ESI,[ESI+ECX+7] { point ESI to next field }
\r
4330 MOV EAX,[EAX].vmtParent { fetch parent VMT }
\r
4333 POP EDX { forget instance, return Nil }
\r
4337 MOV BL,[EDX] { restore BL to length of name }
\r
4338 MOV CL,[ESI+6] { ECX := length of field name }
\r
4342 MOV BL,[ESI+ECX+6] { case insensitive string cmp }
\r
4343 XOR BL,[EDX+ECX+0] { starting with last char }
\r
4346 DEC ECX { ECX serves as counter }
\r
4350 MOV EAX,[ESI] { result is field offset plus ... }
\r
4352 ADD EAX,EDX { instance pointer }
\r
4361 const { copied from xx.h }
\r
4363 cNonContinuable = 1;
\r
4365 cUnwindingForExit = 4;
\r
4366 cUnwindInProgress = cUnwinding or cUnwindingForExit;
\r
4367 cDelphiException = $0EEDFADE;
\r
4368 cDelphiReRaise = $0EEDFADF;
\r
4369 cDelphiExcept = $0EEDFAE0;
\r
4370 cDelphiFinally = $0EEDFAE1;
\r
4371 cDelphiTerminate = $0EEDFAE2;
\r
4372 cDelphiUnhandled = $0EEDFAE3;
\r
4373 cNonDelphiException = $0EEDFAE4;
\r
4374 cDelphiExitFinally = $0EEDFAE5;
\r
4375 cCppException = $0EEFFACE; { used by BCB }
\r
4376 EXCEPTION_CONTINUE_SEARCH = 0;
\r
4377 EXCEPTION_EXECUTE_HANDLER = 1;
\r
4378 EXCEPTION_CONTINUE_EXECUTION = -1;
\r
4384 distance: Longint;
\r
4391 PExcDesc = ^TExcDesc;
\r
4394 jmp: JmpInstruction;
\r
4396 0: (instructions: array [0..0] of Byte);
\r
4397 1{...}: (cnt: Integer; excTab: array [0..0{cnt-1}] of TExcDescEntry);
\r
4400 PExcFrame = ^TExcFrame;
\r
4408 1: ( ConstructedObject: Pointer );
\r
4409 2: ( SelfOfMethod: Pointer );
\r
4412 PExceptionRecord = ^TExceptionRecord;
\r
4413 TExceptionRecord =
\r
4415 ExceptionCode : LongWord;
\r
4416 ExceptionFlags : LongWord;
\r
4417 OuterException : PExceptionRecord;
\r
4418 ExceptionAddress : Pointer;
\r
4419 NumberParameters : Longint;
\r
4420 case {IsOsException:} Boolean of
\r
4421 True: (ExceptionInformation : array [0..14] of Longint);
\r
4422 False: (ExceptAddr: Pointer; ExceptObject: Pointer);
\r
4425 PRaiseFrame = ^TRaiseFrame;
\r
4426 TRaiseFrame = packed record
\r
4427 NextRaise: PRaiseFrame;
\r
4428 ExceptAddr: Pointer;
\r
4429 ExceptObject: TObject;
\r
4430 ExceptionRecord: PExceptionRecord;
\r
4434 procedure _ClassCreate;
\r
4436 { -> EAX = pointer to VMT }
\r
4437 { <- EAX = pointer to instance }
\r
4443 CALL dword ptr [EAX].vmtNewInstance
\r
4448 MOV [ECX].TExcFrame.next,EBX
\r
4449 MOV [ECX].TExcFrame.hEBP,EBP
\r
4450 MOV [ECX].TExcFrame.desc,offset @desc
\r
4451 MOV [ECX].TexcFrame.ConstructedObject,EAX { trick: remember copy to instance }
\r
4459 JMP _HandleAnyException
\r
4461 { destroy the object }
\r
4463 MOV EAX,[ESP+8+9*4]
\r
4464 MOV EAX,[EAX].TExcFrame.ConstructedObject
\r
4470 CALL dword ptr [ECX].vmtDestroy
\r
4472 CALL _ClassDestroy
\r
4474 { reraise the exception }
\r
4479 procedure _ClassDestroy;
\r
4482 CALL dword ptr [EDX].vmtFreeInstance
\r
4486 procedure _AfterConstruction;
\r
4488 { -> EAX = pointer to instance }
\r
4492 CALL dword ptr [EDX].vmtAfterConstruction
\r
4496 procedure _BeforeDestruction;
\r
4498 { -> EAX = pointer to instance }
\r
4499 { DL = dealloc flag }
\r
4508 CALL dword ptr [EDX].vmtBeforeDestruction
\r
4514 The following NotifyXXXX routines are used to "raise" special exceptions
\r
4515 as a signaling mechanism to an interested debugger. If the debugger sets
\r
4516 the DebugHook flag to 1 or 2, then all exception processing is tracked by
\r
4517 raising these special exceptions. The debugger *MUST* respond to the
\r
4518 debug event with DBG_CONTINE so that normal processing will occur.
\r
4521 { tell the debugger that the next raise is a re-raise of the current non-Delphi
\r
4523 procedure NotifyReRaise;
\r
4525 CMP BYTE PTR DebugHook,1
\r
4530 PUSH cDelphiReRaise
\r
4531 CALL RaiseException
\r
4535 { tell the debugger about the raise of a non-Delphi exception }
\r
4536 procedure NotifyNonDelphiException;
\r
4538 CMP BYTE PTR DebugHook,0
\r
4546 PUSH cNonDelphiException
\r
4547 CALL RaiseException
\r
4553 { Tell the debugger where the handler for the current exception is located }
\r
4554 procedure NotifyExcept;
\r
4559 PUSH cDelphiExcept { our magic exception code }
\r
4560 CALL RaiseException
\r
4565 procedure NotifyOnExcept;
\r
4567 CMP BYTE PTR DebugHook,1
\r
4570 PUSH [EBX].TExcDescEntry.handler
\r
4575 procedure NotifyAnyExcept;
\r
4577 CMP BYTE PTR DebugHook,1
\r
4585 procedure CheckJmp;
\r
4590 CMP BYTE PTR [ECX],0E9H { near jmp }
\r
4592 CMP BYTE PTR [ECX],0EBH { short jmp }
\r
4605 { Notify debugger of a finally during an exception unwind }
\r
4606 procedure NotifyExceptFinally;
\r
4608 CMP BYTE PTR DebugHook,1
\r
4615 PUSH ESP { pass pointer to arguments }
\r
4616 PUSH 1 { there is 1 argument }
\r
4617 PUSH cContinuable { continuable execution }
\r
4618 PUSH cDelphiFinally { our magic exception code }
\r
4619 CALL RaiseException
\r
4628 { Tell the debugger that the current exception is handled and cleaned up.
\r
4629 Also indicate where execution is about to resume. }
\r
4630 procedure NotifyTerminate;
\r
4632 CMP BYTE PTR DebugHook,1
\r
4638 PUSH cDelphiTerminate { our magic exception code }
\r
4639 CALL RaiseException
\r
4644 { Tell the debugger that there was no handler found for the current execption
\r
4645 and we are about to go to the default handler }
\r
4646 procedure NotifyUnhandled;
\r
4650 CMP BYTE PTR DebugHook,1
\r
4655 PUSH cDelphiUnhandled
\r
4656 CALL RaiseException
\r
4663 procedure _HandleAnyException;
\r
4665 { -> [ESP+ 4] excPtr: PExceptionRecord }
\r
4666 { [ESP+ 8] errPtr: PExcFrame }
\r
4667 { [ESP+12] ctxPtr: Pointer }
\r
4668 { [ESP+16] dspPtr: Pointer }
\r
4669 { <- EAX return value - always one }
\r
4672 TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress
\r
4675 CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException
\r
4676 MOV EDX,[EAX].TExceptionRecord.ExceptObject
\r
4677 MOV ECX,[EAX].TExceptionRecord.ExceptAddr
\r
4678 JE @@DelphiException
\r
4681 MOV EDX,ExceptObjProc
\r
4689 CMP [ECX].TExceptionRecord.ExceptionCode,cCppException
\r
4691 CALL NotifyNonDelphiException
\r
4692 CMP BYTE PTR JITEnable,0
\r
4693 JBE @@CppException
\r
4694 CMP BYTE PTR DebugHook,0
\r
4695 JA @@CppException { Do not JIT if debugging }
\r
4699 CALL UnhandledExceptionFilter
\r
4700 CMP EAX,EXCEPTION_CONTINUE_SEARCH
\r
4705 MOV ECX,[EAX].TExceptionRecord.ExceptionAddress
\r
4711 MOV ECX,[EAX].TExceptionRecord.ExceptionAddress
\r
4713 @@DelphiException:
\r
4714 CMP BYTE PTR JITEnable,1
\r
4716 CMP BYTE PTR DebugHook,0 { Do not JIT if debugging }
\r
4723 CALL UnhandledExceptionFilter
\r
4724 CMP EAX,EXCEPTION_CONTINUE_SEARCH
\r
4731 OR [EAX].TExceptionRecord.ExceptionFlags,cUnwinding
\r
4740 PUSH EBX { Save pointer to topmost frame }
\r
4741 PUSH EAX { Save OS exception pointer }
\r
4742 PUSH EDX { Save exception object }
\r
4743 PUSH ECX { Save exception address }
\r
4745 MOV EDX,[ESP+8+8*4]
\r
4749 PUSH offset @@returnAddress
\r
4754 MOV EDI,[ESP+8+8*4]
\r
4756 { Make the RaiseList entry on the stack }
\r
4758 CALL SysInit.@GetTLS
\r
4759 PUSH [EAX].RaiseListPtr
\r
4760 MOV [EAX].RaiseListPtr,ESP
\r
4762 MOV EBP,[EDI].TExcFrame.hEBP
\r
4763 MOV EBX,[EDI].TExcFrame.desc
\r
4764 MOV [EDI].TExcFrame.desc,offset @@exceptFinally
\r
4766 ADD EBX,TExcDesc.instructions
\r
4767 CALL NotifyAnyExcept
\r
4771 JMP _HandleFinally
\r
4774 { we come here if an exception handler has thrown yet another exception }
\r
4775 { we need to destroy the exception object and pop the raise list. }
\r
4777 CALL SysInit.@GetTLS
\r
4778 MOV ECX,[EAX].RaiseListPtr
\r
4779 MOV EDX,[ECX].TRaiseFrame.NextRaise
\r
4780 MOV [EAX].RaiseListPtr,EDX
\r
4782 MOV EAX,[ECX].TRaiseFrame.ExceptObject
\r
4790 procedure _HandleOnException;
\r
4792 { -> [ESP+ 4] excPtr: PExceptionRecord }
\r
4793 { [ESP+ 8] errPtr: PExcFrame }
\r
4794 { [ESP+12] ctxPtr: Pointer }
\r
4795 { [ESP+16] dspPtr: Pointer }
\r
4796 { <- EAX return value - always one }
\r
4799 TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress
\r
4802 CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException
\r
4803 JE @@DelphiException
\r
4806 MOV EDX,ExceptClsProc
\r
4814 @@DelphiException:
\r
4815 MOV EAX,[EAX].TExceptionRecord.ExceptObject
\r
4816 MOV EAX,[EAX] { load vtable of exception object }
\r
4827 MOV ECX,[EDX].TExcFrame.desc
\r
4828 MOV EBX,[ECX].TExcDesc.cnt
\r
4829 LEA ESI,[ECX].TExcDesc.excTab { point ECX to exc descriptor table }
\r
4830 MOV EBP,EAX { load vtable of exception object }
\r
4833 MOV EAX,[ESI].TExcDescEntry.vTable
\r
4834 TEST EAX,EAX { catch all clause? }
\r
4835 JE @@doHandler { yes: go execute handler }
\r
4836 MOV EDI,EBP { load vtable of exception object }
\r
4846 MOV ECX,[EAX].vmtInstanceSize
\r
4847 CMP ECX,[EDI].vmtInstanceSize
\r
4850 MOV EAX,[EAX].vmtClassName
\r
4851 MOV EDX,[EDI].vmtClassName
\r
4864 MOV EDI,[EDI].vmtParent { load vtable of parent }
\r
4865 MOV EAX,[ESI].TExcDescEntry.vTable
\r
4880 MOV EAX,[ESP+4+4*4]
\r
4881 CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException
\r
4882 MOV EDX,[EAX].TExceptionRecord.ExceptObject
\r
4883 MOV ECX,[EAX].TExceptionRecord.ExceptAddr
\r
4885 CALL ExceptObjProc
\r
4886 MOV EDX,[ESP+12+4*4]
\r
4887 CALL NotifyNonDelphiException
\r
4888 CMP BYTE PTR JITEnable,0
\r
4890 CMP BYTE PTR DebugHook,0
\r
4891 JA @@noJIT { Do not JIT if debugging }
\r
4895 CALL UnhandledExceptionFilter
\r
4896 CMP EAX,EXCEPTION_CONTINUE_SEARCH
\r
4901 MOV EAX,[ESP+4+4*4]
\r
4902 MOV ECX,[EAX].TExceptionRecord.ExceptionAddress
\r
4906 CMP BYTE PTR JITEnable,1
\r
4908 CMP BYTE PTR DebugHook,0
\r
4915 CALL UnhandledExceptionFilter
\r
4916 CMP EAX,EXCEPTION_CONTINUE_SEARCH
\r
4925 PUSH EBX { Save topmost frame }
\r
4926 PUSH EAX { Save exception record }
\r
4927 PUSH EDX { Save exception object }
\r
4928 PUSH ECX { Save exception address }
\r
4930 MOV EDX,[ESP+8+8*4]
\r
4931 OR [EAX].TExceptionRecord.ExceptionFlags,cUnwinding
\r
4933 PUSH ESI { Save handler entry }
\r
4937 PUSH offset @@returnAddress
\r
4942 POP EBX { Restore handler entry }
\r
4944 MOV EDI,[ESP+8+8*4]
\r
4946 { Make the RaiseList entry on the stack }
\r
4948 CALL SysInit.@GetTLS
\r
4949 PUSH [EAX].RaiseListPtr
\r
4950 MOV [EAX].RaiseListPtr,ESP
\r
4952 MOV EBP,[EDI].TExcFrame.hEBP
\r
4953 MOV [EDI].TExcFrame.desc,offset @@exceptFinally
\r
4954 MOV EAX,[ESP].TRaiseFrame.ExceptObject
\r
4955 CALL NotifyOnExcept
\r
4956 JMP [EBX].TExcDescEntry.handler
\r
4959 JMP _HandleFinally
\r
4962 { we come here if an exception handler has thrown yet another exception }
\r
4963 { we need to destroy the exception object and pop the raise list. }
\r
4965 CALL SysInit.@GetTLS
\r
4966 MOV ECX,[EAX].RaiseListPtr
\r
4967 MOV EDX,[ECX].TRaiseFrame.NextRaise
\r
4968 MOV [EAX].RaiseListPtr,EDX
\r
4970 MOV EAX,[ECX].TRaiseFrame.ExceptObject
\r
4977 procedure _HandleFinally;
\r
4979 { -> [ESP+ 4] excPtr: PExceptionRecord }
\r
4980 { [ESP+ 8] errPtr: PExcFrame }
\r
4981 { [ESP+12] ctxPtr: Pointer }
\r
4982 { [ESP+16] dspPtr: Pointer }
\r
4983 { <- EAX return value - always one }
\r
4987 TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress
\r
4989 MOV ECX,[EDX].TExcFrame.desc
\r
4990 MOV [EDX].TExcFrame.desc,offset @@exit
\r
4997 MOV EBP,[EDX].TExcFrame.hEBP
\r
4998 ADD ECX,TExcDesc.instructions
\r
4999 CALL NotifyExceptFinally
\r
5012 procedure _HandleAutoException;
\r
5014 { -> [ESP+ 4] excPtr: PExceptionRecord }
\r
5015 { [ESP+ 8] errPtr: PExcFrame }
\r
5016 { [ESP+12] ctxPtr: Pointer }
\r
5017 { [ESP+16] dspPtr: Pointer }
\r
5018 { <- EAX return value - always one }
\r
5021 TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress
\r
5024 CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException
\r
5027 JE @@DelphiException
\r
5028 CMP BYTE PTR JITEnable,0
\r
5029 JBE @@DelphiException
\r
5030 CMP BYTE PTR DebugHook,0
\r
5031 JA @@DelphiException
\r
5036 CALL UnhandledExceptionFilter
\r
5037 CMP EAX,EXCEPTION_CONTINUE_SEARCH
\r
5042 @@DelphiException:
\r
5043 CMP BYTE PTR JITEnable,1
\r
5045 CMP BYTE PTR DebugHook,0
\r
5050 OR [EAX].TExceptionRecord.ExceptionFlags,cUnwinding
\r
5056 MOV EDX,[ESP+8+3*4]
\r
5060 PUSH offset @@returnAddress
\r
5070 CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException
\r
5073 MOV EDX,[EAX].TExceptionRecord.ExceptObject
\r
5074 MOV ECX,[EAX].TExceptionRecord.ExceptAddr
\r
5076 MOV EAX,[EAX].TExcFrame.SelfOfMethod
\r
5078 CALL [EBX].vmtSafeCallException.Pointer
\r
5081 MOV EAX,[EAX].TExceptionRecord.ExceptObject
\r
5090 LEA EDX,[EDX].TExcDesc.instructions
\r
5098 procedure _RaiseExcept;
\r
5100 { When making changes to the way Delphi Exceptions are raised, }
\r
5101 { please realize that the C++ Exception handling code reraises }
\r
5102 { some exceptions as Delphi Exceptions. Of course we want to }
\r
5103 { keep exception raising compatible between Delphi and C++, so }
\r
5104 { when you make changes here, consult with the relevant C++ }
\r
5105 { exception handling engineer. The C++ code is in xx.cpp, in }
\r
5106 { the RTL sources, in function tossAnException. }
\r
5108 { -> EAX Pointer to exception object }
\r
5109 { [ESP] Error address }
\r
5118 PUSH EAX { pass class argument }
\r
5119 PUSH EDX { pass address argument }
\r
5121 PUSH ESP { pass pointer to arguments }
\r
5122 PUSH 7 { there are seven arguments }
\r
5123 PUSH cNonContinuable { we can't continue execution }
\r
5124 PUSH cDelphiException { our magic exception code }
\r
5125 PUSH EDX { pass the user's return address }
\r
5126 JMP RaiseException
\r
5130 procedure _RaiseAgain;
\r
5132 { -> [ESP ] return address to user program }
\r
5133 { [ESP+ 4 ] raise list entry (4 dwords) }
\r
5134 { [ESP+ 4+ 4*4] saved topmost frame }
\r
5135 { [ESP+ 4+ 5*4] saved registers (4 dwords) }
\r
5136 { [ESP+ 4+ 9*4] return address to OS }
\r
5137 { -> [ESP+ 4+10*4] excPtr: PExceptionRecord }
\r
5138 { [ESP+ 8+10*4] errPtr: PExcFrame }
\r
5140 { Point the error handler of the exception frame to something harmless }
\r
5142 MOV EAX,[ESP+8+10*4]
\r
5143 MOV [EAX].TExcFrame.desc,offset @@exit
\r
5145 { Pop the RaiseList }
\r
5147 CALL SysInit.@GetTLS
\r
5148 MOV EDX,[EAX].RaiseListPtr
\r
5149 MOV ECX,[EDX].TRaiseFrame.NextRaise
\r
5150 MOV [EAX].RaiseListPtr,ECX
\r
5152 { Destroy any objects created for non-delphi exceptions }
\r
5154 MOV EAX,[EDX].TRaiseFrame.ExceptionRecord
\r
5155 AND [EAX].TExceptionRecord.ExceptionFlags,NOT cUnwinding
\r
5156 CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException
\r
5157 JE @@delphiException
\r
5158 MOV EAX,[EDX].TRaiseFrame.ExceptObject
\r
5160 CALL NotifyReRaise
\r
5162 @@delphiException:
\r
5168 MOV EDX,[EDX].TExcFrame.next
\r
5169 MOV [ECX].TExcFrame.next,EDX
\r
5180 procedure _DoneExcept;
\r
5182 { -> [ESP+ 4+10*4] excPtr: PExceptionRecord }
\r
5183 { [ESP+ 8+10*4] errPtr: PExcFrame }
\r
5185 { Pop the RaiseList }
\r
5187 CALL SysInit.@GetTLS
\r
5188 MOV EDX,[EAX].RaiseListPtr
\r
5189 MOV ECX,[EDX].TRaiseFrame.NextRaise
\r
5190 MOV [EAX].RaiseListPtr,ECX
\r
5192 { Destroy exception object }
\r
5194 MOV EAX,[EDX].TRaiseFrame.ExceptObject
\r
5198 MOV ESP,[ESP+8+9*4]
\r
5204 CALL NotifyTerminate
\r
5209 procedure _TryFinallyExit;
\r
5212 MOV ECX,[ESP+4].TExcFrame.desc
\r
5213 MOV EAX,[ESP+4].TExcFrame.next
\r
5214 ADD ECX,TExcDesc.instructions
\r
5222 PInitContext = ^TInitContext;
\r
5223 TInitContext = record
\r
5224 OuterContext: PInitContext; { saved InitContext }
\r
5225 ExcFrame: PExcFrame; { bottom exc handler }
\r
5226 InitTable: PackageInfo; { unit init info }
\r
5227 InitCount: Integer; { how far we got }
\r
5228 Module: PLibModule; { ptr to module desc }
\r
5229 DLLSaveEBP: Pointer; { saved regs for DLLs }
\r
5230 DLLSaveEBX: Pointer; { saved regs for DLLs }
\r
5231 DLLSaveESI: Pointer; { saved regs for DLLs }
\r
5232 DLLSaveEDI: Pointer; { saved regs for DLLs }
\r
5233 DLLInitState: Byte;
\r
5234 ExitProcessTLS: procedure; { Shutdown for TLS }
\r
5238 InitContext: TInitContext;
\r
5240 procedure RunErrorAt(ErrCode: Integer; ErrorAddr: Pointer);
\r
5242 MOV [ESP],ErrorAddr
\r
5246 procedure MapToRunError(P: PExceptionRecord); stdcall;
\r
5248 STATUS_ACCESS_VIOLATION = $C0000005;
\r
5249 STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
\r
5250 STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
\r
5251 STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
\r
5252 STATUS_FLOAT_INEXACT_RESULT = $C000008F;
\r
5253 STATUS_FLOAT_INVALID_OPERATION = $C0000090;
\r
5254 STATUS_FLOAT_OVERFLOW = $C0000091;
\r
5255 STATUS_FLOAT_STACK_CHECK = $C0000092;
\r
5256 STATUS_FLOAT_UNDERFLOW = $C0000093;
\r
5257 STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
\r
5258 STATUS_INTEGER_OVERFLOW = $C0000095;
\r
5259 STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
\r
5260 STATUS_STACK_OVERFLOW = $C00000FD;
\r
5261 STATUS_CONTROL_C_EXIT = $C000013A;
\r
5265 case P.ExceptionCode of
\r
5266 STATUS_INTEGER_DIVIDE_BY_ZERO: ErrCode := 200;
\r
5267 STATUS_ARRAY_BOUNDS_EXCEEDED: ErrCode := 201;
\r
5268 STATUS_FLOAT_OVERFLOW: ErrCode := 205;
\r
5269 STATUS_FLOAT_INEXACT_RESULT,
\r
5270 STATUS_FLOAT_INVALID_OPERATION,
\r
5271 STATUS_FLOAT_STACK_CHECK: ErrCode := 207;
\r
5272 STATUS_FLOAT_DIVIDE_BY_ZERO: ErrCode := 200;
\r
5273 STATUS_INTEGER_OVERFLOW: ErrCode := 215;
\r
5274 STATUS_FLOAT_UNDERFLOW,
\r
5275 STATUS_FLOAT_DENORMAL_OPERAND: ErrCode := 206;
\r
5276 STATUS_ACCESS_VIOLATION: ErrCode := 216;
\r
5277 STATUS_PRIVILEGED_INSTRUCTION: ErrCode := 218;
\r
5278 STATUS_CONTROL_C_EXIT: ErrCode := 217;
\r
5279 STATUS_STACK_OVERFLOW: ErrCode := 202;
\r
5280 else ErrCode := 255;
\r
5282 RunErrorAt(ErrCode, P.ExceptionAddress);
\r
5285 procedure _ExceptionHandler;
\r
5289 TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress
\r
5291 CMP BYTE PTR DebugHook,0
\r
5292 JA @@ExecuteHandler
\r
5295 CALL UnhandledExceptionFilter
\r
5296 CMP EAX,EXCEPTION_CONTINUE_SEARCH
\r
5297 JNE @@ExecuteHandler
\r
5310 PUSH offset @@returnAddress
\r
5316 CMP [EBX].TExceptionRecord.ExceptionCode,cDelphiException
\r
5317 MOV EDX,[EBX].TExceptionRecord.ExceptAddr
\r
5318 MOV EAX,[EBX].TExceptionRecord.ExceptObject
\r
5319 JE @@DelphiException2
\r
5321 MOV EDX,ExceptObjProc
\r
5328 MOV EDX,[EBX].TExceptionRecord.ExceptionAddress
\r
5330 @@DelphiException2:
\r
5332 CALL NotifyUnhandled
\r
5333 MOV ECX,ExceptProc
\r
5336 CALL ECX { call ExceptProc(ExceptObject, ExceptAddr) }
\r
5341 MOV EDX,[ECX].TExceptionRecord.ExceptAddr
\r
5350 procedure SetExceptionHandler;
\r
5352 XOR EDX,EDX { using [EDX] saves some space over [0] }
\r
5353 {X} // now we come here from another place, and EBP is used above for loop counter
\r
5354 {X} // let us restore it...
\r
5356 {X} LEA EBP, [ESP + $60]
\r
5360 MOV ECX,FS:[EDX] { ECX := head of chain }
\r
5361 MOV FS:[EDX],EAX { head of chain := @exRegRec }
\r
5363 MOV [EAX].TExcFrame.next,ECX
\r
5364 MOV [EAX].TExcFrame.desc,offset _ExceptionHandler
\r
5365 MOV [EAX].TExcFrame.hEBP,EBP
\r
5366 MOV InitContext.ExcFrame,EAX
\r
5372 procedure UnsetExceptionHandler;
\r
5375 MOV EAX,InitContext.ExcFrame
\r
5376 MOV ECX,FS:[EDX] { ECX := head of chain }
\r
5377 CMP EAX,ECX { simple case: our record is first }
\r
5379 MOV EAX,[EAX] { head of chain := exRegRec.next }
\r
5386 CMP ECX,-1 { at end of list? }
\r
5387 JE @@exit { yes - didn't find it }
\r
5388 CMP [ECX],EAX { is it the next one on the list? }
\r
5389 JNE @@loop { no - look at next one on list }
\r
5390 @@unlink: { yes - unlink our record }
\r
5391 MOV EAX,[EAX] { get next record on list }
\r
5392 MOV [ECX],EAX { unlink our record }
\r
5397 {X+ see comments in InitUnits below }
\r
5398 //procedure FInitUnits; {X} - renamed to FInitUnitsHard
\r
5399 {X} procedure FInitUnitsHard;
\r
5402 Table: PUnitEntryTable;
\r
5405 if InitContext.InitTable = nil then
\r
5407 Count := InitContext.InitCount;
\r
5408 Table := InitContext.InitTable^.UnitInfo;
\r
5410 while Count > 0 do
\r
5413 InitContext.InitCount := Count;
\r
5414 P := Table^[Count].FInit;
\r
5415 if Assigned(P) then
\r
5419 {X- rename: FInitUnits; { try to finalize the others }
\r
5425 // This handler can be set in initialization section of
\r
5426 // unit SysSfIni.pas only.
\r
5427 procedure InitUnitsHard( Table : PUnitEntryTable; Idx, Count : Integer );
\r
5430 InitUnitsLight( Table, Idx, Count );
\r
5437 {X+ see comments in InitUnits below }
\r
5438 procedure FInitUnitsLight;
\r
5441 Table: PUnitEntryTable;
\r
5444 if InitContext.InitTable = nil then
\r
5446 Count := InitContext.InitCount;
\r
5447 Table := InitContext.InitTable^.UnitInfo;
\r
5448 while Count > 0 do
\r
5451 InitContext.InitCount := Count;
\r
5452 P := Table^[Count].FInit;
\r
5453 if Assigned(P) then
\r
5458 {X+ see comments in InitUnits below }
\r
5459 procedure InitUnitsLight( Table : PUnitEntryTable; Idx, Count : Integer );
\r
5460 var P : procedure;
\r
5463 Light := @InitUnitsProc = @InitUnitsLight;
\r
5464 while Idx < Count do
\r
5466 P := Table^[ Idx ].Init;
\r
5468 InitContext.InitCount := Idx;
\r
5469 if Assigned( P ) then
\r
5471 if Light and (@InitUnitsProc <> @InitUnitsLight) then
\r
5473 InitUnitsProc( Table, Idx, Count );
\r
5479 {X+ see comments in body of InitUnits below }
\r
5480 procedure InitUnits;
\r
5482 Count, I: Integer;
\r
5483 Table: PUnitEntryTable;
\r
5484 {X- P: procedure; }
\r
5486 if InitContext.InitTable = nil then
\r
5488 Count := InitContext.InitTable^.UnitCount;
\r
5490 Table := InitContext.InitTable^.UnitInfo;
\r
5491 {X- by default, Delphi InitUnits uses try-except & raise constructions,
\r
5492 which leads to permanent use of all exception handler routines.
\r
5493 Let us make this by another way.
\r
5495 while I < Count do
\r
5497 P := Table^[I].Init;
\r
5499 InitContext.InitCount := I;
\r
5500 if Assigned(P) then
\r
5508 InitUnitsProc( Table, I, Count );
\r
5512 procedure _PackageLoad(const Table : PackageInfo);
\r
5514 SavedContext: TInitContext;
\r
5516 SavedContext := InitContext;
\r
5517 InitContext.DLLInitState := 0;
\r
5518 InitContext.InitTable := Table;
\r
5519 InitContext.InitCount := 0;
\r
5520 InitContext.OuterContext := @SavedContext;
\r
5524 InitContext := SavedContext;
\r
5529 procedure _PackageUnload(const Table : PackageInfo);
\r
5531 SavedContext: TInitContext;
\r
5533 SavedContext := InitContext;
\r
5534 InitContext.DLLInitState := 0;
\r
5535 InitContext.InitTable := Table;
\r
5536 InitContext.InitCount := Table^.UnitCount;
\r
5537 InitContext.OuterContext := @SavedContext;
\r
5541 InitContext := SavedContext;
\r
5546 procedure _StartExe;
\r
5548 { -> EAX InitTable }
\r
5550 MOV InitContext.InitTable,EAX
\r
5552 MOV InitContext.InitCount,EAX
\r
5553 MOV InitContext.Module,EDX
\r
5554 MOV EAX,[EDX].TLibModule.Instance
\r
5555 MOV MainInstance,EAX
\r
5557 {X CALL SetExceptionHandler - moved to SysSfIni.pas }
\r
5565 procedure _StartLib;
\r
5567 { -> EAX InitTable }
\r
5570 { [ESP+4] DllProc }
\r
5572 { [EBP+12] Reason }
\r
5574 { Push some desperately needed registers }
\r
5580 { Save the current init context into the stackframe of our caller }
\r
5582 MOV ESI,offset InitContext
\r
5583 LEA EDI,[EBP- (type TExcFrame) - (type TInitContext)]
\r
5584 MOV ECX,(type TInitContext)/4
\r
5587 { Setup the current InitContext }
\r
5589 POP InitContext.DLLSaveEDI
\r
5590 POP InitContext.DLLSaveESI
\r
5591 MOV InitContext.DLLSaveEBP,EBP
\r
5592 MOV InitContext.DLLSaveEBX,EBX
\r
5593 MOV InitContext.InitTable,EAX
\r
5594 MOV InitContext.Module,EDX
\r
5595 LEA ECX,[EBP- (type TExcFrame) - (type TInitContext)]
\r
5596 MOV InitContext.OuterContext,ECX
\r
5598 CMP dword ptr [EBP+12],0
\r
5600 MOV ECX,[EAX].PackageInfoTable.UnitCount
\r
5602 MOV InitContext.InitCount,ECX
\r
5604 CALL SetExceptionHandler {X-- could be moved to SysSfIni.pas but ...}
\r
5608 MOV InitContext.DLLInitState,AL
\r
5611 { Init any needed TLS }
\r
5615 MOV InitContext.ExitProcessTLS,EDX
\r
5617 CALL dword ptr [ECX+EAX*4]
\r
5620 { Call any DllProc }
\r
5629 { Set IsLibrary if there was no exe yet }
\r
5631 CMP MainInstance,0
\r
5634 FNSTCW Default8087CW // save host exe's FPU preferences
\r
5646 procedure _InitResStrings;
\r
5648 { -> EAX Pointer to init table }
\r
5651 { tab: array [1..cnt] record }
\r
5652 { variableAddress: Pointer; }
\r
5653 { resStringAddress: Pointer; }
\r
5662 MOV EAX,[ESI+4] { load resStringAddress }
\r
5663 MOV EDX,[ESI] { load variableAddress }
\r
5664 CALL LoadResString
\r
5673 procedure _InitResStringImports;
\r
5675 { -> EAX Pointer to init table }
\r
5678 { tab: array [1..cnt] record }
\r
5679 { variableAddress: Pointer; }
\r
5680 { resStringAddress: ^Pointer; }
\r
5689 MOV EAX,[ESI+4] { load address of import }
\r
5690 MOV EDX,[ESI] { load address of variable }
\r
5691 MOV EAX,[EAX] { load contents of import }
\r
5692 CALL LoadResString
\r
5701 procedure _InitImports;
\r
5703 { -> EAX Pointer to init table }
\r
5706 { tab: array [1..cnt] record }
\r
5707 { variableAddress: Pointer; }
\r
5708 { sourceAddress: ^Pointer; }
\r
5709 { sourceOffset: Longint; }
\r
5718 MOV EAX,[ESI+4] { load address of import }
\r
5719 MOV EDX,[ESI] { load address of variable }
\r
5720 MOV ECX,[ESI+8] { load offset }
\r
5721 MOV EAX,[EAX] { load contents of import }
\r
5722 ADD EAX,ECX { calc address of variable }
\r
5723 MOV [EDX],EAX { store result }
\r
5732 procedure _InitWideStrings;
\r
5734 { -> EAX Pointer to init table }
\r
5737 { tab: array [1..cnt] record }
\r
5738 { variableAddress: Pointer; }
\r
5739 { stringAddress: ^Pointer; }
\r
5748 MOV EDX,[ESI+4] { load address of string }
\r
5749 MOV EAX,[ESI] { load address of variable }
\r
5760 runErrMsg: array[0..29] of Char = 'Runtime error at 00000000'#0;
\r
5761 // columns: 0123456789012345678901234567890
\r
5762 errCaption: array[0..5] of Char = 'Error'#0;
\r
5765 procedure MakeErrorMessage;
\r
5767 dig : array [0..15] of Char = '0123456789ABCDEF';
\r
5771 MOV EBX,offset runErrMsg + 16
\r
5785 CALL FindHInstance
\r
5786 MOV EDX, ErrorAddr
\r
5788 SUB EAX, EDX { EAX <=> offset from start of code for HINSTANCE }
\r
5789 MOV EBX,offset runErrMsg + 28
\r
5794 MOV DL,byte ptr dig[EDX]
\r
5803 procedure ExitDll;
\r
5805 { Restore the InitContext }
\r
5807 MOV EDI,offset InitContext
\r
5809 MOV EBX,InitContext.DLLSaveEBX
\r
5810 MOV EBP,InitContext.DLLSaveEBP
\r
5811 PUSH [EDI].TInitContext.DLLSaveESI
\r
5812 PUSH [EDI].TInitContext.DLLSaveEDI
\r
5814 MOV ESI,[EDI].TInitContext.OuterContext
\r
5815 MOV ECX,(type TInitContext)/4
\r
5820 { Return False if ExitCode <> 0, and set ExitCode to 0 }
\r
5831 // {X} Procedure Halt0 refers to WriteLn and MessageBox
\r
5832 // but actually such code can be not used really.
\r
5833 // So, implementation changed to avoid such references.
\r
5835 // Either call UseErrorMessageBox or UseErrorMessageWrite
\r
5836 // to provide error message output in GUI or console app.
\r
5839 var ErrorMessageOutProc : procedure = DummyProc;
\r
5841 procedure ErrorMessageBox;
\r
5844 if not NoErrMsg then
\r
5845 MessageBox(0, runErrMsg, errCaption, 0);
\r
5848 procedure UseErrorMessageBox;
\r
5850 ErrorMessageOutProc := ErrorMessageBox;
\r
5853 procedure ErrorMessageWrite;
\r
5856 WriteLn(PChar(@runErrMsg));
\r
5859 procedure UseErrorMessageWrite;
\r
5861 ErrorMessageOutProc := ErrorMessageWrite;
\r
5864 procedure DoCloseInputOutput;
\r
5870 var CloseInputOutput : procedure;
\r
5872 procedure UseInputOutput;
\r
5874 if not assigned( CloseInputOutput ) then
\r
5876 CloseInputOutput := DoCloseInputOutput;
\r
5877 _Assign( Input, '' );
\r
5878 _Assign( Output, '' );
\r
5889 if InitContext.DLLInitState = 0 then
\r
5890 while ExitProc <> nil do
\r
5897 { If there was some kind of runtime error, alert the user }
\r
5899 if ErrorAddr <> nil then
\r
5902 ErrorMessageOutProc;
\r
5906 WriteLn(PChar(@runErrMsg))
\r
5907 else if not NoErrMsg then
\r
5908 MessageBox(0, runErrMsg, errCaption, 0);
\r
5911 {X- As it is said by Alexey Torgashin, it is better not to clear ErrorAddr
\r
5912 to make possible check ErrorAddr <> nil in finalization of rest units.
\r
5913 If You want, You can uncomment it again: }
\r
5914 //ErrorAddr := nil;
\r
5918 { This loop exists because we might be nested in PackageLoad calls when }
\r
5919 { Halt got called. We need to unwind these contexts. }
\r
5924 { If we are a library, and we are starting up fine, there are no units to finalize }
\r
5926 if (InitContext.DLLInitState = 2) and (ExitCode = 0) then
\r
5927 InitContext.InitCount := 0;
\r
5929 { Undo any unit initializations accomplished so far }
\r
5933 if (InitContext.DLLInitState <= 1) or (ExitCode <> 0) then
\r
5934 if InitContext.Module <> nil then
\r
5935 with InitContext do
\r
5937 UnregisterModule(Module);
\r
5938 if Module.ResInstance <> Module.Instance then
\r
5939 FreeLibrary(Module.ResInstance);
\r
5942 {X UnsetExceptionHandler; - changed to call of handler }
\r
5943 UnsetExceptionHandlerProc;
\r
5945 if InitContext.DllInitState = 1 then
\r
5946 InitContext.ExitProcessTLS;
\r
5948 if InitContext.DllInitState <> 0 then
\r
5951 if InitContext.OuterContext = nil then
\r
5952 ExitProcess(ExitCode);
\r
5954 InitContext := InitContext.OuterContext^
\r
5958 db 'Portions Copyright (c) 1983,99 Borland',0
\r
5971 procedure _Run0Error;
\r
5978 procedure _RunError;
\r
5985 procedure _Assert(const Message, Filename: AnsiString; LineNumber: Integer);
\r
5987 CMP AssertErrorProc,0
\r
5989 PUSH [ESP].Pointer
\r
5990 CALL AssertErrorProc
\r
5992 @@1: MOV AL,reAssertionFailed
\r
5997 PThreadRec = ^TThreadRec;
\r
5998 TThreadRec = record
\r
5999 Func: TThreadFunc;
\r
6000 Parameter: Pointer;
\r
6004 function ThreadWrapper(Parameter: Pointer): Integer; stdcall;
\r
6009 PUSH offset _ExceptionHandler
\r
6015 MOV ECX,[EAX].TThreadRec.Parameter
\r
6016 MOV EDX,[EAX].TThreadRec.Func
\r
6032 function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
\r
6033 ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
\r
6034 var ThreadId: LongWord): Integer;
\r
6039 P.Func := ThreadFunc;
\r
6040 P.Parameter := Parameter;
\r
6041 IsMultiThread := TRUE;
\r
6042 Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P,
\r
6043 CreationFlags, ThreadID);
\r
6047 procedure EndThread(ExitCode: Integer);
\r
6049 ExitThread(ExitCode);
\r
6054 StrRec = packed record
\r
6055 allocSiz: Longint;
\r
6061 skew = sizeof(StrRec);
\r
6062 rOff = sizeof(StrRec) - sizeof(Longint); { refCnt offset }
\r
6063 overHead = sizeof(StrRec) + 1;
\r
6066 procedure _LStrClr(var S: AnsiString);
\r
6068 { -> EAX pointer to str }
\r
6070 MOV EDX,[EAX] { fetch str }
\r
6071 TEST EDX,EDX { if nil, nothing to do }
\r
6073 MOV dword ptr [EAX],0 { clear str }
\r
6074 MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
\r
6075 DEC ECX { if < 0: literal str }
\r
6077 {X LOCK} DEC [EDX-skew].StrRec.refCnt { NONthreadsafe dec refCount }
\r
6080 LEA EAX,[EDX-skew].StrRec.refCnt { if refCnt now zero, deallocate}
\r
6087 procedure _LStrArrayClr{var str: AnsiString; cnt: longint};
\r
6089 { -> EAX pointer to str }
\r
6098 MOV EDX,[EBX] { fetch str }
\r
6099 TEST EDX,EDX { if nil, nothing to do }
\r
6101 MOV dword ptr [EBX],0 { clear str }
\r
6102 MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
\r
6103 DEC ECX { if < 0: literal str }
\r
6105 {X LOCK} DEC [EDX-skew].StrRec.refCnt { NONthreadsafe dec refCount }
\r
6107 LEA EAX,[EDX-skew].StrRec.refCnt { if refCnt now zero, deallocate}
\r
6119 This function is used when assigning to global variables.
\r
6121 Literals are copied to prevent a situation where a dynamically
\r
6122 allocated DLL or package assigns a literal to a variable and then
\r
6123 is unloaded -- thereby causing the string memory (in the code
\r
6124 segment of the DLL) to be removed -- and therefore leaving the
\r
6125 global variable pointing to invalid memory.
\r
6127 procedure _LStrAsg{var dest: AnsiString; source: AnsiString};
\r
6129 { -> EAX pointer to dest str }
\r
6130 { -> EDX pointer to source str }
\r
6132 TEST EDX,EDX { have a source? }
\r
6133 JE @@2 { no -> jump }
\r
6135 MOV ECX,[EDX-skew].StrRec.refCnt
\r
6137 JG @@1 { literal string -> jump not taken }
\r
6141 MOV EAX,[EDX-skew].StrRec.length
\r
6142 CALL _NewAnsiString
\r
6146 MOV ECX,[EAX-skew].StrRec.length
\r
6153 {X LOCK} INC [EDX-skew].StrRec.refCnt
\r
6155 @@2: XCHG EDX,[EAX]
\r
6158 MOV ECX,[EDX-skew].StrRec.refCnt
\r
6161 {X LOCK} DEC [EDX-skew].StrRec.refCnt
\r
6163 LEA EAX,[EDX-skew].StrRec.refCnt
\r
6168 procedure _LStrLAsg{var dest: AnsiString; source: AnsiString};
\r
6170 { -> EAX pointer to dest }
\r
6176 { bump up the ref count of the source }
\r
6178 MOV ECX,[EDX-skew].StrRec.refCnt
\r
6180 JLE @@sourceDone { literal assignment -> jump taken }
\r
6181 {X LOCK} INC [EDX-skew].StrRec.refCnt
\r
6184 { we need to release whatever the dest is pointing to }
\r
6186 XCHG EDX,[EAX] { fetch str }
\r
6187 TEST EDX,EDX { if nil, nothing to do }
\r
6189 MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
\r
6190 DEC ECX { if < 0: literal str }
\r
6192 {X LOCK} DEC [EDX-skew].StrRec.refCnt { NONthreadsafe dec refCount }
\r
6194 LEA EAX,[EDX-skew].StrRec.refCnt { if refCnt now zero, deallocate}
\r
6199 function _NewAnsiString(length: Longint): Pointer;
\r
6200 {$IFDEF PUREPASCAL}
\r
6205 if length <= 0 then Exit;
\r
6206 // Alloc an extra null for strings with even length. This has no actual cost
\r
6207 // since the allocator will round up the request to an even size anyway.
\r
6208 // All widestring allocations have even length, and need a double null terminator.
\r
6209 GetMem(P, length + sizeof(StrRec) + 1 + ((length + 1) and 1));
\r
6210 Result := Pointer(Integer(P) + sizeof(StrRec));
\r
6211 P.length := length;
\r
6213 PWideChar(Result)[length div 2] := #0; // length guaranteed >= 2
\r
6218 { <- EAX pointer to new string }
\r
6223 ADD EAX,rOff+2 // one or two nulls (Ansi/Wide)
\r
6224 AND EAX, not 1 // round up to even length
\r
6227 POP EDX // actual allocated length (>= 2)
\r
6228 MOV word ptr [EAX+EDX-2],0 // double null terminator
\r
6230 POP EDX // requested string length
\r
6231 MOV [EAX-skew].StrRec.length,EDX
\r
6232 MOV [EAX-skew].StrRec.refCnt,1
\r
6240 {original, maybe buggy
\r
6241 procedure _NewAnsiString{length: Longint};
\r
6244 { <- EAX pointer to new string }
\r
6253 MOV [EAX-skew].StrRec.length,EDX
\r
6254 MOV [EAX-skew].StrRec.refCnt,1
\r
6255 MOV byte ptr [EAX+EDX],0
\r
6263 procedure _LStrFromPCharLen(var Dest: AnsiString; Source: PAnsiChar; Length: Integer);
\r
6265 { -> EAX pointer to dest }
\r
6277 { allocate new string }
\r
6281 CALL _NewAnsiString
\r
6292 { assign the result to dest }
\r
6305 procedure _LStrFromPWCharLen(var Dest: AnsiString; Source: PWideChar; Length: Integer);
\r
6308 Buffer: array[0..2047] of Char;
\r
6310 if Length <= 0 then
\r
6315 if Length < SizeOf(Buffer) div 2 then
\r
6317 DestLen := WideCharToMultiByte(0, 0, Source, Length,
\r
6318 Buffer, SizeOf(Buffer), nil, nil);
\r
6319 if DestLen > 0 then
\r
6321 _LStrFromPCharLen(Dest, Buffer, DestLen);
\r
6325 DestLen := WideCharToMultiByte(0, 0, Source, Length, nil, 0, nil, nil);
\r
6326 _LStrFromPCharLen(Dest, nil, DestLen);
\r
6327 WideCharToMultiByte(0, 0, Source, Length, Pointer(Dest), DestLen, nil, nil);
\r
6331 procedure _LStrFromChar(var Dest: AnsiString; Source: AnsiChar);
\r
6336 CALL _LStrFromPCharLen
\r
6341 procedure _LStrFromWChar(var Dest: AnsiString; Source: WideChar);
\r
6346 CALL _LStrFromPWCharLen
\r
6351 procedure _LStrFromPChar(var Dest: AnsiString; Source: PAnsiChar);
\r
6357 @@0: CMP CL,[EDX+0]
\r
6373 @@5: JMP _LStrFromPCharLen
\r
6377 procedure _LStrFromPWChar(var Dest: AnsiString; Source: PWideChar);
\r
6383 @@0: CMP CX,[EDX+0]
\r
6400 @@5: JMP _LStrFromPWCharLen
\r
6404 procedure _LStrFromString(var Dest: AnsiString; const Source: ShortString);
\r
6409 JMP _LStrFromPCharLen
\r
6413 procedure _LStrFromArray(var Dest: AnsiString; Source: PAnsiChar; Length: Integer);
\r
6427 JMP _LStrFromPCharLen
\r
6431 procedure _LStrFromWArray(var Dest: AnsiString; Source: PWideChar; Length: Integer);
\r
6445 JMP _LStrFromPWCharLen
\r
6449 procedure _LStrFromWStr(var Dest: AnsiString; const Source: WideString);
\r
6451 { -> EAX pointer to dest }
\r
6452 { EDX pointer to WideString data }
\r
6459 @@1: JMP _LStrFromPWCharLen
\r
6463 procedure _LStrToString{(var Dest: ShortString; const Source: AnsiString; MaxLen: Integer)};
\r
6465 { -> EAX pointer to result }
\r
6466 { EDX AnsiString s }
\r
6467 { ECX length of result }
\r
6472 MOV EBX,[EDX-skew].StrRec.length
\r
6489 MOV byte ptr [EAX],0
\r
6496 function _LStrLen{str: AnsiString}: Longint;
\r
6502 MOV EAX,[EAX-skew].StrRec.length;
\r
6507 procedure _LStrCat{var dest: AnsiString; source: AnsiString};
\r
6509 { -> EAX pointer to dest }
\r
6524 MOV EDI,[ECX-skew].StrRec.length
\r
6526 MOV EDX,[ESI-skew].StrRec.length
\r
6531 CALL _LStrSetLength
\r
6533 MOV ECX,[ESI-skew].StrRec.length
\r
6545 CALL _LStrSetLength
\r
6554 procedure _LStrCat3{var dest:AnsiString; source1: AnsiString; source2: AnsiString};
\r
6556 { ->EAX = Pointer to dest }
\r
6561 JE @@assignSource2
\r
6590 MOV EAX,[EBX-skew].StrRec.length
\r
6591 ADD EAX,[ESI-skew].StrRec.length
\r
6592 CALL _NewAnsiString
\r
6597 MOV ECX,[EBX-skew].StrRec.length
\r
6602 MOV ECX,[ESI-skew].StrRec.length
\r
6603 ADD EDX,[EBX-skew].StrRec.length
\r
6610 DEC [EDI-skew].StrRec.refCnt // EDI = local temp str
\r
6632 procedure _LStrCatN{var dest:AnsiString; argCnt: Integer; ...};
\r
6634 { ->EAX = Pointer to dest }
\r
6635 { EDX = number of args (>= 3) }
\r
6636 { [ESP+4], [ESP+8], ... crgCnt AnsiString arguments }
\r
6646 MOV ECX,[ESP+EDX*4+4*4]
\r
6649 ADD EAX,[ECX-skew].StrRec.length
\r
6654 CALL _NewAnsiString
\r
6659 MOV EAX,[ESP+EBX*4+5*4]
\r
6663 MOV ECX,[EAX-skew].StrRec.length
\r
6674 DEC [EDX-skew].StrRec.refCnt // EDX = local temp str
\r
6682 LEA ESP,[ESP+EDX*4]
\r
6687 procedure _LStrCmp{left: AnsiString; right: AnsiString};
\r
6689 { ->EAX = Pointer to left string }
\r
6690 { EDX = Pointer to right string }
\r
6708 MOV EAX,[ESI-skew].StrRec.length
\r
6709 MOV EDX,[EDI-skew].StrRec.length
\r
6711 SUB EAX,EDX { eax = len1 - len2 }
\r
6713 ADD EDX,EAX { edx = len2 + (len1 - len2) = len1 }
\r
6763 MOV EDX,[EDI-skew].StrRec.length
\r
6768 MOV EAX,[ESI-skew].StrRec.length
\r
6792 procedure _LStrAddRef{str: AnsiString};
\r
6797 MOV EDX,[EAX-skew].StrRec.refCnt
\r
6800 {X LOCK} INC [EAX-skew].StrRec.refCnt
\r
6805 procedure _LStrToPChar{str: AnsiString): PChar};
\r
6807 { -> EAX pointer to str }
\r
6808 { <- EAX pointer to PChar }
\r
6816 MOV EAX,offset @@zeroByte
\r
6820 procedure UniqueString(var str: string);
\r
6822 { -> EAX pointer to str }
\r
6823 { <- EAX pointer to unique copy }
\r
6827 MOV ECX,[EDX-skew].StrRec.refCnt
\r
6833 MOV EAX,[EDX-skew].StrRec.length
\r
6834 CALL _NewAnsiString
\r
6838 MOV ECX,[EAX-skew].StrRec.refCnt
\r
6841 {X LOCK} DEC [EAX-skew].StrRec.refCnt
\r
6843 MOV ECX,[EAX-skew].StrRec.length
\r
6852 procedure _LStrCopy{ const s : AnsiString; index, count : Integer) : AnsiString};
\r
6854 { ->EAX Source string }
\r
6857 { [ESP+4] Pointer to result string }
\r
6864 MOV EBX,[EAX-skew].StrRec.length
\r
6868 { make index 0-based and limit to 0 <= index < Length(src) }
\r
6877 { limit count to satisfy 0 <= count <= Length(src) - index }
\r
6879 SUB EBX,EDX { calculate Length(src) - index }
\r
6889 CALL _LStrFromPCharLen
\r
6909 procedure _LStrDelete{ var s : AnsiString; index, count : Integer };
\r
6911 { ->EAX Pointer to s }
\r
6926 TEST EDX,EDX { source already empty: nothing to do }
\r
6929 MOV ECX,[EDX-skew].StrRec.length
\r
6931 { make index 0-based, if not in [0 .. Length(s)-1] do nothing }
\r
6938 { limit count to [0 .. Length(s) - index] }
\r
6942 SUB ECX,ESI { ECX = Length(s) - index }
\r
6948 { move length - index - count characters from s+index+count to s+index }
\r
6950 SUB ECX,EDI { ECX = Length(s) - index - count }
\r
6951 ADD EDX,ESI { EDX = s+index }
\r
6952 LEA EAX,[EDX+EDI] { EAX = s+index+count }
\r
6955 { set length(s) to length(s) - count }
\r
6959 MOV EDX,[EDX-skew].StrRec.length
\r
6961 CALL _LStrSetLength
\r
6970 procedure _LStrInsert{ const source : AnsiString; var s : AnsiString; index : Integer };
\r
6972 { -> EAX source string }
\r
6973 { EDX pointer to destination string }
\r
6988 { make index 0-based and limit to 0 <= index <= Length(s) }
\r
6994 MOV EDX,[EDX-skew].StrRec.length
\r
7001 JLE @@indexNotHigh
\r
7005 MOV EBP,[EBX-skew].StrRec.length
\r
7007 { set length of result to length(source) + length(s) }
\r
7011 CALL _LStrSetLength
\r
7015 JNE @@notInsertSelf
\r
7020 { move length(s) - length(source) - index chars from s+index to s+index+length(source) }
\r
7022 MOV EAX,[ESI] { EAX = s }
\r
7023 LEA EDX,[EDI+EBP] { EDX = index + length(source) }
\r
7024 MOV ECX,[EAX-skew].StrRec.length
\r
7025 SUB ECX,EDX { ECX = length(s) - length(source) - index }
\r
7026 ADD EDX,EAX { EDX = s + index + length(source) }
\r
7027 ADD EAX,EDI { EAX = s + index }
\r
7030 { copy length(source) chars from source to s+index }
\r
7047 procedure _LStrPos{ const substr : AnsiString; const s : AnsiString ) : Integer};
\r
7049 { ->EAX Pointer to substr }
\r
7050 { EDX Pointer to string }
\r
7051 { <-EAX Position of substr in s or 0 }
\r
7063 MOV ESI,EAX { Point ESI to substr }
\r
7064 MOV EDI,EDX { Point EDI to s }
\r
7066 MOV ECX,[EDI-skew].StrRec.length { ECX = Length(s) }
\r
7068 PUSH EDI { remember s position to calculate index }
\r
7070 MOV EDX,[ESI-skew].StrRec.length { EDX = Length(substr) }
\r
7072 DEC EDX { EDX = Length(substr) - 1 }
\r
7073 JS @@fail { < 0 ? return 0 }
\r
7074 MOV AL,[ESI] { AL = first char of substr }
\r
7075 INC ESI { Point ESI to 2'nd char of substr }
\r
7077 SUB ECX,EDX { #positions in s to look at }
\r
7078 { = Length(s) - Length(substr) + 1 }
\r
7083 MOV EBX,ECX { save outer loop counter }
\r
7084 PUSH ESI { save outer loop substr pointer }
\r
7085 PUSH EDI { save outer loop s pointer }
\r
7089 POP EDI { restore outer loop s pointer }
\r
7090 POP ESI { restore outer loop substr pointer }
\r
7092 MOV ECX,EBX { restore outer loop counter }
\r
7096 POP EDX { get rid of saved s pointer }
\r
7105 POP EDX { restore pointer to first char of s }
\r
7106 MOV EAX,EDI { EDI points of char after match }
\r
7107 SUB EAX,EDX { the difference is the correct index }
\r
7116 procedure _LStrSetLength{ var str: AnsiString; newLength: Integer};
\r
7118 { -> EAX Pointer to str }
\r
7119 { EDX new length }
\r
7135 CMP [EAX-skew].StrRec.refCnt,1
\r
7146 MOV [EAX-skew].StrRec.length,ESI
\r
7147 MOV BYTE PTR [EAX+ESI],0
\r
7152 CALL _NewAnsiString
\r
7160 MOV ECX,[EAX-skew].StrRec.length
\r
7180 procedure _LStrOfChar{ c: Char; count: Integer): AnsiString };
\r
7201 CALL _NewAnsiString
\r
7218 procedure _Write0LString{ VAR t: Text; s: AnsiString };
\r
7220 { -> EAX Pointer to text record }
\r
7221 { EDX Pointer to AnsiString }
\r
7228 procedure _WriteLString{ VAR t: Text; s: AnsiString; width: Longint };
\r
7230 { -> EAX Pointer to text record }
\r
7231 { EDX Pointer to AnsiString }
\r
7232 { ECX Field width }
\r
7242 MOV ECX,[EBX-skew].StrRec.length
\r
7255 procedure _ReadLString{var t: Text; var str: AnsiString};
\r
7257 { -> EAX pointer to Text }
\r
7258 { EDX pointer to AnsiString }
\r
7277 CALL _LStrFromString
\r
7279 CMP byte ptr [ESP],255
\r
7291 CALL _LStrFromString
\r
7301 CMP byte ptr [ESP],255
\r
7311 procedure WStrError;
\r
7313 MOV AL,reOutOfMemory
\r
7318 procedure WStrSet(var S: WideString; P: PWideChar);
\r
7325 CALL SysFreeString
\r
7330 procedure WStrClr;
\r
7335 procedure _WStrClr(var S: WideString);
\r
7337 { -> EAX Pointer to WideString }
\r
7342 MOV DWORD PTR [EAX],0
\r
7345 CALL SysFreeString
\r
7351 procedure WStrArrayClr;
\r
7353 JMP _WStrArrayClr;
\r
7356 procedure _WStrArrayClr(var StrArray; Count: Integer);
\r
7362 @@1: MOV EAX,[EBX]
\r
7365 MOV DWORD PTR [EBX],0
\r
7367 CALL SysFreeString
\r
7376 procedure _WStrAsg(var Dest: WideString; const Source: WideString);
\r
7378 { -> EAX Pointer to WideString }
\r
7379 { EDX Pointer to data }
\r
7388 CALL SysReAllocStringLen
\r
7394 procedure _WStrFromPCharLen(var Dest: WideString; Source: PAnsiChar; Length: Integer);
\r
7397 Buffer: array[0..1023] of WideChar;
\r
7399 if Length <= 0 then
\r
7404 if Length < SizeOf(Buffer) div 2 then
\r
7406 DestLen := MultiByteToWideChar(0, 0, Source, Length,
\r
7407 Buffer, SizeOf(Buffer) div 2);
\r
7408 if DestLen > 0 then
\r
7410 _WStrFromPWCharLen(Dest, Buffer, DestLen);
\r
7414 DestLen := MultiByteToWideChar(0, 0, Source, Length, nil, 0);
\r
7415 _WStrFromPWCharLen(Dest, nil, DestLen);
\r
7416 MultiByteToWideChar(0, 0, Source, Length, Pointer(Dest), DestLen);
\r
7420 procedure _WStrFromPWCharLen(var Dest: WideString; Source: PWideChar; Length: Integer);
\r
7422 { -> EAX Pointer to WideString (dest) }
\r
7423 { EDX Pointer to characters (source) }
\r
7424 { ECX number of characters (not bytes) }
\r
7432 CALL SysAllocStringLen
\r
7437 PUSH [EDX].PWideChar
\r
7440 CALL SysFreeString
\r
7444 procedure _WStrFromChar(var Dest: WideString; Source: AnsiChar);
\r
7449 CALL _WStrFromPCharLen
\r
7454 procedure _WStrFromWChar(var Dest: WideString; Source: WideChar);
\r
7456 { -> EAX Pointer to WideString (dest) }
\r
7457 { EDX character (source) }
\r
7461 CALL _WStrFromPWCharLen
\r
7466 procedure _WStrFromPChar(var Dest: WideString; Source: PAnsiChar);
\r
7468 { -> EAX Pointer to WideString (dest) }
\r
7469 { EDX Pointer to character (source) }
\r
7474 @@0: CMP CL,[EDX+0]
\r
7490 @@5: JMP _WStrFromPCharLen
\r
7494 procedure _WStrFromPWChar(var Dest: WideString; Source: PWideChar);
\r
7496 { -> EAX Pointer to WideString (dest) }
\r
7497 { EDX Pointer to character (source) }
\r
7502 @@0: CMP CX,[EDX+0]
\r
7519 @@5: JMP _WStrFromPWCharLen
\r
7523 procedure _WStrFromString(var Dest: WideString; const Source: ShortString);
\r
7528 JMP _WStrFromPCharLen
\r
7532 procedure _WStrFromArray(var Dest: WideString; Source: PAnsiChar; Length: Integer);
\r
7546 JMP _WStrFromPCharLen
\r
7550 procedure _WStrFromWArray(var Dest: WideString; Source: PWideChar; Length: Integer);
\r
7564 JMP _WStrFromPWCharLen
\r
7568 procedure _WStrFromLStr(var Dest: WideString; const Source: AnsiString);
\r
7574 @@1: JMP _WStrFromPCharLen
\r
7578 procedure _WStrToString(Dest: PShortString; const Source: WideString; MaxLen: Integer);
\r
7580 SourceLen, DestLen: Integer;
\r
7581 Buffer: array[0..511] of Char;
\r
7583 SourceLen := Length(Source);
\r
7584 if SourceLen >= 255 then SourceLen := 255;
\r
7585 if SourceLen = 0 then DestLen := 0 else
\r
7587 DestLen := WideCharToMultiByte(0, 0, Pointer(Source), SourceLen,
\r
7588 Buffer, SizeOf(Buffer), nil, nil);
\r
7589 if DestLen > MaxLen then DestLen := MaxLen;
\r
7591 Dest^[0] := Chr(DestLen);
\r
7592 if DestLen > 0 then Move(Buffer, Dest^[1], DestLen);
\r
7596 function _WStrToPWChar(const S: WideString): PWideChar;
\r
7603 @@1: MOV EAX,OFFSET @@0
\r
7607 function _WStrLen(const S: WideString): Integer;
\r
7609 { -> EAX Pointer to WideString data }
\r
7618 procedure _WStrCat(var Dest: WideString; const Source: WideString);
\r
7620 DestLen, SourceLen: Integer;
\r
7621 NewStr: PWideChar;
\r
7623 SourceLen := Length(Source);
\r
7624 if SourceLen <> 0 then
\r
7626 DestLen := Length(Dest);
\r
7627 NewStr := _NewWideString(DestLen + SourceLen);
\r
7628 if DestLen > 0 then
\r
7629 Move(Pointer(Dest)^, NewStr^, DestLen * 2);
\r
7630 Move(Pointer(Source)^, NewStr[DestLen], SourceLen * 2);
\r
7631 WStrSet(Dest, NewStr);
\r
7636 procedure _WStrCat3(var Dest: WideString; const Source1, Source2: WideString);
\r
7638 Source1Len, Source2Len: Integer;
\r
7639 NewStr: PWideChar;
\r
7641 Source1Len := Length(Source1);
\r
7642 Source2Len := Length(Source2);
\r
7643 if (Source1Len <> 0) or (Source2Len <> 0) then
\r
7645 NewStr := _NewWideString(Source1Len + Source2Len);
\r
7646 Move(Pointer(Source1)^, Pointer(NewStr)^, Source1Len * 2);
\r
7647 Move(Pointer(Source2)^, NewStr[Source1Len], Source2Len * 2);
\r
7648 WStrSet(Dest, NewStr);
\r
7653 procedure _WStrCatN{var Dest: WideString; ArgCnt: Integer; ...};
\r
7655 { ->EAX = Pointer to dest }
\r
7656 { EDX = number of args (>= 3) }
\r
7657 { [ESP+4], [ESP+8], ... crgCnt WideString arguments }
\r
7667 MOV ECX,[ESP+EDX*4+4*4]
\r
7676 CALL _NewWideString
\r
7681 MOV EAX,[ESP+EBX*4+5*4]
\r
7700 LEA ESP,[ESP+EDX*4]
\r
7705 procedure _WStrCmp{left: WideString; right: WideString};
\r
7707 { ->EAX = Pointer to left string }
\r
7708 { EDX = Pointer to right string }
\r
7729 SUB EAX,EDX { eax = len1 - len2 }
\r
7731 ADD EDX,EAX { edx = len2 + (len1 - len2) = len1 }
\r
7795 function _NewWideString(Length: Integer): PWideChar;
\r
7801 CALL SysAllocStringLen
\r
7808 function _WStrCopy(const S: WideString; Index, Count: Integer): WideString;
\r
7813 if Index < 1 then Index := 0 else
\r
7816 if Index > L then Index := L;
\r
7818 if Count < 0 then N := 0 else
\r
7821 if N > Count then N := Count;
\r
7823 _WStrFromPWCharLen(Result, PWideChar(Pointer(S)) + Index, N);
\r
7827 procedure _WStrDelete(var S: WideString; Index, Count: Integer);
\r
7830 NewStr: PWideChar;
\r
7833 if (L > 0) and (Index >= 1) and (Index <= L) and (Count > 0) then
\r
7836 N := L - Index - Count;
\r
7837 if N < 0 then N := 0;
\r
7838 if (Index = 0) and (N = 0) then NewStr := nil else
\r
7840 NewStr := _NewWideString(Index + N);
\r
7842 Move(Pointer(S)^, NewStr^, Index * 2);
\r
7844 Move(PWideChar(Pointer(S))[L - N], NewStr[Index], N * 2);
\r
7846 WStrSet(S, NewStr);
\r
7851 procedure _WStrInsert(const Source: WideString; var Dest: WideString; Index: Integer);
\r
7853 SourceLen, DestLen: Integer;
\r
7854 NewStr: PWideChar;
\r
7856 SourceLen := Length(Source);
\r
7857 if SourceLen > 0 then
\r
7859 DestLen := Length(Dest);
\r
7860 if Index < 1 then Index := 0 else
\r
7863 if Index > DestLen then Index := DestLen;
\r
7865 NewStr := _NewWideString(DestLen + SourceLen);
\r
7867 Move(Pointer(Dest)^, NewStr^, Index * 2);
\r
7868 Move(Pointer(Source)^, NewStr[Index], SourceLen * 2);
\r
7869 if Index < DestLen then
\r
7870 Move(PWideChar(Pointer(Dest))[Index], NewStr[Index + SourceLen],
\r
7871 (DestLen - Index) * 2);
\r
7872 WStrSet(Dest, NewStr);
\r
7877 procedure _WStrPos{ const substr : WideString; const s : WideString ) : Integer};
\r
7879 { ->EAX Pointer to substr }
\r
7880 { EDX Pointer to string }
\r
7881 { <-EAX Position of substr in s or 0 }
\r
7893 MOV ESI,EAX { Point ESI to substr }
\r
7894 MOV EDI,EDX { Point EDI to s }
\r
7896 MOV ECX,[EDI-4] { ECX = Length(s) }
\r
7899 PUSH EDI { remember s position to calculate index }
\r
7901 MOV EDX,[ESI-4] { EDX = Length(substr) }
\r
7904 DEC EDX { EDX = Length(substr) - 1 }
\r
7905 JS @@fail { < 0 ? return 0 }
\r
7906 MOV AX,[ESI] { AL = first char of substr }
\r
7907 ADD ESI,2 { Point ESI to 2'nd char of substr }
\r
7909 SUB ECX,EDX { #positions in s to look at }
\r
7910 { = Length(s) - Length(substr) + 1 }
\r
7915 MOV EBX,ECX { save outer loop counter }
\r
7916 PUSH ESI { save outer loop substr pointer }
\r
7917 PUSH EDI { save outer loop s pointer }
\r
7921 POP EDI { restore outer loop s pointer }
\r
7922 POP ESI { restore outer loop substr pointer }
\r
7924 MOV ECX,EBX { restore outer loop counter }
\r
7928 POP EDX { get rid of saved s pointer }
\r
7937 POP EDX { restore pointer to first char of s }
\r
7938 MOV EAX,EDI { EDI points of char after match }
\r
7939 SUB EAX,EDX { the difference is the correct index }
\r
7949 procedure _WStrSetLength(var S: WideString; NewLength: Integer);
\r
7951 NewStr: PWideChar;
\r
7955 if NewLength > 0 then
\r
7957 NewStr := _NewWideString(NewLength);
\r
7958 Count := Length(S);
\r
7961 if Count > NewLength then Count := NewLength;
\r
7962 Move(Pointer(S)^, NewStr^, Count * 2);
\r
7965 WStrSet(S, NewStr);
\r
7969 function _WStrOfWChar(Ch: WideChar; Count: Integer): WideString;
\r
7973 _WStrFromPWCharLen(Result, nil, Count);
\r
7974 P := Pointer(Result);
\r
7975 while Count > 0 do
\r
7982 procedure WStrAddRef;
\r
7987 procedure _WStrAddRef{var str: WideString};
\r
7997 CALL SysAllocStringLen
\r
8006 procedure _InitializeRecord{ p: Pointer; typeInfo: Pointer };
\r
8008 { -> EAX pointer to record to be initialized }
\r
8009 { EDX pointer to type info }
\r
8014 MOV CL,[EDX+1] { type name length }
\r
8020 LEA ESI,[EDX+ECX+2+8] { address of destructable fields }
\r
8021 MOV EDI,[EDX+ECX+2+4] { number of destructable fields }
\r
8049 procedure _InitializeArray{ p: Pointer; typeInfo: Pointer; elemCount: Longint};
\r
8051 { -> EAX pointer to data to be initialized }
\r
8052 { EDX pointer to type info describing data }
\r
8053 { ECX number of elements of that type }
\r
8077 CMP AL,tkInterface
\r
8081 MOV AL,reInvalidPtr
\r
8111 MOV EDX,[ESI+EBP+2+8]
\r
8113 ADD EBX,[ESI+EBP+2]
\r
8114 MOV ECX,[ESI+EBP+2+4]
\r
8116 CALL _InitializeArray
\r
8127 ADD EBX,[ESI+EBP+2]
\r
8129 CALL _InitializeRecord
\r
8142 procedure _Initialize{ p: Pointer; typeInfo: Pointer};
\r
8145 JMP _InitializeArray
\r
8148 procedure _FinalizeRecord{ p: Pointer; typeInfo: Pointer };
\r
8150 { -> EAX pointer to record to be finalized }
\r
8151 { EDX pointer to type info }
\r
8162 LEA ESI,[EDX+ECX+2+8]
\r
8163 MOV EDI,[EDX+ECX+2+4]
\r
8184 procedure _FinalizeArray{ p: Pointer; typeInfo: Pointer; elemCount: Longint};
\r
8186 { -> EAX pointer to data to be finalized }
\r
8187 { EDX pointer to type info describing data }
\r
8188 { ECX number of elements of that type }
\r
8190 CMP ECX, 0 { no array -> nop }
\r
8220 CMP AL,tkInterface
\r
8229 MOV AL,reInvalidPtr
\r
8240 CALL _LStrArrayClr
\r
8248 CALL [WStrClrProc]
\r
8252 //CALL _WStrArrayClr
\r
8253 CALL [WStrArrayClrProc]
\r
8269 MOV EDX,[ESI+EBP+2+8]
\r
8271 ADD EBX,[ESI+EBP+2]
\r
8272 MOV ECX,[ESI+EBP+2+4]
\r
8274 CALL _FinalizeArray
\r
8284 { inv: EDI = number of array elements to finalize }
\r
8287 ADD EBX,[ESI+EBP+2]
\r
8289 CALL _FinalizeRecord
\r
8307 CALL _DynArrayClear
\r
8321 procedure _Finalize{ p: Pointer; typeInfo: Pointer};
\r
8324 JMP _FinalizeArray
\r
8327 procedure _AddRefRecord{ p: Pointer; typeInfo: Pointer };
\r
8329 { -> EAX pointer to record to be referenced }
\r
8330 { EDX pointer to type info }
\r
8341 LEA ESI,[EDX+ECX+2+8]
\r
8342 MOV EDI,[EDX+ECX+2+4]
\r
8360 procedure DummyProc;
\r
8364 procedure _AddRefArray{ p: Pointer; typeInfo: Pointer; elemCount: Longint};
\r
8366 { -> EAX pointer to data to be referenced }
\r
8367 { EDX pointer to type info describing data }
\r
8368 { ECX number of elements of that type }
\r
8391 CMP AL,tkInterface
\r
8395 MOV AL,reInvalidPtr
\r
8412 //CALL _WStrAddRef
\r
8413 CALL [WStrAddRefProc]
\r
8422 CALL [VarAddRefProc]
\r
8431 MOV EDX,[ESI+EBP+2+8]
\r
8433 ADD EBX,[ESI+EBP+2]
\r
8434 MOV ECX,[ESI+EBP+2+4]
\r
8447 ADD EBX,[ESI+EBP+2]
\r
8449 CALL _AddRefRecord
\r
8466 CALL _DynArrayAddRef
\r
8477 procedure _AddRef{ p: Pointer; typeInfo: Pointer};
\r
8484 procedure _CopyRecord{ dest, source, typeInfo: Pointer };
\r
8486 { -> EAX pointer to dest }
\r
8487 { EDX pointer to source }
\r
8488 { ECX pointer to typeInfo }
\r
8501 LEA EDI,[ECX+EAX+2+8]
\r
8531 CMP CL,tkInterface
\r
8535 MOV AL,reInvalidPtr
\r
8566 PUSH dword ptr [EDX+ECX+2]
\r
8567 PUSH dword ptr [EDX+ECX+2+4]
\r
8568 MOV ECX,[EDX+ECX+2+8]
\r
8579 MOV ECX,[EDX+ECX+2]
\r
8623 procedure _CopyObject{ dest, source: Pointer; vmtPtrOffs: Longint; typeInfo: Pointer };
\r
8625 { -> EAX pointer to dest }
\r
8626 { EDX pointer to source }
\r
8627 { ECX offset of vmt in object }
\r
8628 { [ESP+4] pointer to typeInfo }
\r
8630 ADD ECX,EAX { pointer to dest vmt }
\r
8631 PUSH dword ptr [ECX] { save dest vmt }
\r
8633 MOV ECX,[ESP+4+4+4]
\r
8636 POP dword ptr [ECX] { restore dest vmt }
\r
8641 procedure _CopyArray{ dest, source, typeInfo: Pointer; cnt: Integer };
\r
8643 { -> EAX pointer to dest }
\r
8644 { EDX pointer to source }
\r
8645 { ECX pointer to typeInfo }
\r
8655 MOV EBP,[ESP+4+4*4]
\r
8669 CMP CL,tkInterface
\r
8673 MOV AL,reInvalidPtr
\r
8713 LEA EDI,[EDI+ECX+2]
\r
8718 PUSH dword ptr [EDI+4]
\r
8733 ADD EBX,[EDI+EAX+2]
\r
8734 ADD ESI,[EDI+EAX+2]
\r
8768 procedure _New{ size: Longint; typeInfo: Pointer};
\r
8770 { -> EAX size of object to allocate }
\r
8771 { EDX pointer to typeInfo }
\r
8784 procedure _Dispose{ p: Pointer; typeInfo: Pointer};
\r
8786 { -> EAX Pointer to object to be disposed }
\r
8787 { EDX Pointer to type info }
\r
8795 { ----------------------------------------------------- }
\r
8796 { Wide character support }
\r
8797 { ----------------------------------------------------- }
\r
8799 function WideCharToString(Source: PWideChar): string;
\r
8801 WideCharToStrVar(Source, Result);
\r
8804 function WideCharLenToString(Source: PWideChar; SourceLen: Integer): string;
\r
8806 WideCharLenToStrVar(Source, SourceLen, Result);
\r
8809 procedure WideCharToStrVar(Source: PWideChar; var Dest: string);
\r
8811 SourceLen: Integer;
\r
8814 while Source[SourceLen] <> #0 do Inc(SourceLen);
\r
8815 WideCharLenToStrVar(Source, SourceLen, Dest);
\r
8818 procedure WideCharLenToStrVar(Source: PWideChar; SourceLen: Integer;
\r
8819 var Dest: string);
\r
8822 Buffer: array[0..2047] of Char;
\r
8824 if SourceLen = 0 then
\r
8827 if SourceLen < SizeOf(Buffer) div 2 then
\r
8828 SetString(Dest, Buffer, WideCharToMultiByte(0, 0,
\r
8829 Source, SourceLen, Buffer, SizeOf(Buffer), nil, nil))
\r
8832 DestLen := WideCharToMultiByte(0, 0, Source, SourceLen,
\r
8833 nil, 0, nil, nil);
\r
8834 SetString(Dest, nil, DestLen);
\r
8835 WideCharToMultiByte(0, 0, Source, SourceLen, Pointer(Dest),
\r
8836 DestLen, nil, nil);
\r
8840 function StringToWideChar(const Source: string; Dest: PWideChar;
\r
8841 DestSize: Integer): PWideChar;
\r
8843 Dest[MultiByteToWideChar(0, 0, PChar(Source), Length(Source),
\r
8844 Dest, DestSize - 1)] := #0;
\r
8848 { ----------------------------------------------------- }
\r
8849 { OLE string support }
\r
8850 { ----------------------------------------------------- }
\r
8852 function OleStrToString(Source: PWideChar): string;
\r
8854 OleStrToStrVar(Source, Result);
\r
8857 procedure OleStrToStrVar(Source: PWideChar; var Dest: string);
\r
8859 WideCharLenToStrVar(Source, SysStringLen(WideString(Pointer(Source))), Dest);
\r
8862 function StringToOleStr(const Source: string): PWideChar;
\r
8864 SourceLen, ResultLen: Integer;
\r
8865 Buffer: array[0..1023] of WideChar;
\r
8867 SourceLen := Length(Source);
\r
8868 if Length(Source) < SizeOf(Buffer) div 2 then
\r
8869 Result := SysAllocStringLen(Buffer, MultiByteToWideChar(0, 0,
\r
8870 PChar(Source), SourceLen, Buffer, SizeOf(Buffer) div 2))
\r
8873 ResultLen := MultiByteToWideChar(0, 0,
\r
8874 Pointer(Source), SourceLen, nil, 0);
\r
8875 Result := SysAllocStringLen(nil, ResultLen);
\r
8876 MultiByteToWideChar(0, 0, Pointer(Source), SourceLen,
\r
8877 Result, ResultLen);
\r
8881 { ----------------------------------------------------- }
\r
8882 { Variant support }
\r
8883 { ----------------------------------------------------- }
\r
8886 TBaseType = (btErr, btNul, btInt, btFlt, btCur, btStr, btBol, btDat);
\r
8889 varLast = varByte;
\r
8892 BaseTypeMap: array[0..varLast] of TBaseType = (
\r
8893 btErr, { varEmpty }
\r
8894 btNul, { varNull }
\r
8895 btInt, { varSmallint }
\r
8896 btInt, { varInteger }
\r
8897 btFlt, { varSingle }
\r
8898 btFlt, { varDouble }
\r
8899 btCur, { varCurrency }
\r
8900 btDat, { varDate }
\r
8901 btStr, { varOleStr }
\r
8902 btErr, { varDispatch }
\r
8903 btErr, { varError }
\r
8904 btBol, { varBoolean }
\r
8905 btErr, { varVariant }
\r
8906 btErr, { varUnknown }
\r
8907 btErr, { vt_decimal }
\r
8908 btErr, { undefined }
\r
8910 btInt); { varByte }
\r
8913 OpTypeMap: array[TBaseType, TBaseType] of TBaseType = (
\r
8914 (btErr, btErr, btErr, btErr, btErr, btErr, btErr, btErr),
\r
8915 (btErr, btNul, btNul, btNul, btNul, btNul, btNul, btNul),
\r
8916 (btErr, btNul, btInt, btFlt, btCur, btFlt, btInt, btDat),
\r
8917 (btErr, btNul, btFlt, btFlt, btCur, btFlt, btFlt, btDat),
\r
8918 (btErr, btNul, btCur, btCur, btCur, btCur, btCur, btDat),
\r
8919 (btErr, btNul, btFlt, btFlt, btCur, btStr, btBol, btDat),
\r
8920 (btErr, btNul, btInt, btFlt, btCur, btBol, btBol, btDat),
\r
8921 (btErr, btNul, btDat, btDat, btDat, btDat, btDat, btDat));
\r
8924 C10000: Single = 10000;
\r
8939 procedure _DispInvoke;
\r
8941 { -> [ESP+4] Pointer to result or nil }
\r
8942 { [ESP+8] Pointer to variant }
\r
8943 { [ESP+12] Pointer to call descriptor }
\r
8944 { [ESP+16] Additional parameters, if any }
\r
8949 procedure _DispInvokeError;
\r
8951 MOV AL,reVarDispatch
\r
8955 procedure VarCastError;
\r
8957 MOV AL,reVarTypeCast
\r
8961 procedure VarInvalidOp;
\r
8963 MOV AL,reVarInvalidOp
\r
8967 procedure _VarClear(var V : Variant);
\r
8970 MOV DX,[EAX].TVarData.VType
\r
8979 JMP [ClearAnyProc]
\r
8980 @@1: MOV [EAX].TVarData.VType,varEmpty
\r
8981 ADD EAX,OFFSET TVarData.VString
\r
8983 @@2: MOV [EAX].TVarData.VType,varEmpty
\r
8989 procedure _VarCopy(var Dest : Variant; const Source: Variant);
\r
8993 CMP [EAX].TVarData.VType,varOleStr
\r
8997 CMP [EAX].TVarData.VType,varString
\r
8999 CMP [EAX].TVarData.VType,varAny
\r
9004 @@0: CALL [ClearAnyProc]
\r
9006 @@1: ADD EAX,OFFSET TVarData.VString
\r
9010 @@3: CMP [EDX].TVarData.VType,varOleStr
\r
9012 @@4: MOV ECX,[EDX]
\r
9019 @@5: CMP [EDX].TVarData.VType,varString
\r
9021 CMP [EDX].TVarData.VType,varAny
\r
9027 @@6: MOV EDX,[EDX].TVarData.VString
\r
9030 MOV ECX,[EDX-skew].StrRec.refCnt
\r
9033 {X LOCK} INC [EDX-skew].StrRec.refCnt
\r
9034 @@7: MOV [EAX].TVarData.VType,varString
\r
9035 MOV [EAX].TVarData.VString,EDX
\r
9037 @@8: MOV [EAX].TVarData.VType,varEmpty
\r
9040 CALL VariantCopyInd
\r
9046 procedure VarCopyNoInd(var Dest: Variant; const Source: Variant);
\r
9050 CMP [EAX].TVarData.VType,varOleStr
\r
9054 CMP [EAX].TVarData.VType,varString
\r
9056 CMP [EAX].TVarData.VType,varAny
\r
9061 @@0: CALL [ClearAnyProc]
\r
9063 @@1: ADD EAX,OFFSET TVarData.VString
\r
9067 @@3: CMP [EDX].TVarData.VType,varOleStr
\r
9069 @@4: MOV ECX,[EDX]
\r
9076 @@5: CMP [EDX].TVarData.VType,varString
\r
9078 CMP [EDX].TVarData.VType,varAny
\r
9082 @@6: MOV EDX,[EDX].TVarData.VString
\r
9085 MOV ECX,[EDX-skew].StrRec.refCnt
\r
9088 {X LOCK} INC [EDX-skew].StrRec.refCnt
\r
9089 @@7: MOV [EAX].TVarData.VType,varString
\r
9090 MOV [EAX].TVarData.VString,EDX
\r
9092 @@8: MOV [EAX].TVarData.VType,varEmpty
\r
9100 TAnyProc = procedure (var V: Variant);
\r
9102 procedure VarChangeType(var Dest: Variant; const Source: Variant;
\r
9103 DestType: Word); forward;
\r
9105 procedure AnyChangeType(var Dest: Variant; Source: Variant; DestType: Word);
\r
9107 TAnyProc(ChangeAnyProc)(Source);
\r
9108 VarChangeType(Dest, Source, DestType);
\r
9111 procedure VarChangeType(var Dest: Variant; const Source: Variant;
\r
9114 TVarMem = array[0..3] of Integer;
\r
9116 function ChangeSourceAny(var Dest: Variant; const Source: Variant;
\r
9117 DestType: Word): Boolean;
\r
9120 if TVarData(Source).VType = varAny then
\r
9122 AnyChangeType(Dest, Source, DestType);
\r
9130 case TVarData(Dest).VType of
\r
9133 if not ChangeSourceAny(Dest, Source, DestType) then
\r
9135 Temp.VType := varEmpty;
\r
9136 if VariantChangeTypeEx(Variant(Temp), Source, $400, 0, DestType) <> 0 then
\r
9139 TVarMem(Dest)[0] := TVarMem(Temp)[0];
\r
9140 TVarMem(Dest)[2] := TVarMem(Temp)[2];
\r
9141 TVarMem(Dest)[3] := TVarMem(Temp)[3];
\r
9144 varAny: AnyChangeType(Dest, Source, DestType);
\r
9145 else if not ChangeSourceAny(Dest, Source, DestType) then
\r
9146 if VariantChangeTypeEx(Dest, Source, $400, 0, DestType) <> 0 then
\r
9151 procedure VarOleStrToString(var Dest: Variant; const Source: Variant);
\r
9153 StringPtr: Pointer;
\r
9156 OleStrToStrVar(TVarData(Source).VOleStr, string(StringPtr));
\r
9158 TVarData(Dest).VType := varString;
\r
9159 TVarData(Dest).VString := StringPtr;
\r
9162 procedure VarStringToOleStr(var Dest: Variant; const Source: Variant);
\r
9164 OleStrPtr: PWideChar;
\r
9166 OleStrPtr := StringToOleStr(string(TVarData(Source).VString));
\r
9168 TVarData(Dest).VType := varOleStr;
\r
9169 TVarData(Dest).VOleStr := OleStrPtr;
\r
9172 procedure _VarCast(var Dest : Variant; const Source: Variant; VarType: Integer);
\r
9174 SourceType, DestType: Word;
\r
9177 SourceType := TVarData(Source).VType;
\r
9178 DestType := Word(VarType);
\r
9179 if SourceType = DestType then
\r
9180 _VarCopy(Dest, Source)
\r
9182 if SourceType = varString then
\r
9183 if DestType = varOleStr then
\r
9184 VarStringToOleStr(Variant(Dest), Source)
\r
9187 Temp.VType := varEmpty;
\r
9188 VarStringToOleStr(Variant(Temp), Source);
\r
9190 VarChangeType(Variant(Dest), Variant(Temp), DestType);
\r
9192 _VarClear(PVariant(@Temp)^);
\r
9196 if (DestType = varString) and (SourceType <> varAny) then
\r
9197 if SourceType = varOleStr then
\r
9198 VarOleStrToString(Variant(Dest), Source)
\r
9201 Temp.VType := varEmpty;
\r
9202 VarChangeType(Variant(Temp), Source, varOleStr);
\r
9204 VarOleStrToString(Variant(Dest), Variant(Temp));
\r
9206 _VarClear(Variant(Temp));
\r
9210 VarChangeType(Variant(Dest), Source, DestType);
\r
9213 (* VarCast when the destination is OleVariant *)
\r
9214 procedure _VarCastOle(var Dest : Variant; const Source: Variant; VarType: Integer);
\r
9216 if (VarType = varString) or (VarType = varAny) then
\r
9219 _VarCast(Dest, Source, VarType);
\r
9222 procedure _VarToInt;
\r
9225 MOV DX,[EAX].TVarData.VType
\r
9226 CMP EDX,varInteger
\r
9228 CMP EDX,varSmallint
\r
9236 CMP EDX,varCurrency
\r
9239 MOV [ESP].TVarData.VType,varEmpty
\r
9242 MOV ECX,varInteger
\r
9244 MOV EAX,[ESP].TVarData.VInteger
\r
9247 @@0: MOV EAX,[EAX].TVarData.VInteger
\r
9249 @@1: MOVSX EAX,[EAX].TVarData.VSmallint
\r
9251 @@2: MOVZX EAX,[EAX].TVarData.VByte
\r
9253 @@3: FILD [EAX].TVarData.VCurrency
\r
9256 @@4: FLD [EAX].TVarData.VSingle
\r
9258 @@5: FLD [EAX].TVarData.VDouble
\r
9260 FISTP DWORD PTR [ESP]
\r
9265 procedure _VarToBool;
\r
9267 CMP [EAX].TVarData.VType,varBoolean
\r
9270 MOV [ESP].TVarData.VType,varEmpty
\r
9273 MOV ECX,varBoolean
\r
9275 MOV AX,[ESP].TVarData.VBoolean
\r
9278 @@1: MOV AX,[EAX].TVarData.VBoolean
\r
9284 procedure _VarToReal;
\r
9287 MOV DX,[EAX].TVarData.VType
\r
9292 CMP EDX,varCurrency
\r
9294 CMP EDX,varInteger
\r
9296 CMP EDX,varSmallint
\r
9301 MOV [ESP].TVarData.VType,varEmpty
\r
9306 FLD [ESP].TVarData.VDouble
\r
9309 @@1: FLD [EAX].TVarData.VDouble
\r
9311 @@2: FLD [EAX].TVarData.VSingle
\r
9313 @@3: FILD [EAX].TVarData.VCurrency
\r
9316 @@4: FILD [EAX].TVarData.VInteger
\r
9318 @@5: FILD [EAX].TVarData.VSmallint
\r
9321 procedure _VarToCurr;
\r
9324 MOV DX,[EAX].TVarData.VType
\r
9325 CMP EDX,varCurrency
\r
9331 CMP EDX,varInteger
\r
9333 CMP EDX,varSmallint
\r
9336 MOV [ESP].TVarData.VType,varEmpty
\r
9339 MOV ECX,varCurrency
\r
9341 FILD [ESP].TVarData.VCurrency
\r
9344 @@1: FILD [EAX].TVarData.VCurrency
\r
9346 @@2: FLD [EAX].TVarData.VDouble
\r
9348 @@3: FLD [EAX].TVarData.VSingle
\r
9350 @@4: FILD [EAX].TVarData.VInteger
\r
9352 @@5: FILD [EAX].TVarData.VSmallint
\r
9356 procedure _VarToPStr(var S; const V: Variant);
\r
9360 _VarToLStr(Temp, V);
\r
9361 ShortString(S) := Temp;
\r
9364 procedure _VarToLStr(var S: string; const V: Variant);
\r
9366 { -> EAX: destination string }
\r
9367 { EDX: source variant }
\r
9370 CMP [EDX].TVarData.VType,varString
\r
9372 MOV EDX,[EDX].TVarData.VString
\r
9377 MOV [ESP].TVarData.VType,varEmpty
\r
9383 MOV EAX,[ESP].TVarData.VString
\r
9389 procedure _VarToWStr(var S: WideString; const V: Variant);
\r
9391 CMP [EDX].TVarData.VType,varOleStr
\r
9393 MOV EDX,[EDX].TVarData.VOleStr
\r
9398 MOV [ESP].TVarData.VType,varEmpty
\r
9403 MOV EDX,[ESP].TVarData.VOleStr
\r
9409 procedure AnyToIntf(var Unknown: IUnknown; V: Variant);
\r
9411 TAnyProc(ChangeAnyProc)(V);
\r
9412 if TVarData(V).VType <> varUnknown then
\r
9414 Unknown := IUnknown(TVarData(V).VUnknown);
\r
9417 procedure _VarToIntf(var Unknown: IUnknown; const V: Variant);
\r
9419 CMP [EDX].TVarData.VType,varEmpty
\r
9421 CMP [EDX].TVarData.VType,varUnknown
\r
9423 CMP [EDX].TVarData.VType,varDispatch
\r
9425 CMP [EDX].TVarData.VType,varUnknown+varByRef
\r
9427 CMP [EDX].TVarData.VType,varDispatch+varByRef
\r
9429 CMP [EDX].TVarData.VType,varAny
\r
9432 @@0: CALL _VarClear
\r
9435 @@1: MOV EDX,[EDX].TVarData.VPointer
\r
9438 @@2: MOV EDX,[EDX].TVarData.VUnknown
\r
9442 procedure _VarToDisp(var Dispatch: IDispatch; const V: Variant);
\r
9444 CMP [EDX].TVarData.VType,varEmpty
\r
9446 CMP [EDX].TVarData.VType,varDispatch
\r
9448 CMP [EDX].TVarData.VType,varDispatch+varByRef
\r
9450 MOV EDX,[EDX].TVarData.VPointer
\r
9453 @@1: MOV EDX,[EDX].TVarData.VDispatch
\r
9457 procedure _VarToDynArray(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
\r
9459 CALL DynArrayFromVariant
\r
9466 procedure _VarFromInt;
\r
9468 CMP [EAX].TVarData.VType,varOleStr
\r
9475 @@1: MOV [EAX].TVarData.VType,varInteger
\r
9476 MOV [EAX].TVarData.VInteger,EDX
\r
9479 procedure _VarFromBool;
\r
9481 CMP [EAX].TVarData.VType,varOleStr
\r
9488 @@1: MOV [EAX].TVarData.VType,varBoolean
\r
9491 MOV [EAX].TVarData.VBoolean,DX
\r
9494 procedure _VarFromReal;
\r
9496 CMP [EAX].TVarData.VType,varOleStr
\r
9501 @@1: MOV [EAX].TVarData.VType,varDouble
\r
9502 FSTP [EAX].TVarData.VDouble
\r
9506 procedure _VarFromTDateTime;
\r
9508 CMP [EAX].TVarData.VType,varOleStr
\r
9513 @@1: MOV [EAX].TVarData.VType,varDate
\r
9514 FSTP [EAX].TVarData.VDouble
\r
9518 procedure _VarFromCurr;
\r
9520 CMP [EAX].TVarData.VType,varOleStr
\r
9525 @@1: MOV [EAX].TVarData.VType,varCurrency
\r
9526 FISTP [EAX].TVarData.VCurrency
\r
9530 procedure _VarFromPStr(var V: Variant; const Value: ShortString);
\r
9532 _VarFromLStr(V, Value);
\r
9535 procedure _VarFromLStr(var V: Variant; const Value: string);
\r
9537 CMP [EAX].TVarData.VType,varOleStr
\r
9546 MOV ECX,[EDX-skew].StrRec.refCnt
\r
9549 {X LOCK} INC [EDX-skew].StrRec.refCnt
\r
9553 MOV EAX,[EDX-skew].StrRec.length
\r
9554 CALL _NewAnsiString
\r
9558 MOV ECX,[EDX-skew].StrRec.length
\r
9562 @@3: MOV [EAX].TVarData.VType,varString
\r
9563 MOV [EAX].TVarData.VString,EDX
\r
9566 procedure _VarFromWStr(var V: Variant; const Value: WideString);
\r
9569 CMP [EAX].TVarData.VType,varOleStr
\r
9582 CALL SysAllocStringLen
\r
9586 MOV [EDX].TVarData.VType,varOleStr
\r
9587 MOV [EDX].TVarData.VOleStr,EAX
\r
9590 procedure _VarFromIntf(var V: Variant; const Value: IUnknown);
\r
9592 CMP [EAX].TVarData.VType,varOleStr
\r
9599 @@1: MOV [EAX].TVarData.VType,varUnknown
\r
9600 MOV [EAX].TVarData.VUnknown,EDX
\r
9605 CALL [EAX].vmtAddRef.Pointer
\r
9609 procedure _VarFromDisp(var V: Variant; const Value: IDispatch);
\r
9611 CMP [EAX].TVarData.VType,varOleStr
\r
9618 @@1: MOV [EAX].TVarData.VType,varDispatch
\r
9619 MOV [EAX].TVarData.VDispatch,EDX
\r
9624 CALL [EAX].vmtAddRef.Pointer
\r
9628 procedure _VarFromDynArray(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
\r
9631 CALL DynArrayToVariant
\r
9633 CMP [EAX].TVarData.VType,varEmpty
\r
9639 procedure _OleVarFromPStr(var V: OleVariant; const Value: ShortString);
\r
9641 _OleVarFromLStr(V, Value);
\r
9645 procedure _OleVarFromLStr(var V: OleVariant; const Value: string);
\r
9647 CMP [EAX].TVarData.VType,varOleStr
\r
9654 @@1: MOV [EAX].TVarData.VType,varOleStr
\r
9655 ADD EAX,TVarData.VOleStr
\r
9661 procedure OleVarFromAny(var V: OleVariant; Value: Variant);
\r
9663 TAnyProc(ChangeAnyProc)(Value);
\r
9667 procedure _OleVarFromVar(var V: OleVariant; const Value: Variant);
\r
9669 CMP [EDX].TVarData.VType,varAny
\r
9671 CMP [EDX].TVarData.VType,varString
\r
9673 CMP [EAX].TVarData.VType,varOleStr
\r
9680 @@1: MOV [EAX].TVarData.VType,varOleStr
\r
9681 ADD EAX,TVarData.VOleStr
\r
9682 ADD EDX,TVarData.VString
\r
9691 procedure VarStrCat(var Dest: Variant; const Source: Variant);
\r
9693 if TVarData(Dest).VType = varString then
\r
9694 Dest := string(Dest) + string(Source)
\r
9696 Dest := WideString(Dest) + WideString(Source);
\r
9699 procedure VarOp(var Dest: Variant; const Source: Variant; OpCode: Integer); forward;
\r
9701 procedure AnyOp(var Dest: Variant; Source: Variant; OpCode: Integer);
\r
9703 if TVarData(Dest).VType = varAny then TAnyProc(ChangeAnyProc)(Dest);
\r
9704 if TVarData(Source).VType = varAny then TAnyProc(ChangeAnyProc)(Source);
\r
9705 VarOp(Dest, Source, OpCode);
\r
9708 procedure VarOp(var Dest: Variant; const Source: Variant; OpCode: Integer);
\r
9716 MOV EAX,[EDI].TVarData.VType.Integer
\r
9717 MOV EDX,[ESI].TVarData.VType.Integer
\r
9718 AND EAX,varTypeMask
\r
9719 AND EDX,varTypeMask
\r
9725 @@1: CMP EDX,varLast
\r
9730 @@2: MOV AL,BaseTypeMap.Byte[EAX]
\r
9731 MOV DL,BaseTypeMap.Byte[EDX]
\r
9732 MOVZX ECX,OpTypeMap.Byte[EAX*8+EDX]
\r
9733 CALL @VarOpTable.Pointer[ECX*4]
\r
9739 @@4: CMP EAX,varAny
\r
9768 MOV [EDI].TVarData.VType,varNull
\r
9782 CALL @IntegerOpTable.Pointer[EBX*4]
\r
9862 FSTP TBYTE PTR [ESP]
\r
9865 FLD TBYTE PTR [ESP]
\r
9867 CALL @RealOpTable.Pointer[EBX*4]
\r
9881 FSTP TBYTE PTR [ESP]
\r
9884 FLD TBYTE PTR [ESP]
\r
9886 CALL @RealOpTable.Pointer[EBX*4]
\r
9897 FILD [EDI].TVarData.VCurrency
\r
9899 CALL @RealOpTable.Pointer[EBX*4]
\r
9909 FILD [ESI].TVarData.VCurrency
\r
9914 FILD [EDI].TVarData.VCurrency
\r
9915 FILD [ESI].TVarData.VCurrency
\r
9923 FILD [ESI].TVarData.VCurrency
\r
9965 CALL @IntegerOpTable.Pointer[EBX*4]
\r
9975 CMP AX,btDat+btDat*256
\r
9980 MOV [EDI].TVarData.VType,varDate
\r
9984 procedure _VarAdd;
\r
9990 procedure _VarSub;
\r
9996 procedure _VarMul;
\r
10002 procedure _VarDiv;
\r
10008 procedure _VarMod;
\r
10014 procedure _VarAnd;
\r
10020 procedure _VarOr;
\r
10026 procedure _VarXor;
\r
10032 procedure _VarShl;
\r
10038 procedure _VarShr;
\r
10044 procedure _VarRDiv;
\r
10050 function VarCompareString(const S1, S2: string): Integer;
\r
10069 MOVZX EAX,BYTE PTR [ESI-1]
\r
10070 MOVZX EDX,BYTE PTR [EDI-1]
\r
10076 function VarCmpStr(const V1, V2: Variant): Integer;
\r
10078 Result := VarCompareString(V1, V2);
\r
10081 function AnyCmp(var Dest: Variant; const Source: Variant): Integer;
\r
10090 if TVarData(Dest).VType = varAny then TAnyProc(ChangeAnyProc)(Dest);
\r
10091 if TVarData(Source).VType = varAny then
\r
10094 TAnyProc(ChangeAnyProc)(Temp);
\r
10107 procedure _VarCmp;
\r
10113 MOV EAX,[EDI].TVarData.VType.Integer
\r
10114 MOV EDX,[ESI].TVarData.VType.Integer
\r
10115 AND EAX,varTypeMask
\r
10116 AND EDX,varTypeMask
\r
10119 CMP EAX,varString
\r
10121 MOV EAX,varOleStr
\r
10122 @@1: CMP EDX,varLast
\r
10124 CMP EDX,varString
\r
10126 MOV EDX,varOleStr
\r
10127 @@2: MOV AL,BaseTypeMap.Byte[EAX]
\r
10128 MOV DL,BaseTypeMap.Byte[EDX]
\r
10129 MOVZX ECX,OpTypeMap.Byte[EAX*8+EDX]
\r
10130 JMP @VarCmpTable.Pointer[ECX*4]
\r
10132 @@4: CMP EAX,varAny
\r
10144 DD @VarCmpInteger
\r
10148 DD @VarCmpBoolean
\r
10173 FSTP TBYTE PTR [ESP]
\r
10176 FLD TBYTE PTR [ESP]
\r
10182 MOV AL,AH { Move CF into SF }
\r
10193 FSTP TBYTE PTR [ESP]
\r
10196 FLD TBYTE PTR [ESP]
\r
10220 procedure _VarNeg;
\r
10222 MOV EDX,[EAX].TVarData.VType.Integer
\r
10223 AND EDX,varTypeMask
\r
10226 CMP EDX,varString
\r
10228 MOV EDX,varOleStr
\r
10229 @@1: MOV DL,BaseTypeMap.Byte[EDX]
\r
10230 JMP @VarNegTable.Pointer[EDX*4]
\r
10231 @@2: CMP EAX,varAny
\r
10234 CALL [ChangeAnyProc]
\r
10241 DD @VarNegInteger
\r
10245 DD @VarNegInteger
\r
10270 FILD [EAX].TVarData.VCurrency
\r
10272 FISTP [EAX].TVarData.VCurrency
\r
10277 FLD [EAX].TVarData.VDate
\r
10279 FSTP [EAX].TVarData.VDate
\r
10283 procedure _VarNot;
\r
10285 MOV EDX,[EAX].TVarData.VType.Integer
\r
10286 AND EDX,varTypeMask
\r
10288 CMP EDX,varBoolean
\r
10294 CMP EDX,varString
\r
10299 CALL [ChangeAnyProc]
\r
10308 @@2: JMP VarInvalidOp
\r
10309 @@3: MOV DX,[EAX].TVarData.VBoolean
\r
10313 MOV [EAX].TVarData.VBoolean,DX
\r
10317 procedure _VarCopyNoInd;
\r
10322 procedure VariantClr;
\r
10327 procedure _VarClr;
\r
10334 procedure VariantAddRef;
\r
10339 procedure _VarAddRef;
\r
10341 CMP [EAX].TVarData.VType,varOleStr
\r
10343 PUSH [EAX].Integer[12]
\r
10344 PUSH [EAX].Integer[8]
\r
10345 PUSH [EAX].Integer[4]
\r
10346 PUSH [EAX].Integer[0]
\r
10347 MOV [EAX].TVarData.VType,varEmpty
\r
10354 function VarType(const V: Variant): Integer;
\r
10356 MOVZX EAX,[EAX].TVarData.VType
\r
10359 function VarAsType(const V: Variant; VarType: Integer): Variant;
\r
10361 _VarCast(Result, V, VarType);
\r
10364 function VarIsEmpty(const V: Variant): Boolean;
\r
10366 with TVarData(V) do
\r
10367 Result := (VType = varEmpty) or ((VType = varDispatch) or
\r
10368 (VType = varUnknown)) and (VDispatch = nil);
\r
10371 function VarIsNull(const V: Variant): Boolean;
\r
10373 Result := TVarData(V).VType = varNull;
\r
10376 function VarToStr(const V: Variant): string;
\r
10378 if TVarData(V).VType <> varNull then Result := V else Result := '';
\r
10381 function VarFromDateTime(DateTime: TDateTime): Variant;
\r
10383 _VarClear(Result);
\r
10384 TVarData(Result).VType := varDate;
\r
10385 TVarData(Result).VDate := DateTime;
\r
10388 function VarToDateTime(const V: Variant): TDateTime;
\r
10392 Temp.VType := varEmpty;
\r
10393 _VarCast(Variant(Temp), V, varDate);
\r
10394 Result := Temp.VDate;
\r
10397 function _WriteVariant(var T: Text; const V: Variant; Width: Integer): Pointer;
\r
10401 if TVarData(V).VType >= varSmallint then S := V;
\r
10402 Write(T, S: Width);
\r
10406 function _Write0Variant(var T: Text; const V: Variant): Pointer;
\r
10408 Result := _WriteVariant(T, V, 0);
\r
10411 { ----------------------------------------------------- }
\r
10412 { Variant array support }
\r
10413 { ----------------------------------------------------- }
\r
10415 function VarArrayCreate(const Bounds: array of Integer;
\r
10416 VarType: Integer): Variant;
\r
10418 I, DimCount: Integer;
\r
10419 VarArrayRef: PVarArray;
\r
10420 VarBounds: array[0..63] of TVarArrayBound;
\r
10422 if not Odd(High(Bounds)) or (High(Bounds) > 127) then
\r
10423 Error(reVarArrayCreate);
\r
10424 DimCount := (High(Bounds) + 1) div 2;
\r
10425 for I := 0 to DimCount - 1 do
\r
10426 with VarBounds[I] do
\r
10428 LowBound := Bounds[I * 2];
\r
10429 ElementCount := Bounds[I * 2 + 1] - LowBound + 1;
\r
10431 VarArrayRef := SafeArrayCreate(VarType, DimCount, VarBounds);
\r
10432 if VarArrayRef = nil then Error(reVarArrayCreate);
\r
10433 _VarClear(Result);
\r
10434 TVarData(Result).VType := VarType or varArray;
\r
10435 TVarData(Result).VArray := VarArrayRef;
\r
10438 function VarArrayOf(const Values: array of Variant): Variant;
\r
10442 Result := VarArrayCreate([0, High(Values)], varVariant);
\r
10443 for I := 0 to High(Values) do Result[I] := Values[I];
\r
10446 procedure _VarArrayRedim(var A : Variant; HighBound: Integer);
\r
10448 VarBound: TVarArrayBound;
\r
10450 if (TVarData(A).VType and (varArray or varByRef)) <> varArray then
\r
10451 Error(reVarNotArray);
\r
10452 with TVarData(A).VArray^ do
\r
10453 VarBound.LowBound := Bounds[DimCount - 1].LowBound;
\r
10454 VarBound.ElementCount := HighBound - VarBound.LowBound + 1;
\r
10455 if SafeArrayRedim(TVarData(A).VArray, VarBound) <> 0 then
\r
10456 Error(reVarArrayCreate);
\r
10459 function GetVarArray(const A: Variant): PVarArray;
\r
10461 if TVarData(A).VType and varArray = 0 then Error(reVarNotArray);
\r
10462 if TVarData(A).VType and varByRef <> 0 then
\r
10463 Result := PVarArray(TVarData(A).VPointer^) else
\r
10464 Result := TVarData(A).VArray;
\r
10467 function VarArrayDimCount(const A: Variant): Integer;
\r
10469 if TVarData(A).VType and varArray <> 0 then
\r
10470 Result := GetVarArray(A)^.DimCount else
\r
10474 function VarArrayLowBound(const A: Variant; Dim: Integer): Integer;
\r
10476 if SafeArrayGetLBound(GetVarArray(A), Dim, Result) <> 0 then
\r
10477 Error(reVarArrayBounds);
\r
10480 function VarArrayHighBound(const A: Variant; Dim: Integer): Integer;
\r
10482 if SafeArrayGetUBound(GetVarArray(A), Dim, Result) <> 0 then
\r
10483 Error(reVarArrayBounds);
\r
10486 function VarArrayLock(const A: Variant): Pointer;
\r
10488 if SafeArrayAccessData(GetVarArray(A), Result) <> 0 then
\r
10489 Error(reVarNotArray);
\r
10492 procedure VarArrayUnlock(const A: Variant);
\r
10494 if SafeArrayUnaccessData(GetVarArray(A)) <> 0 then
\r
10495 Error(reVarNotArray);
\r
10498 function VarArrayRef(const A: Variant): Variant;
\r
10500 if TVarData(A).VType and varArray = 0 then Error(reVarNotArray);
\r
10501 _VarClear(Result);
\r
10502 TVarData(Result).VType := TVarData(A).VType or varByRef;
\r
10503 if TVarData(A).VType and varByRef <> 0 then
\r
10504 TVarData(Result).VPointer := TVarData(A).VPointer else
\r
10505 TVarData(Result).VPointer := @TVarData(A).VArray;
\r
10508 function VarIsArray(const A: Variant): Boolean;
\r
10510 Result := TVarData(A).VType and varArray <> 0;
\r
10513 function _VarArrayGet(var A: Variant; IndexCount: Integer;
\r
10514 Indices: Integer): Variant; cdecl;
\r
10516 VarArrayPtr: PVarArray;
\r
10517 VarType: Integer;
\r
10520 if TVarData(A).VType and varArray = 0 then Error(reVarNotArray);
\r
10521 VarArrayPtr := GetVarArray(A);
\r
10522 if VarArrayPtr^.DimCount <> IndexCount then Error(reVarArrayBounds);
\r
10523 VarType := TVarData(A).VType and varTypeMask;
\r
10524 _VarClear(Result);
\r
10525 if VarType = varVariant then
\r
10527 if SafeArrayPtrOfIndex(VarArrayPtr, @Indices, P) <> 0 then
\r
10528 Error(reVarArrayBounds);
\r
10529 Result := PVariant(P)^;
\r
10532 if SafeArrayGetElement(VarArrayPtr, @Indices,
\r
10533 @TVarData(Result).VPointer) <> 0 then Error(reVarArrayBounds);
\r
10534 TVarData(Result).VType := VarType;
\r
10538 procedure _VarArrayPut(var A: Variant; const Value: Variant;
\r
10539 IndexCount: Integer; Indices: Integer); cdecl;
\r
10541 TAnyPutArrayProc = procedure (var A: Variant; const Value: Variant; Index: Integer);
\r
10543 VarArrayPtr: PVarArray;
\r
10544 VarType: Integer;
\r
10548 if TVarData(A).VType and varArray = 0 then Error(reVarNotArray);
\r
10549 VarArrayPtr := GetVarArray(A);
\r
10550 if VarArrayPtr^.DimCount <> IndexCount then Error(reVarArrayBounds);
\r
10551 VarType := TVarData(A).VType and varTypeMask;
\r
10552 if (VarType = varVariant) and (TVarData(Value).VType <> varString) then
\r
10554 if SafeArrayPtrOfIndex(VarArrayPtr, @Indices, P) <> 0 then
\r
10555 Error(reVarArrayBounds);
\r
10556 PVariant(P)^ := Value;
\r
10559 Temp.VType := varEmpty;
\r
10561 if VarType = varVariant then
\r
10563 VarStringToOleStr(Variant(Temp), Value);
\r
10567 _VarCast(Variant(Temp), Value, VarType);
\r
10569 varOleStr, varDispatch, varUnknown:
\r
10570 P := Temp.VPointer;
\r
10572 P := @Temp.VPointer;
\r
10575 if SafeArrayPutElement(VarArrayPtr, @Indices, P) <> 0 then
\r
10576 Error(reVarArrayBounds);
\r
10578 _VarClear(Variant(Temp));
\r
10584 function VarArrayGet(const A: Variant; const Indices: array of Integer): Variant;
\r
10586 { ->EAX Pointer to A }
\r
10587 { EDX Pointer to Indices }
\r
10588 { ECX High bound of Indices }
\r
10589 { [EBP+8] Pointer to result }
\r
10597 PUSH [EDX+ECX*4].Integer
\r
10605 CALL _VarArrayGet
\r
10606 LEA ESP,[ESP+EBX*4+3*4]
\r
10611 procedure VarArrayPut(var A: Variant; const Value: Variant; const Indices: array of Integer);
\r
10613 { ->EAX Pointer to A }
\r
10614 { EDX Pointer to Value }
\r
10615 { ECX Pointer to Indices }
\r
10616 { [EBP+8] High bound of Indices }
\r
10625 PUSH [ECX+EBX*4].Integer
\r
10634 CALL _VarArrayPut
\r
10635 LEA ESP,[ESP+EBX*4+3*4]
\r
10641 { 64-bit Integer helper routines - recycling C++ RTL routines }
\r
10643 procedure __llmul; external; {$L _LL }
\r
10644 procedure __lldiv; external; { _LL }
\r
10645 procedure __llmod; external; { _LL }
\r
10646 procedure __llmulo; external; { _LL (overflow version) }
\r
10647 procedure __lldivo; external; { _LL (overflow version) }
\r
10648 procedure __llmodo; external; { _LL (overflow version) }
\r
10649 procedure __llshl; external; { _LL }
\r
10650 procedure __llushr; external; { _LL }
\r
10651 procedure __llumod; external; { _LL }
\r
10652 procedure __lludiv; external; { _LL }
\r
10654 function _StrInt64(val: Int64; width: Integer): ShortString;
\r
10656 d: array[0..31] of Char; { need 19 digits and a sign }
\r
10661 { Produce an ASCII representation of the number in reverse order }
\r
10665 d[i] := Chr( Abs(val mod 10) + Ord('0') );
\r
10667 val := val div 10;
\r
10675 { Fill the Result with the appropriate number of blanks }
\r
10676 if width > 255 then
\r
10679 spaces := width - i;
\r
10680 while k <= spaces do
\r
10682 Result[k] := ' ';
\r
10686 { Fill the Result with the number }
\r
10690 Result[k] := d[i];
\r
10694 { Result is k-1 characters long }
\r
10695 SetLength(Result, k-1);
\r
10699 function _Str0Int64(val: Int64): ShortString;
\r
10701 Result := _StrInt64(val, 0);
\r
10704 procedure _WriteInt64;
\r
10706 { PROCEDURE _WriteInt64( VAR t: Text; val: Int64; with: Longint); }
\r
10707 { ->EAX Pointer to file record }
\r
10708 { [ESP+4] Value }
\r
10709 { EDX Field width }
\r
10711 SUB ESP,32 { VAR s: String[31]; }
\r
10716 PUSH dword ptr [ESP+8+32+8] { Str( val : 0, s ); }
\r
10717 PUSH dword ptr [ESP+8+32+8]
\r
10719 LEA EDX,[ESP+8+8]
\r
10725 MOV EDX,ESP { Write( t, s : width );}
\r
10726 CALL _WriteString
\r
10732 procedure _Write0Int64;
\r
10734 { PROCEDURE _Write0Long( VAR t: Text; val: Longint); }
\r
10735 { ->EAX Pointer to file record }
\r
10741 procedure _ReadInt64; external; {$L ReadInt64 }
\r
10743 function _ValInt64(const s: AnsiString; var code: Integer): Int64;
\r
10758 while s[i] = ' ' do
\r
10761 if s[i] = '-' then
\r
10766 else if s[i] = '+' then
\r
10769 if (s[i] = '$') or (s[i] = '0') and (Upcase(s[i+1]) = 'X') then
\r
10771 if s[i] = '0' then
\r
10777 '0'..'9': dig := Ord(s[i]) - Ord('0');
\r
10778 'A'..'F': dig := Ord(s[i]) - (Ord('A') - 10);
\r
10779 'a'..'f': dig := Ord(s[i]) - (Ord('a') - 10);
\r
10783 if (Result < 0) or (Result > $0FFFFFFFFFFFFFFF) then
\r
10785 Result := Result shl 4 + dig;
\r
10790 Result := - Result;
\r
10797 '0'..'9': dig := Ord(s[i]) - Ord('0');
\r
10801 if (Result < 0) or (Result > $7FFFFFFFFFFFFFFF div 10) then
\r
10803 Result := Result*10 + dig;
\r
10808 Result := - Result;
\r
10809 if (Result <> 0) and (sign <> (Result < 0)) then
\r
10812 if (s[i] <> #0) or empty then
\r
10818 procedure _DynArrayLength;
\r
10820 { FUNCTION _DynArrayLength(const a: array of ...): Longint; }
\r
10821 { ->EAX Pointer to array or nil }
\r
10822 { <-EAX High bound of array + 1 or 0 }
\r
10829 procedure _DynArrayHigh;
\r
10831 { FUNCTION _DynArrayHigh(const a: array of ...): Longint; }
\r
10832 { ->EAX Pointer to array or nil }
\r
10833 { <-EAX High bound of array or -1 }
\r
10834 CALL _DynArrayLength
\r
10839 PLongint = ^Longint;
\r
10840 PointerArray = array [0..512*1024*1024 -2] of Pointer;
\r
10841 PPointerArray = ^PointerArray;
\r
10842 PDynArrayTypeInfo = ^TDynArrayTypeInfo;
\r
10843 TDynArrayTypeInfo = packed record
\r
10847 elType: ^PDynArrayTypeInfo;
\r
10848 varType: Integer;
\r
10852 procedure CopyArray(dest, source, typeInfo: Pointer; cnt: Integer);
\r
10854 PUSH dword ptr [EBP+8]
\r
10858 procedure FinalizeArray(p, typeInfo: Pointer; cnt: Integer);
\r
10860 JMP _FinalizeArray
\r
10863 procedure DynArrayClear(var a: Pointer; typeInfo: Pointer);
\r
10865 CALL _DynArrayClear
\r
10868 procedure DynArraySetLength(var a: Pointer; typeInfo: PDynArrayTypeInfo; dimCnt: Longint; lengthVec: PLongint);
\r
10871 newLength, oldLength, minLength: Longint;
\r
10873 neededSize: Longint;
\r
10878 // Fetch the new length of the array in this dimension, and the old length
\r
10879 newLength := PLongint(lengthVec)^;
\r
10880 if newLength <= 0 then
\r
10882 if newLength < 0 then
\r
10883 Error(reRangeError);
\r
10884 DynArrayClear(a, typeInfo);
\r
10891 Dec(PLongint(p));
\r
10892 oldLength := PLongint(p)^;
\r
10893 Dec(PLongint(p));
\r
10896 // Calculate the needed size of the heap object
\r
10897 Inc(PChar(typeInfo), Length(typeInfo.name));
\r
10898 elSize := typeInfo.elSize;
\r
10899 if typeInfo.elType <> nil then
\r
10900 typeInfo := typeInfo.elType^
\r
10903 neededSize := newLength*elSize;
\r
10904 if neededSize div newLength <> elSize then
\r
10905 Error(reRangeError);
\r
10906 Inc(neededSize, Sizeof(Longint)*2);
\r
10908 // If the heap object isn't shared (ref count = 1), just resize it. Otherwise, we make a copy
\r
10909 if (p = nil) or (PLongint(p)^ = 1) then
\r
10912 if (newLength < oldLength) and (typeInfo <> nil) then
\r
10913 FinalizeArray(PChar(p) + Sizeof(Longint)*2 + newLength*elSize, typeInfo, oldLength - newLength);
\r
10914 ReallocMem(pp, neededSize);
\r
10919 Dec(PLongint(p)^);
\r
10920 GetMem(p, neededSize);
\r
10921 minLength := oldLength;
\r
10922 if minLength > newLength then
\r
10923 minLength := newLength;
\r
10924 if typeInfo <> nil then
\r
10926 FillChar((PChar(p) + Sizeof(Longint)*2)^, minLength*elSize, 0);
\r
10927 CopyArray(PChar(p) + Sizeof(Longint)*2, a, typeInfo, minLength)
\r
10930 Move(PChar(a)^, (PChar(p) + Sizeof(Longint)*2)^, minLength*elSize);
\r
10933 // The heap object will now have a ref count of 1 and the new length
\r
10934 PLongint(p)^ := 1;
\r
10935 Inc(PLongint(p));
\r
10936 PLongint(p)^ := newLength;
\r
10937 Inc(PLongint(p));
\r
10939 // Set the new memory to all zero bits
\r
10940 FillChar((PChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);
\r
10942 // Take care of the inner dimensions, if any
\r
10943 if dimCnt > 1 then
\r
10947 for i := 0 to newLength-1 do
\r
10948 DynArraySetLength(PPointerArray(p)[i], typeInfo, dimCnt, lengthVec);
\r
10953 procedure _DynArraySetLength;
\r
10955 { PROCEDURE _DynArraySetLength(var a: dynarray; typeInfo: PDynArrayTypeInfo; dimCnt: Longint; lengthVec: ^Longint) }
\r
10956 { ->EAX Pointer to dynamic array (= pointer to pointer to heap object) }
\r
10957 { EDX Pointer to type info for the dynamic array }
\r
10958 { ECX number of dimensions }
\r
10959 { [ESP+4] dimensions }
\r
10961 ADD dword ptr [ESP],4
\r
10962 CALL DynArraySetLength
\r
10965 procedure _DynArrayCopy(a: Pointer; typeInfo: Pointer; var Result: Pointer);
\r
10968 _DynArrayCopyRange(a, typeInfo, 0, PLongint(PChar(a)-4)^, Result);
\r
10971 procedure _DynArrayCopyRange(a: Pointer; typeInfo: Pointer; index, count : Integer; var Result: Pointer);
\r
10973 arrayLength: Integer;
\r
10975 typeInf: PDynArrayTypeInfo;
\r
10981 typeInf := typeInfo;
\r
10983 // Limit index and count to values within the array
\r
10984 if index < 0 then
\r
10986 Inc(count, index);
\r
10989 arrayLength := PLongint(PChar(a)-4)^;
\r
10990 if index > arrayLength then
\r
10991 index := arrayLength;
\r
10992 if count > arrayLength - index then
\r
10993 count := arrayLength - index;
\r
10994 if count < 0 then
\r
10997 if count > 0 then
\r
10999 // Figure out the size and type descriptor of the element type
\r
11000 Inc(PChar(typeInf), Length(typeInf.name));
\r
11001 elSize := typeInf.elSize;
\r
11002 if typeInf.elType <> nil then
\r
11003 typeInf := typeInf.elType^
\r
11007 // Allocate the amount of memory needed
\r
11008 GetMem(p, count*elSize + Sizeof(Longint)*2);
\r
11010 // The reference count of the new array is 1, the length is count
\r
11011 PLongint(p)^ := 1;
\r
11012 Inc(PLongint(p));
\r
11013 PLongint(p)^ := count;
\r
11014 Inc(PLongint(p));
\r
11015 Inc(PChar(a), index*elSize);
\r
11017 // If the element type needs destruction, we must copy each element,
\r
11018 // otherwise we can just copy the bits
\r
11019 if count > 0 then
\r
11021 if typeInf <> nil then
\r
11023 FillChar(p^, count*elSize, 0);
\r
11024 CopyArray(p, a, typeInf, count)
\r
11027 Move(a^, p^, count*elSize);
\r
11031 DynArrayClear(Result, typeInfo);
\r
11035 procedure _DynArrayClear;
\r
11037 { ->EAX Pointer to dynamic array (Pointer to pointer to heap object }
\r
11038 { EDX Pointer to type info }
\r
11040 { Nothing to do if Pointer to heap object is nil }
\r
11045 { Set the variable to be finalized to nil }
\r
11046 MOV dword ptr [EAX],0
\r
11048 { Decrement ref count. Nothing to do if not zero now. }
\r
11049 {X LOCK} DEC dword ptr [ECX-8]
\r
11052 { Save the source - we're supposed to return it }
\r
11056 { Fetch the type descriptor of the elements }
\r
11058 MOV CL,[EDX].TDynArrayTypeInfo.name;
\r
11059 MOV EDX,[EDX+ECX].TDynArrayTypeInfo.elType;
\r
11061 { If it's non-nil, finalize the elements }
\r
11068 CALL _FinalizeArray
\r
11070 { Now deallocate the array }
\r
11078 procedure _DynArrayAsg;
\r
11080 { ->EAX Pointer to destination (pointer to pointer to heap object }
\r
11081 { EDX source (pointer to heap object }
\r
11082 { ECX Pointer to rtti describing dynamic array }
\r
11087 { Increment ref count of source if non-nil }
\r
11091 {X LOCK} INC dword ptr [EDX-8]
\r
11093 { Dec ref count of destination - if it becomes 0, clear dest }
\r
11096 {X LOCK} DEC dword ptr[EBX-8]
\r
11101 INC dword ptr[EBX-8]
\r
11102 CALL _DynArrayClear
\r
11106 { Finally store source into destination }
\r
11112 procedure _DynArrayAddRef;
\r
11114 { ->EAX Pointer to heap object }
\r
11117 {X LOCK} INC dword ptr [EAX-8]
\r
11122 function DynArrayIndex(const P: Pointer; const Indices: array of Integer; const TypInfo: Pointer): Pointer;
\r
11125 { EDX Pointer to Indices }
\r
11126 { ECX High bound of Indices }
\r
11127 { [EBP+8] TypInfo }
\r
11138 XOR EBX,EBX { for i := 0 to High(Indices) do }
\r
11145 MOV AL,[EDI].TDynArrayTypeInfo.name
\r
11147 MOV EAX,[ESI+EBX*4] { P := P + Indices[i]*TypInfo.elSize }
\r
11148 MUL [EDI].TDynArrayTypeInfo.elSize
\r
11149 MOV EDI,[EDI].TDynArrayTypeInfo.elType
\r
11172 TBoundArray = array of Integer;
\r
11173 PPointer = ^Pointer;
\r
11176 { Returns the DynArrayTypeInfo of the Element Type of the specified DynArrayTypeInfo }
\r
11177 function DynArrayElTypeInfo(typeInfo: PDynArrayTypeInfo): PDynArrayTypeInfo;
\r
11180 if typeInfo <> nil then
\r
11182 Inc(PChar(typeInfo), Length(typeInfo.name));
\r
11183 if typeInfo.elType <> nil then
\r
11184 Result := typeInfo.elType^;
\r
11188 { Returns # of dimemsions of the DynArray described by the specified DynArrayTypeInfo}
\r
11189 function DynArrayDim(typeInfo: PDynArrayTypeInfo): Integer;
\r
11192 while (typeInfo <> nil) and (typeInfo.kind = tkDynArray) do
\r
11195 typeInfo := DynArrayElTypeInfo(typeInfo);
\r
11199 { Returns size of the Dynamic Array}
\r
11200 function DynArraySize(a: Pointer): Integer;
\r
11208 // Returns whether array is rectangular
\r
11209 function IsDynArrayRectangular(const DynArray: Pointer; typeInfo: PDynArrayTypeInfo): Boolean;
\r
11211 Dim, I, J, Size, SubSize: Integer;
\r
11214 // Assume we have a rectangular array
\r
11218 Dim := DynArrayDim(typeInfo);
\r
11220 {NOTE: Start at 1. Don't need to test the first dimension - it's rectangular by definition}
\r
11221 for I := 1 to dim-1 do
\r
11225 { Get size of this dimension }
\r
11226 Size := DynArraySize(P);
\r
11228 { Get Size of first sub. dimension }
\r
11229 SubSize := DynArraySize(PPointerArray(P)[0]);
\r
11231 { Walk through every dimension making sure they all have the same size}
\r
11232 for J := 1 to Size-1 do
\r
11233 if DynArraySize(PPointerArray(P)[J]) <> SubSize then
\r
11239 { Point to next dimension}
\r
11240 P := PPointerArray(P)[0];
\r
11245 // Returns Bounds of a DynamicArray in a format usable for creating a Variant.
\r
11246 // i.e. The format of the bounds returns contains pairs of lo and hi bounds where
\r
11247 // lo is always 0, and hi is the size dimension of the array-1.
\r
11248 function DynArrayVariantBounds(const DynArray: Pointer; typeInfo: PDynArrayTypeInfo): TBoundArray;
\r
11255 Dim := DynArrayDim(typeInfo);
\r
11256 SetLength(Result, Dim*2);
\r
11259 while I < dim*2 do
\r
11261 Result[I] := 0; // Always use 0 as low-bound in low/high pair
\r
11265 Result[I] := DynArraySize(P)-1; // Adjust for 0-base low-bound
\r
11266 P := PPointerArray(p)[0]; // Assume rectangular arrays
\r
11272 // Returns Bounds of Dynamic array as an array of integer containing the 'high' of each dimension
\r
11273 function DynArrayBounds(const DynArray: Pointer; typeInfo: PDynArrayTypeInfo): TBoundArray;
\r
11280 Dim := DynArrayDim(typeInfo);
\r
11281 SetLength(Result, Dim);
\r
11283 for I := 0 to dim-1 do
\r
11286 Result[I] := DynArraySize(P)-1;
\r
11287 P := PPointerArray(P)[0]; // Assume rectangular arrays
\r
11291 // The dynamicArrayTypeInformation contains the VariantType of the element type
\r
11292 // when the kind == tkDynArray. This function returns that VariantType.
\r
11293 function DynArrayVarType(typeInfo: PDynArrayTypeInfo): Integer;
\r
11295 Result := varNull;
\r
11296 if (typeInfo <> nil) and (typeInfo.Kind = tkDynArray) then
\r
11298 Inc(PChar(typeInfo), Length(typeInfo.name));
\r
11299 Result := typeInfo.varType;
\r
11302 { NOTE: DECL.H and SYSTEM.PAS have different values for varString }
\r
11303 if Result = $48 then
\r
11304 Result := varString;
\r
11308 IntegerArray = array[0..$effffff] of Integer;
\r
11309 PIntegerArray = ^IntegerArray;
\r
11310 PSmallInt = ^SmallInt;
\r
11311 PInteger = ^Integer;
\r
11312 PSingle = ^Single;
\r
11313 PDouble = ^Double;
\r
11315 PDispatch = ^IDispatch;
\r
11316 PPDispatch = ^PDispatch;
\r
11317 PError = ^LongWord;
\r
11318 PWordBool = ^WordBool;
\r
11319 PUnknown = ^IUnknown;
\r
11320 PPUnknown = ^PUnknown;
\r
11322 PPWideChar = ^PWideChar;
\r
11324 { Decrements to next lower index - Returns True if successful }
\r
11325 { Indices: Indices to be decremented }
\r
11326 { Bounds : High bounds of each dimension }
\r
11327 function DecIndices(var Indices: TBoundArray; const Bounds: TBoundArray): Boolean;
\r
11331 { Find out if we're done: all at zeroes }
\r
11333 for I := Low(Indices) to High(Indices) do
\r
11334 if Indices[I] <> 0 then
\r
11339 if not Result then
\r
11342 { Two arrays must be of same length }
\r
11343 Assert(Length(Indices) = Length(Bounds));
\r
11345 { Find index of item to tweak }
\r
11346 for I := High(Indices) downto Low(Bounds) do
\r
11348 // If not reach zero, dec and bail out
\r
11349 if Indices[I] <> 0 then
\r
11357 while Indices[J] = 0 do
\r
11359 // Restore high bound when we've reached zero on a particular dimension
\r
11360 Indices[J] := Bounds[J];
\r
11361 // Move to higher dimension
\r
11371 // Copy Contents of Dynamic Array to Variant
\r
11372 // NOTE: The Dynamic array must be rectangular
\r
11373 // The Dynamic array must contain items whose type is Automation compatible
\r
11374 // In case of failure, the function returns with a Variant of type VT_EMPTY.
\r
11375 procedure DynArrayToVariant(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
\r
11377 VarBounds, Bounds, Indices: TBoundArray;
\r
11378 DAVarType, VVarType, DynDim: Integer;
\r
11379 PDAData: Pointer;
\r
11382 VarBounds := nil;
\r
11384 { This resets the Variant to VT_EMPTY - flag which is used to determine whether the }
\r
11385 { the cast to Variant succeeded or not }
\r
11388 { Get variantType code from DynArrayTypeInfo }
\r
11389 DAVarType := DynArrayVarType(PDynArrayTypeInfo(TypeInfo));
\r
11391 { Validate the Variant Type }
\r
11392 if ((DAVarType > varNull) and (DAVarType <= varByte)) or (DAVarType = varString) then
\r
11394 {NOTE: Map varString to varOleStr for SafeArrayCreate call }
\r
11395 if DAVarType = varString then
\r
11396 VVarType := varOleStr
\r
11398 VVarType := DAVarType;
\r
11400 { Get dimension of Dynamic Array }
\r
11401 DynDim := DynarrayDim(PDynArrayTypeInfo(TypeInfo));
\r
11403 { If more than one dimension, make sure we're dealing with a rectangular array }
\r
11404 if DynDim > 1 then
\r
11405 if not IsDynArrayRectangular(DynArray, PDynArrayTypeInfo(TypeInfo)) then
\r
11408 { Get Variant-style Bounds (lo/hi pair) of Dynamic Array }
\r
11409 VarBounds := DynArrayVariantBounds(DynArray, TypeInfo);
\r
11411 { Get DynArray Bounds }
\r
11412 Bounds := DynArrayBounds(DynArray, TypeInfo);
\r
11413 Indices:= Copy(Bounds);
\r
11415 { Create Variant of SAFEARRAY }
\r
11416 V := VarArrayCreate(VarBounds, VVarType);
\r
11417 Assert(VarArrayDimCount(V) = DynDim);
\r
11420 PDAData := DynArrayIndex(DynArray, Indices, TypeInfo);
\r
11421 if PDAData <> nil then
\r
11423 case DAVarType of
\r
11424 varSmallInt: Value := PSmallInt(PDAData)^;
\r
11425 varInteger: Value := PInteger(PDAData)^;
\r
11426 varSingle: value := PSingle(PDAData)^;
\r
11427 varDouble: value := PDouble(PDAData)^;
\r
11428 varCurrency: Value := PCurrency(PDAData)^;
\r
11429 varDate: Value := PDouble(PDAData)^;
\r
11430 varOleStr: Value := PWideString(PDAData)^;
\r
11431 varDispatch: Value := PDispatch(PDAData)^;
\r
11432 varError: Value := PError(PDAData)^;
\r
11433 varBoolean: Value := PWordBool(PDAData)^;
\r
11434 varVariant: Value := PVariant(PDAData)^;
\r
11435 varUnknown: Value := PUnknown(PDAData)^;
\r
11436 varByte: Value := PByte(PDAData)^;
\r
11437 varString: Value := PString(PDAData)^;
\r
11441 VarArrayPut(V, Value, Indices);
\r
11443 until not DecIndices(Indices, Bounds);
\r
11447 // Copies data from the Variant to the DynamicArray
\r
11448 procedure DynArrayFromVariant(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
\r
11450 DADimCount, VDimCount : Integer;
\r
11451 DAVarType, I: Integer;
\r
11452 lengthVec: PLongInt;
\r
11453 Bounds, Indices: TBoundArray;
\r
11455 PDAData: Pointer;
\r
11457 { Get Variant information }
\r
11458 VDimCount:= VarArrayDimCount(V);
\r
11460 { Allocate vector for lengths }
\r
11461 GetMem(lengthVec, VDimCount * sizeof(Integer));
\r
11463 { Initialize lengths - NOTE: VarArrayxxxxBound are 1-based.}
\r
11464 for I := 0 to VDimCount-1 do
\r
11465 PIntegerArray(lengthVec)[I]:= (VarArrayHighBound(V, I+1) - VarArrayLowBound(V, I+1)) + 1;
\r
11467 { Set Length of DynArray }
\r
11468 DynArraySetLength(DynArray, PDynArrayTypeInfo(TypeInfo), VDimCount, lengthVec);
\r
11470 { Get DynArray information }
\r
11471 DADimCount:= DynArrayDim(PDynArrayTypeInfo(TypeInfo));
\r
11472 DAVarType := DynArrayVarType(PDynArrayTypeInfo(TypeInfo));
\r
11473 Assert(VDimCount = DADimCount);
\r
11475 { Get DynArray Bounds }
\r
11476 Bounds := DynArrayBounds(DynArray, TypeInfo);
\r
11477 Indices:= Copy(Bounds);
\r
11479 { Copy data over}
\r
11481 Value := VarArrayGet(V, Indices);
\r
11482 PDAData := DynArrayIndex(DynArray, Indices, TypeInfo);
\r
11483 case DAVarType of
\r
11484 varSmallInt: PSmallInt(PDAData)^ := Value;
\r
11485 varInteger: PInteger(PDAData)^ := Value;
\r
11486 varSingle: PSingle(PDAData)^ := Value;
\r
11487 varDouble: PDouble(PDAData)^ := Value;
\r
11488 varCurrency: PCurrency(PDAData)^ := Value;
\r
11489 varDate: PDouble(PDAData)^ := Value;
\r
11490 varOleStr: PWideString(PDAData)^ := Value;
\r
11491 varDispatch: PDispatch(PDAData)^ := Value;
\r
11492 varError: PError(PDAData)^ := Value;
\r
11493 varBoolean: PWordBool(PDAData)^ := Value;
\r
11494 varVariant: PVariant(PDAData)^ := Value;
\r
11495 varUnknown: PUnknown(PDAData)^ := value;
\r
11496 varByte: PByte(PDAData)^ := Value;
\r
11497 varString: PString(PDAData)^ := Value;
\r
11499 until not DecIndices(Indices, Bounds);
\r
11501 { Free vector of lengths }
\r
11502 FreeMem(lengthVec);
\r
11507 { Package/Module registration/unregistration }
\r
11510 LOCALE_SABBREVLANGNAME = $00000003; { abbreviated language name }
\r
11511 LOAD_LIBRARY_AS_DATAFILE = 2;
\r
11512 HKEY_CURRENT_USER = $80000001;
\r
11513 KEY_ALL_ACCESS = $000F003F;
\r
11515 OldLocaleOverrideKey = 'Software\Borland\Delphi\Locales'; // do not localize
\r
11516 NewLocaleOverrideKey = 'Software\Borland\Locales'; // do not localize
\r
11518 function FindHInstance(Address: Pointer): LongWord;
\r
11520 MemInfo: TMemInfo;
\r
11522 VirtualQuery(Address, MemInfo, SizeOf(MemInfo));
\r
11523 if MemInfo.State = $1000{MEM_COMMIT} then
\r
11524 Result := Longint(MemInfo.AllocationBase)
\r
11525 else Result := 0;
\r
11528 function FindClassHInstance(ClassType: TClass): LongWord;
\r
11530 Result := FindHInstance(Pointer(ClassType));
\r
11533 function FindResourceHInstance(Instance: LongWord): LongWord;
\r
11535 CurModule: PLibModule;
\r
11537 CurModule := LibModuleList;
\r
11538 while CurModule <> nil do
\r
11540 if (Instance = CurModule.Instance) or
\r
11541 (Instance = CurModule.CodeInstance) or
\r
11542 (Instance = CurModule.DataInstance) then
\r
11544 Result := CurModule.ResInstance;
\r
11547 CurModule := CurModule.Next;
\r
11549 Result := Instance;
\r
11552 function LoadResourceModule(ModuleName: PChar): LongWord;
\r
11554 FileName: array[0..260] of Char;
\r
11556 LocaleName, LocaleOverride: array[0..4] of Char;
\r
11560 function FindBS(Current: PChar): PChar;
\r
11562 Result := Current;
\r
11563 while (Result^ <> #0) and (Result^ <> '\') do
\r
11564 Result := CharNext(Result);
\r
11567 function ToLongPath(AFileName: PChar): PChar;
\r
11569 CurrBS, NextBS: PChar;
\r
11570 Handle, L: Integer;
\r
11571 FindData: TWin32FindData;
\r
11572 Buffer: array[0..260] of Char;
\r
11573 GetLongPathName: function (ShortPathName: PChar; LongPathName: PChar;
\r
11574 cchBuffer: Integer): Integer stdcall;
\r
11576 Result := AFileName;
\r
11577 Handle := GetModuleHandle(kernel);
\r
11578 if Handle <> 0 then
\r
11580 @GetLongPathName := GetProcAddress(Handle, 'GetLongPathNameA');
\r
11581 if Assigned(GetLongPathName) and
\r
11582 (GetLongPathName(AFileName, Buffer, SizeOf(Buffer)) <> 0) then
\r
11584 lstrcpy(AFileName, Buffer);
\r
11589 if AFileName[0] = '\' then
\r
11591 if AFileName[1] <> '\' then Exit;
\r
11592 CurrBS := FindBS(AFileName + 2); // skip server name
\r
11593 if CurrBS^ = #0 then Exit;
\r
11594 CurrBS := FindBS(CurrBS + 1); // skip share name
\r
11595 if CurrBS^ = #0 then Exit;
\r
11597 CurrBS := AFileName + 2; // skip drive name
\r
11599 L := CurrBS - AFileName;
\r
11600 lstrcpyn(Buffer, AFileName, L + 1);
\r
11601 while CurrBS^ <> #0 do
\r
11603 NextBS := FindBS(CurrBS + 1);
\r
11604 if L + (NextBS - CurrBS) + 1 > SizeOf(Buffer) then Exit;
\r
11605 lstrcpyn(Buffer + L, CurrBS, (NextBS - CurrBS) + 1);
\r
11607 Handle := FindFirstFile(Buffer, FindData);
\r
11608 if (Handle = -1) then Exit;
\r
11609 FindClose(Handle);
\r
11611 if L + 1 + lstrlen(FindData.cFileName) + 1 > SizeOf(Buffer) then Exit;
\r
11612 Buffer[L] := '\';
\r
11613 lstrcpy(Buffer + L + 1, FindData.cFileName);
\r
11614 Inc(L, lstrlen(FindData.cFileName) + 1);
\r
11615 CurrBS := NextBS;
\r
11617 lstrcpy(AFileName, Buffer);
\r
11621 GetModuleFileName(0, FileName, SizeOf(FileName)); // Get host appliation name
\r
11622 LocaleOverride[0] := #0;
\r
11623 if (RegOpenKeyEx(HKEY_CURRENT_USER, NewLocaleOverrideKey, 0, KEY_ALL_ACCESS, Key) = 0) or
\r
11624 (RegOpenKeyEx(HKEY_CURRENT_USER, OldLocaleOverrideKey, 0, KEY_ALL_ACCESS, Key) = 0) then
\r
11626 Size := SizeOf(LocaleOverride);
\r
11627 if RegQueryValueEx(Key, ToLongPath(FileName), nil, nil, LocaleOverride, @Size) <> 0 then
\r
11628 RegQueryValueEx(Key, '', nil, nil, LocaleOverride, @Size);
\r
11630 RegCloseKey(Key);
\r
11632 lstrcpy(FileName, ModuleName);
\r
11633 GetLocaleInfo(GetThreadLocale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName));
\r
11635 if (FileName[0] <> #0) and ((LocaleName[0] <> #0) or (LocaleOverride[0] <> #0)) then
\r
11637 P := PChar(@FileName) + lstrlen(FileName);
\r
11638 while (P^ <> '.') and (P <> @FileName) do Dec(P);
\r
11639 if P <> @FileName then
\r
11642 // First look for a locale registry override
\r
11643 if LocaleOverride[0] <> #0 then
\r
11645 lstrcpy(P, LocaleOverride);
\r
11646 Result := LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE);
\r
11648 if (Result = 0) and (LocaleName[0] <> #0) then
\r
11650 // Then look for a potential language/country translation
\r
11651 lstrcpy(P, LocaleName);
\r
11652 Result := LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE);
\r
11653 if Result = 0 then
\r
11655 // Finally look for a language only translation
\r
11656 LocaleName[2] := #0;
\r
11657 lstrcpy(P, LocaleName);
\r
11658 Result := LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE);
\r
11665 procedure EnumModules(Func: TEnumModuleFunc; Data: Pointer); assembler;
\r
11667 EnumModules(TEnumModuleFuncLW(Func), Data);
\r
11670 procedure EnumResourceModules(Func: TEnumModuleFunc; Data: Pointer);
\r
11672 EnumResourceModules(TEnumModuleFuncLW(Func), Data);
\r
11675 procedure EnumModules(Func: TEnumModuleFuncLW; Data: Pointer);
\r
11677 CurModule: PLibModule;
\r
11679 CurModule := LibModuleList;
\r
11680 while CurModule <> nil do
\r
11682 if not Func(CurModule.Instance, Data) then Exit;
\r
11683 CurModule := CurModule.Next;
\r
11687 procedure EnumResourceModules(Func: TEnumModuleFuncLW; Data: Pointer);
\r
11689 CurModule: PLibModule;
\r
11691 CurModule := LibModuleList;
\r
11692 while CurModule <> nil do
\r
11694 if not Func(CurModule.ResInstance, Data) then Exit;
\r
11695 CurModule := CurModule.Next;
\r
11699 procedure AddModuleUnloadProc(Proc: TModuleUnloadProc);
\r
11701 AddModuleUnloadProc(TModuleUnloadProcLW(Proc));
\r
11704 procedure RemoveModuleUnloadProc(Proc: TModuleUnloadProc);
\r
11706 RemoveModuleUnloadProc(TModuleUnloadProcLW(Proc));
\r
11709 procedure AddModuleUnloadProc(Proc: TModuleUnloadProcLW);
\r
11711 P: PModuleUnloadRec;
\r
11714 P.Next := ModuleUnloadList;
\r
11715 @P.Proc := @Proc;
\r
11716 ModuleUnloadList := P;
\r
11719 procedure RemoveModuleUnloadProc(Proc: TModuleUnloadProcLW);
\r
11721 P, C: PModuleUnloadRec;
\r
11723 P := ModuleUnloadList;
\r
11724 if (P <> nil) and (@P.Proc = @Proc) then
\r
11726 ModuleUnloadList := ModuleUnloadList.Next;
\r
11731 while C <> nil do
\r
11733 if (C.Next <> nil) and (@C.Next.Proc = @Proc) then
\r
11736 C.Next := C.Next.Next;
\r
11745 procedure NotifyModuleUnload(HInstance: LongWord);
\r
11747 P: PModuleUnloadRec;
\r
11749 P := ModuleUnloadList;
\r
11750 while P <> nil do
\r
11753 P.Proc(HInstance);
\r
11755 // Make sure it doesn't stop notifications
\r
11761 procedure RegisterModule(LibModule: PLibModule);
\r
11763 LibModule.Next := LibModuleList;
\r
11764 LibModuleList := LibModule;
\r
11767 {X- procedure UnregisterModule(LibModule: PLibModule); -renamed }
\r
11768 procedure UnRegisterModuleSafely( LibModule: PLibModule );
\r
11770 CurModule: PLibModule;
\r
11773 NotifyModuleUnload(LibModule.Instance);
\r
11775 if LibModule = LibModuleList then
\r
11776 LibModuleList := LibModule.Next
\r
11779 CurModule := LibModuleList;
\r
11780 while CurModule <> nil do
\r
11782 if CurModule.Next = LibModule then
\r
11784 CurModule.Next := LibModule.Next;
\r
11787 CurModule := CurModule.Next;
\r
11793 {X+} // "Light" version of UnRegisterModule - without using of try-except
\r
11794 procedure UnRegisterModuleLight( LibModule: PLibModule );
\r
11796 P: PModuleUnloadRec;
\r
11798 P := ModuleUnloadList;
\r
11799 while P <> nil do
\r
11801 P.Proc(LibModule.Instance);
\r
11807 { ResString support function }
\r
11809 function LoadResString(ResStringRec: PResStringRec): string;
\r
11811 Buffer: array[0..1023] of Char;
\r
11813 if ResStringRec <> nil then
\r
11814 if ResStringRec.Identifier < 64*1024 then
\r
11815 SetString(Result, Buffer, LoadString(FindResourceHInstance(ResStringRec.Module^),
\r
11816 ResStringRec.Identifier, Buffer, SizeOf(Buffer)))
\r
11818 Result := PChar(ResStringRec.Identifier);
\r
11821 procedure _IntfClear(var Dest: IUnknown);
\r
11826 MOV DWORD PTR [EAX],0
\r
11830 CALL [EAX].vmtRelease.Pointer
\r
11835 procedure _IntfCopy(var Dest: IUnknown; const Source: IUnknown);
\r
11837 MOV ECX,[EAX] { save dest }
\r
11838 MOV [EAX],EDX { assign dest }
\r
11839 TEST EDX,EDX { need to addref source before releasing dest }
\r
11840 JE @@1 { to make self assignment (I := I) work right }
\r
11844 CALL [EAX].vmtAddRef.Pointer
\r
11846 @@1: TEST ECX,ECX
\r
11850 CALL [EAX].vmtRelease.Pointer
\r
11854 procedure _IntfCast(var Dest: IUnknown; const Source: IUnknown; const IID: TGUID);
\r
11866 CALL [EAX].vmtRelease.Pointer
\r
11868 @@1: MOV EAX,[EDX]
\r
11869 CALL [EAX].vmtQueryInterface.Pointer
\r
11872 MOV AL,reIntfCastError
\r
11877 procedure _IntfAddRef(const Dest: IUnknown);
\r
11879 if Dest <> nil then Dest._AddRef;
\r
11882 procedure TInterfacedObject.AfterConstruction;
\r
11884 // Release the constructor's implicit refcount
\r
11885 InterlockedDecrement(FRefCount);
\r
11888 procedure TInterfacedObject.BeforeDestruction;
\r
11890 if RefCount <> 0 then Error(reInvalidPtr);
\r
11893 // Set an implicit refcount so that refcounting
\r
11894 // during construction won't destroy the object.
\r
11895 class function TInterfacedObject.NewInstance: TObject;
\r
11897 Result := inherited NewInstance;
\r
11898 TInterfacedObject(Result).FRefCount := 1;
\r
11901 function TInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
\r
11903 E_NOINTERFACE = HResult($80004002);
\r
11905 if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
\r
11908 function TInterfacedObject._AddRef: Integer;
\r
11910 Result := InterlockedIncrement(FRefCount);
\r
11913 function TInterfacedObject._Release: Integer;
\r
11915 Result := InterlockedDecrement(FRefCount);
\r
11916 if Result = 0 then
\r
11920 procedure _CheckAutoResult;
\r
11924 MOV ECX,SafeCallErrorProc
\r
11929 @@1: MOV AL,reSafeCallError
\r
11935 procedure _IntfDispCall;
\r
11937 JMP DispCallByIDProc
\r
11941 procedure _IntfVarCall;
\r
11945 function CompToDouble(acomp: Comp): Double; cdecl;
\r
11950 procedure DoubleToComp(adouble: Double; var result: Comp); cdecl;
\r
11952 result := adouble;
\r
11955 function CompToCurrency(acomp: Comp): Currency; cdecl;
\r
11960 procedure CurrencyToComp(acurrency: Currency; var result: Comp); cdecl;
\r
11962 result := acurrency
\r
11965 function GetMemory(Size: Integer): Pointer; cdecl;
\r
11967 Result := {X- SysGetMem(Size); -replaced to use current memory manager}
\r
11968 MemoryManager.GetMem( Size );
\r
11971 function FreeMemory(P: Pointer): Integer; cdecl;
\r
11976 Result := {X- SysFreeMem(P); - replaced to use current memory manager}
\r
11977 MemoryManager.FreeMem( P );
\r
11980 function ReallocMemory(P: Pointer; Size: Integer): Pointer; cdecl;
\r
11982 {X- Result := SysReallocMem(P, Size); - replaced to use current memory manager}
\r
11983 Result := MemoryManager.ReallocMem( P, Size );
\r
11986 function GetCurrentThreadId: DWORD; stdcall; external kernel name 'GetCurrentThreadId';
\r
11988 {X} // convert var CmdLine : PChar to a function:
\r
11989 {X} function CmdLine : PChar;
\r
11991 {X} Result := GetCommandLine;
\r
11996 {X- initialized by 0 anyway
\r
11998 ErrorAddr := nil;
\r
12003 {X- initialized statically
\r
12010 {X- moved to SysVarnt.pas
\r
12012 TVarData(Unassigned).VType := varEmpty;
\r
12013 TVarData(Null).VType := varNull;
\r
12014 TVarData(EmptyParam).VType := varError;
\r
12015 TVarData(EmptyParam).VError := $80020004; //DISP_E_PARAMNOTFOUND
\r
12017 ClearAnyProc := @VarInvalidOp;
\r
12018 ChangeAnyProc := @VarCastError;
\r
12019 RefAnyProc := @VarInvalidOp;
\r
12024 if _isNECWindows then _FpuMaskInit;
\r
12028 {X- to use Input/Output, call UseInputOutput (or include
\r
12029 following two lines into your code and call Close(Input),
\r
12030 Close(Output) at the end of execution).
\r
12031 _Assign( Input, '' );
\r
12032 _Assign( Output, '' );
\r
12035 {X- CmdLine := GetCommandLine; converted to a function }
\r
12036 {X- CmdShow := GetCmdShow; converted to a function }
\r
12037 MainThreadID := GetCurrentThreadID;
\r
12040 {X}if assigned( CloseInputOutput ) then
\r
12041 {X} CloseInputOutput;
\r
12046 {X UninitAllocator; - replaced with call to UninitMemoryManager handler. }
\r
12047 UninitMemoryManager;
\r