|
|
/******************************************************************
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; }
|