/*++ Copyright (c) 1995 Microsoft Corporation Module Name: cprinter.cxx Abstract: Contains methods for PrintQueue object, GeneralInfo property set and Operation property set for the Print Queue object for the Windows NT provider Author: Ram Viswanathan (ramv) 11-09-95 Revision History: --*/ #include "winnt.hxx" #pragma hdrstop // // Class CWinNTPrintQueue Methods // DEFINE_IDispatch_ExtMgr_Implementation(CWinNTPrintQueue) DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTPrintQueue) DEFINE_IADs_TempImplementation(CWinNTPrintQueue); DEFINE_IADs_PutGetImplementation(CWinNTPrintQueue,PrintQueueClass,gdwPrinterTableSize); DEFINE_IADsPropertyList_Implementation(CWinNTPrintQueue, PrintQueueClass,gdwPrinterTableSize) CWinNTPrintQueue::CWinNTPrintQueue() { _pszPrinterName = NULL; _pDispMgr = NULL; _pExtMgr = NULL; _pPropertyCache = NULL; ENLIST_TRACKING(CWinNTPrintQueue); return; } CWinNTPrintQueue::~CWinNTPrintQueue() { delete _pExtMgr; // created last, destroyed first delete _pDispMgr; delete _pPropertyCache; if(_pszPrinterName){ FreeADsStr(_pszPrinterName); } return; } HRESULT CWinNTPrintQueue:: CreatePrintQueue( LPTSTR pszADsParent, DWORD dwParentId, LPTSTR pszDomainName, LPTSTR pszServerName, LPTSTR pszPrinterName, DWORD dwObjectState, REFIID riid, CWinNTCredentials& Credentials, LPVOID * ppvoid ) { CWinNTPrintQueue *pPrintQueue = NULL; HRESULT hr; // // Create the printer object // hr = AllocatePrintQueueObject(pszServerName, pszPrinterName, &pPrintQueue ); BAIL_ON_FAILURE(hr); ADsAssert(pPrintQueue->_pDispMgr); // // initialize the core object // hr = pPrintQueue->InitializeCoreObject(pszADsParent, pszPrinterName, PRINTER_CLASS_NAME, PRINTER_SCHEMA_NAME, CLSID_WinNTPrintQueue, dwObjectState); BAIL_ON_FAILURE(hr); pPrintQueue->_Credentials = Credentials; hr = pPrintQueue->_Credentials.RefServer(pszServerName); BAIL_ON_FAILURE(hr); // // Load ext mgr and extensions // hr = ADSILoadExtensionManager( PRINTER_CLASS_NAME, (IADsPrintQueue *) pPrintQueue, pPrintQueue->_pDispMgr, Credentials, &pPrintQueue->_pExtMgr ); BAIL_ON_FAILURE(hr); ADsAssert(pPrintQueue->_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. // if(3 == pPrintQueue->_dwNumComponents) { pPrintQueue->_CompClasses[0] = L"Domain"; pPrintQueue->_CompClasses[1] = L"Computer"; pPrintQueue->_CompClasses[2] = L"PrintQueue"; } else if(2 == pPrintQueue->_dwNumComponents) { // no workstation services pPrintQueue->_CompClasses[0] = L"Computer"; pPrintQueue->_CompClasses[1] = L"PrintQueue"; } else BAIL_ON_FAILURE(hr = UMI_E_FAIL); hr = pPrintQueue->InitUmiObject( pPrintQueue->_Credentials, PrintQueueClass, gdwPrinterTableSize, pPrintQueue->_pPropertyCache, (IUnknown *)(INonDelegatingUnknown *) pPrintQueue, pPrintQueue->_pExtMgr, IID_IUnknown, ppvoid ); BAIL_ON_FAILURE(hr); // // 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 = pPrintQueue->QueryInterface(riid, (void **)ppvoid); BAIL_ON_FAILURE(hr); pPrintQueue->Release(); RRETURN(hr); error: delete pPrintQueue; 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 CWinNTPrintQueue::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) CWinNTPrintQueue::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) CWinNTPrintQueue::Release(void) { if(_pUnkOuter != NULL) RRETURN(_pUnkOuter->Release()); RRETURN(NonDelegatingRelease()); } //---------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintQueue::NonDelegatingQueryInterface(REFIID riid, LPVOID FAR* ppvObj) { HRESULT hr = S_OK; if(!ppvObj) { RRETURN(E_POINTER); } if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IADsPrintQueue *)this; } else if (IsEqualIID(riid, IID_IDispatch)) { *ppvObj = (IADsPrintQueue *)this; } else if (IsEqualIID(riid, IID_ISupportErrorInfo)) { *ppvObj = (ISupportErrorInfo FAR *) this; } else if (IsEqualIID(riid, IID_IADsPropertyList)) { *ppvObj = (IADsPropertyList *)this; } else if (IsEqualIID(riid, IID_IADs)) { *ppvObj = (IADsPrintQueue FAR *) this; } else if (IsEqualIID(riid, IID_IADsPrintQueue)) { *ppvObj = (IADsPrintQueue FAR *) this; } else if (IsEqualIID(riid, IID_IADsPrintQueueOperations)) { *ppvObj = (IADsPrintQueueOperations 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 CWinNTPrintQueue::InterfaceSupportsErrorInfo( THIS_ REFIID riid ) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsPrintQueue) || IsEqualIID(riid, IID_IADsPrintQueueOperations) || 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 CWinNTPrintQueue::SetInfo(THIS) { BOOL fStatus = FALSE; LPPRINTER_INFO_2 lpPrinterInfo2 = NULL; BOOL fPrinterAdded = FALSE; POBJECTINFO pObjectInfo = NULL; #if (!defined(BUILD_FOR_NT40)) LPPRINTER_INFO_7 lpPrinterInfo7 = NULL; #endif HRESULT hr; if (GetObjectState() == ADS_OBJECT_UNBOUND) { hr = WinNTAddPrinter(); BAIL_IF_ERROR(hr); SetObjectState(ADS_OBJECT_BOUND); fPrinterAdded = TRUE; } // // first do a getinfo to get properties that werent changed. // hr = GetPrinterInfo(&lpPrinterInfo2, _pszPrinterName); BAIL_IF_ERROR(hr); hr = MarshallAndSet(lpPrinterInfo2); BAIL_IF_ERROR(hr); #if (!defined(BUILD_FOR_NT40)) hr = GetPrinterInfo7(&lpPrinterInfo7, _pszPrinterName); if (SUCCEEDED(hr)) { MarshallAndSet(lpPrinterInfo7); } else if(hr == HRESULT_FROM_WIN32(ERROR_INVALID_LEVEL)) // Level 7 is not supported on NT4. So, ignore this error. hr = S_OK; #endif if(SUCCEEDED(hr)) _pPropertyCache->ClearModifiedFlags(); cleanup: // // If we added a printer and hr is set, we should delete it now // as the SetInfo failed in subsequent operations. // if (FAILED(hr) && fPrinterAdded) { // // Build ObjectInfo first // BuildObjectInfo( _ADsPath, &pObjectInfo ); // // Call delete printer only if the pObjectInfo is valid // We cannot do anything in the other case. // if (pObjectInfo) { WinNTDeletePrinter(pObjectInfo); FreeObjectInfo(pObjectInfo); } } if(lpPrinterInfo2){ FreeADsMem((LPBYTE)lpPrinterInfo2); } #if (!defined(BUILD_FOR_NT40)) if (lpPrinterInfo7) { FreeADsMem((LPBYTE)lpPrinterInfo7); } #endif RRETURN_EXP_IF_ERR(hr); } //+--------------------------------------------------------------------------- // // Function: GetInfo(function overloaded: part of CoreADsObject as well // as IADs).This function here is part of IADs // // 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 CWinNTPrintQueue::GetInfo(THIS) { HRESULT hr = S_OK; #if (!defined(BUILD_FOR_NT40)) hr = GetInfo(7,TRUE); #endif hr = GetInfo(2,TRUE); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CWinNTPrintQueue::ImplicitGetInfo(THIS) { HRESULT hr = S_OK; #if (!defined(BUILD_FOR_NT40)) hr = GetInfo(7,FALSE); #endif hr = GetInfo(2,FALSE); RRETURN_EXP_IF_ERR(hr); } //+--------------------------------------------------------------------------- // // Function: GetInfo (overloaded) // // Synopsis: Calls the IADs GetInfo, because the printer object has just // one info level on which to retrieve info from. // // Arguments: dwApiLevel and fExplicit (Both Ignored) // // Returns: HRESULT. // // Modifies: // // History: 01-05-96 RamV Created //---------------------------------------------------------------------------- STDMETHODIMP CWinNTPrintQueue::GetInfo(THIS_ DWORD dwApiLevel, BOOL fExplicit) { LPPRINTER_INFO_2 lpPrinterInfo2= NULL; HRESULT hr = S_OK; #if (!defined(BUILD_FOR_NT40)) LPPRINTER_INFO_7 lpPrinterInfo7 = NULL; HRESULT hr7 = S_OK; #endif hr = GetPrinterInfo(&lpPrinterInfo2, _pszPrinterName); BAIL_IF_ERROR(hr); hr = UnMarshall(lpPrinterInfo2, fExplicit); #if (!defined(BUILD_FOR_NT40)) hr7 = GetPrinterInfo7(&lpPrinterInfo7, _pszPrinterName); if (SUCCEEDED(hr7)) { hr7 = UnMarshall7(lpPrinterInfo7, fExplicit); } #endif cleanup: if(lpPrinterInfo2) FreeADsMem((LPBYTE)lpPrinterInfo2); #if (!defined(BUILD_FOR_NT40)) if (lpPrinterInfo7) { FreeADsMem((LPBYTE)lpPrinterInfo7); } #endif RRETURN_EXP_IF_ERR(hr); } // // helper function WinNTAddPrinter // HRESULT CWinNTPrintQueue::WinNTAddPrinter(void) { HRESULT hr = S_OK; TCHAR szUncServerName[MAX_PATH]; TCHAR szServerName[MAX_PATH]; PRINTER_INFO_2 PrinterInfo2; HANDLE hPrinter = NULL; LPTSTR pszPrintDevices = NULL; LPTSTR pszModel = NULL; LPTSTR pszDatatype = NULL; LPTSTR pszPrintProcessor = NULL; LPTSTR pszPrinterName = NULL; DWORD dwSyntaxId = 0; DWORD dwNumValues = 0; PNTOBJECT pNTObject = NULL; memset(&PrinterInfo2, 0, sizeof(PRINTER_INFO_2)); hr = GetDelimitedStringPropertyFromCache( _pPropertyCache, TEXT("PrintDevices"), &pszPrintDevices ); if(SUCCEEDED(hr)){ PrinterInfo2.pPortName = pszPrintDevices; } hr = GetLPTSTRPropertyFromCache( _pPropertyCache, TEXT("Model"), &pszModel ); if(SUCCEEDED(hr)){ PrinterInfo2.pDriverName = pszModel; } hr = GetLPTSTRPropertyFromCache( _pPropertyCache, TEXT("PrinterName"), &pszPrinterName ); if(SUCCEEDED(hr)){ PrinterInfo2.pPrinterName = pszPrinterName; } else { PrinterInfo2.pPrinterName = (LPTSTR) _Name; } hr = GetLPTSTRPropertyFromCache( _pPropertyCache, TEXT("PrintProcessor"), &pszPrintProcessor ); if(SUCCEEDED(hr)){ PrinterInfo2.pPrintProcessor = pszPrintProcessor; } hr = GetLPTSTRPropertyFromCache( _pPropertyCache, TEXT("Datatype"), &pszDatatype ); if(SUCCEEDED(hr)){ PrinterInfo2.pDatatype = pszDatatype; } hr = GetServerFromPath(_ADsPath, szServerName); BAIL_IF_ERROR(hr); hr = MakeUncName(szServerName, szUncServerName); BAIL_IF_ERROR(hr); PrinterInfo2.pServerName = szServerName; PrinterInfo2.pShareName = (LPTSTR)_Name; PrinterInfo2.pComment = NULL; PrinterInfo2.pLocation = NULL; PrinterInfo2.pDevMode = NULL; PrinterInfo2.pSepFile = NULL; PrinterInfo2.pParameters = NULL; PrinterInfo2.pSecurityDescriptor = NULL; PrinterInfo2.Attributes = PRINTER_ATTRIBUTE_SHARED; PrinterInfo2.Priority = 0; PrinterInfo2.DefaultPriority = 0; PrinterInfo2.StartTime = 0; PrinterInfo2.UntilTime = 0; PrinterInfo2.Status = 0; PrinterInfo2.cJobs= 0; PrinterInfo2.AveragePPM = 0; // // set properties on printer // hPrinter = AddPrinter(szUncServerName, 2, (LPBYTE)&PrinterInfo2); if(hPrinter == NULL){ hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } cleanup: if(pszPrintDevices){ FreeADsStr(pszPrintDevices); } if(pszModel){ FreeADsStr(pszModel); } if(pszPrintProcessor){ FreeADsStr(pszPrintProcessor); } if(pszDatatype){ FreeADsStr(pszDatatype); } if (pszPrinterName) { FreeADsStr(pszPrinterName); } if (hPrinter) { ClosePrinter(hPrinter); } RRETURN(hr); } HRESULT CWinNTPrintQueue::AllocatePrintQueueObject( LPTSTR pszServerName, LPTSTR pszPrinterName, CWinNTPrintQueue ** ppPrintQueue ) { CWinNTPrintQueue FAR * pPrintQueue = NULL; HRESULT hr = S_OK; TCHAR szUncServerName[MAX_PATH]; TCHAR szUncPrinterName [MAX_PATH]; CAggregatorDispMgr FAR * pDispMgr = NULL; CPropertyCache FAR * pPropertyCache = NULL; pPrintQueue = new CWinNTPrintQueue(); if (pPrintQueue == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); // // Build the UNC form of printer name from the supplied information // if( (wcslen(pszServerName) + 3) > MAX_PATH) { BAIL_ON_FAILURE(hr = E_INVALIDARG); } hr = MakeUncName(pszServerName, szUncServerName); BAIL_ON_FAILURE(hr); if( (wcslen(szUncServerName) + wcslen(pszPrinterName) + 2) > MAX_PATH) { BAIL_ON_FAILURE(hr = E_INVALIDARG); } wcscpy(szUncPrinterName, szUncServerName); wcscat(szUncPrinterName, TEXT("\\")); wcscat(szUncPrinterName, pszPrinterName); pPrintQueue->_pszPrinterName = AllocADsStr(szUncPrinterName); if(!(pPrintQueue->_pszPrinterName)){ hr = E_OUTOFMEMORY; goto error; } pDispMgr = new CAggregatorDispMgr; if (pDispMgr == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry(pDispMgr, LIBID_ADs, IID_IADsPrintQueue, (IADsPrintQueue *)pPrintQueue, DISPID_REGULAR); hr = LoadTypeInfoEntry(pDispMgr, LIBID_ADs, IID_IADsPrintQueueOperations, (IADsPrintQueueOperations *)pPrintQueue, DISPID_REGULAR); BAIL_ON_FAILURE(hr); hr = LoadTypeInfoEntry(pDispMgr, LIBID_ADs, IID_IADsPropertyList, (IADsPropertyList *)pPrintQueue, DISPID_VALUE); BAIL_ON_FAILURE(hr); hr = CPropertyCache::createpropertycache( PrintQueueClass, gdwPrinterTableSize, (CCoreADsObject *)pPrintQueue, &pPropertyCache ); BAIL_ON_FAILURE(hr); pDispMgr->RegisterPropertyCache( pPropertyCache ); pPrintQueue->_pPropertyCache = pPropertyCache; pPrintQueue->_pDispMgr = pDispMgr; *ppPrintQueue = pPrintQueue; RRETURN(hr); error: delete pPropertyCache; delete pDispMgr; delete pPrintQueue; RRETURN(hr); }