system.pp 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2005 by Florian Klaempfl and Pavel Ozerski
  4. and Yury Sidorov member of the Free Pascal development team.
  5. FPC Pascal system unit for the WinCE.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit System;
  13. interface
  14. {$ifdef SYSTEMDEBUG}
  15. {$define SYSTEMEXCEPTIONDEBUG}
  16. {$endif SYSTEMDEBUG}
  17. {$define WINCE_EXCEPTION_HANDLING}
  18. {$define DISABLE_NO_THREAD_MANAGER}
  19. {$define HAS_CMDLINE}
  20. {$define HAS_MEMORYMANAGER} // comment this line to switch from wincemm to fpcmm
  21. {$define HAS_WIDESTRINGMANAGER}
  22. { include system-independent routine headers }
  23. {$I systemh.inc}
  24. const
  25. LineEnding = #13#10;
  26. LFNSupport = true;
  27. DirectorySeparator = '\';
  28. DriveSeparator = ':';
  29. ExtensionSeparator = '.';
  30. PathSeparator = ';';
  31. AllowDirectorySeparators : set of char = ['\','/'];
  32. AllowDriveSeparators : set of char = [':'];
  33. { FileNameCaseSensitive is defined separately below!!! }
  34. maxExitCode = 65535;
  35. MaxPathLen = 260;
  36. AllFilesMask = '*';
  37. const
  38. { Default filehandles }
  39. UnusedHandle : THandle = THandle(-1);
  40. StdInputHandle : THandle = 0;
  41. StdOutputHandle : THandle = 0;
  42. StdErrorHandle : THandle = 0;
  43. FileNameCaseSensitive : boolean = true;
  44. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  45. sLineBreak = LineEnding;
  46. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  47. var
  48. { WinCE Info }
  49. hprevinst,
  50. MainInstance,
  51. DLLreason,DLLparam:DWord;
  52. type
  53. TDLL_Entry_Hook = procedure (dllparam : longint);
  54. const
  55. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  56. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  57. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  58. { ANSI <-> Wide }
  59. function AnsiToWideBuf(AnsiBuf: PChar; AnsiBufLen: longint; WideBuf: PWideChar; WideBufLen: longint): longint;
  60. function WideToAnsiBuf(WideBuf: PWideChar; WideCharsLen: longint; AnsiBuf: PChar; AnsiBufLen: longint): longint;
  61. function PCharToPWideChar(str: PChar; strlen: longint = -1; outlen: PLongInt = nil): PWideChar;
  62. function StringToPWideChar(const s: AnsiString; outlen: PLongInt = nil): PWideChar;
  63. { Wrappers for some WinAPI calls }
  64. function CreateEvent(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:pchar): THandle;
  65. function ResetEvent(h: THandle): LONGBOOL;
  66. function SetEvent(h: THandle): LONGBOOL;
  67. function GetCurrentProcessId:DWORD;
  68. function Win32GetCurrentThreadId:DWORD;
  69. function TlsAlloc : DWord;
  70. function TlsFree(dwTlsIndex : DWord) : LongBool;
  71. function GetFileAttributes(p : pchar) : dword;
  72. function DeleteFile(p : pchar) : longint;
  73. function MoveFile(old,_new : pchar) : longint;
  74. function CreateFile(lpFileName:pchar; dwDesiredAccess:DWORD; dwShareMode:DWORD;
  75. lpSecurityAttributes:pointer; dwCreationDisposition:DWORD;
  76. dwFlagsAndAttributes:DWORD; hTemplateFile:DWORD):longint;
  77. function CreateDirectory(name : pointer;sec : pointer) : longbool;
  78. function RemoveDirectory(name:pointer):longbool;
  79. {$ifdef CPUARM}
  80. { the external directive isn't really necessary here because it is overridden by external (FK) }
  81. function addd(d1,d2 : double) : double; compilerproc;
  82. cdecl;external 'coredll' name '__addd';
  83. function subd(d1,d2 : double) : double; compilerproc;
  84. cdecl;external 'coredll' name '__subd';
  85. function muld(d1,d2 : double) : double; compilerproc;
  86. cdecl;external 'coredll' name '__muld';
  87. function divd(d1,d2 : double) : double; compilerproc;
  88. cdecl;external 'coredll' name '__divd';
  89. function eqd(d1,d2 : double) : boolean; compilerproc;
  90. cdecl;external 'coredll' name '__eqd';
  91. function ned(d1,d2 : double) : boolean; compilerproc;
  92. cdecl;external 'coredll' name '__ned';
  93. function ltd(d1,d2 : double) : boolean; compilerproc;
  94. cdecl;external 'coredll' name '__ltd';
  95. function gtd(d1,d2 : double) : boolean; compilerproc;
  96. cdecl;external 'coredll' name '__gtd';
  97. function ged(d1,d2 : double) : boolean; compilerproc;
  98. cdecl;external 'coredll' name '__ged';
  99. function led(d1,d2 : double) : boolean; compilerproc;
  100. cdecl;external 'coredll' name '__led';
  101. { ***************** single ******************** }
  102. function eqs(d1,d2 : single) : boolean; compilerproc;
  103. cdecl;external 'coredll' name '__eqs';
  104. function nes(d1,d2 : single) : boolean; compilerproc;
  105. cdecl;external 'coredll' name '__nes';
  106. function lts(d1,d2 : single) : boolean; compilerproc;
  107. cdecl;external 'coredll' name '__lts';
  108. function gts(d1,d2 : single) : boolean; compilerproc;
  109. cdecl;external 'coredll' name '__gts';
  110. function ges(d1,d2 : single) : boolean; compilerproc;
  111. cdecl;external 'coredll' name '__ges';
  112. function les(d1,d2 : single) : boolean; compilerproc;
  113. cdecl;external 'coredll' name '__les';
  114. function dtos(d : double) : single; compilerproc;
  115. cdecl;external 'coredll' name '__dtos';
  116. function stod(d : single) : double; compilerproc;
  117. cdecl;external 'coredll' name '__stod';
  118. function negs(d : single) : single; compilerproc;
  119. cdecl;external 'coredll' name '__negs';
  120. function negd(d : double) : double; compilerproc;
  121. cdecl;external 'coredll' name '__negd';
  122. function utod(i : dword) : double; compilerproc;
  123. cdecl;external 'coredll' name '__utod';
  124. function itod(i : longint) : double; compilerproc;
  125. cdecl;external 'coredll' name '__itod';
  126. function ui64tod(i : qword) : double; compilerproc;
  127. cdecl;external 'coredll' name '__u64tod';
  128. function i64tod(i : int64) : double; compilerproc;
  129. cdecl;external 'coredll' name '__i64tod';
  130. function utos(i : dword) : single; compilerproc;
  131. cdecl;external 'coredll' name '__utos';
  132. function itos(i : longint) : single; compilerproc;
  133. cdecl;external 'coredll' name '__itos';
  134. function ui64tos(i : qword) : single; compilerproc;
  135. cdecl;external 'coredll' name '__u64tos';
  136. function i64tos(i : int64) : single; compilerproc;
  137. cdecl;external 'coredll' name '__i64tos';
  138. function adds(s1,s2 : single) : single; compilerproc;
  139. function subs(s1,s2 : single) : single; compilerproc;
  140. function muls(s1,s2 : single) : single; compilerproc;
  141. function divs(s1,s2 : single) : single; compilerproc;
  142. {$endif CPUARM}
  143. function CmdLine: PChar;
  144. { C compatible arguments }
  145. function argc: longint;
  146. function argv: ppchar;
  147. implementation
  148. var
  149. SysInstance : Longint;public name '_FPC_SysInstance';
  150. function MessageBox(w1:longint;l1,l2:PWideChar;w2:longint):longint;
  151. cdecl; external 'coredll' name 'MessageBoxW';
  152. {*****************************************************************************}
  153. {$define FPC_SYSTEM_HAS_MOVE}
  154. procedure memmove(dest, src: pointer; count: longint);
  155. cdecl; external 'coredll' name 'memmove';
  156. procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];
  157. begin
  158. if count > 0 then
  159. memmove(@dest, @source, count);
  160. end;
  161. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  162. function memcmp(buf1, buf2: pointer; count: longint): longint;
  163. cdecl; external 'coredll' name 'memcmp';
  164. function CompareByte(Const buf1,buf2;len:SizeInt):SizeInt;
  165. begin
  166. CompareByte := memcmp(@buf1, @buf2, len);
  167. end;
  168. {$ifdef CPUARM}
  169. {$define FPC_SYSTEM_HAS_INT}
  170. function floor(d : double) : double;
  171. cdecl;external 'coredll' name 'floor';
  172. function ceil(d : double) : double;
  173. cdecl;external 'coredll' name 'ceil';
  174. function fpc_int_real(d: ValReal): ValReal;compilerproc;
  175. begin
  176. if d > 0 then
  177. fpc_int_real:=floor(d)
  178. else
  179. fpc_int_real:=ceil(d);
  180. end;
  181. {$define FPC_SYSTEM_HAS_TRUNC}
  182. function __dtoi64(d: double) : int64; cdecl; external 'coredll';
  183. function fpc_trunc_real(d : ValReal) : int64; assembler; nostackframe; compilerproc;
  184. asm
  185. b __dtoi64
  186. end;
  187. {$define FPC_SYSTEM_HAS_ABS}
  188. function fabs(d: double): double; cdecl; external 'coredll';
  189. function fpc_abs_real(d : ValReal) : ValReal; assembler; nostackframe; compilerproc;
  190. asm
  191. b fabs
  192. end;
  193. {$define FPC_SYSTEM_HAS_SQRT}
  194. function coresqrt(d: double): double; cdecl; external 'coredll' name 'sqrt';
  195. function fpc_sqrt_real(d : ValReal) : ValReal; assembler; nostackframe; compilerproc;
  196. asm
  197. b coresqrt
  198. end;
  199. function adds(s1,s2 : single) : single;
  200. begin
  201. adds := addd(s1, s2);
  202. end;
  203. function subs(s1,s2 : single) : single;
  204. begin
  205. subs := subd(s1, s2);
  206. end;
  207. function muls(s1,s2 : single) : single;
  208. begin
  209. muls := muld(s1, s2);
  210. end;
  211. function divs(s1,s2 : single) : single;
  212. begin
  213. divs := divd(s1, s2);
  214. end;
  215. {$endif CPUARM}
  216. {*****************************************************************************}
  217. { include system independent routines }
  218. {$I system.inc}
  219. {*****************************************************************************
  220. ANSI <-> Wide
  221. *****************************************************************************}
  222. const
  223. { MultiByteToWideChar }
  224. MB_PRECOMPOSED = 1;
  225. MB_COMPOSITE = 2;
  226. MB_ERR_INVALID_CHARS = 8;
  227. MB_USEGLYPHCHARS = 4;
  228. CP_ACP = 0;
  229. CP_OEMCP = 1;
  230. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  231. cdecl; external 'coredll' name 'MultiByteToWideChar';
  232. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  233. cdecl; external 'coredll' name 'WideCharToMultiByte';
  234. { Returns number of characters stored to WideBuf, including null-terminator. }
  235. function AnsiToWideBuf(AnsiBuf: PChar; AnsiBufLen: longint; WideBuf: PWideChar; WideBufLen: longint): longint;
  236. begin
  237. Result := MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, AnsiBuf, AnsiBufLen, WideBuf, WideBufLen div SizeOf(WideChar));
  238. if ((AnsiBufLen <> -1) or (Result = 0)) and (WideBuf <> nil) then
  239. begin
  240. if (Result + 1)*SizeOf(WideChar) > WideBufLen then
  241. begin
  242. Result := 0;
  243. if WideBufLen < SizeOf(WideChar) then
  244. exit;
  245. end;
  246. WideBuf[Result] := #0;
  247. end;
  248. if (AnsiBufLen <> -1) and ((Result <> 0) or (AnsiBufLen = 0)) then
  249. Inc(Result);
  250. end;
  251. { Returns number of characters stored to AnsiBuf, including null-terminator. }
  252. function WideToAnsiBuf(WideBuf: PWideChar; WideCharsLen: longint; AnsiBuf: PChar; AnsiBufLen: longint): longint;
  253. begin
  254. Result := WideCharToMultiByte(CP_ACP, 0, WideBuf, WideCharsLen, AnsiBuf, AnsiBufLen, nil, nil);
  255. if ((WideCharsLen <> -1) or (Result = 0)) and (AnsiBuf <> nil) then
  256. begin
  257. if Result + 1 > AnsiBufLen then
  258. begin
  259. Result := 0;
  260. if AnsiBufLen < 1 then
  261. exit;
  262. end;
  263. AnsiBuf[Result] := #0;
  264. end;
  265. if (WideCharsLen <> -1) and ((Result <> 0) or (WideCharsLen = 0)) then
  266. Inc(Result);
  267. end;
  268. { Returns dynamic memory block, which contains wide string. This memory should be freed using FreeMem. }
  269. { outlen will contain number of wide characters stored to result buffer, including null-terminator. }
  270. function PCharToPWideChar(str: PChar; strlen: longint = -1; outlen: PLongInt = nil): PWideChar;
  271. var
  272. len: longint;
  273. begin
  274. while True do begin
  275. if strlen <> -1 then
  276. len:=strlen + 1
  277. else
  278. len:=AnsiToWideBuf(str, -1, nil, 0);
  279. if len > 0 then
  280. begin
  281. len:=len*SizeOf(WideChar);
  282. GetMem(Result, len);
  283. len:=AnsiToWideBuf(str, strlen, Result, len);
  284. if (len = 0) and (strlen <> -1) then
  285. begin
  286. FreeMem(Result);
  287. strlen:=-1;
  288. continue;
  289. end;
  290. end
  291. else begin
  292. GetMem(Result, SizeOf(WideChar));
  293. len:=1;
  294. Result^:=#0;
  295. end;
  296. break;
  297. end;
  298. if outlen <> nil then
  299. outlen^:=len;
  300. end;
  301. { Returns dynamic memory block, which contains wide string. This memory should be freed using FreeMem. }
  302. { outlen will contain number of wide characters stored to result buffer, including null-terminator. }
  303. function StringToPWideChar(const s: AnsiString; outlen: PLongInt = nil): PWideChar;
  304. var
  305. len, wlen: longint;
  306. begin
  307. len:=Length(s);
  308. wlen:=(len + 1)*SizeOf(WideChar);
  309. GetMem(Result, wlen);
  310. wlen:=AnsiToWideBuf(PChar(s), len, Result, wlen)*SizeOf(WideChar);
  311. if wlen = 0 then
  312. begin
  313. wlen:=AnsiToWideBuf(PChar(s), len, nil, 0)*SizeOf(WideChar);
  314. if wlen > 0 then
  315. begin
  316. ReAllocMem(Result, wlen);
  317. wlen:=AnsiToWideBuf(PChar(s), len, Result, wlen)*SizeOf(WideChar);
  318. end
  319. else
  320. begin
  321. Result^:=#0;
  322. wlen:=SizeOf(WideChar);
  323. end;
  324. end;
  325. if outlen <> nil then
  326. outlen^:=wlen div SizeOf(WideChar);
  327. end;
  328. {*****************************************************************************
  329. WinAPI wrappers implementation
  330. *****************************************************************************}
  331. function GetFileAttributesW(p : pwidechar) : dword;
  332. cdecl; external KernelDLL name 'GetFileAttributesW';
  333. function DeleteFileW(p : pwidechar) : longint;
  334. cdecl; external KernelDLL name 'DeleteFileW';
  335. function MoveFileW(old,_new : pwidechar) : longint;
  336. cdecl; external KernelDLL name 'MoveFileW';
  337. function CreateFileW(lpFileName:pwidechar; dwDesiredAccess:DWORD; dwShareMode:DWORD;
  338. lpSecurityAttributes:pointer; dwCreationDisposition:DWORD;
  339. dwFlagsAndAttributes:DWORD; hTemplateFile:DWORD):longint;
  340. cdecl; external KernelDLL name 'CreateFileW';
  341. function CreateDirectoryW(name : pwidechar;sec : pointer) : longbool;
  342. cdecl; external KernelDLL name 'CreateDirectoryW';
  343. function RemoveDirectoryW(name:pwidechar):longbool;
  344. cdecl; external KernelDLL name 'RemoveDirectoryW';
  345. function GetFileAttributes(p : pchar) : dword;
  346. var
  347. buf: array[0..MaxPathLen] of WideChar;
  348. begin
  349. AnsiToWideBuf(p, -1, buf, SizeOf(buf));
  350. GetFileAttributes := GetFileAttributesW(buf);
  351. end;
  352. function DeleteFile(p : pchar) : longint;
  353. var
  354. buf: array[0..MaxPathLen] of WideChar;
  355. begin
  356. AnsiToWideBuf(p, -1, buf, SizeOf(buf));
  357. DeleteFile := DeleteFileW(buf);
  358. end;
  359. function MoveFile(old,_new : pchar) : longint;
  360. var
  361. buf_old, buf_new: array[0..MaxPathLen] of WideChar;
  362. begin
  363. AnsiToWideBuf(old, -1, buf_old, SizeOf(buf_old));
  364. AnsiToWideBuf(_new, -1, buf_new, SizeOf(buf_new));
  365. MoveFile := MoveFileW(buf_old, buf_new);
  366. end;
  367. function CreateFile(lpFileName:pchar; dwDesiredAccess:DWORD; dwShareMode:DWORD;
  368. lpSecurityAttributes:pointer; dwCreationDisposition:DWORD;
  369. dwFlagsAndAttributes:DWORD; hTemplateFile:DWORD):longint;
  370. var
  371. buf: array[0..MaxPathLen] of WideChar;
  372. begin
  373. AnsiToWideBuf(lpFileName, -1, buf, SizeOf(buf));
  374. CreateFile := CreateFileW(buf, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
  375. dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  376. end;
  377. function CreateDirectory(name : pointer;sec : pointer) : longbool;
  378. var
  379. buf: array[0..MaxPathLen] of WideChar;
  380. begin
  381. AnsiToWideBuf(name, -1, buf, SizeOf(buf));
  382. CreateDirectory := CreateDirectoryW(buf, sec);
  383. end;
  384. function RemoveDirectory(name:pointer):longbool;
  385. var
  386. buf: array[0..MaxPathLen] of WideChar;
  387. begin
  388. AnsiToWideBuf(name, -1, buf, SizeOf(buf));
  389. RemoveDirectory := RemoveDirectoryW(buf);
  390. end;
  391. const
  392. {$ifdef CPUARM}
  393. UserKData = $FFFFC800;
  394. {$else CPUARM}
  395. UserKData = $00005800;
  396. {$endif CPUARM}
  397. SYSHANDLE_OFFSET = $004;
  398. SYS_HANDLE_BASE = 64;
  399. SH_CURTHREAD = 1;
  400. SH_CURPROC = 2;
  401. type
  402. PHandle = ^THandle;
  403. const
  404. EVENT_PULSE = 1;
  405. EVENT_RESET = 2;
  406. EVENT_SET = 3;
  407. function CreateEventW(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:PWideChar): THandle;
  408. cdecl; external KernelDLL name 'CreateEventW';
  409. function CreateEvent(lpEventAttributes:pointer;bManualReset:longbool;bInitialState:longbool;lpName:pchar): THandle;
  410. var
  411. buf: array[0..MaxPathLen] of WideChar;
  412. begin
  413. AnsiToWideBuf(lpName, -1, buf, SizeOf(buf));
  414. CreateEvent := CreateEventW(lpEventAttributes, bManualReset, bInitialState, buf);
  415. end;
  416. function EventModify(h: THandle; func: DWORD): LONGBOOL;
  417. cdecl; external KernelDLL name 'EventModify';
  418. function TlsCall(p1, p2: DWORD): DWORD;
  419. cdecl; external KernelDLL name 'TlsCall';
  420. function ResetEvent(h: THandle): LONGBOOL;
  421. begin
  422. ResetEvent := EventModify(h,EVENT_RESET);
  423. end;
  424. function SetEvent(h: THandle): LONGBOOL;
  425. begin
  426. SetEvent := EventModify(h,EVENT_SET);
  427. end;
  428. function GetCurrentProcessId:DWORD;
  429. var
  430. p: PHandle;
  431. begin
  432. p:=PHandle(UserKData+SYSHANDLE_OFFSET + SH_CURPROC*SizeOf(THandle));
  433. GetCurrentProcessId := p^;
  434. end;
  435. function Win32GetCurrentThreadId:DWORD;
  436. var
  437. p: PHandle;
  438. begin
  439. p:=PHandle(UserKData+SYSHANDLE_OFFSET + SH_CURTHREAD*SizeOf(THandle));
  440. Win32GetCurrentThreadId := p^;
  441. end;
  442. const
  443. TLS_FUNCALLOC = 0;
  444. TLS_FUNCFREE = 1;
  445. function TlsAlloc : DWord;
  446. begin
  447. TlsAlloc := TlsCall(TLS_FUNCALLOC, 0);
  448. end;
  449. function TlsFree(dwTlsIndex : DWord) : LongBool;
  450. begin
  451. TlsFree := LongBool(TlsCall(TLS_FUNCFREE, dwTlsIndex));
  452. end;
  453. {*****************************************************************************
  454. Parameter Handling
  455. *****************************************************************************}
  456. function GetCommandLine : pwidechar;
  457. cdecl; external KernelDLL name 'GetCommandLineW';
  458. var
  459. ModuleName : array[0..255] of char;
  460. function GetCommandFile:pchar;
  461. var
  462. buf: array[0..MaxPathLen] of WideChar;
  463. begin
  464. if ModuleName[0] = #0 then begin
  465. GetModuleFileName(0, @buf, SizeOf(buf));
  466. WideToAnsiBuf(buf, -1, @ModuleName, SizeOf(ModuleName));
  467. end;
  468. GetCommandFile:=@ModuleName;
  469. end;
  470. var
  471. Fargc: longint;
  472. Fargv: ppchar;
  473. FCmdLine: PChar;
  474. procedure setup_arguments;
  475. var
  476. arglen,
  477. count : longint;
  478. argstart,
  479. pc,arg : pchar;
  480. quote : char;
  481. argvlen : longint;
  482. procedure allocarg(idx,len:longint);
  483. var
  484. oldargvlen : longint;
  485. begin
  486. if idx>=argvlen then
  487. begin
  488. oldargvlen:=argvlen;
  489. argvlen:=(idx+8) and (not 7);
  490. sysreallocmem(Fargv,argvlen*sizeof(pointer));
  491. fillchar(Fargv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  492. end;
  493. { use realloc to reuse already existing memory }
  494. { always allocate, even if length is zero, since }
  495. { the arg. is still present! }
  496. sysreallocmem(Fargv[idx],len+1);
  497. end;
  498. begin
  499. { create commandline, it starts with the executed filename which is argv[0] }
  500. { WinCE passes the command NOT via the args, but via getmodulefilename}
  501. if FCmdLine <> nil then exit;
  502. argvlen:=0;
  503. pc:=getcommandfile;
  504. Arglen:=0;
  505. while pc[Arglen] <> #0 do
  506. Inc(Arglen);
  507. allocarg(0,arglen);
  508. move(pc^,Fargv[0]^,arglen+1);
  509. { Setup FCmdLine variable }
  510. arg:=PChar(GetCommandLine);
  511. count:=WideToAnsiBuf(PWideChar(arg), -1, nil, 0);
  512. FCmdLine:=SysGetMem(arglen + count + 3);
  513. FCmdLine^:='"';
  514. move(pc^, (FCmdLine + 1)^, arglen);
  515. (FCmdLine + arglen + 1)^:='"';
  516. (FCmdLine + arglen + 2)^:=' ';
  517. WideToAnsiBuf(PWideChar(arg), -1, FCmdLine + arglen + 3, count);
  518. { process arguments }
  519. count:=0;
  520. pc:=FCmdLine;
  521. {$IfDef SYSTEM_DEBUG_STARTUP}
  522. Writeln(stderr,'WinCE GetCommandLine is #',pc,'#');
  523. {$EndIf }
  524. while pc^<>#0 do
  525. begin
  526. { skip leading spaces }
  527. while pc^ in [#1..#32] do
  528. inc(pc);
  529. if pc^=#0 then
  530. break;
  531. { calc argument length }
  532. quote:=' ';
  533. argstart:=pc;
  534. arglen:=0;
  535. while (pc^<>#0) do
  536. begin
  537. case pc^ of
  538. #1..#32 :
  539. begin
  540. if quote<>' ' then
  541. inc(arglen)
  542. else
  543. break;
  544. end;
  545. '"' :
  546. begin
  547. if quote<>'''' then
  548. begin
  549. if pchar(pc+1)^<>'"' then
  550. begin
  551. if quote='"' then
  552. quote:=' '
  553. else
  554. quote:='"';
  555. end
  556. else
  557. inc(pc);
  558. end
  559. else
  560. inc(arglen);
  561. end;
  562. '''' :
  563. begin
  564. if quote<>'"' then
  565. begin
  566. if pchar(pc+1)^<>'''' then
  567. begin
  568. if quote='''' then
  569. quote:=' '
  570. else
  571. quote:='''';
  572. end
  573. else
  574. inc(pc);
  575. end
  576. else
  577. inc(arglen);
  578. end;
  579. else
  580. inc(arglen);
  581. end;
  582. inc(pc);
  583. end;
  584. { copy argument }
  585. { Don't copy the first one, it is already there.}
  586. If Count<>0 then
  587. begin
  588. allocarg(count,arglen);
  589. quote:=' ';
  590. pc:=argstart;
  591. arg:=Fargv[count];
  592. while (pc^<>#0) do
  593. begin
  594. case pc^ of
  595. #1..#32 :
  596. begin
  597. if quote<>' ' then
  598. begin
  599. arg^:=pc^;
  600. inc(arg);
  601. end
  602. else
  603. break;
  604. end;
  605. '"' :
  606. begin
  607. if quote<>'''' then
  608. begin
  609. if pchar(pc+1)^<>'"' then
  610. begin
  611. if quote='"' then
  612. quote:=' '
  613. else
  614. quote:='"';
  615. end
  616. else
  617. inc(pc);
  618. end
  619. else
  620. begin
  621. arg^:=pc^;
  622. inc(arg);
  623. end;
  624. end;
  625. '''' :
  626. begin
  627. if quote<>'"' then
  628. begin
  629. if pchar(pc+1)^<>'''' then
  630. begin
  631. if quote='''' then
  632. quote:=' '
  633. else
  634. quote:='''';
  635. end
  636. else
  637. inc(pc);
  638. end
  639. else
  640. begin
  641. arg^:=pc^;
  642. inc(arg);
  643. end;
  644. end;
  645. else
  646. begin
  647. arg^:=pc^;
  648. inc(arg);
  649. end;
  650. end;
  651. inc(pc);
  652. end;
  653. arg^:=#0;
  654. end;
  655. {$IfDef SYSTEM_DEBUG_STARTUP}
  656. Writeln(stderr,'dos arg ',count,' #',arglen,'#',Fargv[count],'#');
  657. {$EndIf SYSTEM_DEBUG_STARTUP}
  658. inc(count);
  659. end;
  660. { get argc and create an nil entry }
  661. Fargc:=count;
  662. allocarg(argc,0);
  663. { free unused memory }
  664. sysreallocmem(Fargv,(argc+1)*sizeof(pointer));
  665. end;
  666. function CmdLine: PChar;
  667. begin
  668. setup_arguments;
  669. Result:=FCmdLine;
  670. end;
  671. function argc: longint;
  672. begin
  673. setup_arguments;
  674. Result:=Fargc;
  675. end;
  676. function argv: ppchar;
  677. begin
  678. setup_arguments;
  679. Result:=Fargv;
  680. end;
  681. function paramcount : longint;
  682. begin
  683. paramcount := argc - 1;
  684. end;
  685. function paramstr(l : longint) : string;
  686. begin
  687. setup_arguments;
  688. if (l>=0) and (l<Fargc) then
  689. paramstr:=strpas(Fargv[l])
  690. else
  691. paramstr:='';
  692. end;
  693. procedure randomize;
  694. begin
  695. randseed:=GetTickCount;
  696. end;
  697. {*****************************************************************************
  698. System Dependent Exit code
  699. *****************************************************************************}
  700. procedure PascalMain;external name 'PASCALMAIN';
  701. procedure ExitThread(Exitcode : longint); cdecl; external 'coredll';
  702. Procedure system_exit;
  703. begin
  704. if IsLibrary then
  705. exit;
  706. if not IsConsole then
  707. begin
  708. Close(stderr);
  709. Close(stdout);
  710. Close(erroutput);
  711. Close(Input);
  712. Close(Output);
  713. end;
  714. ExitThread(exitcode);
  715. end;
  716. {$ifdef cpu386}
  717. var
  718. { value of the stack segment
  719. to check if the call stack can be written on exceptions }
  720. _SS : Cardinal;
  721. {$endif cpu386}
  722. Const
  723. { DllEntryPoint }
  724. DLL_PROCESS_ATTACH = 1;
  725. DLL_THREAD_ATTACH = 2;
  726. DLL_PROCESS_DETACH = 0;
  727. DLL_THREAD_DETACH = 3;
  728. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  729. begin
  730. IsLibrary:=true;
  731. Dll_entry:=false;
  732. case DLLreason of
  733. DLL_PROCESS_ATTACH :
  734. begin
  735. PASCALMAIN;
  736. Dll_entry:=true;
  737. end;
  738. DLL_THREAD_ATTACH :
  739. begin
  740. { Allocate Threadvars ?!}
  741. if assigned(Dll_Thread_Attach_Hook) then
  742. Dll_Thread_Attach_Hook(DllParam);
  743. end;
  744. DLL_THREAD_DETACH :
  745. begin
  746. if assigned(Dll_Thread_Detach_Hook) then
  747. Dll_Thread_Detach_Hook(DllParam);
  748. { Release Threadvars ?!}
  749. end;
  750. DLL_PROCESS_DETACH :
  751. begin
  752. Lib_Exit;
  753. if assigned(Dll_Process_Detach_Hook) then
  754. Dll_Process_Detach_Hook(DllParam);
  755. end;
  756. end;
  757. end;
  758. {$ifdef WINCE_EXCEPTION_HANDLING}
  759. //
  760. // Hardware exception handling
  761. //
  762. {
  763. Error code definitions for the WinCE API functions
  764. Values are 32 bit values layed out as follows:
  765. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  766. 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  767. +---+-+-+-----------------------+-------------------------------+
  768. |Sev|C|R| Facility | Code |
  769. +---+-+-+-----------------------+-------------------------------+
  770. where
  771. Sev - is the severity code
  772. 00 - Success
  773. 01 - Informational
  774. 10 - Warning
  775. 11 - Error
  776. C - is the Customer code flag
  777. R - is a reserved bit
  778. Facility - is the facility code
  779. Code - is the facility's status code
  780. }
  781. const
  782. SEVERITY_SUCCESS = $00000000;
  783. SEVERITY_INFORMATIONAL = $40000000;
  784. SEVERITY_WARNING = $80000000;
  785. SEVERITY_ERROR = $C0000000;
  786. const
  787. STATUS_SEGMENT_NOTIFICATION = $40000005;
  788. DBG_TERMINATE_THREAD = $40010003;
  789. DBG_TERMINATE_PROCESS = $40010004;
  790. DBG_CONTROL_C = $40010005;
  791. DBG_CONTROL_BREAK = $40010008;
  792. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  793. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  794. STATUS_BREAKPOINT = $80000003;
  795. STATUS_SINGLE_STEP = $80000004;
  796. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  797. STATUS_ACCESS_VIOLATION = $C0000005;
  798. STATUS_IN_PAGE_ERROR = $C0000006;
  799. STATUS_INVALID_HANDLE = $C0000008;
  800. STATUS_NO_MEMORY = $C0000017;
  801. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  802. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  803. STATUS_INVALID_DISPOSITION = $C0000026;
  804. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  805. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  806. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  807. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  808. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  809. STATUS_FLOAT_OVERFLOW = $C0000091;
  810. STATUS_FLOAT_STACK_CHECK = $C0000092;
  811. STATUS_FLOAT_UNDERFLOW = $C0000093;
  812. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  813. STATUS_INTEGER_OVERFLOW = $C0000095;
  814. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  815. STATUS_STACK_OVERFLOW = $C00000FD;
  816. STATUS_CONTROL_C_EXIT = $C000013A;
  817. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  818. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  819. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  820. const
  821. ExceptionContinueExecution = 0;
  822. ExceptionContinueSearch = 1;
  823. ExceptionNestedException = 2;
  824. ExceptionCollidedUnwind = 3;
  825. ExceptionExecuteHandler = 4;
  826. MaxExceptionLevel = 16;
  827. exceptLevel : Byte = 0;
  828. {$ifdef CPUARM}
  829. const
  830. CONTEXT_ARM = $0000040;
  831. CONTEXT_CONTROL = CONTEXT_ARM or $00000001;
  832. CONTEXT_INTEGER = CONTEXT_ARM or $00000002;
  833. CONTEXT_SEGMENTS = CONTEXT_ARM or $00000004;
  834. CONTEXT_FLOATING_POINT = CONTEXT_ARM or $00000008;
  835. CONTEXT_DEBUG_REGISTERS = CONTEXT_ARM or $00000010;
  836. CONTEXT_EXTENDED_REGISTERS = CONTEXT_ARM or $00000020;
  837. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  838. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  839. NUM_VFP_REGS = 32;
  840. NUM_EXTRA_CONTROL_REGS = 8;
  841. type
  842. PContext = ^TContext;
  843. TContext = record
  844. ContextFlags : LongWord;
  845. // This section is specified/returned if the ContextFlags word contains
  846. // the flag CONTEXT_INTEGER.
  847. R0 : LongWord;
  848. R1 : LongWord;
  849. R2 : LongWord;
  850. R3 : LongWord;
  851. R4 : LongWord;
  852. R5 : LongWord;
  853. R6 : LongWord;
  854. R7 : LongWord;
  855. R8 : LongWord;
  856. R9 : LongWord;
  857. R10 : LongWord;
  858. R11 : LongWord;
  859. R12 : LongWord;
  860. // This section is specified/returned if the ContextFlags word contains
  861. // the flag CONTEXT_CONTROL.
  862. Sp : LongWord;
  863. Lr : LongWord;
  864. Pc : LongWord;
  865. Psr : LongWord;
  866. Fpscr : LongWord;
  867. FpExc : LongWord;
  868. // Floating point registers
  869. S : array[0..(NUM_VFP_REGS + 1)-1] of LongWord;
  870. FpExtra : array[0..(NUM_EXTRA_CONTROL_REGS)-1] of LongWord;
  871. end;
  872. {$endif CPUARM}
  873. {$ifdef CPUI386}
  874. const
  875. CONTEXT_X86 = $00010000;
  876. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  877. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  878. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  879. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  880. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  881. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  882. MAXIMUM_SUPPORTED_EXTENSION = 512;
  883. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  884. type
  885. PFloatingSaveArea = ^TFloatingSaveArea;
  886. TFloatingSaveArea = packed record
  887. ControlWord : Cardinal;
  888. StatusWord : Cardinal;
  889. TagWord : Cardinal;
  890. ErrorOffset : Cardinal;
  891. ErrorSelector : Cardinal;
  892. DataOffset : Cardinal;
  893. DataSelector : Cardinal;
  894. RegisterArea : array[0..79] of Byte;
  895. Cr0NpxState : Cardinal;
  896. end;
  897. PContext = ^TContext;
  898. TContext = packed record
  899. //
  900. // The flags values within this flag control the contents of
  901. // a CONTEXT record.
  902. //
  903. ContextFlags : Cardinal;
  904. //
  905. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  906. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  907. // included in CONTEXT_FULL.
  908. //
  909. Dr0, Dr1, Dr2,
  910. Dr3, Dr6, Dr7 : Cardinal;
  911. //
  912. // This section is specified/returned if the
  913. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  914. //
  915. FloatSave : TFloatingSaveArea;
  916. //
  917. // This section is specified/returned if the
  918. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  919. //
  920. SegGs, SegFs,
  921. SegEs, SegDs : Cardinal;
  922. //
  923. // This section is specified/returned if the
  924. // ContextFlags word contains the flag CONTEXT_INTEGER.
  925. //
  926. Edi, Esi, Ebx,
  927. Edx, Ecx, Eax : Cardinal;
  928. //
  929. // This section is specified/returned if the
  930. // ContextFlags word contains the flag CONTEXT_CONTROL.
  931. //
  932. Ebp : Cardinal;
  933. Eip : Cardinal;
  934. SegCs : Cardinal;
  935. EFlags, Esp, SegSs : Cardinal;
  936. //
  937. // This section is specified/returned if the ContextFlags word
  938. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  939. // The format and contexts are processor specific
  940. //
  941. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  942. end;
  943. {$endif CPUI386}
  944. type
  945. PExceptionRecord = ^TExceptionRecord;
  946. TExceptionRecord = packed record
  947. ExceptionCode : Longint;
  948. ExceptionFlags : Longint;
  949. ExceptionRecord : PExceptionRecord;
  950. ExceptionAddress : Pointer;
  951. NumberParameters : Longint;
  952. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  953. end;
  954. PExceptionPointers = ^TExceptionPointers;
  955. TExceptionPointers = packed record
  956. ExceptionRecord : PExceptionRecord;
  957. ContextRecord : PContext;
  958. end;
  959. {$ifdef CPUI386}
  960. {**************************** i386 Exception handling *****************************************}
  961. function GetCurrentProcess:DWORD;
  962. begin
  963. GetCurrentProcess := SH_CURPROC+SYS_HANDLE_BASE;
  964. end;
  965. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  966. cdecl; external 'coredll' name 'ReadProcessMemory';
  967. function is_prefetch(p : pointer) : boolean;
  968. var
  969. a : array[0..15] of byte;
  970. doagain : boolean;
  971. instrlo,instrhi,opcode : byte;
  972. i : longint;
  973. begin
  974. result:=false;
  975. { read memory savely without causing another exeception }
  976. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  977. exit;
  978. i:=0;
  979. doagain:=true;
  980. while doagain and (i<15) do
  981. begin
  982. opcode:=a[i];
  983. instrlo:=opcode and $f;
  984. instrhi:=opcode and $f0;
  985. case instrhi of
  986. { prefix? }
  987. $20,$30:
  988. doagain:=(instrlo and 7)=6;
  989. $60:
  990. doagain:=(instrlo and $c)=4;
  991. $f0:
  992. doagain:=instrlo in [0,2,3];
  993. $0:
  994. begin
  995. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  996. exit;
  997. end;
  998. else
  999. doagain:=false;
  1000. end;
  1001. inc(i);
  1002. end;
  1003. end;
  1004. var
  1005. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  1006. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  1007. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  1008. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1009. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  1010. begin
  1011. if IsConsole then
  1012. begin
  1013. write(stderr,'HandleErrorAddrFrame(error=',error);
  1014. write(stderr,',addr=',hexstr(addr,8));
  1015. writeln(stderr,',frame=',hexstr(frame,8),')');
  1016. end;
  1017. HandleErrorAddrFrame(error,addr,frame);
  1018. end;
  1019. {$endif SYSTEMEXCEPTIONDEBUG}
  1020. procedure JumpToHandleErrorFrame;
  1021. var
  1022. eip, ebp, error : Longint;
  1023. begin
  1024. // save ebp
  1025. asm
  1026. movl (%ebp),%eax
  1027. movl %eax,ebp
  1028. end;
  1029. if (exceptLevel > 0) then
  1030. dec(exceptLevel);
  1031. eip:=exceptEip[exceptLevel];
  1032. error:=exceptError[exceptLevel];
  1033. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1034. if IsConsole then
  1035. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  1036. {$endif SYSTEMEXCEPTIONDEBUG}
  1037. if resetFPU[exceptLevel] then
  1038. SysResetFPU;
  1039. { build a fake stack }
  1040. asm
  1041. {$ifdef REGCALL}
  1042. movl ebp,%ecx
  1043. movl eip,%edx
  1044. movl error,%eax
  1045. pushl eip
  1046. movl ebp,%ebp // Change frame pointer
  1047. {$else}
  1048. movl ebp,%eax
  1049. pushl %eax
  1050. movl eip,%eax
  1051. pushl %eax
  1052. movl error,%eax
  1053. pushl %eax
  1054. movl eip,%eax
  1055. pushl %eax
  1056. movl ebp,%ebp // Change frame pointer
  1057. {$endif}
  1058. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1059. jmpl DebugHandleErrorAddrFrame
  1060. {$else not SYSTEMEXCEPTIONDEBUG}
  1061. jmpl HandleErrorAddrFrame
  1062. {$endif SYSTEMEXCEPTIONDEBUG}
  1063. end;
  1064. end;
  1065. function i386_exception_handler(ExceptionRecord: PExceptionRecord;
  1066. EstablisherFrame: pointer; ContextRecord: PContext;
  1067. DispatcherContext: pointer): longint; cdecl;
  1068. var
  1069. res: longint;
  1070. must_reset_fpu: boolean;
  1071. begin
  1072. res := ExceptionContinueSearch;
  1073. if ContextRecord^.SegSs=_SS then begin
  1074. must_reset_fpu := true;
  1075. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1076. if IsConsole then Writeln(stderr,'Exception ',
  1077. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  1078. {$endif SYSTEMEXCEPTIONDEBUG}
  1079. case cardinal(ExceptionRecord^.ExceptionCode) of
  1080. STATUS_INTEGER_DIVIDE_BY_ZERO,
  1081. STATUS_FLOAT_DIVIDE_BY_ZERO :
  1082. res := 200;
  1083. STATUS_ARRAY_BOUNDS_EXCEEDED :
  1084. begin
  1085. res := 201;
  1086. must_reset_fpu := false;
  1087. end;
  1088. STATUS_STACK_OVERFLOW :
  1089. begin
  1090. res := 202;
  1091. must_reset_fpu := false;
  1092. end;
  1093. STATUS_FLOAT_OVERFLOW :
  1094. res := 205;
  1095. STATUS_FLOAT_DENORMAL_OPERAND,
  1096. STATUS_FLOAT_UNDERFLOW :
  1097. res := 206;
  1098. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  1099. STATUS_FLOAT_INEXACT_RESULT,
  1100. STATUS_FLOAT_INVALID_OPERATION,
  1101. STATUS_FLOAT_STACK_CHECK :
  1102. res := 207;
  1103. STATUS_INTEGER_OVERFLOW :
  1104. begin
  1105. res := 215;
  1106. must_reset_fpu := false;
  1107. end;
  1108. STATUS_ILLEGAL_INSTRUCTION:
  1109. res := 216;
  1110. STATUS_ACCESS_VIOLATION:
  1111. { Athlon prefetch bug? }
  1112. if is_prefetch(pointer(ContextRecord^.Eip)) then
  1113. begin
  1114. { if yes, then retry }
  1115. ExceptionRecord^.ExceptionCode := 0;
  1116. res:=ExceptionContinueExecution;
  1117. end
  1118. else
  1119. res := 216;
  1120. STATUS_CONTROL_C_EXIT:
  1121. res := 217;
  1122. STATUS_PRIVILEGED_INSTRUCTION:
  1123. begin
  1124. res := 218;
  1125. must_reset_fpu := false;
  1126. end;
  1127. else
  1128. begin
  1129. if ((ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  1130. res := 217
  1131. else
  1132. res := 255;
  1133. end;
  1134. end;
  1135. if (res >= 200) and (exceptLevel < MaxExceptionLevel) then begin
  1136. exceptEip[exceptLevel] := ContextRecord^.Eip;
  1137. exceptError[exceptLevel] := res;
  1138. resetFPU[exceptLevel] := must_reset_fpu;
  1139. inc(exceptLevel);
  1140. ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  1141. ExceptionRecord^.ExceptionCode := 0;
  1142. res := ExceptionContinueExecution;
  1143. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1144. if IsConsole then begin
  1145. writeln(stderr,'Exception Continue Exception set at ',
  1146. hexstr(exceptEip[exceptLevel],8));
  1147. writeln(stderr,'Eip changed to ',
  1148. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  1149. end;
  1150. {$endif SYSTEMEXCEPTIONDEBUG}
  1151. end;
  1152. end;
  1153. i386_exception_handler := res;
  1154. end;
  1155. {$endif CPUI386}
  1156. {$ifdef CPUARM}
  1157. {**************************** ARM Exception handling *****************************************}
  1158. var
  1159. exceptPC : array[0..MaxExceptionLevel-1] of Longint;
  1160. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  1161. procedure JumpToHandleErrorFrame;
  1162. var
  1163. _pc, _fp, _error : Longint;
  1164. begin
  1165. // get original fp
  1166. asm
  1167. ldr r0,[r11,#-12]
  1168. str r0,_fp
  1169. end;
  1170. if (exceptLevel > 0) then
  1171. dec(exceptLevel);
  1172. _pc:=exceptPC[exceptLevel];
  1173. _error:=exceptError[exceptLevel];
  1174. asm
  1175. ldr r0,_error
  1176. ldr r1,_pc
  1177. ldr r2,_fp
  1178. mov r11,r2 // Change frame pointer
  1179. b HandleErrorAddrFrame
  1180. end;
  1181. end;
  1182. function ARM_ExceptionHandler(ExceptionRecord: PExceptionRecord;
  1183. EstablisherFrame: pointer; ContextRecord: PContext;
  1184. DispatcherContext: pointer): longint; [public, alias : '_ARM_ExceptionHandler'];
  1185. var
  1186. res: longint;
  1187. begin
  1188. res := ExceptionContinueSearch;
  1189. case cardinal(ExceptionRecord^.ExceptionCode) of
  1190. STATUS_INTEGER_DIVIDE_BY_ZERO,
  1191. STATUS_FLOAT_DIVIDE_BY_ZERO :
  1192. res := 200;
  1193. STATUS_ARRAY_BOUNDS_EXCEEDED :
  1194. res := 201;
  1195. STATUS_STACK_OVERFLOW :
  1196. res := 202;
  1197. STATUS_FLOAT_OVERFLOW :
  1198. res := 205;
  1199. STATUS_FLOAT_DENORMAL_OPERAND,
  1200. STATUS_FLOAT_UNDERFLOW :
  1201. res := 206;
  1202. STATUS_FLOAT_INEXACT_RESULT,
  1203. STATUS_FLOAT_INVALID_OPERATION,
  1204. STATUS_FLOAT_STACK_CHECK :
  1205. res := 207;
  1206. STATUS_INTEGER_OVERFLOW :
  1207. res := 215;
  1208. STATUS_ILLEGAL_INSTRUCTION:
  1209. res := 216;
  1210. STATUS_ACCESS_VIOLATION:
  1211. res := 216;
  1212. STATUS_DATATYPE_MISALIGNMENT:
  1213. res := 214;
  1214. STATUS_CONTROL_C_EXIT:
  1215. res := 217;
  1216. STATUS_PRIVILEGED_INSTRUCTION:
  1217. res := 218;
  1218. else
  1219. begin
  1220. if ((cardinal(ExceptionRecord^.ExceptionCode) and SEVERITY_ERROR) = SEVERITY_ERROR) then
  1221. res := 217
  1222. else
  1223. res := 255;
  1224. end;
  1225. end;
  1226. if (res <> ExceptionContinueSearch) and (exceptLevel < MaxExceptionLevel) then begin
  1227. exceptPC[exceptLevel] := ContextRecord^.PC;
  1228. exceptError[exceptLevel] := res;
  1229. inc(exceptLevel);
  1230. ContextRecord^.PC := Longint(@JumpToHandleErrorFrame);
  1231. ExceptionRecord^.ExceptionCode := 0;
  1232. res := ExceptionContinueExecution;
  1233. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1234. if IsConsole then begin
  1235. writeln(stderr,'Exception Continue Exception set at ',
  1236. hexstr(exceptEip[exceptLevel],8));
  1237. writeln(stderr,'Eip changed to ',
  1238. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  1239. end;
  1240. {$endif SYSTEMEXCEPTIONDEBUG}
  1241. end;
  1242. ARM_ExceptionHandler := res;
  1243. end;
  1244. {$endif CPUARM}
  1245. {$endif WINCE_EXCEPTION_HANDLING}
  1246. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  1247. var
  1248. st: pointer;
  1249. begin
  1250. IsLibrary:=false;
  1251. {$ifdef CPUARM}
  1252. asm
  1253. str sp,st
  1254. end;
  1255. StackTop:=st;
  1256. asm
  1257. mov fp,#0
  1258. bl PASCALMAIN;
  1259. end;
  1260. {$endif CPUARM}
  1261. {$ifdef CPUI386}
  1262. asm
  1263. {$ifdef WINCE_EXCEPTION_HANDLING}
  1264. pushl i386_exception_handler
  1265. pushl %fs:(0)
  1266. mov %esp,%fs:(0)
  1267. {$endif WINCE_EXCEPTION_HANDLING}
  1268. pushl %ebp
  1269. movl %esp,%eax
  1270. movl %eax,st
  1271. end;
  1272. StackTop:=st;
  1273. asm
  1274. xorl %eax,%eax
  1275. movw %ss,%ax
  1276. movl %eax,_SS
  1277. xorl %ebp,%ebp
  1278. call PASCALMAIN
  1279. popl %ebp
  1280. {$ifdef WINCE_EXCEPTION_HANDLING}
  1281. popl %fs:(0)
  1282. addl $4, %esp
  1283. {$endif WINCE_EXCEPTION_HANDLING}
  1284. end;
  1285. {$endif CPUI386}
  1286. end;
  1287. procedure _FPC_mainCRTStartup;public name '_mainCRTStartup';
  1288. begin
  1289. IsConsole:=True;
  1290. Exe_entry;
  1291. end;
  1292. procedure _FPC_WinMainCRTStartup;public name '_WinMainCRTStartup';
  1293. begin
  1294. IsConsole:=False;
  1295. Exe_entry;
  1296. end;
  1297. procedure _FPC_DLLMainCRTStartup(_hinstance,_dllreason,_dllparam:longint);public name '_DLLMainCRTStartup';
  1298. begin
  1299. IsConsole:=true;
  1300. sysinstance:=_hinstance;
  1301. dllreason:=_dllreason;
  1302. dllparam:=_dllparam;
  1303. DLL_Entry;
  1304. end;
  1305. procedure _FPC_DLLWinMainCRTStartup(_hinstance,_dllreason,_dllparam:longint);public name '_DLLWinMainCRTStartup';
  1306. begin
  1307. IsConsole:=false;
  1308. sysinstance:=_hinstance;
  1309. dllreason:=_dllreason;
  1310. dllparam:=_dllparam;
  1311. DLL_Entry;
  1312. end;
  1313. {****************************************************************************
  1314. OS dependend widestrings
  1315. ****************************************************************************}
  1316. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; cdecl; external KernelDLL name 'CharUpperBuffW';
  1317. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; cdecl; external KernelDLL name 'CharLowerBuffW';
  1318. procedure WinCEWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  1319. var
  1320. i: integer;
  1321. begin
  1322. if len = 0 then
  1323. dest:=''
  1324. else
  1325. begin
  1326. for i:=1 to 2 do begin
  1327. setlength(dest, len);
  1328. len:=WideCharToMultiByte(CP_ACP, 0, source, len, @dest[1], len, nil, nil);
  1329. if len > 0 then
  1330. break;
  1331. len:=WideCharToMultiByte(CP_ACP, 0, source, len, nil, 0, nil, nil);
  1332. end;
  1333. setlength(dest, len);
  1334. end;
  1335. end;
  1336. procedure WinCEAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  1337. var
  1338. i: integer;
  1339. begin
  1340. if len = 0 then
  1341. dest:=''
  1342. else
  1343. begin
  1344. for i:=1 to 2 do begin
  1345. setlength(dest, len);
  1346. len:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], len);
  1347. if len > 0 then
  1348. break;
  1349. len:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0);
  1350. end;
  1351. setlength(dest, len);
  1352. end;
  1353. end;
  1354. function WinCEWideUpper(const s : WideString) : WideString;
  1355. begin
  1356. result:=s;
  1357. UniqueString(result);
  1358. if length(result)>0 then
  1359. CharUpperBuff(LPWSTR(result),length(result));
  1360. end;
  1361. function WinCEWideLower(const s : WideString) : WideString;
  1362. begin
  1363. result:=s;
  1364. UniqueString(result);
  1365. if length(result)>0 then
  1366. CharLowerBuff(LPWSTR(result),length(result));
  1367. end;
  1368. { Currently widestrings are ref-counted on wince.
  1369. Unicode helpers are just wrappers over widestring helpers. }
  1370. procedure WinCEUnicode2AnsiMove(source:punicodechar;var dest:ansistring;len:SizeInt);
  1371. begin
  1372. WinCEWide2AnsiMove(source, dest, len);
  1373. end;
  1374. procedure WinCEAnsi2UnicodeMove(source:pchar;var dest:UnicodeString;len:SizeInt);
  1375. begin
  1376. WinCEAnsi2WideMove(source, PWideString(@dest)^, len);
  1377. end;
  1378. function WinCEUnicodeUpper(const s : UnicodeString) : UnicodeString;
  1379. begin
  1380. Result:=WinCEWideUpper(s);
  1381. end;
  1382. function WinCEUnicodeLower(const s : UnicodeString) : UnicodeString;
  1383. begin
  1384. Result:=WinCEWideLower(s);
  1385. end;
  1386. { there is a similiar procedure in sysutils which inits the fields which
  1387. are only relevant for the sysutils units }
  1388. procedure InitWinCEWidestrings;
  1389. begin
  1390. widestringmanager.Wide2AnsiMoveProc:=@WinCEWide2AnsiMove;
  1391. widestringmanager.Ansi2WideMoveProc:=@WinCEAnsi2WideMove;
  1392. widestringmanager.UpperWideStringProc:=@WinCEWideUpper;
  1393. widestringmanager.LowerWideStringProc:=@WinCEWideLower;
  1394. {$ifndef VER2_2}
  1395. { Unicode }
  1396. widestringmanager.Unicode2AnsiMoveProc:=@WinCEUnicode2AnsiMove;
  1397. widestringmanager.Ansi2UnicodeMoveProc:=@WinCEAnsi2UnicodeMove;
  1398. widestringmanager.UpperUnicodeStringProc:=@WinCEUnicodeUpper;
  1399. widestringmanager.LowerUnicodeStringProc:=@WinCEUnicodeLower;
  1400. {$endif VER2_2}
  1401. end;
  1402. {$IFDEF HAS_MEMORYMANAGER}
  1403. {****************************************************************************
  1404. Memory manager
  1405. ****************************************************************************}
  1406. function malloc(Size : ptruint) : Pointer; cdecl; external 'coredll';
  1407. procedure free(P : pointer); cdecl; external 'coredll';
  1408. function realloc(P : Pointer; Size : ptruint) : pointer; cdecl; external 'coredll';
  1409. function _msize(P : pointer): ptruint; cdecl; external 'coredll';
  1410. function SysGetMem (Size : ptruint) : Pointer;
  1411. begin
  1412. Result:=malloc(Size);
  1413. end;
  1414. Function SysFreeMem (P : pointer) : ptruint;
  1415. begin
  1416. free(P);
  1417. Result:=0;
  1418. end;
  1419. Function SysFreeMemSize(p:pointer;Size:ptruint):ptruint;
  1420. begin
  1421. Result:=0;
  1422. if (size > 0) and (p <> nil) then
  1423. Result:=SysFreeMem(P);
  1424. end;
  1425. Function SysAllocMem(Size : ptruint) : Pointer;
  1426. begin
  1427. Result:=SysGetMem(Size);
  1428. if Result <> nil then
  1429. FillChar(Result^, Size, 0);
  1430. end;
  1431. Function SysReAllocMem (var p:pointer;Size:ptruint):Pointer;
  1432. begin
  1433. Result:=realloc(p, Size);
  1434. p:=Result;
  1435. end;
  1436. function SysTryResizeMem(var p:pointer;size : ptruint):boolean;
  1437. var
  1438. res: pointer;
  1439. begin
  1440. res:=realloc(p, Size);
  1441. Result:=(res <> nil) or (Size = 0);
  1442. if Result then
  1443. p:=res;
  1444. end;
  1445. function SysMemSize(P : pointer): ptruint;
  1446. begin
  1447. Result:=_msize(P);
  1448. end;
  1449. function SysGetHeapStatus:THeapStatus;
  1450. begin
  1451. fillchar(Result,sizeof(Result),0);
  1452. end;
  1453. function SysGetFPCHeapStatus:TFPCHeapStatus;
  1454. begin
  1455. fillchar(Result,sizeof(Result),0);
  1456. end;
  1457. {$ENDIF HAS_MEMORYMANAGER}
  1458. {****************************************************************************
  1459. Error Message writing using messageboxes
  1460. ****************************************************************************}
  1461. const
  1462. ErrorBufferLength = 1024;
  1463. var
  1464. ErrorBuf : array[0..ErrorBufferLength] of char;
  1465. ErrorBufW : array[0..ErrorBufferLength] of widechar;
  1466. ErrorLen : longint;
  1467. Function ErrorWrite(Var F: TextRec): Integer;
  1468. {
  1469. An error message should always end with #13#10#13#10
  1470. }
  1471. var
  1472. i : longint;
  1473. Begin
  1474. while F.BufPos>0 do
  1475. begin
  1476. begin
  1477. if F.BufPos+ErrorLen>ErrorBufferLength then
  1478. i:=ErrorBufferLength-ErrorLen
  1479. else
  1480. i:=F.BufPos;
  1481. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  1482. inc(ErrorLen,i);
  1483. ErrorBuf[ErrorLen]:=#0;
  1484. end;
  1485. if ErrorLen=ErrorBufferLength then
  1486. begin
  1487. AnsiToWideBuf(@ErrorBuf, -1, @ErrorBufW, SizeOf(ErrorBufW));
  1488. MessageBox(0,@ErrorBufW,'Error',$10010); { MB_SETFOREGROUND or ICON_ERROR }
  1489. ErrorLen:=0;
  1490. end;
  1491. Dec(F.BufPos,i);
  1492. end;
  1493. ErrorWrite:=0;
  1494. End;
  1495. Function ErrorClose(Var F: TextRec): Integer;
  1496. begin
  1497. if ErrorLen>0 then
  1498. begin
  1499. AnsiToWideBuf(@ErrorBuf, -1, @ErrorBufW, SizeOf(ErrorBufW));
  1500. MessageBox(0,@ErrorBufW,'Error',$10010); { MB_SETFOREGROUND or ICON_ERROR }
  1501. ErrorLen:=0;
  1502. end;
  1503. ErrorLen:=0;
  1504. ErrorClose:=0;
  1505. end;
  1506. Function ErrorOpen(Var F: TextRec): Integer;
  1507. Begin
  1508. TextRec(F).InOutFunc:=@ErrorWrite;
  1509. TextRec(F).FlushFunc:=@ErrorWrite;
  1510. TextRec(F).CloseFunc:=@ErrorClose;
  1511. ErrorLen:=0;
  1512. ErrorOpen:=0;
  1513. End;
  1514. procedure AssignError(Var T: Text);
  1515. begin
  1516. Assign(T,'');
  1517. TextRec(T).OpenFunc:=@ErrorOpen;
  1518. Rewrite(T);
  1519. end;
  1520. function _getstdfilex(fd: integer): pointer; cdecl; external 'coredll';
  1521. function _fileno(fd: pointer): THandle; cdecl; external 'coredll';
  1522. procedure SysInitStdIO;
  1523. begin
  1524. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  1525. displayed in and messagebox }
  1526. if not IsConsole then
  1527. begin
  1528. AssignError(stderr);
  1529. AssignError(stdout);
  1530. Assign(Output,'');
  1531. Assign(Input,'');
  1532. Assign(ErrOutput,'');
  1533. end
  1534. else
  1535. begin
  1536. StdInputHandle:=_fileno(_getstdfilex(0));
  1537. StdOutputHandle:=_fileno(_getstdfilex(1));
  1538. StdErrorHandle:=_fileno(_getstdfilex(2));
  1539. OpenStdIO(Input,fmInput,StdInputHandle);
  1540. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1541. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  1542. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1543. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1544. end;
  1545. end;
  1546. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  1547. var
  1548. ProcessID: SizeUInt;
  1549. function GetProcessID: SizeUInt;
  1550. begin
  1551. GetProcessID := ProcessID;
  1552. end;
  1553. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  1554. begin
  1555. result := stklen;
  1556. end;
  1557. procedure SysCleanup;
  1558. var
  1559. i: integer;
  1560. begin
  1561. if FCmdLine = nil then
  1562. exit;
  1563. SysFreeMem(FCmdLine);
  1564. for i:=0 to Fargc do
  1565. sysfreemem(Fargv[i]);
  1566. sysfreemem(Fargv);
  1567. end;
  1568. initialization
  1569. SysResetFPU;
  1570. if not(IsLibrary) then
  1571. SysInitFPU;
  1572. StackLength := CheckInitialStkLen(InitialStkLen);
  1573. StackBottom := StackTop - StackLength;
  1574. { some misc stuff }
  1575. hprevinst:=0;
  1576. if not IsLibrary then
  1577. SysInstance:=GetModuleHandle(nil);
  1578. MainInstance:=SysInstance;
  1579. {$IFNDEF HAS_MEMORYMANAGER}
  1580. { Setup Heap }
  1581. InitHeap;
  1582. {$ENDIF HAS_MEMORYMANAGER}
  1583. SysInitExceptions;
  1584. if not IsLibrary then
  1585. begin
  1586. SysInitStdIO;
  1587. end;
  1588. { Reset IO Error }
  1589. InOutRes:=0;
  1590. ProcessID := GetCurrentProcessID;
  1591. { threading }
  1592. InitSystemThreads;
  1593. { Reset internal error variable }
  1594. errno:=0;
  1595. initvariantmanager;
  1596. {$ifndef VER2_2}
  1597. initunicodestringmanager;
  1598. {$endif VER2_2}
  1599. InitWinCEWidestrings;
  1600. DispCallByIDProc:=@DoDispCallByIDError;
  1601. finalization
  1602. SysCleanup;
  1603. end.