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.

839 lines
22KB

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