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.

343 lines
11 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. // Must have access to:
  4. // IID_IPrinterFolder & IID_IFolderNotify interfaces
  5. // declared in windows\inc\winprtp.h
  6. //
  7. #include <initguid.h>
  8. #include <winprtp.h>
  9. #include "w32utils.h"
  10. #include "dpa.h"
  11. #include <msprintx.h>
  12. #include "ids.h"
  13. #include "printer.h"
  14. #include "copy.h"
  15. #include "fstreex.h"
  16. #include "datautil.h"
  17. #include "infotip.h"
  18. #include "idldrop.h"
  19. #include "ovrlaymn.h"
  20. #include "netview.h"
  21. #include "prnfldr.h"
  22. // thread data param
  23. typedef struct {
  24. CIDLDropTarget *pdt;
  25. IStream *pstmDataObj;
  26. IDataObject *pdtobj;
  27. DWORD grfKeyState;
  28. POINTL pt;
  29. DWORD dwEffect;
  30. } PRINT_DROP_THREAD;
  31. class CPrinterFolderDropTarget : public CIDLDropTarget
  32. {
  33. friend HRESULT CPrinterFolderDropTarget_CreateInstance(HWND hwnd, IDropTarget **ppdropt);
  34. public:
  35. CPrinterFolderDropTarget(HWND hwnd) : CIDLDropTarget(hwnd) { };
  36. // IDropTarget methods overwirte
  37. STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  38. STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  39. static STDMETHODIMP _HIDATestForRmPrns( LPIDA pida, int * pcRPFs, int * pcNonRPFs );
  40. static void _FreePrintDropData(PRINT_DROP_THREAD *pthp);
  41. static DWORD CALLBACK _ThreadProc(void *pv);
  42. };
  43. STDMETHODIMP CPrinterFolderDropTarget::_HIDATestForRmPrns(LPIDA pida, int *pcRPFs, int *pcNonRPFs)
  44. {
  45. // check to see if any of the ID's are remote printers....
  46. for (UINT i = 0; i < pida->cidl; i++)
  47. {
  48. LPITEMIDLIST pidlTo = IDA_ILClone(pida, i);
  49. if (pidlTo)
  50. {
  51. LPCITEMIDLIST pidlRemainder = NULL;
  52. // *pidlRemainder will be NULL for remote print folders,
  53. // and non-NULL for printers under remote print folders
  54. if (NET_IsRemoteRegItem(pidlTo, CLSID_Printers, &pidlRemainder)) // && (pidlRemainder->mkid.cb == 0))
  55. {
  56. (*pcRPFs)++;
  57. }
  58. else
  59. {
  60. (*pcNonRPFs)++;
  61. }
  62. ILFree(pidlTo);
  63. }
  64. }
  65. return S_OK;
  66. }
  67. STDMETHODIMP CPrinterFolderDropTarget::DragEnter(IDataObject * pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  68. {
  69. // We allow printer shares to be dropped for installing
  70. // But we don't want to spend the time on DragEnter finding out if it's
  71. // a printer share, so allow drops of any net resource or HIDA
  72. // REVIEW: Actually, it wouldn't take long to check the first one, but
  73. // sequencing through everything does seem like a pain.
  74. // let the base-class process it now to save away the pdwEffect
  75. CIDLDropTarget::DragEnter(pdtobj, grfKeyState, pt, pdwEffect);
  76. // are we dropping on the background ? Do we have the IDLIST clipformat ?
  77. if (m_dwData & DTID_HIDA)
  78. {
  79. int cRPFs = 0;
  80. int cNonRPFs = 0;
  81. STGMEDIUM medium;
  82. FORMATETC fmte = {g_cfNetResource, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  83. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  84. if (pida)
  85. {
  86. _HIDATestForRmPrns( pida, &cRPFs, &cNonRPFs );
  87. HIDA_ReleaseStgMedium(pida, &medium);
  88. }
  89. // if we have no Remote printers or we have any non "remote printers"
  90. // and we have no other clipformat to test...
  91. if ((( cRPFs == 0 ) || ( cNonRPFs != 0 )) && !( m_dwData & DTID_NETRES ))
  92. {
  93. // the Drop code below only handles drops for HIDA format on NT
  94. // and only if all off them are Remote Printers
  95. *pdwEffect &= ~DROPEFFECT_LINK;
  96. }
  97. }
  98. if ((m_dwData & DTID_NETRES) || (m_dwData & DTID_HIDA))
  99. {
  100. *pdwEffect &= DROPEFFECT_LINK;
  101. }
  102. else
  103. {
  104. *pdwEffect = DROPEFFECT_NONE;
  105. }
  106. m_dwEffectLastReturned = *pdwEffect;
  107. return S_OK;
  108. }
  109. void CPrinterFolderDropTarget::_FreePrintDropData(PRINT_DROP_THREAD *pthp)
  110. {
  111. if (pthp->pstmDataObj)
  112. pthp->pstmDataObj->Release();
  113. if (pthp->pdtobj)
  114. pthp->pdtobj->Release();
  115. pthp->pdt->Release();
  116. LocalFree((HLOCAL)pthp);
  117. }
  118. DWORD CALLBACK CPrinterFolderDropTarget::_ThreadProc(void *pv)
  119. {
  120. PRINT_DROP_THREAD *pthp = (PRINT_DROP_THREAD *)pv;
  121. STGMEDIUM medium;
  122. HRESULT hres = E_FAIL;
  123. FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  124. CoGetInterfaceAndReleaseStream(pthp->pstmDataObj, IID_IDataObject, (void **)&pthp->pdtobj);
  125. pthp->pstmDataObj = NULL;
  126. if (pthp->pdtobj == NULL)
  127. {
  128. _FreePrintDropData(pthp);
  129. return 0;
  130. }
  131. // First try to drop as a link to a remote print folder
  132. LPIDA pida = DataObj_GetHIDA(pthp->pdtobj, &medium);
  133. if (pida)
  134. {
  135. // Make sure that if one item in the dataobject is a
  136. // remote print folder, that they are all remote print folders.
  137. // If none are, we just give up on dropping as a RPF link, and
  138. // fall through to checking for printer shares via the
  139. // NETRESOURCE clipboard format, below.
  140. int cRPFs = 0, cNonRPFs = 0;
  141. _HIDATestForRmPrns( pida, &cRPFs, &cNonRPFs );
  142. if ((cRPFs > 0) && (cNonRPFs == 0))
  143. {
  144. // All the items in the dataobject are remote print folders or
  145. // printers under remote printer folders
  146. for (UINT i = 0; i < pida->cidl; i++)
  147. {
  148. LPITEMIDLIST pidlTo = IDA_ILClone(pida, i);
  149. if (pidlTo)
  150. {
  151. LPCITEMIDLIST pidlRemainder; // The part after the remote regitem
  152. NET_IsRemoteRegItem(pidlTo, CLSID_Printers, &pidlRemainder);
  153. if (ILIsEmpty(pidlRemainder))
  154. {
  155. // This is a remote printer folder. Drop a link to the
  156. // 'PrintHood' directory
  157. IShellFolder2 *psf = CPrintRoot_GetPSF();
  158. if (psf)
  159. {
  160. IDropTarget *pdt;
  161. hres = psf->CreateViewObject(pthp->pdt->_GetWindow(),
  162. IID_PPV_ARG(IDropTarget, &pdt));
  163. if (SUCCEEDED(hres))
  164. {
  165. pthp->dwEffect = DROPEFFECT_LINK;
  166. hres = SHSimulateDrop(pdt, pthp->pdtobj, pthp->grfKeyState, &pthp->pt, &pthp->dwEffect);
  167. pdt->Release();
  168. }
  169. }
  170. }
  171. else
  172. {
  173. TCHAR szPrinter[MAX_PATH];
  174. SHGetNameAndFlags(pidlTo, SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL);
  175. //
  176. // Setup if not the add printer wizard.
  177. //
  178. if (lstrcmpi(szPrinter, c_szNewObject))
  179. {
  180. LPITEMIDLIST pidl = Printers_PrinterSetup(pthp->pdt->_GetWindow(), MSP_NETPRINTER, szPrinter, NULL);
  181. if (pidl)
  182. ILFree(pidl);
  183. }
  184. // make sure we set hres to S_OK, so we don't break the main loop
  185. hres = S_OK;
  186. }
  187. ILFree(pidlTo);
  188. if (FAILED(hres))
  189. break;
  190. }
  191. }
  192. HIDA_ReleaseStgMedium(pida, &medium);
  193. SHChangeNotifyHandleEvents(); // force update now
  194. goto Cleanup;
  195. }
  196. else if ((cRPFs > 0) && (cNonRPFs > 0))
  197. {
  198. // At least one, but not all, item(s) in this dataobject
  199. // was a remote printer folder. Jump out now.
  200. goto Cleanup;
  201. }
  202. // else none of the items in the dataobject were remote print
  203. // folders, so fall through to the NETRESOURCE parsing
  204. }
  205. // Reset FORMATETC to NETRESOURCE clipformat for next GetData call
  206. fmte.cfFormat = g_cfNetResource;
  207. // DragEnter only allows network resources to be DROPEFFECT_LINKed
  208. ASSERT(S_OK == pthp->pdtobj->QueryGetData(&fmte));
  209. if (SUCCEEDED(pthp->pdtobj->GetData(&fmte, &medium)))
  210. {
  211. LPNETRESOURCE pnr = (LPNETRESOURCE)LocalAlloc(LPTR, 1024);
  212. if (pnr)
  213. {
  214. BOOL fNonPrnShare = FALSE;
  215. UINT cItems = SHGetNetResource(medium.hGlobal, (UINT)-1, NULL, 0);
  216. for (UINT iItem = 0; iItem < cItems; iItem++)
  217. {
  218. if (SHGetNetResource(medium.hGlobal, iItem, pnr, 1024) &&
  219. pnr->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE &&
  220. pnr->dwType == RESOURCETYPE_PRINT)
  221. {
  222. LPITEMIDLIST pidl = Printers_PrinterSetup(pthp->pdt->_GetWindow(),
  223. MSP_NETPRINTER, pnr->lpRemoteName, NULL);
  224. if (pidl)
  225. ILFree(pidl);
  226. }
  227. else
  228. {
  229. if (!fNonPrnShare)
  230. {
  231. // so we don't get > 1 of these messages per drop
  232. fNonPrnShare = TRUE;
  233. // let the user know that they can't drop non-printer
  234. // shares into the printers folder
  235. SetForegroundWindow(pthp->pdt->_GetWindow());
  236. ShellMessageBox(HINST_THISDLL,
  237. pthp->pdt->_GetWindow(),
  238. MAKEINTRESOURCE(IDS_CANTINSTALLRESOURCE), NULL,
  239. MB_OK|MB_ICONINFORMATION,
  240. (LPTSTR)pnr->lpRemoteName);
  241. }
  242. }
  243. }
  244. LocalFree((HLOCAL)pnr);
  245. }
  246. ReleaseStgMedium(&medium);
  247. }
  248. Cleanup:
  249. _FreePrintDropData(pthp);
  250. return 0;
  251. }
  252. STDMETHODIMP CPrinterFolderDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  253. {
  254. *pdwEffect = DROPEFFECT_LINK;
  255. HRESULT hr = CIDLDropTarget::DragDropMenu(DROPEFFECT_LINK, pdtobj,
  256. pt, pdwEffect, NULL, NULL, MENU_PRINTOBJ_NEWPRN_DD, grfKeyState);
  257. if (*pdwEffect)
  258. {
  259. PRINT_DROP_THREAD *pthp = (PRINT_DROP_THREAD *)LocalAlloc(LPTR, SIZEOF(*pthp));
  260. if (pthp)
  261. {
  262. pthp->grfKeyState = grfKeyState;
  263. pthp->pt = pt;
  264. pthp->dwEffect = *pdwEffect;
  265. CoMarshalInterThreadInterfaceInStream(IID_IDataObject, (IUnknown *)pdtobj, &pthp->pstmDataObj);
  266. pthp->pdt = this;
  267. pthp->pdt->AddRef();
  268. if (SHCreateThread(_ThreadProc, pthp, CTF_COINIT, NULL))
  269. {
  270. hr = S_OK;
  271. }
  272. else
  273. {
  274. _FreePrintDropData(pthp);
  275. hr = E_OUTOFMEMORY;
  276. }
  277. }
  278. }
  279. CIDLDropTarget::DragLeave();
  280. return hr;
  281. }
  282. STDAPI CPrinterFolderDropTarget_CreateInstance(HWND hwnd, IDropTarget **ppdropt)
  283. {
  284. *ppdropt = NULL;
  285. HRESULT hr;
  286. CPrinterFolderDropTarget *ppfdt = new CPrinterFolderDropTarget(hwnd);
  287. if (ppfdt)
  288. {
  289. hr = ppfdt->QueryInterface(IID_PPV_ARG(IDropTarget, ppdropt));
  290. ppfdt->Release();
  291. }
  292. else
  293. hr = E_OUTOFMEMORY;
  294. return hr;
  295. }