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.

895 lines
24KB

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