ole.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /** (c) Nullsoft, Inc. C O N F I D E N T I A L
  2. ** Filename:
  3. ** Project:
  4. ** Description:
  5. ** Author:
  6. ** Created:
  7. **/
  8. #include "main.h"
  9. #include "../nu/AutoWide.h"
  10. #include "../nu/AutoWideFn.h"
  11. extern "C"
  12. {
  13. extern int g_has_deleted_current;
  14. };
  15. #include "shlobj.h"
  16. #include "../Plugins/General/gen_ff/ff_ipc.h"
  17. bool refuseDrops = false;
  18. class DropTarget: public IDropTarget
  19. {
  20. public:
  21. DropTarget(int enqueue, int isshell)
  22. { m_enqueue = enqueue; m_isshell = isshell; }
  23. STDMETHODIMP QueryInterface (REFIID riid, LPVOID * ppvObj)
  24. {
  25. if (riid == IID_IDropTarget || riid == IID_IUnknown)
  26. {
  27. *ppvObj = this;
  28. return S_OK;
  29. }
  30. *ppvObj = NULL;
  31. return E_NOINTERFACE;
  32. }
  33. STDMETHODIMP_(ULONG) AddRef ()
  34. { return 0; }
  35. STDMETHODIMP_(ULONG) Release ()
  36. { return 0; }
  37. STDMETHODIMP DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  38. {
  39. if (pdwEffect)
  40. {
  41. if (refuseDrops && !m_isshell)
  42. *pdwEffect = DROPEFFECT_NONE;
  43. else
  44. *pdwEffect = DROPEFFECT_COPY;
  45. }
  46. return S_OK;
  47. }
  48. STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  49. {
  50. if (pdwEffect)
  51. {
  52. if (refuseDrops && !m_isshell)
  53. *pdwEffect = DROPEFFECT_NONE;
  54. }
  55. return S_OK;
  56. }
  57. STDMETHODIMP DragLeave()
  58. {
  59. return 0;
  60. }
  61. STDMETHODIMP Drop(IDataObject * pDataObj, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  62. {
  63. POINT p = {pt.x, pt.y};
  64. HWND wnd;
  65. int pl_forceappend = 0;
  66. int is_main = 0;
  67. int is_pe = 0;
  68. int pe_insert = 0;
  69. if (m_isshell)
  70. {
  71. is_main = 1;
  72. wnd = hMainWindow;
  73. if (m_enqueue == 2)
  74. {
  75. pe_insert = !SendMessageW(hMainWindow, WM_WA_IPC, PlayList_getlength(), IPC_SHELL_ACTION_START);
  76. }
  77. }
  78. else
  79. {
  80. wnd = WindowFromPoint(p);
  81. HWND child=0;
  82. do
  83. {
  84. RECT r;
  85. GetWindowRect(wnd, &r);
  86. POINT offset = p;
  87. offset.x -= r.left;
  88. offset.y -= r.top;
  89. child = ChildWindowFromPoint(wnd, offset);
  90. if (child == wnd)
  91. child = 0;
  92. else if (child)
  93. wnd = child;
  94. } while (child);
  95. HWND par = wnd;
  96. HWND pledit_poopie = NULL;
  97. while (par && !(GetWindowLongW(par, GWL_EXSTYLE) & WS_EX_ACCEPTFILES))
  98. {
  99. par = GetParent(par);
  100. }
  101. if (par) wnd = par;
  102. if (wnd == hMainWindow || IsChild(hMainWindow, wnd)
  103. || (HWND)SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)wnd, IPC_FF_GETCONTENTWND) == hMainWindow)
  104. {
  105. is_main = 1;
  106. }
  107. else if (wnd == hPLWindow || IsChild(hPLWindow, wnd) || GetParent(hPLWindow) && IsChild(wnd, hPLWindow) ||
  108. (pledit_poopie = (HWND)SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)wnd, IPC_FF_GETCONTENTWND)) == hPLWindow)
  109. {
  110. is_pe = 1;
  111. if (pledit_poopie) pl_forceappend = 1; // if we got here because we're hosting the pledit, but not actually
  112. // parenting it (meaning we are windowshaded playlist)
  113. }
  114. else
  115. {
  116. EnterCriticalSection(&embedcs);
  117. {
  118. embedWindowState *p = embedwndlist;
  119. while (p)
  120. {
  121. if (IsChild(p->me, wnd) || (GetParent(p->me) && IsChild(wnd, p->me))) break;
  122. p = p->link;
  123. }
  124. if (p)
  125. {
  126. if (wnd == p->me || IsChild(wnd, p->me) || !(GetWindowLongW(wnd, GWL_EXSTYLE) & WS_EX_ACCEPTFILES)) // if this window accepts files, dont fuck it up
  127. {
  128. HWND wnd2 = FindWindowExW(p->me, NULL, NULL, NULL);
  129. if (!(GetWindowLongW(wnd2, GWL_EXSTYLE)&WS_EX_ACCEPTFILES)) is_main = 1;
  130. else
  131. {
  132. HWND h = GetParent(p->me);
  133. char buf[128] = {0};
  134. // see if we are (AVS) docked to the main (modern) window
  135. if (h && (h = GetParent(h)) && GetWindowTextA(h, buf, sizeof(buf)) && !_stricmp(buf, "Player Window"))
  136. is_main = 1;
  137. else wnd = wnd2;
  138. }
  139. }
  140. }
  141. else is_main = 1;
  142. }
  143. LeaveCriticalSection(&embedcs);
  144. }
  145. if (is_main) wnd = hMainWindow;
  146. if (is_pe) wnd = hPLWindow;
  147. }
  148. HRESULT hr = S_OK;
  149. if (pDataObj)
  150. {
  151. // Important: these strings need to be non-Unicode (don't compile UNICODE)
  152. unsigned short cp_format_url = (unsigned short)RegisterClipboardFormat(CFSTR_SHELLURL);
  153. //Set up format structure for the descriptor and contents
  154. FORMATETC format_url =
  155. {cp_format_url, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  156. FORMATETC format_file =
  157. {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  158. // Check for URL
  159. hr = pDataObj->QueryGetData(&format_url);
  160. if (hr == S_OK)
  161. {
  162. // Get the descriptor information
  163. STGMEDIUM storage = {0, 0, 0};
  164. hr = pDataObj->GetData(&format_url, &storage);
  165. char* url = (char *)GlobalLock(storage.hGlobal);
  166. if (url)
  167. {
  168. if (is_pe || is_main || m_isshell)
  169. {
  170. int t, lp, a;
  171. int del = is_main && !(GetAsyncKeyState(VK_SHIFT) & (1 << 15));
  172. if (del) PlayList_delete();
  173. else if (!is_main && !m_isshell) // playlist
  174. {
  175. RECT r;
  176. POINT dp;
  177. GetWindowRect(wnd, &r);
  178. dp.x = pt.x - r.left;
  179. dp.y = pt.y - r.top;
  180. if (config_pe_height == 14 || pl_forceappend) t = PlayList_getlength();
  181. else
  182. {
  183. t = (dp.y - 20) / pe_fontheight;
  184. if (t < 0) t = 0;
  185. else if (t > (config_pe_height - 38 - 20 - 2) / pe_fontheight) t = PlayList_getlength();
  186. else t += pledit_disp_offs;
  187. }
  188. a = PlayList_getlength();
  189. PlayList_saveend(t);
  190. lp = PlayList_getPosition();
  191. }
  192. if(!PathIsURLA(url))
  193. {
  194. // if it's not reported as an url, try to treat it like
  195. // a filepath which has been url-encoded and insert it
  196. // though if it fails to be converted then revert to it
  197. // just being added to the playlist without processing.
  198. char url2[FILENAME_SIZE] = {"file:///"};
  199. strncat(url2, url, FILENAME_SIZE);
  200. DWORD len = lstrlenA(url2);
  201. if(SUCCEEDED(PathCreateFromUrlA(url2, url2, &len, 0)))
  202. {
  203. PlayList_appendthing(AutoWideFn(url2), 0, 0);
  204. }
  205. else
  206. {
  207. PlayList_appendthing(AutoWideFn(url), 0, 0);
  208. }
  209. }
  210. else
  211. {
  212. PlayList_appendthing(AutoWideFn(url), 0, 0);
  213. }
  214. if (del) StartPlaying();
  215. else if (!is_main && !m_isshell) // playlist
  216. {
  217. PlayList_restoreend();
  218. if (t <= PlayList_getPosition())
  219. {
  220. PlayList_setposition(lp + PlayList_getlength() - a);
  221. if (!g_has_deleted_current)
  222. {
  223. PlayList_getcurrent(FileName, FileTitle, FileTitleNum);
  224. draw_songname(FileTitle, &ui_songposition, playing ? in_getlength() : PlayList_getcurrentlength());
  225. }
  226. }
  227. plEditRefresh();
  228. }
  229. }
  230. else // fucko: pass url to 'wnd' somehow?
  231. {}
  232. }
  233. GlobalUnlock(url);
  234. GlobalFree(url);
  235. }
  236. else
  237. {
  238. // check for file
  239. hr = pDataObj->QueryGetData(&format_file);
  240. if (hr == S_OK)
  241. {
  242. STGMEDIUM medium;
  243. pDataObj->GetData (&format_file, &medium);
  244. wchar_t temp[FILENAME_SIZE] = {0};
  245. if (m_enqueue)
  246. {
  247. HDROP hdrop = (HDROP)medium.hGlobal;
  248. int y = DragQueryFileW(hdrop, 0xffffffff, temp, FILENAME_SIZE);
  249. int current = PlayList_getPosition();
  250. for (int x = 0; x < y; x ++)
  251. {
  252. DragQueryFileW(hdrop, x, temp, FILENAME_SIZE);
  253. if (!pe_insert)
  254. PlayList_appendthing(temp, 0, 0);
  255. else
  256. {
  257. PlayList_insert(++current, temp);
  258. }
  259. }
  260. DragFinish(hdrop);
  261. plEditRefresh();
  262. }
  263. else
  264. {
  265. int skinLoad = -2;
  266. int langLoad = -2;
  267. RECT r;
  268. GetWindowRect(wnd, &r);
  269. LPDROPFILES d = (LPDROPFILES)GlobalLock(medium.hGlobal);
  270. d->pt.x = pt.x - r.left;
  271. if (pl_forceappend)
  272. d->pt.y = r.bottom - r.top;
  273. else d->pt.y = pt.y - r.top;
  274. d->fNC = FALSE;
  275. GlobalUnlock(d);
  276. // check for the file being a skin or language pack
  277. // being dropped so we can intercept and not add it
  278. // into the pledit but can instead prompt for install
  279. DragQueryFileW((HDROP)medium.hGlobal, 0, temp, FILENAME_SIZE);
  280. CheckSkin(temp, hMainWindow, &skinLoad);
  281. CheckLang(temp, hMainWindow, &langLoad);
  282. if(!skinLoad && !langLoad)
  283. {
  284. PostMessageW(wnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0);
  285. }
  286. }
  287. }
  288. }
  289. }
  290. if (m_isshell && (m_enqueue == 2))
  291. {
  292. SendMessageW(hMainWindow, WM_WA_IPC, PlayList_getlength(), IPC_SHELL_ACTION_END);
  293. }
  294. return S_OK;
  295. }
  296. public:
  297. int m_enqueue;
  298. int m_isshell;
  299. };
  300. static DropTarget m_target(0, 0);
  301. class ClassFactory : public IClassFactory
  302. {
  303. public:
  304. ClassFactory(int enqueue) { m_drop = new DropTarget(enqueue, 1); }
  305. ~ClassFactory() { delete(m_drop); }
  306. STDMETHODIMP QueryInterface (REFIID riid, LPVOID * ppvObj)
  307. {
  308. if (riid == IID_IClassFactory || riid == IID_IUnknown)
  309. {
  310. *ppvObj = this;
  311. return S_OK;
  312. }
  313. *ppvObj = NULL;
  314. return E_NOINTERFACE;
  315. }
  316. STDMETHODIMP_(ULONG) AddRef ()
  317. { return 0; }
  318. STDMETHODIMP_(ULONG) Release ()
  319. { return 0; }
  320. STDMETHODIMP CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject)
  321. {
  322. if (pUnkOuter != NULL)
  323. {
  324. return CLASS_E_NOAGGREGATION;
  325. }
  326. if (riid == IID_IDropTarget || riid == IID_IUnknown)
  327. {
  328. *ppvObject = m_drop;
  329. return S_OK;
  330. }
  331. return E_NOINTERFACE;
  332. }
  333. STDMETHODIMP LockServer(BOOL fLock)
  334. {
  335. return S_OK;
  336. }
  337. private:
  338. DropTarget *m_drop;
  339. };
  340. static ClassFactory m_playCF(0);
  341. static ClassFactory m_enqueueCF(1);
  342. static ClassFactory m_enqueuePlayCF(2);
  343. static DWORD m_exposePlayHandle = NULL, m_exposeEnqueueHandle = NULL, m_exposeEnqueuePlayHandle = NULL;
  344. extern "C"
  345. {
  346. void InitDragDrops()
  347. {
  348. SetWindowLong(hMainWindow, GWL_EXSTYLE, GetWindowLongW(hMainWindow, GWL_EXSTYLE)|(WS_EX_ACCEPTFILES));
  349. refuseDrops = false;
  350. }
  351. void Ole_initDragDrop()
  352. {
  353. OleInitialize(NULL);
  354. RegisterDragDrop(hMainWindow, &m_target);
  355. RegisterDragDrop(hPLWindow, &m_target);
  356. if (hVideoWindow) RegisterDragDrop(hVideoWindow, &m_target);
  357. // {46986115-84D6-459c-8F95-52DD653E532E}
  358. static const GUID playGuid =
  359. { 0x46986115, 0x84D6, 0x459c, { 0x8f, 0x95, 0x52, 0xdd, 0x65, 0x3e, 0x53, 0x2e } };
  360. if (CoRegisterClassObject(playGuid, &m_playCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_exposePlayHandle) != S_OK)
  361. m_exposePlayHandle = NULL;
  362. // {77A366BA-2BE4-4a1e-9263-7734AA3E99A2}
  363. static const GUID enqueueGuid =
  364. { 0x77A366BA, 0x2BE4, 0x4a1e, { 0x92, 0x63, 0x77, 0x34, 0xAA, 0x3e, 0x99, 0xa2 } };
  365. if (CoRegisterClassObject(enqueueGuid, &m_enqueueCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_exposeEnqueueHandle) != S_OK)
  366. m_exposeEnqueueHandle = NULL;
  367. // {ED50B649-42B0-4153-9E99-54C45F6BD708}
  368. static const GUID enqueuePlayGuid =
  369. { 0xed50b649, 0x42b0, 0x4153, { 0x9e, 0x99, 0x54, 0xc4, 0x5f, 0x6b, 0xd7, 0x8 } };
  370. if (CoRegisterClassObject(enqueuePlayGuid, &m_enqueuePlayCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_exposeEnqueuePlayHandle) != S_OK)
  371. m_exposeEnqueuePlayHandle = NULL;
  372. }
  373. void UninitDragDrops()
  374. {
  375. SetWindowLong(hMainWindow, GWL_EXSTYLE, GetWindowLongW(hMainWindow, GWL_EXSTYLE)&~(WS_EX_ACCEPTFILES));
  376. refuseDrops = true;
  377. }
  378. void Ole_uninitDragDrop()
  379. {
  380. if (hVideoWindow) RevokeDragDrop(hVideoWindow);
  381. RevokeDragDrop(hPLWindow);
  382. RevokeDragDrop(hMainWindow);
  383. if (m_exposePlayHandle)
  384. CoRevokeClassObject(m_exposePlayHandle);
  385. if (m_exposeEnqueueHandle)
  386. CoRevokeClassObject(m_exposeEnqueueHandle);
  387. if (m_exposeEnqueuePlayHandle)
  388. CoRevokeClassObject(m_exposeEnqueuePlayHandle);
  389. OleUninitialize();
  390. }
  391. void *Ole_getDropTarget()
  392. {
  393. return (void *)&m_target;
  394. }
  395. };