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.

924 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, const bool dontCountDirectories)
  33. {
  34. if (fileName.isEmpty())
  35. return false;
  36. const DWORD attr = GetFileAttributes (fileName);
  37. return dontCountDirectories ? ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
  38. : (attr != 0xffffffff);
  39. }
  40. bool juce_isDirectory (const String& fileName)
  41. {
  42. const DWORD attr = GetFileAttributes (fileName);
  43. return (attr != 0xffffffff)
  44. && ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0);
  45. }
  46. bool juce_canWriteToFile (const String& fileName)
  47. {
  48. const DWORD attr = GetFileAttributes (fileName);
  49. return ((attr & FILE_ATTRIBUTE_READONLY) == 0);
  50. }
  51. bool juce_setFileReadOnly (const String& fileName, bool isReadOnly)
  52. {
  53. DWORD attr = GetFileAttributes (fileName);
  54. if (attr == 0xffffffff)
  55. return false;
  56. if (isReadOnly != juce_canWriteToFile (fileName))
  57. return true;
  58. if (isReadOnly)
  59. attr |= FILE_ATTRIBUTE_READONLY;
  60. else
  61. attr &= ~FILE_ATTRIBUTE_READONLY;
  62. return SetFileAttributes (fileName, attr) != FALSE;
  63. }
  64. bool File::isHidden() const
  65. {
  66. return (GetFileAttributes (getFullPathName()) & FILE_ATTRIBUTE_HIDDEN) != 0;
  67. }
  68. //==============================================================================
  69. bool juce_deleteFile (const String& fileName)
  70. {
  71. if (juce_isDirectory (fileName))
  72. return RemoveDirectory (fileName) != 0;
  73. return DeleteFile (fileName) != 0;
  74. }
  75. bool File::moveToTrash() const
  76. {
  77. if (! exists())
  78. return true;
  79. SHFILEOPSTRUCT fos;
  80. zerostruct (fos);
  81. // The string we pass in must be double null terminated..
  82. String doubleNullTermPath (getFullPathName() + " ");
  83. TCHAR* p = (TCHAR*) (const TCHAR*) doubleNullTermPath;
  84. p [getFullPathName().length()] = 0;
  85. fos.wFunc = FO_DELETE;
  86. fos.hwnd = (HWND) 0;
  87. fos.pFrom = p;
  88. fos.pTo = NULL;
  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. {
  105. CreateDirectory (fileName, 0);
  106. }
  107. }
  108. //==============================================================================
  109. // return 0 if not possible
  110. void* juce_fileOpen (const String& fileName, bool forWriting)
  111. {
  112. HANDLE h;
  113. if (forWriting)
  114. {
  115. h = CreateFile (fileName, GENERIC_WRITE, FILE_SHARE_READ, 0,
  116. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  117. if (h != INVALID_HANDLE_VALUE)
  118. SetFilePointer (h, 0, 0, FILE_END);
  119. else
  120. h = 0;
  121. }
  122. else
  123. {
  124. h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  125. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
  126. if (h == INVALID_HANDLE_VALUE)
  127. h = 0;
  128. }
  129. return (void*) h;
  130. }
  131. void juce_fileClose (void* handle)
  132. {
  133. CloseHandle (handle);
  134. }
  135. //==============================================================================
  136. int juce_fileRead (void* handle, void* buffer, int size)
  137. {
  138. DWORD num = 0;
  139. ReadFile ((HANDLE) handle, buffer, size, &num, 0);
  140. return num;
  141. }
  142. int juce_fileWrite (void* handle, const void* buffer, int size)
  143. {
  144. DWORD num;
  145. WriteFile ((HANDLE) handle,
  146. buffer, size,
  147. &num, 0);
  148. return num;
  149. }
  150. int64 juce_fileSetPosition (void* handle, int64 pos)
  151. {
  152. LARGE_INTEGER li;
  153. li.QuadPart = pos;
  154. li.LowPart = SetFilePointer ((HANDLE) handle,
  155. li.LowPart,
  156. &li.HighPart,
  157. FILE_BEGIN); // (returns -1 if it fails)
  158. return li.QuadPart;
  159. }
  160. int64 juce_fileGetPosition (void* handle)
  161. {
  162. LARGE_INTEGER li;
  163. li.QuadPart = 0;
  164. li.LowPart = SetFilePointer ((HANDLE) handle,
  165. 0, &li.HighPart,
  166. FILE_CURRENT); // (returns -1 if it fails)
  167. return jmax ((int64) 0, li.QuadPart);
  168. }
  169. void juce_fileFlush (void* handle)
  170. {
  171. FlushFileBuffers ((HANDLE) handle);
  172. }
  173. int64 juce_getFileSize (const String& fileName)
  174. {
  175. WIN32_FILE_ATTRIBUTE_DATA attributes;
  176. if (GetFileAttributesEx (fileName, GetFileExInfoStandard, &attributes))
  177. {
  178. return (((int64) attributes.nFileSizeHigh) << 32)
  179. | attributes.nFileSizeLow;
  180. }
  181. return 0;
  182. }
  183. //==============================================================================
  184. static int64 fileTimeToTime (const FILETIME* const ft)
  185. {
  186. // tell me if this fails!
  187. static_jassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME));
  188. #if JUCE_GCC
  189. return (((const ULARGE_INTEGER*) ft)->QuadPart - 116444736000000000LL) / 10000;
  190. #else
  191. return (((const ULARGE_INTEGER*) ft)->QuadPart - 116444736000000000) / 10000;
  192. #endif
  193. }
  194. static void timeToFileTime (const int64 time, FILETIME* const ft)
  195. {
  196. #if JUCE_GCC
  197. ((ULARGE_INTEGER*) ft)->QuadPart = time * 10000 + 116444736000000000LL;
  198. #else
  199. ((ULARGE_INTEGER*) ft)->QuadPart = time * 10000 + 116444736000000000;
  200. #endif
  201. }
  202. void juce_getFileTimes (const String& fileName,
  203. int64& modificationTime,
  204. int64& accessTime,
  205. int64& creationTime)
  206. {
  207. WIN32_FILE_ATTRIBUTE_DATA attributes;
  208. if (GetFileAttributesEx (fileName, GetFileExInfoStandard, &attributes))
  209. {
  210. modificationTime = fileTimeToTime (&attributes.ftLastWriteTime);
  211. creationTime = fileTimeToTime (&attributes.ftCreationTime);
  212. accessTime = fileTimeToTime (&attributes.ftLastAccessTime);
  213. }
  214. else
  215. {
  216. creationTime = accessTime = modificationTime = 0;
  217. }
  218. }
  219. bool juce_setFileTimes (const String& fileName,
  220. int64 modificationTime,
  221. int64 accessTime,
  222. int64 creationTime)
  223. {
  224. FILETIME m, a, c;
  225. if (modificationTime > 0)
  226. timeToFileTime (modificationTime, &m);
  227. if (accessTime > 0)
  228. timeToFileTime (accessTime, &a);
  229. if (creationTime > 0)
  230. timeToFileTime (creationTime, &c);
  231. void* const h = juce_fileOpen (fileName, true);
  232. bool ok = false;
  233. if (h != 0)
  234. {
  235. ok = SetFileTime ((HANDLE) h,
  236. (creationTime > 0) ? &c : 0,
  237. (accessTime > 0) ? &a : 0,
  238. (modificationTime > 0) ? &m : 0) != 0;
  239. juce_fileClose (h);
  240. }
  241. return ok;
  242. }
  243. //==============================================================================
  244. // return '\0' separated list of strings
  245. const StringArray juce_getFileSystemRoots()
  246. {
  247. TCHAR buffer [2048];
  248. buffer[0] = 0;
  249. buffer[1] = 0;
  250. GetLogicalDriveStrings (2048, buffer);
  251. TCHAR* n = buffer;
  252. StringArray roots;
  253. while (*n != 0)
  254. {
  255. roots.add (String (n));
  256. while (*n++ != 0)
  257. {
  258. }
  259. }
  260. roots.sort (true);
  261. return roots;
  262. }
  263. //==============================================================================
  264. const String juce_getVolumeLabel (const String& filenameOnVolume,
  265. int& volumeSerialNumber)
  266. {
  267. TCHAR n [4];
  268. n[0] = *(const TCHAR*) filenameOnVolume;
  269. n[1] = L':';
  270. n[2] = L'\\';
  271. n[3] = 0;
  272. TCHAR dest [64];
  273. DWORD serialNum;
  274. if (! GetVolumeInformation (n, dest, 64, (DWORD*) &serialNum, 0, 0, 0, 0))
  275. {
  276. dest[0] = 0;
  277. serialNum = 0;
  278. }
  279. volumeSerialNumber = serialNum;
  280. return String (dest);
  281. }
  282. static int64 getDiskSpaceInfo (String fn, const bool total)
  283. {
  284. if (fn[1] == T(':'))
  285. fn = fn.substring (0, 2) + T("\\");
  286. ULARGE_INTEGER spc, tot, totFree;
  287. if (GetDiskFreeSpaceEx (fn, &spc, &tot, &totFree))
  288. return (int64) (total ? tot.QuadPart
  289. : spc.QuadPart);
  290. return 0;
  291. }
  292. int64 File::getBytesFreeOnVolume() const
  293. {
  294. return getDiskSpaceInfo (getFullPathName(), false);
  295. }
  296. int64 File::getVolumeTotalSize() const
  297. {
  298. return getDiskSpaceInfo (getFullPathName(), true);
  299. }
  300. //==============================================================================
  301. static unsigned int getWindowsDriveType (const String& fileName)
  302. {
  303. TCHAR n[4];
  304. n[0] = *(const TCHAR*) fileName;
  305. n[1] = L':';
  306. n[2] = L'\\';
  307. n[3] = 0;
  308. return GetDriveType (n);
  309. }
  310. bool File::isOnCDRomDrive() const
  311. {
  312. return getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
  313. }
  314. bool File::isOnHardDisk() const
  315. {
  316. if (fullPath.isEmpty())
  317. return false;
  318. const unsigned int n = getWindowsDriveType (getFullPathName());
  319. if (fullPath.toLowerCase()[0] <= 'b'
  320. && fullPath[1] == T(':'))
  321. {
  322. return n != DRIVE_REMOVABLE;
  323. }
  324. else
  325. {
  326. return n != DRIVE_CDROM && n != DRIVE_REMOTE;
  327. }
  328. }
  329. bool File::isOnRemovableDrive() const
  330. {
  331. if (fullPath.isEmpty())
  332. return false;
  333. const unsigned int n = getWindowsDriveType (getFullPathName());
  334. return n == DRIVE_CDROM
  335. || n == DRIVE_REMOTE
  336. || n == DRIVE_REMOVABLE
  337. || n == DRIVE_RAMDISK;
  338. }
  339. //==============================================================================
  340. #define MAX_PATH_CHARS (MAX_PATH + 256)
  341. static const File juce_getSpecialFolderPath (int type)
  342. {
  343. WCHAR path [MAX_PATH_CHARS];
  344. if (SHGetSpecialFolderPath (0, path, type, 0))
  345. return File (String (path));
  346. return File::nonexistent;
  347. }
  348. const File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
  349. {
  350. int csidlType = 0;
  351. switch (type)
  352. {
  353. case userHomeDirectory:
  354. csidlType = CSIDL_PROFILE;
  355. break;
  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 invokedExecutableFile:
  385. case currentExecutableFile:
  386. case currentApplicationFile:
  387. {
  388. HINSTANCE moduleHandle = (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle();
  389. WCHAR dest [MAX_PATH_CHARS];
  390. dest[0] = 0;
  391. GetModuleFileName (moduleHandle, dest, MAX_PATH_CHARS);
  392. return File (String (dest));
  393. }
  394. break;
  395. default:
  396. jassertfalse // unknown type?
  397. return File::nonexistent;
  398. }
  399. return juce_getSpecialFolderPath (csidlType);
  400. }
  401. //==============================================================================
  402. const File File::getCurrentWorkingDirectory()
  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
  410. {
  411. return SetCurrentDirectory (getFullPathName()) != FALSE;
  412. }
  413. //==============================================================================
  414. const String File::getVersion() const
  415. {
  416. String result;
  417. DWORD handle = 0;
  418. DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle);
  419. HeapBlock <char> buffer;
  420. buffer.calloc (bufferSize);
  421. if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer))
  422. {
  423. VS_FIXEDFILEINFO* vffi;
  424. UINT len = 0;
  425. if (VerQueryValue (buffer, _T("\\"), (LPVOID*) &vffi, &len))
  426. {
  427. result << (int) HIWORD (vffi->dwFileVersionMS) << "."
  428. << (int) LOWORD (vffi->dwFileVersionMS) << "."
  429. << (int) HIWORD (vffi->dwFileVersionLS) << "."
  430. << (int) LOWORD (vffi->dwFileVersionLS);
  431. }
  432. }
  433. return result;
  434. }
  435. //==============================================================================
  436. const File File::getLinkedTarget() const
  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)
  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)
  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)
  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)
  517. {
  518. FindClose (handle);
  519. }
  520. //==============================================================================
  521. bool juce_launchFile (const String& fileName,
  522. const String& parameters)
  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. void File::revealToUser() const
  533. {
  534. if (isDirectory())
  535. startAsProcess();
  536. else if (getParentDirectory().exists())
  537. getParentDirectory().startAsProcess();
  538. }
  539. //==============================================================================
  540. struct NamedPipeInternal
  541. {
  542. HANDLE pipeH;
  543. HANDLE cancelEvent;
  544. bool connected, createdPipe;
  545. NamedPipeInternal()
  546. : pipeH (0),
  547. cancelEvent (0),
  548. connected (false),
  549. createdPipe (false)
  550. {
  551. cancelEvent = CreateEvent (0, FALSE, FALSE, 0);
  552. }
  553. ~NamedPipeInternal()
  554. {
  555. disconnect();
  556. if (pipeH != 0)
  557. CloseHandle (pipeH);
  558. CloseHandle (cancelEvent);
  559. }
  560. bool connect (const int timeOutMs)
  561. {
  562. if (! createdPipe)
  563. return true;
  564. if (! connected)
  565. {
  566. OVERLAPPED over;
  567. zerostruct (over);
  568. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  569. if (ConnectNamedPipe (pipeH, &over))
  570. {
  571. connected = false; // yes, you read that right. In overlapped mode it should always return 0.
  572. }
  573. else
  574. {
  575. const int err = GetLastError();
  576. if (err == ERROR_IO_PENDING || err == ERROR_PIPE_LISTENING)
  577. {
  578. HANDLE handles[] = { over.hEvent, cancelEvent };
  579. if (WaitForMultipleObjects (2, handles, FALSE,
  580. timeOutMs >= 0 ? timeOutMs : INFINITE) == WAIT_OBJECT_0)
  581. connected = true;
  582. }
  583. else if (err == ERROR_PIPE_CONNECTED)
  584. {
  585. connected = true;
  586. }
  587. }
  588. CloseHandle (over.hEvent);
  589. }
  590. return connected;
  591. }
  592. void disconnect()
  593. {
  594. if (connected)
  595. {
  596. DisconnectNamedPipe (pipeH);
  597. connected = false;
  598. }
  599. }
  600. };
  601. void NamedPipe::close()
  602. {
  603. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  604. delete intern;
  605. internal = 0;
  606. }
  607. bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
  608. {
  609. close();
  610. NamedPipeInternal* const intern = new NamedPipeInternal();
  611. String file ("\\\\.\\pipe\\");
  612. file += pipeName;
  613. intern->createdPipe = createPipe;
  614. if (createPipe)
  615. {
  616. intern->pipeH = CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
  617. PIPE_UNLIMITED_INSTANCES,
  618. 4096, 4096, 0, NULL);
  619. }
  620. else
  621. {
  622. intern->pipeH = CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  623. FILE_FLAG_OVERLAPPED, 0);
  624. }
  625. if (intern->pipeH != INVALID_HANDLE_VALUE)
  626. {
  627. internal = intern;
  628. return true;
  629. }
  630. delete intern;
  631. return false;
  632. }
  633. int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
  634. {
  635. int bytesRead = -1;
  636. bool waitAgain = true;
  637. while (waitAgain && internal != 0)
  638. {
  639. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  640. waitAgain = false;
  641. if (! intern->connect (timeOutMilliseconds))
  642. break;
  643. if (maxBytesToRead <= 0)
  644. return 0;
  645. OVERLAPPED over;
  646. zerostruct (over);
  647. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  648. unsigned long numRead;
  649. if (ReadFile (intern->pipeH, destBuffer, maxBytesToRead, &numRead, &over))
  650. {
  651. bytesRead = (int) numRead;
  652. }
  653. else if (GetLastError() == ERROR_IO_PENDING)
  654. {
  655. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  656. DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
  657. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  658. : INFINITE);
  659. if (waitResult != WAIT_OBJECT_0)
  660. {
  661. // if the operation timed out, let's cancel it...
  662. CancelIo (intern->pipeH);
  663. WaitForSingleObject (over.hEvent, INFINITE); // makes sure cancel is complete
  664. }
  665. if (GetOverlappedResult (intern->pipeH, &over, &numRead, FALSE))
  666. {
  667. bytesRead = (int) numRead;
  668. }
  669. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  670. {
  671. intern->disconnect();
  672. waitAgain = true;
  673. }
  674. }
  675. else
  676. {
  677. waitAgain = internal != 0;
  678. Sleep (5);
  679. }
  680. CloseHandle (over.hEvent);
  681. }
  682. return bytesRead;
  683. }
  684. int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
  685. {
  686. int bytesWritten = -1;
  687. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  688. if (intern != 0 && intern->connect (timeOutMilliseconds))
  689. {
  690. if (numBytesToWrite <= 0)
  691. return 0;
  692. OVERLAPPED over;
  693. zerostruct (over);
  694. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  695. unsigned long numWritten;
  696. if (WriteFile (intern->pipeH, sourceBuffer, numBytesToWrite, &numWritten, &over))
  697. {
  698. bytesWritten = (int) numWritten;
  699. }
  700. else if (GetLastError() == ERROR_IO_PENDING)
  701. {
  702. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  703. DWORD waitResult;
  704. waitResult = WaitForMultipleObjects (2, handles, FALSE,
  705. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  706. : INFINITE);
  707. if (waitResult != WAIT_OBJECT_0)
  708. {
  709. CancelIo (intern->pipeH);
  710. WaitForSingleObject (over.hEvent, INFINITE);
  711. }
  712. if (GetOverlappedResult (intern->pipeH, &over, &numWritten, FALSE))
  713. {
  714. bytesWritten = (int) numWritten;
  715. }
  716. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  717. {
  718. intern->disconnect();
  719. }
  720. }
  721. CloseHandle (over.hEvent);
  722. }
  723. return bytesWritten;
  724. }
  725. void NamedPipe::cancelPendingReads()
  726. {
  727. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  728. if (intern != 0)
  729. SetEvent (intern->cancelEvent);
  730. }
  731. #endif