syswin32.pp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl and Pavel Ozerski
  5. member of the Free Pascal development team.
  6. FPC Pascal system unit for the Win32 API.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit syswin32;
  14. interface
  15. {$ifdef i386}
  16. {$define Set_i386_Exception_handler}
  17. {$endif i386}
  18. { include system-independent routine headers }
  19. {$I systemh.inc}
  20. { include heap support headers }
  21. {$I heaph.inc}
  22. const
  23. { Default filehandles }
  24. UnusedHandle : longint = -1;
  25. StdInputHandle : longint = 0;
  26. StdOutputHandle : longint = 0;
  27. StdErrorHandle : longint = 0;
  28. FileNameCaseSensitive : boolean = true;
  29. type
  30. TStartupInfo=packed record
  31. cb : longint;
  32. lpReserved : Pointer;
  33. lpDesktop : Pointer;
  34. lpTitle : Pointer;
  35. dwX : longint;
  36. dwY : longint;
  37. dwXSize : longint;
  38. dwYSize : longint;
  39. dwXCountChars : longint;
  40. dwYCountChars : longint;
  41. dwFillAttribute : longint;
  42. dwFlags : longint;
  43. wShowWindow : Word;
  44. cbReserved2 : Word;
  45. lpReserved2 : Pointer;
  46. hStdInput : longint;
  47. hStdOutput : longint;
  48. hStdError : longint;
  49. end;
  50. var
  51. { C compatible arguments }
  52. argc : longint;
  53. argv : ppchar;
  54. { Win32 Info }
  55. startupinfo : tstartupinfo;
  56. hprevinst,
  57. HInstance,
  58. MainInstance,
  59. cmdshow : longint;
  60. IsLibrary,IsMultiThreaded,IsConsole : boolean;
  61. DLLreason,DLLparam:longint;
  62. Win32StackTop : Dword;
  63. { Thread count for DLL }
  64. const
  65. Thread_count : longint = 0;
  66. type
  67. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  68. TDLL_Entry_Hook = procedure (dllparam : longint);
  69. const
  70. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  71. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  72. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  73. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  74. implementation
  75. { include system independent routines }
  76. {$I system.inc}
  77. { some declarations for Win32 API calls }
  78. {$I win32.inc}
  79. CONST
  80. { These constants are used for conversion of error codes }
  81. { from win32 i/o errors to tp i/o errors }
  82. { errors 1 to 18 are the same as in Turbo Pascal }
  83. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING! }
  84. { The media is write protected. }
  85. ERROR_WRITE_PROTECT = 19;
  86. { The system cannot find the device specified. }
  87. ERROR_BAD_UNIT = 20;
  88. { The device is not ready. }
  89. ERROR_NOT_READY = 21;
  90. { The device does not recognize the command. }
  91. ERROR_BAD_COMMAND = 22;
  92. { Data error (cyclic redundancy check) }
  93. ERROR_CRC = 23;
  94. { The program issued a command but the }
  95. { command length is incorrect. }
  96. ERROR_BAD_LENGTH = 24;
  97. { The drive cannot locate a specific }
  98. { area or track on the disk. }
  99. ERROR_SEEK = 25;
  100. { The specified disk or diskette cannot be accessed. }
  101. ERROR_NOT_DOS_DISK = 26;
  102. { The drive cannot find the sector requested. }
  103. ERROR_SECTOR_NOT_FOUND = 27;
  104. { The printer is out of paper. }
  105. ERROR_OUT_OF_PAPER = 28;
  106. { The system cannot write to the specified device. }
  107. ERROR_WRITE_FAULT = 29;
  108. { The system cannot read from the specified device. }
  109. ERROR_READ_FAULT = 30;
  110. { A device attached to the system is not functioning.}
  111. ERROR_GEN_FAILURE = 31;
  112. { The process cannot access the file because }
  113. { it is being used by another process. }
  114. ERROR_SHARING_VIOLATION = 32;
  115. var
  116. errno : longint;
  117. {$ASMMODE ATT}
  118. { misc. functions }
  119. function GetLastError : DWORD;
  120. external 'kernel32' name 'GetLastError';
  121. { time and date functions }
  122. function GetTickCount : longint;
  123. external 'kernel32' name 'GetTickCount';
  124. { process functions }
  125. procedure ExitProcess(uExitCode : UINT);
  126. external 'kernel32' name 'ExitProcess';
  127. Procedure Errno2InOutRes;
  128. Begin
  129. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING }
  130. if (errno >= ERROR_WRITE_PROTECT) and (errno <= ERROR_GEN_FAILURE) THEN
  131. BEGIN
  132. { This is the offset to the Win32 to add to directly map }
  133. { to the DOS/TP compatible error codes when in this range }
  134. InOutRes := word(errno)+131;
  135. END
  136. else
  137. { This case is special }
  138. if errno=ERROR_SHARING_VIOLATION THEN
  139. BEGIN
  140. InOutRes :=5;
  141. END
  142. else
  143. { other error codes can directly be mapped }
  144. InOutRes := Word(errno);
  145. errno:=0;
  146. end;
  147. {$ifdef dummy}
  148. procedure int_stackcheck(stack_size:longint);[public,alias: 'STACKCHECK'];
  149. {
  150. called when trying to get local stack if the compiler directive $S
  151. is set this function must preserve esi !!!! because esi is set by
  152. the calling proc for methods it must preserve all registers !!
  153. With a 2048 byte safe area used to write to StdIo without crossing
  154. the stack boundary
  155. }
  156. begin
  157. asm
  158. pushl %eax
  159. pushl %ebx
  160. movl stack_size,%ebx
  161. addl $2048,%ebx
  162. movl %esp,%eax
  163. subl %ebx,%eax
  164. movl stacklimit,%ebx
  165. cmpl %eax,%ebx
  166. jae .L__short_on_stack
  167. popl %ebx
  168. popl %eax
  169. leave
  170. ret $4
  171. .L__short_on_stack:
  172. { can be usefull for error recovery !! }
  173. popl %ebx
  174. popl %eax
  175. end['EAX','EBX'];
  176. HandleError(202);
  177. end;
  178. {$endif dummy}
  179. procedure halt(errnum : byte);
  180. begin
  181. ExitCode:=errnum;
  182. do_exit;
  183. system_exit;
  184. end;
  185. function paramcount : longint;
  186. begin
  187. paramcount := argc - 1;
  188. end;
  189. { module functions }
  190. function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
  191. external 'kernel32' name 'GetModuleFileNameA';
  192. function GetModuleHandle(p : pointer) : longint;
  193. external 'kernel32' name 'GetModuleHandleA';
  194. function GetCommandFile:pchar;forward;
  195. function paramstr(l : longint) : string;
  196. begin
  197. if (l>=0) and (l<argc) then
  198. paramstr:=strpas(argv[l])
  199. else
  200. paramstr:='';
  201. end;
  202. procedure randomize;
  203. begin
  204. randseed:=GetTickCount;
  205. end;
  206. {*****************************************************************************
  207. Heap Management
  208. *****************************************************************************}
  209. { memory functions }
  210. function GlobalAlloc(mode,size:longint):longint;
  211. external 'kernel32' name 'GlobalAlloc';
  212. function GlobalLock(handle:longint):pointer;
  213. external 'kernel32' name 'GlobalLock';
  214. {$ifdef SYSTEMDEBUG}
  215. function GlobalSize(h:longint):longint;
  216. external 'kernel32' name 'GlobalSize';
  217. {$endif}
  218. var
  219. heap : longint;external name 'HEAP';
  220. intern_heapsize : longint;external name 'HEAPSIZE';
  221. function getheapstart:pointer;assembler;
  222. asm
  223. leal HEAP,%eax
  224. end ['EAX'];
  225. function getheapsize:longint;assembler;
  226. asm
  227. movl intern_HEAPSIZE,%eax
  228. end ['EAX'];
  229. function Sbrk(size : longint):longint;
  230. var
  231. h,l : longint;
  232. begin
  233. h:=GlobalAlloc(258,size);
  234. l:=longint(GlobalLock(h));
  235. if l=0 then
  236. l:=-1;
  237. {$ifdef SYSTEMDEBUG}
  238. Writeln('new heap part at $',hexstr(l,8), ' size = ',GlobalSize(h));
  239. {$endif}
  240. sbrk:=l;
  241. end;
  242. { include standard heap management }
  243. {$I heap.inc}
  244. {*****************************************************************************
  245. Low Level File Routines
  246. *****************************************************************************}
  247. function WriteFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  248. overlap:pointer):longint;
  249. external 'kernel32' name 'WriteFile';
  250. function ReadFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  251. overlap:pointer):longint;
  252. external 'kernel32' name 'ReadFile';
  253. function CloseHandle(h : longint) : longint;
  254. external 'kernel32' name 'CloseHandle';
  255. function DeleteFile(p : pchar) : longint;
  256. external 'kernel32' name 'DeleteFileA';
  257. function MoveFile(old,_new : pchar) : longint;
  258. external 'kernel32' name 'MoveFileA';
  259. function SetFilePointer(l1,l2 : longint;l3 : pointer;l4 : longint) : longint;
  260. external 'kernel32' name 'SetFilePointer';
  261. function GetFileSize(h:longint;p:pointer) : longint;
  262. external 'kernel32' name 'GetFileSize';
  263. function CreateFile(name : pointer;access,sharing : longint;
  264. security : pointer;how,attr,template : longint) : longint;
  265. external 'kernel32' name 'CreateFileA';
  266. function SetEndOfFile(h : longint) : longbool;
  267. external 'kernel32' name 'SetEndOfFile';
  268. function GetFileType(Handle:DWORD):DWord;
  269. external 'kernel32' name 'GetFileType';
  270. procedure AllowSlash(p:pchar);
  271. var
  272. i : longint;
  273. begin
  274. { allow slash as backslash }
  275. for i:=0 to strlen(p) do
  276. if p[i]='/' then p[i]:='\';
  277. end;
  278. procedure do_close(h : longint);
  279. begin
  280. if Handle<=4 then
  281. exit;
  282. CloseHandle(h);
  283. end;
  284. procedure do_erase(p : pchar);
  285. begin
  286. AllowSlash(p);
  287. if DeleteFile(p)=0 then
  288. Begin
  289. errno:=GetLastError;
  290. Errno2InoutRes;
  291. end;
  292. end;
  293. procedure do_rename(p1,p2 : pchar);
  294. begin
  295. AllowSlash(p1);
  296. AllowSlash(p2);
  297. if MoveFile(p1,p2)=0 then
  298. Begin
  299. errno:=GetLastError;
  300. Errno2InoutRes;
  301. end;
  302. end;
  303. function do_write(h,addr,len : longint) : longint;
  304. var
  305. size:longint;
  306. begin
  307. if writefile(h,pointer(addr),len,size,nil)=0 then
  308. Begin
  309. errno:=GetLastError;
  310. Errno2InoutRes;
  311. end;
  312. do_write:=size;
  313. end;
  314. function do_read(h,addr,len : longint) : longint;
  315. var
  316. _result:longint;
  317. begin
  318. if readfile(h,pointer(addr),len,_result,nil)=0 then
  319. Begin
  320. errno:=GetLastError;
  321. Errno2InoutRes;
  322. end;
  323. do_read:=_result;
  324. end;
  325. function do_filepos(handle : longint) : longint;
  326. var
  327. l:longint;
  328. begin
  329. l:=SetFilePointer(handle,0,nil,FILE_CURRENT);
  330. if l=-1 then
  331. begin
  332. l:=0;
  333. errno:=GetLastError;
  334. Errno2InoutRes;
  335. end;
  336. do_filepos:=l;
  337. end;
  338. procedure do_seek(handle,pos : longint);
  339. begin
  340. if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
  341. Begin
  342. errno:=GetLastError;
  343. Errno2InoutRes;
  344. end;
  345. end;
  346. function do_seekend(handle:longint):longint;
  347. begin
  348. do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
  349. if do_seekend=-1 then
  350. begin
  351. errno:=GetLastError;
  352. Errno2InoutRes;
  353. end;
  354. end;
  355. function do_filesize(handle : longint) : longint;
  356. var
  357. aktfilepos : longint;
  358. begin
  359. aktfilepos:=do_filepos(handle);
  360. do_filesize:=do_seekend(handle);
  361. do_seek(handle,aktfilepos);
  362. end;
  363. procedure do_truncate (handle,pos:longint);
  364. begin
  365. do_seek(handle,pos);
  366. if not(SetEndOfFile(handle)) then
  367. begin
  368. errno:=GetLastError;
  369. Errno2InoutRes;
  370. end;
  371. end;
  372. procedure do_open(var f;p : pchar;flags:longint);
  373. {
  374. filerec and textrec have both handle and mode as the first items so
  375. they could use the same routine for opening/creating.
  376. when (flags and $100) the file will be append
  377. when (flags and $1000) the file will be truncate/rewritten
  378. when (flags and $10000) there is no check for close (needed for textfiles)
  379. }
  380. Const
  381. file_Share_Read = $00000001;
  382. file_Share_Write = $00000002;
  383. fmShareCompat = $00000000;
  384. fmShareExclusive = $10;
  385. fmShareDenyWrite = $20;
  386. fmShareDenyRead = $30;
  387. fmShareDenyNone = $40;
  388. Var
  389. shflags,
  390. oflags,cd : longint;
  391. begin
  392. AllowSlash(p);
  393. { close first if opened }
  394. if ((flags and $10000)=0) then
  395. begin
  396. case filerec(f).mode of
  397. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  398. fmclosed : ;
  399. else
  400. begin
  401. {not assigned}
  402. inoutres:=102;
  403. exit;
  404. end;
  405. end;
  406. end;
  407. { reset file handle }
  408. filerec(f).handle:=UnusedHandle;
  409. { convert filesharing }
  410. shflags:=0;
  411. if ((filemode and fmshareExclusive) = fmshareExclusive) then
  412. { no sharing }
  413. else
  414. if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
  415. shflags := file_Share_Read
  416. else
  417. if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
  418. shflags := file_Share_Write
  419. else
  420. if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
  421. shflags := file_Share_Read + file_Share_Write;
  422. { convert filemode to filerec modes }
  423. case (flags and 3) of
  424. 0 : begin
  425. filerec(f).mode:=fminput;
  426. oflags:=GENERIC_READ;
  427. end;
  428. 1 : begin
  429. filerec(f).mode:=fmoutput;
  430. oflags:=GENERIC_WRITE;
  431. end;
  432. 2 : begin
  433. filerec(f).mode:=fminout;
  434. oflags:=GENERIC_WRITE or GENERIC_READ;
  435. end;
  436. end;
  437. { standard is opening and existing file }
  438. cd:=OPEN_EXISTING;
  439. { create it ? }
  440. if (flags and $1000)<>0 then
  441. cd:=CREATE_ALWAYS
  442. { or append ? }
  443. else
  444. if (flags and $100)<>0 then
  445. cd:=OPEN_ALWAYS;
  446. { empty name is special }
  447. if p[0]=#0 then
  448. begin
  449. case filerec(f).mode of
  450. fminput : filerec(f).handle:=StdInputHandle;
  451. fmappend,
  452. fmoutput : begin
  453. filerec(f).handle:=StdOutputHandle;
  454. filerec(f).mode:=fmoutput; {fool fmappend}
  455. end;
  456. end;
  457. exit;
  458. end;
  459. filerec(f).handle:=CreateFile(p,oflags,shflags,nil,cd,FILE_ATTRIBUTE_NORMAL,0);
  460. { append mode }
  461. if (flags and $100)<>0 then
  462. begin
  463. do_seekend(filerec(f).handle);
  464. filerec(f).mode:=fmoutput; {fool fmappend}
  465. end;
  466. { get errors }
  467. { handle -1 is returned sometimes !! (PM) }
  468. if (filerec(f).handle=0) or (filerec(f).handle=-1) then
  469. begin
  470. errno:=GetLastError;
  471. Errno2InoutRes;
  472. end;
  473. end;
  474. function do_isdevice(handle:longint):boolean;
  475. begin
  476. do_isdevice:=(getfiletype(handle)=2);
  477. end;
  478. {*****************************************************************************
  479. UnTyped File Handling
  480. *****************************************************************************}
  481. {$i file.inc}
  482. {*****************************************************************************
  483. Typed File Handling
  484. *****************************************************************************}
  485. {$i typefile.inc}
  486. {*****************************************************************************
  487. Text File Handling
  488. *****************************************************************************}
  489. {$DEFINE EOF_CTRLZ}
  490. {$i text.inc}
  491. {*****************************************************************************
  492. Directory Handling
  493. *****************************************************************************}
  494. function CreateDirectory(name : pointer;sec : pointer) : longint;
  495. external 'kernel32' name 'CreateDirectoryA';
  496. function RemoveDirectory(name:pointer):longint;
  497. external 'kernel32' name 'RemoveDirectoryA';
  498. function SetCurrentDirectory(name : pointer) : longint;
  499. external 'kernel32' name 'SetCurrentDirectoryA';
  500. function GetCurrentDirectory(bufsize : longint;name : pchar) : longint;
  501. external 'kernel32' name 'GetCurrentDirectoryA';
  502. type
  503. TDirFnType=function(name:pointer):word;
  504. procedure dirfn(afunc : TDirFnType;const s:string);
  505. var
  506. buffer : array[0..255] of char;
  507. begin
  508. move(s[1],buffer,length(s));
  509. buffer[length(s)]:=#0;
  510. AllowSlash(pchar(@buffer));
  511. if aFunc(@buffer)=0 then
  512. begin
  513. errno:=GetLastError;
  514. Errno2InoutRes;
  515. end;
  516. end;
  517. function CreateDirectoryTrunc(name:pointer):word;
  518. begin
  519. CreateDirectoryTrunc:=CreateDirectory(name,nil);
  520. end;
  521. procedure mkdir(const s:string);[IOCHECK];
  522. begin
  523. If InOutRes <> 0 then exit;
  524. dirfn(TDirFnType(@CreateDirectoryTrunc),s);
  525. end;
  526. procedure rmdir(const s:string);[IOCHECK];
  527. begin
  528. If InOutRes <> 0 then exit;
  529. dirfn(TDirFnType(@RemoveDirectory),s);
  530. end;
  531. procedure chdir(const s:string);[IOCHECK];
  532. begin
  533. If InOutRes <> 0 then exit;
  534. dirfn(TDirFnType(@SetCurrentDirectory),s);
  535. end;
  536. procedure getdir(drivenr:byte;var dir:shortstring);
  537. const
  538. Drive:array[0..3]of char=(#0,':',#0,#0);
  539. var
  540. defaultdrive:boolean;
  541. DirBuf,SaveBuf:array[0..259] of Char;
  542. begin
  543. defaultdrive:=drivenr=0;
  544. if not defaultdrive then
  545. begin
  546. byte(Drive[0]):=Drivenr+64;
  547. GetCurrentDirectory(SizeOf(SaveBuf),SaveBuf);
  548. SetCurrentDirectory(@Drive);
  549. end;
  550. GetCurrentDirectory(SizeOf(DirBuf),DirBuf);
  551. if not defaultdrive then
  552. SetCurrentDirectory(@SaveBuf);
  553. dir:=strpas(DirBuf);
  554. if not FileNameCaseSensitive then
  555. dir:=upcase(dir);
  556. end;
  557. {*****************************************************************************
  558. SystemUnit Initialization
  559. *****************************************************************************}
  560. { Startup }
  561. procedure GetStartupInfo(p : pointer);
  562. external 'kernel32' name 'GetStartupInfoA';
  563. function GetStdHandle(nStdHandle:DWORD):THANDLE;
  564. external 'kernel32' name 'GetStdHandle';
  565. { command line/enviroment functions }
  566. function GetCommandLine : pchar;
  567. external 'kernel32' name 'GetCommandLineA';
  568. var
  569. ModuleName : array[0..255] of char;
  570. function GetCommandFile:pchar;
  571. begin
  572. GetModuleFileName(0,@ModuleName,255);
  573. GetCommandFile:=@ModuleName;
  574. end;
  575. procedure setup_arguments;
  576. var
  577. arglen,
  578. count : longint;
  579. argstart,
  580. pc : pchar;
  581. quote : set of char;
  582. argsbuf : array[0..127] of pchar;
  583. begin
  584. { create commandline, it starts with the executed filename which is argv[0] }
  585. { Win32 passes the command NOT via the args, but via getmodulefilename}
  586. count:=0;
  587. pc:=getcommandfile;
  588. Arglen:=0;
  589. repeat
  590. Inc(Arglen);
  591. until (pc[Arglen]=#0);
  592. getmem(argsbuf[count],arglen+1);
  593. move(pc^,argsbuf[count]^,arglen);
  594. { Now skip the first one }
  595. pc:=GetCommandLine;
  596. repeat
  597. { skip leading spaces }
  598. while pc^ in [' ',#9,#13] do
  599. inc(pc);
  600. case pc^ of
  601. #0 : break;
  602. '"' : begin
  603. quote:=['"'];
  604. inc(pc);
  605. end;
  606. '''' : begin
  607. quote:=[''''];
  608. inc(pc);
  609. end;
  610. else
  611. quote:=[' ',#9,#13];
  612. end;
  613. { scan until the end of the argument }
  614. argstart:=pc;
  615. while (pc^<>#0) and not(pc^ in quote) do
  616. inc(pc);
  617. { Don't copy the first one, it is already there.}
  618. If Count<>0 then
  619. begin
  620. { reserve some memory }
  621. arglen:=pc-argstart;
  622. getmem(argsbuf[count],arglen+1);
  623. move(argstart^,argsbuf[count]^,arglen);
  624. argsbuf[count][arglen]:=#0;
  625. end;
  626. { skip quote }
  627. if pc^ in quote then
  628. inc(pc);
  629. inc(count);
  630. until false;
  631. { create argc }
  632. argc:=count;
  633. { create an nil entry }
  634. argsbuf[count]:=nil;
  635. inc(count);
  636. { create the argv }
  637. getmem(argv,count shl 2);
  638. move(argsbuf,argv^,count shl 2);
  639. { Setup cmdline variable }
  640. cmdline:=GetCommandLine;
  641. end;
  642. {*****************************************************************************
  643. System Dependent Exit code
  644. *****************************************************************************}
  645. Procedure system_exit;
  646. begin
  647. if not IsConsole then
  648. begin
  649. Close(stderr);
  650. Close(stdout);
  651. { what about Input and Output ?? PM }
  652. end;
  653. ExitProcess(ExitCode);
  654. end;
  655. {$ifdef dummy}
  656. Function SetUpStack : longint;
  657. { This routine does the following : }
  658. { returns the value of the initial SP - __stklen }
  659. begin
  660. asm
  661. pushl %ebx
  662. pushl %eax
  663. movl __stklen,%ebx
  664. movl %esp,%eax
  665. subl %ebx,%eax
  666. movl %eax,__RESULT
  667. popl %eax
  668. popl %ebx
  669. end;
  670. end;
  671. {$endif}
  672. procedure install_exception_handlers;forward;
  673. procedure PascalMain;external name 'PASCALMAIN';
  674. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  675. var
  676. { value of the stack segment
  677. to check if the call stack can be written on exceptions }
  678. _SS : longint;
  679. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  680. begin
  681. IsLibrary:=false;
  682. { install the handlers for exe only ?
  683. or should we install them for DLL also ? (PM) }
  684. install_exception_handlers;
  685. { This strange construction is needed to solve the _SS problem
  686. with a smartlinked syswin32 (PFV) }
  687. asm
  688. pushl %ebp
  689. xorl %ebp,%ebp
  690. movl %esp,%eax
  691. movl %eax,Win32StackTop
  692. movw %ss,%bp
  693. movl %ebp,_SS
  694. xorl %ebp,%ebp
  695. call PASCALMAIN
  696. popl %ebp
  697. end;
  698. { if we pass here there was no error ! }
  699. system_exit;
  700. end;
  701. Const
  702. { DllEntryPoint }
  703. DLL_PROCESS_ATTACH = 1;
  704. DLL_THREAD_ATTACH = 2;
  705. DLL_PROCESS_DETACH = 0;
  706. DLL_THREAD_DETACH = 3;
  707. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  708. var
  709. res : longbool;
  710. begin
  711. IsLibrary:=true;
  712. case DLLreason of
  713. DLL_PROCESS_ATTACH :
  714. begin
  715. asm
  716. movl %esp,%eax
  717. movl %eax,Win32StackTop
  718. xorl %edi,%edi
  719. movw %ss,%di
  720. movl %edi,_SS
  721. end;
  722. if assigned(Dll_Process_Attach_Hook) then
  723. begin
  724. res:=Dll_Process_Attach_Hook(DllParam);
  725. if not res then
  726. begin
  727. Dll_entry:=false;
  728. exit;
  729. end;
  730. end;
  731. PASCALMAIN;
  732. Dll_entry:=true;
  733. end;
  734. DLL_THREAD_ATTACH :
  735. begin
  736. inc(Thread_count);
  737. if assigned(Dll_Thread_Attach_Hook) then
  738. Dll_Thread_Attach_Hook(DllParam);
  739. Dll_entry:=true; { return value is ignored }
  740. end;
  741. DLL_THREAD_DETACH :
  742. begin
  743. dec(Thread_count);
  744. if assigned(Dll_Thread_Detach_Hook) then
  745. Dll_Thread_Detach_Hook(DllParam);
  746. Dll_entry:=true; { return value is ignored }
  747. end;
  748. DLL_PROCESS_DETACH :
  749. begin
  750. inc(Thread_count);
  751. Dll_entry:=true; { return value is ignored }
  752. FPC_DO_EXIT;
  753. if assigned(Dll_Process_Detach_Hook) then
  754. Dll_Process_Detach_Hook(DllParam);
  755. end;
  756. end;
  757. end;
  758. {$ifdef Set_i386_Exception_handler}
  759. const
  760. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  761. EXCEPTION_ACCESS_VIOLATION = $c0000005;
  762. EXCEPTION_BREAKPOINT = $80000003;
  763. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  764. EXCEPTION_SINGLE_STEP = $80000004;
  765. EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
  766. EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
  767. EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
  768. EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  769. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
  770. EXCEPTION_FLT_OVERFLOW = $c0000091;
  771. EXCEPTION_FLT_STACK_CHECK = $c0000092;
  772. EXCEPTION_FLT_UNDERFLOW = $c0000093;
  773. EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
  774. EXCEPTION_INT_OVERFLOW = $c0000095;
  775. EXCEPTION_INVALID_HANDLE = $c0000008;
  776. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  777. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  778. EXCEPTION_NONCONTINUABLE = $1;
  779. EXCEPTION_STACK_OVERFLOW = $c00000fd;
  780. EXCEPTION_INVALID_DISPOSITION = $c0000026;
  781. ExceptionContinueExecution = 0;
  782. ExceptionContinueSearch = 1;
  783. type
  784. FLOATING_SAVE_AREA = record
  785. ControlWord : DWORD;
  786. StatusWord : DWORD;
  787. TagWord : DWORD;
  788. ErrorOffset : DWORD;
  789. ErrorSelector : DWORD;
  790. DataOffset : DWORD;
  791. DataSelector : DWORD;
  792. RegisterArea : array[0..79] of BYTE;
  793. Cr0NpxState : DWORD;
  794. end;
  795. _FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
  796. TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
  797. PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
  798. CONTEXT = record
  799. ContextFlags : DWORD;
  800. Dr0 : DWORD;
  801. Dr1 : DWORD;
  802. Dr2 : DWORD;
  803. Dr3 : DWORD;
  804. Dr6 : DWORD;
  805. Dr7 : DWORD;
  806. FloatSave : FLOATING_SAVE_AREA;
  807. SegGs : DWORD;
  808. SegFs : DWORD;
  809. SegEs : DWORD;
  810. SegDs : DWORD;
  811. Edi : DWORD;
  812. Esi : DWORD;
  813. Ebx : DWORD;
  814. Edx : DWORD;
  815. Ecx : DWORD;
  816. Eax : DWORD;
  817. Ebp : DWORD;
  818. Eip : DWORD;
  819. SegCs : DWORD;
  820. EFlags : DWORD;
  821. Esp : DWORD;
  822. SegSs : DWORD;
  823. end;
  824. LPCONTEXT = ^CONTEXT;
  825. _CONTEXT = CONTEXT;
  826. TCONTEXT = CONTEXT;
  827. PCONTEXT = ^CONTEXT;
  828. type pexception_record = ^exception_record;
  829. EXCEPTION_RECORD = record
  830. ExceptionCode : longint;
  831. ExceptionFlags : longint;
  832. ExceptionRecord : pexception_record;
  833. ExceptionAddress : pointer;
  834. NumberParameters : longint;
  835. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
  836. end;
  837. PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
  838. EXCEPTION_POINTERS = record
  839. ExceptionRecord : PEXCEPTION_RECORD ;
  840. ContextRecord : PCONTEXT ;
  841. end;
  842. { type of functions that should be used for exception handling }
  843. LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;
  844. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
  845. : LPTOP_LEVEL_EXCEPTION_FILTER;
  846. external 'kernel32' name 'SetUnhandledExceptionFilter';
  847. function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
  848. var frame : longint;
  849. begin
  850. { default : unhandled !}
  851. if excep^.ContextRecord^.SegSs=_SS then
  852. frame:=excep^.ContextRecord^.Ebp
  853. else
  854. frame:=0;
  855. syswin32_i386_exception_handler:=ExceptionContinueSearch;
  856. case excep^.ExceptionRecord^.ExceptionCode of
  857. EXCEPTION_ACCESS_VIOLATION :
  858. HandleErrorFrame(216,frame);
  859. { EXCEPTION_BREAKPOINT = $80000003;
  860. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  861. EXCEPTION_SINGLE_STEP = $80000004; }
  862. EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
  863. HandleErrorFrame(201,frame);
  864. { EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; }
  865. EXCEPTION_FLT_DIVIDE_BY_ZERO :
  866. HandleErrorFrame(200,frame);
  867. {EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  868. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;}
  869. EXCEPTION_FLT_OVERFLOW :
  870. HandleErrorFrame(205,frame);
  871. EXCEPTION_FLT_STACK_CHECK :
  872. HandleErrorFrame(207,frame);
  873. { EXCEPTION_FLT_UNDERFLOW :
  874. HandleErrorFrame(206,frame); should be accepted as zero !! }
  875. EXCEPTION_INT_DIVIDE_BY_ZERO :
  876. HandleErrorFrame(200,frame);
  877. EXCEPTION_INT_OVERFLOW :
  878. HandleErrorFrame(215,frame);
  879. {EXCEPTION_INVALID_HANDLE = $c0000008;
  880. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  881. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  882. EXCEPTION_NONCONTINUABLE = $1;}
  883. EXCEPTION_STACK_OVERFLOW :
  884. HandleErrorFrame(202,frame);
  885. {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
  886. end;
  887. end;
  888. procedure install_exception_handlers;
  889. begin
  890. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  891. end;
  892. {$else not i386 (Processor specific !!)}
  893. procedure install_exception_handlers;
  894. begin
  895. end;
  896. {$endif Set_i386_Exception_handler}
  897. {****************************************************************************
  898. Error Message writing using messageboxes
  899. ****************************************************************************}
  900. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  901. external 'user32' name 'MessageBoxA';
  902. const
  903. ErrorBufferLength = 1024;
  904. var
  905. ErrorBuf : array[0..ErrorBufferLength] of char;
  906. ErrorLen : longint;
  907. Function ErrorWrite(Var F: TextRec): Integer;
  908. {
  909. An error message should always end with #13#10#13#10
  910. }
  911. var
  912. p : pchar;
  913. i : longint;
  914. Begin
  915. if F.BufPos>0 then
  916. begin
  917. if F.BufPos+ErrorLen>ErrorBufferLength then
  918. i:=ErrorBufferLength-ErrorLen
  919. else
  920. i:=F.BufPos;
  921. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  922. inc(ErrorLen,i);
  923. ErrorBuf[ErrorLen]:=#0;
  924. end;
  925. if ErrorLen>3 then
  926. begin
  927. p:=@ErrorBuf[ErrorLen];
  928. for i:=1 to 4 do
  929. begin
  930. dec(p);
  931. if not(p^ in [#10,#13]) then
  932. break;
  933. end;
  934. end;
  935. if ErrorLen=ErrorBufferLength then
  936. i:=4;
  937. if (i=4) then
  938. begin
  939. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  940. ErrorLen:=0;
  941. end;
  942. F.BufPos:=0;
  943. ErrorWrite:=0;
  944. End;
  945. Function ErrorClose(Var F: TextRec): Integer;
  946. begin
  947. if ErrorLen>0 then
  948. begin
  949. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  950. ErrorLen:=0;
  951. end;
  952. ErrorLen:=0;
  953. ErrorClose:=0;
  954. end;
  955. Function ErrorOpen(Var F: TextRec): Integer;
  956. Begin
  957. TextRec(F).InOutFunc:=@ErrorWrite;
  958. TextRec(F).FlushFunc:=@ErrorWrite;
  959. TextRec(F).CloseFunc:=@ErrorClose;
  960. ErrorOpen:=0;
  961. End;
  962. procedure AssignError(Var T: Text);
  963. begin
  964. Assign(T,'');
  965. TextRec(T).OpenFunc:=@ErrorOpen;
  966. Rewrite(T);
  967. end;
  968. const
  969. Exe_entry_code : pointer = @Exe_entry;
  970. Dll_entry_code : pointer = @Dll_entry;
  971. begin
  972. { get some helpful informations }
  973. GetStartupInfo(@startupinfo);
  974. { some misc Win32 stuff }
  975. hprevinst:=0;
  976. if not IsLibrary then
  977. HInstance:=getmodulehandle(GetCommandFile);
  978. MainInstance:=HInstance;
  979. { No idea how to know this issue !! }
  980. IsMultithreaded:=false;
  981. cmdshow:=startupinfo.wshowwindow;
  982. { to test stack depth }
  983. loweststack:=maxlongint;
  984. { real test stack depth }
  985. { stacklimit := setupstack; }
  986. { Setup heap }
  987. InitHeap;
  988. InitExceptions;
  989. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  990. displayed in and messagebox }
  991. StdInputHandle:=longint(GetStdHandle(STD_INPUT_HANDLE));
  992. StdOutputHandle:=longint(GetStdHandle(STD_OUTPUT_HANDLE));
  993. StdErrorHandle:=longint(GetStdHandle(STD_ERROR_HANDLE));
  994. if not IsConsole then
  995. begin
  996. AssignError(stderr);
  997. AssignError(stdout);
  998. Assign(Output,'');
  999. Assign(Input,'');
  1000. end
  1001. else
  1002. begin
  1003. OpenStdIO(Input,fmInput,StdInputHandle);
  1004. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1005. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1006. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1007. end;
  1008. { Arguments }
  1009. setup_arguments;
  1010. { Reset IO Error }
  1011. InOutRes:=0;
  1012. { Reset internal error variable }
  1013. errno:=0;
  1014. end.
  1015. {
  1016. $Log$
  1017. Revision 1.55 2000-01-16 22:25:38 peter
  1018. * check handle for file closing
  1019. Revision 1.54 2000/01/07 16:41:52 daniel
  1020. * copyright 2000
  1021. Revision 1.53 2000/01/07 16:32:34 daniel
  1022. * copyright 2000 added
  1023. Revision 1.52 2000/01/06 23:40:36 peter
  1024. * fixed exitprocess call, it's now in system_exit and uses exitcode
  1025. Revision 1.51 1999/12/01 22:57:31 peter
  1026. * cmdline support
  1027. Revision 1.50 1999/11/20 00:16:44 pierre
  1028. + DLL Hooks for the four callings added
  1029. Revision 1.49 1999/11/18 22:19:57 pierre
  1030. * bug fix for web bug703 and 704
  1031. Revision 1.48 1999/11/09 22:34:00 pierre
  1032. * Check ErrorBuf at exit
  1033. + Win32StackTop
  1034. Revision 1.47 1999/10/26 12:25:51 peter
  1035. * report stderr,stdout to message box for errors
  1036. * close input,output when GUI app is made
  1037. Revision 1.46 1999/10/22 14:47:19 peter
  1038. * allocate an extra byte for argv[0]
  1039. Revision 1.45 1999/10/03 19:39:05 peter
  1040. * fixed argv[0] length
  1041. Revision 1.44 1999/09/10 15:40:35 peter
  1042. * fixed do_open flags to be > $100, becuase filemode can be upto 255
  1043. Revision 1.43 1999/07/07 10:04:43 michael
  1044. + Small edit in paramstr
  1045. Revision 1.42 1999/07/07 09:43:16 michael
  1046. Better construction of commandline argv
  1047. Revision 1.41 1999/07/05 20:04:30 peter
  1048. * removed temp defines
  1049. Revision 1.40 1999/06/11 16:26:40 michael
  1050. + Fixed paramstr(0)
  1051. Revision 1.39 1999/05/17 21:52:47 florian
  1052. * most of the Object Pascal stuff moved to the system unit
  1053. Revision 1.38 1999/04/28 11:42:53 peter
  1054. + FileNameCaseSensetive boolean
  1055. Revision 1.37 1999/04/08 12:23:11 peter
  1056. * removed os.inc
  1057. Revision 1.36 1999/03/24 23:25:59 peter
  1058. * fixed file sharing
  1059. Revision 1.35 1999/03/12 00:07:48 pierre
  1060. + code for coff writer
  1061. Revision 1.34 1999/03/10 22:15:31 florian
  1062. + system.cmdline variable for go32v2 and win32 added
  1063. Revision 1.33 1999/01/18 10:05:57 pierre
  1064. + system_exit procedure added
  1065. Revision 1.32 1998/12/28 23:30:11 peter
  1066. * fixes for smartlinking
  1067. Revision 1.31 1998/12/28 15:50:51 peter
  1068. + stdout, which is needed when you write something in the system unit
  1069. to the screen. Like the runtime error
  1070. Revision 1.30 1998/12/21 14:28:23 pierre
  1071. * HandleError -> HandleErrorFrame to avoid problem in
  1072. assembler code in i386.inc
  1073. (call to overloaded function in assembler block !)
  1074. Revision 1.29 1998/12/15 22:43:14 peter
  1075. * removed temp symbols
  1076. Revision 1.28 1998/12/09 17:57:33 pierre
  1077. + exception handling by default
  1078. Revision 1.27 1998/12/01 14:00:08 pierre
  1079. + added conversion from exceptions into run time error
  1080. (only if syswin32 compiled with -ddebug for now !)
  1081. * added HandleErrorFrame(errno,frame)
  1082. where you specify the frame
  1083. needed for win32 exception handling
  1084. Revision 1.26 1998/11/30 13:13:41 pierre
  1085. * needs asw to link correctly wprt0 or wdllprt0 file
  1086. Revision 1.25 1998/11/30 09:16:58 pierre
  1087. + added the changes from Pavel Ozerski after several modifications
  1088. to be able to create DLLs
  1089. Revision 1.24 1998/11/16 15:48:54 peter
  1090. * fixed longbool returns for api calls
  1091. Revision 1.23 1998/11/16 14:14:58 pierre
  1092. * changed getdir(byte,string) to getdir(byte,shortstring)
  1093. Revision 1.22 1998/10/27 15:07:16 florian
  1094. + Is* flags added
  1095. + IsLibrary works also
  1096. Revision 1.21 1998/10/15 16:26:19 peter
  1097. + fpuinit
  1098. + end of backtrace indicator
  1099. Revision 1.20 1998/09/14 10:48:33 peter
  1100. * FPC_ names
  1101. * Heap manager is now system independent
  1102. Revision 1.19 1998/09/02 09:03:46 pierre
  1103. * do_open sometimes returns -1 as handle on fail
  1104. was not checked correctly
  1105. Revision 1.16 1998/08/24 14:45:22 pierre
  1106. * sbrk was wrong
  1107. heap growing now works for win32
  1108. Revision 1.15 1998/08/21 10:10:16 peter
  1109. * winheap turned off by default
  1110. Revision 1.14 1998/07/30 13:27:19 michael
  1111. + Added support for errorproc. Changed runerror to HandleError
  1112. Revision 1.13 1998/07/13 21:19:15 florian
  1113. * some problems with ansi string support fixed
  1114. Revision 1.12 1998/07/07 12:37:28 carl
  1115. * correct mapping of error codes for TP compatibility
  1116. + implemented stack checking in ifdef dummy
  1117. Revision 1.11 1998/07/02 12:33:18 carl
  1118. * IOCheck/InOutRes check for mkdir,rmdir and chdir like in TP
  1119. Revision 1.10 1998/07/01 15:30:02 peter
  1120. * better readln/writeln
  1121. Revision 1.9 1998/06/10 10:39:17 peter
  1122. * working w32 rtl
  1123. Revision 1.8 1998/06/08 23:07:47 peter
  1124. * dos interface is now 100% compatible
  1125. * fixed call PASCALMAIN which must be direct asm
  1126. Revision 1.7 1998/05/06 12:36:51 michael
  1127. + Removed log from before restored version.
  1128. Revision 1.6 1998/04/27 18:29:09 florian
  1129. + do_open implemented, the file-I/O should be now complete
  1130. Revision 1.5 1998/04/27 13:58:21 florian
  1131. + paramstr/paramcount implemented
  1132. Revision 1.4 1998/04/26 22:37:22 florian
  1133. * some small extensions
  1134. Revision 1.3 1998/04/26 21:49:57 florian
  1135. + more stuff added (??dir procedures etc.)
  1136. }