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.

961 lines
28KB

  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. #ifdef _MSC_VER
  24. #pragma warning (disable: 4514)
  25. #pragma warning (push)
  26. #endif
  27. #include "win32_headers.h"
  28. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  29. #include <ctime>
  30. #ifndef _WIN32_IE
  31. #define _WIN32_IE 0x0400
  32. #endif
  33. #include <shlobj.h>
  34. BEGIN_JUCE_NAMESPACE
  35. #include "../../../src/juce_core/io/files/juce_File.h"
  36. #include "../../../src/juce_core/io/network/juce_URL.h"
  37. #include "../../../src/juce_core/basics/juce_SystemStats.h"
  38. #include "../../../src/juce_core/io/files/juce_NamedPipe.h"
  39. #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
  40. #ifdef _MSC_VER
  41. #pragma warning (pop)
  42. #endif
  43. //==============================================================================
  44. const tchar File::separator = T('\\');
  45. const tchar* File::separatorString = T("\\");
  46. //==============================================================================
  47. UNICODE_FUNCTION (GetFileAttributesW, DWORD, (LPCWSTR))
  48. UNICODE_FUNCTION (SetFileAttributesW, BOOL, (LPCWSTR, DWORD))
  49. UNICODE_FUNCTION (RemoveDirectoryW, BOOL, (LPCWSTR))
  50. UNICODE_FUNCTION (DeleteFileW, BOOL, (LPCWSTR))
  51. UNICODE_FUNCTION (MoveFileW, BOOL, (LPCWSTR, LPCWSTR))
  52. UNICODE_FUNCTION (CopyFileW, BOOL, (LPCWSTR, LPCWSTR, BOOL))
  53. UNICODE_FUNCTION (CreateDirectoryW, BOOL, (LPCWSTR, LPSECURITY_ATTRIBUTES))
  54. UNICODE_FUNCTION (CreateFileW, HANDLE, (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE))
  55. UNICODE_FUNCTION (CreateNamedPipeW, HANDLE, (LPCWSTR, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPSECURITY_ATTRIBUTES))
  56. UNICODE_FUNCTION (GetTempPathW, DWORD, (DWORD, LPCWSTR))
  57. UNICODE_FUNCTION (SHGetSpecialFolderPathW, BOOL, (HWND, LPCWSTR, int, BOOL))
  58. UNICODE_FUNCTION (GetModuleFileNameW, DWORD, (HMODULE, LPCWSTR, DWORD))
  59. UNICODE_FUNCTION (GetCurrentDirectoryW, DWORD, (DWORD, LPCWSTR))
  60. UNICODE_FUNCTION (SetCurrentDirectoryW, BOOL, (LPCWSTR))
  61. UNICODE_FUNCTION (FindFirstFileW, HANDLE, (LPCWSTR, LPWIN32_FIND_DATAW))
  62. UNICODE_FUNCTION (FindNextFileW, BOOL, (HANDLE, LPWIN32_FIND_DATAW))
  63. void juce_initialiseUnicodeFileFunctions()
  64. {
  65. if ((SystemStats::getOperatingSystemType() & SystemStats::WindowsNT) != 0)
  66. {
  67. HMODULE h = GetModuleHandleA ("kernel32.dll");
  68. UNICODE_FUNCTION_LOAD (GetFileAttributesW)
  69. UNICODE_FUNCTION_LOAD (SetFileAttributesW)
  70. UNICODE_FUNCTION_LOAD (RemoveDirectoryW)
  71. UNICODE_FUNCTION_LOAD (DeleteFileW)
  72. UNICODE_FUNCTION_LOAD (MoveFileW)
  73. UNICODE_FUNCTION_LOAD (CopyFileW)
  74. UNICODE_FUNCTION_LOAD (CreateDirectoryW)
  75. UNICODE_FUNCTION_LOAD (CreateFileW)
  76. UNICODE_FUNCTION_LOAD (CreateNamedPipeW)
  77. UNICODE_FUNCTION_LOAD (GetTempPathW)
  78. UNICODE_FUNCTION_LOAD (GetModuleFileNameW)
  79. UNICODE_FUNCTION_LOAD (GetCurrentDirectoryW)
  80. UNICODE_FUNCTION_LOAD (SetCurrentDirectoryW)
  81. UNICODE_FUNCTION_LOAD (FindFirstFileW)
  82. UNICODE_FUNCTION_LOAD (FindNextFileW)
  83. h = LoadLibraryA ("shell32.dll");
  84. UNICODE_FUNCTION_LOAD (SHGetSpecialFolderPathW)
  85. }
  86. }
  87. //==============================================================================
  88. bool juce_fileExists (const String& fileName,
  89. const bool dontCountDirectories)
  90. {
  91. if (fileName.isEmpty())
  92. return false;
  93. const DWORD attr = (wGetFileAttributesW != 0) ? wGetFileAttributesW (fileName)
  94. : GetFileAttributes (fileName);
  95. return (dontCountDirectories) ? ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
  96. : (attr != 0xffffffff);
  97. }
  98. bool juce_isDirectory (const String& fileName)
  99. {
  100. const DWORD attr = (wGetFileAttributesW != 0) ? wGetFileAttributesW (fileName)
  101. : GetFileAttributes (fileName);
  102. return (attr != 0xffffffff)
  103. && ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0);
  104. }
  105. bool juce_canWriteToFile (const String& fileName)
  106. {
  107. const DWORD attr = (wGetFileAttributesW != 0) ? wGetFileAttributesW (fileName)
  108. : GetFileAttributes (fileName);
  109. return ((attr & FILE_ATTRIBUTE_READONLY) == 0);
  110. }
  111. bool juce_setFileReadOnly (const String& fileName,
  112. bool isReadOnly)
  113. {
  114. DWORD attr = (wGetFileAttributesW != 0) ? wGetFileAttributesW (fileName)
  115. : GetFileAttributes (fileName);
  116. if (attr == 0xffffffff)
  117. return false;
  118. if (isReadOnly != juce_canWriteToFile (fileName))
  119. return true;
  120. if (isReadOnly)
  121. attr |= FILE_ATTRIBUTE_READONLY;
  122. else
  123. attr &= ~FILE_ATTRIBUTE_READONLY;
  124. if (wSetFileAttributesW != 0)
  125. return wSetFileAttributesW (fileName, attr) != FALSE;
  126. return SetFileAttributes (fileName, attr) != FALSE;
  127. }
  128. //==============================================================================
  129. bool juce_deleteFile (const String& fileName)
  130. {
  131. if (juce_isDirectory (fileName))
  132. return (wRemoveDirectoryW != 0) ? wRemoveDirectoryW (fileName) != 0
  133. : RemoveDirectory (fileName) != 0;
  134. else
  135. return (wDeleteFileW != 0) ? wDeleteFileW (fileName) != 0
  136. : DeleteFile (fileName) != 0;
  137. }
  138. bool juce_moveFile (const String& source, const String& dest)
  139. {
  140. return (wMoveFileW != 0) ? wMoveFileW (source, dest) != 0
  141. : MoveFile (source, dest) != 0;
  142. }
  143. bool juce_copyFile (const String& source, const String& dest)
  144. {
  145. return (wCopyFileW != 0) ? wCopyFileW (source, dest, false) != 0
  146. : CopyFile (source, dest, false) != 0;
  147. }
  148. void juce_createDirectory (const String& fileName)
  149. {
  150. if (! juce_fileExists (fileName, true))
  151. {
  152. if (wCreateDirectoryW != 0)
  153. wCreateDirectoryW (fileName, 0);
  154. else
  155. CreateDirectory (fileName, 0);
  156. }
  157. }
  158. //==============================================================================
  159. // return 0 if not possible
  160. void* juce_fileOpen (const String& fileName, bool forWriting)
  161. {
  162. HANDLE h;
  163. if (forWriting)
  164. {
  165. if (wCreateFileW != 0)
  166. h = wCreateFileW (fileName, GENERIC_WRITE, FILE_SHARE_READ, 0,
  167. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  168. else
  169. h = CreateFile (fileName, GENERIC_WRITE, FILE_SHARE_READ, 0,
  170. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  171. if (h != INVALID_HANDLE_VALUE)
  172. SetFilePointer (h, 0, 0, FILE_END);
  173. else
  174. h = 0;
  175. }
  176. else
  177. {
  178. if (wCreateFileW != 0)
  179. h = wCreateFileW (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  180. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
  181. else
  182. h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  183. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
  184. if (h == INVALID_HANDLE_VALUE)
  185. h = 0;
  186. }
  187. return (void*) h;
  188. }
  189. void juce_fileClose (void* handle)
  190. {
  191. CloseHandle (handle);
  192. }
  193. //==============================================================================
  194. int juce_fileRead (void* handle, void* buffer, int size)
  195. {
  196. DWORD num = 0;
  197. ReadFile ((HANDLE) handle, buffer, size, &num, 0);
  198. return num;
  199. }
  200. int juce_fileWrite (void* handle, const void* buffer, int size)
  201. {
  202. DWORD num;
  203. WriteFile ((HANDLE) handle,
  204. buffer, size,
  205. &num, 0);
  206. return num;
  207. }
  208. int64 juce_fileSetPosition (void* handle, int64 pos)
  209. {
  210. LARGE_INTEGER li;
  211. li.QuadPart = pos;
  212. li.LowPart = SetFilePointer ((HANDLE) handle,
  213. li.LowPart,
  214. &li.HighPart,
  215. FILE_BEGIN); // (returns -1 if it fails)
  216. return li.QuadPart;
  217. }
  218. int64 juce_fileGetPosition (void* handle)
  219. {
  220. LARGE_INTEGER li;
  221. li.QuadPart = 0;
  222. li.LowPart = SetFilePointer ((HANDLE) handle,
  223. 0, &li.HighPart,
  224. FILE_CURRENT); // (returns -1 if it fails)
  225. return jmax ((int64) 0, li.QuadPart);
  226. }
  227. void juce_fileFlush (void* handle)
  228. {
  229. FlushFileBuffers ((HANDLE) handle);
  230. }
  231. int64 juce_getFileSize (const String& fileName)
  232. {
  233. void* const handle = juce_fileOpen (fileName, false);
  234. if (handle != 0)
  235. {
  236. LARGE_INTEGER li;
  237. li.LowPart = GetFileSize (handle, (LPDWORD) &li.HighPart);
  238. juce_fileClose (handle);
  239. if (li.LowPart != INVALID_FILE_SIZE || GetLastError() != NO_ERROR)
  240. return li.QuadPart;
  241. }
  242. return 0;
  243. }
  244. //==============================================================================
  245. static int64 fileTimeToTime (const FILETIME* const ft) throw()
  246. {
  247. // tell me if this fails!
  248. static_jassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME));
  249. #ifdef JUCE_GCC
  250. return (((const ULARGE_INTEGER*) ft)->QuadPart - 116444736000000000LL) / 10000;
  251. #else
  252. return (((const ULARGE_INTEGER*) ft)->QuadPart - 116444736000000000) / 10000;
  253. #endif
  254. }
  255. static void timeToFileTime (const int64 time, FILETIME* const ft) throw()
  256. {
  257. #ifdef JUCE_GCC
  258. ((ULARGE_INTEGER*) ft)->QuadPart = time * 10000 + 116444736000000000LL;
  259. #else
  260. ((ULARGE_INTEGER*) ft)->QuadPart = time * 10000 + 116444736000000000;
  261. #endif
  262. }
  263. void juce_getFileTimes (const String& fileName,
  264. int64& modificationTime,
  265. int64& accessTime,
  266. int64& creationTime)
  267. {
  268. creationTime = accessTime = modificationTime = 0;
  269. void* const h = juce_fileOpen (fileName, false);
  270. if (h != 0)
  271. {
  272. FILETIME m, a, c;
  273. if (GetFileTime ((HANDLE) h, &c, &a, &m))
  274. {
  275. creationTime = fileTimeToTime (&c);
  276. accessTime = fileTimeToTime (&a);
  277. modificationTime = fileTimeToTime (&m);
  278. }
  279. juce_fileClose (h);
  280. }
  281. }
  282. bool juce_setFileTimes (const String& fileName,
  283. int64 modificationTime,
  284. int64 accessTime,
  285. int64 creationTime)
  286. {
  287. FILETIME m, a, c;
  288. if (modificationTime > 0)
  289. timeToFileTime (modificationTime, &m);
  290. if (accessTime > 0)
  291. timeToFileTime (accessTime, &a);
  292. if (creationTime > 0)
  293. timeToFileTime (creationTime, &c);
  294. void* const h = juce_fileOpen (fileName, true);
  295. bool ok = false;
  296. if (h != 0)
  297. {
  298. ok = SetFileTime ((HANDLE) h,
  299. (creationTime > 0) ? &c : 0,
  300. (accessTime > 0) ? &a : 0,
  301. (modificationTime > 0) ? &m : 0) != 0;
  302. juce_fileClose (h);
  303. }
  304. return ok;
  305. }
  306. //==============================================================================
  307. // return '\0' separated list of strings
  308. const StringArray juce_getFileSystemRoots()
  309. {
  310. TCHAR buffer [2048];
  311. buffer[0] = 0;
  312. buffer[1] = 0;
  313. GetLogicalDriveStrings (2048, buffer);
  314. TCHAR* n = buffer;
  315. StringArray roots;
  316. while (*n != 0)
  317. {
  318. roots.add (String (n));
  319. while (*n++ != 0)
  320. {
  321. }
  322. }
  323. roots.sort (true);
  324. return roots;
  325. }
  326. //==============================================================================
  327. const String juce_getVolumeLabel (const String& filenameOnVolume,
  328. int& volumeSerialNumber)
  329. {
  330. TCHAR n [4];
  331. n[0] = *(const TCHAR*) filenameOnVolume;
  332. n[1] = L':';
  333. n[2] = L'\\';
  334. n[3] = 0;
  335. TCHAR dest [64];
  336. DWORD serialNum;
  337. if (! GetVolumeInformation (n, dest, 64, (DWORD*) &serialNum, 0, 0, 0, 0))
  338. {
  339. dest[0] = 0;
  340. serialNum = 0;
  341. }
  342. volumeSerialNumber = serialNum;
  343. return String (dest);
  344. }
  345. int64 File::getBytesFreeOnVolume() const throw()
  346. {
  347. String fn (getFullPathName());
  348. if (fn[1] == T(':'))
  349. fn = fn.substring (0, 2) + T("\\");
  350. ULARGE_INTEGER spc;
  351. ULARGE_INTEGER tot;
  352. ULARGE_INTEGER totFree;
  353. if (GetDiskFreeSpaceEx (fn, &spc, &tot, &totFree))
  354. return (int64)(spc.QuadPart);
  355. return 0;
  356. }
  357. //==============================================================================
  358. static unsigned int getWindowsDriveType (const String& fileName)
  359. {
  360. TCHAR n[4];
  361. n[0] = *(const TCHAR*) fileName;
  362. n[1] = L':';
  363. n[2] = L'\\';
  364. n[3] = 0;
  365. return GetDriveType (n);
  366. }
  367. bool File::isOnCDRomDrive() const throw()
  368. {
  369. return getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
  370. }
  371. bool File::isOnHardDisk() const throw()
  372. {
  373. if (fullPath.isEmpty())
  374. return false;
  375. const unsigned int n = getWindowsDriveType (getFullPathName());
  376. if (fullPath.toLowerCase()[0] <= 'b'
  377. && fullPath[1] == T(':'))
  378. {
  379. return n != DRIVE_REMOVABLE;
  380. }
  381. else
  382. {
  383. return n != DRIVE_CDROM && n != DRIVE_REMOTE;
  384. }
  385. }
  386. bool File::isOnRemovableDrive() const throw()
  387. {
  388. if (fullPath.isEmpty())
  389. return false;
  390. const unsigned int n = getWindowsDriveType (getFullPathName());
  391. return n == DRIVE_CDROM
  392. || n == DRIVE_REMOTE
  393. || n == DRIVE_REMOVABLE
  394. || n == DRIVE_RAMDISK;
  395. }
  396. //==============================================================================
  397. #define MAX_PATH_CHARS (MAX_PATH + 256)
  398. static const File juce_getSpecialFolderPath (int type)
  399. {
  400. if (wSHGetSpecialFolderPathW != 0)
  401. {
  402. WCHAR path [MAX_PATH_CHARS];
  403. if (wSHGetSpecialFolderPathW (0, path, type, 0))
  404. return File (String (path));
  405. }
  406. else
  407. {
  408. TCHAR path [MAX_PATH_CHARS];
  409. if (SHGetSpecialFolderPath (0, path, type, 0))
  410. return File (String (path));
  411. }
  412. return File::nonexistent;
  413. }
  414. const File File::getSpecialLocation (const SpecialLocationType type)
  415. {
  416. switch (type)
  417. {
  418. case userHomeDirectory:
  419. case userDocumentsDirectory:
  420. return juce_getSpecialFolderPath (CSIDL_PERSONAL);
  421. case userDesktopDirectory:
  422. return juce_getSpecialFolderPath (CSIDL_DESKTOP);
  423. case userApplicationDataDirectory:
  424. return juce_getSpecialFolderPath (CSIDL_APPDATA);
  425. case commonApplicationDataDirectory:
  426. return juce_getSpecialFolderPath (CSIDL_COMMON_APPDATA);
  427. case globalApplicationsDirectory:
  428. return juce_getSpecialFolderPath (CSIDL_PROGRAM_FILES);
  429. case tempDirectory:
  430. if (wGetTempPathW != 0)
  431. {
  432. WCHAR dest [2048];
  433. dest[0] = 0;
  434. wGetTempPathW (2048, dest);
  435. return File (String (dest));
  436. }
  437. else
  438. {
  439. TCHAR dest [2048];
  440. dest[0] = 0;
  441. GetTempPath (2048, dest);
  442. return File (String (dest));
  443. }
  444. case currentExecutableFile:
  445. case currentApplicationFile:
  446. {
  447. HINSTANCE moduleHandle = (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle();
  448. if (wGetModuleFileNameW != 0)
  449. {
  450. WCHAR dest [MAX_PATH_CHARS];
  451. dest[0] = 0;
  452. wGetModuleFileNameW (moduleHandle, dest, MAX_PATH_CHARS);
  453. return File (String (dest));
  454. }
  455. else
  456. {
  457. TCHAR dest [MAX_PATH_CHARS];
  458. dest[0] = 0;
  459. GetModuleFileName (moduleHandle, dest, MAX_PATH_CHARS);
  460. return File (String (dest));
  461. }
  462. }
  463. break;
  464. default:
  465. jassertfalse // unknown type?
  466. break;
  467. }
  468. return File::nonexistent;
  469. }
  470. void juce_setCurrentExecutableFileName (const String&)
  471. {
  472. // n/a on windows
  473. }
  474. //==============================================================================
  475. const File File::getCurrentWorkingDirectory() throw()
  476. {
  477. if (wGetCurrentDirectoryW != 0)
  478. {
  479. WCHAR dest [MAX_PATH_CHARS];
  480. dest[0] = 0;
  481. wGetCurrentDirectoryW (MAX_PATH_CHARS, dest);
  482. return File (String (dest));
  483. }
  484. else
  485. {
  486. TCHAR dest [MAX_PATH_CHARS];
  487. dest[0] = 0;
  488. GetCurrentDirectory (MAX_PATH_CHARS, dest);
  489. return File (String (dest));
  490. }
  491. }
  492. bool File::setAsCurrentWorkingDirectory() const throw()
  493. {
  494. return (wSetCurrentDirectoryW != 0) ? wSetCurrentDirectoryW (getFullPathName()) != FALSE
  495. : SetCurrentDirectory (getFullPathName()) != FALSE;
  496. }
  497. //==============================================================================
  498. template <class FindDataType>
  499. static void getFindFileInfo (FindDataType& findData,
  500. String& filename, bool* const isDir, bool* const isHidden,
  501. int64* const fileSize, Time* const modTime, Time* const creationTime,
  502. bool* const isReadOnly)
  503. {
  504. filename = findData.cFileName;
  505. if (isDir != 0)
  506. *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  507. if (isHidden != 0)
  508. *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
  509. if (fileSize != 0)
  510. *fileSize = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
  511. if (modTime != 0)
  512. *modTime = fileTimeToTime (&findData.ftLastWriteTime);
  513. if (creationTime != 0)
  514. *creationTime = fileTimeToTime (&findData.ftCreationTime);
  515. if (isReadOnly != 0)
  516. *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
  517. }
  518. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResult,
  519. bool* isDir, bool* isHidden, int64* fileSize,
  520. Time* modTime, Time* creationTime, bool* isReadOnly)
  521. {
  522. String wc (directory);
  523. if (! wc.endsWithChar (File::separator))
  524. wc += File::separator;
  525. wc += wildCard;
  526. if (wFindFirstFileW != 0)
  527. {
  528. WIN32_FIND_DATAW findData;
  529. HANDLE h = wFindFirstFileW (wc, &findData);
  530. if (h != INVALID_HANDLE_VALUE)
  531. {
  532. getFindFileInfo (findData, firstResult, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  533. return h;
  534. }
  535. }
  536. else
  537. {
  538. WIN32_FIND_DATA findData;
  539. HANDLE h = FindFirstFile (wc, &findData);
  540. if (h != INVALID_HANDLE_VALUE)
  541. {
  542. getFindFileInfo (findData, firstResult, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  543. return h;
  544. }
  545. }
  546. firstResult = String::empty;
  547. return 0;
  548. }
  549. bool juce_findFileNext (void* handle, String& resultFile,
  550. bool* isDir, bool* isHidden, int64* fileSize,
  551. Time* modTime, Time* creationTime, bool* isReadOnly)
  552. {
  553. if (wFindNextFileW != 0)
  554. {
  555. WIN32_FIND_DATAW findData;
  556. if (handle != 0 && wFindNextFileW ((HANDLE) handle, &findData) != 0)
  557. {
  558. getFindFileInfo (findData, resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  559. return true;
  560. }
  561. }
  562. else
  563. {
  564. WIN32_FIND_DATA findData;
  565. if (handle != 0 && FindNextFile ((HANDLE) handle, &findData) != 0)
  566. {
  567. getFindFileInfo (findData, resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  568. return true;
  569. }
  570. }
  571. resultFile = String::empty;
  572. return false;
  573. }
  574. void juce_findFileClose (void* handle)
  575. {
  576. FindClose (handle);
  577. }
  578. //==============================================================================
  579. bool juce_launchFile (const String& fileName,
  580. const String& parameters)
  581. {
  582. HINSTANCE hInstance = 0;
  583. JUCE_TRY
  584. {
  585. hInstance = ShellExecute (0, 0, fileName, parameters, 0, SW_SHOWDEFAULT);
  586. }
  587. JUCE_CATCH_ALL
  588. return hInstance > (HINSTANCE) 32;
  589. }
  590. //==============================================================================
  591. struct NamedPipeInternal
  592. {
  593. HANDLE pipeH;
  594. HANDLE cancelEvent;
  595. bool connected, createdPipe;
  596. NamedPipeInternal()
  597. : pipeH (0),
  598. cancelEvent (0),
  599. connected (false),
  600. createdPipe (false)
  601. {
  602. cancelEvent = CreateEvent (0, FALSE, FALSE, 0);
  603. }
  604. ~NamedPipeInternal()
  605. {
  606. disconnect();
  607. if (pipeH != 0)
  608. CloseHandle (pipeH);
  609. CloseHandle (cancelEvent);
  610. }
  611. bool connect (const int timeOutMs)
  612. {
  613. if (! createdPipe)
  614. return true;
  615. if (! connected)
  616. {
  617. OVERLAPPED over;
  618. zerostruct (over);
  619. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  620. if (ConnectNamedPipe (pipeH, &over))
  621. {
  622. connected = false; // yes, you read that right. In overlapped mode it should always return 0.
  623. }
  624. else
  625. {
  626. const int err = GetLastError();
  627. if (err == ERROR_IO_PENDING || err == ERROR_PIPE_LISTENING)
  628. {
  629. HANDLE handles[] = { over.hEvent, cancelEvent };
  630. if (WaitForMultipleObjects (2, handles, FALSE,
  631. timeOutMs >= 0 ? timeOutMs : INFINITE) == WAIT_OBJECT_0)
  632. connected = true;
  633. }
  634. else if (err == ERROR_PIPE_CONNECTED)
  635. {
  636. connected = true;
  637. }
  638. }
  639. CloseHandle (over.hEvent);
  640. }
  641. return connected;
  642. }
  643. void disconnect()
  644. {
  645. if (connected)
  646. {
  647. DisconnectNamedPipe (pipeH);
  648. connected = false;
  649. }
  650. }
  651. };
  652. void NamedPipe::close()
  653. {
  654. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  655. delete intern;
  656. internal = 0;
  657. }
  658. bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
  659. {
  660. close();
  661. NamedPipeInternal* const intern = new NamedPipeInternal();
  662. String file (T("\\\\.\\pipe\\"));
  663. file += pipeName;
  664. intern->createdPipe = createPipe;
  665. if (createPipe)
  666. {
  667. if (wCreateNamedPipeW != 0)
  668. intern->pipeH = wCreateNamedPipeW (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
  669. 1, 64, 64, 0, NULL);
  670. else
  671. intern->pipeH = CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
  672. 1, 64, 64, 0, NULL);
  673. }
  674. else
  675. {
  676. if (wCreateFileW != 0)
  677. intern->pipeH = wCreateFileW (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  678. FILE_FLAG_OVERLAPPED, 0);
  679. else
  680. intern->pipeH = CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  681. FILE_FLAG_OVERLAPPED, 0);
  682. }
  683. if (intern->pipeH != INVALID_HANDLE_VALUE)
  684. {
  685. internal = intern;
  686. return true;
  687. }
  688. delete intern;
  689. return false;
  690. }
  691. int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
  692. {
  693. int bytesRead = -1;
  694. bool waitAgain = true;
  695. while (waitAgain && internal != 0)
  696. {
  697. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  698. waitAgain = false;
  699. if (! intern->connect (timeOutMilliseconds))
  700. break;
  701. if (maxBytesToRead <= 0)
  702. return 0;
  703. OVERLAPPED over;
  704. zerostruct (over);
  705. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  706. unsigned long numRead;
  707. if (ReadFile (intern->pipeH, destBuffer, maxBytesToRead, &numRead, &over))
  708. {
  709. bytesRead = (int) numRead;
  710. }
  711. else if (GetLastError() == ERROR_IO_PENDING)
  712. {
  713. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  714. if (WaitForMultipleObjects (2, handles, FALSE,
  715. timeOutMilliseconds >= 0 ? timeOutMilliseconds
  716. : INFINITE) == WAIT_OBJECT_0)
  717. {
  718. if (GetOverlappedResult (intern->pipeH, &over, &numRead, FALSE))
  719. {
  720. bytesRead = (int) numRead;
  721. }
  722. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  723. {
  724. intern->disconnect();
  725. waitAgain = true;
  726. }
  727. }
  728. }
  729. else
  730. {
  731. waitAgain = internal != 0;
  732. Sleep (5);
  733. }
  734. CloseHandle (over.hEvent);
  735. }
  736. return bytesRead;
  737. }
  738. int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
  739. {
  740. int bytesWritten = -1;
  741. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  742. if (intern != 0 && intern->connect (timeOutMilliseconds))
  743. {
  744. if (numBytesToWrite <= 0)
  745. return 0;
  746. OVERLAPPED over;
  747. zerostruct (over);
  748. over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
  749. unsigned long numWritten;
  750. if (WriteFile (intern->pipeH, sourceBuffer, numBytesToWrite, &numWritten, &over))
  751. {
  752. bytesWritten = (int) numWritten;
  753. }
  754. else if (GetLastError() == ERROR_IO_PENDING)
  755. {
  756. HANDLE handles[] = { over.hEvent, intern->cancelEvent };
  757. if (WaitForMultipleObjects (2, handles, FALSE, timeOutMilliseconds >= 0 ? timeOutMilliseconds
  758. : INFINITE) == WAIT_OBJECT_0)
  759. {
  760. if (GetOverlappedResult (intern->pipeH, &over, &numWritten, FALSE))
  761. {
  762. bytesWritten = (int) numWritten;
  763. }
  764. else if (GetLastError() == ERROR_BROKEN_PIPE && intern->createdPipe)
  765. {
  766. intern->disconnect();
  767. }
  768. }
  769. }
  770. CloseHandle (over.hEvent);
  771. }
  772. return bytesWritten;
  773. }
  774. void NamedPipe::cancelPendingReads()
  775. {
  776. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  777. if (intern != 0)
  778. SetEvent (intern->cancelEvent);
  779. }
  780. END_JUCE_NAMESPACE