syswin32.pp 35 KB

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