printobj.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 16k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #pragma  hdrstop
  3. #include "printer.h"
  4. typedef struct tagPREVPRINTER
  5. {
  6.     TCHAR szPrinterName[MAXNAMELENBUFFER];
  7.     HWND hwndStub;
  8. } PREVPRINTER, *LPPREVPRINTER;
  9. int FindPrinter(HDSA hPrevPrinters, LPCTSTR lpszPrinterName)
  10. {
  11.     int i = -1;
  12.     if (hPrevPrinters)
  13.     {
  14.         for (i=DSA_GetItemCount(hPrevPrinters)-1; i>=0; --i)
  15.         {
  16.             LPPREVPRINTER pPrevPrinter = DSA_GetItemPtr(hPrevPrinters, i);
  17.             if (lstrcmpi(pPrevPrinter->szPrinterName, lpszPrinterName) == 0)
  18.             {
  19.                 break;
  20.             }
  21.         }
  22.     }
  23.     return(i);
  24. }
  25. //
  26. // if uAction IS NOT MSP_NEWDRIVER then:
  27. //    installs a printer (uAction).  If successful, notifies the shell and
  28. //    returns a pidl to the printer.  ILFree() is callers responsibility.
  29. // otherwise, if uAction IS MSP_NEWDRIVER then:
  30. //    installs a printer driver (uAction).  If successful, fills the new
  31. //    driver's name into lpBuffer (ASSUMED >= MAXNAMELEN).
  32. //    Always returns NULL.
  33. // if uAction is MSP_TESTPAGEPARTIALPROMPT then:
  34. //    executes the test page code
  35. //    Always returns NULL.
  36. //
  37. HWND hwndPrinterSetup = NULL; // active printer setup window, if any
  38. LPITEMIDLIST Printers_PrinterSetup(HWND hwndStub, UINT uAction, LPTSTR lpBuffer, LPCTSTR pszServer)
  39. {
  40. #ifndef WINNT // PRINTQ
  41.     HINSTANCE hmMSPrint;
  42.     PRINTERSETUPPROC32 pfnPrinterSetup;
  43. #endif
  44.     LPITEMIDLIST pidl = NULL;
  45.     //
  46.     // HACK! This hack is related to BUG #272207
  47.     // This function is called from Printers_DeletePrinter for
  48.     // printer deletion and this case we should not check
  49.     // for REST_NOPRINTERADD restriction.
  50.     //
  51.     // -LazarI
  52.     //
  53.     if (MSP_NEWPRINTER == uAction ||
  54.         MSP_NETPRINTER == uAction ||
  55.         MSP_NEWPRINTER_MODELESS == uAction)
  56.     {
  57.             if (SHIsRestricted(hwndStub, REST_NOPRINTERADD))
  58.             {
  59.                 return NULL;
  60.             }
  61.     }
  62. #ifndef WINNT
  63.     //
  64.     // Windows 95 permits a user to printer a test page from the help trouble 
  65.     // shooter, with out any contextual information.  i.e. a printer has 
  66.     // not been selected.  In this case they will prompt the user for a 
  67.     // printer from a list of printers.  In Windows NT we do not support
  68.     // printing a test page from the help trouble shooter.  
  69.     //
  70.     // In Windows NT we prevent multiple add printer wizards from within 
  71.     // the bPrinterSetup API located in printui.dll, where as Windows 95
  72.     // prevents multiple add printer wizards here using a global.
  73.     // we only want one PrinterSetup window up at a time
  74.     //
  75.     if (uAction != MSP_TESTPAGEPARTIALPROMPT)
  76.     {
  77.         BOOL fRet = FALSE;
  78.         HWND hwnd;
  79.         ENTERCRITICAL;
  80.         if (hwndPrinterSetup != NULL &&
  81.             SetForegroundWindow(
  82.                 hwnd = GetLastActivePopup(hwndPrinterSetup) ))
  83.         {
  84.             fRet = TRUE;
  85.         }
  86.         else
  87.         {
  88.             hwndPrinterSetup = hwndStub;
  89.         }
  90.         LEAVECRITICAL;
  91.         if (fRet)
  92.         {
  93.             // In the case of deleting a printer, it is very unclear
  94.             // why the "install wizard" popped up into the user's face.
  95.             // Put up a generic "you must complete this operation" message.
  96.             ShellMessageBox(HINST_THISDLL, hwnd,
  97.                 MAKEINTRESOURCE(IDS_MUSTCOMPLETE), MAKEINTRESOURCE(IDS_PRINTERS), MB_OK);
  98.             return NULL;
  99.         }
  100.     }
  101. #endif
  102. #if WINNT // PRINTQ
  103.     if (1)
  104.     {
  105.         DWORD cchBufLen = 0;
  106. #else
  107.     hmMSPrint = LoadLibrary(TEXT("MSPRINT2.DLL"));
  108.     if (!ISVALIDHINSTANCE(hmMSPrint))
  109.     {
  110.         DebugMsg(DM_WARNING,TEXT("sh WN - Printers_PrinterSetup could not load MSPRINT2.DLL"));
  111.         ASSERT(FALSE);
  112.         return NULL;
  113.     }
  114.     // BUGBUG: pop up a message box on error?
  115.     pfnPrinterSetup = (PRINTERSETUPPROC32)GetProcAddress(hmMSPrint, "PrinterSetup32");
  116.     if (pfnPrinterSetup)
  117.     {
  118.         WORD cchBufLen = 0;
  119. #endif // PRINTQ
  120.         LPIDPRINTER pidp;
  121.         if (lpBuffer)
  122.             cchBufLen = lstrlen(lpBuffer) + 1;
  123.         if (cchBufLen < ARRAYSIZE(pidp->cName))
  124.             cchBufLen = ARRAYSIZE(pidp->cName);
  125.         pidp = (void*)LocalAlloc(LPTR, SIZEOF(IDPRINTER) - SIZEOF(pidp->cName) + cchBufLen * SIZEOF(TCHAR));
  126.         if (pidp)
  127.         {
  128.             pidp->cName[0] = TEXT('');
  129.             if (lpBuffer)
  130.                 lstrcpy(pidp->cName, lpBuffer);
  131.             //
  132.             // We don't have to worry about PrinterSetup failing due to the
  133.             // output buffer being too small.  It's the right size
  134.             // (32 bytes for Win9x, MAXNAMELENBUFFER for WinNT).
  135.             //
  136.             // On Win9x, this is ANSI, on WinNT, setup expects UNICODE.
  137.             //
  138.             // Also, there are no alignment problems since pidp is
  139.             // allocated by us.
  140.             //
  141. #ifdef WINNT // PRINTQ
  142.             if (bPrinterSetup(hwndStub,LOWORD(uAction),cchBufLen, pidp->cName,&cchBufLen, pszServer))
  143.             {
  144. #else
  145.             if (pfnPrinterSetup(hwndStub,LOWORD(uAction),cchBufLen,
  146.                 (LPBYTE)pidp->cName,&cchBufLen))
  147.             {
  148. #endif
  149.                 if (uAction == MSP_NEWDRIVER)
  150.                 {
  151.                     ASSERT(lstrlen(pidp->cName) < MAXNAMELEN);
  152.                     lstrcpy(lpBuffer, (LPTSTR)(pidp->cName));
  153.                 }
  154.                 else if (uAction == MSP_TESTPAGEPARTIALPROMPT)
  155.                 {
  156.                     // nothing to do for this case
  157.                 }
  158.                 else if (uAction == MSP_REMOVEPRINTER)
  159.                 {
  160.                     // a bit ugly, but we need to pass back success for this case
  161.                     pidl = (LPITEMIDLIST)TRUE;
  162.                 }
  163. #ifdef WINNT
  164.                 else if (uAction == MSP_NEWPRINTER_MODELESS)
  165.                 {
  166.                     // a bit ugly, but we need to pass back success for this case
  167.                     pidl = (LPITEMIDLIST)TRUE;
  168.                 }
  169. #endif
  170.                 else
  171.                 {
  172.                     LPITEMIDLIST pidlParent = SHCloneSpecialIDList(NULL, CSIDL_PRINTERS, FALSE);
  173.                     if (pidlParent)
  174.                     {
  175.                         pidp->cb = (USHORT)(FIELD_OFFSET(IDPRINTER,cName) + (lstrlen(pidp->cName) + 1) * SIZEOF(TCHAR));
  176.                         *(USHORT *)((LPBYTE)(pidp) + pidp->cb) = 0;
  177.                         pidl = ILCombine(pidlParent, (LPCITEMIDLIST)pidp);
  178.                         ILFree(pidlParent);
  179.                     }
  180.                 }
  181.             }
  182.             else
  183.             {
  184.                 DebugMsg(DM_TRACE,TEXT("sh TR - PrinterSetup32() failed (%x)"), GetLastError());
  185.             }
  186.             LocalFree((HLOCAL)pidp);
  187.         }
  188.     }
  189.     else
  190.     {
  191.         DebugMsg(DM_ERROR,TEXT("sh ER - GetProcAddress(MSPRINT32.DLL,PrinterSetup32) failed"));
  192.     }
  193.     hwndPrinterSetup = NULL;
  194. #ifndef WINNT // PRINTQ
  195.     FreeLibrary(hmMSPrint);
  196. #endif
  197.     return(pidl);
  198. }
  199. //
  200. // Printer_OneWindowAction calls pfn iff it's not in use for printer lpName.
  201. // If it's already in use for printer lpName, bring focus to that window.
  202. //
  203. void Printer_OneWindowAction(HWND hwndStub, LPCTSTR lpName, HDSA *lphdsa, LPFNPRINTACTION pfn, LPARAM lParam, BOOL fModal)
  204. {
  205.     int i;
  206.     PREVPRINTER sThisPrinter;
  207.     LPPREVPRINTER pPrevPrinter;
  208.     EnterCriticalSection(&g_csPrinters);
  209.     // Initialize the DSA if we need to
  210.     if (!*lphdsa)
  211.     {
  212.         *lphdsa = DSA_Create(SIZEOF(sThisPrinter), 4);
  213.         if (!*lphdsa)
  214.         {
  215.             goto error_exit;
  216.         }
  217.     }
  218.     // Bring window up if lpName is in use
  219.     i = FindPrinter(*lphdsa, lpName);
  220.     if (i >= 0)
  221.     {
  222.         HWND hwnd;
  223.         if (fModal) {
  224.             ShellMessageBox(HINST_THISDLL,
  225.                 hwndStub,
  226.                 MAKEINTRESOURCE(IDS_CANTOPENMODALPROP),
  227.                 MAKEINTRESOURCE(IDS_PRINTERS),
  228.                 MB_OK|MB_ICONERROR);
  229.         }
  230.         pPrevPrinter = DSA_GetItemPtr(*lphdsa, i);
  231.         if (pPrevPrinter->hwndStub == NULL ||
  232.             (hwnd = GetLastActivePopup(pPrevPrinter->hwndStub)) == NULL ||
  233.             !ShowWindow(hwnd, SW_SHOW) ||
  234.             !SetForegroundWindow(hwnd) )
  235.         {
  236.             // The window must have crashed before.  Remove it from the
  237.             // hdsa and add it again.
  238.             // WARNING: This window could be stuck waiting for a
  239.             // PRINTER_INFO_2 before putting up the window. In this case, the
  240.             // ShowWindow will fail and we'll wind up with two windows up.
  241.             DSA_DeleteItem(*lphdsa, i);
  242.         }
  243.         else
  244.         {
  245.             // We brought the existing window to the front.  We're done.
  246.             goto exit;
  247.         }
  248.     }
  249.     // We're bringing up the window
  250.     lstrcpy(sThisPrinter.szPrinterName, lpName);
  251.     sThisPrinter.hwndStub = hwndStub;
  252.     if (DSA_AppendItem(*lphdsa, &sThisPrinter) < 0)
  253.     {
  254.         goto error_exit;
  255.     }
  256.     // Call the printer function.  Make sure winspool is loaded
  257.     LeaveCriticalSection(&g_csPrinters);
  258.     pfn(hwndStub, lpName, SW_SHOWNORMAL, lParam);
  259.     EnterCriticalSection(&g_csPrinters);
  260.     // The window is gone
  261.     // (Use sThisPrinter.szPrinterName since it may have been renamed)
  262.     i = FindPrinter(*lphdsa, sThisPrinter.szPrinterName);
  263.     if (i >= 0)
  264.     {
  265.         DSA_DeleteItem(*lphdsa, i);
  266.         // Don't use up memory we don't need
  267.         if (DSA_GetItemCount(*lphdsa) == 0)
  268.         {
  269.             DSA_Destroy(*lphdsa);
  270.             *lphdsa = NULL;
  271.         }
  272.     }
  273.     goto exit;
  274. error_exit:
  275.     // BUGBUG: do we want to put up an Out Of Memory error?
  276.     DebugMsg(DM_WARNING, TEXT("sh WN - Printer_OneWindowAction() - Out Of Memory"));
  277. exit:
  278.     LeaveCriticalSection(&g_csPrinters);
  279.     return;
  280. }
  281. extern HDSA hdsaPrintDef;
  282. void PrintDef_UpdateHwnd(LPCTSTR lpszPrinterName, HWND hWnd)
  283. {
  284.     int i;
  285.     LPPREVPRINTER pThisPrinter;
  286.     EnterCriticalSection(&g_csPrinters);
  287.     if (!hdsaPrintDef)
  288.     {
  289.         goto Error0;
  290.     }
  291.     i = FindPrinter(hdsaPrintDef, lpszPrinterName);
  292.     if (i < 0)
  293.     {
  294.         goto Error0;
  295.     }
  296.     pThisPrinter = DSA_GetItemPtr(hdsaPrintDef, i);
  297.     pThisPrinter->hwndStub = hWnd;
  298. Error0:
  299.     LeaveCriticalSection(&g_csPrinters);
  300. }
  301. void PrintDef_UpdateName(LPCTSTR lpszPrinterName, LPCTSTR lpszNewName)
  302. {
  303.     int i;
  304.     LPPREVPRINTER pThisPrinter;
  305.     EnterCriticalSection(&g_csPrinters);
  306.     if (!hdsaPrintDef)
  307.     {
  308.         goto Error0;
  309.     }
  310.     i = FindPrinter(hdsaPrintDef, lpszPrinterName);
  311.     if (i < 0)
  312.     {
  313.         goto Error0;
  314.     }
  315.     pThisPrinter = DSA_GetItemPtr(hdsaPrintDef, i);
  316.     lstrcpy(pThisPrinter->szPrinterName, lpszNewName);
  317. Error0:
  318.     LeaveCriticalSection(&g_csPrinters);
  319. }
  320. void PrintDef_RefreshQueue(LPCTSTR lpszPrinterName)
  321. {
  322.     int i;
  323.     LPPREVPRINTER pThisPrinter;
  324.     EnterCriticalSection(&g_csPrinters);
  325.     if (!hdsaPrintDef)
  326.     {
  327.         goto Error0;
  328.     }
  329.     if (lpszPrinterName)
  330.     {
  331.         i = FindPrinter(hdsaPrintDef, lpszPrinterName);
  332.         if (i < 0)
  333.         {
  334.             goto Error0;
  335.         }
  336.         pThisPrinter = DSA_GetItemPtr(hdsaPrintDef, i);
  337.         SendMessage(pThisPrinter->hwndStub, WM_COMMAND, ID_VIEW_REFRESH, 0L);
  338.     }
  339.     else
  340.     {
  341.         for (i=DSA_GetItemCount(hdsaPrintDef)-1; i>=0; --i)
  342.         {
  343.             pThisPrinter = DSA_GetItemPtr(hdsaPrintDef, i);
  344.             SendMessage(pThisPrinter->hwndStub, WM_COMMAND, ID_VIEW_REFRESH, 0L);
  345.         }
  346.     }
  347. Error0:
  348.     LeaveCriticalSection(&g_csPrinters);
  349. }
  350. //---------------------------------------------------------------------------
  351. //
  352. // IDropTarget stuff
  353. //
  354. STDMETHODIMP CPrintObjs_DragEnter(IDropTarget *pdt, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  355. {
  356.     CIDLDropTarget *this = IToClass(CIDLDropTarget, dropt, pdt);
  357.     // let the base-class process it now to save away pdwEffect
  358.     CIDLDropTarget_DragEnter(pdt, pDataObj, grfKeyState, pt, pdwEffect);
  359.     // We allow files to be dropped for printing
  360.     // if it is from the bitbucket only DROEFFECT_MOVE will be set in *pdwEffect
  361.     // so this will keep us from printing wastbasket items.
  362.     if (this->dwData & DTID_HDROP)
  363.         *pdwEffect &= DROPEFFECT_COPY;
  364.     else
  365.         *pdwEffect = DROPEFFECT_NONE;   // Default action is nothing
  366.     this->dwEffectLastReturned = *pdwEffect;
  367.     return S_OK;
  368. }
  369. void Printer_PrintHDROPFiles(HWND hwnd, HDROP hdrop, LPCITEMIDLIST pidlPrinter)
  370. {
  371.     DRAGINFO di;
  372.     di.uSize = SIZEOF(di);
  373.     if (DragQueryInfo(hdrop, &di))
  374.     {
  375.         LPTSTR lpFileName = di.lpFileList;
  376.         int i = IDYES;
  377.         // Printing more than one file at a time can easily fail.
  378.         // Ask the user to confirm this operation.
  379.         if (*lpFileName && *(lpFileName + lstrlen(lpFileName) + 1))
  380.         {
  381.             i = ShellMessageBox(HINST_THISDLL,
  382.                 NULL,
  383.                 MAKEINTRESOURCE(IDS_MULTIPLEPRINTFILE),
  384.                 MAKEINTRESOURCE(IDS_PRINTERS),
  385.                 MB_YESNO|MB_ICONINFORMATION);
  386.         }
  387.         if (i == IDYES)
  388.         {
  389.             // BUGBUG: It would be really nice to have a progress bar when
  390.             // printing multiple files.  And there should definitely be a way
  391.             // to cancel this operation. Oh well, we warned them...
  392.             while (*lpFileName != TEXT(''))
  393.             {
  394.                 Printer_PrintFile(hwnd, lpFileName, pidlPrinter);
  395.                 lpFileName += lstrlen(lpFileName) + 1;
  396.             }
  397.         }
  398.         SHFree(di.lpFileList);
  399.     }
  400. }
  401. void FreePrinterThreadParam(PRNTHREADPARAM *pthp)
  402. {
  403.     if (pthp->pDataObj)
  404.         pthp->pDataObj->lpVtbl->Release(pthp->pDataObj);
  405.     if (pthp->pstmDataObj)
  406.         pthp->pstmDataObj->lpVtbl->Release(pthp->pstmDataObj);
  407.     ILFree(pthp->pidl);
  408.     LocalFree((HLOCAL)pthp);
  409. }
  410. //
  411. // This is the entry of "drop thread"
  412. //
  413. DWORD CALLBACK CPrintObj_DropThreadProc(void *pv)
  414. {
  415.     PRNTHREADPARAM *pthp = (PRNTHREADPARAM *)pv;
  416.     STGMEDIUM medium;
  417.     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  418.     CoGetInterfaceAndReleaseStream(pthp->pstmDataObj, &IID_IDataObject, (void **)&pthp->pDataObj);
  419.     pthp->pstmDataObj = NULL;
  420.     if (pthp->pDataObj && SUCCEEDED(pthp->pDataObj->lpVtbl->GetData(pthp->pDataObj, &fmte, &medium)))
  421.     {
  422.         Printer_PrintHDROPFiles(pthp->hwnd, medium.hGlobal, pthp->pidl);
  423.         ReleaseStgMedium(&medium);
  424.     }
  425.     FreePrinterThreadParam(pthp);
  426.     return 0;
  427. }
  428. HRESULT PrintObj_DropPrint(IDataObject *pDataObj, HWND hwnd, DWORD dwEffect, LPCITEMIDLIST pidl, LPTHREAD_START_ROUTINE pfn)
  429. {
  430.     HRESULT hres;
  431.     PRNTHREADPARAM *pthp = (PRNTHREADPARAM *)LocalAlloc(LPTR, SIZEOF(*pthp));
  432.     if (pthp)
  433.     {
  434.         CoMarshalInterThreadInterfaceInStream(&IID_IDataObject, (IUnknown *)pDataObj, &pthp->pstmDataObj);
  435.         pthp->hwnd = hwnd;
  436.         pthp->dwEffect = dwEffect;
  437.         pthp->pidl = ILClone(pidl);
  438.         if (hwnd)
  439.             ShellFolderView_GetAnchorPoint(hwnd, FALSE, &pthp->ptDrop);
  440.         if (SHCreateThread(pfn, pthp, CTF_COINIT, NULL))
  441.         {
  442.             hres = S_OK;
  443.         }
  444.         else
  445.         {
  446.             FreePrinterThreadParam(pthp);
  447.             hres = E_OUTOFMEMORY;
  448.         }
  449.     }
  450.     return hres;
  451. }
  452. STDMETHODIMP CPrintObjs_DropCallback(IDropTarget *pdt, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect, LPTHREAD_START_ROUTINE pfn)
  453. {
  454.     CIDLDropTarget *this = IToClass(CIDLDropTarget, dropt, pdt);
  455.     HRESULT hres;
  456.     *pdwEffect = this->dwEffectLastReturned;
  457.     if (*pdwEffect)
  458.         hres = CIDLDropTarget_DragDropMenu(this, DROPEFFECT_COPY, pDataObj,
  459.                                            pt, pdwEffect, NULL, NULL, MENU_PRINTOBJ_DD, grfKeyState);
  460.     else
  461.         hres = S_FALSE;
  462.     if (*pdwEffect)
  463.         hres = PrintObj_DropPrint(pDataObj, this->hwndOwner, *pdwEffect, this->pidl, pfn);
  464.     CIDLDropTarget_DragLeave(pdt);
  465.     return hres;
  466. }
  467. STDMETHODIMP CPrintObjs_Drop(IDropTarget *pdt, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  468. {
  469.     return CPrintObjs_DropCallback(pdt, pDataObj, grfKeyState, pt, pdwEffect, CPrintObj_DropThreadProc);
  470. }
  471. const IDropTargetVtbl c_CPrintObjsDropTargetVtbl =
  472. {
  473.     CIDLDropTarget_QueryInterface, CIDLDropTarget_AddRef, CIDLDropTarget_Release,
  474.     CPrintObjs_DragEnter,
  475.     CIDLDropTarget_DragOver,
  476.     CIDLDropTarget_DragLeave,
  477.     CPrintObjs_Drop,
  478. };