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.

840 lines
24KB

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