syswin.inc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2008 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit part shared by win32/win64.
  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. {
  13. Error code definitions for the Win32 API functions
  14. Values are 32 bit values layed out as follows:
  15. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  16. 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
  17. +---+-+-+-----------------------+-------------------------------+
  18. |Sev|C|R| Facility | Code |
  19. +---+-+-+-----------------------+-------------------------------+
  20. where
  21. Sev - is the severity code
  22. 00 - Success
  23. 01 - Informational
  24. 10 - Warning
  25. 11 - Error
  26. C - is the Customer code flag
  27. R - is a reserved bit
  28. Facility - is the facility code
  29. Code - is the facility's status code
  30. }
  31. const
  32. SEVERITY_SUCCESS = $00000000;
  33. SEVERITY_INFORMATIONAL = $40000000;
  34. SEVERITY_WARNING = $80000000;
  35. SEVERITY_ERROR = $C0000000;
  36. const
  37. STATUS_SEGMENT_NOTIFICATION = $40000005;
  38. DBG_TERMINATE_THREAD = $40010003;
  39. DBG_TERMINATE_PROCESS = $40010004;
  40. DBG_CONTROL_C = $40010005;
  41. DBG_CONTROL_BREAK = $40010008;
  42. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  43. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  44. STATUS_BREAKPOINT = $80000003;
  45. STATUS_SINGLE_STEP = $80000004;
  46. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  47. STATUS_ACCESS_VIOLATION = $C0000005;
  48. STATUS_IN_PAGE_ERROR = $C0000006;
  49. STATUS_INVALID_HANDLE = $C0000008;
  50. STATUS_NO_MEMORY = $C0000017;
  51. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  52. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  53. STATUS_INVALID_DISPOSITION = $C0000026;
  54. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  55. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  56. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  57. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  58. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  59. STATUS_FLOAT_OVERFLOW = $C0000091;
  60. STATUS_FLOAT_STACK_CHECK = $C0000092;
  61. STATUS_FLOAT_UNDERFLOW = $C0000093;
  62. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  63. STATUS_INTEGER_OVERFLOW = $C0000095;
  64. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  65. STATUS_STACK_OVERFLOW = $C00000FD;
  66. STATUS_CONTROL_C_EXIT = $C000013A;
  67. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  68. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  69. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  70. { Exceptions raised by RTL use this code }
  71. FPC_EXCEPTION_CODE = $E0465043;
  72. EXCEPTION_EXECUTE_HANDLER = 1;
  73. EXCEPTION_CONTINUE_EXECUTION = -1;
  74. EXCEPTION_CONTINUE_SEARCH = 0;
  75. { exception flags (not everything applies to Win32!) }
  76. EXCEPTION_NONCONTINUABLE = $01;
  77. EXCEPTION_UNWINDING = $02;
  78. EXCEPTION_EXIT_UNWIND = $04;
  79. EXCEPTION_STACK_INVALID = $08;
  80. EXCEPTION_NESTED_CALL = $10;
  81. EXCEPTION_TARGET_UNWIND = $20;
  82. EXCEPTION_COLLIDED_UNWIND = $40;
  83. CONTEXT_X86 = $00010000;
  84. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  85. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  86. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  87. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  88. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  89. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  90. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  91. MAXIMUM_SUPPORTED_EXTENSION = 512;
  92. type
  93. EXCEPTION_DISPOSITION=(
  94. ExceptionContinueExecution,
  95. ExceptionContinueSearch,
  96. ExceptionNestedException,
  97. ExceptionCollidedUnwind
  98. );
  99. TUnwindProc=procedure(frame: PtrUInt);
  100. PFilterRec=^TFilterRec;
  101. TFilterRec=record
  102. RvaClass: DWord;
  103. RvaHandler: DWord;
  104. end;
  105. TExceptObjProc=function(code: Longint; const rec: TExceptionRecord): Pointer; { Exception }
  106. TExceptClsProc=function(code: Longint): Pointer; { ExceptClass }
  107. function RunErrorCode(const rec: TExceptionRecord): longint;
  108. begin
  109. { negative result means 'FPU reset required' }
  110. case rec.ExceptionCode of
  111. STATUS_INTEGER_DIVIDE_BY_ZERO: result := 200; { reDivByZero }
  112. STATUS_FLOAT_DIVIDE_BY_ZERO: result := -208; { !!reZeroDivide }
  113. STATUS_ARRAY_BOUNDS_EXCEEDED: result := 201; { reRangeError }
  114. STATUS_STACK_OVERFLOW: result := 202; { reStackOverflow }
  115. STATUS_FLOAT_OVERFLOW: result := -205; { reOverflow }
  116. STATUS_FLOAT_DENORMAL_OPERAND,
  117. STATUS_FLOAT_UNDERFLOW: result := -206; { reUnderflow }
  118. STATUS_FLOAT_INEXACT_RESULT,
  119. STATUS_FLOAT_INVALID_OPERATION,
  120. STATUS_FLOAT_STACK_CHECK: result := -207; { reInvalidOp }
  121. STATUS_INTEGER_OVERFLOW: result := 215; { reIntOverflow }
  122. STATUS_ILLEGAL_INSTRUCTION: result := -216;
  123. STATUS_ACCESS_VIOLATION: result := 216; { reAccessViolation }
  124. STATUS_CONTROL_C_EXIT: result := 217; { reControlBreak }
  125. STATUS_PRIVILEGED_INSTRUCTION: result := 218; { rePrivilegedInstruction }
  126. STATUS_FLOAT_MULTIPLE_TRAPS,
  127. STATUS_FLOAT_MULTIPLE_FAULTS: result := -255; { indicate FPU reset }
  128. else
  129. result := 255; { reExternalException }
  130. end;
  131. end;
  132. procedure TranslateMxcsr(mxcsr: longword; var code: longint);
  133. begin
  134. { we can return only one value, further one's are lost }
  135. { InvalidOp }
  136. if (mxcsr and 1)<>0 then
  137. code:=-207
  138. { Denormal }
  139. else if (mxcsr and 2)<>0 then
  140. code:=-206
  141. { !!reZeroDivide }
  142. else if (mxcsr and 4)<>0 then
  143. code:=-208
  144. { reOverflow }
  145. else if (mxcsr and 8)<>0 then
  146. code:=-205
  147. { Underflow }
  148. else if (mxcsr and 16)<>0 then
  149. code:=-206
  150. { Precision }
  151. else if (mxcsr and 32)<>0 then
  152. code:=-207
  153. else { this should not happen }
  154. code:=-255
  155. end;
  156. function FilterException(var rec:TExceptionRecord; imagebase: PtrUInt; filterRva: DWord; errcode: Longint): Pointer;
  157. var
  158. ExClass: TClass;
  159. i: Longint;
  160. Filter: Pointer;
  161. curFilt: PFilterRec;
  162. begin
  163. result:=nil;
  164. if rec.ExceptionCode=FPC_EXCEPTION_CODE then
  165. ExClass:=TObject(rec.ExceptionInformation[1]).ClassType
  166. else if Assigned(ExceptClsProc) then
  167. ExClass:=TClass(TExceptClsProc(ExceptClsProc)(errcode))
  168. else
  169. Exit; { if we cannot determine type of exception, don't handle it }
  170. Filter:=Pointer(imagebase+filterRva);
  171. for i:=0 to PLongint(Filter)^-1 do
  172. begin
  173. CurFilt:=@PFilterRec(Filter+sizeof(Longint))[i];
  174. if (CurFilt^.RvaClass=$FFFFFFFF) or
  175. { TODO: exception might be coming from another module, need more advanced comparing }
  176. (ExClass.InheritsFrom({$if not defined(ver3_0) and not defined(ver3_2)}PClass(imagebase+CurFilt^.RvaClass)^{$else}TClass(imagebase+CurFilt^.RvaClass){$endif})) then
  177. begin
  178. result:=Pointer(imagebase+CurFilt^.RvaHandler);
  179. exit;
  180. end;
  181. end;
  182. end;
  183. {*****************************************************************************
  184. Parameter Handling
  185. *****************************************************************************}
  186. var
  187. argvw: PPWideChar;
  188. procedure setup_arguments;
  189. var
  190. CmdLineW, pw: PWideChar;
  191. c: WideChar;
  192. buf: array[0..MaxPathLen] of WideChar;
  193. i, len, argvw_size: longint;
  194. s: RawByteString;
  195. quote: char;
  196. begin
  197. // Get the unicode command line
  198. CmdLineW:=GetCommandLineW;
  199. // Create the ansi command line
  200. s:=ansistring(CmdLineW);
  201. len:=Length(s) + 1;
  202. CmdLine:=SysGetMem(len);
  203. Move(PAnsiChar(s)^, CmdLine^, len);
  204. // Alloc initial space for argvw
  205. if CmdLineW^ = #0 then
  206. argvw_size:=2
  207. else
  208. argvw_size:=10;
  209. argvw:=SysGetMem(argvw_size*SizeOf(pointer));
  210. // Get the full module name to be used as the first argument
  211. len:=GetModuleFileNameW(0, @buf, Length(buf));
  212. // Alloc maximum possible space for all arguments
  213. pw:=SysGetMem((len + IndexWord(CmdLineW^, High(longint), 0) + 2)*SizeOf(WideChar));
  214. // Copy the module name as the first argument. It will be nil terminated later
  215. Move(buf, pw^, len*SizeOf(WideChar));
  216. argvw[0]:=pw;
  217. Inc(pw, len);
  218. // Parse the command line
  219. argc:=0;
  220. quote:=' ';
  221. while True do
  222. begin
  223. c:=CmdLineW^;
  224. Inc(CmdLineW);
  225. case c of
  226. #0..#32:
  227. if (quote = ' ') or (c = #0) then
  228. begin
  229. // Are there any chars of an argument?
  230. if argvw[argc] <> pw then
  231. begin
  232. // End of an argument found
  233. pw^:=#0;
  234. Inc(pw);
  235. Inc(argc);
  236. if argc = argvw_size then
  237. begin
  238. // Increase the argvw space
  239. Inc(argvw_size, argvw_size shr 1);
  240. SysReAllocMem(argvw, argvw_size*SizeOf(pointer));
  241. end;
  242. if c = #0 then
  243. break;
  244. argvw[argc]:=pw;
  245. continue;
  246. end
  247. else
  248. if c = #0 then
  249. break
  250. else
  251. continue; // Skip whitespace
  252. end;
  253. '"':
  254. begin
  255. if quote<>'''' then
  256. begin
  257. if CmdLineW^<>'"' then
  258. begin
  259. if quote='"' then
  260. quote:=' '
  261. else
  262. quote:='"';
  263. continue;
  264. end
  265. else
  266. Inc(CmdLineW);
  267. end;
  268. end;
  269. '''':
  270. begin
  271. if quote<>'"' then
  272. begin
  273. if CmdLineW^<>'''' then
  274. begin
  275. if quote='''' then
  276. quote:=' '
  277. else
  278. quote:='''';
  279. continue;
  280. end
  281. else
  282. Inc(CmdLineW);
  283. end;
  284. end;
  285. end;
  286. // Ignore the first argument, it is already copied
  287. if argc <> 0 then
  288. begin
  289. // Copy the argument's AnsiChar
  290. pw^:=c;
  291. Inc(pw);
  292. end;
  293. end;
  294. // Finalization
  295. // argvw is terminated by nil
  296. argvw[argc]:=nil;
  297. // Trim the memory
  298. SysReAllocMem(argvw, (argc + 1)*SizeOf(pointer));
  299. SysReAllocMem(argvw[0], ptruint(pw) - ptruint(argvw[0]));
  300. // Construct the ansi argv
  301. argv:=SysGetMem((argc + 1)*SizeOf(pointer));
  302. for i:=0 to argc - 1 do
  303. begin
  304. // Convert argvw[i] to argv[i]
  305. s:=ansistring(argvw[i]);
  306. len:=Length(s) + 1;
  307. argv[i]:=SysGetMem(len);
  308. Move(s[1], argv[i]^, len);
  309. end;
  310. // argv is terminated by nil
  311. argv[argc]:=nil;
  312. end;
  313. procedure finalize_arguments;
  314. var
  315. i: longint;
  316. begin
  317. SysFreeMem(CmdLine);
  318. // Free unicode arguments
  319. SysFreeMem(argvw[0]);
  320. SysFreeMem(argvw);
  321. // Free ansi arguments
  322. for i:=0 to argc - 1 do
  323. SysFreeMem(argv[i]);
  324. SysFreeMem(argv);
  325. end;
  326. function paramcount : longint;
  327. begin
  328. paramcount := argc - 1;
  329. end;
  330. Function ParamStrU(l:Longint): UnicodeString; [public,alias:'_FPC_ParamStrU'];
  331. begin
  332. if (l >= 0) and (l < argc) then
  333. Result:=argvw[l]
  334. else
  335. Result:='';
  336. end;
  337. Function ParamStrA(l:Longint): AnsiString; [public,alias:'_FPC_ParamStrA'];
  338. begin
  339. Result:=AnsiString(ParamStrU(l));
  340. end;
  341. Function ParamStr(l:Longint): shortstring;
  342. begin
  343. if (l >= 0) and (l < argc) then
  344. Result:=argv[l]
  345. else
  346. Result:='';
  347. end;
  348. {*****************************************************************************}
  349. procedure randomize;
  350. begin
  351. randseed:=GetTickCount;
  352. end;
  353. Var
  354. DLLInitState : Longint = -1;
  355. DLLBuf : Jmp_buf;
  356. {$if defined(FPC_USE_WIN32_SEH) or defined(FPC_USE_WIN64_SEH)}
  357. {$define FPC_USE_SEH}
  358. {$endif}
  359. function Dll_entry{$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}(constref info : TEntryInformation){$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  360. begin
  361. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  362. SetupEntryInformation(info);
  363. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  364. IsLibrary:=true;
  365. DllInitState:=DLLreason;
  366. Dll_entry:=false; { return value is ignored, except when DLLreason=DLL_PROCESS_ATTACH }
  367. case DLLreason of
  368. DLL_PROCESS_ATTACH :
  369. begin
  370. MainThreadIdWin32 := Win32GetCurrentThreadId;
  371. If SetJmp(DLLBuf) = 0 then
  372. begin
  373. {$ifdef FPC_USE_SEH}
  374. try
  375. {$endif}
  376. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  377. EntryInformation.PascalMain();
  378. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  379. PascalMain;
  380. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  381. Dll_entry:=true;
  382. {$ifdef FPC_USE_SEH}
  383. except
  384. DoUnHandledException;
  385. Dll_entry:=false;
  386. end;
  387. {$endif}
  388. end
  389. else
  390. Dll_entry:=(ExitCode=0);
  391. end;
  392. DLL_THREAD_ATTACH :
  393. begin
  394. { SysInitMultithreading must not be called here,
  395. see comments in exec_tls_callback below }
  396. { Allocate Threadvars }
  397. SysAllocateThreadVars;
  398. { NS : no idea what is correct to pass here - pass dummy value for now }
  399. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  400. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  401. if assigned(Dll_Thread_Attach_Hook) then
  402. Dll_Thread_Attach_Hook(DllParam);
  403. end;
  404. DLL_THREAD_DETACH :
  405. begin
  406. if assigned(Dll_Thread_Detach_Hook) then
  407. Dll_Thread_Detach_Hook(DllParam);
  408. { Release Threadvars }
  409. if TlsGetValue(TLSKey^)<>nil then
  410. DoneThread; { Assume everything is idempotent there }
  411. end;
  412. DLL_PROCESS_DETACH :
  413. begin
  414. if MainThreadIDWin32=0 then // already been here.
  415. exit;
  416. If SetJmp(DLLBuf) = 0 then
  417. begin
  418. if assigned(Dll_Process_Detach_Hook) then
  419. Dll_Process_Detach_Hook(DllParam);
  420. InternalExit;
  421. end;
  422. SysReleaseThreadVars;
  423. { Free TLS resources used by ThreadVars }
  424. SysFiniMultiThreading;
  425. MainThreadIDWin32:=0;
  426. end;
  427. end;
  428. DllInitState:=-1;
  429. end;
  430. {****************************************************************************
  431. Error Message writing using messageboxes
  432. ****************************************************************************}
  433. function MessageBox(w1:THandle;l1,l2:pointer;w2:longint):longint;
  434. stdcall;external 'user32' name 'MessageBoxA';
  435. const
  436. ErrorBufferLength = 1024;
  437. var
  438. ErrorBuf : array[0..ErrorBufferLength] of AnsiChar;
  439. ErrorLen : SizeInt;
  440. procedure ErrorWrite(Var F: TextRec);
  441. {
  442. An error message should always end with #13#10#13#10
  443. }
  444. var
  445. i : SizeInt;
  446. Begin
  447. while F.BufPos>0 do
  448. begin
  449. begin
  450. if F.BufPos+ErrorLen>ErrorBufferLength then
  451. i:=ErrorBufferLength-ErrorLen
  452. else
  453. i:=F.BufPos;
  454. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  455. inc(ErrorLen,i);
  456. ErrorBuf[ErrorLen]:=#0;
  457. end;
  458. if ErrorLen=ErrorBufferLength then
  459. begin
  460. if not NoErrMsg then
  461. MessageBox(0,@ErrorBuf,PAnsiChar('Error'),0);
  462. ErrorLen:=0;
  463. end;
  464. Dec(F.BufPos,i);
  465. end;
  466. End;
  467. procedure ErrorClose(Var F: TextRec);
  468. begin
  469. if ErrorLen>0 then
  470. begin
  471. MessageBox(0,@ErrorBuf,PAnsiChar('Error'),0);
  472. ErrorLen:=0;
  473. end;
  474. ErrorLen:=0;
  475. end;
  476. procedure ErrorOpen(Var F: TextRec);
  477. Begin
  478. TextRec(F).InOutFunc:=@ErrorWrite;
  479. TextRec(F).FlushFunc:=@ErrorWrite;
  480. TextRec(F).CloseFunc:=@ErrorClose;
  481. ErrorLen:=0;
  482. End;
  483. procedure AssignError(Var T: Text);
  484. begin
  485. Assign(T,'');
  486. TextRec(T).OpenFunc:=@ErrorOpen;
  487. Rewrite(T);
  488. end;
  489. procedure SysInitStdIO;
  490. begin
  491. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  492. displayed in a messagebox }
  493. { WARNING: this should be done only once at startup,
  494. not for DLL entry code, as the standard handles might
  495. have been redirected }
  496. if StdInputHandle=0 then
  497. StdInputHandle:=THandle(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  498. if StdOutputHandle=0 then
  499. StdOutputHandle:=THandle(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  500. if StdErrorHandle=0 then
  501. StdErrorHandle:=THandle(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  502. if not IsConsole then
  503. begin
  504. AssignError(stderr);
  505. AssignError(StdOut);
  506. Assign(Output,'');
  507. Assign(Input,'');
  508. Assign(ErrOutput,'');
  509. end
  510. else
  511. begin
  512. OpenStdIO(Input,fmInput,StdInputHandle);
  513. OpenStdIO(Output,fmOutput,StdOutputHandle);
  514. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  515. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  516. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  517. end;
  518. end;
  519. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  520. var
  521. ProcessID: SizeUInt;
  522. function GetProcessID: SizeUInt;
  523. begin
  524. GetProcessID := ProcessID;
  525. end;
  526. {******************************************************************************
  527. Unicode
  528. ******************************************************************************}
  529. const
  530. { MultiByteToWideChar }
  531. MB_PRECOMPOSED = 1;
  532. WC_NO_BEST_FIT_CHARS = $400;
  533. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PAnsiChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  534. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  535. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PAnsiChar;cchMultiByte:longint; lpDefaultChar:PAnsiChar; lpUsedDefaultChar:pointer):longint;
  536. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  537. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  538. stdcall; external 'user32' name 'CharUpperBuffW';
  539. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  540. stdcall; external 'user32' name 'CharLowerBuffW';
  541. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  542. var
  543. destlen: SizeInt;
  544. begin
  545. // retrieve length including trailing #0
  546. // not anymore, because this must also be usable for single characters
  547. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  548. // this will null-terminate
  549. setlength(dest, destlen);
  550. if destlen>0 then
  551. begin
  552. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  553. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  554. end;
  555. end;
  556. procedure Win32Ansi2UnicodeMove(source:PAnsiChar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  557. var
  558. destlen: SizeInt;
  559. dwflags: DWORD;
  560. begin
  561. // retrieve length including trailing #0
  562. // not anymore, because this must also be usable for single characters
  563. case cp of
  564. // Under https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar
  565. CP_UTF8, CP_UTF7, 50220, 50221, 50222, 50225, 50227, 50229, 57002..57011, 42:
  566. dwFlags:=0
  567. else
  568. dwFlags:=MB_PRECOMPOSED;
  569. end;
  570. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  571. { destlen=0 means that Windows cannot convert, so call the default
  572. handler. This is similiar to what unix does and is a good fallback
  573. if rawbyte strings are passed }
  574. if destlen=0 then
  575. begin
  576. DefaultAnsi2UnicodeMove(source,DefaultSystemCodePage,dest,len);
  577. exit;
  578. end;
  579. // this will null-terminate
  580. setlength(dest, destlen);
  581. if destlen>0 then
  582. begin
  583. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  584. PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
  585. end;
  586. end;
  587. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  588. begin
  589. result:=s;
  590. UniqueString(result);
  591. if length(result)>0 then
  592. CharUpperBuff(LPWSTR(result),length(result));
  593. end;
  594. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  595. begin
  596. result:=s;
  597. UniqueString(result);
  598. if length(result)>0 then
  599. CharLowerBuff(LPWSTR(result),length(result));
  600. end;
  601. {******************************************************************************
  602. Widestring
  603. ******************************************************************************}
  604. procedure Win32Ansi2WideMove(source:PAnsiChar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  605. var
  606. destlen: SizeInt;
  607. dwFlags: DWORD;
  608. begin
  609. // retrieve length including trailing #0
  610. // not anymore, because this must also be usable for single characters
  611. if cp=CP_UTF8 then
  612. dwFlags:=0
  613. else
  614. dwFlags:=MB_PRECOMPOSED;
  615. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  616. // this will null-terminate
  617. setlength(dest, destlen);
  618. if destlen>0 then
  619. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  620. end;
  621. function Win32WideUpper(const s : WideString) : WideString;
  622. begin
  623. result:=s;
  624. if length(result)>0 then
  625. CharUpperBuff(LPWSTR(result),length(result));
  626. end;
  627. function Win32WideLower(const s : WideString) : WideString;
  628. begin
  629. result:=s;
  630. if length(result)>0 then
  631. CharLowerBuff(LPWSTR(result),length(result));
  632. end;
  633. type
  634. PWStrInitEntry = ^TWStrInitEntry;
  635. TWStrInitEntry = record
  636. addr: PPointer;
  637. data: Pointer;
  638. end;
  639. PWStrInitTablesTable = ^TWStrInitTablesTable;
  640. TWStrInitTablesTable = packed record
  641. count : sizeint;
  642. tables : packed array [1..32767] of PWStrInitEntry;
  643. end;
  644. var
  645. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  646. WStrInitTablesTable: PWStrInitTablesTable;
  647. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  648. WStrInitTablesTableVar: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  649. WStrInitTablesTable: PWStrInitTablesTable = @WStrInitTablesTableVar;
  650. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  651. function GetACP:UINT; stdcall; external 'kernel32' name 'GetACP';
  652. function GetConsoleCP:UINT; stdcall; external 'kernel32' name 'GetConsoleCP';
  653. function Win32GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  654. begin
  655. case stdcp of
  656. scpAnsi,
  657. scpFileSystemSingleByte: Result := GetACP;
  658. scpConsoleInput: Result := GetConsoleCP;
  659. scpConsoleOutput: Result := GetConsoleOutputCP;
  660. end;
  661. end;
  662. { there is a similiar procedure in sysutils which inits the fields which
  663. are only relevant for the sysutils units }
  664. procedure InitWin32Widestrings;
  665. var
  666. i: longint;
  667. ptable: PWStrInitEntry;
  668. begin
  669. {$if not(defined(VER2_2) or defined(VER2_4))}
  670. { assign initial values to global Widestring typed consts }
  671. for i:=1 to WStrInitTablesTable^.count do
  672. begin
  673. ptable:=WStrInitTablesTable^.tables[i];
  674. while Assigned(ptable^.addr) do
  675. begin
  676. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  677. Inc(ptable);
  678. end;
  679. end;
  680. {$endif}
  681. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  682. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  683. { Widestring }
  684. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  685. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  686. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  687. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  688. { Unicode }
  689. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  690. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  691. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  692. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  693. { Codepage }
  694. widestringmanager.GetStandardCodePageProc:=@Win32GetStandardCodePage;
  695. DefaultSystemCodePage:=GetACP;
  696. DefaultUnicodeCodePage:=CP_UTF16;
  697. DefaultFileSystemCodePage:=CP_UTF8;
  698. DefaultRTLFileSystemCodePage:=DefaultSystemCodePage;
  699. end;
  700. type
  701. WINBOOL = longbool;
  702. PHANDLER_ROUTINE = function (dwCtrlType:DWORD):WINBOOL; stdcall;
  703. function SetConsoleCtrlHandler(HandlerRoutine:PHANDLER_ROUTINE; Add:WINBOOL):WINBOOL; stdcall;
  704. external 'kernel32' name 'SetConsoleCtrlHandler';
  705. function WinCtrlBreakHandler(dwCtrlType:DWORD): WINBOOL;stdcall;
  706. const
  707. CTRL_BREAK_EVENT = 1;
  708. begin
  709. if Assigned(CtrlBreakHandler) then
  710. Result:=CtrlBreakHandler((dwCtrlType and CTRL_BREAK_EVENT > 0))
  711. else
  712. Result:=false;
  713. end;
  714. function SysSetCtrlBreakHandler (Handler: TCtrlBreakHandler): TCtrlBreakHandler;
  715. begin
  716. (* Return either nil or previous handler *)
  717. if (Assigned(CtrlBreakHandler)) and (not Assigned(Handler)) then
  718. SetConsoleCtrlHandler(@WinCtrlBreakHandler, false)
  719. else if (not Assigned(CtrlBreakHandler)) and (Assigned(Handler)) then
  720. SetConsoleCtrlHandler(@WinCtrlBreakHandler, true);
  721. SysSetCtrlBreakHandler := CtrlBreakHandler;
  722. CtrlBreakHandler := Handler;
  723. end;
  724. procedure WinFinalizeSystem;
  725. begin
  726. finalize_arguments;
  727. end;