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.

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