|
|
#include "shellprv.h"
#pragma hdrstop
// Must have access to:
// IID_IPrinterFolder & IID_IFolderNotify interfaces
// declared in windows\inc\winprtp.h
//
#include <initguid.h>
#include <winprtp.h>
#include "w32utils.h"
#include "dpa.h"
#include <msprintx.h>
#include "ids.h"
#include "printer.h"
#include "copy.h"
#include "fstreex.h"
#include "datautil.h"
#include "infotip.h"
#include "idldrop.h"
#include "ovrlaymn.h"
#include "netview.h"
#include "prnfldr.h"
// thread data param
typedef struct { CIDLDropTarget *pdt; IStream *pstmDataObj; IDataObject *pdtobj; DWORD grfKeyState; POINTL pt; DWORD dwEffect; } PRINT_DROP_THREAD;
class CPrinterFolderDropTarget : public CIDLDropTarget { friend HRESULT CPrinterFolderDropTarget_CreateInstance(HWND hwnd, IDropTarget **ppdropt); public: CPrinterFolderDropTarget(HWND hwnd) : CIDLDropTarget(hwnd) { };
// IDropTarget methods overwirte
STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
static STDMETHODIMP _HIDATestForRmPrns( LPIDA pida, int * pcRPFs, int * pcNonRPFs ); static void _FreePrintDropData(PRINT_DROP_THREAD *pthp); static DWORD CALLBACK _ThreadProc(void *pv); };
STDMETHODIMP CPrinterFolderDropTarget::_HIDATestForRmPrns(LPIDA pida, int *pcRPFs, int *pcNonRPFs) { // check to see if any of the ID's are remote printers....
for (UINT i = 0; i < pida->cidl; i++) { LPITEMIDLIST pidlTo = IDA_ILClone(pida, i); if (pidlTo) { LPCITEMIDLIST pidlRemainder = NULL; // *pidlRemainder will be NULL for remote print folders,
// and non-NULL for printers under remote print folders
if (NET_IsRemoteRegItem(pidlTo, CLSID_Printers, &pidlRemainder)) // && (pidlRemainder->mkid.cb == 0))
{ (*pcRPFs)++; } else { (*pcNonRPFs)++; } ILFree(pidlTo); } }
return S_OK; }
STDMETHODIMP CPrinterFolderDropTarget::DragEnter(IDataObject * pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { // We allow printer shares to be dropped for installing
// But we don't want to spend the time on DragEnter finding out if it's
// a printer share, so allow drops of any net resource or HIDA
// REVIEW: Actually, it wouldn't take long to check the first one, but
// sequencing through everything does seem like a pain.
// let the base-class process it now to save away the pdwEffect
CIDLDropTarget::DragEnter(pdtobj, grfKeyState, pt, pdwEffect);
// are we dropping on the background ? Do we have the IDLIST clipformat ?
if (m_dwData & DTID_HIDA) { int cRPFs = 0; int cNonRPFs = 0; STGMEDIUM medium; FORMATETC fmte = {g_cfNetResource, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; LPIDA pida = DataObj_GetHIDA(pdtobj, &medium); if (pida) { _HIDATestForRmPrns( pida, &cRPFs, &cNonRPFs ); HIDA_ReleaseStgMedium(pida, &medium); }
// if we have no Remote printers or we have any non "remote printers"
// and we have no other clipformat to test...
if ((( cRPFs == 0 ) || ( cNonRPFs != 0 )) && !( m_dwData & DTID_NETRES )) { // the Drop code below only handles drops for HIDA format on NT
// and only if all off them are Remote Printers
*pdwEffect &= ~DROPEFFECT_LINK; } }
if ((m_dwData & DTID_NETRES) || (m_dwData & DTID_HIDA)) { *pdwEffect &= DROPEFFECT_LINK; } else { *pdwEffect = DROPEFFECT_NONE; }
m_dwEffectLastReturned = *pdwEffect; return S_OK; }
void CPrinterFolderDropTarget::_FreePrintDropData(PRINT_DROP_THREAD *pthp) { if (pthp->pstmDataObj) pthp->pstmDataObj->Release();
if (pthp->pdtobj) pthp->pdtobj->Release();
pthp->pdt->Release(); LocalFree((HLOCAL)pthp); }
DWORD CALLBACK CPrinterFolderDropTarget::_ThreadProc(void *pv) { PRINT_DROP_THREAD *pthp = (PRINT_DROP_THREAD *)pv; STGMEDIUM medium; HRESULT hres = E_FAIL; FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
CoGetInterfaceAndReleaseStream(pthp->pstmDataObj, IID_IDataObject, (void **)&pthp->pdtobj); pthp->pstmDataObj = NULL;
if (pthp->pdtobj == NULL) { _FreePrintDropData(pthp); return 0; }
// First try to drop as a link to a remote print folder
LPIDA pida = DataObj_GetHIDA(pthp->pdtobj, &medium); if (pida) { // Make sure that if one item in the dataobject is a
// remote print folder, that they are all remote print folders.
// If none are, we just give up on dropping as a RPF link, and
// fall through to checking for printer shares via the
// NETRESOURCE clipboard format, below.
int cRPFs = 0, cNonRPFs = 0; _HIDATestForRmPrns( pida, &cRPFs, &cNonRPFs );
if ((cRPFs > 0) && (cNonRPFs == 0)) { // All the items in the dataobject are remote print folders or
// printers under remote printer folders
for (UINT i = 0; i < pida->cidl; i++) { LPITEMIDLIST pidlTo = IDA_ILClone(pida, i); if (pidlTo) { LPCITEMIDLIST pidlRemainder; // The part after the remote regitem
NET_IsRemoteRegItem(pidlTo, CLSID_Printers, &pidlRemainder); if (ILIsEmpty(pidlRemainder)) { // This is a remote printer folder. Drop a link to the
// 'PrintHood' directory
IShellFolder2 *psf = CPrintRoot_GetPSF(); if (psf) { IDropTarget *pdt; hres = psf->CreateViewObject(pthp->pdt->_GetWindow(), IID_PPV_ARG(IDropTarget, &pdt)); if (SUCCEEDED(hres)) { pthp->dwEffect = DROPEFFECT_LINK; hres = SHSimulateDrop(pdt, pthp->pdtobj, pthp->grfKeyState, &pthp->pt, &pthp->dwEffect); pdt->Release(); } } } else { TCHAR szPrinter[MAX_PATH];
SHGetNameAndFlags(pidlTo, SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL); //
// Setup if not the add printer wizard.
//
if (lstrcmpi(szPrinter, c_szNewObject)) { LPITEMIDLIST pidl = Printers_PrinterSetup(pthp->pdt->_GetWindow(), MSP_NETPRINTER, szPrinter, NULL); if (pidl) ILFree(pidl); }
// make sure we set hres to S_OK, so we don't break the main loop
hres = S_OK; } ILFree(pidlTo);
if (FAILED(hres)) break; } } HIDA_ReleaseStgMedium(pida, &medium); SHChangeNotifyHandleEvents(); // force update now
goto Cleanup; } else if ((cRPFs > 0) && (cNonRPFs > 0)) { // At least one, but not all, item(s) in this dataobject
// was a remote printer folder. Jump out now.
goto Cleanup; }
// else none of the items in the dataobject were remote print
// folders, so fall through to the NETRESOURCE parsing
}
// Reset FORMATETC to NETRESOURCE clipformat for next GetData call
fmte.cfFormat = g_cfNetResource;
// DragEnter only allows network resources to be DROPEFFECT_LINKed
ASSERT(S_OK == pthp->pdtobj->QueryGetData(&fmte));
if (SUCCEEDED(pthp->pdtobj->GetData(&fmte, &medium))) { LPNETRESOURCE pnr = (LPNETRESOURCE)LocalAlloc(LPTR, 1024); if (pnr) { BOOL fNonPrnShare = FALSE; UINT cItems = SHGetNetResource(medium.hGlobal, (UINT)-1, NULL, 0); for (UINT iItem = 0; iItem < cItems; iItem++) { if (SHGetNetResource(medium.hGlobal, iItem, pnr, 1024) && pnr->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE && pnr->dwType == RESOURCETYPE_PRINT) { LPITEMIDLIST pidl = Printers_PrinterSetup(pthp->pdt->_GetWindow(), MSP_NETPRINTER, pnr->lpRemoteName, NULL);
if (pidl) ILFree(pidl); } else { if (!fNonPrnShare) { // so we don't get > 1 of these messages per drop
fNonPrnShare = TRUE;
// let the user know that they can't drop non-printer
// shares into the printers folder
SetForegroundWindow(pthp->pdt->_GetWindow()); ShellMessageBox(HINST_THISDLL, pthp->pdt->_GetWindow(), MAKEINTRESOURCE(IDS_CANTINSTALLRESOURCE), NULL, MB_OK|MB_ICONINFORMATION, (LPTSTR)pnr->lpRemoteName); } } }
LocalFree((HLOCAL)pnr); } ReleaseStgMedium(&medium); }
Cleanup: _FreePrintDropData(pthp); return 0; }
STDMETHODIMP CPrinterFolderDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { *pdwEffect = DROPEFFECT_LINK;
HRESULT hr = CIDLDropTarget::DragDropMenu(DROPEFFECT_LINK, pdtobj, pt, pdwEffect, NULL, NULL, MENU_PRINTOBJ_NEWPRN_DD, grfKeyState);
if (*pdwEffect) { PRINT_DROP_THREAD *pthp = (PRINT_DROP_THREAD *)LocalAlloc(LPTR, SIZEOF(*pthp)); if (pthp) { pthp->grfKeyState = grfKeyState; pthp->pt = pt; pthp->dwEffect = *pdwEffect;
CoMarshalInterThreadInterfaceInStream(IID_IDataObject, (IUnknown *)pdtobj, &pthp->pstmDataObj);
pthp->pdt = this; pthp->pdt->AddRef();
if (SHCreateThread(_ThreadProc, pthp, CTF_COINIT, NULL)) { hr = S_OK; } else { _FreePrintDropData(pthp); hr = E_OUTOFMEMORY; } } } CIDLDropTarget::DragLeave();
return hr; }
STDAPI CPrinterFolderDropTarget_CreateInstance(HWND hwnd, IDropTarget **ppdropt) { *ppdropt = NULL;
HRESULT hr; CPrinterFolderDropTarget *ppfdt = new CPrinterFolderDropTarget(hwnd); if (ppfdt) { hr = ppfdt->QueryInterface(IID_PPV_ARG(IDropTarget, ppdropt)); ppfdt->Release(); } else hr = E_OUTOFMEMORY; return hr; }
|