PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/pwlib/src/ptlib/msos/win32.cxx

https://bitbucket.org/thelearninglabs/uclinux-distro-tll-public
C++ | 2081 lines | 1438 code | 67 blank | 576 comment | 24 complexity | b4dbfed3178258c93dc37b4a2f68545b MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-3.0, Unlicense, GPL-2.0, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0, ISC, MIT, 0BSD, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * win32.cxx
  3. *
  4. * Miscellaneous implementation of classes for Win32
  5. *
  6. * Portable Windows Library
  7. *
  8. * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9. *
  10. * The contents of this file are subject to the Mozilla Public License
  11. * Version 1.0 (the "License"); you may not use this file except in
  12. * compliance with the License. You may obtain a copy of the License at
  13. * http://www.mozilla.org/MPL/
  14. *
  15. * Software distributed under the License is distributed on an "AS IS"
  16. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17. * the License for the specific language governing rights and limitations
  18. * under the License.
  19. *
  20. * The Original Code is Portable Windows Library.
  21. *
  22. * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23. *
  24. * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25. * All Rights Reserved.
  26. *
  27. * Contributor(s): ______________________________________.
  28. *
  29. * $Log: win32.cxx,v $
  30. * Revision 1.156 2005/11/30 12:47:42 csoutheren
  31. * Removed tabs, reformatted some code, and changed tags for Doxygen
  32. *
  33. * Revision 1.155 2005/11/17 22:54:26 csoutheren
  34. * Fixed missed functions in de-consting PMutex functions
  35. *
  36. * Revision 1.154 2005/11/14 22:29:13 csoutheren
  37. * Reverted Wait and Signal to non-const - there is no way we can guarantee that all
  38. * descendant classes everywhere will be changed over, so we have to keep the
  39. * original API
  40. *
  41. * Revision 1.153 2005/11/09 09:19:10 csoutheren
  42. * Now actually remove the call :)
  43. *
  44. * Revision 1.152 2005/11/09 09:11:39 csoutheren
  45. * Moved Windows-specific AttachThreadInput callsto seperate member function
  46. * on PThread. This removes a linearly increasing delay in creating new threads
  47. *
  48. * Revision 1.151 2005/11/04 06:34:20 csoutheren
  49. * Added new class PSync as abstract base class for all mutex/sempahore classes
  50. * Changed PCriticalSection to use Wait/Signal rather than Enter/Leave
  51. * Changed Wait/Signal to be const member functions
  52. * Renamed PMutex to PTimedMutex and made PMutex synonym for PCriticalSection.
  53. * This allows use of very efficient mutex primitives in 99% of cases where timed waits
  54. * are not needed
  55. *
  56. * Revision 1.150 2005/09/23 15:30:46 dominance
  57. * more progress to make mingw compile nicely. Thanks goes to Julien Puydt for pointing out to me how to do it properly. ;)
  58. *
  59. * Revision 1.149 2005/09/18 13:01:43 dominance
  60. * fixed pragma warnings when building with gcc.
  61. *
  62. * Revision 1.148 2005/07/13 12:48:32 csoutheren
  63. * Backported fix from isvo branch
  64. *
  65. * Revision 1.147 2005/06/07 07:41:42 csoutheren
  66. * Applied patch 1176459 for PocketPC. Thanks to Matthias Weber
  67. *
  68. * Revision 1.146.2.1 2005/04/25 13:12:39 shorne
  69. * Fixed OSConfigDir for win32/NT/XP
  70. *
  71. * Revision 1.146 2005/02/02 23:21:16 csoutheren
  72. * Fixed problem with race condition in HousekeepingThread
  73. * Thanks to an idea from Auri Vizgaitis
  74. *
  75. * Revision 1.145 2005/01/25 11:28:25 csoutheren
  76. * Changed parms to CreateEvent to be more clear
  77. *
  78. * Revision 1.144 2005/01/16 23:00:36 csoutheren
  79. * Fixed problem when calling WaitForTermination from within the same thread
  80. *
  81. * Revision 1.143 2005/01/11 06:57:15 csoutheren
  82. * Fixed namespace collisions with plugin starup factories
  83. *
  84. * Revision 1.142 2005/01/04 07:44:04 csoutheren
  85. * More changes to implement the new configuration methodology, and also to
  86. * attack the global static problem
  87. *
  88. * Revision 1.141 2004/11/17 12:50:44 csoutheren
  89. * Win32 DCOM support, thanks to Simon Horne
  90. *
  91. * Revision 1.140 2004/10/31 22:22:06 csoutheren
  92. * Added pragma to include ole32.lib for static builds
  93. *
  94. * Revision 1.139 2004/10/23 10:50:28 ykiryanov
  95. * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port
  96. *
  97. * Revision 1.138 2004/09/17 04:05:12 csoutheren
  98. * Changed Windows PDirectory semantics to be the same as Unix
  99. *
  100. * Revision 1.137 2004/06/09 13:35:11 csoutheren
  101. * Disabled "wait for key" at end of program unless in debug mode or PMEMORY_CHECK
  102. * is enabled
  103. *
  104. * Revision 1.136 2004/05/21 00:28:40 csoutheren
  105. * Moved PProcessStartup creation to PProcess::Initialise
  106. * Added PreShutdown function and called it from ~PProcess to handle PProcessStartup removal
  107. *
  108. * Revision 1.135 2004/04/09 06:52:18 rjongbloed
  109. * Removed #pargma linker command for /delayload of DLL as documentations sais that
  110. * you cannot do this.
  111. *
  112. * Revision 1.134 2004/04/03 06:54:30 rjongbloed
  113. * Many and various changes to support new Visual C++ 2003
  114. *
  115. * Revision 1.133 2004/02/23 23:52:20 csoutheren
  116. * Added pragmas to avoid every Windows application needing to include libs explicitly
  117. *
  118. * Revision 1.132 2003/11/10 20:52:26 dereksmithies
  119. * add fix from Diego Tartara to recognize win XP and 2003 Server. Many thanks.
  120. *
  121. * Revision 1.131 2003/11/08 01:43:05 rjongbloed
  122. * Fixed race condition that could start two housekeeping threads, thanks Ted Szoczei
  123. *
  124. * Revision 1.130 2003/11/05 05:56:08 csoutheren
  125. * Added #pragma to include required libs
  126. *
  127. * Revision 1.129 2003/10/27 03:29:11 csoutheren
  128. * Added support for QoS
  129. * Thanks to Henry Harrison of AliceStreet
  130. *
  131. * Revision 1.128 2003/09/17 05:45:10 csoutheren
  132. * Removed recursive includes
  133. *
  134. * Revision 1.127 2003/02/26 01:12:52 robertj
  135. * Fixed race condition where thread can terminatebefore an IsSuspeded() call
  136. * occurs and cause an assert, thanks Sebastian Meyer
  137. *
  138. * Revision 1.126 2002/12/11 22:25:04 robertj
  139. * Added ability to set user identity temporarily and permanently.
  140. * Added get and set users group functions.
  141. *
  142. * Revision 1.125 2002/11/20 02:38:38 robertj
  143. * Fixed file path parsing for common unix/dos path error.
  144. *
  145. * Revision 1.124 2002/11/20 00:58:58 robertj
  146. * Made file path parsing slightly smarter for common unix/dos path error.
  147. *
  148. * Revision 1.123 2002/11/19 10:28:50 robertj
  149. * Changed PFilePath so can be empty string, indicating illegal path.
  150. *
  151. * Revision 1.122 2002/09/23 07:17:24 robertj
  152. * Changes to allow winsock2 to be included.
  153. *
  154. * Revision 1.121 2002/06/04 00:25:31 robertj
  155. * Fixed incorrectly initialised trace indent, thanks Artis Kugevics
  156. *
  157. * Revision 1.120 2002/04/24 01:11:05 robertj
  158. * Fixed problem with PTRACE_BLOCK indent level being correct across threads.
  159. *
  160. * Revision 1.119 2002/01/26 15:05:35 yurik
  161. * Removed extra ifdefs
  162. *
  163. * Revision 1.118 2002/01/23 04:45:50 craigs
  164. * Added copy Constructors for PSemaphore, PMutex and PSyncPoint
  165. *
  166. * Revision 1.117 2001/12/08 00:22:37 robertj
  167. * Prevented assert if doing SetUserName() with empty string.
  168. *
  169. * Revision 1.116 2001/11/23 06:59:00 robertj
  170. * Added PProcess::SetUserName() function for effective user changes.
  171. *
  172. * Revision 1.115 2001/10/26 04:20:25 craigs
  173. * Changed housekeeping thread to be Normal priority to avoide starvation
  174. * of PTimer dependent threads
  175. *
  176. * Revision 1.114 2001/10/23 05:42:48 robertj
  177. * Fixed bug in retry loop waiting for termination, applies only to heavily
  178. * laoded Win98 class machines.
  179. *
  180. * Revision 1.113 2001/10/07 16:05:59 yurik
  181. * Removed MFC dependency
  182. *
  183. * Revision 1.112 2001/09/11 03:27:46 robertj
  184. * Improved error processing on high level protocol failures, usually
  185. * caused by unexpected shut down of a socket.
  186. *
  187. * Revision 1.111 2001/09/10 02:51:23 robertj
  188. * Major change to fix problem with error codes being corrupted in a
  189. * PChannel when have simultaneous reads and writes in threads.
  190. *
  191. * Revision 1.110 2001/08/07 03:20:39 robertj
  192. * Fixed close of DLL so flagged as closed, thanks Stefan Ditscheid.
  193. *
  194. * Revision 1.109 2001/07/09 01:35:48 robertj
  195. * Added name to housekeeper thread.
  196. *
  197. * Revision 1.108 2001/06/01 04:03:05 yurik
  198. * Removed dependency on obsolete function
  199. *
  200. * Revision 1.107 2001/05/29 00:49:18 robertj
  201. * Added ability to put in a printf %x in thread name to get thread object
  202. * address into user settable thread name.
  203. *
  204. * Revision 1.106 2001/05/10 15:21:30 yurik
  205. * Fixed bug in PSemaphore::Signal(), courtesy of Dave Cassel, dcassel@cyberfone.com.
  206. * Also Refined thread priorities for WinCE.
  207. *
  208. * Revision 1.105 2001/05/04 05:42:23 yurik
  209. * GetUserName for Pocket PC (Windows CE 3.0) implemented
  210. *
  211. * Revision 1.104 2001/04/26 06:07:34 yurik
  212. * UI improvements
  213. *
  214. * Revision 1.103 2001/04/15 03:38:42 yurik
  215. * Removed shutdown flag. Use IsTerminated() instead
  216. *
  217. * Revision 1.102 2001/04/14 04:54:03 yurik
  218. * Added process shutdown flag
  219. *
  220. * Revision 1.101 2001/03/24 05:52:42 robertj
  221. * Added Windows 98 and ME to GetOSName()
  222. * Added build number to GetOSVersion()
  223. *
  224. * Revision 1.100 2001/03/03 00:55:02 yurik
  225. * Proper fix for filetime routines used in guid calc done for WinCE
  226. *
  227. * Revision 1.99 2001/02/13 06:55:21 robertj
  228. * Fixed problem with operator= in PDirectory class, part of larger change previously made.
  229. *
  230. * Revision 1.98 2001/01/30 06:37:52 yurik
  231. * Modification submitted by Dave Cassel, dcassel@cyberfone.com
  232. * DC: ARM, x86em were content without this change, but SH4 insisted
  233. *
  234. * Revision 1.97 2001/01/29 01:19:32 robertj
  235. * Fixed Win32 compile broken by WinCE changes.
  236. *
  237. * Revision 1.96 2001/01/28 01:50:46 yurik
  238. * WinCE port-related. System version check and new semaphore code
  239. *
  240. * Revision 1.95 2001/01/24 06:44:35 yurik
  241. * Windows CE port-related changes
  242. *
  243. * Revision 1.94 2000/11/02 01:31:11 robertj
  244. * Fixed problem with PSemaphore::WillBlock actually locking semaphore.
  245. *
  246. * Revision 1.93 2000/10/20 05:31:53 robertj
  247. * Added function to change auto delete flag on a thread.
  248. *
  249. * Revision 1.92 2000/08/25 08:07:48 robertj
  250. * Added Windows 2000 to operating system reporting.
  251. *
  252. * Revision 1.91 2000/04/05 02:50:18 robertj
  253. * Added microseconds to PTime class.
  254. *
  255. * Revision 1.90 2000/03/29 04:31:59 robertj
  256. * Removed assertion on terminating terminated thread, this is really OK.
  257. *
  258. * Revision 1.89 2000/03/04 08:07:27 robertj
  259. * Fixed problem with window not appearing when assert on GUI based win32 apps.
  260. *
  261. * Revision 1.88 2000/02/29 12:26:15 robertj
  262. * Added named threads to tracing, thanks to Dave Harvey
  263. *
  264. * Revision 1.87 2000/01/06 14:09:42 robertj
  265. * Fixed problems with starting up timers,losing up to 10 seconds
  266. *
  267. * Revision 1.86 1999/11/18 02:22:53 robertj
  268. * Fixed bug in GetErrorText() occasionally returning incorrect empty string, thanks Ulrich Findeisen
  269. *
  270. * Revision 1.85 1999/07/06 13:37:07 robertj
  271. * Fixed bug in PThread::IsSuspended(), returned exactly the opposite state!
  272. *
  273. * Revision 1.84 1999/07/06 04:46:01 robertj
  274. * Fixed being able to case an unsigned to a PTimeInterval.
  275. * Improved resolution of PTimer::Tick() to be millisecond accurate.
  276. *
  277. * Revision 1.83 1999/03/09 10:30:19 robertj
  278. * Fixed ability to have PMEMORY_CHECK on/off on both debug/release versions.
  279. *
  280. * Revision 1.82 1999/03/09 08:19:15 robertj
  281. * Adjustment found during documentation frenzy.
  282. *
  283. * Revision 1.81 1999/02/12 01:01:57 craigs
  284. * Fixed problem with linking static versions of libraries
  285. *
  286. * Revision 1.80 1999/01/30 14:28:25 robertj
  287. * Added GetOSConfigDir() function.
  288. *
  289. * Revision 1.79 1999/01/16 02:00:29 robertj
  290. * Added hardware description funtion.
  291. *
  292. * Revision 1.78 1998/12/04 10:10:47 robertj
  293. * Added virtual for determining if process is a service. Fixes linkage problem.
  294. *
  295. * Revision 1.77 1998/11/30 07:31:18 robertj
  296. * New directory structure
  297. * Fission of file into pipe.cxx, winserial.cxx and wincfg.cxx
  298. *
  299. * Revision 1.76 1998/11/26 10:35:08 robertj
  300. * Improved support of FAT32 and large NTFS volumes in GetFreeSpace().
  301. *
  302. * Revision 1.75 1998/11/20 03:17:19 robertj
  303. * Added thread WaitForTermination() function.
  304. *
  305. * Revision 1.74 1998/11/19 05:19:53 robertj
  306. * Bullet proofed WaitForMultipleObjects under 95.
  307. *
  308. * Revision 1.73 1998/11/02 10:07:20 robertj
  309. * Added capability of pip output to go to stdout/stderr.
  310. *
  311. * Revision 1.72 1998/10/31 12:50:47 robertj
  312. * Removed ability to start threads immediately, race condition with vtable (Main() function).
  313. * Rearranged PPipChannel functions to help with multi-platform-ness.
  314. *
  315. * Revision 1.71 1998/10/29 11:29:20 robertj
  316. * Added ability to set environment in sub-process.
  317. *
  318. * Revision 1.70 1998/10/28 00:59:12 robertj
  319. * Fixed problem when reading standard error from pipe channel, no terminating null on string.
  320. *
  321. * Revision 1.69 1998/10/26 09:11:31 robertj
  322. * Added ability to separate out stdout from stderr on pipe channels.
  323. *
  324. * Revision 1.68 1998/10/15 02:20:26 robertj
  325. * Added message for connection aborted error.
  326. *
  327. * Revision 1.67 1998/10/13 14:13:36 robertj
  328. * Removed uneeded heap allocation.
  329. *
  330. * Revision 1.66 1998/09/24 03:30:59 robertj
  331. * Added open software license.
  332. *
  333. * Revision 1.65 1998/09/18 13:56:20 robertj
  334. * Added support of REG_BINARY registry types in PConfig class.
  335. *
  336. * Revision 1.64 1998/08/20 06:05:28 robertj
  337. * Allowed Win32 class to be used in other compilation modules
  338. *
  339. * Revision 1.63 1998/04/01 01:52:42 robertj
  340. * Fixed problem with NoAutoDelete threads.
  341. *
  342. * Revision 1.62 1998/03/29 06:16:56 robertj
  343. * Rearranged initialisation sequence so PProcess descendent constructors can do "things".
  344. *
  345. * Revision 1.61 1998/03/27 10:52:39 robertj
  346. * Fixed crash bug in win95 OSR2 GetVolumeSpace().
  347. * Fixed error 87 problem with threads.
  348. * Fixed GetVolumeSpace() when UNC used.
  349. *
  350. * Revision 1.60 1998/03/20 03:19:49 robertj
  351. * Added special classes for specific sepahores, PMutex and PSyncPoint.
  352. *
  353. * Revision 1.59 1998/03/17 10:17:09 robertj
  354. * Fixed problem with viewing registry entries where the section ends with a \.
  355. *
  356. * Revision 1.58 1998/03/09 11:17:38 robertj
  357. * FAT32 compatibility
  358. *
  359. * Revision 1.57 1998/03/05 12:48:37 robertj
  360. * Fixed bug in get free space on volume.
  361. * Added cluster size.
  362. * MemCheck fixes.
  363. *
  364. * Revision 1.56 1998/02/16 00:10:45 robertj
  365. * Added function to open a URL in a browser.
  366. * Added functions to validate characters in a filename.
  367. *
  368. * Revision 1.55 1998/01/26 00:57:09 robertj
  369. * Fixed uninitialised source in PConfig when getting environment.
  370. *
  371. * Revision 1.54 1997/08/28 12:50:21 robertj
  372. * Fixed race condition in cleaning up threads on application termination.
  373. *
  374. * Revision 1.53 1997/08/21 13:27:41 robertj
  375. * Attempt to fix very slight possibility of endless loop in housekeeping thread.
  376. *
  377. * Revision 1.52 1997/08/21 12:44:56 robertj
  378. * Removed extension from DLL "short" name.
  379. *
  380. * Revision 1.51 1997/08/07 11:57:42 robertj
  381. * Added ability to get registry data from other applications and anywhere in system registry.
  382. *
  383. * Revision 1.50 1997/08/04 10:38:43 robertj
  384. * Fixed infamous error 87 assert failure in housekeeping thread.
  385. *
  386. * Revision 1.49 1997/07/14 11:47:22 robertj
  387. * Added "const" to numerous variables.
  388. *
  389. * Revision 1.48 1997/06/16 13:15:53 robertj
  390. * Added function to get a dyna-link libraries name.
  391. *
  392. * Revision 1.47 1997/06/08 04:42:41 robertj
  393. * Added DLL file extension string function.
  394. *
  395. * Revision 1.46 1997/03/28 04:36:30 robertj
  396. * Added assert for error in thread cleanup wait.
  397. *
  398. * Revision 1.45 1997/02/05 11:50:58 robertj
  399. * Changed current process function to return reference and validate objects descendancy.
  400. *
  401. * Revision 1.44 1997/01/12 04:24:16 robertj
  402. * Added function to get disk size and free space.
  403. *
  404. * Revision 1.43 1997/01/01 11:17:06 robertj
  405. * Added implementation for PPipeChannel::GetReturnCode and PPipeChannel::IsRunning
  406. *
  407. * Revision 1.44 1996/12/29 13:05:03 robertj
  408. * Added wait and abort for pipe channel commands.
  409. * Added setting of error codes on status error.
  410. *
  411. * Revision 1.43 1996/12/29 02:53:13 craigs
  412. * Added implementation for PPipeChannel::GetReturnCode and
  413. * PPipeChannel::IsRunning
  414. *
  415. * Revision 1.42 1996/12/17 13:13:05 robertj
  416. * Fixed win95 support for registry security code,
  417. *
  418. * Revision 1.41 1996/12/17 11:00:28 robertj
  419. * Fixed register entry security access control lists.
  420. *
  421. * Revision 1.40 1996/11/16 10:52:48 robertj
  422. * Fixed bug in PPipeChannel test for open channel, win95 support.
  423. * Put time back to C function as run time library bug fixed now.
  424. *
  425. * Revision 1.39 1996/11/04 03:36:31 robertj
  426. * Added extra error message for UDP packet truncated.
  427. *
  428. * Revision 1.38 1996/10/26 01:42:51 robertj
  429. * Added more translations for winsock error codes to standard error codes.
  430. *
  431. * Revision 1.37 1996/10/14 03:11:25 robertj
  432. * Changed registry key so when reading only opens in ReadOnly mode.
  433. *
  434. * Revision 1.36 1996/10/08 13:03:47 robertj
  435. * Added new error messages.
  436. *
  437. * Revision 1.35 1996/08/08 10:03:43 robertj
  438. * Fixed static error text returned when no osError value.
  439. *
  440. * Revision 1.34 1996/07/27 04:05:31 robertj
  441. * Created static version of ConvertOSError().
  442. * Created static version of GetErrorText().
  443. * Changed thread creation to use C library function instead of direct WIN32.
  444. * Fixed bug in auto-deleting the housekeeping thread.
  445. *
  446. * Revision 1.33 1996/07/20 05:34:05 robertj
  447. * Fixed order of registry section tree traversal so can delete whole trees.
  448. *
  449. * Revision 1.32 1996/06/28 13:24:33 robertj
  450. * Fixed enumeration of sections to recurse into registry tree.
  451. *
  452. * Revision 1.31 1996/06/17 11:38:58 robertj
  453. * Fixed memory leak on termination of threads.
  454. *
  455. * Revision 1.30 1996/06/13 13:32:13 robertj
  456. * Rewrite of auto-delete threads, fixes Windows95 total crash.
  457. *
  458. * Revision 1.29 1996/06/10 09:54:35 robertj
  459. * Fixed Win95 compatibility for semaphores.
  460. *
  461. * Revision 1.28 1996/05/30 11:48:51 robertj
  462. * Fixed error on socket timeout to return "Timed Out".
  463. *
  464. * Revision 1.27 1996/05/23 10:05:36 robertj
  465. * Fixed bug in PConfig::GetBoolean().
  466. * Changed PTimeInterval millisecond access function so can get int64.
  467. * Moved service process code into separate module.
  468. *
  469. * Revision 1.26 1996/04/29 12:23:22 robertj
  470. * Fixed ability to access GDI stuff from subthreads.
  471. * Added function to return process ID.
  472. *
  473. * Revision 1.25 1996/04/17 12:09:30 robertj
  474. * Added service dependencies.
  475. * Started win95 support.
  476. *
  477. * Revision 1.24 1996/04/09 03:33:58 robertj
  478. * Fixed bug in incorrect report of timeout on socket read.
  479. *
  480. * Revision 1.23 1996/04/01 13:33:19 robertj
  481. * Fixed bug in install of service, incorrectly required installation before install.
  482. *
  483. * Revision 1.22 1996/03/31 09:10:33 robertj
  484. * Added use of "CurrentVersion" key in registry.
  485. * Added version display to service process.
  486. * Added another socket error text message.
  487. *
  488. * Revision 1.21 1996/03/12 11:31:39 robertj
  489. * Moved PProcess destructor to platform dependent code.
  490. * Fixed bug in deleting Event Viewer registry entry for service process.
  491. *
  492. * Revision 1.20 1996/03/10 13:16:49 robertj
  493. * Implemented system version functions.
  494. *
  495. * Revision 1.19 1996/03/04 13:07:33 robertj
  496. * Allowed for auto deletion of threads on termination.
  497. *
  498. * Revision 1.18 1996/02/25 11:15:29 robertj
  499. * Added platform dependent Construct function to PProcess.
  500. *
  501. * Revision 1.17 1996/02/25 03:12:48 robertj
  502. * Added consts to all GetXxxx functions in PConfig.
  503. * Fixed bug in PTime::GetTimeZone(), incorrect sign!
  504. * Fixed problem with PConfig get functions and their WIN32 types should be
  505. * able to interchange strings and numbers.
  506. *
  507. * Revision 1.16 1996/02/19 13:53:21 robertj
  508. * Fixed error reporting for winsock classes.
  509. *
  510. * Revision 1.15 1996/02/15 14:54:06 robertj
  511. * Compensated for C library bug in time().
  512. *
  513. * Revision 1.14 1996/02/08 12:30:41 robertj
  514. * Time zone changes.
  515. * Added OS identification strings to PProcess.
  516. *
  517. * Revision 1.13 1996/01/28 02:56:56 robertj
  518. * Fixed bug in PFilePath functions for if path ends in a directory separator.
  519. * Made sure all directory separators are correct character in normalised path.
  520. *
  521. * Revision 1.12 1996/01/23 13:25:21 robertj
  522. * Added time zones.
  523. * Fixed bug if daylight savings indication.
  524. *
  525. * Revision 1.11 1996/01/02 12:58:33 robertj
  526. * Fixed copy of directories.
  527. * Changed process construction mechanism.
  528. * Made service process "common".
  529. *
  530. * Revision 1.10 1995/12/10 12:05:48 robertj
  531. * Changes to main() startup mechanism to support Mac.
  532. * Moved error code for specific WIN32 and MS-DOS versions.
  533. * Added WIN32 registry support for PConfig objects.
  534. * Added asserts in WIN32 semaphores.
  535. *
  536. * Revision 1.9 1995/11/21 11:53:24 robertj
  537. * Added timeout on semaphore wait.
  538. *
  539. * Revision 1.8 1995/10/14 15:13:04 robertj
  540. * Fixed bug in WIN32 service command line parameters.
  541. *
  542. * Revision 1.7 1995/08/24 12:42:33 robertj
  543. * Changed PChannel so not a PContainer.
  544. * Rewrote PSerialChannel::Read yet again so can break out of I/O.
  545. *
  546. * Revision 1.6 1995/07/02 01:26:52 robertj
  547. * Changed thread internal variables.
  548. * Added service process support for NT.
  549. *
  550. * Revision 1.5 1995/06/17 01:03:08 robertj
  551. * Added NT service process type.
  552. *
  553. * Revision 1.4 1995/06/04 12:48:52 robertj
  554. * Fixed bug in directory path creation.
  555. * Fixed bug in comms channel open error.
  556. *
  557. * Revision 1.3 1995/04/25 11:33:54 robertj
  558. * Fixed Borland compiler warnings.
  559. *
  560. * Revision 1.2 1995/03/22 13:56:18 robertj
  561. * Fixed directory handle value check for closing directory.
  562. *
  563. // Revision 1.1 1995/03/14 12:45:20 robertj
  564. // Initial revision
  565. //
  566. */
  567. #include <ptlib.h>
  568. #include <process.h>
  569. #include <ptlib/msos/ptlib/debstrm.h>
  570. #include <winsock2.h>
  571. #include <ws2tcpip.h>
  572. #ifndef _WIN32_WCE
  573. #ifdef _MSC_VER
  574. #pragma comment(lib, "mpr.lib")
  575. #endif
  576. #endif
  577. #define new PNEW
  578. #if defined(_WIN32_DCOM)
  579. #include <objbase.h>
  580. #ifdef _MSC_VER
  581. #pragma comment(lib, _OLE_LIB)
  582. #endif
  583. #endif
  584. #include "../common/pglobalstatic.cxx"
  585. ///////////////////////////////////////////////////////////////////////////////
  586. // PTime
  587. PTime::PTime()
  588. {
  589. // Magic constant to convert epoch from 1601 to 1970
  590. static const PInt64 delta = ((PInt64)369*365+(369/4)-3)*24*60*60U;
  591. static const PInt64 scale = 10000000;
  592. PInt64 timestamp;
  593. #ifndef _WIN32_WCE
  594. GetSystemTimeAsFileTime((LPFILETIME)&timestamp);
  595. #else
  596. SYSTEMTIME SystemTime;
  597. GetSystemTime(&SystemTime);
  598. SystemTimeToFileTime(&SystemTime, (LPFILETIME)&timestamp);
  599. #endif
  600. theTime = (time_t)(timestamp/scale - delta);
  601. microseconds = (long)(timestamp%scale/10);
  602. }
  603. #ifdef UNICODE
  604. static void PWIN32GetLocaleInfo(LCID Locale,LCTYPE LCType,LPSTR lpLCData,int cchData)
  605. {
  606. TCHAR* pw = new TCHAR[cchData+1];
  607. GetLocaleInfo(Locale,LCType,pw,cchData);
  608. lpLCData[0]=0;
  609. WideCharToMultiByte(GetACP(), 0, pw, -1, lpLCData, cchData, NULL, NULL);
  610. }
  611. #else
  612. #define PWIN32GetLocaleInfo GetLocaleInfo
  613. #endif
  614. PString PTime::GetTimeSeparator()
  615. {
  616. PString str;
  617. PWIN32GetLocaleInfo(GetUserDefaultLCID(), LOCALE_STIME, str.GetPointer(100), 99);
  618. str.MakeMinimumSize();
  619. return str;
  620. }
  621. BOOL PTime::GetTimeAMPM()
  622. {
  623. char str[2];
  624. PWIN32GetLocaleInfo(GetUserDefaultLCID(), LOCALE_ITIME, str, sizeof(str));
  625. return str[0] == '0';
  626. }
  627. PString PTime::GetTimeAM()
  628. {
  629. PString str;
  630. PWIN32GetLocaleInfo(GetUserDefaultLCID(), LOCALE_S1159, str.GetPointer(100), 99);
  631. str.MakeMinimumSize();
  632. return str;
  633. }
  634. PString PTime::GetTimePM()
  635. {
  636. PString str;
  637. PWIN32GetLocaleInfo(GetUserDefaultLCID(), LOCALE_S2359, str.GetPointer(100), 99);
  638. str.MakeMinimumSize();
  639. return str;
  640. }
  641. PString PTime::GetDayName(Weekdays dayOfWeek, NameType type)
  642. {
  643. PString str;
  644. // Of course Sunday is 6 and Monday is 1...
  645. PWIN32GetLocaleInfo(GetUserDefaultLCID(), (dayOfWeek+6)%7 +
  646. (type == Abbreviated ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1),
  647. str.GetPointer(100), 99);
  648. str.MakeMinimumSize();
  649. return str;
  650. }
  651. PString PTime::GetDateSeparator()
  652. {
  653. PString str;
  654. PWIN32GetLocaleInfo(GetUserDefaultLCID(), LOCALE_SDATE, str.GetPointer(100), 99);
  655. str.MakeMinimumSize();
  656. return str;
  657. }
  658. PString PTime::GetMonthName(Months month, NameType type)
  659. {
  660. PString str;
  661. PWIN32GetLocaleInfo(GetUserDefaultLCID(), month-1 +
  662. (type == Abbreviated ? LOCALE_SABBREVMONTHNAME1 : LOCALE_SMONTHNAME1),
  663. str.GetPointer(100), 99);
  664. str.MakeMinimumSize();
  665. return str;
  666. }
  667. PTime::DateOrder PTime::GetDateOrder()
  668. {
  669. char str[2];
  670. PWIN32GetLocaleInfo(GetUserDefaultLCID(), LOCALE_IDATE, str, sizeof(str));
  671. return (DateOrder)(str[0] - '0');
  672. }
  673. BOOL PTime::IsDaylightSavings()
  674. {
  675. TIME_ZONE_INFORMATION tz;
  676. DWORD result = GetTimeZoneInformation(&tz);
  677. PAssertOS(result != 0xffffffff);
  678. return result == TIME_ZONE_ID_DAYLIGHT;
  679. }
  680. int PTime::GetTimeZone(TimeZoneType type)
  681. {
  682. TIME_ZONE_INFORMATION tz;
  683. PAssertOS(GetTimeZoneInformation(&tz) != 0xffffffff);
  684. if (type == DaylightSavings)
  685. tz.Bias += tz.DaylightBias;
  686. return -tz.Bias;
  687. }
  688. PString PTime::GetTimeZoneString(TimeZoneType type)
  689. {
  690. TIME_ZONE_INFORMATION tz;
  691. PAssertOS(GetTimeZoneInformation(&tz) != 0xffffffff);
  692. return (const WORD *)(type == StandardTime ? tz.StandardName : tz.DaylightName);
  693. }
  694. ///////////////////////////////////////////////////////////////////////////////
  695. // PTimeInterval
  696. static unsigned GetDivisor()
  697. {
  698. LARGE_INTEGER frequency;
  699. if (QueryPerformanceFrequency(&frequency))
  700. return (unsigned)frequency.QuadPart/1000;
  701. return 0;
  702. }
  703. PTimeInterval PTimer::Tick()
  704. {
  705. static unsigned divisor = GetDivisor();
  706. if (divisor == 0)
  707. return (int)(GetTickCount()&0x7fffffff);
  708. LARGE_INTEGER count;
  709. QueryPerformanceCounter(&count);
  710. return count.QuadPart/divisor;
  711. }
  712. unsigned PTimer::Resolution()
  713. {
  714. LARGE_INTEGER frequency;
  715. if (QueryPerformanceFrequency(&frequency) && frequency.QuadPart >= 1000)
  716. return 1;
  717. DWORD err = GetLastError();
  718. #ifndef _WIN32_WCE
  719. DWORD timeAdjustment;
  720. DWORD timeIncrement;
  721. BOOL timeAdjustmentDisabled;
  722. if (GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &timeAdjustmentDisabled))
  723. return timeIncrement/10000;
  724. err = GetLastError();
  725. #endif
  726. return 55;
  727. }
  728. ///////////////////////////////////////////////////////////////////////////////
  729. // Directories
  730. void PDirectory::Construct()
  731. {
  732. hFindFile = INVALID_HANDLE_VALUE;
  733. fileinfo.cFileName[0] = '\0';
  734. PCaselessString::AssignContents(CreateFullPath(*this, TRUE));
  735. }
  736. void PDirectory::CopyContents(const PDirectory & dir)
  737. {
  738. scanMask = dir.scanMask;
  739. hFindFile = INVALID_HANDLE_VALUE;
  740. fileinfo = dir.fileinfo;
  741. }
  742. BOOL PDirectory::Open(int newScanMask)
  743. {
  744. scanMask = newScanMask;
  745. #ifdef UNICODE
  746. USES_CONVERSION;
  747. hFindFile = FindFirstFile(A2T(operator+("*.*")), &fileinfo);
  748. #else
  749. hFindFile = FindFirstFile(operator+("*.*"), &fileinfo);
  750. #endif
  751. if (hFindFile == INVALID_HANDLE_VALUE)
  752. return FALSE;
  753. return Filtered() ? Next() : TRUE;
  754. }
  755. BOOL PDirectory::Next()
  756. {
  757. if (hFindFile == INVALID_HANDLE_VALUE)
  758. return FALSE;
  759. do {
  760. if (!FindNextFile(hFindFile, &fileinfo))
  761. return FALSE;
  762. } while (Filtered());
  763. return TRUE;
  764. }
  765. PCaselessString PDirectory::GetEntryName() const
  766. {
  767. return fileinfo.cFileName;
  768. }
  769. BOOL PDirectory::IsSubDir() const
  770. {
  771. return (fileinfo.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0;
  772. }
  773. PCaselessString PDirectory::GetVolume() const
  774. {
  775. #ifdef _WIN32_WCE
  776. return PCaselessString("\\");
  777. #else
  778. char volName[100];
  779. PAssertOS(GetVolumeInformation(NULL, volName, sizeof(volName), NULL, NULL, NULL, NULL, 0));
  780. return PCaselessString(volName);
  781. #endif
  782. }
  783. void PDirectory::Close()
  784. {
  785. if (hFindFile != INVALID_HANDLE_VALUE) {
  786. FindClose(hFindFile);
  787. hFindFile = INVALID_HANDLE_VALUE;
  788. }
  789. }
  790. PString PDirectory::CreateFullPath(const PString & path, BOOL isDirectory)
  791. {
  792. if (path.IsEmpty() && !isDirectory)
  793. return path;
  794. #ifdef _WIN32_WCE //doesn't support Current Directory so the path suppose to be full
  795. PString fullpath=path;
  796. PINDEX len = fullpath.GetLength();
  797. #else
  798. PString partialpath = path;
  799. // Look for special case of "\c:\" at start of string as some generalised
  800. // directory processing algorithms have a habit of adding a leading
  801. // PDIR_SEPARATOR as it would be for Unix.
  802. if (partialpath.NumCompare("\\\\\\") == EqualTo ||
  803. (partialpath.GetLength() > 3 &&
  804. partialpath[0] == PDIR_SEPARATOR &&
  805. partialpath[2] == ':'))
  806. partialpath.Delete(0, 1);
  807. LPSTR dummy;
  808. PString fullpath;
  809. PINDEX len = (PINDEX)GetFullPathName(partialpath,
  810. _MAX_PATH, fullpath.GetPointer(_MAX_PATH), &dummy);
  811. #endif
  812. if (isDirectory && len > 0 && fullpath[len-1] != PDIR_SEPARATOR)
  813. fullpath += PDIR_SEPARATOR;
  814. PINDEX pos = 0;
  815. while ((pos = fullpath.Find('/', pos)) != P_MAX_INDEX)
  816. fullpath[pos] = PDIR_SEPARATOR;
  817. return fullpath;
  818. }
  819. typedef BOOL (WINAPI *GetDiskFreeSpaceExType)(LPCTSTR lpDirectoryName,
  820. PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  821. PULARGE_INTEGER lpTotalNumberOfBytes,
  822. PULARGE_INTEGER lpTotalNumberOfFreeBytes);
  823. BOOL PDirectory::GetVolumeSpace(PInt64 & total, PInt64 & free, DWORD & clusterSize) const
  824. {
  825. clusterSize = 512;
  826. total = free = ULONG_MAX;
  827. PString root;
  828. if ((*this)[1] == ':')
  829. root = Left(3);
  830. else if (theArray[0] == '\\' && theArray[1] == '\\') {
  831. PINDEX backslash = Find('\\', 2);
  832. if (backslash != P_MAX_INDEX) {
  833. backslash = Find('\\', backslash+1);
  834. if (backslash != P_MAX_INDEX)
  835. root = Left(backslash+1);
  836. }
  837. }
  838. if (root.IsEmpty())
  839. return FALSE;
  840. #ifndef _WIN32_WCE
  841. BOOL needTotalAndFree = TRUE;
  842. static GetDiskFreeSpaceExType GetDiskFreeSpaceEx =
  843. (GetDiskFreeSpaceExType)GetProcAddress(LoadLibrary("KERNEL32.DLL"), "GetDiskFreeSpaceExA");
  844. if (GetDiskFreeSpaceEx != NULL) {
  845. ULARGE_INTEGER freeBytesAvailableToCaller;
  846. ULARGE_INTEGER totalNumberOfBytes;
  847. ULARGE_INTEGER totalNumberOfFreeBytes;
  848. if (GetDiskFreeSpaceEx(root,
  849. &freeBytesAvailableToCaller,
  850. &totalNumberOfBytes,
  851. &totalNumberOfFreeBytes)) {
  852. total = totalNumberOfBytes.QuadPart;
  853. free = totalNumberOfFreeBytes.QuadPart;
  854. needTotalAndFree = FALSE;
  855. }
  856. }
  857. clusterSize = 0;
  858. char fsName[100];
  859. if (GetVolumeInformation(root, NULL, 0, NULL, NULL, NULL, fsName, sizeof(fsName))) {
  860. if (stricmp(fsName, "FAT32") == 0) {
  861. clusterSize = 4096; // Cannot use GetDiskFreeSpace() results for FAT32
  862. if (!needTotalAndFree)
  863. return TRUE;
  864. }
  865. }
  866. DWORD sectorsPerCluster; // address of sectors per cluster
  867. DWORD bytesPerSector; // address of bytes per sector
  868. DWORD numberOfFreeClusters; // address of number of free clusters
  869. DWORD totalNumberOfClusters; // address of total number of clusters
  870. if (!GetDiskFreeSpace(root,
  871. &sectorsPerCluster,
  872. &bytesPerSector,
  873. &numberOfFreeClusters,
  874. &totalNumberOfClusters))
  875. {
  876. if (root[0] != '\\' || ::GetLastError() != ERROR_NOT_SUPPORTED)
  877. return FALSE;
  878. PString drive = "A:";
  879. while (WNetAddConnection(root, NULL, drive) != NO_ERROR) {
  880. if (GetLastError() != ERROR_ALREADY_ASSIGNED)
  881. return FALSE;
  882. drive[0]++;
  883. }
  884. BOOL ok = GetDiskFreeSpace(drive+'\\',
  885. &sectorsPerCluster,
  886. &bytesPerSector,
  887. &numberOfFreeClusters,
  888. &totalNumberOfClusters);
  889. WNetCancelConnection(drive, TRUE);
  890. if (!ok)
  891. return FALSE;
  892. }
  893. if (needTotalAndFree) {
  894. free = numberOfFreeClusters*sectorsPerCluster*bytesPerSector;
  895. total = totalNumberOfClusters*sectorsPerCluster*bytesPerSector;
  896. }
  897. if (clusterSize == 0)
  898. clusterSize = bytesPerSector*sectorsPerCluster;
  899. return TRUE;
  900. #elif _WIN32_WCE < 300
  901. USES_CONVERSION;
  902. ULARGE_INTEGER freeBytesAvailableToCaller;
  903. ULARGE_INTEGER totalNumberOfBytes;
  904. ULARGE_INTEGER totalNumberOfFreeBytes;
  905. if (GetDiskFreeSpaceEx(A2T(root),
  906. &freeBytesAvailableToCaller,
  907. &totalNumberOfBytes,
  908. &totalNumberOfFreeBytes))
  909. {
  910. total = totalNumberOfBytes.QuadPart;
  911. free = totalNumberOfFreeBytes.QuadPart;
  912. clusterSize = 512; //X3
  913. return TRUE;
  914. }
  915. return FALSE;
  916. #else
  917. return FALSE;
  918. #endif
  919. }
  920. ///////////////////////////////////////////////////////////////////////////////
  921. // PFilePath
  922. static PString IllegalFilenameCharacters =
  923. "\\/:*?\"<>|"
  924. "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\0x10"
  925. "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
  926. BOOL PFilePath::IsValid(char c)
  927. {
  928. return IllegalFilenameCharacters.Find(c) == P_MAX_INDEX;
  929. }
  930. BOOL PFilePath::IsValid(const PString & str)
  931. {
  932. return str != "." && str != ".." &&
  933. str.FindOneOf(IllegalFilenameCharacters) == P_MAX_INDEX;
  934. }
  935. ///////////////////////////////////////////////////////////////////////////////
  936. // PChannel
  937. PString PChannel::GetErrorText(Errors lastError, int osError)
  938. {
  939. if (osError == 0) {
  940. if (lastError == NoError)
  941. return PString();
  942. static int const errors[NumNormalisedErrors] = {
  943. 0, ENOENT, EEXIST, ENOSPC, EACCES, EBUSY, EINVAL, ENOMEM, EBADF, EAGAIN, EINTR,
  944. WSAEMSGSIZE|PWIN32ErrorFlag, EIO, 0x1000000|PWIN32ErrorFlag
  945. };
  946. osError = errors[lastError];
  947. }
  948. #ifndef _WIN32_WCE
  949. if (osError > 0 && osError < _sys_nerr && _sys_errlist[osError][0] != '\0')
  950. return _sys_errlist[osError];
  951. #endif
  952. if ((osError & PWIN32ErrorFlag) == 0)
  953. return psprintf("C runtime error %u", osError);
  954. DWORD err = osError & ~PWIN32ErrorFlag;
  955. static const struct {
  956. DWORD id;
  957. const char * msg;
  958. } win32_errlist[] = {
  959. { ERROR_FILE_NOT_FOUND, "File not found" },
  960. { ERROR_PATH_NOT_FOUND, "Path not found" },
  961. { ERROR_ACCESS_DENIED, "Access denied" },
  962. { ERROR_NOT_ENOUGH_MEMORY, "Not enough memory" },
  963. { ERROR_INVALID_FUNCTION, "Invalid function" },
  964. { WSAEADDRINUSE, "Address in use" },
  965. { WSAENETDOWN, "Network subsystem failed" },
  966. { WSAEISCONN, "Socket is already connected" },
  967. { WSAENETUNREACH, "Network unreachable" },
  968. { WSAEHOSTUNREACH, "Host unreachable" },
  969. { WSAECONNREFUSED, "Connection refused" },
  970. { WSAEINVAL, "Invalid operation" },
  971. { WSAENOTCONN, "Socket not connected" },
  972. { WSAECONNABORTED, "Connection aborted" },
  973. { WSAECONNRESET, "Connection reset" },
  974. { WSAESHUTDOWN, "Connection shutdown" },
  975. { WSAENOTSOCK, "Socket closed or invalid" },
  976. { WSAETIMEDOUT, "Timed out" },
  977. { WSAEMSGSIZE, "Message larger than buffer" },
  978. { WSAEWOULDBLOCK, "Would block" },
  979. { 0x1000000, "High level protocol failure" }
  980. };
  981. for (PINDEX i = 0; i < PARRAYSIZE(win32_errlist); i++)
  982. if (win32_errlist[i].id == err)
  983. return win32_errlist[i].msg;
  984. return psprintf("WIN32 error %u", err);
  985. }
  986. BOOL PChannel::ConvertOSError(int status, Errors & lastError, int & osError)
  987. {
  988. if (status >= 0) {
  989. lastError = NoError;
  990. osError = 0;
  991. return TRUE;
  992. }
  993. if (status != -2)
  994. osError = errno;
  995. else {
  996. osError = GetLastError();
  997. switch (osError) {
  998. case ERROR_INVALID_HANDLE :
  999. case WSAEBADF :
  1000. osError = EBADF;
  1001. break;
  1002. case ERROR_INVALID_PARAMETER :
  1003. case WSAEINVAL :
  1004. osError = EINVAL;
  1005. break;
  1006. case ERROR_ACCESS_DENIED :
  1007. case WSAEACCES :
  1008. osError = EACCES;
  1009. break;
  1010. case ERROR_NOT_ENOUGH_MEMORY :
  1011. osError = ENOMEM;
  1012. break;
  1013. case WSAEINTR :
  1014. osError = EINTR;
  1015. break;
  1016. case WSAEMSGSIZE :
  1017. osError |= PWIN32ErrorFlag;
  1018. lastError = BufferTooSmall;
  1019. return FALSE;
  1020. case WSAEWOULDBLOCK :
  1021. case WSAETIMEDOUT :
  1022. osError |= PWIN32ErrorFlag;
  1023. lastError = Timeout;
  1024. return FALSE;
  1025. default :
  1026. osError |= PWIN32ErrorFlag;
  1027. }
  1028. }
  1029. switch (osError) {
  1030. case 0 :
  1031. lastError = NoError;
  1032. return TRUE;
  1033. case ENOENT :
  1034. lastError = NotFound;
  1035. break;
  1036. case EEXIST :
  1037. lastError = FileExists;
  1038. break;
  1039. case EACCES :
  1040. lastError = AccessDenied;
  1041. break;
  1042. case ENOMEM :
  1043. lastError = NoMemory;
  1044. break;
  1045. case ENOSPC :
  1046. lastError = DiskFull;
  1047. break;
  1048. case EINVAL :
  1049. lastError = BadParameter;
  1050. break;
  1051. case EBADF :
  1052. lastError = NotOpen;
  1053. break;
  1054. case EAGAIN :
  1055. lastError = Timeout;
  1056. break;
  1057. case EINTR :
  1058. lastError = Interrupted;
  1059. break;
  1060. default :
  1061. lastError = Miscellaneous;
  1062. }
  1063. return FALSE;
  1064. }
  1065. ///////////////////////////////////////////////////////////////////////////////
  1066. // PWin32Overlapped
  1067. PWin32Overlapped::PWin32Overlapped()
  1068. {
  1069. memset(this, 0, sizeof(*this));
  1070. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1071. }
  1072. PWin32Overlapped::~PWin32Overlapped()
  1073. {
  1074. if (hEvent != NULL)
  1075. CloseHandle(hEvent);
  1076. }
  1077. void PWin32Overlapped::Reset()
  1078. {
  1079. Offset = OffsetHigh = 0;
  1080. if (hEvent != NULL)
  1081. ResetEvent(hEvent);
  1082. }
  1083. ///////////////////////////////////////////////////////////////////////////////
  1084. // Threads
  1085. UINT __stdcall PThread::MainFunction(void * threadPtr)
  1086. {
  1087. PThread * thread = (PThread *)PAssertNULL(threadPtr);
  1088. thread->SetThreadName(thread->GetThreadName());
  1089. PProcess & process = PProcess::Current();
  1090. /*
  1091. * Removed this code because it causes a linear increase
  1092. * in thread startup time when there are many (< 500) threads.
  1093. * If this functionality is needed, call Win32AttachThreadInput
  1094. * after the thread has been started
  1095. *
  1096. #ifndef _WIN32_WCE
  1097. AttachThreadInput(thread->threadId, ((PThread&)process).threadId, TRUE);
  1098. AttachThreadInput(((PThread&)process).threadId, thread->threadId, TRUE);
  1099. #endif
  1100. */
  1101. process.activeThreadMutex.Wait();
  1102. process.activeThreads.SetAt(thread->threadId, thread);
  1103. process.activeThreadMutex.Signal();
  1104. process.SignalTimerChange();
  1105. #if defined(_WIN32_DCOM)
  1106. ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1107. #endif
  1108. thread->Main();
  1109. #if defined(_WIN32_DCOM)
  1110. ::CoUninitialize();
  1111. #endif
  1112. return 0;
  1113. }
  1114. void PThread::Win32AttachThreadInput()
  1115. {
  1116. #ifndef _WIN32_WCE
  1117. PProcess & process = PProcess::Current();
  1118. ::AttachThreadInput(threadId, ((PThread&)process).threadId, TRUE);
  1119. ::AttachThreadInput(((PThread&)process).threadId, threadId, TRUE);
  1120. #endif
  1121. }
  1122. PThread::PThread(PINDEX stackSize,
  1123. AutoDeleteFlag deletion,
  1124. Priority priorityLevel,
  1125. const PString & name)
  1126. : threadName(name)
  1127. {
  1128. PAssert(stackSize > 0, PInvalidParameter);
  1129. originalStackSize = stackSize;
  1130. autoDelete = deletion == AutoDeleteThread;
  1131. #ifndef _WIN32_WCE
  1132. threadHandle = (HANDLE)_beginthreadex(NULL, stackSize, MainFunction,
  1133. this, CREATE_SUSPENDED, &threadId);
  1134. #else
  1135. threadHandle = CreateThread(NULL, stackSize,
  1136. (LPTHREAD_START_ROUTINE)MainFunction,
  1137. this, CREATE_SUSPENDED, (LPDWORD) &threadId);
  1138. #endif
  1139. PAssertOS(threadHandle != NULL);
  1140. SetPriority(priorityLevel);
  1141. traceBlockIndentLevel = 0;
  1142. if (autoDelete) {
  1143. PProcess & process = PProcess::Current();
  1144. process.deleteThreadMutex.Wait();
  1145. process.autoDeleteThreads.Append(this);
  1146. process.deleteThreadMutex.Signal();
  1147. }
  1148. }
  1149. PThread::~PThread()
  1150. {
  1151. if (originalStackSize <= 0)
  1152. return;
  1153. PProcess & process = PProcess::Current();
  1154. process.activeThreadMutex.Wait();
  1155. process.activeThreads.SetAt(threadId, NULL);
  1156. process.activeThreadMutex.Signal();
  1157. if (!IsTerminated())
  1158. Terminate();
  1159. if (threadHandle != NULL)
  1160. CloseHandle(threadHandle);
  1161. }
  1162. void PThread::Restart()
  1163. {
  1164. PAssert(IsTerminated(), "Cannot restart running thread");
  1165. #ifndef _WIN32_WCE
  1166. threadHandle = (HANDLE)_beginthreadex(NULL,
  1167. originalStackSize, MainFunction, this, 0, &threadId);
  1168. #else
  1169. threadHandle = CreateThread(NULL, originalStackSize,
  1170. (LPTHREAD_START_ROUTINE) MainFunction,
  1171. this, 0, (LPDWORD) &threadId);
  1172. #endif
  1173. PAssertOS(threadHandle != NULL);
  1174. }
  1175. void PThread::Terminate()
  1176. {
  1177. PAssert(originalStackSize > 0, PLogicError);
  1178. if (Current() == this)
  1179. ExitThread(0);
  1180. else
  1181. TerminateThread(threadHandle, 1);
  1182. }
  1183. BOOL PThread::IsTerminated() const
  1184. {
  1185. if (this == PThread::Current())
  1186. return FALSE;
  1187. return WaitForTermination(0);
  1188. }
  1189. void PThread::WaitForTermination() const
  1190. {
  1191. WaitForTermination(PMaxTimeInterval);
  1192. }
  1193. BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
  1194. {
  1195. if ((this == PThread::Current()) || threadHandle == NULL) {
  1196. PTRACE(2, "WaitForTermination short circuited");
  1197. return TRUE;
  1198. }
  1199. DWORD result;
  1200. PINDEX retries = 10;
  1201. while ((result = WaitForSingleObject(threadHandle, maxWait.GetInterval())) != WAIT_TIMEOUT) {
  1202. if (result == WAIT_OBJECT_0)
  1203. return TRUE;
  1204. if (::GetLastError() != ERROR_INVALID_HANDLE) {
  1205. PAssertAlways(POperatingSystemError);
  1206. return TRUE;
  1207. }
  1208. if (retries == 0)
  1209. return TRUE;
  1210. retries--;
  1211. }
  1212. return FALSE;
  1213. }
  1214. void PThread::Suspend(BOOL susp)
  1215. {
  1216. PAssert(!IsTerminated(), "Operation on terminated thread");
  1217. if (susp)
  1218. SuspendThread(threadHandle);
  1219. else
  1220. Resume();
  1221. }
  1222. void PThread::Resume()
  1223. {
  1224. PAssert(!IsTerminated(), "Operation on terminated thread");
  1225. ResumeThread(threadHandle);
  1226. }
  1227. BOOL PThread::IsSuspended() const
  1228. {
  1229. SuspendThread(threadHandle);
  1230. return ResumeThread(threadHandle) > 1;
  1231. }
  1232. void PThread::SetAutoDelete(AutoDeleteFlag deletion)
  1233. {
  1234. PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
  1235. PProcess & process = PProcess::Current();
  1236. if (autoDelete && deletion != AutoDeleteThread) {
  1237. process.deleteThreadMutex.Wait();
  1238. process.autoDeleteThreads.DisallowDeleteObjects();
  1239. process.autoDeleteThreads.Remove(this);
  1240. process.autoDeleteThreads.AllowDeleteObjects();
  1241. process.deleteThreadMutex.Signal();
  1242. }
  1243. else if (!autoDelete && deletion == AutoDeleteThread) {
  1244. process.deleteThreadMutex.Wait();
  1245. process.autoDeleteThreads.Append(this);
  1246. process.deleteThreadMutex.Signal();
  1247. }
  1248. autoDelete = deletion == AutoDeleteThread;
  1249. }
  1250. #if !defined(_WIN32_WCE) || (_WIN32_WCE < 300)
  1251. #define PTHREAD_PRIORITY_LOWEST THREAD_PRIORITY_LOWEST
  1252. #define PTHREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_BELOW_NORMAL
  1253. #define PTHREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
  1254. #define PTHREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_ABOVE_NORMAL
  1255. #define PTHREAD_PRIORITY_HIGHEST THREAD_PRIORITY_HIGHEST
  1256. #else
  1257. #define PTHREAD_PRIORITY_LOWEST 243
  1258. #define PTHREAD_PRIORITY_BELOW_NORMAL 245
  1259. #define PTHREAD_PRIORITY_NORMAL 247
  1260. #define PTHREAD_PRIORITY_ABOVE_NORMAL 249
  1261. #define PTHREAD_PRIORITY_HIGHEST 251
  1262. #endif
  1263. void PThread::SetPriority(Priority priorityLevel)
  1264. {
  1265. PAssert(!IsTerminated(), "Operation on terminated thread");
  1266. static int const priorities[NumPriorities] = {
  1267. PTHREAD_PRIORITY_LOWEST,
  1268. PTHREAD_PRIORITY_BELOW_NORMAL,
  1269. PTHREAD_PRIORITY_NORMAL,
  1270. PTHREAD_PRIORITY_ABOVE_NORMAL,
  1271. PTHREAD_PRIORITY_HIGHEST
  1272. };
  1273. SetThreadPriority(threadHandle, priorities[priorityLevel]);
  1274. }
  1275. PThread::Priority PThread::GetPriority() const
  1276. {
  1277. PAssert(!IsTerminated(), "Operation on terminated thread");
  1278. switch (GetThreadPriority(threadHandle)) {
  1279. case PTHREAD_PRIORITY_LOWEST :
  1280. return LowestPriority;
  1281. case PTHREAD_PRIORITY_BELOW_NORMAL :
  1282. return LowPriority;
  1283. case PTHREAD_PRIORITY_NORMAL :
  1284. return NormalPriority;
  1285. case PTHREAD_PRIORITY_ABOVE_NORMAL :
  1286. return HighPriority;
  1287. case PTHREAD_PRIORITY_HIGHEST :
  1288. return HighestPriority;
  1289. }
  1290. PAssertAlways(POperatingSystemError);
  1291. return LowestPriority;
  1292. }
  1293. void PThread::Yield()
  1294. {
  1295. ::Sleep(0);
  1296. }
  1297. void PThread::InitialiseProcessThread()
  1298. {
  1299. originalStackSize = 0;
  1300. autoDelete = FALSE;
  1301. threadHandle = GetCurrentThread();
  1302. threadId = GetCurrentThreadId();
  1303. ((PProcess *)this)->activeThreads.DisallowDeleteObjects();
  1304. ((PProcess *)this)->activeThreads.SetAt(threadId, this);
  1305. traceBlockIndentLevel = 0;
  1306. }
  1307. PThread * PThread::Current()
  1308. {
  1309. PProcess & process = PProcess::Current();
  1310. process.activeThreadMutex.Wait();
  1311. PThread * thread = process.activeThreads.GetAt(GetCurrentThreadId());
  1312. process.activeThreadMutex.Signal();
  1313. return thread;
  1314. }
  1315. ///////////////////////////////////////////////////////////////////////////////
  1316. // PProcess::TimerThread
  1317. PProcess::HouseKeepingThread::HouseKeepingThread()
  1318. : PThread(1000, NoAutoDeleteThread, NormalPriority, "PWLib Housekeeper")
  1319. {
  1320. Resume();
  1321. }
  1322. void PProcess::HouseKeepingThread::Main()
  1323. {
  1324. PProcess & process = PProcess::Current();
  1325. for (;;) {
  1326. // collect a list of thread handles to check, and clean up
  1327. // handles for threads that disappeared without telling us
  1328. process.deleteThreadMutex.Wait();
  1329. HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  1330. DWORD numHandles = 1;
  1331. DWORD dwFlags;
  1332. handles[0] = breakBlock.GetHandle();
  1333. for (PINDEX i = 0; i < process.autoDeleteThreads.GetSize(); i++) {
  1334. PThread & thread = process.autoDeleteThreads[i];
  1335. if (thread.IsTerminated())
  1336. process.autoDeleteThreads.RemoveAt(i--);
  1337. else {
  1338. handles[numHandles] = thread.GetHandle();
  1339. // make sure we don't put invalid handles into the list
  1340. #ifndef _WIN32_WCE
  1341. if (GetHandleInformation(handles[numHandles], &dwFlags) == 0) {
  1342. PTRACE(2, "Refused to put invalid handle into wait list");
  1343. }
  1344. else
  1345. #endif
  1346. // don't put the handle for the current process in the list
  1347. if (handles[numHandles] != process.GetHandle()) {
  1348. numHandles++;
  1349. if (numHandles >= MAXIMUM_WAIT_OBJECTS)
  1350. break;
  1351. }
  1352. }
  1353. }
  1354. process.deleteThreadMutex.Signal();
  1355. PTimeInterval nextTimer = process.timers.Process();
  1356. DWORD delay;
  1357. if (nextTimer == PMaxTimeInterval)
  1358. delay = INFINITE;
  1359. else if (nextTimer > 1000)
  1360. delay = 1000;
  1361. else
  1362. delay = nextTimer.GetInterval();
  1363. DWORD result;
  1364. int retries = 100;
  1365. while ((result = WaitForMultipleObjects(numHandles, handles, FALSE, delay)) == WAIT_FAILED) {
  1366. // if we get an invalid handle error, than assume this is because a thread ended between
  1367. // creating the handle list and testing it. So, cleanup the list before calling
  1368. // WaitForMultipleObjects again
  1369. if (::GetLastError() == ERROR_INVALID_HANDLE)
  1370. break;
  1371. // sometimes WaitForMultipleObjects fails. No idea why, so allow some retries
  1372. else {
  1373. retries--;
  1374. if (retries <= 0)
  1375. break;
  1376. }
  1377. }
  1378. }
  1379. }
  1380. void PProcess::SignalTimerChange()
  1381. {
  1382. deleteThreadMutex.Wait();
  1383. if (houseKeeper == NULL)
  1384. houseKeeper = new HouseKeepingThread;
  1385. else
  1386. houseKeeper->breakBlock.Signal();
  1387. deleteThreadMutex.Signal();
  1388. }
  1389. ///////////////////////////////////////////////////////////////////////////////
  1390. // PProcess
  1391. PProcess::~PProcess()
  1392. {
  1393. // do whatever needs to shutdown
  1394. PreShutdown();
  1395. Sleep(100); // Give threads time to die a natural death
  1396. // Get rid of the house keeper (majordomocide)
  1397. delete houseKeeper;
  1398. // OK, if there are any left we get really insistent...
  1399. activeThreadMutex.Wait();
  1400. for (PINDEX i = 0; i < activeThreads.GetSize(); i++) {
  1401. PThread & thread = activeThreads.GetDataAt(i);
  1402. if (this != &thread && !thread.IsTerminated())
  1403. TerminateThread(thread.GetHandle(), 1); // With extreme prejudice
  1404. }
  1405. activeThreadMutex.Signal();
  1406. deleteThreadMutex.Wait();
  1407. autoDeleteThreads.RemoveAll();
  1408. deleteThreadMutex.Signal();
  1409. #if PMEMORY_CHECK || _DEBUG
  1410. extern void PWaitOnExitConsoleWindow();
  1411. PWaitOnExitConsoleWindow();
  1412. #endif
  1413. }
  1414. PString PProcess::GetOSClass()
  1415. {
  1416. return "Windows";
  1417. }
  1418. PString PProcess::GetOSName()
  1419. {
  1420. OSVERSIONINFO info;
  1421. info.dwOSVersionInfoSize = sizeof(info);
  1422. GetVersionEx(&info);
  1423. switch (info.dwPlatformId) {
  1424. case VER_PLATFORM_WIN32s :
  1425. return "32s";
  1426. #ifdef VER_PLATFORM_WIN32_CE
  1427. case VER_PLATFORM_WIN32_CE :
  1428. return "CE";
  1429. #endif
  1430. case VER_PLATFORM_WIN32_WINDOWS :
  1431. if (info.dwMinorVersion < 10)
  1432. return "95";
  1433. if (info.dwMinorVersion < 90)
  1434. return "98";
  1435. return "ME";
  1436. case VER_PLATFORM_WIN32_NT :
  1437. if (info.dwMajorVersion < 5)
  1438. return "NT";
  1439. else if (info.dwMinorVersion == 0)
  1440. return "2000";
  1441. else if (info.dwMinorVersion == 1)
  1442. return "XP";
  1443. else
  1444. return "Server 2003";
  1445. }
  1446. return "?";
  1447. }
  1448. PString PProcess::GetOSHardware()
  1449. {
  1450. SYSTEM_INFO info;
  1451. GetSystemInfo(&info);
  1452. switch (info.wProcessorArchitecture) {
  1453. case PROCESSOR_ARCHITECTURE_INTEL :
  1454. switch (info.dwProcessorType) {
  1455. case PROCESSOR_INTEL_386 :
  1456. return "i386";
  1457. case PROCESSOR_INTEL_486 :
  1458. return "i486";
  1459. case PROCESSOR_INTEL_PENTIUM :
  1460. return "i586";
  1461. }
  1462. return "iX86";
  1463. case PROCESSOR_ARCHITECTURE_MIPS :
  1464. return "mips";
  1465. case PROCESSOR_ARCHITECTURE_ALPHA :
  1466. return "alpha";
  1467. case PROCESSOR_ARCHITECTURE_PPC :
  1468. return "ppc";
  1469. }
  1470. return "?";
  1471. }
  1472. PString PProcess::GetOSVersion()
  1473. {
  1474. OSVERSIONINFO info;
  1475. info.dwOSVersionInfoSize = sizeof(info);
  1476. GetVersionEx(&info);
  1477. WORD wBuildNumber = (WORD)info.dwBuildNumber;
  1478. return psprintf(wBuildNumber > 0 ? "v%u.%u.%u" : "v%u.%u",
  1479. info.dwMajorVersion, info.dwMinorVersion, wBuildNumber);
  1480. }
  1481. PDirectory PProcess::GetOSConfigDir()
  1482. {
  1483. #ifdef _WIN32_WCE
  1484. return PString("\\Windows");
  1485. #else
  1486. OSVERSIONINFO info;
  1487. info.dwOSVersionInfoSize = sizeof(info);
  1488. GetVersionEx(&info);
  1489. char dir[_MAX_PATH];
  1490. if (info.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  1491. PAssertOS(GetWindowsDirectory(dir, sizeof(dir)) != 0);
  1492. return dir;
  1493. }
  1494. PAssertOS(GetSystemDirectory(dir, sizeof(dir)) != 0);
  1495. PDirectory sysdir = dir;
  1496. return sysdir; //+ "drivers\\etc";
  1497. #endif
  1498. }
  1499. PString PProcess::GetUserName() const
  1500. {
  1501. PString username;
  1502. unsigned long size = 50;
  1503. #ifndef _WIN32_WCE
  1504. ::GetUserName(usern

Large files files are truncated, but you can click here to view the full file