syswin.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  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. EXCEPTION_EXECUTE_HANDLER = 1;
  71. EXCEPTION_CONTINUE_EXECUTION = -1;
  72. EXCEPTION_CONTINUE_SEARCH = 0;
  73. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  74. CONTEXT_X86 = $00010000;
  75. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  76. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  77. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  78. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  79. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  80. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  81. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  82. MAXIMUM_SUPPORTED_EXTENSION = 512;
  83. {*****************************************************************************
  84. Parameter Handling
  85. *****************************************************************************}
  86. procedure setup_arguments;
  87. var
  88. arglen,
  89. count : longint;
  90. argstart,
  91. pc,arg : pchar;
  92. quote : Boolean;
  93. argvlen : longint;
  94. buf: array[0..259] of char; // need MAX_PATH bytes, not 256!
  95. procedure allocarg(idx,len:longint);
  96. var
  97. oldargvlen : longint;
  98. begin
  99. if idx>=argvlen then
  100. begin
  101. oldargvlen:=argvlen;
  102. argvlen:=(idx+8) and (not 7);
  103. sysreallocmem(argv,argvlen*sizeof(pointer));
  104. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  105. end;
  106. { use realloc to reuse already existing memory }
  107. { always allocate, even if length is zero, since }
  108. { the arg. is still present! }
  109. sysreallocmem(argv[idx],len+1);
  110. end;
  111. begin
  112. { create commandline, it starts with the executed filename which is argv[0] }
  113. { Win32 passes the command NOT via the args, but via getmodulefilename}
  114. count:=0;
  115. argv:=nil;
  116. argvlen:=0;
  117. ArgLen := GetModuleFileName(0, @buf[0], sizeof(buf));
  118. buf[ArgLen] := #0; // be safe
  119. allocarg(0,arglen);
  120. move(buf,argv[0]^,arglen+1);
  121. { Setup cmdline variable }
  122. cmdline:=GetCommandLine;
  123. { process arguments }
  124. pc:=cmdline;
  125. {$IfDef SYSTEM_DEBUG_STARTUP}
  126. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  127. {$EndIf }
  128. while pc^<>#0 do
  129. begin
  130. { skip leading spaces }
  131. while pc^ in [#1..#32] do
  132. inc(pc);
  133. if pc^=#0 then
  134. break;
  135. { calc argument length }
  136. quote:=False;
  137. argstart:=pc;
  138. arglen:=0;
  139. while (pc^<>#0) do
  140. begin
  141. case pc^ of
  142. #1..#32 :
  143. begin
  144. if quote then
  145. inc(arglen)
  146. else
  147. break;
  148. end;
  149. '"' :
  150. if pc[1]<>'"' then
  151. quote := not quote
  152. else
  153. inc(pc);
  154. else
  155. inc(arglen);
  156. end;
  157. inc(pc);
  158. end;
  159. { copy argument }
  160. { Don't copy the first one, it is already there.}
  161. If Count<>0 then
  162. begin
  163. allocarg(count,arglen);
  164. quote:=False;
  165. pc:=argstart;
  166. arg:=argv[count];
  167. while (pc^<>#0) do
  168. begin
  169. case pc^ of
  170. #1..#32 :
  171. begin
  172. if quote then
  173. begin
  174. arg^:=pc^;
  175. inc(arg);
  176. end
  177. else
  178. break;
  179. end;
  180. '"' :
  181. if pc[1]<>'"' then
  182. quote := not quote
  183. else
  184. inc(pc);
  185. else
  186. begin
  187. arg^:=pc^;
  188. inc(arg);
  189. end;
  190. end;
  191. inc(pc);
  192. end;
  193. arg^:=#0;
  194. end;
  195. {$IfDef SYSTEM_DEBUG_STARTUP}
  196. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  197. {$EndIf SYSTEM_DEBUG_STARTUP}
  198. inc(count);
  199. end;
  200. { get argc }
  201. argc:=count;
  202. { free unused memory, leaving a nil entry at the end }
  203. sysreallocmem(argv,(count+1)*sizeof(pointer));
  204. argv[count] := nil;
  205. end;
  206. function paramcount : longint;
  207. begin
  208. paramcount := argc - 1;
  209. end;
  210. function paramstr(l : longint) : string;
  211. begin
  212. if (l>=0) and (l<argc) then
  213. paramstr:=strpas(argv[l])
  214. else
  215. paramstr:='';
  216. end;
  217. procedure randomize;
  218. begin
  219. randseed:=GetTickCount;
  220. end;
  221. Const
  222. DLL_PROCESS_ATTACH = 1;
  223. DLL_THREAD_ATTACH = 2;
  224. DLL_PROCESS_DETACH = 0;
  225. DLL_THREAD_DETACH = 3;
  226. DLLExitOK : boolean = true;
  227. Var
  228. DLLBuf : Jmp_buf;
  229. function Dll_entry{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}(const info : TEntryInformation){$endif FPC_HAS_INDIRECT_MAIN_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  230. begin
  231. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  232. EntryInformation:=info;
  233. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  234. IsLibrary:=true;
  235. Dll_entry:=false; { return value is ignored, except when DLLreason=DLL_PROCESS_ATTACH }
  236. case DLLreason of
  237. DLL_PROCESS_ATTACH :
  238. begin
  239. MainThreadIdWin32 := Win32GetCurrentThreadId;
  240. If SetJmp(DLLBuf) = 0 then
  241. begin
  242. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  243. EntryInformation.PascalMain();
  244. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  245. PascalMain;
  246. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  247. Dll_entry:=true;
  248. end
  249. else
  250. Dll_entry:=DLLExitOK;
  251. end;
  252. DLL_THREAD_ATTACH :
  253. begin
  254. { SysInitMultithreading must not be called here,
  255. see comments in exec_tls_callback below }
  256. { Allocate Threadvars }
  257. SysAllocateThreadVars;
  258. { NS : no idea what is correct to pass here - pass dummy value for now }
  259. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  260. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  261. if assigned(Dll_Thread_Attach_Hook) then
  262. Dll_Thread_Attach_Hook(DllParam);
  263. end;
  264. DLL_THREAD_DETACH :
  265. begin
  266. if assigned(Dll_Thread_Detach_Hook) then
  267. Dll_Thread_Detach_Hook(DllParam);
  268. { Release Threadvars }
  269. if TlsGetValue(TLSKey)<>nil then
  270. DoneThread; { Assume everything is idempotent there }
  271. end;
  272. DLL_PROCESS_DETACH :
  273. begin
  274. if MainThreadIDWin32=0 then // already been here.
  275. exit;
  276. If SetJmp(DLLBuf) = 0 then
  277. FPC_Do_Exit;
  278. if assigned(Dll_Process_Detach_Hook) then
  279. Dll_Process_Detach_Hook(DllParam);
  280. SysReleaseThreadVars;
  281. { Free TLS resources used by ThreadVars }
  282. SysFiniMultiThreading;
  283. MainThreadIDWin32:=0;
  284. end;
  285. end;
  286. end;
  287. Procedure ExitDLL(Exitcode : longint);
  288. begin
  289. DLLExitOK:=ExitCode=0;
  290. LongJmp(DLLBuf,1);
  291. end;
  292. {$ifdef FPC_USE_TLS_DIRECTORY}
  293. { Process TLS callback function }
  294. { This is only useful for executables
  295. for DLLs, DLL_Entry gets called. PM }
  296. procedure Exec_Tls_callback(Handle : pointer; reason : Dword; Reserved : pointer);
  297. stdcall; [public,alias:'_FPC_Tls_Callback'];
  298. begin
  299. if IsLibrary then
  300. Exit;
  301. case reason of
  302. { For executables, DLL_PROCESS_ATTACH is called *before* the entry point,
  303. and DLL_PROCESS_DETACH is called *after* RTL shuts down and calls ExitProcess.
  304. It isn't a good idea to handle resources of the main thread at these points.
  305. SysInitMultithreading is necessary however, because if some statically loaded
  306. DLL creates a thread, it will invoke DLL_THREAD_ATTACH before anything else is
  307. initialized. }
  308. DLL_PROCESS_ATTACH:
  309. SysInitMultithreading;
  310. DLL_THREAD_ATTACH :
  311. begin
  312. { !!! SysInitMultithreading must NOT be called here. Windows guarantees that
  313. the main thread invokes PROCESS_ATTACH, not THREAD_ATTACH. So this always
  314. executes in non-main thread. SysInitMultithreading() here will cause
  315. initial threadvars to be copied to TLS of non-main thread, and threadvars
  316. of the main thread will be reinitialized upon the next access with zeroes,
  317. ending up in a delayed failure which is very hard to debug.
  318. Fortunately this nasty scenario can happen only when the first non-main thread
  319. was created outside of RTL (Sergei).
  320. }
  321. { Allocate Threadvars }
  322. SysAllocateThreadVars;
  323. { NS : no idea what is correct to pass here - pass dummy value for now }
  324. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  325. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  326. end;
  327. DLL_THREAD_DETACH :
  328. begin
  329. if TlsGetValue(TLSKey)<>nil then
  330. DoneThread; { Assume everything is idempotent there }
  331. end;
  332. end;
  333. end;
  334. { Mingw tlssup.c source code has
  335. _CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0;
  336. _CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0;
  337. and the callback pointer is set to:
  338. (&__xl_a+1), (+1 meaning =+sizeof(pointer))
  339. I am not sure this can be compatible with
  340. }
  341. const
  342. FreePascal_TLS_callback : pointer = @Exec_Tls_callback;
  343. public name '__FPC_tls_callbacks' section '.CRT$XLFPC';
  344. FreePascal_end_of_TLS_callback : pointer = nil;
  345. public name '__FPC_end_of_tls_callbacks' section '.CRT$XLZZZ';
  346. var
  347. tls_callbacks : pointer; external name '___crt_xl_start__';
  348. tls_data_start : pointer; external name '___tls_start__';
  349. tls_data_end : pointer; external name '___tls_end__';
  350. _tls_index : dword; cvar; external;
  351. const
  352. _tls_used : TTlsDirectory = (
  353. data_start : @tls_data_start;
  354. data_end : @tls_data_end;
  355. index_pointer : @_tls_index;
  356. callbacks_pointer : @tls_callbacks;
  357. zero_fill_size : 0;
  358. flags : 0;
  359. ); cvar; public;
  360. {$ifdef win64}
  361. { This is a hack to support external linking.
  362. All released win64 versions of GNU binutils miss proper prefix handling
  363. when searching for _tls_used and expect two leading underscores.
  364. The issue has been fixed in binutils snapshots, but not released yet.
  365. TODO: This should be removed as soon as next version of binutils (>2.21) is
  366. released and we upgrade to it. }
  367. __tls_used : TTlsDirectory = (
  368. data_start : @tls_data_start;
  369. data_end : @tls_data_end;
  370. index_pointer : @_tls_index;
  371. callbacks_pointer : @tls_callbacks;
  372. zero_fill_size : 0;
  373. flags : 0;
  374. ); cvar; public;
  375. {$endif win64}
  376. {$endif FPC_USE_TLS_DIRECTORY}
  377. {****************************************************************************
  378. Error Message writing using messageboxes
  379. ****************************************************************************}
  380. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  381. stdcall;external 'user32' name 'MessageBoxA';
  382. const
  383. ErrorBufferLength = 1024;
  384. var
  385. ErrorBuf : array[0..ErrorBufferLength] of char;
  386. ErrorLen : SizeInt;
  387. Function ErrorWrite(Var F: TextRec): Integer;
  388. {
  389. An error message should always end with #13#10#13#10
  390. }
  391. var
  392. i : SizeInt;
  393. Begin
  394. while F.BufPos>0 do
  395. begin
  396. begin
  397. if F.BufPos+ErrorLen>ErrorBufferLength then
  398. i:=ErrorBufferLength-ErrorLen
  399. else
  400. i:=F.BufPos;
  401. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  402. inc(ErrorLen,i);
  403. ErrorBuf[ErrorLen]:=#0;
  404. end;
  405. if ErrorLen=ErrorBufferLength then
  406. begin
  407. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  408. ErrorLen:=0;
  409. end;
  410. Dec(F.BufPos,i);
  411. end;
  412. ErrorWrite:=0;
  413. End;
  414. Function ErrorClose(Var F: TextRec): Integer;
  415. begin
  416. if ErrorLen>0 then
  417. begin
  418. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  419. ErrorLen:=0;
  420. end;
  421. ErrorLen:=0;
  422. ErrorClose:=0;
  423. end;
  424. Function ErrorOpen(Var F: TextRec): Integer;
  425. Begin
  426. TextRec(F).InOutFunc:=@ErrorWrite;
  427. TextRec(F).FlushFunc:=@ErrorWrite;
  428. TextRec(F).CloseFunc:=@ErrorClose;
  429. ErrorLen:=0;
  430. ErrorOpen:=0;
  431. End;
  432. procedure AssignError(Var T: Text);
  433. begin
  434. Assign(T,'');
  435. TextRec(T).OpenFunc:=@ErrorOpen;
  436. Rewrite(T);
  437. end;
  438. procedure SysInitStdIO;
  439. begin
  440. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  441. displayed in a messagebox }
  442. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  443. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  444. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  445. if not IsConsole then
  446. begin
  447. AssignError(stderr);
  448. AssignError(StdOut);
  449. Assign(Output,'');
  450. Assign(Input,'');
  451. Assign(ErrOutput,'');
  452. end
  453. else
  454. begin
  455. OpenStdIO(Input,fmInput,StdInputHandle);
  456. OpenStdIO(Output,fmOutput,StdOutputHandle);
  457. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  458. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  459. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  460. end;
  461. end;
  462. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  463. var
  464. ProcessID: SizeUInt;
  465. function GetProcessID: SizeUInt;
  466. begin
  467. GetProcessID := ProcessID;
  468. end;
  469. {******************************************************************************
  470. Unicode
  471. ******************************************************************************}
  472. const
  473. { MultiByteToWideChar }
  474. MB_PRECOMPOSED = 1;
  475. WC_NO_BEST_FIT_CHARS = $400;
  476. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  477. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  478. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  479. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  480. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  481. stdcall; external 'user32' name 'CharUpperBuffW';
  482. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  483. stdcall; external 'user32' name 'CharLowerBuffW';
  484. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  485. var
  486. destlen: SizeInt;
  487. begin
  488. // retrieve length including trailing #0
  489. // not anymore, because this must also be usable for single characters
  490. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  491. // this will null-terminate
  492. setlength(dest, destlen);
  493. if destlen>0 then
  494. begin
  495. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  496. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  497. end;
  498. end;
  499. procedure Win32Ansi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  500. var
  501. destlen: SizeInt;
  502. dwflags: DWORD;
  503. begin
  504. // retrieve length including trailing #0
  505. // not anymore, because this must also be usable for single characters
  506. if cp=CP_UTF8 then
  507. dwFlags:=0
  508. else
  509. dwFlags:=MB_PRECOMPOSED;
  510. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  511. // this will null-terminate
  512. setlength(dest, destlen);
  513. if destlen>0 then
  514. begin
  515. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  516. PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
  517. end;
  518. end;
  519. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  520. begin
  521. result:=s;
  522. UniqueString(result);
  523. if length(result)>0 then
  524. CharUpperBuff(LPWSTR(result),length(result));
  525. end;
  526. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  527. begin
  528. result:=s;
  529. UniqueString(result);
  530. if length(result)>0 then
  531. CharLowerBuff(LPWSTR(result),length(result));
  532. end;
  533. {******************************************************************************
  534. Widestring
  535. ******************************************************************************}
  536. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  537. var
  538. destlen: SizeInt;
  539. begin
  540. // retrieve length including trailing #0
  541. // not anymore, because this must also be usable for single characters
  542. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  543. // this will null-terminate
  544. setlength(dest, destlen);
  545. if destlen>0 then
  546. begin
  547. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  548. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  549. end;
  550. end;
  551. procedure Win32Ansi2WideMove(source:pchar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  552. var
  553. destlen: SizeInt;
  554. dwFlags: DWORD;
  555. begin
  556. // retrieve length including trailing #0
  557. // not anymore, because this must also be usable for single characters
  558. if cp=CP_UTF8 then
  559. dwFlags:=0
  560. else
  561. dwFlags:=MB_PRECOMPOSED;
  562. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  563. // this will null-terminate
  564. setlength(dest, destlen);
  565. if destlen>0 then
  566. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  567. end;
  568. function Win32WideUpper(const s : WideString) : WideString;
  569. begin
  570. result:=s;
  571. if length(result)>0 then
  572. CharUpperBuff(LPWSTR(result),length(result));
  573. end;
  574. function Win32WideLower(const s : WideString) : WideString;
  575. begin
  576. result:=s;
  577. if length(result)>0 then
  578. CharLowerBuff(LPWSTR(result),length(result));
  579. end;
  580. type
  581. PWStrInitEntry = ^TWStrInitEntry;
  582. TWStrInitEntry = record
  583. addr: PPointer;
  584. data: Pointer;
  585. end;
  586. PWStrInitTablesTable = ^TWStrInitTablesTable;
  587. TWStrInitTablesTable = packed record
  588. count : longint;
  589. tables : packed array [1..32767] of PWStrInitEntry;
  590. end;
  591. {$if not(defined(VER2_2) or defined(VER2_4))}
  592. var
  593. WStrInitTablesTable: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  594. {$endif}
  595. function GetACP:UINT; stdcall; external 'kernel32' name 'GetACP';
  596. function GetConsoleCP:UINT; stdcall; external 'kernel32' name 'GetConsoleCP';
  597. function Win32GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  598. begin
  599. case stdcp of
  600. scpAnsi: Result := GetACP;
  601. scpConsoleInput: Result := GetConsoleCP;
  602. scpConsoleOutput: Result := GetConsoleOutputCP;
  603. end;
  604. end;
  605. { there is a similiar procedure in sysutils which inits the fields which
  606. are only relevant for the sysutils units }
  607. procedure InitWin32Widestrings;
  608. var
  609. i: longint;
  610. ptable: PWStrInitEntry;
  611. begin
  612. {$if not(defined(VER2_2) or defined(VER2_4))}
  613. { assign initial values to global Widestring typed consts }
  614. for i:=1 to WStrInitTablesTable.count do
  615. begin
  616. ptable:=WStrInitTablesTable.tables[i];
  617. while Assigned(ptable^.addr) do
  618. begin
  619. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  620. Inc(ptable);
  621. end;
  622. end;
  623. {$endif}
  624. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  625. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  626. { Widestring }
  627. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  628. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  629. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  630. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  631. { Unicode }
  632. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  633. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  634. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  635. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  636. { Codepage }
  637. widestringmanager.GetStandardCodePageProc:=@Win32GetStandardCodePage;
  638. DefaultSystemCodePage:=GetACP;
  639. DefaultUnicodeCodePage:=CP_UTF16;
  640. end;