The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

834 lines
23KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  24. // compiled on its own).
  25. #if JUCE_INCLUDED_FILE
  26. //==============================================================================
  27. #ifndef CSIDL_MYMUSIC
  28. #define CSIDL_MYMUSIC 0x000d
  29. #endif
  30. #ifndef CSIDL_MYVIDEO
  31. #define CSIDL_MYVIDEO 0x000e
  32. #endif
  33. //==============================================================================
  34. const tchar File::separator = T('\\');
  35. const tchar* File::separatorString = T("\\");
  36. //==============================================================================
  37. bool juce_fileExists (const String& fileName,
  38. const bool dontCountDirectories) throw()
  39. {
  40. if (fileName.isEmpty())
  41. return false;
  42. const DWORD attr = GetFileAttributes (fileName);
  43. return dontCountDirectories ? ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
  44. : (attr != 0xffffffff);
  45. }
  46. bool juce_isDirectory (const String& fileName) throw()
  47. {
  48. const DWORD attr = GetFileAttributes (fileName);
  49. return (attr != 0xffffffff)
  50. && ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0);
  51. }
  52. bool juce_canWriteToFile (const String& fileName) throw()
  53. {
  54. const DWORD attr = GetFileAttributes (fileName);
  55. return ((attr & FILE_ATTRIBUTE_READONLY) == 0);
  56. }
  57. bool juce_setFileReadOnly (const String& fileName,
  58. bool isReadOnly)
  59. {
  60. DWORD attr = GetFileAttributes (fileName);
  61. if (attr == 0xffffffff)
  62. return false;
  63. if (isReadOnly != juce_canWriteToFile (fileName))
  64. return true;
  65. if (isReadOnly)
  66. attr |= FILE_ATTRIBUTE_READONLY;
  67. else
  68. attr &= ~FILE_ATTRIBUTE_READONLY;
  69. return SetFileAttributes (fileName, attr) != FALSE;
  70. }
  71. bool File::isHidden() const throw()
  72. {
  73. return (GetFileAttributes (getFullPathName()) & FILE_ATTRIBUTE_HIDDEN) != 0;
  74. }
  75. //==============================================================================
  76. bool juce_deleteFile (const String& fileName) throw()
  77. {
  78. if (juce_isDirectory (fileName))
  79. return RemoveDirectory (fileName) != 0;
  80. return DeleteFile (fileName) != 0;
  81. }
  82. bool juce_moveFile (const String& source, const String& dest) throw()
  83. {
  84. return MoveFile (source, dest) != 0;
  85. }
  86. bool juce_copyFile (const String& source, const String& dest) throw()
  87. {
  88. return CopyFile (source, dest, false) != 0;
  89. }
  90. void juce_createDirectory (const String& fileName) throw()
  91. {
  92. if (! juce_fileExists (fileName, true))
  93. {
  94. CreateDirectory (fileName, 0);
  95. }
  96. }
  97. //==============================================================================
  98. // return 0 if not possible
  99. void* juce_fileOpen (const String& fileName, bool forWriting) throw()
  100. {
  101. HANDLE h;
  102. if (forWriting)
  103. {
  104. h = CreateFile (fileName, GENERIC_WRITE, FILE_SHARE_READ, 0,
  105. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  106. if (h != INVALID_HANDLE_VALUE)
  107. SetFilePointer (h, 0, 0, FILE_END);
  108. else
  109. h = 0;
  110. }
  111. else
  112. {
  113. h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  114. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
  115. if (h == INVALID_HANDLE_VALUE)
  116. h = 0;
  117. }
  118. return (void*) h;
  119. }
  120. void juce_fileClose (void* handle) throw()
  121. {
  122. CloseHandle (handle);
  123. }
  124. //==============================================================================
  125. int juce_fileRead (void* handle, void* buffer, int size) throw()
  126. {
  127. DWORD num = 0;
  128. ReadFile ((HANDLE) handle, buffer, size, &num, 0);
  129. return num;
  130. }
  131. int juce_fileWrite (void* handle, const void* buffer, int size) throw()
  132. {
  133. DWORD num;
  134. WriteFile ((HANDLE) handle,
  135. buffer, size,
  136. &num, 0);
  137. return num;
  138. }
  139. int64 juce_fileSetPosition (void* handle, int64 pos) throw()
  140. {
  141. LARGE_INTEGER li;
  142. li.QuadPart = pos;
  143. li.LowPart = SetFilePointer ((HANDLE) handle,
  144. li.LowPart,
  145. &li.HighPart,
  146. FILE_BEGIN); // (returns -1 if it fails)
  147. return li.QuadPart;
  148. }
  149. int64 juce_fileGetPosition (void* handle) throw()
  150. {
  151. LARGE_INTEGER li;
  152. li.QuadPart = 0;
  153. li.LowPart = SetFilePointer ((HANDLE) handle,
  154. 0, &li.HighPart,
  155. FILE_CURRENT); // (returns -1 if it fails)
  156. return jmax ((int64) 0, li.QuadPart);
  157. }
  158. void juce_fileFlush (void* handle) throw()
  159. {
  160. FlushFileBuffers ((HANDLE) handle);
  161. }
  162. int64 juce_getFileSize (const String& fileName) throw()
  163. {
  164. WIN32_FILE_ATTRIBUTE_DATA attributes;
  165. if (GetFileAttributesEx (fileName, GetFileExInfoStandard, &attributes))
  166. {
  167. return (((int64) attributes.nFileSizeHigh) << 32)
  168. | attributes.nFileSizeLow;
  169. }
  170. return 0;
  171. }
  172. //==============================================================================
  173. static int64 fileTimeToTime (const FILETIME* const ft) throw()
  174. {
  175. // tell me if this fails!
  176. static_jassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME));
  177. #if JUCE_GCC
  178. return (((const ULARGE_INTEGER*) ft)->QuadPart - 116444736000000000LL) / 10000;
  179. #else
  180. return (((const ULARGE_INTEGER*) ft)->QuadPart - 116444736000000000) / 10000;
  181. #endif
  182. }
  183. static void timeToFileTime (const int64 time, FILETIME* const ft) throw()
  184. {
  185. #if JUCE_GCC
  186. ((ULARGE_INTEGER*) ft)->QuadPart = time * 10000 + 116444736000000000LL;
  187. #else
  188. ((ULARGE_INTEGER*) ft)->QuadPart = time * 10000 + 116444736000000000;
  189. #endif
  190. }
  191. void juce_getFileTimes (const String& fileName,
  192. int64& modificationTime,
  193. int64& accessTime,
  194. int64& creationTime) throw()
  195. {
  196. WIN32_FILE_ATTRIBUTE_DATA attributes;
  197. if (GetFileAttributesEx (fileName, GetFileExInfoStandard, &attributes))
  198. {
  199. modificationTime = fileTimeToTime (&attributes.ftLastWriteTime);
  200. creationTime = fileTimeToTime (&attributes.ftCreationTime);
  201. accessTime = fileTimeToTime (&attributes.ftLastAccessTime);
  202. }
  203. else
  204. {
  205. creationTime = accessTime = modificationTime = 0;
  206. }
  207. }
  208. bool juce_setFileTimes (const String& fileName,
  209. int64 modificationTime,
  210. int64 accessTime,
  211. int64 creationTime) throw()
  212. {
  213. FILETIME m, a, c;
  214. if (modificationTime > 0)
  215. timeToFileTime (modificationTime, &m);
  216. if (accessTime > 0)
  217. timeToFileTime (accessTime, &a);
  218. if (creationTime > 0)
  219. timeToFileTime (creationTime, &c);
  220. void* const h = juce_fileOpen (fileName, true);
  221. bool ok = false;
  222. if (h != 0)
  223. {
  224. ok = SetFileTime ((HANDLE) h,
  225. (creationTime > 0) ? &c : 0,
  226. (accessTime > 0) ? &a : 0,
  227. (modificationTime > 0) ? &m : 0) != 0;
  228. juce_fileClose (h);
  229. }
  230. return ok;
  231. }
  232. //==============================================================================
  233. // return '\0' separated list of strings
  234. const StringArray juce_getFileSystemRoots() throw()
  235. {
  236. TCHAR buffer [2048];
  237. buffer[0] = 0;
  238. buffer[1] = 0;
  239. GetLogicalDriveStrings (2048, buffer);
  240. TCHAR* n = buffer;
  241. StringArray roots;
  242. while (*n != 0)
  243. {
  244. roots.add (String (n));
  245. while (*n++ != 0)
  246. {
  247. }
  248. }
  249. roots.sort (true);
  250. return roots;
  251. }
  252. //==============================================================================
  253. const String juce_getVolumeLabel (const String& filenameOnVolume,
  254. int& volumeSerialNumber) throw()
  255. {
  256. TCHAR n [4];
  257. n[0] = *(const TCHAR*) filenameOnVolume;
  258. n[1] = L':';
  259. n[2] = L'\\';
  260. n[3] = 0;
  261. TCHAR dest [64];
  262. DWORD serialNum;
  263. if (! GetVolumeInformation (n, dest, 64, (DWORD*) &serialNum, 0, 0, 0, 0))
  264. {
  265. dest[0] = 0;
  266. serialNum = 0;
  267. }
  268. volumeSerialNumber = serialNum;
  269. return String (dest);
  270. }
  271. int64 File::getBytesFreeOnVolume() const throw()
  272. {
  273. String fn (getFullPathName());
  274. if (fn[1] == T(':'))
  275. fn = fn.substring (0, 2) + T("\\");
  276. ULARGE_INTEGER spc;
  277. ULARGE_INTEGER tot;
  278. ULARGE_INTEGER totFree;
  279. if (GetDiskFreeSpaceEx (fn, &spc, &tot, &totFree))
  280. return (int64)(spc.QuadPart);
  281. return 0;
  282. }
  283. //==============================================================================
  284. static unsigned int getWindowsDriveType (const String& fileName) throw()
  285. {
  286. TCHAR n[4];
  287. n[0] = *(const TCHAR*) fileName;
  288. n[1] = L':';
  289. n[2] = L'\\';
  290. n[3] = 0;
  291. return GetDriveType (n);
  292. }
  293. bool File::isOnCDRomDrive() const throw()
  294. {
  295. return getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
  296. }
  297. bool File::isOnHardDisk() const throw()
  298. {
  299. if (fullPath.isEmpty())
  300. return false;
  301. const unsigned int n = getWindowsDriveType (getFullPathName());
  302. if (fullPath.toLowerCase()[0] <= 'b'
  303. && fullPath[1] == T(':'))
  304. {
  305. return n != DRIVE_REMOVABLE;
  306. }
  307. else
  308. {
  309. return n != DRIVE_CDROM && n != DRIVE_REMOTE;
  310. }
  311. }
  312. bool File::isOnRemovableDrive() const throw()
  313. {
  314. if (fullPath.isEmpty())
  315. return false;
  316. const unsigned int n = getWindowsDriveType (getFullPathName());
  317. return n == DRIVE_CDROM
  318. || n == DRIVE_REMOTE
  319. || n == DRIVE_REMOVABLE
  320. || n == DRIVE_RAMDISK;
  321. }
  322. //==============================================================================
  323. #define MAX_PATH_CHARS (MAX_PATH + 256)
  324. static const File juce_getSpecialFolderPath (int type) throw()
  325. {
  326. WCHAR path [MAX_PATH_CHARS];
  327. if (SHGetSpecialFolderPath (0, path, type, 0))
  328. return File (String (path));
  329. return File::nonexistent;
  330. }
  331. const File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
  332. {
  333. int csidlType = 0;
  334. switch (type)
  335. {
  336. case userHomeDirectory:
  337. case userDocumentsDirectory:
  338. csidlType = CSIDL_PERSONAL;
  339. break;
  340. case userDesktopDirectory:
  341. csidlType = CSIDL_DESKTOP;
  342. break;
  343. case userApplicationDataDirectory:
  344. csidlType = CSIDL_APPDATA;
  345. break;
  346. case commonApplicationDataDirectory:
  347. csidlType = CSIDL_COMMON_APPDATA;
  348. break;
  349. case globalApplicationsDirectory:
  350. csidlType = CSIDL_PROGRAM_FILES;
  351. break;
  352. case userMusicDirectory:
  353. csidlType = CSIDL_MYMUSIC;
  354. break;
  355. case userMoviesDirectory:
  356. csidlType = CSIDL_MYVIDEO;
  357. break;
  358. case tempDirectory:
  359. {
  360. WCHAR dest [2048];
  361. dest[0] = 0;
  362. GetTempPath (2048, dest);
  363. return File (String (dest));
  364. }
  365. case currentExecutableFile:
  366. case currentApplicationFile:
  367. {
  368. HINSTANCE moduleHandle = (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle();
  369. WCHAR dest [MAX_PATH_CHARS];
  370. dest[0] = 0;
  371. GetModuleFileName (moduleHandle, dest, MAX_PATH_CHARS);
  372. return File (String (dest));
  373. }
  374. break;
  375. default:
  376. jassertfalse // unknown type?
  377. return File::nonexistent;
  378. }
  379. return juce_getSpecialFolderPath (csidlType);
  380. }
  381. void juce_setCurrentExecutableFileName (const String&) throw()
  382. {
  383. // n/a on windows
  384. }
  385. //==============================================================================
  386. const File File::getCurrentWorkingDirectory() throw()
  387. {
  388. WCHAR dest [MAX_PATH_CHARS];
  389. dest[0] = 0;
  390. GetCurrentDirectory (MAX_PATH_CHARS, dest);
  391. return File (String (dest));
  392. }
  393. bool File::setAsCurrentWorkingDirectory() const throw()
  394. {
  395. return SetCurrentDirectory (getFullPathName()) != FALSE;
  396. }
  397. //==============================================================================
  398. template <class FindDataType>
  399. static void getFindFileInfo (FindDataType& findData,
  400. String& filename, bool* const isDir, bool* const isHidden,
  401. int64* const fileSize, Time* const modTime, Time* const creationTime,
  402. bool* const isReadOnly) throw()
  403. {
  404. filename = findData.cFileName;
  405. if (isDir != 0)
  406. *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  407. if (isHidden != 0)
  408. *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
  409. if (fileSize != 0)
  410. *fileSize = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
  411. if (modTime != 0)
  412. *modTime = fileTimeToTime (&findData.ftLastWriteTime);
  413. if (creationTime != 0)
  414. *creationTime = fileTimeToTime (&findData.ftCreationTime);
  415. if (isReadOnly != 0)
  416. *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
  417. }
  418. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResult,
  419. bool* isDir, bool* isHidden, int64* fileSize,
  420. Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  421. {
  422. String wc (directory);
  423. if (! wc.endsWithChar (File::separator))
  424. wc += File::separator;
  425. wc += wildCard;
  426. WIN32_FIND_DATA findData;
  427. HANDLE h = FindFirstFile (wc, &findData);
  428. if (h != INVALID_HANDLE_VALUE)
  429. {
  430. getFindFileInfo (findData, firstResult, isDir, isHidden, fileSize,
  431. modTime, creationTime, isReadOnly);
  432. return h;
  433. }
  434. firstResult = String::empty;
  435. return 0;
  436. }
  437. bool juce_findFileNext (void* handle, String& resultFile,
  438. bool* isDir, bool* isHidden, int64* fileSize,
  439. Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  440. {
  441. WIN32_FIND_DATA findData;
  442. if (handle != 0 && FindNextFile ((HANDLE) handle, &findData) != 0)
  443. {
  444. getFindFileInfo (findData, resultFile, isDir, isHidden, fileSize,
  445. modTime, creationTime, isReadOnly);
  446. return true;
  447. }
  448. resultFile = String::empty;
  449. return false;
  450. }
  451. void juce_findFileClose (void* handle) throw()
  452. {
  453. FindClose (handle);
  454. }
  455. //==============================================================================
  456. bool juce_launchFile (const String& fileName,
  457. const String& parameters) throw()
  458. {
  459. HINSTANCE hInstance = 0;
  460. JUCE_TRY
  461. {
  462. hInstance = ShellExecute (0, 0, fileName, parameters, 0, SW_SHOWDEFAULT);
  463. }
  464. JUCE_CATCH_ALL
  465. return hInstance > (HINSTANCE) 32;
  466. }
  467. //==============================================================================
  468. struct NamedPipeInternal
  469. {
  470. HANDLE pipeH;
  471. HANDLE cancelEvent;
  472. bool connected, createdPipe;
  473. NamedPipeInternal()
  474. : pipeH (0),
  475. cancelEvent (0),
  476. connected (false),
  477. createdPipe (false)
  478. {
  479. cancelEvent = CreateEvent (0, FALSE, FALSE, 0);
  480. }
  481. ~NamedPipeInternal()
  482. {
  483. disconnect();
  484. if (pipeH != 0)
  485. CloseHandle (pipeH);
  486. CloseHandle (cancelEvent);
  487. }
  488. bool connect (const int timeOutMs)
  489. {
  490. if (! createdPipe)
  491. return true;
  492. if (! connected)
  493. {
  494. OVERLAPPED over;
  495. zerostruct (over);
  496. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  497. if (ConnectNamedPipe (pipeH, &over))
  498. {
  499. connected = false; // yes, you read that right. In overlapped mode it should always return 0.
  500. }
  501. else
  502. {
  503. const int err = GetLastError();
  504. if (err == ERROR_IO_PENDING || err == ERROR_PIPE_LISTENING)
  505. {
  506. HANDLE handles[] = { over.hEvent, cancelEvent };
  507. if (WaitForMultipleObjects (2, handles, FALSE,
  508. timeOutMs >= 0 ? timeOutMs : INFINITE) == WAIT_OBJECT_0)
  509. connected = true;
  510. }
  511. else if (err == ERROR_PIPE_CONNECTED)
  512. {
  513. connected = true;
  514. }
  515. }
  516. CloseHandle (over.hEvent);
  517. }
  518. return connected;
  519. }
  520. void disconnect()
  521. {
  522. if (connected)
  523. {
  524. DisconnectNamedPipe (pipeH);
  525. connected = false;
  526. }
  527. }
  528. };
  529. void NamedPipe::close()
  530. {
  531. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  532. delete intern;
  533. internal = 0;
  534. }
  535. bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
  536. {
  537. close();
  538. NamedPipeInternal* const intern = new NamedPipeInternal();
  539. String file ("\\\\.\\pipe\\");
  540. file += pipeName;
  541. intern->createdPipe = createPipe;
  542. if (createPipe)
  543. {
  544. intern->pipeH = CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
  545. PIPE_UNLIMITED_INSTANCES,
  546. 4096, 4096, 0, NULL);
  547. }
  548. else
  549. {
  550. intern->pipeH = CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  551. FILE_FLAG_OVERLAPPED, 0);
  552. }
  553. if (intern->pipeH != INVALID_HANDLE_VALUE)
  554. {
  555. internal = intern;
  556. return true;
  557. }
  558. delete intern;
  559. return false;
  560. }
  561. int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
  562. {
  563. int bytesRead = -1;
  564. bool waitAgain = true;
  565. while (waitAgain && internal != 0)
  566. {
  567. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  568. waitAgain = false;
  569. if (! intern->connect (timeOutMilliseconds))
  570. break;
  571. if (maxBytesToRead <= 0)
  572. return 0;
  573. OVERLAPPED over;
  574. zerostruct (over);
  575. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  576. unsigned long numRead;
  577. if (ReadFile (intern->pipeH, destBuffer, maxBytesToRead, &numRead, &over))
  578. {
  579. bytesRead = (int) numRead;
  580. }
  581. else if (GetLastError() == ERROR_IO_PENDING)
  582. {
  583. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  584. DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
  585. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  586. : INFINITE);
  587. if (waitResult != WAIT_OBJECT_0)
  588. {
  589. // if the operation timed out, let's cancel it...
  590. CancelIo (intern->pipeH);
  591. WaitForSingleObject (over.hEvent, INFINITE); // makes sure cancel is complete
  592. }
  593. if (GetOverlappedResult (intern->pipeH, &over, &numRead, FALSE))
  594. {
  595. bytesRead = (int) numRead;
  596. }
  597. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  598. {
  599. intern->disconnect();
  600. waitAgain = true;
  601. }
  602. }
  603. else
  604. {
  605. waitAgain = internal != 0;
  606. Sleep (5);
  607. }
  608. CloseHandle (over.hEvent);
  609. }
  610. return bytesRead;
  611. }
  612. int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
  613. {
  614. int bytesWritten = -1;
  615. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  616. if (intern != 0 && intern->connect (timeOutMilliseconds))
  617. {
  618. if (numBytesToWrite <= 0)
  619. return 0;
  620. OVERLAPPED over;
  621. zerostruct (over);
  622. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  623. unsigned long numWritten;
  624. if (WriteFile (intern->pipeH, sourceBuffer, numBytesToWrite, &numWritten, &over))
  625. {
  626. bytesWritten = (int) numWritten;
  627. }
  628. else if (GetLastError() == ERROR_IO_PENDING)
  629. {
  630. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  631. DWORD waitResult;
  632. waitResult = WaitForMultipleObjects (2, handles, FALSE,
  633. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  634. : INFINITE);
  635. if (waitResult != WAIT_OBJECT_0)
  636. {
  637. CancelIo (intern->pipeH);
  638. WaitForSingleObject (over.hEvent, INFINITE);
  639. }
  640. if (GetOverlappedResult (intern->pipeH, &over, &numWritten, FALSE))
  641. {
  642. bytesWritten = (int) numWritten;
  643. }
  644. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  645. {
  646. intern->disconnect();
  647. }
  648. }
  649. CloseHandle (over.hEvent);
  650. }
  651. return bytesWritten;
  652. }
  653. void NamedPipe::cancelPendingReads()
  654. {
  655. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  656. if (intern != 0)
  657. SetEvent (intern->cancelEvent);
  658. }
  659. #endif