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.

927 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. static int64 getDiskSpaceInfo (String fn, const bool total) throw()
  290. {
  291. if (fn[1] == T(':'))
  292. fn = fn.substring (0, 2) + T("\\");
  293. ULARGE_INTEGER spc, tot, totFree;
  294. if (GetDiskFreeSpaceEx (fn, &spc, &tot, &totFree))
  295. return (int64) (total ? tot.QuadPart
  296. : spc.QuadPart);
  297. return 0;
  298. }
  299. int64 File::getBytesFreeOnVolume() const throw()
  300. {
  301. return getDiskSpaceInfo (getFullPathName(), false);
  302. }
  303. int64 File::getVolumeTotalSize() const throw()
  304. {
  305. return getDiskSpaceInfo (getFullPathName(), true);
  306. }
  307. //==============================================================================
  308. static unsigned int getWindowsDriveType (const String& fileName) throw()
  309. {
  310. TCHAR n[4];
  311. n[0] = *(const TCHAR*) fileName;
  312. n[1] = L':';
  313. n[2] = L'\\';
  314. n[3] = 0;
  315. return GetDriveType (n);
  316. }
  317. bool File::isOnCDRomDrive() const throw()
  318. {
  319. return getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
  320. }
  321. bool File::isOnHardDisk() const throw()
  322. {
  323. if (fullPath.isEmpty())
  324. return false;
  325. const unsigned int n = getWindowsDriveType (getFullPathName());
  326. if (fullPath.toLowerCase()[0] <= 'b'
  327. && fullPath[1] == T(':'))
  328. {
  329. return n != DRIVE_REMOVABLE;
  330. }
  331. else
  332. {
  333. return n != DRIVE_CDROM && n != DRIVE_REMOTE;
  334. }
  335. }
  336. bool File::isOnRemovableDrive() const throw()
  337. {
  338. if (fullPath.isEmpty())
  339. return false;
  340. const unsigned int n = getWindowsDriveType (getFullPathName());
  341. return n == DRIVE_CDROM
  342. || n == DRIVE_REMOTE
  343. || n == DRIVE_REMOVABLE
  344. || n == DRIVE_RAMDISK;
  345. }
  346. //==============================================================================
  347. #define MAX_PATH_CHARS (MAX_PATH + 256)
  348. static const File juce_getSpecialFolderPath (int type) throw()
  349. {
  350. WCHAR path [MAX_PATH_CHARS];
  351. if (SHGetSpecialFolderPath (0, path, type, 0))
  352. return File (String (path));
  353. return File::nonexistent;
  354. }
  355. const File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
  356. {
  357. int csidlType = 0;
  358. switch (type)
  359. {
  360. case userHomeDirectory:
  361. case userDocumentsDirectory:
  362. csidlType = CSIDL_PERSONAL;
  363. break;
  364. case userDesktopDirectory:
  365. csidlType = CSIDL_DESKTOP;
  366. break;
  367. case userApplicationDataDirectory:
  368. csidlType = CSIDL_APPDATA;
  369. break;
  370. case commonApplicationDataDirectory:
  371. csidlType = CSIDL_COMMON_APPDATA;
  372. break;
  373. case globalApplicationsDirectory:
  374. csidlType = CSIDL_PROGRAM_FILES;
  375. break;
  376. case userMusicDirectory:
  377. csidlType = CSIDL_MYMUSIC;
  378. break;
  379. case userMoviesDirectory:
  380. csidlType = CSIDL_MYVIDEO;
  381. break;
  382. case tempDirectory:
  383. {
  384. WCHAR dest [2048];
  385. dest[0] = 0;
  386. GetTempPath (2048, dest);
  387. return File (String (dest));
  388. }
  389. case currentExecutableFile:
  390. case currentApplicationFile:
  391. {
  392. HINSTANCE moduleHandle = (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle();
  393. WCHAR dest [MAX_PATH_CHARS];
  394. dest[0] = 0;
  395. GetModuleFileName (moduleHandle, dest, MAX_PATH_CHARS);
  396. return File (String (dest));
  397. }
  398. break;
  399. default:
  400. jassertfalse // unknown type?
  401. return File::nonexistent;
  402. }
  403. return juce_getSpecialFolderPath (csidlType);
  404. }
  405. void juce_setCurrentExecutableFileName (const String&) throw()
  406. {
  407. // n/a on windows
  408. }
  409. //==============================================================================
  410. const File File::getCurrentWorkingDirectory() throw()
  411. {
  412. WCHAR dest [MAX_PATH_CHARS];
  413. dest[0] = 0;
  414. GetCurrentDirectory (MAX_PATH_CHARS, dest);
  415. return File (String (dest));
  416. }
  417. bool File::setAsCurrentWorkingDirectory() const throw()
  418. {
  419. return SetCurrentDirectory (getFullPathName()) != FALSE;
  420. }
  421. //==============================================================================
  422. const String File::getVersion() const throw()
  423. {
  424. String result;
  425. DWORD handle = 0;
  426. DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle);
  427. void* buffer = juce_calloc (bufferSize);
  428. if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer))
  429. {
  430. VS_FIXEDFILEINFO* vffi;
  431. UINT len = 0;
  432. if (VerQueryValue (buffer, _T("\\"), (LPVOID*) &vffi, &len))
  433. {
  434. result.printf (T("%d.%d.%d.%d"),
  435. HIWORD (vffi->dwFileVersionMS),
  436. LOWORD (vffi->dwFileVersionMS),
  437. HIWORD (vffi->dwFileVersionLS),
  438. LOWORD (vffi->dwFileVersionLS));
  439. }
  440. }
  441. juce_free (buffer);
  442. return result;
  443. }
  444. //==============================================================================
  445. const File File::getLinkedTarget() const throw()
  446. {
  447. File result (*this);
  448. String p (getFullPathName());
  449. if (! exists())
  450. p += T(".lnk");
  451. else if (getFileExtension() != T(".lnk"))
  452. return result;
  453. ComSmartPtr <IShellLink> shellLink;
  454. if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink, CLSCTX_INPROC_SERVER)))
  455. {
  456. ComSmartPtr <IPersistFile> persistFile;
  457. if (SUCCEEDED (shellLink->QueryInterface (IID_IPersistFile, (LPVOID*) &persistFile)))
  458. {
  459. if (SUCCEEDED (persistFile->Load ((const WCHAR*) p, STGM_READ))
  460. && SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))
  461. {
  462. WIN32_FIND_DATA winFindData;
  463. WCHAR resolvedPath [MAX_PATH];
  464. if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY)))
  465. result = File (resolvedPath);
  466. }
  467. }
  468. }
  469. return result;
  470. }
  471. //==============================================================================
  472. template <class FindDataType>
  473. static void getFindFileInfo (FindDataType& findData,
  474. String& filename, bool* const isDir, bool* const isHidden,
  475. int64* const fileSize, Time* const modTime, Time* const creationTime,
  476. bool* const isReadOnly) throw()
  477. {
  478. filename = findData.cFileName;
  479. if (isDir != 0)
  480. *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  481. if (isHidden != 0)
  482. *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
  483. if (fileSize != 0)
  484. *fileSize = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
  485. if (modTime != 0)
  486. *modTime = fileTimeToTime (&findData.ftLastWriteTime);
  487. if (creationTime != 0)
  488. *creationTime = fileTimeToTime (&findData.ftCreationTime);
  489. if (isReadOnly != 0)
  490. *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
  491. }
  492. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResult,
  493. bool* isDir, bool* isHidden, int64* fileSize,
  494. Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  495. {
  496. String wc (directory);
  497. if (! wc.endsWithChar (File::separator))
  498. wc += File::separator;
  499. wc += wildCard;
  500. WIN32_FIND_DATA findData;
  501. HANDLE h = FindFirstFile (wc, &findData);
  502. if (h != INVALID_HANDLE_VALUE)
  503. {
  504. getFindFileInfo (findData, firstResult, isDir, isHidden, fileSize,
  505. modTime, creationTime, isReadOnly);
  506. return h;
  507. }
  508. firstResult = String::empty;
  509. return 0;
  510. }
  511. bool juce_findFileNext (void* handle, String& resultFile,
  512. bool* isDir, bool* isHidden, int64* fileSize,
  513. Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  514. {
  515. WIN32_FIND_DATA findData;
  516. if (handle != 0 && FindNextFile ((HANDLE) handle, &findData) != 0)
  517. {
  518. getFindFileInfo (findData, resultFile, isDir, isHidden, fileSize,
  519. modTime, creationTime, isReadOnly);
  520. return true;
  521. }
  522. resultFile = String::empty;
  523. return false;
  524. }
  525. void juce_findFileClose (void* handle) throw()
  526. {
  527. FindClose (handle);
  528. }
  529. //==============================================================================
  530. bool juce_launchFile (const String& fileName,
  531. const String& parameters) throw()
  532. {
  533. HINSTANCE hInstance = 0;
  534. JUCE_TRY
  535. {
  536. hInstance = ShellExecute (0, 0, fileName, parameters, 0, SW_SHOWDEFAULT);
  537. }
  538. JUCE_CATCH_ALL
  539. return hInstance > (HINSTANCE) 32;
  540. }
  541. //==============================================================================
  542. struct NamedPipeInternal
  543. {
  544. HANDLE pipeH;
  545. HANDLE cancelEvent;
  546. bool connected, createdPipe;
  547. NamedPipeInternal()
  548. : pipeH (0),
  549. cancelEvent (0),
  550. connected (false),
  551. createdPipe (false)
  552. {
  553. cancelEvent = CreateEvent (0, FALSE, FALSE, 0);
  554. }
  555. ~NamedPipeInternal()
  556. {
  557. disconnect();
  558. if (pipeH != 0)
  559. CloseHandle (pipeH);
  560. CloseHandle (cancelEvent);
  561. }
  562. bool connect (const int timeOutMs)
  563. {
  564. if (! createdPipe)
  565. return true;
  566. if (! connected)
  567. {
  568. OVERLAPPED over;
  569. zerostruct (over);
  570. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  571. if (ConnectNamedPipe (pipeH, &over))
  572. {
  573. connected = false; // yes, you read that right. In overlapped mode it should always return 0.
  574. }
  575. else
  576. {
  577. const int err = GetLastError();
  578. if (err == ERROR_IO_PENDING || err == ERROR_PIPE_LISTENING)
  579. {
  580. HANDLE handles[] = { over.hEvent, cancelEvent };
  581. if (WaitForMultipleObjects (2, handles, FALSE,
  582. timeOutMs >= 0 ? timeOutMs : INFINITE) == WAIT_OBJECT_0)
  583. connected = true;
  584. }
  585. else if (err == ERROR_PIPE_CONNECTED)
  586. {
  587. connected = true;
  588. }
  589. }
  590. CloseHandle (over.hEvent);
  591. }
  592. return connected;
  593. }
  594. void disconnect()
  595. {
  596. if (connected)
  597. {
  598. DisconnectNamedPipe (pipeH);
  599. connected = false;
  600. }
  601. }
  602. };
  603. void NamedPipe::close()
  604. {
  605. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  606. delete intern;
  607. internal = 0;
  608. }
  609. bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
  610. {
  611. close();
  612. NamedPipeInternal* const intern = new NamedPipeInternal();
  613. String file ("\\\\.\\pipe\\");
  614. file += pipeName;
  615. intern->createdPipe = createPipe;
  616. if (createPipe)
  617. {
  618. intern->pipeH = CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
  619. PIPE_UNLIMITED_INSTANCES,
  620. 4096, 4096, 0, NULL);
  621. }
  622. else
  623. {
  624. intern->pipeH = CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  625. FILE_FLAG_OVERLAPPED, 0);
  626. }
  627. if (intern->pipeH != INVALID_HANDLE_VALUE)
  628. {
  629. internal = intern;
  630. return true;
  631. }
  632. delete intern;
  633. return false;
  634. }
  635. int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
  636. {
  637. int bytesRead = -1;
  638. bool waitAgain = true;
  639. while (waitAgain && internal != 0)
  640. {
  641. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  642. waitAgain = false;
  643. if (! intern->connect (timeOutMilliseconds))
  644. break;
  645. if (maxBytesToRead <= 0)
  646. return 0;
  647. OVERLAPPED over;
  648. zerostruct (over);
  649. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  650. unsigned long numRead;
  651. if (ReadFile (intern->pipeH, destBuffer, maxBytesToRead, &numRead, &over))
  652. {
  653. bytesRead = (int) numRead;
  654. }
  655. else if (GetLastError() == ERROR_IO_PENDING)
  656. {
  657. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  658. DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
  659. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  660. : INFINITE);
  661. if (waitResult != WAIT_OBJECT_0)
  662. {
  663. // if the operation timed out, let's cancel it...
  664. CancelIo (intern->pipeH);
  665. WaitForSingleObject (over.hEvent, INFINITE); // makes sure cancel is complete
  666. }
  667. if (GetOverlappedResult (intern->pipeH, &over, &numRead, FALSE))
  668. {
  669. bytesRead = (int) numRead;
  670. }
  671. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  672. {
  673. intern->disconnect();
  674. waitAgain = true;
  675. }
  676. }
  677. else
  678. {
  679. waitAgain = internal != 0;
  680. Sleep (5);
  681. }
  682. CloseHandle (over.hEvent);
  683. }
  684. return bytesRead;
  685. }
  686. int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
  687. {
  688. int bytesWritten = -1;
  689. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  690. if (intern != 0 && intern->connect (timeOutMilliseconds))
  691. {
  692. if (numBytesToWrite <= 0)
  693. return 0;
  694. OVERLAPPED over;
  695. zerostruct (over);
  696. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  697. unsigned long numWritten;
  698. if (WriteFile (intern->pipeH, sourceBuffer, numBytesToWrite, &numWritten, &over))
  699. {
  700. bytesWritten = (int) numWritten;
  701. }
  702. else if (GetLastError() == ERROR_IO_PENDING)
  703. {
  704. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  705. DWORD waitResult;
  706. waitResult = WaitForMultipleObjects (2, handles, FALSE,
  707. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  708. : INFINITE);
  709. if (waitResult != WAIT_OBJECT_0)
  710. {
  711. CancelIo (intern->pipeH);
  712. WaitForSingleObject (over.hEvent, INFINITE);
  713. }
  714. if (GetOverlappedResult (intern->pipeH, &over, &numWritten, FALSE))
  715. {
  716. bytesWritten = (int) numWritten;
  717. }
  718. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  719. {
  720. intern->disconnect();
  721. }
  722. }
  723. CloseHandle (over.hEvent);
  724. }
  725. return bytesWritten;
  726. }
  727. void NamedPipe::cancelPendingReads()
  728. {
  729. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  730. if (intern != 0)
  731. SetEvent (intern->cancelEvent);
  732. }
  733. #endif