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.

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