Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

816 lines
19 KiB

/*++
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);
}
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);
}
MakeUncName(pszServerName,
szUncServerName);
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);
}