Source code of Windows XP (NT5)
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.

846 lines
23 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1995 - 1999
  3. All rights reserved.
  4. Module Name:
  5. dragdrop.hxx
  6. Abstract:
  7. Print queue drag & drop related stuff
  8. Author:
  9. Lazar Ivanov (LazarI) 10-Mar-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. #include "dragdrop.hxx"
  15. #include <initguid.h>
  16. #include "guids.h"
  17. /////////////////////////////////////////////////////
  18. // CPrintQueueDT - print queue drop target impl.
  19. //
  20. QITABLE_DECLARE(CPrintQueueDT)
  21. class CPrintQueueDT: public CUnknownMT<QITABLE_GET(CPrintQueueDT)>, // MT impl. of IUnknown
  22. public IDropTarget,
  23. public IPrintQueueDT,
  24. public CSimpleWndSubclass<CPrintQueueDT>
  25. {
  26. private:
  27. // private members
  28. void DrawVisualFeedBack() const;
  29. void VisualFeedBack(const POINTL &ptl, BOOL bRemove = FALSE);
  30. int GetTargetItem(const POINTL &ptl) const;
  31. HRESULT DropMoveJob(const DragDrop::JOBINFO &job, POINTL ptl);
  32. HRESULT DropPrintFiles(IDataObject *pDataObj);
  33. DWORD RightClickChooseEffect(const POINTL &ptl, DWORD dwEffectIn);
  34. HRESULT GetPrinterName(LPTSTR pszName, UINT nMaxLength);
  35. // static services
  36. static DWORD WINAPI ThreadProc_PrintFiles(LPVOID lpParameter);
  37. public:
  38. // construction/destruction
  39. CPrintQueueDT();
  40. ~CPrintQueueDT();
  41. //////////////////
  42. // IUnknown
  43. //
  44. IMPLEMENT_IUNKNOWN()
  45. ///////////////////
  46. // IPrintQueueDT
  47. //
  48. STDMETHODIMP RegisterDragDrop(HWND hwndLV, TPrinter *pPrinter);
  49. STDMETHODIMP RevokeDragDrop();
  50. ///////////////////
  51. // IDropTarget
  52. //
  53. virtual HRESULT STDMETHODCALLTYPE DragEnter(
  54. /* [unique][in] */ IDataObject *pDataObj,
  55. /* [in] */ DWORD grfKeyState,
  56. /* [in] */ POINTL pt,
  57. /* [out][in] */ DWORD *pdwEffect);
  58. virtual HRESULT STDMETHODCALLTYPE DragOver(
  59. /* [in] */ DWORD grfKeyState,
  60. /* [in] */ POINTL pt,
  61. /* [out][in] */ DWORD *pdwEffect);
  62. virtual HRESULT STDMETHODCALLTYPE DragLeave( void);
  63. virtual HRESULT STDMETHODCALLTYPE Drop(
  64. /* [unique][in] */ IDataObject *pDataObj,
  65. /* [in] */ DWORD grfKeyState,
  66. /* [in] */ POINTL pt,
  67. /* [out][in] */ DWORD *pdwEffect);
  68. // implement CSimpleWndSubclass<CPrintQueueDT>
  69. LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  70. private:
  71. // private data
  72. LONG m_cRef; // ref count
  73. TPrinter *m_pPrinter; // target print queue
  74. COleComInitializer m_ole2; // make sure OLE2 is initialized.
  75. AUTO_SCROLL_DATA m_asd; // drag & drop autoscroll stuff (declared in shlobjp.h)
  76. DWORD m_grfKeyStateLast; // we need this to implement IDropTarget::Drop correctly
  77. DWORD m_dwEffect; // save the last effect to implement IDropTarget::DragOver
  78. int m_iLastItem; // last item selected (visual feedback)
  79. };
  80. // QueryInterface table
  81. QITABLE_BEGIN(CPrintQueueDT)
  82. QITABENT(CPrintQueueDT, IDropTarget), // IID_IDropTarget
  83. QITABENT(CPrintQueueDT, IPrintQueueDT), // IID_IPrintQueueDT
  84. QITABLE_END()
  85. ///////////////////
  86. // CPrintQueueDT
  87. //
  88. void CPrintQueueDT::DrawVisualFeedBack() const
  89. {
  90. ASSERT(IsAttached());
  91. int iCount = ListView_GetItemCount(m_hwnd);
  92. ASSERT(iCount && m_iLastItem <= iCount && m_iLastItem >= 0);
  93. RECT rc;
  94. if( m_iLastItem < ListView_GetItemCount(m_hwnd) )
  95. {
  96. ListView_GetItemRect(m_hwnd, m_iLastItem, &rc, LVIR_BOUNDS);
  97. }
  98. else
  99. {
  100. ListView_GetItemRect(m_hwnd, m_iLastItem-1, &rc, LVIR_BOUNDS);
  101. InflateRect(&rc, 0, -abs(rc.bottom - rc.top));
  102. }
  103. // draw a standard XOR line
  104. HDC hDC = GetDC(m_hwnd);
  105. if( hDC )
  106. {
  107. CAutoHandlePen shPen = CreatePen(PS_SOLID, 2, GetSysColor(COLOR_WINDOW));
  108. if( shPen )
  109. {
  110. HGDIOBJ hObjOld = SelectObject(hDC, shPen);
  111. SetROP2(hDC, R2_XORPEN);
  112. MoveToEx(hDC, rc.left+1, rc.top+1, NULL);
  113. LineTo(hDC, rc.right-1, rc.top+1);
  114. SelectObject(hDC, hObjOld);
  115. }
  116. ReleaseDC(m_hwnd, hDC);
  117. }
  118. }
  119. void CPrintQueueDT::VisualFeedBack(const POINTL &ptl, BOOL bRemove)
  120. {
  121. ASSERT(IsAttached());
  122. if( bRemove && -1 != m_iLastItem )
  123. {
  124. // hide the latest visual feedback
  125. DrawVisualFeedBack();
  126. m_iLastItem = -1;
  127. }
  128. else
  129. {
  130. int iItem = GetTargetItem(ptl);
  131. if( iItem != -1 && iItem != m_iLastItem )
  132. {
  133. if( -1 != m_iLastItem )
  134. {
  135. // hide the latest visual feedback
  136. DrawVisualFeedBack();
  137. m_iLastItem = -1;
  138. }
  139. // save the lastest item and draw the new
  140. // visual feedback
  141. m_iLastItem = iItem;
  142. DrawVisualFeedBack();
  143. }
  144. else
  145. {
  146. if( -1 == iItem && -1 != m_iLastItem )
  147. {
  148. // hide the latest visual feedback
  149. DrawVisualFeedBack();
  150. m_iLastItem = -1;
  151. }
  152. }
  153. }
  154. }
  155. int CPrintQueueDT::GetTargetItem(const POINTL &ptl) const
  156. {
  157. ASSERT(IsAttached());
  158. LV_HITTESTINFO info = {0};
  159. int iItem = -1;
  160. // find the item on this point
  161. info.pt.x = ptl.x;
  162. info.pt.y = ptl.y;
  163. ScreenToClient(m_hwnd, &info.pt);
  164. iItem = ListView_HitTest(m_hwnd, &info);
  165. if( (info.flags & LVHT_ONITEM) && iItem != -1 )
  166. {
  167. // get the header RECT here
  168. RECT rcHeader;
  169. HWND hwndHeader = ListView_GetHeader(m_hwnd);
  170. ASSERT(hwndHeader);
  171. GetWindowRect(hwndHeader, &rcHeader);
  172. MapWindowPoints(NULL, m_hwnd, reinterpret_cast<LPPOINT>(&rcHeader), 2);
  173. // check if the point is inside the header.
  174. if( PtInRect(&rcHeader, info.pt) )
  175. {
  176. // this item is partially covered from the header -
  177. // not a valid item.
  178. iItem = -1;
  179. }
  180. else
  181. {
  182. RECT rcItem;
  183. ListView_GetItemRect(m_hwnd, iItem, &rcItem, LVIR_BOUNDS);
  184. if( abs(rcItem.top - info.pt.y) > (abs(rcItem.bottom - rcItem.top)/2) )
  185. {
  186. // this point is in the lower half of the item rect -
  187. // go to the next item (not a problem if iItem == count
  188. iItem ++;
  189. }
  190. }
  191. }
  192. return iItem;
  193. }
  194. HRESULT CPrintQueueDT::DropMoveJob(const DragDrop::JOBINFO &job, POINTL ptl)
  195. {
  196. ASSERT(IsAttached());
  197. IDENT jobID = -1;
  198. int iItem = GetTargetItem(ptl);
  199. HRESULT hr = S_OK;
  200. // get the position of the job we are mving in front of
  201. if( iItem < ListView_GetItemCount(m_hwnd) )
  202. {
  203. LVITEM lvi = {0};
  204. lvi.iItem = iItem;
  205. lvi.iSubItem = 0;
  206. lvi.mask = LVIF_PARAM;
  207. if( ListView_GetItem(m_hwnd, &lvi) )
  208. {
  209. jobID = m_pPrinter->pData()->GetId((HITEM)lvi.lParam);
  210. }
  211. }
  212. // calculate the new & old position of the job moved
  213. NATURAL_INDEX uNewPos = (-1 == jobID) ? iItem : m_pPrinter->pData()->GetNaturalIndex(jobID, NULL);
  214. NATURAL_INDEX uOldPos = (-1 == job.dwJobID) ? job.iItem : m_pPrinter->pData()->GetNaturalIndex(job.dwJobID, NULL);
  215. if( uNewPos > uOldPos )
  216. {
  217. uNewPos--;
  218. }
  219. if( uNewPos != uOldPos )
  220. {
  221. CAutoHandlePrinter shPrinter = NULL;
  222. DWORD dwAccess = 0;
  223. if( ERROR_SUCCESS == TPrinter::sOpenPrinter(job.szPrinterName, &dwAccess, &shPrinter) )
  224. {
  225. DWORD cbJob2 = 0;
  226. CAutoPtrSpl<JOB_INFO_2> spJob2 = NULL;
  227. if( VDataRefresh::bGetJob(shPrinter, job.dwJobID, 2, spJob2.GetPPV(), &cbJob2) )
  228. {
  229. // set the new position and call SetJob to reorder.
  230. spJob2->Position = uNewPos+1;
  231. if( !SetJob(shPrinter, job.dwJobID, 2, spJob2.GetPtrAs<LPBYTE>(), 0) )
  232. {
  233. hr = HRESULT_FROM_WIN32(GetLastError());
  234. MessageBeep((UINT)-1);
  235. }
  236. }
  237. }
  238. }
  239. return hr;
  240. }
  241. HRESULT CPrintQueueDT::DropPrintFiles(IDataObject *pDataObj)
  242. {
  243. HRESULT hr = E_UNEXPECTED;
  244. CRefPtrCOM<IStream> spStream;
  245. // we create a background therad which will attempt to print
  246. // documents in pDataObj
  247. hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObj, &spStream);
  248. if( SUCCEEDED(hr) )
  249. {
  250. CAutoPtr<CCookiesHolder> spThreadInfo = new CCookiesHolder;
  251. if( spThreadInfo && spThreadInfo->SetCount(2) )
  252. {
  253. // as we pass pointer to ourselves to the thread proc
  254. // we need to AddRef ourselves here
  255. AddRef();
  256. // setup the cookie holder
  257. spThreadInfo->SetCookie<IStream*>(0, spStream);
  258. spThreadInfo->SetCookie<CPrintQueueDT*>(1, this);
  259. // spin the background thread here
  260. DWORD dwThreadId;
  261. CAutoHandleNT shThread = TSafeThread::Create(NULL, 0,
  262. (LPTHREAD_START_ROUTINE)CPrintQueueDT::ThreadProc_PrintFiles,
  263. spThreadInfo, 0, &dwThreadId);
  264. if( shThread )
  265. {
  266. // the thread will take care to free this memory
  267. spThreadInfo.Detach();
  268. spStream.Detach();
  269. hr = S_OK;
  270. }
  271. else
  272. {
  273. // thread creation failed. setup appropriate HRESULT from
  274. // last error
  275. hr = HRESULT_FROM_WIN32(GetLastError());
  276. // compensate the AddRef above
  277. Release();
  278. }
  279. }
  280. else
  281. {
  282. // new CCookiesHolder has failed
  283. hr = E_OUTOFMEMORY;
  284. }
  285. }
  286. return hr;
  287. }
  288. HRESULT CPrintQueueDT::GetPrinterName(LPTSTR pszName, UINT nMaxLength)
  289. {
  290. HRESULT hr = E_INVALIDARG;
  291. TCHAR szCurrentPrinterName[kPrinterBufMax];
  292. if( pszName )
  293. {
  294. if( m_pPrinter )
  295. {
  296. m_pPrinter->pszPrinterName(szCurrentPrinterName);
  297. lstrcpyn(pszName, szCurrentPrinterName, nMaxLength);
  298. hr = S_OK;
  299. }
  300. else
  301. {
  302. hr = E_UNEXPECTED;
  303. }
  304. }
  305. return hr;
  306. }
  307. DWORD WINAPI CPrintQueueDT::ThreadProc_PrintFiles(LPVOID lpParameter)
  308. {
  309. TCHAR szPrinterName[kPrinterBufMax];
  310. HRESULT hr = E_UNEXPECTED;
  311. CAutoPtr<CCookiesHolder> spThreadInfo = (CCookiesHolder *)lpParameter;
  312. if( spThreadInfo )
  313. {
  314. // make sure OLE2 is initialized.
  315. COleComInitializer ole2(TRUE);
  316. // get the cookies
  317. CAutoPtrCOM<IStream> spStream = spThreadInfo->GetCookie<IStream*>(0);
  318. CAutoPtrCOM<CPrintQueueDT> spPrintQueueDT = spThreadInfo->GetCookie<CPrintQueueDT*>(1);
  319. if( ole2 && spStream && spPrintQueueDT )
  320. {
  321. UINT uCount = 0;
  322. CAutoPtrPIDL pidlPrinter;
  323. CRefPtrCOM<IShellFolder> spLocalPrnFolder;
  324. CRefPtrCOM<IDropTarget> spPrinterDT;
  325. for( ;; )
  326. {
  327. // attempt to get IDropTarget for the printer name
  328. if( SUCCEEDED(hr = spPrintQueueDT->GetPrinterName(szPrinterName, ARRAYSIZE(szPrinterName))) &&
  329. SUCCEEDED(hr = ShellServices::CreatePrinterPIDL(NULL, szPrinterName,
  330. &spLocalPrnFolder, &pidlPrinter)) &&
  331. SUCCEEDED(hr = spLocalPrnFolder->GetUIObjectOf(NULL, 1, pidlPrinter.GetPPCT(),
  332. IID_IDropTarget, &uCount, spPrinterDT.GetPPV())) )
  333. {
  334. // unmarshal the data object from the stream
  335. CRefPtrCOM<IDataObject> spDataObj;
  336. hr = CoGetInterfaceAndReleaseStream(spStream, IID_IDataObject, spDataObj.GetPPV());
  337. if( SUCCEEDED(hr) )
  338. {
  339. // CoGetInterfaceAndReleaseStream relases the stream -
  340. // make sure we don't release twice
  341. spStream.Detach();
  342. // simulate drag & drop over the printer object here
  343. DWORD dwEffect = DROPEFFECT_COPY;
  344. hr = SHSimulateDrop(spPrinterDT, spDataObj, MK_LBUTTON, NULL, &dwEffect);
  345. }
  346. }
  347. if( FAILED(hr) && ERROR_INVALID_PRINTER_NAME == SCODE_CODE(GetScode(hr)) )
  348. {
  349. // this printer is probably a remote printer which the user is not connected to.
  350. // he must be connected to the printer in order to be able to print. show up
  351. // appropriate message to inform the user about this case and ask if he wants to
  352. // connect to this printer and then print.
  353. if( IDYES == iMessage(NULL, IDS_PRINTERS_TITLE, IDS_PRINT_NOTCONNECTED,
  354. MB_YESNO|MB_ICONQUESTION, kMsgNone, NULL) )
  355. {
  356. // make a printer connection here.
  357. UINT uLen = COUNTOF(szPrinterName);
  358. // attempt to connect to this printer. if this fails it shows up the
  359. // appropriate error message, so don't bother to show up UI here.
  360. if( bPrinterSetup(NULL, MSP_NETPRINTER, uLen, szPrinterName, &uLen, NULL) )
  361. {
  362. // release/reset the smart pointers and try to print again.
  363. spLocalPrnFolder = NULL;
  364. spPrinterDT = NULL;
  365. pidlPrinter = NULL;
  366. continue;
  367. }
  368. }
  369. }
  370. break;
  371. }
  372. }
  373. }
  374. // setup the return value here
  375. if( SUCCEEDED(hr) )
  376. {
  377. return ERROR_SUCCESS;
  378. }
  379. else
  380. {
  381. DWORD dwErr = HRESULT_CODE(hr);
  382. SetLastError(dwErr);
  383. return dwErr;
  384. }
  385. }
  386. // implement CSimpleWndSubclass<CPrintQueueDT>
  387. LRESULT CPrintQueueDT::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  388. {
  389. switch( uMsg )
  390. {
  391. case WM_VSCROLL:
  392. case WM_HSCROLL:
  393. {
  394. // make sure the feedback is hidden when scrolling
  395. POINTL ptl = {0};
  396. VisualFeedBack(ptl, TRUE);
  397. }
  398. break;
  399. default:
  400. break;
  401. }
  402. // allways call the default processing
  403. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  404. }
  405. DWORD CPrintQueueDT::RightClickChooseEffect(const POINTL &ptl, DWORD dwEffectIn)
  406. {
  407. HMENU hMenu = NULL;
  408. // pop up a menu to choose from.
  409. if( dwEffectIn == DROPEFFECT_MOVE )
  410. {
  411. // we're moving a job
  412. hMenu = ShellServices::LoadPopupMenu(ghInst, POPUP_DRAGDROP_MOVE);
  413. SetMenuDefaultItem(hMenu, POPUP_DRAGDROP_MOVE, MF_BYCOMMAND);
  414. }
  415. else if( dwEffectIn == DROPEFFECT_COPY )
  416. {
  417. // we are printing files
  418. hMenu = ShellServices::LoadPopupMenu(ghInst, POPUP_DRAGDROP_PRINT);
  419. SetMenuDefaultItem(hMenu, POPUP_DRAGDROP_PRINT, MF_BYCOMMAND);
  420. }
  421. if( hMenu )
  422. {
  423. // show up the context menu
  424. BOOL bReturn = TrackPopupMenu(hMenu,
  425. TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTALIGN,
  426. ptl.x, ptl.y, 0, m_hwnd, NULL);
  427. // modify the dwEffectIn according the user choise
  428. switch( bReturn )
  429. {
  430. case IDM_DRAGDROP_PRINT:
  431. dwEffectIn = DROPEFFECT_COPY;
  432. break;
  433. case IDM_DRAGDROP_MOVE:
  434. dwEffectIn = DROPEFFECT_MOVE;
  435. break;
  436. case IDM_DRAGDROP_CANCEL:
  437. dwEffectIn = DROPEFFECT_NONE;
  438. break;
  439. default:
  440. dwEffectIn = DROPEFFECT_NONE;
  441. }
  442. DestroyMenu(hMenu);
  443. }
  444. else
  445. {
  446. // if hMenu is NULL (i.e. LoadMenu has falied) then
  447. // cancel the whole operation
  448. dwEffectIn = DROPEFFECT_NONE;
  449. }
  450. // return modified dwEffectIn.
  451. return dwEffectIn;
  452. }
  453. CPrintQueueDT::CPrintQueueDT()
  454. : m_cRef(1),
  455. m_pPrinter(NULL),
  456. m_ole2(TRUE),
  457. m_grfKeyStateLast(0),
  458. m_dwEffect(0),
  459. m_iLastItem(-1)
  460. {
  461. // nothing
  462. }
  463. CPrintQueueDT::~CPrintQueueDT()
  464. {
  465. if( IsAttached() )
  466. {
  467. RevokeDragDrop();
  468. }
  469. }
  470. /////////////////////////////////////////////////////
  471. // IPrintQueueDT members
  472. //
  473. STDMETHODIMP CPrintQueueDT::RegisterDragDrop(HWND hwndLV, TPrinter *pPrinter)
  474. {
  475. HRESULT hr = E_FAIL;
  476. if( !IsAttached() && m_ole2 && hwndLV && pPrinter )
  477. {
  478. // register this window for OLE2 drag & drop
  479. hr = ::RegisterDragDrop(GetParent(hwndLV), static_cast<IDropTarget*>(this));
  480. if( SUCCEEDED(hr) && Attach(hwndLV) )
  481. {
  482. // make sure shell icon cache is initialized, so
  483. // DAD_* functions behave correctly.
  484. FileIconInit(FALSE);
  485. m_pPrinter = pPrinter;
  486. }
  487. }
  488. return hr;
  489. }
  490. STDMETHODIMP CPrintQueueDT::RevokeDragDrop()
  491. {
  492. HRESULT hr = E_FAIL;
  493. if( IsAttached() && m_ole2 && m_pPrinter )
  494. {
  495. // unregister this window for OLE2 drag & drop
  496. hr = ::RevokeDragDrop(GetParent(m_hwnd));
  497. Detach();
  498. m_pPrinter = NULL;
  499. }
  500. return hr;
  501. }
  502. // this API is supposed to be declared in shlobjp.h, and exported from shell32.dll,
  503. // but for some reason it isn't. duplicate the code here.
  504. STDAPI_(BOOL) DAD_DragEnterEx3(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtobj)
  505. {
  506. RECT rc;
  507. GetWindowRect(hwndTarget, &rc);
  508. // If hwndTarget is RTL mirrored, then measure the
  509. // the client point from the visual right edge
  510. // (near edge in RTL mirrored windows). [samera]
  511. POINT pt;
  512. if( GetWindowLong(hwndTarget, GWL_EXSTYLE) & WS_EX_LAYOUTRTL )
  513. pt.x = rc.right - ptStart.x;
  514. else
  515. pt.x = ptStart.x - rc.left;
  516. pt.y = ptStart.y - rc.top;
  517. return DAD_DragEnterEx2(hwndTarget, pt, pdtobj);
  518. }
  519. ///////////////////
  520. // IDropTarget
  521. //
  522. HRESULT STDMETHODCALLTYPE CPrintQueueDT::DragEnter(
  523. /* [unique][in] */ IDataObject *pDataObj,
  524. /* [in] */ DWORD grfKeyState,
  525. /* [in] */ POINTL pt,
  526. /* [out][in] */ DWORD *pdwEffect)
  527. {
  528. ASSERT(IsAttached());
  529. // save the last key state
  530. m_grfKeyStateLast = grfKeyState;
  531. // by default - none
  532. *pdwEffect = DROPEFFECT_NONE;
  533. STGMEDIUM medium;
  534. FORMATETC fmte = {DragDrop::g_cfPrintJob, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  535. // try to get DragDrop::g_cfPrintJob data first.
  536. if( SUCCEEDED(pDataObj->GetData(&fmte, &medium)) )
  537. {
  538. // aquire the JOBINFO
  539. DragDrop::JOBINFO *pJobInfo = (DragDrop::JOBINFO *)GlobalLock(medium.hGlobal);
  540. if( pJobInfo && pJobInfo->hwndLV == m_hwnd )
  541. {
  542. // this is a print job from our window, accept this
  543. *pdwEffect = DROPEFFECT_MOVE;
  544. }
  545. // release medium
  546. GlobalUnlock(medium.hGlobal);
  547. ReleaseStgMedium(&medium);
  548. }
  549. else
  550. {
  551. // try to get CF_HDROP data.
  552. FORMATETC fmte2 = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  553. if( SUCCEEDED(pDataObj->QueryGetData(&fmte2)) )
  554. {
  555. // we also accept files for printing
  556. *pdwEffect = DROPEFFECT_COPY;
  557. }
  558. }
  559. // store dwEffect for DragOver
  560. m_dwEffect = *pdwEffect;
  561. // invoke shell to do the standard stuff
  562. DAD_DragEnterEx3(m_hwnd, pt, pDataObj);
  563. DAD_InitScrollData(&m_asd);
  564. return S_OK;
  565. }
  566. HRESULT STDMETHODCALLTYPE CPrintQueueDT::DragOver(
  567. /* [in] */ DWORD grfKeyState,
  568. /* [in] */ POINTL pt,
  569. /* [out][in] */ DWORD *pdwEffect)
  570. {
  571. ASSERT(IsAttached());
  572. // effect was stored in DragEnter
  573. *pdwEffect = m_dwEffect;
  574. // convert to local coords
  575. POINT pts = {pt.x, pt.y};
  576. ScreenToClient(m_hwnd, &pts);
  577. // assume coords of our window match listview
  578. if( DAD_AutoScroll(m_hwnd, &m_asd, &pts) )
  579. {
  580. *pdwEffect |= DROPEFFECT_SCROLL;
  581. }
  582. if( DROPEFFECT_MOVE & (*pdwEffect) )
  583. {
  584. // draw visual feedback if necessary
  585. VisualFeedBack(pt, FALSE);
  586. }
  587. // invoke shell to do the standard stuff
  588. DAD_DragMove(pts);
  589. return S_OK;
  590. }
  591. HRESULT STDMETHODCALLTYPE CPrintQueueDT::DragLeave( void)
  592. {
  593. ASSERT(IsAttached());
  594. // remove the visual feedback if any
  595. POINTL ptl = {0};
  596. VisualFeedBack(ptl, TRUE);
  597. // invoke shell to do the standard stuff
  598. DAD_DragLeave();
  599. return S_OK;
  600. }
  601. HRESULT STDMETHODCALLTYPE CPrintQueueDT::Drop(
  602. /* [unique][in] */ IDataObject *pDataObj,
  603. /* [in] */ DWORD grfKeyState,
  604. /* [in] */ POINTL pt,
  605. /* [out][in] */ DWORD *pdwEffect)
  606. {
  607. ASSERT(IsAttached());
  608. HRESULT hr = E_UNEXPECTED;
  609. if( m_grfKeyStateLast & MK_LBUTTON )
  610. {
  611. *pdwEffect = m_dwEffect;
  612. }
  613. else
  614. {
  615. *pdwEffect = RightClickChooseEffect(pt, m_dwEffect);
  616. }
  617. // do the drop here
  618. if( DROPEFFECT_COPY == *pdwEffect )
  619. {
  620. // we're printing the file(s) pDataObj to the printer
  621. DropPrintFiles(pDataObj);
  622. }
  623. else if( DROPEFFECT_MOVE == *pdwEffect )
  624. {
  625. // we are reordering jobs withing this print queue
  626. STGMEDIUM medium = {0};
  627. FORMATETC fmte = {DragDrop::g_cfPrintJob, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  628. hr = pDataObj->GetData(&fmte, &medium);
  629. if( SUCCEEDED(hr) )
  630. {
  631. DragDrop::JOBINFO *pJobInfo = (DragDrop::JOBINFO *)GlobalLock(medium.hGlobal);
  632. if( pJobInfo )
  633. {
  634. hr = DropMoveJob(*pJobInfo, pt);
  635. GlobalUnlock(medium.hGlobal);
  636. }
  637. ReleaseStgMedium(&medium);
  638. }
  639. }
  640. // make sure to unlock the window for updating
  641. DragLeave();
  642. return hr;
  643. }
  644. /////////////////////////////////////////////////////
  645. // common drag & drop APIs & data structures
  646. //
  647. namespace DragDrop
  648. {
  649. // print job clipboard format (JOBINFO)
  650. CLIPFORMAT g_cfPrintJob = 0;
  651. // registers the clipboard format for a print job (JOBINFO)
  652. void RegisterPrintJobClipboardFormat()
  653. {
  654. if( !g_cfPrintJob )
  655. {
  656. g_cfPrintJob = static_cast<CLIPFORMAT>(
  657. RegisterClipboardFormat(TEXT("PrintJob32")));
  658. }
  659. }
  660. // creates IDataObject & IDropSource for a printer job objec
  661. HRESULT CreatePrintJobObject(const JOBINFO &jobInfo, REFIID riid, void **ppv)
  662. {
  663. HRESULT hr = E_INVALIDARG;
  664. if( ppv )
  665. {
  666. *ppv = NULL; // reset this
  667. // make sure print job data type is registered first
  668. RegisterPrintJobClipboardFormat();
  669. // instantiate CSimpleDataObjImpl template for JOBINFO
  670. CAutoPtrCOM< CDataObj<> > spDataObj = new CDataObj<>;
  671. CAutoPtrCOM< CSimpleDataObjImpl<JOBINFO> > spJobObj = new CSimpleDataObjImpl<JOBINFO>(jobInfo, g_cfPrintJob, spDataObj);
  672. if( spDataObj && spJobObj )
  673. {
  674. hr = spJobObj->QueryInterface(riid, ppv);
  675. }
  676. else
  677. {
  678. hr = E_OUTOFMEMORY;
  679. }
  680. }
  681. return hr;
  682. }
  683. // instantiate a IPrintQueueDT implementation
  684. HRESULT CreatePrintQueueDT(REFIID riid, void **ppv)
  685. {
  686. HRESULT hr = E_INVALIDARG;
  687. if( ppv )
  688. {
  689. *ppv = NULL; // reset this
  690. // instantiate CPrintQueueDT
  691. CAutoPtrCOM<CPrintQueueDT> spObj = new CPrintQueueDT;
  692. if( spObj )
  693. {
  694. hr = spObj->QueryInterface(riid, ppv);
  695. }
  696. else
  697. {
  698. hr = E_OUTOFMEMORY;
  699. }
  700. }
  701. return hr;
  702. }
  703. } // namespace DragDrop