1387 lines
40 KiB
C++
1387 lines
40 KiB
C++
|
/******************************************************************
|
||
|
Printer.CPP -- WMI provider class implementation
|
||
|
|
||
|
Generated by Microsoft WMI Code Generation Engine
|
||
|
|
||
|
TO DO: - See individual function headers
|
||
|
- When linking, make sure you link to framedyd.lib &
|
||
|
msvcrtd.lib (debug) or framedyn.lib & msvcrt.lib (retail).
|
||
|
|
||
|
Description:
|
||
|
|
||
|
|
||
|
|
||
|
******************************************************************/
|
||
|
|
||
|
#include "pchealth.h"
|
||
|
#include "Printer.h"
|
||
|
#include "exdisp.h"
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// tracing stuff
|
||
|
|
||
|
#ifdef THIS_FILE
|
||
|
#undef THIS_FILE
|
||
|
#endif
|
||
|
static char __szTraceSourceFile[] = __FILE__;
|
||
|
#define THIS_FILE __szTraceSourceFile
|
||
|
#define TRACE_ID DCID_PRINTERDRIVER
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// initialization
|
||
|
|
||
|
CPrinter MyPrinterSet(PROVIDER_NAME_PRINTER, PCH_NAMESPACE);
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Property names
|
||
|
|
||
|
// PCH
|
||
|
const static WCHAR *c_wszDate = L"Date";
|
||
|
const static WCHAR *c_wszDefault = L"Default";
|
||
|
const static WCHAR *c_wszFilename = L"Filename";
|
||
|
const static WCHAR *c_wszManufacturer = L"Manufacturer";
|
||
|
const static WCHAR *c_wszName = L"Name";
|
||
|
const static WCHAR *c_wszPath = L"Path";
|
||
|
const static WCHAR *c_wszPaused = L"Paused";
|
||
|
const static WCHAR *c_wszSize = L"Size";
|
||
|
const static WCHAR *c_wszVersion = L"Version";
|
||
|
const static WCHAR *c_wszSpooler = L"SpoolEnabled";
|
||
|
const static WCHAR *c_wszNetwork = L"Network";
|
||
|
const static WCHAR *c_wszNSTimeout = L"NSTimeout";
|
||
|
const static WCHAR *c_wszRetryTimeout = L"RetryTimeout";
|
||
|
|
||
|
// Win32
|
||
|
const static WCHAR *c_wszPortName = L"PortName";
|
||
|
const static WCHAR *c_wszFileSize = L"FileSize";
|
||
|
const static WCHAR *c_wszLastModified = L"LastModified";
|
||
|
const static WCHAR *c_wszDeviceID = L"DeviceID";
|
||
|
|
||
|
|
||
|
// method parameters
|
||
|
const static WCHAR *c_wszURL = L"strURL";
|
||
|
const static WCHAR *c_wszRetVal = L"ReturnValue";
|
||
|
const static WCHAR *c_wszEnable = L"fEnable";
|
||
|
const static WCHAR *c_wszTxTimeoutP = L"uitxTimeout";
|
||
|
const static WCHAR *c_wszDNSTimeoutP = L"uidnsTimeout";
|
||
|
|
||
|
// misc
|
||
|
const static TCHAR *c_szRegPathPrn = _T("SYSTEM\\CurrentControlSet\\Control\\Print\\Printers\\");
|
||
|
const static TCHAR *c_szTxTimeout = _T("txTimeout");
|
||
|
const static TCHAR *c_szDNSTimeout = _T("dnsTimeout");
|
||
|
|
||
|
CComBSTR g_bstrDeviceID = L"DeviceID";
|
||
|
CComBSTR g_bstrAttrib = L"Attributes";
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// utility functions
|
||
|
|
||
|
// ***************************************************************************
|
||
|
// ***** IMPORTANT NOTE *****
|
||
|
// You must free the value you get returned via ppPrnInfo via MyFree()
|
||
|
HRESULT GetPrinterInfo(LPTSTR szPrinter, LPBYTE *ppPrnInfo,
|
||
|
HANDLE *phPrinter, DWORD dwLevel)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("GetPrinterInfo");
|
||
|
|
||
|
HRESULT hr = NOERROR;
|
||
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
||
|
LPBYTE pbBuff = NULL;
|
||
|
DWORD cbRead, cbNeed;
|
||
|
BOOL fOk;
|
||
|
|
||
|
if (szPrinter == NULL)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// yay! Now we have a printer name we can call OpenPrinter with.
|
||
|
fOk = OpenPrinter(szPrinter, &hPrinter, NULL);
|
||
|
if (fOk == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Unable to open printer %ls: 0x%08x", szPrinter,
|
||
|
hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// only need to get this if the user wants it...
|
||
|
if (ppPrnInfo != NULL)
|
||
|
{
|
||
|
// GetPrinter expects a buffer larger than PRINTER_INFO_2 all by itself...
|
||
|
// So gotta figure out how big of a buffer it wants and allocate it...
|
||
|
fOk = GetPrinter(hPrinter, dwLevel, NULL, 0, &cbNeed);
|
||
|
if (fOk == FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Unable to get printer info for %ls: 0x%08x",
|
||
|
szPrinter, hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
pbBuff = (LPBYTE)MyAlloc(cbNeed);
|
||
|
if (pbBuff == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
ErrorTrace(TRACE_ID, "Out of memory allocating buffer for printer data");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
fOk = GetPrinter(hPrinter, dwLevel, pbBuff, cbNeed, &cbRead);
|
||
|
if (fOk == FALSE || cbRead > cbNeed)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Unable to get printer info for %ls: 0x%08x",
|
||
|
szPrinter, hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
*ppPrnInfo = pbBuff;
|
||
|
pbBuff = NULL;
|
||
|
}
|
||
|
|
||
|
if (phPrinter != NULL)
|
||
|
{
|
||
|
*phPrinter = hPrinter;
|
||
|
hPrinter = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
if (pbBuff != NULL)
|
||
|
MyFree(pbBuff);
|
||
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
||
|
ClosePrinter(hPrinter);
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
HRESULT FindJobError(HANDLE hPrinter, DWORD cJobs, LPTSTR szUser,
|
||
|
DWORD *pdwStatus, DWORD *pdwID)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("FindJobError");
|
||
|
|
||
|
JOB_INFO_2 *rgJobInfo = NULL;
|
||
|
HRESULT hr = NOERROR;
|
||
|
DWORD cbNeed, cbRead, cFetched, i;
|
||
|
BOOL fOk;
|
||
|
|
||
|
if (szUser == NULL || pdwStatus == NULL || pdwID == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Invalid parameters");
|
||
|
hr = E_INVALIDARG;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// EnumJobs requires a random amount of space to fill up. Find out
|
||
|
// how much it wants this time.
|
||
|
fOk = EnumJobs(hPrinter, 0, cJobs, 2, NULL, 0, &cbNeed, &cFetched);
|
||
|
if (fOk == FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "EnumJobs failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
rgJobInfo = (JOB_INFO_2 *)MyAlloc(cbNeed);
|
||
|
if (rgJobInfo == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
ErrorTrace(TRACE_ID, "Out of memory");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// actually get the data
|
||
|
fOk = EnumJobs(hPrinter, 0, cJobs, 2, (LPBYTE)rgJobInfo, cbNeed, &cbRead,
|
||
|
&cFetched);
|
||
|
if (fOk == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "EnumJobs failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// we are looking for two things:
|
||
|
|
||
|
// if the current user has job that failed
|
||
|
for(i = 0; i < cJobs; i++)
|
||
|
{
|
||
|
if (rgJobInfo[i].pUserName != NULL &&
|
||
|
_tcscmp(rgJobInfo[i].pUserName, szUser) == 0)
|
||
|
{
|
||
|
if ((rgJobInfo[i].Status & (JOB_STATUS_PAUSED |
|
||
|
JOB_STATUS_DELETING |
|
||
|
JOB_STATUS_ERROR |
|
||
|
JOB_STATUS_OFFLINE |
|
||
|
JOB_STATUS_PAPEROUT |
|
||
|
JOB_STATUS_BLOCKED_DEVQ |
|
||
|
JOB_STATUS_PAUSED |
|
||
|
JOB_STATUS_USER_INTERVENTION)) != 0)
|
||
|
{
|
||
|
*pdwID = rgJobInfo[i].JobId;
|
||
|
*pdwStatus = rgJobInfo[i].Status;
|
||
|
hr = NOERROR;
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if anyone has a job that failed
|
||
|
for(i = 0; i < cJobs; i++)
|
||
|
{
|
||
|
if ((rgJobInfo[i].Status & JOB_STATUS_PRINTING) != 0 &&
|
||
|
(rgJobInfo[i].Status & (JOB_STATUS_ERROR |
|
||
|
JOB_STATUS_OFFLINE |
|
||
|
JOB_STATUS_PAPEROUT |
|
||
|
JOB_STATUS_BLOCKED_DEVQ |
|
||
|
JOB_STATUS_USER_INTERVENTION)) != 0)
|
||
|
{
|
||
|
_tcscpy(szUser, rgJobInfo[i].pUserName);
|
||
|
*pdwID = rgJobInfo[i].JobId;
|
||
|
*pdwStatus = rgJobInfo[i].Status;
|
||
|
hr = NOERROR;
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pdwID = (DWORD)-1;
|
||
|
*pdwStatus = 0;
|
||
|
|
||
|
|
||
|
done:
|
||
|
if (rgJobInfo != NULL)
|
||
|
MyFree(rgJobInfo);
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// construction / destruction
|
||
|
|
||
|
// ***************************************************************************
|
||
|
CPrinter::CPrinter (LPCWSTR lpwszName, LPCWSTR lpwszNameSpace) :
|
||
|
Provider(lpwszName, lpwszNameSpace)
|
||
|
{
|
||
|
m_pParamOut = NULL;
|
||
|
m_pCurrent = NULL;
|
||
|
m_pParamIn = NULL;
|
||
|
m_lFlags = 0;
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
CPrinter::~CPrinter ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// internal methods
|
||
|
|
||
|
// ****************************************************************************
|
||
|
HRESULT CPrinter::GetInstanceData(IWbemClassObjectPtr pObj, CInstance *pInst)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::GetInstanceData");
|
||
|
|
||
|
IWbemClassObjectPtr pFileObj = NULL;
|
||
|
PRINTER_INFO_2 *pPrnInfo2 = NULL;
|
||
|
PRINTER_INFO_5 *pPrnInfo5 = NULL;
|
||
|
struct _stat filestat;
|
||
|
CComVariant varValue;
|
||
|
CComBSTR bstrPrinterDriverWithPath;
|
||
|
CComBSTR bstrPrinterDriver;
|
||
|
CComBSTR bstrProperty;
|
||
|
HRESULT hr = WBEM_S_NO_ERROR;
|
||
|
DWORD dwStatus, dwErr;
|
||
|
ULONG ulPrinterRetVal = 0;
|
||
|
ULONG uiReturn = 0;
|
||
|
TCHAR szDeviceID[MAX_PATH];
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
TCHAR *pchToken;
|
||
|
BOOL fDriverFound;
|
||
|
BOOL fLocal = TRUE;
|
||
|
|
||
|
// ** name
|
||
|
CopyProperty(pObj, c_wszDeviceID, pInst, c_wszName);
|
||
|
|
||
|
// ** path
|
||
|
CopyProperty(pObj, c_wszPortName, pInst, c_wszPath);
|
||
|
|
||
|
// ** spoolenabled
|
||
|
CopyProperty(pObj, c_wszSpooler, pInst, c_wszSpooler);
|
||
|
|
||
|
|
||
|
// get the attribute property from the passed in printer object. With that
|
||
|
// we can get all sorts of info (default, network / local, etc)
|
||
|
hr = pObj->Get(g_bstrAttrib, 0, &varValue, NULL, NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to get attribute property from WMI: 0x%08x",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
else if (V_VT(&varValue) != VT_I4)
|
||
|
{
|
||
|
hr = VariantChangeType(&varValue, &varValue, 0, VT_I4);
|
||
|
if (FAILED(hr))
|
||
|
ErrorTrace(TRACE_ID, "Unable to convert type: 0x%08x", hr);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DWORD dwAttribs;
|
||
|
|
||
|
dwAttribs = V_I4(&varValue);
|
||
|
|
||
|
|
||
|
// ** default
|
||
|
|
||
|
varValue = VARIANT_FALSE;
|
||
|
if ((dwAttribs & PRINTER_ATTRIBUTE_DEFAULT) != 0)
|
||
|
varValue = VARIANT_TRUE;
|
||
|
|
||
|
if (pInst->SetVariant(c_wszDefault, varValue) == FALSE)
|
||
|
ErrorTrace(TRACE_ID, "SetVariant on Default failed");
|
||
|
|
||
|
|
||
|
// ** network
|
||
|
|
||
|
varValue = VARIANT_FALSE;
|
||
|
if ((dwAttribs & PRINTER_ATTRIBUTE_NETWORK) != 0)
|
||
|
{
|
||
|
varValue = VARIANT_TRUE;
|
||
|
fLocal = FALSE;
|
||
|
}
|
||
|
|
||
|
if (pInst->SetVariant(c_wszNetwork, varValue) == FALSE)
|
||
|
ErrorTrace(TRACE_ID, "SetVariant on Network failed");
|
||
|
}
|
||
|
|
||
|
// we need the deviceID to do a whole bunch of stuff...
|
||
|
varValue.Clear();
|
||
|
hr = pObj->Get(g_bstrDeviceID, 0, &varValue, NULL, NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to get attribute property from WMI: 0x%08x",
|
||
|
hr);
|
||
|
}
|
||
|
else if (V_VT(&varValue) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&varValue, &varValue, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
ErrorTrace(TRACE_ID, "Unable to convert type: 0x%08x", hr);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// since we're going to need it a lot as a TCHAR, convert the
|
||
|
// name of the printer to one...
|
||
|
_tcscpy(szDeviceID, OLE2T(V_BSTR(&varValue)));
|
||
|
|
||
|
// ** paused
|
||
|
|
||
|
hr = GetPrinterInfo(szDeviceID, (LPBYTE *)&pPrnInfo2, NULL, 2);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
varValue.Clear();
|
||
|
varValue = VARIANT_FALSE;
|
||
|
if ((pPrnInfo2->Status & PRINTER_STATUS_PAUSED) != 0)
|
||
|
varValue = VARIANT_TRUE;
|
||
|
|
||
|
if (pInst->SetVariant(c_wszPaused, varValue) == FALSE)
|
||
|
ErrorTrace(TRACE_ID, "SetVariant on Paused failed");
|
||
|
|
||
|
MyFree(pPrnInfo2);
|
||
|
pPrnInfo2 = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ** timeout values
|
||
|
|
||
|
hr = GetPrinterInfo(szDeviceID, (LPBYTE *)&pPrnInfo5, NULL, 5);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
varValue.Clear();
|
||
|
|
||
|
V_VT(&varValue) = VT_I4;
|
||
|
|
||
|
V_I4(&varValue) = pPrnInfo5->DeviceNotSelectedTimeout;
|
||
|
if (pInst->SetVariant(c_wszNSTimeout, varValue) == FALSE)
|
||
|
ErrorTrace(TRACE_ID, "SetVariant on NSTimeout failed");
|
||
|
|
||
|
|
||
|
V_I4(&varValue) = pPrnInfo5->TransmissionRetryTimeout;
|
||
|
if (pInst->SetVariant(c_wszRetryTimeout, varValue) == FALSE)
|
||
|
ErrorTrace(TRACE_ID, "SetVariant on RetryTimeout failed");
|
||
|
|
||
|
MyFree(pPrnInfo5);
|
||
|
pPrnInfo5 = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ** filename + others
|
||
|
|
||
|
// Now call GetProfileString to get the Driver
|
||
|
varValue.Clear();
|
||
|
if (GetProfileString(_T("Devices"), szDeviceID, _T("\0"), szBuffer,
|
||
|
MAX_PATH) > 1)
|
||
|
{
|
||
|
// szBuffer contains a string of two tokens, first the driver,
|
||
|
// second the PathName
|
||
|
|
||
|
// Get the driver
|
||
|
pchToken = _tcstok(szBuffer, _T(","));
|
||
|
if(pchToken != NULL)
|
||
|
{
|
||
|
// Got the Driver Name
|
||
|
bstrPrinterDriver = pchToken;
|
||
|
varValue = pchToken;
|
||
|
|
||
|
|
||
|
// ** set the filename
|
||
|
|
||
|
if (pInst->SetVariant(c_wszFilename, varValue) == FALSE)
|
||
|
ErrorTrace(TRACE_ID, "SetVariant on FileName failed");
|
||
|
|
||
|
// in order to get the file properties, we have to construct
|
||
|
// the full path to the file
|
||
|
bstrPrinterDriver.Append(L".drv");
|
||
|
fDriverFound = getCompletePath(bstrPrinterDriver,
|
||
|
bstrPrinterDriverWithPath);
|
||
|
if (fDriverFound)
|
||
|
{
|
||
|
// GetCIMDataFile Function fetches properties of this file.
|
||
|
hr = GetCIMDataFile(bstrPrinterDriverWithPath, &pFileObj);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// ** version
|
||
|
|
||
|
CopyProperty(pFileObj, c_wszVersion,
|
||
|
pInst, c_wszVersion);
|
||
|
|
||
|
|
||
|
// ** filesize
|
||
|
|
||
|
CopyProperty(pFileObj, c_wszFileSize,
|
||
|
pInst, c_wszSize);
|
||
|
|
||
|
|
||
|
// ** date
|
||
|
|
||
|
CopyProperty(pFileObj, c_wszLastModified,
|
||
|
pInst, c_wszDate);
|
||
|
|
||
|
|
||
|
// ** manufacturer
|
||
|
|
||
|
CopyProperty(pFileObj, c_wszManufacturer,
|
||
|
pInst, c_wszManufacturer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ****************************************************************************
|
||
|
HRESULT CPrinter::GetStatus(void)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::GetStatus");
|
||
|
|
||
|
PRINTER_INFO_2 *pPrnInfo = NULL;
|
||
|
HRESULT hr = NOERROR;
|
||
|
VARIANT var;
|
||
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
||
|
DWORD dwStatus;
|
||
|
DWORD dwLocation;
|
||
|
TCHAR szPrinter[1024];
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
if (m_pCurrent == NULL || m_pParamOut == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter objects not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&var) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&var, &var, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_tcscpy(szPrinter, OLE2T(V_BSTR(&var)));
|
||
|
|
||
|
// get the printer info structure
|
||
|
hr = GetPrinterInfo(szPrinter, (LPBYTE *)&pPrnInfo, &hPrinter, 2);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
dwStatus = pPrnInfo->Status;
|
||
|
|
||
|
// if the status is not in the error state, then we need to look at the
|
||
|
// list of print jobs available
|
||
|
if (dwStatus == 0)
|
||
|
{
|
||
|
DWORD dwJobID;
|
||
|
DWORD cbUser;
|
||
|
TCHAR szUser[512];
|
||
|
|
||
|
cbUser = 512;
|
||
|
GetUserName(szUser, &cbUser);
|
||
|
hr = FindJobError(hPrinter, pPrnInfo->cJobs, szUser, &dwStatus,
|
||
|
&dwJobID);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
VariantClear(&var);
|
||
|
V_VT(&var) = VT_I4;
|
||
|
V_I4(&var) = dwStatus;
|
||
|
|
||
|
if (m_pParamOut->SetVariant(c_wszRetVal, var) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to set return val object");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
VariantClear(&var);
|
||
|
if (pPrnInfo != NULL)
|
||
|
MyFree(pPrnInfo);
|
||
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
||
|
ClosePrinter(hPrinter);
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ****************************************************************************
|
||
|
HRESULT CPrinter::RemovePause(void)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::RemovePause");
|
||
|
|
||
|
PRINTER_INFO_2 *pPrnInfo = NULL;
|
||
|
HRESULT hr = NOERROR;
|
||
|
VARIANT var;
|
||
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
||
|
BOOL fOk;
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
if (m_pCurrent == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter object not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&var) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&var, &var, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = GetPrinterInfo(OLE2T(V_BSTR(&var)), (LPBYTE *)&pPrnInfo, &hPrinter,
|
||
|
2);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
if (pPrnInfo->Status == PRINTER_STATUS_PAUSED)
|
||
|
{
|
||
|
fOk = SetPrinter(hPrinter, 0, NULL, PRINTER_CONTROL_RESUME);
|
||
|
if (fOk == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "SetPrinter failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
VariantClear(&var);
|
||
|
if (pPrnInfo != NULL)
|
||
|
MyFree(pPrnInfo);
|
||
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
||
|
ClosePrinter(hPrinter);
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ****************************************************************************
|
||
|
HRESULT CPrinter::PrinterProperties(void)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::PrinterProperties");
|
||
|
|
||
|
PRINTER_INFO_2 *pPrnInfo = NULL;
|
||
|
LPDEVMODE pDevMode = NULL;
|
||
|
HRESULT hr = NOERROR;
|
||
|
VARIANT var;
|
||
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
||
|
DWORD cbDevMode;
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
if (m_pCurrent == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter object not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&var) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&var, &var, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = GetPrinterInfo(OLE2T(V_BSTR(&var)), (LPBYTE *)pPrnInfo, &hPrinter, 2);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
|
||
|
cbDevMode = DocumentProperties(NULL, hPrinter, OLE2T(V_BSTR(&var)),
|
||
|
NULL, NULL, 0);
|
||
|
pDevMode = (LPDEVMODE)MyAlloc(cbDevMode);
|
||
|
if (pDevMode == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
ErrorTrace(TRACE_ID, "Out of memory allocating DEVMODE structure");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// ok, call this for real this time...
|
||
|
if (DocumentProperties(NULL, hPrinter, OLE2T(V_BSTR(&var)),
|
||
|
pDevMode, NULL, DM_PROMPT) == IDOK)
|
||
|
{
|
||
|
// nothing to free here cuz pPrnInfo->pDevMode points into the memory blob
|
||
|
// that pPrnInfo points to...
|
||
|
pPrnInfo->pDevMode = pDevMode;
|
||
|
|
||
|
if (SetPrinter(hPrinter, 2, (LPBYTE)pPrnInfo, 0) == FALSE)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
ErrorTrace(TRACE_ID, "Unable to set new printer info.");
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
VariantClear(&var);
|
||
|
if (pPrnInfo != NULL)
|
||
|
MyFree(pPrnInfo);
|
||
|
if (pDevMode != NULL)
|
||
|
MyFree(pDevMode);
|
||
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
||
|
ClosePrinter(hPrinter);
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ****************************************************************************
|
||
|
HRESULT CPrinter::SetAsDefault(TCHAR *szOldDefault, DWORD cchOldDefault,
|
||
|
BOOL fSetOldDefault)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::SetAsDefault");
|
||
|
|
||
|
HRESULT hr = NOERROR;
|
||
|
VARIANT var;
|
||
|
DWORD dw;
|
||
|
TCHAR szPrinter[1024], szNewDefault[1024];
|
||
|
BOOL fOk;
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
if (m_pCurrent == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter object not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// See if the caller wants to know what the old default is or wants to set
|
||
|
// the old default...
|
||
|
if (szOldDefault != NULL)
|
||
|
{
|
||
|
// see if we want to set the default
|
||
|
if (fSetOldDefault)
|
||
|
{
|
||
|
fOk = WriteProfileString(_T("Windows"), _T("Device"), szOldDefault);
|
||
|
if (fOk == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Failed to write old default printer: 0x%08x",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
// can goto done here cuz we don't need to do anything else...
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// or maybe we just want to grab is and then set m_pCurrent to be the
|
||
|
// default
|
||
|
else
|
||
|
{
|
||
|
dw = GetProfileString(_T("Windows"), _T("Device"), _T("\0"),
|
||
|
szOldDefault, cchOldDefault);
|
||
|
if (dw <= 1)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Failed to fetch current default: 0x%08x",
|
||
|
hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if we're here, then we gotta set the printer pointed to by m_pCurrent as
|
||
|
// the default printer, so fetch the name of the printer we want to be the
|
||
|
// default
|
||
|
if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&var) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&var, &var, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get the printer info from win.ini
|
||
|
dw = GetProfileString(_T("Devices"), OLE2T(V_BSTR(&var)), _T("\0"),
|
||
|
szPrinter, sizeof(szPrinter) / sizeof(TCHAR));
|
||
|
if (dw <= 1)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Failed to fetch current default: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// build a string & slam it back into win.ini
|
||
|
wsprintf(szNewDefault, "%s,%s", OLE2T(V_BSTR(&var)), szPrinter);
|
||
|
fOk = WriteProfileString(_T("Windows"), _T("Device"), szNewDefault);
|
||
|
if (fOk == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Failed to write new default printer: 0x%08x",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
// got to notify everyone in existance (well, all the top level windows
|
||
|
// anyway) that we changed the default printer...
|
||
|
SendMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0L,
|
||
|
(LPARAM)(LPCTSTR)_T("windows"), SMTO_NORMAL, 1000,
|
||
|
NULL);
|
||
|
|
||
|
done:
|
||
|
VariantClear(&var);
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ****************************************************************************
|
||
|
// *** NOTE: this method doesn't work on WinNT cuz WinMgmt runs as a service
|
||
|
// which has different printer settings / permissions than the user
|
||
|
// account
|
||
|
HRESULT CPrinter::TestPrinter(void)
|
||
|
{
|
||
|
TraceFunctEnter("CPrinter::TestPrinter");
|
||
|
|
||
|
IWebBrowser2 *pwb = NULL;
|
||
|
READYSTATE rs;
|
||
|
VARIANT varFlags, varOpt, varURL;
|
||
|
HRESULT hr = NOERROR;
|
||
|
CLSID clsid;
|
||
|
DWORD dwStart;
|
||
|
TCHAR szDefault[1024];
|
||
|
|
||
|
VariantInit(&varFlags);
|
||
|
VariantInit(&varURL);
|
||
|
VariantInit(&varOpt);
|
||
|
|
||
|
if (m_pParamIn == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter object not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (m_pParamIn->GetVariant(c_wszURL, varURL) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "strURL parameter not present.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
hr = VariantChangeType(&varURL, &varURL, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "unable to convert strURL to string");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// the URL should be at least 4 characters long in order for it to be a
|
||
|
// valid file path. Need 3 characters for drive path & at least 1 for
|
||
|
// the filename (as in 'd:\a')
|
||
|
if (SysStringLen(V_BSTR(&varURL)) < 4)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "strURL parameter < 4 characters.");
|
||
|
hr = E_INVALIDARG;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// we obviously need a web browser object, so make one
|
||
|
hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
|
||
|
IID_IWebBrowser2, (LPVOID *)&pwb);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to CoCreate web browser control: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// load the URL
|
||
|
V_VT(&varFlags) = VT_I4;
|
||
|
V_I4(&varFlags) = navNoHistory;
|
||
|
V_VT(&varOpt) = VT_ERROR;
|
||
|
V_ERROR(&varOpt) = DISP_E_PARAMNOTFOUND;
|
||
|
hr = pwb->Navigate2(&varURL, &varOpt, &varOpt, &varOpt, &varOpt);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to Navigate to URL '%ls': 0x%08x",
|
||
|
V_BSTR(&varURL), hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// wait for a maximum of 5 minutes for this URL to come in...
|
||
|
for(dwStart = GetTickCount(); GetTickCount() - dwStart <= 300000;)
|
||
|
{
|
||
|
hr = pwb->get_ReadyState(&rs);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to get web browser state: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (rs == READYSTATE_COMPLETE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// make sure we didn't timeout...
|
||
|
if (rs != READYSTATE_COMPLETE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Timeout waiting for browser to load URL");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// since we aren't prompting the user, we need to temporarily set the
|
||
|
// default printer to be the one we want to test
|
||
|
hr = this->SetAsDefault(szDefault, sizeof(szDefault) / sizeof(TCHAR), FALSE);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
// do the print
|
||
|
hr = pwb->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, &varOpt, &varOpt);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to print: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// revert back to the original printer
|
||
|
hr = this->SetAsDefault(szDefault, sizeof(szDefault) / sizeof(TCHAR), TRUE);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
done:
|
||
|
VariantClear(&varURL);
|
||
|
if (pwb != NULL)
|
||
|
pwb->Release();
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::EnableSpooler(void)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::EnableSpooler");
|
||
|
|
||
|
PRINTER_INFO_2 *pPrnInfo = NULL;
|
||
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
||
|
VARIANT varEnable, varName;
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
VariantInit(&varEnable);
|
||
|
VariantInit(&varName);
|
||
|
|
||
|
// get the parameter
|
||
|
if (m_pParamIn == NULL || m_pCurrent == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter object not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (m_pParamIn->GetVariant(c_wszEnable, varEnable) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "strURL parameter not present.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&varEnable) != VT_BOOL)
|
||
|
{
|
||
|
hr = VariantChangeType(&varEnable, &varEnable, 0, VT_BOOL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "unable to convert fEnable to bool: 0x%08x",
|
||
|
hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_pCurrent->GetVariant(c_wszName, varName) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&varName) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&varName, &varName, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = GetPrinterInfo(OLE2T(V_BSTR(&varName)), (LPBYTE *)&pPrnInfo,
|
||
|
&hPrinter, 2);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
if (V_BOOL(&varEnable) == VARIANT_FALSE)
|
||
|
pPrnInfo->Attributes &= ~PRINTER_ATTRIBUTE_DIRECT;
|
||
|
else
|
||
|
pPrnInfo->Attributes |= PRINTER_ATTRIBUTE_DIRECT;
|
||
|
|
||
|
if (SetPrinter(hPrinter, 2, (LPBYTE)pPrnInfo, 0) == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "SetPrinter failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
VariantClear(&varName);
|
||
|
VariantClear(&varEnable);
|
||
|
if (pPrnInfo != NULL)
|
||
|
MyFree(pPrnInfo);
|
||
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
||
|
ClosePrinter(hPrinter);
|
||
|
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::SetTimeouts(void)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::SetTimeouts");
|
||
|
|
||
|
PRINTER_INFO_5 *pPrnInfo5 = NULL;
|
||
|
HRESULT hr = NOERROR;
|
||
|
VARIANT varName, varDNS, varTX;
|
||
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
VariantInit(&varName);
|
||
|
VariantInit(&varDNS);
|
||
|
VariantInit(&varTX);
|
||
|
|
||
|
// get the parameter
|
||
|
if (m_pParamIn == NULL || m_pCurrent == NULL)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Parameter object not set.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// get uiTxTimeout
|
||
|
if (m_pParamIn->GetVariant(c_wszTxTimeoutP, varTX) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "uiTxTimeout parameter not present.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&varTX) != VT_I4)
|
||
|
{
|
||
|
hr = VariantChangeType(&varTX, &varTX, 0, VT_I4);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x",
|
||
|
hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get uiDNSTimeout
|
||
|
if (m_pParamIn->GetVariant(c_wszDNSTimeoutP, varDNS) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "uiDNSTimeout parameter not present.");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&varDNS) != VT_I4)
|
||
|
{
|
||
|
hr = VariantChangeType(&varDNS, &varDNS, 0, VT_I4);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x",
|
||
|
hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get Name
|
||
|
if (m_pCurrent->GetVariant(c_wszName, varName) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&varName) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&varName, &varName, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = GetPrinterInfo(OLE2T(V_BSTR(&varName)), (LPBYTE *)&pPrnInfo5,
|
||
|
&hPrinter, 5);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
pPrnInfo5->TransmissionRetryTimeout = V_I4(&varTX);
|
||
|
pPrnInfo5->DeviceNotSelectedTimeout = V_I4(&varDNS);
|
||
|
|
||
|
if (SetPrinter(hPrinter, 5, (LPBYTE)pPrnInfo5, 0) == FALSE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
ErrorTrace(TRACE_ID, "Unable to set printer info: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
VariantClear(&varName);
|
||
|
VariantClear(&varDNS);
|
||
|
VariantClear(&varTX);
|
||
|
if (pPrnInfo5 != NULL)
|
||
|
MyFree(pPrnInfo5);
|
||
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
||
|
ClosePrinter(hPrinter);
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// exposed methods
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::EnumerateInstances(MethodContext* pMethodContext, long lFlags)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
TraceFunctEnter("CPrinter::EnumerateInstances");
|
||
|
|
||
|
IEnumWbemClassObject *pEnumInst = NULL;
|
||
|
IWbemClassObjectPtr pObj = NULL;
|
||
|
CComBSTR bstrPrinterQuery;
|
||
|
HRESULT hr = WBEM_S_NO_ERROR;
|
||
|
ULONG ulPrinterRetVal = 0;
|
||
|
|
||
|
// Execute the query to get DeviceID, PortName from the Win32_Printer class
|
||
|
bstrPrinterQuery = L"Select DeviceID, PortName, SpoolEnabled, Status, Attributes FROM win32_printer";
|
||
|
hr = ExecWQLQuery(&pEnumInst, bstrPrinterQuery);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
// Enumerate the instances from pEnumInstance
|
||
|
while(pEnumInst->Next(WBEM_INFINITE, 1, &pObj, &ulPrinterRetVal) == WBEM_S_NO_ERROR)
|
||
|
{
|
||
|
// Create a new instance of PCH_PrinterDriver Class based on the
|
||
|
// passed-in MethodContext
|
||
|
CInstancePtr pInst(CreateNewInstance(pMethodContext), FALSE);
|
||
|
|
||
|
// original code didn't really care if this failed, so neither do I...
|
||
|
hr = GetInstanceData(pObj, pInst);
|
||
|
|
||
|
// All the properties are set. Commit the instance
|
||
|
hr = pInst->Commit();
|
||
|
if(FAILED(hr))
|
||
|
ErrorTrace(TRACE_ID, "Could not commit instance: 0x%08x", hr);
|
||
|
|
||
|
// Ok, so WMI does not follow it's own docs on how GetObject
|
||
|
// works. According to them, we should release this object here. But
|
||
|
// if I try, winmgmt GPFs.
|
||
|
// pObj->Release();
|
||
|
pObj = NULL;
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
if (pEnumInst != NULL)
|
||
|
pEnumInst->Release();
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::ExecMethod (const CInstance& Instance,
|
||
|
const BSTR bstrMethodName,
|
||
|
CInstance *pInParams, CInstance *pOutParams,
|
||
|
long lFlags)
|
||
|
{
|
||
|
TraceFunctEnter("CPrinter::ExecMethod");
|
||
|
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
m_pCurrent = (CInstance *)&Instance;
|
||
|
m_pParamIn = pInParams;
|
||
|
m_pParamOut = pOutParams;
|
||
|
m_lFlags = lFlags;
|
||
|
|
||
|
if (_wcsicmp(bstrMethodName, L"SetAsDefault") == 0)
|
||
|
hr = this->SetAsDefault();
|
||
|
|
||
|
else if (_wcsicmp(bstrMethodName, L"PrinterProperties") == 0)
|
||
|
hr = this->PrinterProperties();
|
||
|
|
||
|
else if (_wcsicmp(bstrMethodName, L"RemovePause") == 0)
|
||
|
hr = this->RemovePause();
|
||
|
|
||
|
else if (_wcsicmp(bstrMethodName, L"TestPrinter") == 0)
|
||
|
hr = this->TestPrinter();
|
||
|
|
||
|
else if (_wcsicmp(bstrMethodName, L"ErrorStatus") == 0)
|
||
|
hr = this->GetStatus();
|
||
|
|
||
|
else if (_wcsicmp(bstrMethodName, L"EnableSpooler") == 0)
|
||
|
hr = this->EnableSpooler();
|
||
|
|
||
|
else if (_wcsicmp(bstrMethodName, L"SetTimeouts") == 0)
|
||
|
hr = this->SetTimeouts();
|
||
|
|
||
|
else
|
||
|
hr = WBEM_E_INVALID_METHOD;
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
done:
|
||
|
m_pCurrent = NULL;
|
||
|
m_pParamIn = NULL;
|
||
|
m_pParamOut = NULL;
|
||
|
m_lFlags = 0;
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::GetObject(CInstance* pInstance, long lFlags)
|
||
|
{
|
||
|
TraceFunctEnter("CPrinter::GetObject");
|
||
|
|
||
|
IWbemClassObjectPtr pObj = NULL;
|
||
|
CComBSTR bstrPath;
|
||
|
HRESULT hr = NOERROR;
|
||
|
VARIANT var;
|
||
|
WCHAR wszBuffer[1024], *pwszPrn, *pwszBuf;
|
||
|
DWORD i;
|
||
|
BSTR bstrPrn;
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
if (pInstance == NULL)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
// get the name of the printer
|
||
|
if (pInstance->GetVariant(c_wszName, var) == FALSE)
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "Unable to fetch printer name");
|
||
|
hr = E_FAIL;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (V_VT(&var) != VT_BSTR)
|
||
|
{
|
||
|
hr = VariantChangeType(&var, &var, 0, VT_BSTR);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WMI!! It expects me to turn a printer with a name \\server\share
|
||
|
// into \\\\server\\share. (double '\'s)
|
||
|
bstrPrn = V_BSTR(&var);
|
||
|
if ((bstrPrn[0] != L'\\' && bstrPrn[1] != L'\\') ||
|
||
|
(bstrPrn[0] == L'\\' && bstrPrn[1] == L'\\' && bstrPrn[2] == L'\\' &&
|
||
|
bstrPrn[3] == L'\\'))
|
||
|
{
|
||
|
wcscpy(wszBuffer, bstrPrn);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
// ok, here's the annoying part...
|
||
|
wcscpy(wszBuffer, L"\\\\\\\\");
|
||
|
pwszBuf = wszBuffer + 4;
|
||
|
pwszPrn = bstrPrn + 2;
|
||
|
|
||
|
// actually, we only need to scan to the first '\' cuz we've already
|
||
|
// taken care of the 1st two & this needs to fit into '\\server\share'
|
||
|
while (pwszPrn != L'\0')
|
||
|
{
|
||
|
if (*pwszPrn == L'\\')
|
||
|
{
|
||
|
*pwszBuf++ = L'\\';
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*pwszBuf++ = *pwszPrn++;
|
||
|
}
|
||
|
|
||
|
wcscpy(pwszBuf, pwszPrn);
|
||
|
}
|
||
|
|
||
|
|
||
|
// build the path to the object
|
||
|
bstrPath = L"\\\\.\\root\\cimv2:Win32_Printer.DeviceID=\"";
|
||
|
bstrPath.Append(wszBuffer);
|
||
|
bstrPath.Append("\"");
|
||
|
|
||
|
// fetch it
|
||
|
hr = GetCIMObj(bstrPath, &pObj, lFlags);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
// populate the CInstance object
|
||
|
hr = GetInstanceData(pObj, pInstance);
|
||
|
if (FAILED(hr))
|
||
|
goto done;
|
||
|
|
||
|
// All the properties are set. Commit the instance
|
||
|
hr = pInstance->Commit();
|
||
|
if(FAILED(hr))
|
||
|
ErrorTrace(TRACE_ID, "Could not commit instance: 0x%08x", hr);
|
||
|
|
||
|
done:
|
||
|
VariantClear(&var);
|
||
|
|
||
|
// Ok, so WMI does not follow it's own docs on how GetObject
|
||
|
// works. According to them, we should release this object here. But
|
||
|
// if I try, winmgmt GPFs.
|
||
|
// if (pObj != NULL)
|
||
|
// pObj->Release();
|
||
|
|
||
|
TraceFunctLeave();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::ExecQuery(MethodContext *pMethodContext,
|
||
|
CFrameworkQuery& Query, long lFlags)
|
||
|
{
|
||
|
return WBEM_E_PROVIDER_NOT_CAPABLE;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::PutInstance(const CInstance& Instance, long lFlags)
|
||
|
{
|
||
|
return WBEM_E_PROVIDER_NOT_CAPABLE;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
HRESULT CPrinter::DeleteInstance(const CInstance& Instance, long lFlags)
|
||
|
{
|
||
|
return WBEM_E_PROVIDER_NOT_CAPABLE;
|
||
|
}
|