plugin.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "main.h"
  2. #include <vector>
  3. //#include <crtdbg.h>
  4. #include <strsafe.h>
  5. typedef std::vector<PluginUnloadCallback> UnloadCallbackList;
  6. static int Plugin_Init();
  7. static void Plugin_Quit();
  8. static INT_PTR
  9. Plugin_MessageProc(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3);
  10. extern "C" winampMediaLibraryPlugin plugin =
  11. {
  12. MLHDR_VER,
  13. "nullsoft(ml_devices.dll)",
  14. Plugin_Init,
  15. Plugin_Quit,
  16. Plugin_MessageProc,
  17. 0,
  18. 0,
  19. 0,
  20. };
  21. static UnloadCallbackList *unloadCallbacks = NULL;
  22. static DeviceImageCache *imageCache = NULL;
  23. static HWND eventRelayWindow = NULL;
  24. HINSTANCE
  25. Plugin_GetInstance(void)
  26. {
  27. return plugin.hDllInstance;
  28. }
  29. HWND
  30. Plugin_GetWinampWindow(void)
  31. {
  32. return plugin.hwndWinampParent;
  33. }
  34. HWND
  35. Plugin_GetLibraryWindow(void)
  36. {
  37. return plugin.hwndLibraryParent;
  38. }
  39. static void
  40. Plugin_SetDescription()
  41. {
  42. static wchar_t szDescription[256];
  43. StringCchPrintf(szDescription, ARRAYSIZE(szDescription),
  44. WASABI_API_LNGSTRINGW(IDS_PLUGIN_NAME),
  45. PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR);
  46. plugin.description = (char*)szDescription;
  47. }
  48. static int Plugin_Init()
  49. {
  50. unloadCallbacks = NULL;
  51. // _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF |
  52. // _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_CHECK_CRT_DF);
  53. if (FALSE == Wasabi_InitializeFromWinamp(plugin.hDllInstance, plugin.hwndWinampParent))
  54. return ML_INIT_FAILURE;
  55. Wasabi_LoadDefaultServices();
  56. Plugin_SetDescription();
  57. imageCache = DeviceImageCache_Create();
  58. if (NULL == eventRelayWindow)
  59. {
  60. eventRelayWindow = EventRelay_CreateWindow();
  61. if (NULL == eventRelayWindow)
  62. return 2;
  63. }
  64. if (FALSE == Navigation_Initialize())
  65. {
  66. if (NULL != eventRelayWindow)
  67. {
  68. DestroyWindow(eventRelayWindow);
  69. eventRelayWindow = NULL;
  70. }
  71. Wasabi_Release();
  72. return 3;
  73. }
  74. DeviceCommands_Register();
  75. return ML_INIT_SUCCESS;
  76. }
  77. static void Plugin_Quit()
  78. {
  79. if (NULL != unloadCallbacks)
  80. {
  81. size_t index = unloadCallbacks->size();
  82. while(index--)
  83. unloadCallbacks->at(index)();
  84. delete(unloadCallbacks);
  85. }
  86. if (NULL != eventRelayWindow)
  87. {
  88. DestroyWindow(eventRelayWindow);
  89. eventRelayWindow = NULL;
  90. }
  91. Navigation_Uninitialize();
  92. if (NULL != imageCache)
  93. {
  94. DeviceImageCache_Free(imageCache);
  95. imageCache = NULL;
  96. }
  97. Wasabi_Release();
  98. }
  99. static INT_PTR
  100. Plugin_MessageProc(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3)
  101. {
  102. INT_PTR result = 0;
  103. if (FALSE != Navigation_ProcessMessage(msg, param1, param2, param3, &result))
  104. return result;
  105. return FALSE;
  106. }
  107. BOOL
  108. Plugin_RegisterUnloadCallback(PluginUnloadCallback callback)
  109. {
  110. if (NULL == callback)
  111. return FALSE;
  112. if (NULL == unloadCallbacks)
  113. {
  114. unloadCallbacks = new UnloadCallbackList();
  115. if (NULL == unloadCallbacks)
  116. return FALSE;
  117. }
  118. unloadCallbacks->push_back(callback);
  119. return TRUE;
  120. }
  121. DeviceImageCache *
  122. Plugin_GetImageCache()
  123. {
  124. return imageCache;
  125. }
  126. HWND
  127. Plugin_GetEventRelayWindow()
  128. {
  129. return eventRelayWindow;
  130. }
  131. const wchar_t *
  132. Plugin_GetDefaultDeviceImage(unsigned int width, unsigned int height)
  133. {
  134. const ImageInfo *image;
  135. const ImageInfo deviceImages[] =
  136. {
  137. {16, 16, MAKEINTRESOURCE(IDR_GENERIC_DEVICE_16x16_IMAGE)},
  138. {160, 160, MAKEINTRESOURCE(IDR_GENERIC_DEVICE_160x160_IMAGE)},
  139. };
  140. image = Image_GetBestFit(deviceImages, ARRAYSIZE(deviceImages), width, height);
  141. if (NULL == image)
  142. return NULL;
  143. return image->path;
  144. }
  145. HRESULT
  146. Plugin_EnsurePathExist(const wchar_t *path)
  147. {
  148. unsigned long errorCode;
  149. unsigned int errorMode;
  150. errorCode = ERROR_SUCCESS;
  151. errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  152. if (0 == CreateDirectory(path, NULL))
  153. {
  154. errorCode = GetLastError();
  155. if (ERROR_PATH_NOT_FOUND == errorCode)
  156. {
  157. const wchar_t *block, *cursor;
  158. wchar_t buffer[MAX_PATH] = {0};
  159. block = path;
  160. cursor = PathFindNextComponent(block);
  161. errorCode = (cursor == block ||
  162. S_OK != StringCchCopyN(buffer, ARRAYSIZE(buffer), block, (cursor - block))) ?
  163. ERROR_INVALID_NAME : ERROR_SUCCESS;
  164. block = cursor;
  165. while(ERROR_SUCCESS == errorCode &&
  166. NULL != (cursor = PathFindNextComponent(block)))
  167. {
  168. if (cursor == block ||
  169. S_OK != StringCchCatN(buffer, ARRAYSIZE(buffer), block, (cursor - block)))
  170. {
  171. errorCode = ERROR_INVALID_NAME;
  172. }
  173. if (ERROR_SUCCESS == errorCode &&
  174. FALSE == CreateDirectory(buffer, NULL))
  175. {
  176. errorCode = GetLastError();
  177. if (ERROR_ALREADY_EXISTS == errorCode)
  178. errorCode = ERROR_SUCCESS;
  179. }
  180. block = cursor;
  181. }
  182. }
  183. if (ERROR_ALREADY_EXISTS == errorCode)
  184. errorCode = ERROR_SUCCESS;
  185. }
  186. SetErrorMode(errorMode);
  187. SetLastError(errorCode);
  188. return HRESULT_FROM_WIN32(errorCode);
  189. }
  190. BOOL
  191. Plugin_GetResourceString(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax)
  192. {
  193. unsigned long filenameLength;
  194. if (NULL == resourceName)
  195. return FALSE;
  196. if (FAILED(StringCchCopyEx(buffer, bufferMax, L"res://", &buffer, &bufferMax, 0)))
  197. return FALSE;
  198. filenameLength = GetModuleFileName(Plugin_GetInstance(), buffer, (DWORD)bufferMax);
  199. if (0 == filenameLength || bufferMax == filenameLength)
  200. return FALSE;
  201. buffer += filenameLength;
  202. bufferMax -= filenameLength;
  203. if (NULL != resourceType)
  204. {
  205. if (FALSE != IS_INTRESOURCE(resourceType))
  206. {
  207. if (FAILED(StringCchPrintfEx(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceType)))
  208. return FALSE;
  209. }
  210. else
  211. {
  212. if (FAILED(StringCchPrintfEx(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceType)))
  213. return FALSE;
  214. }
  215. }
  216. if (FALSE != IS_INTRESOURCE(resourceName))
  217. {
  218. if (FAILED(StringCchPrintfEx(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceName)))
  219. return FALSE;
  220. }
  221. else
  222. {
  223. if (FAILED(StringCchPrintfEx(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceName)))
  224. return FALSE;
  225. }
  226. return TRUE;
  227. }
  228. HMENU
  229. Plugin_LoadMenu()
  230. {
  231. return WASABI_API_LOADMENUW(IDR_PLUGIN_MENU);
  232. }
  233. BOOL
  234. Plugin_ShowHelp()
  235. {
  236. BOOL result;
  237. wchar_t buffer[8192] = {0};
  238. WASABI_API_LNGSTRINGW_BUF(IDS_PLUGIN_HELP_URL, buffer, ARRAYSIZE(buffer));
  239. if (L'\0' == buffer[0])
  240. {
  241. if (FAILED(StringCchCopy(buffer, ARRAYSIZE(buffer),
  242. L"https://help.winamp.com/hc/articles/8106455294612-Winamp-Portables-Guide")))
  243. {
  244. return FALSE;
  245. }
  246. }
  247. result = MediaLibrary_ShowHelp(plugin.hwndLibraryParent, buffer);
  248. return result;
  249. }
  250. BOOL
  251. Plugin_BeginDiscovery()
  252. {
  253. if (NULL == WASABI_API_DEVICES ||
  254. FAILED(WASABI_API_DEVICES->BeginDiscovery()))
  255. {
  256. return FALSE;
  257. }
  258. return TRUE;
  259. }
  260. BOOL
  261. Plugin_OpenUrl(HWND ownerWindow, const wchar_t *url, BOOL forceExternal)
  262. {
  263. BOOL result;
  264. HCURSOR cursor;
  265. if (NULL == WASABI_API_WINAMP)
  266. return FALSE;
  267. cursor = LoadCursor(NULL, IDC_APPSTARTING);
  268. if (NULL != cursor)
  269. cursor = SetCursor(cursor);
  270. if (FALSE != forceExternal)
  271. {
  272. HINSTANCE instance = ShellExecute(ownerWindow, L"open", url, NULL, NULL, SW_SHOWNORMAL);
  273. result = ((INT_PTR)instance > 32) ? TRUE: FALSE;
  274. }
  275. else
  276. {
  277. HRESULT hr = WASABI_API_WINAMP->OpenUrl(ownerWindow, url);
  278. result = SUCCEEDED(hr);
  279. }
  280. if (NULL != cursor)
  281. SetCursor(cursor);
  282. return result;
  283. }
  284. EXTERN_C __declspec(dllexport) winampMediaLibraryPlugin *
  285. winampGetMediaLibraryPlugin()
  286. {
  287. return &plugin;
  288. }