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-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) throw()
  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 String File::getVersion() const throw()
  417. {
  418. String result;
  419. DWORD handle = 0;
  420. DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle);
  421. void* buffer = juce_calloc (bufferSize);
  422. if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer))
  423. {
  424. VS_FIXEDFILEINFO* vffi;
  425. UINT len = 0;
  426. if (VerQueryValue (buffer, _T("\\"), (LPVOID*) &vffi, &len))
  427. {
  428. result.printf (T("%d.%d.%d.%d"),
  429. HIWORD (vffi->dwFileVersionMS),
  430. LOWORD (vffi->dwFileVersionMS),
  431. HIWORD (vffi->dwFileVersionLS),
  432. LOWORD (vffi->dwFileVersionLS));
  433. }
  434. }
  435. juce_free (buffer);
  436. return result;
  437. }
  438. //==============================================================================
  439. const File File::getLinkedTarget() const throw()
  440. {
  441. File result (*this);
  442. String p (getFullPathName());
  443. if (! exists())
  444. p += T(".lnk");
  445. else if (getFileExtension() != T(".lnk"))
  446. return result;
  447. IShellLink* shellLink = 0;
  448. if (SUCCEEDED (CoCreateInstance (CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER,
  449. IID_IShellLink, (LPVOID*) &shellLink)))
  450. {
  451. IPersistFile* persistFile;
  452. if (SUCCEEDED (shellLink->QueryInterface (IID_IPersistFile, (LPVOID*) &persistFile)))
  453. {
  454. if (SUCCEEDED (persistFile->Load ((const WCHAR*) p, STGM_READ))
  455. && SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))
  456. {
  457. WIN32_FIND_DATA winFindData;
  458. WCHAR resolvedPath [MAX_PATH];
  459. if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY)))
  460. result = File (resolvedPath);
  461. }
  462. persistFile->Release();
  463. }
  464. shellLink->Release();
  465. }
  466. return result;
  467. }
  468. //==============================================================================
  469. template <class FindDataType>
  470. static void getFindFileInfo (FindDataType& findData,
  471. String& filename, bool* const isDir, bool* const isHidden,
  472. int64* const fileSize, Time* const modTime, Time* const creationTime,
  473. bool* const isReadOnly) throw()
  474. {
  475. filename = findData.cFileName;
  476. if (isDir != 0)
  477. *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  478. if (isHidden != 0)
  479. *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
  480. if (fileSize != 0)
  481. *fileSize = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
  482. if (modTime != 0)
  483. *modTime = fileTimeToTime (&findData.ftLastWriteTime);
  484. if (creationTime != 0)
  485. *creationTime = fileTimeToTime (&findData.ftCreationTime);
  486. if (isReadOnly != 0)
  487. *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
  488. }
  489. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResult,
  490. bool* isDir, bool* isHidden, int64* fileSize,
  491. Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  492. {
  493. String wc (directory);
  494. if (! wc.endsWithChar (File::separator))
  495. wc += File::separator;
  496. wc += wildCard;
  497. WIN32_FIND_DATA findData;
  498. HANDLE h = FindFirstFile (wc, &findData);
  499. if (h != INVALID_HANDLE_VALUE)
  500. {
  501. getFindFileInfo (findData, firstResult, isDir, isHidden, fileSize,
  502. modTime, creationTime, isReadOnly);
  503. return h;
  504. }
  505. firstResult = String::empty;
  506. return 0;
  507. }
  508. bool juce_findFileNext (void* handle, String& resultFile,
  509. bool* isDir, bool* isHidden, int64* fileSize,
  510. Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  511. {
  512. WIN32_FIND_DATA findData;
  513. if (handle != 0 && FindNextFile ((HANDLE) handle, &findData) != 0)
  514. {
  515. getFindFileInfo (findData, resultFile, isDir, isHidden, fileSize,
  516. modTime, creationTime, isReadOnly);
  517. return true;
  518. }
  519. resultFile = String::empty;
  520. return false;
  521. }
  522. void juce_findFileClose (void* handle) throw()
  523. {
  524. FindClose (handle);
  525. }
  526. //==============================================================================
  527. bool juce_launchFile (const String& fileName,
  528. const String& parameters) throw()
  529. {
  530. HINSTANCE hInstance = 0;
  531. JUCE_TRY
  532. {
  533. hInstance = ShellExecute (0, 0, fileName, parameters, 0, SW_SHOWDEFAULT);
  534. }
  535. JUCE_CATCH_ALL
  536. return hInstance > (HINSTANCE) 32;
  537. }
  538. //==============================================================================
  539. struct NamedPipeInternal
  540. {
  541. HANDLE pipeH;
  542. HANDLE cancelEvent;
  543. bool connected, createdPipe;
  544. NamedPipeInternal()
  545. : pipeH (0),
  546. cancelEvent (0),
  547. connected (false),
  548. createdPipe (false)
  549. {
  550. cancelEvent = CreateEvent (0, FALSE, FALSE, 0);
  551. }
  552. ~NamedPipeInternal()
  553. {
  554. disconnect();
  555. if (pipeH != 0)
  556. CloseHandle (pipeH);
  557. CloseHandle (cancelEvent);
  558. }
  559. bool connect (const int timeOutMs)
  560. {
  561. if (! createdPipe)
  562. return true;
  563. if (! connected)
  564. {
  565. OVERLAPPED over;
  566. zerostruct (over);
  567. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  568. if (ConnectNamedPipe (pipeH, &over))
  569. {
  570. connected = false; // yes, you read that right. In overlapped mode it should always return 0.
  571. }
  572. else
  573. {
  574. const int err = GetLastError();
  575. if (err == ERROR_IO_PENDING || err == ERROR_PIPE_LISTENING)
  576. {
  577. HANDLE handles[] = { over.hEvent, cancelEvent };
  578. if (WaitForMultipleObjects (2, handles, FALSE,
  579. timeOutMs >= 0 ? timeOutMs : INFINITE) == WAIT_OBJECT_0)
  580. connected = true;
  581. }
  582. else if (err == ERROR_PIPE_CONNECTED)
  583. {
  584. connected = true;
  585. }
  586. }
  587. CloseHandle (over.hEvent);
  588. }
  589. return connected;
  590. }
  591. void disconnect()
  592. {
  593. if (connected)
  594. {
  595. DisconnectNamedPipe (pipeH);
  596. connected = false;
  597. }
  598. }
  599. };
  600. void NamedPipe::close()
  601. {
  602. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  603. delete intern;
  604. internal = 0;
  605. }
  606. bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
  607. {
  608. close();
  609. NamedPipeInternal* const intern = new NamedPipeInternal();
  610. String file ("\\\\.\\pipe\\");
  611. file += pipeName;
  612. intern->createdPipe = createPipe;
  613. if (createPipe)
  614. {
  615. intern->pipeH = CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
  616. PIPE_UNLIMITED_INSTANCES,
  617. 4096, 4096, 0, NULL);
  618. }
  619. else
  620. {
  621. intern->pipeH = CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  622. FILE_FLAG_OVERLAPPED, 0);
  623. }
  624. if (intern->pipeH != INVALID_HANDLE_VALUE)
  625. {
  626. internal = intern;
  627. return true;
  628. }
  629. delete intern;
  630. return false;
  631. }
  632. int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
  633. {
  634. int bytesRead = -1;
  635. bool waitAgain = true;
  636. while (waitAgain && internal != 0)
  637. {
  638. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  639. waitAgain = false;
  640. if (! intern->connect (timeOutMilliseconds))
  641. break;
  642. if (maxBytesToRead <= 0)
  643. return 0;
  644. OVERLAPPED over;
  645. zerostruct (over);
  646. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  647. unsigned long numRead;
  648. if (ReadFile (intern->pipeH, destBuffer, maxBytesToRead, &numRead, &over))
  649. {
  650. bytesRead = (int) numRead;
  651. }
  652. else if (GetLastError() == ERROR_IO_PENDING)
  653. {
  654. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  655. DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
  656. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  657. : INFINITE);
  658. if (waitResult != WAIT_OBJECT_0)
  659. {
  660. // if the operation timed out, let's cancel it...
  661. CancelIo (intern->pipeH);
  662. WaitForSingleObject (over.hEvent, INFINITE); // makes sure cancel is complete
  663. }
  664. if (GetOverlappedResult (intern->pipeH, &over, &numRead, FALSE))
  665. {
  666. bytesRead = (int) numRead;
  667. }
  668. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  669. {
  670. intern->disconnect();
  671. waitAgain = true;
  672. }
  673. }
  674. else
  675. {
  676. waitAgain = internal != 0;
  677. Sleep (5);
  678. }
  679. CloseHandle (over.hEvent);
  680. }
  681. return bytesRead;
  682. }
  683. int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
  684. {
  685. int bytesWritten = -1;
  686. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  687. if (intern != 0 && intern->connect (timeOutMilliseconds))
  688. {
  689. if (numBytesToWrite <= 0)
  690. return 0;
  691. OVERLAPPED over;
  692. zerostruct (over);
  693. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  694. unsigned long numWritten;
  695. if (WriteFile (intern->pipeH, sourceBuffer, numBytesToWrite, &numWritten, &over))
  696. {
  697. bytesWritten = (int) numWritten;
  698. }
  699. else if (GetLastError() == ERROR_IO_PENDING)
  700. {
  701. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  702. DWORD waitResult;
  703. waitResult = WaitForMultipleObjects (2, handles, FALSE,
  704. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  705. : INFINITE);
  706. if (waitResult != WAIT_OBJECT_0)
  707. {
  708. CancelIo (intern->pipeH);
  709. WaitForSingleObject (over.hEvent, INFINITE);
  710. }
  711. if (GetOverlappedResult (intern->pipeH, &over, &numWritten, FALSE))
  712. {
  713. bytesWritten = (int) numWritten;
  714. }
  715. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  716. {
  717. intern->disconnect();
  718. }
  719. }
  720. CloseHandle (over.hEvent);
  721. }
  722. return bytesWritten;
  723. }
  724. void NamedPipe::cancelPendingReads()
  725. {
  726. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  727. if (intern != 0)
  728. SetEvent (intern->cancelEvent);
  729. }
  730. #endif