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.

915 lines
25KB

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