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.

496 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. #ifndef INTERNET_FLAG_NEED_FILE
  22. #define INTERNET_FLAG_NEED_FILE 0x00000010
  23. #endif
  24. #ifndef INTERNET_OPTION_DISABLE_AUTODIAL
  25. #define INTERNET_OPTION_DISABLE_AUTODIAL 70
  26. #endif
  27. //==============================================================================
  28. struct ConnectionAndRequestStruct
  29. {
  30. HINTERNET connection, request;
  31. };
  32. static HINTERNET sessionHandle = 0;
  33. #ifndef WORKAROUND_TIMEOUT_BUG
  34. //#define WORKAROUND_TIMEOUT_BUG 1
  35. #endif
  36. #if WORKAROUND_TIMEOUT_BUG
  37. // Required because of a Microsoft bug in setting a timeout
  38. class InternetConnectThread : public Thread
  39. {
  40. public:
  41. InternetConnectThread (URL_COMPONENTS& uc_, HINTERNET& connection_, const bool isFtp_)
  42. : Thread ("Internet"), uc (uc_), connection (connection_), isFtp (isFtp_)
  43. {
  44. startThread();
  45. }
  46. ~InternetConnectThread()
  47. {
  48. stopThread (60000);
  49. }
  50. void run()
  51. {
  52. connection = InternetConnect (sessionHandle, uc.lpszHostName,
  53. uc.nPort, _T(""), _T(""),
  54. isFtp ? INTERNET_SERVICE_FTP
  55. : INTERNET_SERVICE_HTTP,
  56. 0, 0);
  57. notify();
  58. }
  59. juce_UseDebuggingNewOperator
  60. private:
  61. URL_COMPONENTS& uc;
  62. HINTERNET& connection;
  63. const bool isFtp;
  64. InternetConnectThread (const InternetConnectThread&);
  65. InternetConnectThread& operator= (const InternetConnectThread&);
  66. };
  67. #endif
  68. void* juce_openInternetFile (const String& url,
  69. const String& headers,
  70. const MemoryBlock& postData,
  71. const bool isPost,
  72. URL::OpenStreamProgressCallback* callback,
  73. void* callbackContext,
  74. int timeOutMs)
  75. {
  76. if (sessionHandle == 0)
  77. sessionHandle = InternetOpen (_T("juce"),
  78. INTERNET_OPEN_TYPE_PRECONFIG,
  79. 0, 0, 0);
  80. if (sessionHandle != 0)
  81. {
  82. // break up the url..
  83. TCHAR file[1024], server[1024];
  84. URL_COMPONENTS uc;
  85. zerostruct (uc);
  86. uc.dwStructSize = sizeof (uc);
  87. uc.dwUrlPathLength = sizeof (file);
  88. uc.dwHostNameLength = sizeof (server);
  89. uc.lpszUrlPath = file;
  90. uc.lpszHostName = server;
  91. if (InternetCrackUrl (url, 0, 0, &uc))
  92. {
  93. int disable = 1;
  94. InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
  95. if (timeOutMs == 0)
  96. timeOutMs = 30000;
  97. else if (timeOutMs < 0)
  98. timeOutMs = -1;
  99. InternetSetOption (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT, &timeOutMs, sizeof (timeOutMs));
  100. const bool isFtp = url.startsWithIgnoreCase ("ftp:");
  101. #if WORKAROUND_TIMEOUT_BUG
  102. HINTERNET connection = 0;
  103. {
  104. InternetConnectThread connectThread (uc, connection, isFtp);
  105. connectThread.wait (timeOutMs);
  106. if (connection == 0)
  107. {
  108. InternetCloseHandle (sessionHandle);
  109. sessionHandle = 0;
  110. }
  111. }
  112. #else
  113. HINTERNET connection = InternetConnect (sessionHandle,
  114. uc.lpszHostName,
  115. uc.nPort,
  116. _T(""), _T(""),
  117. isFtp ? INTERNET_SERVICE_FTP
  118. : INTERNET_SERVICE_HTTP,
  119. 0, 0);
  120. #endif
  121. if (connection != 0)
  122. {
  123. if (isFtp)
  124. {
  125. HINTERNET request = FtpOpenFile (connection,
  126. uc.lpszUrlPath,
  127. GENERIC_READ,
  128. FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE,
  129. 0);
  130. ConnectionAndRequestStruct* const result = new ConnectionAndRequestStruct();
  131. result->connection = connection;
  132. result->request = request;
  133. return result;
  134. }
  135. else
  136. {
  137. const TCHAR* mimeTypes[] = { _T("*/*"), 0 };
  138. DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
  139. if (url.startsWithIgnoreCase ("https:"))
  140. flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
  141. // IE7 seems to automatically work out when it's https)
  142. HINTERNET request = HttpOpenRequest (connection,
  143. isPost ? _T("POST")
  144. : _T("GET"),
  145. uc.lpszUrlPath,
  146. 0, 0, mimeTypes, flags, 0);
  147. if (request != 0)
  148. {
  149. INTERNET_BUFFERS buffers;
  150. zerostruct (buffers);
  151. buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
  152. buffers.lpcszHeader = (LPCTSTR) headers;
  153. buffers.dwHeadersLength = headers.length();
  154. buffers.dwBufferTotal = (DWORD) postData.getSize();
  155. ConnectionAndRequestStruct* result = 0;
  156. if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
  157. {
  158. int bytesSent = 0;
  159. for (;;)
  160. {
  161. const int bytesToDo = jmin (1024, (int) postData.getSize() - bytesSent);
  162. DWORD bytesDone = 0;
  163. if (bytesToDo > 0
  164. && ! InternetWriteFile (request,
  165. static_cast <const char*> (postData.getData()) + bytesSent,
  166. bytesToDo, &bytesDone))
  167. {
  168. break;
  169. }
  170. if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
  171. {
  172. result = new ConnectionAndRequestStruct();
  173. result->connection = connection;
  174. result->request = request;
  175. if (! HttpEndRequest (request, 0, 0, 0))
  176. break;
  177. return result;
  178. }
  179. bytesSent += bytesDone;
  180. if (callback != 0 && ! callback (callbackContext, bytesSent, postData.getSize()))
  181. break;
  182. }
  183. }
  184. InternetCloseHandle (request);
  185. }
  186. InternetCloseHandle (connection);
  187. }
  188. }
  189. }
  190. }
  191. return 0;
  192. }
  193. int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
  194. {
  195. DWORD bytesRead = 0;
  196. const ConnectionAndRequestStruct* const crs = static_cast <ConnectionAndRequestStruct*> (handle);
  197. if (crs != 0)
  198. InternetReadFile (crs->request,
  199. buffer, bytesToRead,
  200. &bytesRead);
  201. return bytesRead;
  202. }
  203. int juce_seekInInternetFile (void* handle, int newPosition)
  204. {
  205. if (handle != 0)
  206. {
  207. const ConnectionAndRequestStruct* const crs = static_cast <ConnectionAndRequestStruct*> (handle);
  208. return InternetSetFilePointer (crs->request, newPosition, 0, FILE_BEGIN, 0);
  209. }
  210. return -1;
  211. }
  212. int64 juce_getInternetFileContentLength (void* handle)
  213. {
  214. const ConnectionAndRequestStruct* const crs = static_cast <ConnectionAndRequestStruct*> (handle);
  215. if (crs != 0)
  216. {
  217. DWORD index = 0, result = 0, size = sizeof (result);
  218. if (HttpQueryInfo (crs->request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
  219. return (int64) result;
  220. }
  221. return -1;
  222. }
  223. void juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
  224. {
  225. const ConnectionAndRequestStruct* const crs = static_cast <ConnectionAndRequestStruct*> (handle);
  226. if (crs != 0)
  227. {
  228. DWORD bufferSizeBytes = 4096;
  229. for (;;)
  230. {
  231. HeapBlock<char> buffer ((size_t) bufferSizeBytes);
  232. if (HttpQueryInfo (crs->request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
  233. {
  234. StringArray headersArray;
  235. headersArray.addLines (reinterpret_cast <const WCHAR*> (buffer.getData()));
  236. for (int i = 0; i < headersArray.size(); ++i)
  237. {
  238. const String& header = headersArray[i];
  239. const String key (header.upToFirstOccurrenceOf ("; ", false, false));
  240. const String value (header.fromFirstOccurrenceOf ("; ", false, false));
  241. const String previousValue (headers [key]);
  242. headers.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
  243. }
  244. break;
  245. }
  246. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  247. break;
  248. }
  249. }
  250. }
  251. void juce_closeInternetFile (void* handle)
  252. {
  253. if (handle != 0)
  254. {
  255. ScopedPointer <ConnectionAndRequestStruct> crs (static_cast <ConnectionAndRequestStruct*> (handle));
  256. InternetCloseHandle (crs->request);
  257. InternetCloseHandle (crs->connection);
  258. }
  259. }
  260. //==============================================================================
  261. static int getMACAddressViaGetAdaptersInfo (int64* addresses, int maxNum, const bool littleEndian) throw()
  262. {
  263. int numFound = 0;
  264. DynamicLibraryLoader dll ("iphlpapi.dll");
  265. DynamicLibraryImport (GetAdaptersInfo, getAdaptersInfo, DWORD, dll, (PIP_ADAPTER_INFO, PULONG))
  266. if (getAdaptersInfo != 0)
  267. {
  268. ULONG len = sizeof (IP_ADAPTER_INFO);
  269. MemoryBlock mb;
  270. PIP_ADAPTER_INFO adapterInfo = (PIP_ADAPTER_INFO) mb.getData();
  271. if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
  272. {
  273. mb.setSize (len);
  274. adapterInfo = (PIP_ADAPTER_INFO) mb.getData();
  275. }
  276. if (getAdaptersInfo (adapterInfo, &len) == NO_ERROR)
  277. {
  278. PIP_ADAPTER_INFO adapter = adapterInfo;
  279. while (adapter != 0)
  280. {
  281. int64 mac = 0;
  282. for (unsigned int i = 0; i < adapter->AddressLength; ++i)
  283. mac = (mac << 8) | adapter->Address[i];
  284. if (littleEndian)
  285. mac = (int64) ByteOrder::swap ((uint64) mac);
  286. if (numFound < maxNum && mac != 0)
  287. addresses [numFound++] = mac;
  288. adapter = adapter->Next;
  289. }
  290. }
  291. }
  292. return numFound;
  293. }
  294. static int getMACAddressesViaNetBios (int64* addresses, int maxNum, const bool littleEndian) throw()
  295. {
  296. int numFound = 0;
  297. DynamicLibraryLoader dll ("netapi32.dll");
  298. DynamicLibraryImport (Netbios, NetbiosCall, UCHAR, dll, (PNCB))
  299. if (NetbiosCall != 0)
  300. {
  301. NCB ncb;
  302. zerostruct (ncb);
  303. struct ASTAT
  304. {
  305. ADAPTER_STATUS adapt;
  306. NAME_BUFFER NameBuff [30];
  307. };
  308. ASTAT astat;
  309. zeromem (&astat, sizeof (astat)); // (can't use zerostruct here in VC6)
  310. LANA_ENUM enums;
  311. zerostruct (enums);
  312. ncb.ncb_command = NCBENUM;
  313. ncb.ncb_buffer = (unsigned char*) &enums;
  314. ncb.ncb_length = sizeof (LANA_ENUM);
  315. NetbiosCall (&ncb);
  316. for (int i = 0; i < enums.length; ++i)
  317. {
  318. zerostruct (ncb);
  319. ncb.ncb_command = NCBRESET;
  320. ncb.ncb_lana_num = enums.lana[i];
  321. if (NetbiosCall (&ncb) == 0)
  322. {
  323. zerostruct (ncb);
  324. memcpy (ncb.ncb_callname, "* ", NCBNAMSZ);
  325. ncb.ncb_command = NCBASTAT;
  326. ncb.ncb_lana_num = enums.lana[i];
  327. ncb.ncb_buffer = (unsigned char*) &astat;
  328. ncb.ncb_length = sizeof (ASTAT);
  329. if (NetbiosCall (&ncb) == 0)
  330. {
  331. if (astat.adapt.adapter_type == 0xfe)
  332. {
  333. uint64 mac = 0;
  334. for (int i = 6; --i >= 0;)
  335. mac = (mac << 8) | astat.adapt.adapter_address [littleEndian ? i : (5 - i)];
  336. if (numFound < maxNum && mac != 0)
  337. addresses [numFound++] = mac;
  338. }
  339. }
  340. }
  341. }
  342. }
  343. return numFound;
  344. }
  345. int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
  346. {
  347. int numFound = getMACAddressViaGetAdaptersInfo (addresses, maxNum, littleEndian);
  348. if (numFound == 0)
  349. numFound = getMACAddressesViaNetBios (addresses, maxNum, littleEndian);
  350. return numFound;
  351. }
  352. //==============================================================================
  353. bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
  354. const String& emailSubject,
  355. const String& bodyText,
  356. const StringArray& filesToAttach)
  357. {
  358. HMODULE h = LoadLibraryA ("MAPI32.dll");
  359. typedef ULONG (WINAPI *MAPISendMailType) (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG);
  360. MAPISendMailType mapiSendMail = (MAPISendMailType) GetProcAddress (h, "MAPISendMail");
  361. bool ok = false;
  362. if (mapiSendMail != 0)
  363. {
  364. MapiMessage message;
  365. zerostruct (message);
  366. message.lpszSubject = (LPSTR) emailSubject.toCString();
  367. message.lpszNoteText = (LPSTR) bodyText.toCString();
  368. MapiRecipDesc recip;
  369. zerostruct (recip);
  370. recip.ulRecipClass = MAPI_TO;
  371. String targetEmailAddress_ (targetEmailAddress);
  372. if (targetEmailAddress_.isEmpty())
  373. targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
  374. recip.lpszName = (LPSTR) targetEmailAddress_.toCString();
  375. message.nRecipCount = 1;
  376. message.lpRecips = &recip;
  377. HeapBlock <MapiFileDesc> files;
  378. files.calloc (filesToAttach.size());
  379. message.nFileCount = filesToAttach.size();
  380. message.lpFiles = files;
  381. for (int i = 0; i < filesToAttach.size(); ++i)
  382. {
  383. files[i].nPosition = (ULONG) -1;
  384. files[i].lpszPathName = (LPSTR) filesToAttach[i].toCString();
  385. }
  386. ok = (mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS);
  387. }
  388. FreeLibrary (h);
  389. return ok;
  390. }
  391. #endif