/*++ Copyright (c) 1995-1996 Microsoft Corporation Module Name: cjob.cxx Abstract: Contains methods for Print Job object and its property sets for the Windows NT provider. Objects whose methods are supported here are CWinNTPrintJob, CWinNTPrintJob and CWinNTPrintJob. Author: Ram Viswanathan (ramv) 11-18-95 Revision History: --*/ #include "winnt.hxx" #pragma hdrstop #define INITGUID // // class CWinNTPrintJob Methods // DEFINE_IDispatch_ExtMgr_Implementation(CWinNTPrintJob); DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTPrintJob); DEFINE_IADs_TempImplementation(CWinNTPrintJob); DEFINE_IADs_PutGetImplementation(CWinNTPrintJob, PrintJobClass,gdwJobTableSize); DEFINE_IADsPropertyList_Implementation(CWinNTPrintJob, PrintJobClass,gdwJobTableSize) CWinNTPrintJob::CWinNTPrintJob() { _pDispMgr = NULL; _pExtMgr = NULL; _hprinter = NULL; _lJobId = 0; _pszPrinterName = NULL; _pszPrinterPath = NULL; _pPropertyCache = NULL; ENLIST_TRACKING(CWinNTPrintJob); return; } CWinNTPrintJob::~CWinNTPrintJob() { if(_pszPrinterName){ FreeADsStr(_pszPrinterName); } if(_pszPrinterPath){ FreeADsStr(_pszPrinterPath); } _hprinter = NULL; delete _pExtMgr; // created last, destroyed first delete _pDispMgr; delete _pPropertyCache; return; } HRESULT CWinNTPrintJob::CreatePrintJob( LPTSTR pszPrinterPath, LONG lJobId, DWORD dwObjectState, REFIID riid, CWinNTCredentials& Credentials, LPVOID *ppvoid ) { CWinNTPrintJob *pCWinNTPrintJob = NULL; HRESULT hr; TCHAR szJobName[MAX_LONG_LENGTH]; POBJECTINFO pObjectInfo = NULL; TCHAR szUncPrinterName[MAX_PATH]; // // Create the job object // hr = AllocatePrintJobObject(pszPrinterPath, &pCWinNTPrintJob ); BAIL_ON_FAILURE(hr); ADsAssert(pCWinNTPrintJob->_pDispMgr); // // convert the JobId that we have into a string that we move // into the Name field // _ltow(lJobId, szJobName, 10); hr = pCWinNTPrintJob->InitializeCoreObject(pszPrinterPath, szJobName, PRINTJOB_CLASS_NAME, PRINTJOB_SCHEMA_NAME, CLSID_WinNTPrintJob, dwObjectState); BAIL_ON_FAILURE(hr); hr = BuildObjectInfo(pszPrinterPath, &pObjectInfo); BAIL_ON_FAILURE(hr); hr = PrinterNameFromObjectInfo(pObjectInfo, szUncPrinterName); BAIL_ON_FAILURE(hr); pCWinNTPrintJob->_Credentials = Credentials; hr = pCWinNTPrintJob->_Credentials.RefServer( pObjectInfo->ComponentArray[1]); BAIL_ON_FAILURE(hr); pCWinNTPrintJob->_pszPrinterName = AllocADsStr(szUncPrinterName); if(!(pCWinNTPrintJob->_pszPrinterName)){ hr = E_OUTOFMEMORY; goto error; } pCWinNTPrintJob->_lJobId = lJobId; hr = SetLPTSTRPropertyInCache(pCWinNTPrintJob->_pPropertyCache, TEXT("HostPrintQueue"), pszPrinterPath, TRUE ); // // Load ext mgr and extensions // hr = ADSILoadExtensionManager( PRINTJOB_CLASS_NAME, (IADsPrintJob *) pCWinNTPrintJob, pCWinNTPrintJob->_pDispMgr, Credentials, &pCWinNTPrintJob->_pExtMgr ); BAIL_ON_FAILURE(hr); ADsAssert(pCWinNTPrintJob->_pExtMgr); // check if the call is from UMI if(Credentials.GetFlags() & ADS_AUTH_RESERVED) { // // we do not pass riid to InitUmiObject below. This is because UMI object // does not support IDispatch. There are several places in ADSI code where // riid passed into this function is defaulted to IID_IDispatch - // IADsContainer::Create for example. To handle these cases, we always // request IID_IUnknown from the UMI object. Subsequent code within UMI // will QI for the appropriate interface. // // Printjob objects have "" as their ADsPath. Just set the class for // iddentification purposes. pCWinNTPrintJob->_CompClasses[0] = L"PrintJob"; hr = pCWinNTPrintJob->InitUmiObject( pCWinNTPrintJob->_Credentials, PrintJobClass, gdwJobTableSize, pCWinNTPrintJob->_pPropertyCache, (IUnknown *)(INonDelegatingUnknown *) pCWinNTPrintJob, pCWinNTPrintJob->_pExtMgr, IID_IUnknown, ppvoid ); BAIL_ON_FAILURE(hr); FreeObjectInfo(pObjectInfo); // // UMI object was created and the interface was obtained successfully. // UMI object now has a reference to the inner unknown of IADs, since // the call to Release() below is not going to be made in this case. // RRETURN(hr); } hr = pCWinNTPrintJob->QueryInterface( riid,(void **)ppvoid); BAIL_ON_FAILURE(hr); pCWinNTPrintJob->Release(); FreeObjectInfo(pObjectInfo); RRETURN(hr); error: FreeObjectInfo(pObjectInfo); delete pCWinNTPrintJob; RRETURN (hr); } HRESULT CWinNTPrintJob::AllocatePrintJobObject( LPTSTR pszPrinterPath, CWinNTPrintJob ** ppPrintJob ) { CWinNTPrintJob FAR * pPrintJob = NULL; HRESULT hr = S_OK; pPrintJob = new CWinNTPrintJob(); if (pPrintJob == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); pPrintJob->_pszPrinterPath = AllocADsStr(pszPrinterPath); if(!(pPrintJob->_pszPrinterPath)){ hr = E_OUTOFMEMORY; goto error; } pPrintJob->_pDispMgr = new CAggregatorDispMgr; if (pPrintJob->_pDispMgr == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pPrintJob->_pDispMgr, LIBID_ADs, IID_IADsPrintJob, (IADsPrintJob *)pPrintJob, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pPrintJob->_pDispMgr, LIBID_ADs, IID_IADsPrintJobOperations, (IADsPrintJobOperations *)pPrintJob, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry( pPrintJob->_pDispMgr, LIBID_ADs, IID_IADsPropertyList, (IADsPropertyList *)pPrintJob, DISPID_VALUE ); BAIL_ON_FAILURE(hr); hr = CPropertyCache::createpropertycache( PrintJobClass, gdwJobTableSize, (CCoreADsObject *)pPrintJob, &(pPrintJob->_pPropertyCache) ); BAIL_ON_FAILURE(hr); (pPrintJob->_pDispMgr)->RegisterPropertyCache( pPrintJob->_pPropertyCache ); *ppPrintJob = pPrintJob; RRETURN(hr); error: // // direct memeber assignement assignement at pt of creation, so // do NOT delete _pPropertyCache or _pDisMgr here to avoid attempt // of deletion again in pPrintJob destructor and AV // delete pPrintJob; RRETURN_EXP_IF_ERR(hr); } /* IUnknown methods for printer object */ //---------------------------------------------------------------------------- // Function: QueryInterface // // Synopsis: If this object is aggregated within another object, then // all calls will delegate to the outer object. Otherwise, the // non-delegating QI is called // // Arguments: // // iid interface requested // ppInterface Returns pointer to interface requested. NULL if interface // is not supported. // // Returns: S_OK on success. Error code otherwise. // // Modifies: *ppInterface to return interface pointer // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintJob::QueryInterface( REFIID iid, LPVOID *ppInterface ) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->QueryInterface( iid, ppInterface )); RRETURN(NonDelegatingQueryInterface( iid, ppInterface )); } //---------------------------------------------------------------------------- // Function: AddRef // // Synopsis: IUnknown::AddRef. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating AddRef is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTPrintJob::AddRef(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->AddRef()); RRETURN(NonDelegatingAddRef()); } //---------------------------------------------------------------------------- // Function: Release // // Synopsis: IUnknown::Release. If this object is aggregated within // another, all calls will delegate to the outer object. // Otherwise, the non-delegating Release is called // // Arguments: // // None // // Returns: New reference count // // Modifies: Nothing // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CWinNTPrintJob::Release(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->Release()); RRETURN(NonDelegatingRelease()); } //---------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintJob::NonDelegatingQueryInterface(REFIID riid, LPVOID FAR* ppvObj) { HRESULT hr = S_OK; if(!ppvObj){ RRETURN(E_POINTER); } if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IADsPrintJob *)this; } else if (IsEqualIID(riid, IID_IDispatch)) { *ppvObj = (IADsPrintJob *)this; } else if (IsEqualIID(riid, IID_ISupportErrorInfo)) { *ppvObj = (ISupportErrorInfo FAR *)this; } else if (IsEqualIID(riid, IID_IADs)) { *ppvObj = (IADsPrintJob FAR *) this; } else if (IsEqualIID(riid, IID_IADsPropertyList)) { *ppvObj = (IADsPropertyList FAR *) this; } else if (IsEqualIID(riid, IID_IADsPrintJob)) { *ppvObj = (IADsPrintJob FAR *) this; } else if (IsEqualIID(riid, IID_IADsPrintJobOperations)) { *ppvObj = (IADsPrintJobOperations FAR *) this; } else if( (_pDispatch != NULL) && IsEqualIID(riid, IID_IADsExtension) ) { *ppvObj = (IADsExtension *) this; } else if (_pExtMgr) { RRETURN( _pExtMgr->QueryInterface(riid, ppvObj)); } else { *ppvObj = NULL; RRETURN(E_NOINTERFACE); } ((LPUNKNOWN)*ppvObj)->AddRef(); RRETURN(S_OK); } /* ISupportErrorInfo method */ STDMETHODIMP CWinNTPrintJob::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsPrintJob) || IsEqualIID(riid, IID_IADsPrintJobOperations) |\ IsEqualIID(riid, IID_IADsPropertyList)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } //+----------------------------------------------------------------- // // Function: SetInfo // // Synopsis: Binds to real printer as specified in _PrinterName and attempts // to set the real printer. // // Arguments: void // // Returns: HRESULT. // // Modifies: // // History: 11/08/95 RamV Created // part of code appropriated from NetOle project //---------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintJob::SetInfo(THIS) { BOOL fStatus = FALSE; LPJOB_INFO_2 lpJobInfo2 = NULL; HRESULT hr; // // do a getinfo to refresh those properties that arent being set // hr = GetJobInfo(2, (LPBYTE*)&lpJobInfo2, _pszPrinterName, _lJobId); BAIL_IF_ERROR(hr); hr = MarshallAndSet(lpJobInfo2, _pszPrinterName, _lJobId); BAIL_IF_ERROR(hr); if(SUCCEEDED(hr)) _pPropertyCache->ClearModifiedFlags(); cleanup: if(lpJobInfo2){ FreeADsMem((LPBYTE)lpJobInfo2); } RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintJob::GetInfo(THIS_ DWORD dwApiLevel, BOOL fExplicit) { LPJOB_INFO_1 lpJobInfo1 = NULL; LPJOB_INFO_2 lpJobInfo2 = NULL; HRESULT hr = S_OK; switch (dwApiLevel) { case 1: hr = GetJobInfo(dwApiLevel, (LPBYTE*)&lpJobInfo1, _pszPrinterName, _lJobId ); BAIL_IF_ERROR(hr); hr = UnMarshallLevel1(lpJobInfo1, fExplicit ); BAIL_IF_ERROR(hr); break; case 2: hr = GetJobInfo(dwApiLevel, (LPBYTE *)&lpJobInfo2, _pszPrinterName, _lJobId ); BAIL_IF_ERROR(hr); hr = UnMarshallLevel2(lpJobInfo2, fExplicit ); BAIL_IF_ERROR(hr); break; default: hr = E_FAIL; break; } cleanup: if (lpJobInfo1) { FreeADsMem(lpJobInfo1); } if (lpJobInfo2) { FreeADsMem(lpJobInfo2); } RRETURN_EXP_IF_ERR(hr); } //+--------------------------------------------------------------------------- // // Function: GetInfo // // Synopsis: Binds to real printer as specified in _PrinterName and attempts // to get information from the real printer. // // Arguments: void // // Returns: HRESULT. // // Modifies: // // History: 11/08/95 RamV Created // part of code appropriated from NetOle project //---------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintJob::GetInfo(THIS) { RRETURN(GetInfo(2, TRUE)); } STDMETHODIMP CWinNTPrintJob::ImplicitGetInfo(THIS) { RRETURN(GetInfo(2, FALSE)); } STDMETHODIMP CWinNTPrintJob::get_Description(THIS_ BSTR FAR* retval) { GET_PROPERTY_BSTR((IADsPrintJob *)this, Description); } STDMETHODIMP CWinNTPrintJob::put_Description(THIS_ BSTR bstrDescription) { PUT_PROPERTY_BSTR((IADsPrintJob *)this, Description); } STDMETHODIMP CWinNTPrintJob::get_HostPrintQueue(THIS_ BSTR FAR* retval) { GET_PROPERTY_BSTR((IADsPrintJob *)this, HostPrintQueue); } STDMETHODIMP CWinNTPrintJob::get_User(THIS_ BSTR FAR* retval) { GET_PROPERTY_BSTR((IADsPrintJob *)this, User); } STDMETHODIMP CWinNTPrintJob::get_UserPath(THIS_ BSTR FAR* retval) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTPrintJob::put_Priority(THIS_ LONG lPriority) { PUT_PROPERTY_LONG((IADsPrintJob *)this, Priority); } STDMETHODIMP CWinNTPrintJob::get_Priority(THIS_ LONG FAR* retval) { GET_PROPERTY_LONG((IADsPrintJob *)this, Priority); } STDMETHODIMP CWinNTPrintJob::get_TimeSubmitted(THIS_ DATE FAR* retval) { GET_PROPERTY_DATE((IADsPrintJob *)this, TimeSubmitted); } STDMETHODIMP CWinNTPrintJob::get_TotalPages(THIS_ LONG FAR* retval) { GET_PROPERTY_LONG((IADsPrintJob *)this, TotalPages); } STDMETHODIMP CWinNTPrintJob::put_StartTime(THIS_ DATE daStartTime) { PUT_PROPERTY_DATE((IADsPrintJob *)this, StartTime); } STDMETHODIMP CWinNTPrintJob::get_StartTime(THIS_ DATE FAR* retval) { GET_PROPERTY_DATE((IADsPrintJob *)this, StartTime); } STDMETHODIMP CWinNTPrintJob::put_UntilTime(THIS_ DATE daUntilTime) { PUT_PROPERTY_DATE((IADsPrintJob *)this, UntilTime); } STDMETHODIMP CWinNTPrintJob::get_UntilTime(THIS_ DATE FAR* retval) { GET_PROPERTY_DATE((IADsPrintJob *)this, UntilTime); } STDMETHODIMP CWinNTPrintJob::get_Size(THIS_ LONG FAR* retval) { GET_PROPERTY_LONG((IADsPrintJob *)this, Size); } STDMETHODIMP CWinNTPrintJob::put_Notify(THIS_ BSTR bstrNotify) { PUT_PROPERTY_BSTR((IADsPrintJob *)this, Notify); } STDMETHODIMP CWinNTPrintJob::get_Notify(THIS_ BSTR FAR* retval) { GET_PROPERTY_BSTR((IADsPrintJob *)this, Notify); } STDMETHODIMP CWinNTPrintJob::put_NotifyPath(THIS_ BSTR bstrNotify) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTPrintJob::get_NotifyPath(THIS_ BSTR FAR* retval) { RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED); } STDMETHODIMP CWinNTPrintJob::put_Position(THIS_ LONG lPosition) { PUT_PROPERTY_LONG((IADsPrintJob *)this, Position); } STDMETHODIMP CWinNTPrintJob::get_Position(THIS_ LONG FAR* retval) { GET_PROPERTY_LONG((IADsPrintJob *)this, Position); } STDMETHODIMP CWinNTPrintJob::get_PagesPrinted(THIS_ LONG FAR* retval) { GET_PROPERTY_LONG((IADsPrintJob *)this, PagesPrinted); } STDMETHODIMP CWinNTPrintJob::get_TimeElapsed(THIS_ LONG FAR* retval) { GET_PROPERTY_LONG((IADsPrintJob *)this, TimeElapsed); } //+------------------------------------------------------------------------ // // Function: CWinNTPrintJob::Pause // // Synopsis: Binds to real printer as specified in _lpszPrinterName and attempts // to pause this job. // // Arguments: none // // Returns: HRESULT. // // Modifies: nothing // // History: 11-07-95 RamV Created // //--------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintJob::Pause(THIS) { BOOL fStatus = FALSE; PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE}; HANDLE hPrinter = NULL; HRESULT hr = S_OK; // // we need to open the printer with the right printer // defaults in order to perform the operations that we // have here // fStatus = OpenPrinter((LPTSTR)_pszPrinterName, &hPrinter, &PrinterDefaults ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } fStatus = SetJob (hPrinter, _lJobId, 0, NULL, JOB_CONTROL_PAUSE ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } cleanup: fStatus = ClosePrinter(hPrinter); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintJob::Resume(THIS) { BOOL fStatus = FALSE; PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE}; HANDLE hPrinter = NULL; HRESULT hr = S_OK; // // we need to open the printer with the right printer // defaults in order to perform the operations that we // have here // fStatus = OpenPrinter((LPTSTR)_pszPrinterName, &hPrinter, &PrinterDefaults ); if (!fStatus) { hr =HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } fStatus = SetJob (hPrinter, _lJobId, 0, NULL, JOB_CONTROL_RESUME ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } cleanup: fStatus = ClosePrinter(hPrinter); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintJob::Remove(THIS) { BOOL fStatus = FALSE; PRINTER_DEFAULTS PrinterDefaults = {0, 0, PRINTER_ACCESS_USE}; HANDLE hPrinter = NULL; HRESULT hr = S_OK; fStatus = OpenPrinter((LPTSTR)_pszPrinterName, &hPrinter, &PrinterDefaults ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } // // se JOB_CONTROL_DELETE instead of JOB_CONTROL_CANCEL as DELETE works // even when a print job has been restarted while CANCLE won't // fStatus = SetJob (hPrinter, _lJobId, 0, NULL, JOB_CONTROL_DELETE ); if (!fStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } cleanup: fStatus = ClosePrinter(hPrinter); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintJob::get_Status(THIS_ long FAR* retval) { HRESULT hr =S_OK; LPJOB_INFO_1 lpJobInfo1 = NULL; BOOL found; DWORD dwStatus; if(!retval){ RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER); } hr = GetJobInfo(1, (LPBYTE*)&lpJobInfo1, _pszPrinterName, _lJobId); BAIL_IF_ERROR(hr); // // instead of a conversion routine, just return the WinNT // Status code // *retval = lpJobInfo1->Status; cleanup: if(lpJobInfo1){ FreeADsMem((LPBYTE)lpJobInfo1); } RRETURN_EXP_IF_ERR(hr); }