/*++ Copyright (c) 1995 Microsoft Corporation Module Name: cenumjob.cxx Abstract: Contains methods for implementing the Enumeration of print jobs on a printer. Has methods for the CWinNTPrintJobsCollection object as well as the CWinNTJobsEnumVar object. Author: Ram Viswanathan (ramv) 11-28-95 Revision History: --*/ #include "winnt.hxx" #pragma hdrstop CWinNTPrintJobsCollection::CWinNTPrintJobsCollection() { _pDispMgr = NULL; _pCJobsEnumVar = NULL; ENLIST_TRACKING(CWinNTPrintJobsCollection); } CWinNTPrintJobsCollection::~CWinNTPrintJobsCollection() { DWORD fStatus; // // close the printer and destroy sub objects // if(_pszADsPrinterPath){ FreeADsStr(_pszADsPrinterPath); } if(_pszPrinterName){ FreeADsStr(_pszPrinterName); } if (_hPrinter){ fStatus = ClosePrinter(_hPrinter); } delete _pDispMgr; } HRESULT CWinNTPrintJobsCollection::Create(LPWSTR pszADsPrinterPath, CWinNTCredentials& Credentials, CWinNTPrintJobsCollection ** ppCWinNTPrintJobsCollection ) { BOOL fStatus = FALSE, LastError; HANDLE hPrinter = NULL; PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE| READ_CONTROL}; HRESULT hr; CWinNTPrintJobsCollection *pCWinNTJobsCollection = NULL; POBJECTINFO pObjectInfo = NULL; TCHAR szUncPrinterName[MAX_PATH]; // // create the jobs collection object // pCWinNTJobsCollection = new CWinNTPrintJobsCollection(); if(pCWinNTJobsCollection == NULL) { hr = E_OUTOFMEMORY; goto error; } hr = BuildObjectInfo(pszADsPrinterPath, &pObjectInfo ); BAIL_ON_FAILURE(hr); pCWinNTJobsCollection->_Credentials = Credentials; hr = pCWinNTJobsCollection->_Credentials.RefServer( pObjectInfo->ComponentArray[1]); BAIL_ON_FAILURE(hr); hr = PrinterNameFromObjectInfo(pObjectInfo, szUncPrinterName ); BAIL_ON_FAILURE(hr); pCWinNTJobsCollection->_pszPrinterName = AllocADsStr(szUncPrinterName); if(!(pCWinNTJobsCollection->_pszPrinterName)){ hr = E_OUTOFMEMORY; goto error; } pCWinNTJobsCollection->_pszADsPrinterPath = AllocADsStr(pszADsPrinterPath); if(!(pCWinNTJobsCollection->_pszADsPrinterPath)){ hr = E_OUTOFMEMORY; goto error; } // // open printer and set the handle to the appropriate value // fStatus = OpenPrinter(szUncPrinterName, &hPrinter, &PrinterDefaults ); if (!fStatus) { LastError = GetLastError(); switch (LastError) { case ERROR_ACCESS_DENIED: { PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE}; fStatus = OpenPrinter(szUncPrinterName, &hPrinter, &PrinterDefaults ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); } break; } default: hr = HRESULT_FROM_WIN32(GetLastError()); break; } } BAIL_ON_FAILURE(hr); pCWinNTJobsCollection->_hPrinter = hPrinter; pCWinNTJobsCollection->_pDispMgr = new CAggregatorDispMgr; if (pCWinNTJobsCollection->_pDispMgr == NULL){ hr = E_OUTOFMEMORY; goto error; } hr = LoadTypeInfoEntry(pCWinNTJobsCollection->_pDispMgr, LIBID_ADs, IID_IADsCollection, (IADsCollection *)pCWinNTJobsCollection, DISPID_NEWENUM ); BAIL_ON_FAILURE(hr); *ppCWinNTPrintJobsCollection =pCWinNTJobsCollection; if(pObjectInfo){ FreeObjectInfo(pObjectInfo); } RRETURN(hr); error: delete pCWinNTJobsCollection; if(pObjectInfo){ FreeObjectInfo(pObjectInfo); } RRETURN_EXP_IF_ERR(hr); } /* IUnknown methods for jobs collection object */ STDMETHODIMP CWinNTPrintJobsCollection::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) { if(!ppvObj) { RRETURN(E_POINTER); } if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = this; } else if (IsEqualIID(riid, IID_IDispatch)) { *ppvObj = (IDispatch *)this; } else if (IsEqualIID(riid, IID_ISupportErrorInfo)) { *ppvObj = (ISupportErrorInfo FAR *) this; } else if (IsEqualIID(riid, IID_IADsCollection)) { *ppvObj = (IADsCollection FAR *)this; } else { *ppvObj = NULL; return E_NOINTERFACE; } ((LPUNKNOWN)*ppvObj)->AddRef(); RRETURN(S_OK); } /* ISupportErrorInfo method */ STDMETHODIMP CWinNTPrintJobsCollection::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADsCollection)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } DEFINE_IDispatch_Implementation(CWinNTPrintJobsCollection); /* IADsCollection methods */ STDMETHODIMP CWinNTPrintJobsCollection::get__NewEnum(THIS_ IUnknown * FAR* retval) { HRESULT hr; CWinNTJobsEnumVar *pCJobsEnumVar = NULL; if(!retval){ RRETURN_EXP_IF_ERR(E_POINTER); } *retval = NULL; hr = CWinNTJobsEnumVar::Create(_hPrinter, _pszADsPrinterPath, _Credentials, &pCJobsEnumVar); if (FAILED(hr)) { goto error; } ADsAssert(pCJobsEnumVar); _pCJobsEnumVar = pCJobsEnumVar; hr = _pCJobsEnumVar->QueryInterface(IID_IUnknown, (void **)retval ); BAIL_ON_FAILURE(hr); _pCJobsEnumVar->Release(); RRETURN(S_OK); error: delete pCJobsEnumVar; RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintJobsCollection::GetObject(THIS_ BSTR bstrJobName, VARIANT *pvar) { HRESULT hr; DWORD dwJobId; IDispatch *pDispatch = NULL; if(!bstrJobName || !pvar){ RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); } dwJobId = (DWORD)_wtol(bstrJobName); hr = CWinNTPrintJob::CreatePrintJob(_pszADsPrinterPath, dwJobId, ADS_OBJECT_BOUND, IID_IDispatch, _Credentials, (void **)&pDispatch); BAIL_IF_ERROR(hr); // // stick this IDispatch pointer into caller provided variant // VariantInit(pvar); V_VT(pvar) = VT_DISPATCH; V_DISPATCH(pvar) = pDispatch; cleanup: RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintJobsCollection::Add(THIS_ BSTR bstrName, VARIANT varNewItem) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } STDMETHODIMP CWinNTPrintJobsCollection::Remove(THIS_ BSTR bstrJobName) { DWORD dwJobId; HRESULT hr = S_OK; HANDLE hPrinter = NULL; BOOL fStatus = FALSE; PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE}; if(! bstrJobName){ RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); } // // convert the job name into a jobid // dwJobId = (DWORD)_wtol(bstrJobName); fStatus = OpenPrinter((LPTSTR)_pszPrinterName, &hPrinter, &PrinterDefaults ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } // // use JOB_CONTROL_DELETE instead of JOB_CONTROL_CANCEL as DELETE works // even when a print job has been restarted while CANCEL won't // fStatus = SetJob (hPrinter, dwJobId, 0, NULL, JOB_CONTROL_DELETE ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } cleanup: if (hPrinter) { ClosePrinter(hPrinter); } RRETURN (hr); } // // CWinNTJobsEnumVar methods follow // //+--------------------------------------------------------------------------- // // Function: CWinNTJobsEnumVar::CWinNTJobsEnumVar // // Synopsis: // // // Arguments: // // // Returns: // // Modifies: // // History: 11-22-95 RamV Created. // //---------------------------------------------------------------------------- CWinNTJobsEnumVar::CWinNTJobsEnumVar() { _pszADsPrinterPath = NULL; _pSafeArray = NULL; _cElements = 0; _lLBound = 0; _lCurrentPosition = _lLBound; ENLIST_TRACKING(CWinNTJobsEnumVar); } //+--------------------------------------------------------------------------- // // Function: CWinNTJobsEnumVar::~CWinNTJobsEnumVar // // Synopsis: // // // Arguments: // // Returns: // // Modifies: // // History: 11-22-95 RamV Created. // //---------------------------------------------------------------------------- CWinNTJobsEnumVar::~CWinNTJobsEnumVar() { if (_pSafeArray != NULL) SafeArrayDestroy(_pSafeArray); _pSafeArray = NULL; if(_pszADsPrinterPath){ FreeADsStr(_pszADsPrinterPath); } } HRESULT CWinNTJobsEnumVar::Create(HANDLE hPrinter, LPTSTR szADsPrinterPath, CWinNTCredentials& Credentials, CWinNTJobsEnumVar ** ppCJobsEnumVar) { // // This function uses the handle to the printer to query for the // number of jobs(cJobs) on the printer, It uses the returned value // to create a safearray of cJobs number of Job Objects. // HRESULT hr; BOOL fStatus = FALSE; PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE| READ_CONTROL}; OBJECTINFO ObjectInfo; CLexer Lexer(szADsPrinterPath); CWinNTJobsEnumVar FAR* pCJobsEnumVar = NULL; *ppCJobsEnumVar = NULL; memset((void*)&ObjectInfo, 0, sizeof(OBJECTINFO)); pCJobsEnumVar = new CWinNTJobsEnumVar(); if (pCJobsEnumVar == NULL){ hr = E_OUTOFMEMORY; goto error; } pCJobsEnumVar->_pszADsPrinterPath = AllocADsStr(szADsPrinterPath); if (!(pCJobsEnumVar->_pszADsPrinterPath)){ hr = E_OUTOFMEMORY; goto error; } hr = Object(&Lexer, &ObjectInfo); BAIL_ON_FAILURE(hr); pCJobsEnumVar->_Credentials = Credentials; // We want the next-to-last element in the array. ADsAssert(ObjectInfo.NumComponents >= 2); hr = pCJobsEnumVar->_Credentials.RefServer( ObjectInfo.ComponentArray[(ObjectInfo.NumComponents - 1) - 1]); BAIL_ON_FAILURE(hr); // // Fill in the safearray with relevant information here // hr = FillSafeArray(hPrinter, szADsPrinterPath, pCJobsEnumVar->_Credentials, pCJobsEnumVar); BAIL_ON_FAILURE(hr); *ppCJobsEnumVar = pCJobsEnumVar; // // Free the objectInfo data // FreeObjectInfo( &ObjectInfo, TRUE ); RRETURN(S_OK); error: // // Free the objectInfo data // FreeObjectInfo( &ObjectInfo, TRUE ); delete pCJobsEnumVar; RRETURN_EXP_IF_ERR(hr); } //+------------------------------------------------------------------------ // // Function: CWinNTJobsEnumVar::QueryInterface // // Synopsis: // // Arguments: [iid] // [ppv] // // Returns: HRESULT // // Modifies: // // History: 11-22-95 RamV Created. // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTJobsEnumVar::QueryInterface(REFIID iid, void FAR* FAR* ppv) { if(!ppv){ RRETURN(E_POINTER); } *ppv = NULL; if (iid == IID_IUnknown ) { *ppv = this; } else if(iid == IID_IEnumVARIANT) { *ppv = (IEnumVARIANT *)this; } else { return E_NOINTERFACE; } AddRef(); RRETURN(S_OK); } //+--------------------------------------------------------------------------- // // Function: CWinNTJobsEnumVar::Next // // Synopsis: Returns cElements number of requested Job objects in the // array supplied in pvar. // // Arguments: [cElements] -- The number of elements requested by client // [pvar] -- ptr to array of VARIANTs to for return objects // [pcElementFetched] -- if non-NULL, then number of elements // -- actually returned is placed here // // Returns: HRESULT -- S_OK if number of elements requested are returned // -- S_FALSE if number of elements is < requested // // Modifies: // // History: 11-27-95 RamV Created. // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTJobsEnumVar::Next(ULONG ulNumElementsRequested, VARIANT FAR* pvar, ULONG FAR* pulNumFetched) { HRESULT hresult; ULONG l; LONG lNewCurrent; ULONG lNumFetched; if (pulNumFetched != NULL) *pulNumFetched = 0; // // Check the out parameter to ensure it is valid // if (!pvar) { // // Returning S_FALSE to indicate that we aren't returning // as many elements as requested. // return(S_FALSE); } // // Initialize the elements to be returned // for (l=0; l (LONG)(_lLBound +_cElements)){ _lCurrentPosition = _lLBound +_cElements; return (S_FALSE); } else RRETURN(S_OK); } //+--------------------------------------------------------------------------- // // Function: CWinNTJobsEnumVar::Reset // // Synopsis: // // Arguments: [] // // Returns: HRESULT // // Modifies: // // History: // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTJobsEnumVar::Reset() { // //Just move the CurrentPosition to the lower array boundary // _lCurrentPosition = _lLBound; RRETURN(S_OK); } //+--------------------------------------------------------------------------- // // Function: CWinNTJobsEnumVar::Clone // // Synopsis: // // Arguments: [pCollection] // [ppEnumVariant] // // Returns: HRESULT // // Modifies: // // History: 11-22-95 RamV Created. // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTJobsEnumVar::Clone(IEnumVARIANT FAR* FAR* ppenum) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } HRESULT FillSafeArray(HANDLE hPrinter, LPTSTR szPrinterPath, CWinNTCredentials& Credentials, CWinNTJobsEnumVar *pJobsEnumVar ) { BOOL fStatus = FALSE; DWORD dwPassed =0, dwNeeded = 0; DWORD dwcJobs; // Number of jobs in print queue LPPRINTER_INFO_2 pPrinterInfo2; DWORD dwError = 0, LastError =0; LPBYTE pMem = NULL; LPBYTE lpbJobs = NULL; DWORD cbBuf =0; DWORD dwReturned =0; CWinNTPrintJob *pCWinNTPrintJob = NULL; SAFEARRAYBOUND sabound[1]; IDispatch *pDispatch; VARIANT v; LONG l; HRESULT hr = S_OK; LPJOB_INFO_1 lpJobInfo1 = NULL; if(hPrinter == NULL){ RRETURN_EXP_IF_ERR(HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE)); } VariantInit(&v); // // First Get info from printer to determine the number of jobs. // AjayR: 10-01-99. We always expect this call to fail but tell // us how much memory is needed !!! // fStatus = GetPrinter(hPrinter, 2, (LPBYTE)pMem, dwPassed, &dwNeeded ); if (!fStatus) { LastError = GetLastError(); switch (LastError) { case ERROR_INSUFFICIENT_BUFFER: if (pMem){ FreeADsMem(pMem); } dwPassed = dwNeeded; pMem = (LPBYTE)AllocADsMem(dwPassed); if (!pMem) { hr = E_OUTOFMEMORY; break; } fStatus = GetPrinter(hPrinter, 2, (LPBYTE)pMem, dwPassed, &dwNeeded ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); } break; default: hr = HRESULT_FROM_WIN32(GetLastError());; break; } } if(FAILED(hr)) goto error; pPrinterInfo2 =(LPPRINTER_INFO_2)pMem; dwcJobs = pPrinterInfo2->cJobs; fStatus = MyEnumJobs(hPrinter, 0, // First job you want dwcJobs, 1, //Job Info level &lpbJobs, &cbBuf, &dwReturned ); if(!fStatus){ hr =HRESULT_FROM_WIN32(GetLastError()); goto error; } // // Use the array bound as the number of jobs returned, not // the number of jobs you requested, this may have changed! // sabound[0].cElements = dwReturned; sabound[0].lLbound = 0; // // Create a one dimensional SafeArray // pJobsEnumVar->_pSafeArray = SafeArrayCreate(VT_VARIANT, 1, sabound); if (pJobsEnumVar->_pSafeArray == NULL){ hr = E_OUTOFMEMORY; goto error; } // // for each of the Jobs retrieved create the appropriate structure // for(l=0; l<(LONG)dwReturned; l++){ lpJobInfo1 = (LPJOB_INFO_1)(lpbJobs +l*sizeof(JOB_INFO_1)); hr = CWinNTPrintJob::CreatePrintJob( szPrinterPath, lpJobInfo1->JobId, ADS_OBJECT_BOUND, IID_IDispatch, Credentials, (void **)&pDispatch ); if(FAILED(hr)){ break; } VariantInit(&v); V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = pDispatch; // // Stick the caller provided data into the end of the SafeArray // hr = SafeArrayPutElement(pJobsEnumVar->_pSafeArray, &l, &v); VariantClear(&v); if (FAILED(hr)){ break; } pJobsEnumVar->_cElements++; } BAIL_ON_FAILURE(hr); if (pMem) { FreeADsMem(pMem); } if(lpbJobs){ FreeADsMem(lpbJobs); } RRETURN(S_OK); error: if (pMem) { FreeADsMem(pMem); } // // Free the buffer you just allocated // if (lpbJobs){ FreeADsMem(lpbJobs); } // // Destroy the safearray // if(pJobsEnumVar->_pSafeArray != NULL) SafeArrayDestroy(pJobsEnumVar->_pSafeArray); VariantClear(&v); RRETURN_EXP_IF_ERR(hr); } BOOL MyEnumJobs(HANDLE hPrinter, DWORD dwFirstJob, DWORD dwNoJobs, DWORD dwLevel, LPBYTE *lplpbJobs, DWORD *pcbBuf, LPDWORD lpdwReturned ) { BOOL fStatus = FALSE; DWORD dwNeeded = 0; DWORD dwError = 0; fStatus = EnumJobs(hPrinter, dwFirstJob, dwNoJobs, dwLevel, *lplpbJobs, *pcbBuf, &dwNeeded, lpdwReturned ); if (!fStatus) { if ((dwError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER) { if (*lplpbJobs) { FreeADsMem( *lplpbJobs ); } *lplpbJobs = (LPBYTE)AllocADsMem(dwNeeded); if (!*lplpbJobs) { *pcbBuf = 0; return(FALSE); } *pcbBuf = dwNeeded; fStatus = EnumJobs(hPrinter, dwFirstJob, dwNoJobs, dwLevel, *lplpbJobs, *pcbBuf, &dwNeeded, lpdwReturned ); if (!fStatus) { return(FALSE); }else { return(TRUE); } }else { return(FALSE); } }else { return(TRUE); } }