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.

1091 lines
32KB

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