win32.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:40k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  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.91  2000/04/05 02:50:18  robertj
  31.  * Added microseconds to PTime class.
  32.  *
  33.  * Revision 1.90  2000/03/29 04:31:59  robertj
  34.  * Removed assertion on terminating terminated thread, this is really OK.
  35.  *
  36.  * Revision 1.89  2000/03/04 08:07:27  robertj
  37.  * Fixed problem with window not appearing when assert on GUI based win32 apps.
  38.  *
  39.  * Revision 1.88  2000/02/29 12:26:15  robertj
  40.  * Added named threads to tracing, thanks to Dave Harvey
  41.  *
  42.  * Revision 1.87  2000/01/06 14:09:42  robertj
  43.  * Fixed problems with starting up timers,losing up to 10 seconds
  44.  *
  45.  * Revision 1.86  1999/11/18 02:22:53  robertj
  46.  * Fixed bug in GetErrorText() occasionally returning incorrect empty string, thanks Ulrich Findeisen
  47.  *
  48.  * Revision 1.85  1999/07/06 13:37:07  robertj
  49.  * Fixed bug in PThread::IsSuspended(), returned exactly the opposite state!
  50.  *
  51.  * Revision 1.84  1999/07/06 04:46:01  robertj
  52.  * Fixed being able to case an unsigned to a PTimeInterval.
  53.  * Improved resolution of PTimer::Tick() to be millisecond accurate.
  54.  *
  55.  * Revision 1.83  1999/03/09 10:30:19  robertj
  56.  * Fixed ability to have PMEMORY_CHECK on/off on both debug/release versions.
  57.  *
  58.  * Revision 1.82  1999/03/09 08:19:15  robertj
  59.  * Adjustment found during documentation frenzy.
  60.  *
  61.  * Revision 1.81  1999/02/12 01:01:57  craigs
  62.  * Fixed problem with linking static versions of libraries
  63.  *
  64.  * Revision 1.80  1999/01/30 14:28:25  robertj
  65.  * Added GetOSConfigDir() function.
  66.  *
  67.  * Revision 1.79  1999/01/16 02:00:29  robertj
  68.  * Added hardware description funtion.
  69.  *
  70.  * Revision 1.78  1998/12/04 10:10:47  robertj
  71.  * Added virtual for determining if process is a service. Fixes linkage problem.
  72.  *
  73.  * Revision 1.77  1998/11/30 07:31:18  robertj
  74.  * New directory structure
  75.  * Fission of file into pipe.cxx, winserial.cxx and wincfg.cxx
  76.  *
  77.  * Revision 1.76  1998/11/26 10:35:08  robertj
  78.  * Improved support of FAT32 and large NTFS volumes in GetFreeSpace().
  79.  *
  80.  * Revision 1.75  1998/11/20 03:17:19  robertj
  81.  * Added thread WaitForTermination() function.
  82.  *
  83.  * Revision 1.74  1998/11/19 05:19:53  robertj
  84.  * Bullet proofed WaitForMultipleObjects under 95.
  85.  *
  86.  * Revision 1.73  1998/11/02 10:07:20  robertj
  87.  * Added capability of pip output to go to stdout/stderr.
  88.  *
  89.  * Revision 1.72  1998/10/31 12:50:47  robertj
  90.  * Removed ability to start threads immediately, race condition with vtable (Main() function).
  91.  * Rearranged PPipChannel functions to help with multi-platform-ness.
  92.  *
  93.  * Revision 1.71  1998/10/29 11:29:20  robertj
  94.  * Added ability to set environment in sub-process.
  95.  *
  96.  * Revision 1.70  1998/10/28 00:59:12  robertj
  97.  * Fixed problem when reading standard error from pipe channel, no terminating null on string.
  98.  *
  99.  * Revision 1.69  1998/10/26 09:11:31  robertj
  100.  * Added ability to separate out stdout from stderr on pipe channels.
  101.  *
  102.  * Revision 1.68  1998/10/15 02:20:26  robertj
  103.  * Added message for connection aborted error.
  104.  *
  105.  * Revision 1.67  1998/10/13 14:13:36  robertj
  106.  * Removed uneeded heap allocation.
  107.  *
  108.  * Revision 1.66  1998/09/24 03:30:59  robertj
  109.  * Added open software license.
  110.  *
  111.  * Revision 1.65  1998/09/18 13:56:20  robertj
  112.  * Added support of REG_BINARY registry types in PConfig class.
  113.  *
  114.  * Revision 1.64  1998/08/20 06:05:28  robertj
  115.  * Allowed Win32 class to be used in other compilation modules
  116.  *
  117.  * Revision 1.63  1998/04/01 01:52:42  robertj
  118.  * Fixed problem with NoAutoDelete threads.
  119.  *
  120.  * Revision 1.62  1998/03/29 06:16:56  robertj
  121.  * Rearranged initialisation sequence so PProcess descendent constructors can do "things".
  122.  *
  123.  * Revision 1.61  1998/03/27 10:52:39  robertj
  124.  * Fixed crash bug in win95 OSR2 GetVolumeSpace().
  125.  * Fixed error 87 problem with threads.
  126.  * Fixed GetVolumeSpace() when UNC used.
  127.  *
  128.  * Revision 1.60  1998/03/20 03:19:49  robertj
  129.  * Added special classes for specific sepahores, PMutex and PSyncPoint.
  130.  *
  131.  * Revision 1.59  1998/03/17 10:17:09  robertj
  132.  * Fixed problem with viewing registry entries where the section ends with a .
  133.  *
  134.  * Revision 1.58  1998/03/09 11:17:38  robertj
  135.  * FAT32 compatibility
  136.  *
  137.  * Revision 1.57  1998/03/05 12:48:37  robertj
  138.  * Fixed bug in get free space on volume.
  139.  * Added cluster size.
  140.  * MemCheck fixes.
  141.  *
  142.  * Revision 1.56  1998/02/16 00:10:45  robertj
  143.  * Added function to open a URL in a browser.
  144.  * Added functions to validate characters in a filename.
  145.  *
  146.  * Revision 1.55  1998/01/26 00:57:09  robertj
  147.  * Fixed uninitialised source in PConfig when getting environment.
  148.  *
  149.  * Revision 1.54  1997/08/28 12:50:21  robertj
  150.  * Fixed race condition in cleaning up threads on application termination.
  151.  *
  152.  * Revision 1.53  1997/08/21 13:27:41  robertj
  153.  * Attempt to fix very slight possibility of endless loop in housekeeping thread.
  154.  *
  155.  * Revision 1.52  1997/08/21 12:44:56  robertj
  156.  * Removed extension from DLL "short" name.
  157.  *
  158.  * Revision 1.51  1997/08/07 11:57:42  robertj
  159.  * Added ability to get registry data from other applications and anywhere in system registry.
  160.  *
  161.  * Revision 1.50  1997/08/04 10:38:43  robertj
  162.  * Fixed infamous error 87 assert failure in housekeeping thread.
  163.  *
  164.  * Revision 1.49  1997/07/14 11:47:22  robertj
  165.  * Added "const" to numerous variables.
  166.  *
  167.  * Revision 1.48  1997/06/16 13:15:53  robertj
  168.  * Added function to get a dyna-link libraries name.
  169.  *
  170.  * Revision 1.47  1997/06/08 04:42:41  robertj
  171.  * Added DLL file extension string function.
  172.  *
  173.  * Revision 1.46  1997/03/28 04:36:30  robertj
  174.  * Added assert for error in thread cleanup wait.
  175.  *
  176.  * Revision 1.45  1997/02/05 11:50:58  robertj
  177.  * Changed current process function to return reference and validate objects descendancy.
  178.  *
  179.  * Revision 1.44  1997/01/12 04:24:16  robertj
  180.  * Added function to get disk size and free space.
  181.  *
  182.  * Revision 1.43  1997/01/01 11:17:06  robertj
  183.  * Added implementation for PPipeChannel::GetReturnCode and PPipeChannel::IsRunning
  184.  *
  185.  * Revision 1.44  1996/12/29 13:05:03  robertj
  186.  * Added wait and abort for pipe channel commands.
  187.  * Added setting of error codes on status error.
  188.  *
  189.  * Revision 1.43  1996/12/29 02:53:13  craigs
  190.  * Added implementation for PPipeChannel::GetReturnCode and
  191.  *   PPipeChannel::IsRunning
  192.  *
  193.  * Revision 1.42  1996/12/17 13:13:05  robertj
  194.  * Fixed win95 support for registry security code,
  195.  *
  196.  * Revision 1.41  1996/12/17 11:00:28  robertj
  197.  * Fixed register entry security access control lists.
  198.  *
  199.  * Revision 1.40  1996/11/16 10:52:48  robertj
  200.  * Fixed bug in PPipeChannel test for open channel, win95 support.
  201.  * Put time back to C function as run time library bug fixed now.
  202.  *
  203.  * Revision 1.39  1996/11/04 03:36:31  robertj
  204.  * Added extra error message for UDP packet truncated.
  205.  *
  206.  * Revision 1.38  1996/10/26 01:42:51  robertj
  207.  * Added more translations for winsock error codes to standard error codes.
  208.  *
  209.  * Revision 1.37  1996/10/14 03:11:25  robertj
  210.  * Changed registry key so when reading only opens in ReadOnly mode.
  211.  *
  212.  * Revision 1.36  1996/10/08 13:03:47  robertj
  213.  * Added new error messages.
  214.  *
  215.  * Revision 1.35  1996/08/08 10:03:43  robertj
  216.  * Fixed static error text returned when no osError value.
  217.  *
  218.  * Revision 1.34  1996/07/27 04:05:31  robertj
  219.  * Created static version of ConvertOSError().
  220.  * Created static version of GetErrorText().
  221.  * Changed thread creation to use C library function instead of direct WIN32.
  222.  * Fixed bug in auto-deleting the housekeeping thread.
  223.  *
  224.  * Revision 1.33  1996/07/20 05:34:05  robertj
  225.  * Fixed order of registry section tree traversal so can delete whole trees.
  226.  *
  227.  * Revision 1.32  1996/06/28 13:24:33  robertj
  228.  * Fixed enumeration of sections to recurse into registry tree.
  229.  *
  230.  * Revision 1.31  1996/06/17 11:38:58  robertj
  231.  * Fixed memory leak on termination of threads.
  232.  *
  233.  * Revision 1.30  1996/06/13 13:32:13  robertj
  234.  * Rewrite of auto-delete threads, fixes Windows95 total crash.
  235.  *
  236.  * Revision 1.29  1996/06/10 09:54:35  robertj
  237.  * Fixed Win95 compatibility for semaphores.
  238.  *
  239.  * Revision 1.28  1996/05/30 11:48:51  robertj
  240.  * Fixed error on socket timeout to return "Timed Out".
  241.  *
  242.  * Revision 1.27  1996/05/23 10:05:36  robertj
  243.  * Fixed bug in PConfig::GetBoolean().
  244.  * Changed PTimeInterval millisecond access function so can get int64.
  245.  * Moved service process code into separate module.
  246.  *
  247.  * Revision 1.26  1996/04/29 12:23:22  robertj
  248.  * Fixed ability to access GDI stuff from subthreads.
  249.  * Added function to return process ID.
  250.  *
  251.  * Revision 1.25  1996/04/17 12:09:30  robertj
  252.  * Added service dependencies.
  253.  * Started win95 support.
  254.  *
  255.  * Revision 1.24  1996/04/09 03:33:58  robertj
  256.  * Fixed bug in incorrect report of timeout on socket read.
  257.  *
  258.  * Revision 1.23  1996/04/01 13:33:19  robertj
  259.  * Fixed bug in install of service, incorrectly required installation before install.
  260.  *
  261.  * Revision 1.22  1996/03/31 09:10:33  robertj
  262.  * Added use of "CurrentVersion" key in registry.
  263.  * Added version display to service process.
  264.  * Added another socket error text message.
  265.  *
  266.  * Revision 1.21  1996/03/12 11:31:39  robertj
  267.  * Moved PProcess destructor to platform dependent code.
  268.  * Fixed bug in deleting Event Viewer registry entry for service process.
  269.  *
  270.  * Revision 1.20  1996/03/10 13:16:49  robertj
  271.  * Implemented system version functions.
  272.  *
  273.  * Revision 1.19  1996/03/04 13:07:33  robertj
  274.  * Allowed for auto deletion of threads on termination.
  275.  *
  276.  * Revision 1.18  1996/02/25 11:15:29  robertj
  277.  * Added platform dependent Construct function to PProcess.
  278.  *
  279.  * Revision 1.17  1996/02/25 03:12:48  robertj
  280.  * Added consts to all GetXxxx functions in PConfig.
  281.  * Fixed bug in PTime::GetTimeZone(), incorrect sign!
  282.  * Fixed problem with PConfig get functions and their WIN32 types should be
  283.  *    able to interchange strings and numbers.
  284.  *
  285.  * Revision 1.16  1996/02/19 13:53:21  robertj
  286.  * Fixed error reporting for winsock classes.
  287.  *
  288.  * Revision 1.15  1996/02/15 14:54:06  robertj
  289.  * Compensated for C library bug in time().
  290.  *
  291.  * Revision 1.14  1996/02/08 12:30:41  robertj
  292.  * Time zone changes.
  293.  * Added OS identification strings to PProcess.
  294.  *
  295.  * Revision 1.13  1996/01/28 02:56:56  robertj
  296.  * Fixed bug in PFilePath functions for if path ends in a directory separator.
  297.  * Made sure all directory separators are correct character in normalised path.
  298.  *
  299.  * Revision 1.12  1996/01/23 13:25:21  robertj
  300.  * Added time zones.
  301.  * Fixed bug if daylight savings indication.
  302.  *
  303.  * Revision 1.11  1996/01/02 12:58:33  robertj
  304.  * Fixed copy of directories.
  305.  * Changed process construction mechanism.
  306.  * Made service process "common".
  307.  *
  308.  * Revision 1.10  1995/12/10 12:05:48  robertj
  309.  * Changes to main() startup mechanism to support Mac.
  310.  * Moved error code for specific WIN32 and MS-DOS versions.
  311.  * Added WIN32 registry support for PConfig objects.
  312.  * Added asserts in WIN32 semaphores.
  313.  *
  314.  * Revision 1.9  1995/11/21 11:53:24  robertj
  315.  * Added timeout on semaphore wait.
  316.  *
  317.  * Revision 1.8  1995/10/14 15:13:04  robertj
  318.  * Fixed bug in WIN32 service command line parameters.
  319.  *
  320.  * Revision 1.7  1995/08/24 12:42:33  robertj
  321.  * Changed PChannel so not a PContainer.
  322.  * Rewrote PSerialChannel::Read yet again so can break out of I/O.
  323.  *
  324.  * Revision 1.6  1995/07/02 01:26:52  robertj
  325.  * Changed thread internal variables.
  326.  * Added service process support for NT.
  327.  *
  328.  * Revision 1.5  1995/06/17 01:03:08  robertj
  329.  * Added NT service process type.
  330.  *
  331.  * Revision 1.4  1995/06/04 12:48:52  robertj
  332.  * Fixed bug in directory path creation.
  333.  * Fixed bug in comms channel open error.
  334.  *
  335.  * Revision 1.3  1995/04/25 11:33:54  robertj
  336.  * Fixed Borland compiler warnings.
  337.  *
  338.  * Revision 1.2  1995/03/22 13:56:18  robertj
  339.  * Fixed directory handle value check for closing directory.
  340.  *
  341. // Revision 1.1  1995/03/14  12:45:20  robertj
  342. // Initial revision
  343. //
  344.  */
  345. #include <ptlib.h>
  346. #include <process.h>
  347. #include <ptlib/debstrm.h>
  348. #define new PNEW
  349. ///////////////////////////////////////////////////////////////////////////////
  350. // PTime
  351. PTime::PTime()
  352. {
  353.   // Magic constant to convert epoch from 1601 to 1970
  354.   static const PInt64 delta = ((PInt64)369*365+(369/4)-3)*24*60*60U;
  355.   static const PInt64 scale = 10000000;
  356.   PInt64 timestamp;
  357.   GetSystemTimeAsFileTime((LPFILETIME)&timestamp);
  358.   theTime = (time_t)(timestamp/scale - delta);
  359.   microseconds = (long)(timestamp%scale/10);
  360. }
  361. PString PTime::GetTimeSeparator()
  362. {
  363.   PString str;
  364.   GetLocaleInfo(GetUserDefaultLCID(), LOCALE_STIME, str.GetPointer(100), 99);
  365.   str.MakeMinimumSize();
  366.   return str;
  367. }
  368. BOOL PTime::GetTimeAMPM()
  369. {
  370.   char str[2];
  371.   GetLocaleInfo(GetUserDefaultLCID(), LOCALE_ITIME, str, sizeof(str));
  372.   return str[0] == '0';
  373. }
  374. PString PTime::GetTimeAM()
  375. {
  376.   PString str;
  377.   GetLocaleInfo(GetUserDefaultLCID(), LOCALE_S1159, str.GetPointer(100), 99);
  378.   str.MakeMinimumSize();
  379.   return str;
  380. }
  381. PString PTime::GetTimePM()
  382. {
  383.   PString str;
  384.   GetLocaleInfo(GetUserDefaultLCID(), LOCALE_S2359, str.GetPointer(100), 99);
  385.   str.MakeMinimumSize();
  386.   return str;
  387. }
  388. PString PTime::GetDayName(Weekdays dayOfWeek, NameType type)
  389. {
  390.   PString str;
  391.   // Of course Sunday is 6 and Monday is 1...
  392.   GetLocaleInfo(GetUserDefaultLCID(), (dayOfWeek+6)%7 +
  393.           (type == Abbreviated ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1),
  394.           str.GetPointer(100), 99);
  395.   str.MakeMinimumSize();
  396.   return str;
  397. }
  398. PString PTime::GetDateSeparator()
  399. {
  400.   PString str;
  401.   GetLocaleInfo(GetUserDefaultLCID(), LOCALE_SDATE, str.GetPointer(100), 99);
  402.   str.MakeMinimumSize();
  403.   return str;
  404. }
  405. PString PTime::GetMonthName(Months month, NameType type)
  406. {
  407.   PString str;
  408.   GetLocaleInfo(GetUserDefaultLCID(), month-1 +
  409.       (type == Abbreviated ? LOCALE_SABBREVMONTHNAME1 : LOCALE_SMONTHNAME1),
  410.       str.GetPointer(100), 99);
  411.   str.MakeMinimumSize();
  412.   return str;
  413. }
  414. PTime::DateOrder PTime::GetDateOrder()
  415. {
  416.   char str[2];
  417.   GetLocaleInfo(GetUserDefaultLCID(), LOCALE_IDATE, str, sizeof(str));
  418.   return (DateOrder)(str[0] - '0');
  419. }
  420. BOOL PTime::IsDaylightSavings()
  421. {
  422.   TIME_ZONE_INFORMATION tz;
  423.   DWORD result = GetTimeZoneInformation(&tz);
  424.   PAssertOS(result != 0xffffffff);
  425.   return result == TIME_ZONE_ID_DAYLIGHT;
  426. }
  427. int PTime::GetTimeZone(TimeZoneType type)
  428. {
  429.   TIME_ZONE_INFORMATION tz;
  430.   PAssertOS(GetTimeZoneInformation(&tz) != 0xffffffff);
  431.   if (type == DaylightSavings)
  432.     tz.Bias += tz.DaylightBias;
  433.   return -tz.Bias;
  434. }
  435. PString PTime::GetTimeZoneString(TimeZoneType type)
  436. {
  437.   TIME_ZONE_INFORMATION tz;
  438.   PAssertOS(GetTimeZoneInformation(&tz) != 0xffffffff);
  439.   return type == StandardTime ? tz.StandardName : tz.DaylightName;
  440. }
  441. ///////////////////////////////////////////////////////////////////////////////
  442. // PTimeInterval 
  443. static unsigned GetDivisor()
  444. {
  445.   LARGE_INTEGER frequency;
  446.   if (QueryPerformanceFrequency(&frequency))
  447.     return (unsigned)frequency.QuadPart/1000;
  448.   return 0;
  449. }
  450. PTimeInterval PTimer::Tick()
  451. {
  452.   static unsigned divisor = GetDivisor();
  453.   if (divisor == 0)
  454.     return (int)(GetTickCount()&0x7fffffff);
  455.   
  456.   LARGE_INTEGER count;
  457.   QueryPerformanceCounter(&count);
  458.   return count.QuadPart/divisor;
  459. }
  460. unsigned PTimer::Resolution()
  461. {
  462.   LARGE_INTEGER frequency;
  463.   if (QueryPerformanceFrequency(&frequency) && frequency.QuadPart >= 1000)
  464.     return 1;
  465.   DWORD err = GetLastError();
  466.   DWORD timeAdjustment;
  467.   DWORD timeIncrement;
  468.   BOOL timeAdjustmentDisabled;
  469.   if (GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &timeAdjustmentDisabled))
  470.     return timeIncrement/10000;
  471.   err = GetLastError();
  472.   return 55;
  473. }
  474. ///////////////////////////////////////////////////////////////////////////////
  475. // Directories
  476. void PDirectory::Construct()
  477. {
  478.   hFindFile = INVALID_HANDLE_VALUE;
  479.   fileinfo.cFileName[0] = '';
  480.   PString::operator=(CreateFullPath(*this, TRUE));
  481. }
  482. void PDirectory::CopyContents(const PDirectory & dir)
  483. {
  484.   scanMask  = dir.scanMask;
  485.   hFindFile = dir.hFindFile;
  486.   fileinfo  = dir.fileinfo;
  487. }
  488. BOOL PDirectory::Open(int newScanMask)
  489. {
  490.   scanMask = newScanMask;
  491.   hFindFile = FindFirstFile(operator+("*.*"), &fileinfo);
  492.   if (hFindFile == INVALID_HANDLE_VALUE)
  493.     return FALSE;
  494.   return Filtered() ? Next() : TRUE;
  495. }
  496. BOOL PDirectory::Next()
  497. {
  498.   if (hFindFile == INVALID_HANDLE_VALUE)
  499.     return FALSE;
  500.   do {
  501.     if (!FindNextFile(hFindFile, &fileinfo))
  502.       return FALSE;
  503.   } while (Filtered());
  504.   return TRUE;
  505. }
  506. PCaselessString PDirectory::GetEntryName() const
  507. {
  508.   return fileinfo.cFileName;
  509. }
  510. BOOL PDirectory::IsSubDir() const
  511. {
  512.   return (fileinfo.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0;
  513. }
  514. PCaselessString PDirectory::GetVolume() const
  515. {
  516.   char volName[100];
  517.   PAssertOS(GetVolumeInformation(NULL, volName, sizeof(volName), NULL, NULL, NULL, NULL, 0));
  518.   return PCaselessString(volName);
  519. }
  520. void PDirectory::Close()
  521. {
  522.   if (hFindFile != INVALID_HANDLE_VALUE) {
  523.     FindClose(hFindFile);
  524.     hFindFile = INVALID_HANDLE_VALUE;
  525.   }
  526. }
  527. PString PDirectory::CreateFullPath(const PString & path, BOOL isDirectory)
  528. {
  529.   PString partialpath = path;
  530.   if (path.IsEmpty())
  531.     partialpath = ".";
  532.   LPSTR dummy;
  533.   PString fullpath;
  534.   PINDEX len = (PINDEX)GetFullPathName(partialpath,
  535.                            _MAX_PATH, fullpath.GetPointer(_MAX_PATH), &dummy);
  536.   if (isDirectory && len > 0 && fullpath[len-1] != PDIR_SEPARATOR)
  537.     fullpath += PDIR_SEPARATOR;
  538.   PINDEX pos = 0;
  539.   while ((pos = fullpath.Find('/', pos)) != P_MAX_INDEX)
  540.     fullpath[pos] = PDIR_SEPARATOR;
  541.   return fullpath;
  542. }
  543. typedef BOOL (WINAPI *GetDiskFreeSpaceExType)(LPCTSTR lpDirectoryName,
  544.                                               PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  545.                                               PULARGE_INTEGER lpTotalNumberOfBytes,
  546.                                               PULARGE_INTEGER lpTotalNumberOfFreeBytes);
  547. BOOL PDirectory::GetVolumeSpace(PInt64 & total, PInt64 & free, DWORD & clusterSize) const
  548. {
  549.   clusterSize = 512;
  550.   total = free = ULONG_MAX;
  551.   PString root;
  552.   if ((*this)[1] == ':')
  553.     root = Left(3);
  554.   else if (theArray[0] == '\' && theArray[1] == '\') {
  555.     PINDEX backslash = Find('\', 2);
  556.     if (backslash != P_MAX_INDEX) {
  557.       backslash = Find('\', backslash+1);
  558.       if (backslash != P_MAX_INDEX)
  559.         root = Left(backslash+1);
  560.     }
  561.   }
  562.   if (root.IsEmpty())
  563.     return FALSE;
  564.   BOOL needTotalAndFree = TRUE;
  565.   static GetDiskFreeSpaceExType GetDiskFreeSpaceEx =
  566.         (GetDiskFreeSpaceExType)GetProcAddress(LoadLibrary("KERNEL32.DLL"), "GetDiskFreeSpaceExA");
  567.   if (GetDiskFreeSpaceEx != NULL) {
  568.     ULARGE_INTEGER freeBytesAvailableToCaller;
  569.     ULARGE_INTEGER totalNumberOfBytes; 
  570.     ULARGE_INTEGER totalNumberOfFreeBytes;
  571.     if (GetDiskFreeSpaceEx(root,
  572.                            &freeBytesAvailableToCaller,
  573.                            &totalNumberOfBytes,
  574.                            &totalNumberOfFreeBytes)) {
  575.       total = totalNumberOfBytes.QuadPart;
  576.       free = totalNumberOfFreeBytes.QuadPart;
  577.       needTotalAndFree = FALSE;
  578.     }
  579.   }
  580.   clusterSize = 0;
  581.   char fsName[100];
  582.   if (GetVolumeInformation(root, NULL, 0, NULL, NULL, NULL, fsName, sizeof(fsName))) {
  583.     if (stricmp(fsName, "FAT32") == 0) {
  584.       clusterSize = 4096; // Cannot use GetDiskFreeSpace() results for FAT32
  585.       if (!needTotalAndFree)
  586.         return TRUE;
  587.     }
  588.   }
  589.   DWORD sectorsPerCluster;      // address of sectors per cluster 
  590.   DWORD bytesPerSector;         // address of bytes per sector 
  591.   DWORD numberOfFreeClusters;   // address of number of free clusters  
  592.   DWORD totalNumberOfClusters;  // address of total number of clusters 
  593.   if (!GetDiskFreeSpace(root,
  594.                         &sectorsPerCluster,
  595.                         &bytesPerSector,
  596.                         &numberOfFreeClusters,
  597.                         &totalNumberOfClusters)) {
  598.     if (root[0] != '\' || ::GetLastError() != ERROR_NOT_SUPPORTED)
  599.       return FALSE;
  600.     PString drive = "A:";
  601.     while (WNetAddConnection(root, NULL, drive) != NO_ERROR) {
  602.       if (GetLastError() != ERROR_ALREADY_ASSIGNED)
  603.         return FALSE;
  604.       drive[0]++;
  605.     }
  606.     BOOL ok = GetDiskFreeSpace(drive+'\',
  607.                                &sectorsPerCluster,
  608.                                &bytesPerSector,
  609.                                &numberOfFreeClusters,
  610.                                &totalNumberOfClusters);
  611.     WNetCancelConnection(drive, TRUE);
  612.     if (!ok)
  613.       return FALSE;
  614.   }
  615.   if (needTotalAndFree) {
  616.     free = numberOfFreeClusters*sectorsPerCluster*bytesPerSector;
  617.     total = totalNumberOfClusters*sectorsPerCluster*bytesPerSector;
  618.   }
  619.   if (clusterSize == 0)
  620.     clusterSize = bytesPerSector*sectorsPerCluster;
  621.   return TRUE;
  622. }
  623. ///////////////////////////////////////////////////////////////////////////////
  624. // PFilePath
  625. static PString IllegalFilenameCharacters =
  626.   "\/:*?"<>|"
  627.   "x01x02x03x04x05x06x07x08x09x0ax0bx0cx0dx0ex0fx10"
  628.   "x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f";
  629. BOOL PFilePath::IsValid(char c)
  630. {
  631.   return IllegalFilenameCharacters.Find(c) == P_MAX_INDEX;
  632. }
  633. BOOL PFilePath::IsValid(const PString & str)
  634. {
  635.   return str != "." && str != ".." &&
  636.          str.FindOneOf(IllegalFilenameCharacters) == P_MAX_INDEX;
  637. }
  638. ///////////////////////////////////////////////////////////////////////////////
  639. // PChannel
  640. PString PChannel::GetErrorText() const
  641. {
  642.   return GetErrorText(lastError, osError);
  643. }
  644. PString PChannel::GetErrorText(Errors lastError, int osError)
  645. {
  646.   if (osError == 0) {
  647.     if (lastError == NoError)
  648.       return PString();
  649.     static int const errors[Miscellaneous+1] = {
  650.       0, ENOENT, EEXIST, ENOSPC, EACCES, 1000, EINVAL, ENOMEM, EBADF, EAGAIN, EINTR, 1001
  651.     };
  652.     osError = errors[lastError];
  653.   }
  654.   if (osError > 0 && osError < _sys_nerr && _sys_errlist[osError][0] != '')
  655.     return _sys_errlist[osError];
  656.   if ((osError & 0x40000000) == 0)
  657.     return psprintf("C runtime error %u", osError);
  658.   DWORD err = osError & 0x3fffffff;
  659.   static const struct {
  660.     DWORD id;
  661.     const char * msg;
  662.   } win32_errlist[] = {
  663.     { ERROR_FILE_NOT_FOUND,     "File not found" },
  664.     { ERROR_PATH_NOT_FOUND,     "Path not found" },
  665.     { ERROR_ACCESS_DENIED,      "Access denied" },
  666.     { ERROR_NOT_ENOUGH_MEMORY,  "Not enough memory" },
  667.     { ERROR_INVALID_FUNCTION,   "Invalid function" },
  668.     { WSAEADDRINUSE,            "Address in use" },
  669.     { WSAENETDOWN,              "Network subsystem failed" },
  670.     { WSAEISCONN,               "Socket is already connected" },
  671.     { WSAENETUNREACH,           "Network unreachable" },
  672.     { WSAEHOSTUNREACH,          "Host unreachable" },
  673.     { WSAECONNREFUSED,          "Connection refused" },
  674.     { WSAEINVAL,                "Invalid operation" },
  675.     { WSAENOTCONN,              "Socket not connected" },
  676.     { WSAECONNABORTED,          "Connection aborted" },
  677.     { WSAECONNRESET,            "Connection reset" },
  678.     { WSAESHUTDOWN,             "Connection shutdown" },
  679.     { WSAENOTSOCK,              "Socket closed or invalid" },
  680.     { WSAETIMEDOUT,             "Timed out" },
  681.     { WSAEMSGSIZE,              "Message larger than buffer" },
  682.     { WSAEWOULDBLOCK,           "Would block" },
  683.     { 0x1000000,                "Unexpected error in protocol" }
  684.   };
  685.   for (PINDEX i = 0; i < PARRAYSIZE(win32_errlist); i++)
  686.     if (win32_errlist[i].id == err)
  687.       return win32_errlist[i].msg;
  688.   return psprintf("WIN32 error %u", err);
  689. }
  690. BOOL PChannel::ConvertOSError(int error)
  691. {
  692.   return ConvertOSError(error, lastError, osError);
  693. }
  694. BOOL PChannel::ConvertOSError(int error, Errors & lastError, int & osError)
  695. {
  696.   if (error >= 0) {
  697.     lastError = NoError;
  698.     osError = 0;
  699.     return TRUE;
  700.   }
  701.   if (error != -2)
  702.     osError = errno;
  703.   else {
  704.     osError = GetLastError();
  705.     switch (osError) {
  706.       case ERROR_INVALID_HANDLE :
  707.       case WSAEBADF :
  708.         osError = EBADF;
  709.         break;
  710.       case ERROR_INVALID_PARAMETER :
  711.       case WSAEINVAL :
  712.         osError = EINVAL;
  713.         break;
  714.       case ERROR_ACCESS_DENIED :
  715.       case WSAEACCES :
  716.         osError = EACCES;
  717.         break;
  718.       case ERROR_NOT_ENOUGH_MEMORY :
  719.         osError = ENOMEM;
  720.         break;
  721.       case WSAEINTR :
  722.         osError = EINTR;
  723.         break;
  724.       case WSAEMSGSIZE :
  725.         osError |= 0x40000000;
  726.         lastError = BufferTooSmall;
  727.         return FALSE;
  728.       case WSAEWOULDBLOCK :
  729.       case WSAETIMEDOUT :
  730.         osError |= 0x40000000;
  731.         lastError = Timeout;
  732.         return FALSE;
  733.       default :
  734.         osError |= 0x40000000;
  735.     }
  736.   }
  737.   switch (osError) {
  738.     case 0 :
  739.       lastError = NoError;
  740.       return TRUE;
  741.     case ENOENT :
  742.       lastError = NotFound;
  743.       break;
  744.     case EEXIST :
  745.       lastError = FileExists;
  746.       break;
  747.     case EACCES :
  748.       lastError = AccessDenied;
  749.       break;
  750.     case ENOMEM :
  751.       lastError = NoMemory;
  752.       break;
  753.     case ENOSPC :
  754.       lastError = DiskFull;
  755.       break;
  756.     case EINVAL :
  757.       lastError = BadParameter;
  758.       break;
  759.     case EBADF :
  760.       lastError = NotOpen;
  761.       break;
  762.     case EAGAIN :
  763.       lastError = Timeout;
  764.       break;
  765.     case EINTR :
  766.       lastError = Interrupted;
  767.       break;
  768.     default :
  769.       lastError = Miscellaneous;
  770.   }
  771.   return FALSE;
  772. }
  773. ///////////////////////////////////////////////////////////////////////////////
  774. // PWin32Overlapped
  775. PWin32Overlapped::PWin32Overlapped()
  776. {
  777.   memset(this, 0, sizeof(*this));
  778.   hEvent = CreateEvent(0, TRUE, 0, NULL);
  779. }
  780. PWin32Overlapped::~PWin32Overlapped()
  781. {
  782.   if (hEvent != NULL)
  783.     CloseHandle(hEvent);
  784. }
  785. void PWin32Overlapped::Reset()
  786. {
  787.   Offset = OffsetHigh = 0;
  788.   if (hEvent != NULL)
  789.     ResetEvent(hEvent);
  790. }
  791. ///////////////////////////////////////////////////////////////////////////////
  792. // Threads
  793. UINT __stdcall PThread::MainFunction(void * threadPtr)
  794. {
  795.   PThread * thread = (PThread *)PAssertNULL(threadPtr);
  796.   PProcess & process = PProcess::Current();
  797.   AttachThreadInput(thread->threadId, ((PThread&)process).threadId, TRUE);
  798.   AttachThreadInput(((PThread&)process).threadId, thread->threadId, TRUE);
  799.   process.activeThreadMutex.Wait();
  800.   process.activeThreads.SetAt(thread->threadId, thread);
  801.   process.activeThreadMutex.Signal();
  802.   process.SignalTimerChange();
  803.   thread->Main();
  804.   return 0;
  805. }
  806. PThread::PThread(PINDEX stackSize,
  807.                  AutoDeleteFlag deletion,
  808.                  Priority priorityLevel,
  809.                  const PString & name)
  810.   : threadName(name)
  811. {
  812.   PAssert(stackSize > 0, PInvalidParameter);
  813.   originalStackSize = stackSize;
  814.   autoDelete = deletion == AutoDeleteThread;
  815.   threadHandle = (HANDLE)_beginthreadex(NULL, stackSize, MainFunction,
  816.                                         this, CREATE_SUSPENDED, &threadId);
  817.   PAssertOS(threadHandle != NULL);
  818.   SetPriority(priorityLevel);
  819.   if (autoDelete) {
  820.     PProcess & process = PProcess::Current();
  821.     process.deleteThreadMutex.Wait();
  822.     process.autoDeleteThreads.Append(this);
  823.     process.deleteThreadMutex.Signal();
  824.   }
  825. }
  826. PThread::~PThread()
  827. {
  828.   if (originalStackSize <= 0)
  829.     return;
  830.   PProcess & process = PProcess::Current();
  831.   process.activeThreadMutex.Wait();
  832.   process.activeThreads.SetAt(threadId, NULL);
  833.   process.activeThreadMutex.Signal();
  834.   if (!IsTerminated())
  835.     Terminate();
  836.   if (threadHandle != NULL)
  837.     CloseHandle(threadHandle);
  838. }
  839. void PThread::Restart()
  840. {
  841.   PAssert(IsTerminated(), "Cannot restart running thread");
  842.   threadHandle = (HANDLE)_beginthreadex(NULL,
  843.                          originalStackSize, MainFunction, this, 0, &threadId);
  844.   PAssertOS(threadHandle != NULL);
  845. }
  846. void PThread::Terminate()
  847. {
  848.   PAssert(originalStackSize > 0, PLogicError);
  849.   if (Current() == this)
  850.     ExitThread(0);
  851.   else
  852.     TerminateThread(threadHandle, 1);
  853. }
  854. BOOL PThread::IsTerminated() const
  855. {
  856.   return WaitForTermination(0);
  857. }
  858. void PThread::WaitForTermination() const
  859. {
  860.   WaitForTermination(PMaxTimeInterval);
  861. }
  862. BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
  863. {
  864.   if (threadHandle == NULL)
  865.     return TRUE;
  866.   DWORD result;
  867.   PINDEX retries = 10;
  868.   while ((result = WaitForSingleObject(threadHandle, maxWait.GetInterval())) != WAIT_TIMEOUT) {
  869.     if (result == WAIT_OBJECT_0)
  870.       return TRUE;
  871.     if (::GetLastError() != ERROR_INVALID_HANDLE) {
  872.       PAssertAlways(POperatingSystemError);
  873.       return TRUE;
  874.     }
  875.     if (retries > 0)
  876.       return TRUE;
  877.     retries--;
  878.   }
  879.   return FALSE;
  880. }
  881. void PThread::Suspend(BOOL susp)
  882. {
  883.   PAssert(!IsTerminated(), "Operation on terminated thread");
  884.   if (susp)
  885.     SuspendThread(threadHandle);
  886.   else
  887.     Resume();
  888. }
  889. void PThread::Resume()
  890. {
  891.   PAssert(!IsTerminated(), "Operation on terminated thread");
  892.   ResumeThread(threadHandle);
  893. }
  894. BOOL PThread::IsSuspended() const
  895. {
  896.   PAssert(!IsTerminated(), "Operation on terminated thread");
  897.   SuspendThread(threadHandle);
  898.   return ResumeThread(threadHandle) > 1;
  899. }
  900. void PThread::SetPriority(Priority priorityLevel)
  901. {
  902.   PAssert(!IsTerminated(), "Operation on terminated thread");
  903.   static int const priorities[NumPriorities] = {
  904.     THREAD_PRIORITY_LOWEST,
  905.     THREAD_PRIORITY_BELOW_NORMAL,
  906.     THREAD_PRIORITY_NORMAL,
  907.     THREAD_PRIORITY_ABOVE_NORMAL,
  908.     THREAD_PRIORITY_HIGHEST
  909.   };
  910.   SetThreadPriority(threadHandle, priorities[priorityLevel]);
  911. }
  912. PThread::Priority PThread::GetPriority() const
  913. {
  914.   PAssert(!IsTerminated(), "Operation on terminated thread");
  915.   switch (GetThreadPriority(threadHandle)) {
  916.     case THREAD_PRIORITY_LOWEST :
  917.       return LowestPriority;
  918.     case THREAD_PRIORITY_BELOW_NORMAL :
  919.       return LowPriority;
  920.     case THREAD_PRIORITY_NORMAL :
  921.       return NormalPriority;
  922.     case THREAD_PRIORITY_ABOVE_NORMAL :
  923.       return HighPriority;
  924.     case THREAD_PRIORITY_HIGHEST :
  925.       return HighestPriority;
  926.   }
  927.   PAssertAlways(POperatingSystemError);
  928.   return LowestPriority;
  929. }
  930. void PThread::Yield()
  931. {
  932.   ::Sleep(0);
  933. }
  934. void PThread::InitialiseProcessThread()
  935. {
  936.   originalStackSize = 0;
  937.   autoDelete = FALSE;
  938.   threadHandle = GetCurrentThread();
  939.   threadId = GetCurrentThreadId();
  940.   ((PProcess *)this)->activeThreads.DisallowDeleteObjects();
  941.   ((PProcess *)this)->activeThreads.SetAt(threadId, this);
  942. }
  943. PThread * PThread::Current()
  944. {
  945.   PProcess & process = PProcess::Current();
  946.   process.activeThreadMutex.Wait();
  947.   PThread * thread = process.activeThreads.GetAt(GetCurrentThreadId());
  948.   process.activeThreadMutex.Signal();
  949.   return thread;
  950. }
  951. ///////////////////////////////////////////////////////////////////////////////
  952. // PProcess::TimerThread
  953. PProcess::HouseKeepingThread::HouseKeepingThread()
  954.   : PThread(1000, NoAutoDeleteThread, LowPriority)
  955. {
  956.   Resume();
  957. }
  958. void PProcess::HouseKeepingThread::Main()
  959. {
  960.   PProcess & process = PProcess::Current();
  961.   for (;;) {
  962.     process.deleteThreadMutex.Wait();
  963.     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  964.     DWORD numHandles = 1;
  965.     handles[0] = breakBlock.GetHandle();
  966.     for (PINDEX i = 0; i < process.autoDeleteThreads.GetSize(); i++) {
  967.       PThread & thread = process.autoDeleteThreads[i];
  968.       if (thread.IsTerminated())
  969.         process.autoDeleteThreads.RemoveAt(i--);
  970.       else {
  971.         handles[numHandles] = thread.GetHandle();
  972.         if (handles[numHandles] != process.GetHandle()) {
  973.           numHandles++;
  974.           if (numHandles >= MAXIMUM_WAIT_OBJECTS)
  975.             break;
  976.         }
  977.       }
  978.     }
  979.     process.deleteThreadMutex.Signal();
  980.     PTimeInterval nextTimer = process.timers.Process();
  981.     DWORD delay;
  982.     if (nextTimer == PMaxTimeInterval)
  983.       delay = INFINITE;
  984.     else if (nextTimer > 1000)
  985.       delay = 1000;
  986.     else
  987.       delay = nextTimer.GetInterval();
  988.     DWORD result;
  989.     PINDEX retries = 100;
  990.     while ((result = WaitForMultipleObjects(numHandles, handles, FALSE, delay)) == WAIT_FAILED) {
  991.       PAssertOS(::GetLastError() == ERROR_INVALID_HANDLE || retries > 0);
  992.       retries--;
  993.     }
  994.   }
  995. }
  996. void PProcess::SignalTimerChange()
  997. {
  998.   if (houseKeeper == NULL)
  999.     houseKeeper = new HouseKeepingThread;
  1000.   else
  1001.     houseKeeper->breakBlock.Signal();
  1002. }
  1003. ///////////////////////////////////////////////////////////////////////////////
  1004. // PProcess
  1005. PProcess::~PProcess()
  1006. {
  1007.   Sleep(100);  // Give threads time to die a natural death
  1008.   // Get rid of the house keeper (majordomocide)
  1009.   delete houseKeeper;
  1010.   // OK, if there are any left we get really insistent...
  1011.   activeThreadMutex.Wait();
  1012.   for (PINDEX i = 0; i < activeThreads.GetSize(); i++) {
  1013.     PThread & thread = activeThreads.GetDataAt(i);
  1014.     if (this != &thread && !thread.IsTerminated())
  1015.       TerminateThread(thread.GetHandle(), 1);  // With extreme prejudice
  1016.   }
  1017.   activeThreadMutex.Signal();
  1018.   deleteThreadMutex.Wait();
  1019.   autoDeleteThreads.RemoveAll();
  1020.   deleteThreadMutex.Signal();
  1021. #if !PMEMORY_CHECK
  1022.   extern void PWaitOnExitConsoleWindow();
  1023.   PWaitOnExitConsoleWindow();
  1024. #endif
  1025. }
  1026. PString PProcess::GetOSClass()
  1027. {
  1028.   return "Windows";
  1029. }
  1030. PString PProcess::GetOSName()
  1031. {
  1032.   OSVERSIONINFO info;
  1033.   info.dwOSVersionInfoSize = sizeof(info);
  1034.   GetVersionEx(&info);
  1035.   switch (info.dwPlatformId) {
  1036.     case VER_PLATFORM_WIN32s :
  1037.       return "32s";
  1038.     case 1 : //VER_PLATFORM_WIN32_WINDOWS :
  1039.       return "95";
  1040.     case VER_PLATFORM_WIN32_NT :
  1041.       return "NT";
  1042.   }
  1043.   return "?";
  1044. }
  1045. PString PProcess::GetOSHardware()
  1046. {
  1047.   SYSTEM_INFO info;
  1048.   GetSystemInfo(&info);
  1049.   switch (info.wProcessorArchitecture) {
  1050.     case PROCESSOR_ARCHITECTURE_INTEL :
  1051.       switch (info.dwProcessorType) {
  1052.         case PROCESSOR_INTEL_386 :
  1053.           return "i386";
  1054.         case PROCESSOR_INTEL_486 :
  1055.           return "i486";
  1056.         case PROCESSOR_INTEL_PENTIUM :
  1057.           return "i586";
  1058.       }
  1059.       return "iX86";
  1060.     case PROCESSOR_ARCHITECTURE_MIPS :
  1061.       return "mips";
  1062.     case PROCESSOR_ARCHITECTURE_ALPHA :
  1063.       return "alpha";
  1064.     case PROCESSOR_ARCHITECTURE_PPC :
  1065.       return "ppc";
  1066.   }
  1067.   return "?";
  1068. }
  1069. PString PProcess::GetOSVersion()
  1070. {
  1071.   OSVERSIONINFO info;
  1072.   info.dwOSVersionInfoSize = sizeof(info);
  1073.   GetVersionEx(&info);
  1074.   return psprintf("v%u.%u", info.dwMajorVersion, info.dwMinorVersion);
  1075. }
  1076. PDirectory PProcess::GetOSConfigDir()
  1077. {
  1078.   OSVERSIONINFO info;
  1079.   info.dwOSVersionInfoSize = sizeof(info);
  1080.   GetVersionEx(&info);
  1081.   char dir[_MAX_PATH];
  1082.   if (info.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  1083.     PAssertOS(GetWindowsDirectory(dir, sizeof(dir)) != 0);
  1084.     return dir;
  1085.   }
  1086.   PAssertOS(GetSystemDirectory(dir, sizeof(dir)) != 0);
  1087.   PDirectory sysdir = dir;
  1088.   return sysdir + "drivers\etc";
  1089. }
  1090. PString PProcess::GetUserName() const
  1091. {
  1092.   PString username;
  1093.   unsigned long size = 50;
  1094.   ::GetUserName(username.GetPointer((PINDEX)size), &size);
  1095.   username.MakeMinimumSize();
  1096.   return username;
  1097. }
  1098. DWORD PProcess::GetProcessID() const
  1099. {
  1100.   return GetCurrentProcessId();
  1101. }
  1102. BOOL PProcess::IsServiceProcess() const
  1103. {
  1104.   return FALSE;
  1105. }
  1106. BOOL PProcess::IsGUIProcess() const
  1107. {
  1108.   return FALSE;
  1109. }
  1110. ///////////////////////////////////////////////////////////////////////////////
  1111. // PSemaphore
  1112. PSemaphore::PSemaphore(HANDLE h)
  1113. {
  1114.   handle = h;
  1115.   PAssertOS(handle != NULL);
  1116. }
  1117. PSemaphore::PSemaphore(unsigned initial, unsigned maxCount)
  1118. {
  1119.   if (initial > maxCount)
  1120.     initial = maxCount;
  1121.   handle = CreateSemaphore(NULL, initial, maxCount, NULL);
  1122.   PAssertOS(handle != NULL);
  1123. }
  1124. PSemaphore::~PSemaphore()
  1125. {
  1126.   if (handle != NULL)
  1127.     PAssertOS(CloseHandle(handle));
  1128. }
  1129. void PSemaphore::Wait()
  1130. {
  1131.   PAssertOS(WaitForSingleObject(handle, INFINITE) != WAIT_FAILED);
  1132. }
  1133. BOOL PSemaphore::Wait(const PTimeInterval & timeout)
  1134. {
  1135.   DWORD result = WaitForSingleObject(handle, timeout.GetInterval());
  1136.   PAssertOS(result != WAIT_FAILED);
  1137.   return result != WAIT_TIMEOUT;
  1138. }
  1139. void PSemaphore::Signal()
  1140. {
  1141.   if (!ReleaseSemaphore(handle, 1, NULL))
  1142.     PAssertOS(GetLastError() != ERROR_INVALID_HANDLE);
  1143.   SetLastError(ERROR_SUCCESS);
  1144. }
  1145. BOOL PSemaphore::WillBlock() const
  1146. {
  1147.   DWORD result = WaitForSingleObject(handle, 0);
  1148.   PAssertOS(result != WAIT_FAILED);
  1149.   return result == WAIT_TIMEOUT;
  1150. }
  1151. ///////////////////////////////////////////////////////////////////////////////
  1152. // PMutex
  1153. PMutex::PMutex()
  1154.   : PSemaphore(::CreateMutex(NULL, FALSE, NULL))
  1155. {
  1156. }
  1157. void PMutex::Signal()
  1158. {
  1159.   ::ReleaseMutex(handle);
  1160. }
  1161. ///////////////////////////////////////////////////////////////////////////////
  1162. // PSyncPoint
  1163. PSyncPoint::PSyncPoint()
  1164.   : PSemaphore(::CreateEvent(NULL, FALSE, FALSE, NULL))
  1165. {
  1166. }
  1167. void PSyncPoint::Signal()
  1168. {
  1169.   ::SetEvent(handle);
  1170. }
  1171. ///////////////////////////////////////////////////////////////////////////////
  1172. // PDynaLink
  1173. PDynaLink::PDynaLink()
  1174. {
  1175.   _hDLL = NULL;
  1176. }
  1177. PDynaLink::PDynaLink(const PString & name)
  1178. {
  1179.   Open(name);
  1180. }
  1181. PDynaLink::~PDynaLink()
  1182. {
  1183.   Close();
  1184. }
  1185. PString PDynaLink::GetExtension()
  1186. {
  1187.   return ".DLL";
  1188. }
  1189. BOOL PDynaLink::Open(const PString & name)
  1190. {
  1191.   _hDLL = LoadLibrary(name);
  1192.   return _hDLL != NULL;
  1193. }
  1194. void PDynaLink::Close()
  1195. {
  1196.   if (_hDLL != NULL)
  1197.     FreeLibrary(_hDLL);
  1198. }
  1199. BOOL PDynaLink::IsLoaded() const
  1200. {
  1201.   return _hDLL != NULL;
  1202. }
  1203. PString PDynaLink::GetName(BOOL full) const
  1204. {
  1205.   PFilePathString str;
  1206.   if (_hDLL != NULL) {
  1207.     GetModuleFileName(_hDLL, str.GetPointer(_MAX_PATH), _MAX_PATH-1);
  1208.     if (!full) {
  1209.       str.Delete(0, str.FindLast('\')+1);
  1210.       PINDEX pos = str.Find(".DLL");
  1211.       if (pos != P_MAX_INDEX)
  1212.         str.Delete(pos, P_MAX_INDEX);
  1213.     }
  1214.   }
  1215.   str.MakeMinimumSize();
  1216.   return str;
  1217. }
  1218. BOOL PDynaLink::GetFunction(PINDEX index, Function & func)
  1219. {
  1220.   if (_hDLL == NULL)
  1221.     return FALSE;
  1222.   FARPROC p = GetProcAddress(_hDLL, (LPSTR)(DWORD)LOWORD(index));
  1223.   if (p == NULL)
  1224.     return FALSE;
  1225.   func = (Function)p;
  1226.   return TRUE;
  1227. }
  1228. BOOL PDynaLink::GetFunction(const PString & name, Function & func)
  1229. {
  1230.   if (_hDLL == NULL)
  1231.     return FALSE;
  1232.   FARPROC p = GetProcAddress(_hDLL, name);
  1233.   if (p == NULL)
  1234.     return FALSE;
  1235.   func = (Function)p;
  1236.   return TRUE;
  1237. }
  1238. ///////////////////////////////////////////////////////////////////////////////
  1239. // PDebugStream
  1240. PDebugStream::PDebugStream()
  1241.   : ostream(&buffer)
  1242. {
  1243. }
  1244. PDebugStream::Buffer::Buffer()
  1245. {
  1246.   setb(buffer, &buffer[sizeof(buffer)-2]);
  1247.   unbuffered(FALSE);
  1248.   setp(base(), ebuf());
  1249. }
  1250. int PDebugStream::Buffer::overflow(int c)
  1251. {
  1252.   int bufSize = out_waiting();
  1253.   if (c != EOF) {
  1254.     *pptr() = (char)c;
  1255.     bufSize++;
  1256.   }
  1257.   if (bufSize != 0) {
  1258.     char * p = pbase();
  1259.     setp(p, epptr());
  1260.     p[bufSize] = '';
  1261.     OutputDebugString(p);
  1262.   }
  1263.   return 0;
  1264. }
  1265. int PDebugStream::Buffer::underflow()
  1266. {
  1267.   return EOF;
  1268. }
  1269. int PDebugStream::Buffer::sync()
  1270. {
  1271.   return overflow(EOF);
  1272. }
  1273. // End Of File ///////////////////////////////////////////////////////////////