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.

1386 lines
40 KiB

  1. /******************************************************************
  2. Printer.CPP -- WMI provider class implementation
  3. Generated by Microsoft WMI Code Generation Engine
  4. TO DO: - See individual function headers
  5. - When linking, make sure you link to framedyd.lib &
  6. msvcrtd.lib (debug) or framedyn.lib & msvcrt.lib (retail).
  7. Description:
  8. ******************************************************************/
  9. #include "pchealth.h"
  10. #include "Printer.h"
  11. #include "exdisp.h"
  12. /////////////////////////////////////////////////////////////////////////////
  13. // tracing stuff
  14. #ifdef THIS_FILE
  15. #undef THIS_FILE
  16. #endif
  17. static char __szTraceSourceFile[] = __FILE__;
  18. #define THIS_FILE __szTraceSourceFile
  19. #define TRACE_ID DCID_PRINTERDRIVER
  20. /////////////////////////////////////////////////////////////////////////////
  21. // initialization
  22. CPrinter MyPrinterSet(PROVIDER_NAME_PRINTER, PCH_NAMESPACE);
  23. /////////////////////////////////////////////////////////////////////////////
  24. // Property names
  25. // PCH
  26. const static WCHAR *c_wszDate = L"Date";
  27. const static WCHAR *c_wszDefault = L"Default";
  28. const static WCHAR *c_wszFilename = L"Filename";
  29. const static WCHAR *c_wszManufacturer = L"Manufacturer";
  30. const static WCHAR *c_wszName = L"Name";
  31. const static WCHAR *c_wszPath = L"Path";
  32. const static WCHAR *c_wszPaused = L"Paused";
  33. const static WCHAR *c_wszSize = L"Size";
  34. const static WCHAR *c_wszVersion = L"Version";
  35. const static WCHAR *c_wszSpooler = L"SpoolEnabled";
  36. const static WCHAR *c_wszNetwork = L"Network";
  37. const static WCHAR *c_wszNSTimeout = L"NSTimeout";
  38. const static WCHAR *c_wszRetryTimeout = L"RetryTimeout";
  39. // Win32
  40. const static WCHAR *c_wszPortName = L"PortName";
  41. const static WCHAR *c_wszFileSize = L"FileSize";
  42. const static WCHAR *c_wszLastModified = L"LastModified";
  43. const static WCHAR *c_wszDeviceID = L"DeviceID";
  44. // method parameters
  45. const static WCHAR *c_wszURL = L"strURL";
  46. const static WCHAR *c_wszRetVal = L"ReturnValue";
  47. const static WCHAR *c_wszEnable = L"fEnable";
  48. const static WCHAR *c_wszTxTimeoutP = L"uitxTimeout";
  49. const static WCHAR *c_wszDNSTimeoutP = L"uidnsTimeout";
  50. // misc
  51. const static TCHAR *c_szRegPathPrn = _T("SYSTEM\\CurrentControlSet\\Control\\Print\\Printers\\");
  52. const static TCHAR *c_szTxTimeout = _T("txTimeout");
  53. const static TCHAR *c_szDNSTimeout = _T("dnsTimeout");
  54. CComBSTR g_bstrDeviceID = L"DeviceID";
  55. CComBSTR g_bstrAttrib = L"Attributes";
  56. //////////////////////////////////////////////////////////////////////////////
  57. // utility functions
  58. // ***************************************************************************
  59. // ***** IMPORTANT NOTE *****
  60. // You must free the value you get returned via ppPrnInfo via MyFree()
  61. HRESULT GetPrinterInfo(LPTSTR szPrinter, LPBYTE *ppPrnInfo,
  62. HANDLE *phPrinter, DWORD dwLevel)
  63. {
  64. USES_CONVERSION;
  65. TraceFunctEnter("GetPrinterInfo");
  66. HRESULT hr = NOERROR;
  67. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  68. LPBYTE pbBuff = NULL;
  69. DWORD cbRead, cbNeed;
  70. BOOL fOk;
  71. if (szPrinter == NULL)
  72. {
  73. hr = E_INVALIDARG;
  74. goto done;
  75. }
  76. // yay! Now we have a printer name we can call OpenPrinter with.
  77. fOk = OpenPrinter(szPrinter, &hPrinter, NULL);
  78. if (fOk == FALSE)
  79. {
  80. hr = HRESULT_FROM_WIN32(GetLastError());
  81. ErrorTrace(TRACE_ID, "Unable to open printer %ls: 0x%08x", szPrinter,
  82. hr);
  83. goto done;
  84. }
  85. // only need to get this if the user wants it...
  86. if (ppPrnInfo != NULL)
  87. {
  88. // GetPrinter expects a buffer larger than PRINTER_INFO_2 all by itself...
  89. // So gotta figure out how big of a buffer it wants and allocate it...
  90. fOk = GetPrinter(hPrinter, dwLevel, NULL, 0, &cbNeed);
  91. if (fOk == FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  92. {
  93. hr = HRESULT_FROM_WIN32(GetLastError());
  94. ErrorTrace(TRACE_ID, "Unable to get printer info for %ls: 0x%08x",
  95. szPrinter, hr);
  96. goto done;
  97. }
  98. pbBuff = (LPBYTE)MyAlloc(cbNeed);
  99. if (pbBuff == NULL)
  100. {
  101. hr = E_OUTOFMEMORY;
  102. ErrorTrace(TRACE_ID, "Out of memory allocating buffer for printer data");
  103. goto done;
  104. }
  105. fOk = GetPrinter(hPrinter, dwLevel, pbBuff, cbNeed, &cbRead);
  106. if (fOk == FALSE || cbRead > cbNeed)
  107. {
  108. hr = HRESULT_FROM_WIN32(GetLastError());
  109. ErrorTrace(TRACE_ID, "Unable to get printer info for %ls: 0x%08x",
  110. szPrinter, hr);
  111. goto done;
  112. }
  113. *ppPrnInfo = pbBuff;
  114. pbBuff = NULL;
  115. }
  116. if (phPrinter != NULL)
  117. {
  118. *phPrinter = hPrinter;
  119. hPrinter = INVALID_HANDLE_VALUE;
  120. }
  121. done:
  122. if (pbBuff != NULL)
  123. MyFree(pbBuff);
  124. if (hPrinter != INVALID_HANDLE_VALUE)
  125. ClosePrinter(hPrinter);
  126. TraceFunctLeave();
  127. return hr;
  128. }
  129. // ***************************************************************************
  130. HRESULT FindJobError(HANDLE hPrinter, DWORD cJobs, LPTSTR szUser,
  131. DWORD *pdwStatus, DWORD *pdwID)
  132. {
  133. USES_CONVERSION;
  134. TraceFunctEnter("FindJobError");
  135. JOB_INFO_2 *rgJobInfo = NULL;
  136. HRESULT hr = NOERROR;
  137. DWORD cbNeed, cbRead, cFetched, i;
  138. BOOL fOk;
  139. if (szUser == NULL || pdwStatus == NULL || pdwID == NULL)
  140. {
  141. ErrorTrace(TRACE_ID, "Invalid parameters");
  142. hr = E_INVALIDARG;
  143. goto done;
  144. }
  145. // EnumJobs requires a random amount of space to fill up. Find out
  146. // how much it wants this time.
  147. fOk = EnumJobs(hPrinter, 0, cJobs, 2, NULL, 0, &cbNeed, &cFetched);
  148. if (fOk == FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  149. {
  150. hr = HRESULT_FROM_WIN32(GetLastError());
  151. ErrorTrace(TRACE_ID, "EnumJobs failed: 0x%08x", hr);
  152. goto done;
  153. }
  154. rgJobInfo = (JOB_INFO_2 *)MyAlloc(cbNeed);
  155. if (rgJobInfo == NULL)
  156. {
  157. hr = E_OUTOFMEMORY;
  158. ErrorTrace(TRACE_ID, "Out of memory");
  159. goto done;
  160. }
  161. // actually get the data
  162. fOk = EnumJobs(hPrinter, 0, cJobs, 2, (LPBYTE)rgJobInfo, cbNeed, &cbRead,
  163. &cFetched);
  164. if (fOk == FALSE)
  165. {
  166. hr = HRESULT_FROM_WIN32(GetLastError());
  167. ErrorTrace(TRACE_ID, "EnumJobs failed: 0x%08x", hr);
  168. goto done;
  169. }
  170. // we are looking for two things:
  171. // if the current user has job that failed
  172. for(i = 0; i < cJobs; i++)
  173. {
  174. if (rgJobInfo[i].pUserName != NULL &&
  175. _tcscmp(rgJobInfo[i].pUserName, szUser) == 0)
  176. {
  177. if ((rgJobInfo[i].Status & (JOB_STATUS_PAUSED |
  178. JOB_STATUS_DELETING |
  179. JOB_STATUS_ERROR |
  180. JOB_STATUS_OFFLINE |
  181. JOB_STATUS_PAPEROUT |
  182. JOB_STATUS_BLOCKED_DEVQ |
  183. JOB_STATUS_PAUSED |
  184. JOB_STATUS_USER_INTERVENTION)) != 0)
  185. {
  186. *pdwID = rgJobInfo[i].JobId;
  187. *pdwStatus = rgJobInfo[i].Status;
  188. hr = NOERROR;
  189. goto done;
  190. }
  191. }
  192. }
  193. // if anyone has a job that failed
  194. for(i = 0; i < cJobs; i++)
  195. {
  196. if ((rgJobInfo[i].Status & JOB_STATUS_PRINTING) != 0 &&
  197. (rgJobInfo[i].Status & (JOB_STATUS_ERROR |
  198. JOB_STATUS_OFFLINE |
  199. JOB_STATUS_PAPEROUT |
  200. JOB_STATUS_BLOCKED_DEVQ |
  201. JOB_STATUS_USER_INTERVENTION)) != 0)
  202. {
  203. _tcscpy(szUser, rgJobInfo[i].pUserName);
  204. *pdwID = rgJobInfo[i].JobId;
  205. *pdwStatus = rgJobInfo[i].Status;
  206. hr = NOERROR;
  207. goto done;
  208. }
  209. }
  210. *pdwID = (DWORD)-1;
  211. *pdwStatus = 0;
  212. done:
  213. if (rgJobInfo != NULL)
  214. MyFree(rgJobInfo);
  215. TraceFunctLeave();
  216. return hr;
  217. }
  218. //////////////////////////////////////////////////////////////////////////////
  219. // construction / destruction
  220. // ***************************************************************************
  221. CPrinter::CPrinter (LPCWSTR lpwszName, LPCWSTR lpwszNameSpace) :
  222. Provider(lpwszName, lpwszNameSpace)
  223. {
  224. m_pParamOut = NULL;
  225. m_pCurrent = NULL;
  226. m_pParamIn = NULL;
  227. m_lFlags = 0;
  228. }
  229. // ***************************************************************************
  230. CPrinter::~CPrinter ()
  231. {
  232. }
  233. //////////////////////////////////////////////////////////////////////////////
  234. // internal methods
  235. // ****************************************************************************
  236. HRESULT CPrinter::GetInstanceData(IWbemClassObjectPtr pObj, CInstance *pInst)
  237. {
  238. USES_CONVERSION;
  239. TraceFunctEnter("CPrinter::GetInstanceData");
  240. IWbemClassObjectPtr pFileObj = NULL;
  241. PRINTER_INFO_2 *pPrnInfo2 = NULL;
  242. PRINTER_INFO_5 *pPrnInfo5 = NULL;
  243. struct _stat filestat;
  244. CComVariant varValue;
  245. CComBSTR bstrPrinterDriverWithPath;
  246. CComBSTR bstrPrinterDriver;
  247. CComBSTR bstrProperty;
  248. HRESULT hr = WBEM_S_NO_ERROR;
  249. DWORD dwStatus, dwErr;
  250. ULONG ulPrinterRetVal = 0;
  251. ULONG uiReturn = 0;
  252. TCHAR szDeviceID[MAX_PATH];
  253. TCHAR szBuffer[MAX_PATH];
  254. TCHAR *pchToken;
  255. BOOL fDriverFound;
  256. BOOL fLocal = TRUE;
  257. // ** name
  258. CopyProperty(pObj, c_wszDeviceID, pInst, c_wszName);
  259. // ** path
  260. CopyProperty(pObj, c_wszPortName, pInst, c_wszPath);
  261. // ** spoolenabled
  262. CopyProperty(pObj, c_wszSpooler, pInst, c_wszSpooler);
  263. // get the attribute property from the passed in printer object. With that
  264. // we can get all sorts of info (default, network / local, etc)
  265. hr = pObj->Get(g_bstrAttrib, 0, &varValue, NULL, NULL);
  266. if (FAILED(hr))
  267. {
  268. ErrorTrace(TRACE_ID, "Unable to get attribute property from WMI: 0x%08x",
  269. hr);
  270. }
  271. else if (V_VT(&varValue) != VT_I4)
  272. {
  273. hr = VariantChangeType(&varValue, &varValue, 0, VT_I4);
  274. if (FAILED(hr))
  275. ErrorTrace(TRACE_ID, "Unable to convert type: 0x%08x", hr);
  276. }
  277. if (SUCCEEDED(hr))
  278. {
  279. DWORD dwAttribs;
  280. dwAttribs = V_I4(&varValue);
  281. // ** default
  282. varValue = VARIANT_FALSE;
  283. if ((dwAttribs & PRINTER_ATTRIBUTE_DEFAULT) != 0)
  284. varValue = VARIANT_TRUE;
  285. if (pInst->SetVariant(c_wszDefault, varValue) == FALSE)
  286. ErrorTrace(TRACE_ID, "SetVariant on Default failed");
  287. // ** network
  288. varValue = VARIANT_FALSE;
  289. if ((dwAttribs & PRINTER_ATTRIBUTE_NETWORK) != 0)
  290. {
  291. varValue = VARIANT_TRUE;
  292. fLocal = FALSE;
  293. }
  294. if (pInst->SetVariant(c_wszNetwork, varValue) == FALSE)
  295. ErrorTrace(TRACE_ID, "SetVariant on Network failed");
  296. }
  297. // we need the deviceID to do a whole bunch of stuff...
  298. varValue.Clear();
  299. hr = pObj->Get(g_bstrDeviceID, 0, &varValue, NULL, NULL);
  300. if (FAILED(hr))
  301. {
  302. ErrorTrace(TRACE_ID, "Unable to get attribute property from WMI: 0x%08x",
  303. hr);
  304. }
  305. else if (V_VT(&varValue) != VT_BSTR)
  306. {
  307. hr = VariantChangeType(&varValue, &varValue, 0, VT_BSTR);
  308. if (FAILED(hr))
  309. ErrorTrace(TRACE_ID, "Unable to convert type: 0x%08x", hr);
  310. }
  311. if (SUCCEEDED(hr))
  312. {
  313. // since we're going to need it a lot as a TCHAR, convert the
  314. // name of the printer to one...
  315. _tcscpy(szDeviceID, OLE2T(V_BSTR(&varValue)));
  316. // ** paused
  317. hr = GetPrinterInfo(szDeviceID, (LPBYTE *)&pPrnInfo2, NULL, 2);
  318. if (SUCCEEDED(hr))
  319. {
  320. varValue.Clear();
  321. varValue = VARIANT_FALSE;
  322. if ((pPrnInfo2->Status & PRINTER_STATUS_PAUSED) != 0)
  323. varValue = VARIANT_TRUE;
  324. if (pInst->SetVariant(c_wszPaused, varValue) == FALSE)
  325. ErrorTrace(TRACE_ID, "SetVariant on Paused failed");
  326. MyFree(pPrnInfo2);
  327. pPrnInfo2 = NULL;
  328. }
  329. // ** timeout values
  330. hr = GetPrinterInfo(szDeviceID, (LPBYTE *)&pPrnInfo5, NULL, 5);
  331. if (SUCCEEDED(hr))
  332. {
  333. varValue.Clear();
  334. V_VT(&varValue) = VT_I4;
  335. V_I4(&varValue) = pPrnInfo5->DeviceNotSelectedTimeout;
  336. if (pInst->SetVariant(c_wszNSTimeout, varValue) == FALSE)
  337. ErrorTrace(TRACE_ID, "SetVariant on NSTimeout failed");
  338. V_I4(&varValue) = pPrnInfo5->TransmissionRetryTimeout;
  339. if (pInst->SetVariant(c_wszRetryTimeout, varValue) == FALSE)
  340. ErrorTrace(TRACE_ID, "SetVariant on RetryTimeout failed");
  341. MyFree(pPrnInfo5);
  342. pPrnInfo5 = NULL;
  343. }
  344. // ** filename + others
  345. // Now call GetProfileString to get the Driver
  346. varValue.Clear();
  347. if (GetProfileString(_T("Devices"), szDeviceID, _T("\0"), szBuffer,
  348. MAX_PATH) > 1)
  349. {
  350. // szBuffer contains a string of two tokens, first the driver,
  351. // second the PathName
  352. // Get the driver
  353. pchToken = _tcstok(szBuffer, _T(","));
  354. if(pchToken != NULL)
  355. {
  356. // Got the Driver Name
  357. bstrPrinterDriver = pchToken;
  358. varValue = pchToken;
  359. // ** set the filename
  360. if (pInst->SetVariant(c_wszFilename, varValue) == FALSE)
  361. ErrorTrace(TRACE_ID, "SetVariant on FileName failed");
  362. // in order to get the file properties, we have to construct
  363. // the full path to the file
  364. bstrPrinterDriver.Append(L".drv");
  365. fDriverFound = getCompletePath(bstrPrinterDriver,
  366. bstrPrinterDriverWithPath);
  367. if (fDriverFound)
  368. {
  369. // GetCIMDataFile Function fetches properties of this file.
  370. hr = GetCIMDataFile(bstrPrinterDriverWithPath, &pFileObj);
  371. if (SUCCEEDED(hr))
  372. {
  373. // ** version
  374. CopyProperty(pFileObj, c_wszVersion,
  375. pInst, c_wszVersion);
  376. // ** filesize
  377. CopyProperty(pFileObj, c_wszFileSize,
  378. pInst, c_wszSize);
  379. // ** date
  380. CopyProperty(pFileObj, c_wszLastModified,
  381. pInst, c_wszDate);
  382. // ** manufacturer
  383. CopyProperty(pFileObj, c_wszManufacturer,
  384. pInst, c_wszManufacturer);
  385. }
  386. }
  387. }
  388. }
  389. }
  390. TraceFunctLeave();
  391. return hr;
  392. }
  393. // ****************************************************************************
  394. HRESULT CPrinter::GetStatus(void)
  395. {
  396. USES_CONVERSION;
  397. TraceFunctEnter("CPrinter::GetStatus");
  398. PRINTER_INFO_2 *pPrnInfo = NULL;
  399. HRESULT hr = NOERROR;
  400. VARIANT var;
  401. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  402. DWORD dwStatus;
  403. DWORD dwLocation;
  404. TCHAR szPrinter[1024];
  405. VariantInit(&var);
  406. if (m_pCurrent == NULL || m_pParamOut == NULL)
  407. {
  408. ErrorTrace(TRACE_ID, "Parameter objects not set.");
  409. hr = E_FAIL;
  410. goto done;
  411. }
  412. if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
  413. {
  414. ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
  415. hr = E_FAIL;
  416. goto done;
  417. }
  418. if (V_VT(&var) != VT_BSTR)
  419. {
  420. hr = VariantChangeType(&var, &var, 0, VT_BSTR);
  421. if (FAILED(hr))
  422. {
  423. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  424. goto done;
  425. }
  426. }
  427. _tcscpy(szPrinter, OLE2T(V_BSTR(&var)));
  428. // get the printer info structure
  429. hr = GetPrinterInfo(szPrinter, (LPBYTE *)&pPrnInfo, &hPrinter, 2);
  430. if (FAILED(hr))
  431. goto done;
  432. dwStatus = pPrnInfo->Status;
  433. // if the status is not in the error state, then we need to look at the
  434. // list of print jobs available
  435. if (dwStatus == 0)
  436. {
  437. DWORD dwJobID;
  438. DWORD cbUser;
  439. TCHAR szUser[512];
  440. cbUser = 512;
  441. GetUserName(szUser, &cbUser);
  442. hr = FindJobError(hPrinter, pPrnInfo->cJobs, szUser, &dwStatus,
  443. &dwJobID);
  444. if (FAILED(hr))
  445. goto done;
  446. }
  447. VariantClear(&var);
  448. V_VT(&var) = VT_I4;
  449. V_I4(&var) = dwStatus;
  450. if (m_pParamOut->SetVariant(c_wszRetVal, var) == FALSE)
  451. {
  452. ErrorTrace(TRACE_ID, "Unable to set return val object");
  453. hr = E_FAIL;
  454. goto done;
  455. }
  456. done:
  457. VariantClear(&var);
  458. if (pPrnInfo != NULL)
  459. MyFree(pPrnInfo);
  460. if (hPrinter != INVALID_HANDLE_VALUE)
  461. ClosePrinter(hPrinter);
  462. TraceFunctLeave();
  463. return hr;
  464. }
  465. // ****************************************************************************
  466. HRESULT CPrinter::RemovePause(void)
  467. {
  468. USES_CONVERSION;
  469. TraceFunctEnter("CPrinter::RemovePause");
  470. PRINTER_INFO_2 *pPrnInfo = NULL;
  471. HRESULT hr = NOERROR;
  472. VARIANT var;
  473. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  474. BOOL fOk;
  475. VariantInit(&var);
  476. if (m_pCurrent == NULL)
  477. {
  478. ErrorTrace(TRACE_ID, "Parameter object not set.");
  479. hr = E_FAIL;
  480. goto done;
  481. }
  482. if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
  483. {
  484. ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
  485. hr = E_FAIL;
  486. goto done;
  487. }
  488. if (V_VT(&var) != VT_BSTR)
  489. {
  490. hr = VariantChangeType(&var, &var, 0, VT_BSTR);
  491. if (FAILED(hr))
  492. {
  493. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  494. goto done;
  495. }
  496. }
  497. hr = GetPrinterInfo(OLE2T(V_BSTR(&var)), (LPBYTE *)&pPrnInfo, &hPrinter,
  498. 2);
  499. if (FAILED(hr))
  500. goto done;
  501. if (pPrnInfo->Status == PRINTER_STATUS_PAUSED)
  502. {
  503. fOk = SetPrinter(hPrinter, 0, NULL, PRINTER_CONTROL_RESUME);
  504. if (fOk == FALSE)
  505. {
  506. hr = HRESULT_FROM_WIN32(GetLastError());
  507. ErrorTrace(TRACE_ID, "SetPrinter failed: 0x%08x", hr);
  508. goto done;
  509. }
  510. }
  511. done:
  512. VariantClear(&var);
  513. if (pPrnInfo != NULL)
  514. MyFree(pPrnInfo);
  515. if (hPrinter != INVALID_HANDLE_VALUE)
  516. ClosePrinter(hPrinter);
  517. TraceFunctLeave();
  518. return hr;
  519. }
  520. // ****************************************************************************
  521. HRESULT CPrinter::PrinterProperties(void)
  522. {
  523. USES_CONVERSION;
  524. TraceFunctEnter("CPrinter::PrinterProperties");
  525. PRINTER_INFO_2 *pPrnInfo = NULL;
  526. LPDEVMODE pDevMode = NULL;
  527. HRESULT hr = NOERROR;
  528. VARIANT var;
  529. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  530. DWORD cbDevMode;
  531. VariantInit(&var);
  532. if (m_pCurrent == NULL)
  533. {
  534. ErrorTrace(TRACE_ID, "Parameter object not set.");
  535. hr = E_FAIL;
  536. goto done;
  537. }
  538. if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
  539. {
  540. ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
  541. hr = E_FAIL;
  542. goto done;
  543. }
  544. if (V_VT(&var) != VT_BSTR)
  545. {
  546. hr = VariantChangeType(&var, &var, 0, VT_BSTR);
  547. if (FAILED(hr))
  548. {
  549. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  550. goto done;
  551. }
  552. }
  553. hr = GetPrinterInfo(OLE2T(V_BSTR(&var)), (LPBYTE *)pPrnInfo, &hPrinter, 2);
  554. if (FAILED(hr))
  555. goto done;
  556. cbDevMode = DocumentProperties(NULL, hPrinter, OLE2T(V_BSTR(&var)),
  557. NULL, NULL, 0);
  558. pDevMode = (LPDEVMODE)MyAlloc(cbDevMode);
  559. if (pDevMode == NULL)
  560. {
  561. hr = E_OUTOFMEMORY;
  562. ErrorTrace(TRACE_ID, "Out of memory allocating DEVMODE structure");
  563. goto done;
  564. }
  565. // ok, call this for real this time...
  566. if (DocumentProperties(NULL, hPrinter, OLE2T(V_BSTR(&var)),
  567. pDevMode, NULL, DM_PROMPT) == IDOK)
  568. {
  569. // nothing to free here cuz pPrnInfo->pDevMode points into the memory blob
  570. // that pPrnInfo points to...
  571. pPrnInfo->pDevMode = pDevMode;
  572. if (SetPrinter(hPrinter, 2, (LPBYTE)pPrnInfo, 0) == FALSE)
  573. {
  574. hr = E_OUTOFMEMORY;
  575. ErrorTrace(TRACE_ID, "Unable to set new printer info.");
  576. goto done;
  577. }
  578. }
  579. done:
  580. VariantClear(&var);
  581. if (pPrnInfo != NULL)
  582. MyFree(pPrnInfo);
  583. if (pDevMode != NULL)
  584. MyFree(pDevMode);
  585. if (hPrinter != INVALID_HANDLE_VALUE)
  586. ClosePrinter(hPrinter);
  587. TraceFunctLeave();
  588. return hr;
  589. }
  590. // ****************************************************************************
  591. HRESULT CPrinter::SetAsDefault(TCHAR *szOldDefault, DWORD cchOldDefault,
  592. BOOL fSetOldDefault)
  593. {
  594. USES_CONVERSION;
  595. TraceFunctEnter("CPrinter::SetAsDefault");
  596. HRESULT hr = NOERROR;
  597. VARIANT var;
  598. DWORD dw;
  599. TCHAR szPrinter[1024], szNewDefault[1024];
  600. BOOL fOk;
  601. VariantInit(&var);
  602. if (m_pCurrent == NULL)
  603. {
  604. ErrorTrace(TRACE_ID, "Parameter object not set.");
  605. hr = E_FAIL;
  606. goto done;
  607. }
  608. // See if the caller wants to know what the old default is or wants to set
  609. // the old default...
  610. if (szOldDefault != NULL)
  611. {
  612. // see if we want to set the default
  613. if (fSetOldDefault)
  614. {
  615. fOk = WriteProfileString(_T("Windows"), _T("Device"), szOldDefault);
  616. if (fOk == FALSE)
  617. {
  618. hr = HRESULT_FROM_WIN32(GetLastError());
  619. ErrorTrace(TRACE_ID, "Failed to write old default printer: 0x%08x",
  620. hr);
  621. }
  622. // can goto done here cuz we don't need to do anything else...
  623. goto done;
  624. }
  625. // or maybe we just want to grab is and then set m_pCurrent to be the
  626. // default
  627. else
  628. {
  629. dw = GetProfileString(_T("Windows"), _T("Device"), _T("\0"),
  630. szOldDefault, cchOldDefault);
  631. if (dw <= 1)
  632. {
  633. hr = HRESULT_FROM_WIN32(GetLastError());
  634. ErrorTrace(TRACE_ID, "Failed to fetch current default: 0x%08x",
  635. hr);
  636. goto done;
  637. }
  638. }
  639. }
  640. // if we're here, then we gotta set the printer pointed to by m_pCurrent as
  641. // the default printer, so fetch the name of the printer we want to be the
  642. // default
  643. if (m_pCurrent->GetVariant(c_wszName, var) == FALSE)
  644. {
  645. ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
  646. hr = E_FAIL;
  647. goto done;
  648. }
  649. if (V_VT(&var) != VT_BSTR)
  650. {
  651. hr = VariantChangeType(&var, &var, 0, VT_BSTR);
  652. if (FAILED(hr))
  653. {
  654. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  655. goto done;
  656. }
  657. }
  658. // get the printer info from win.ini
  659. dw = GetProfileString(_T("Devices"), OLE2T(V_BSTR(&var)), _T("\0"),
  660. szPrinter, sizeof(szPrinter) / sizeof(TCHAR));
  661. if (dw <= 1)
  662. {
  663. hr = HRESULT_FROM_WIN32(GetLastError());
  664. ErrorTrace(TRACE_ID, "Failed to fetch current default: 0x%08x", hr);
  665. goto done;
  666. }
  667. // build a string & slam it back into win.ini
  668. wsprintf(szNewDefault, "%s,%s", OLE2T(V_BSTR(&var)), szPrinter);
  669. fOk = WriteProfileString(_T("Windows"), _T("Device"), szNewDefault);
  670. if (fOk == FALSE)
  671. {
  672. hr = HRESULT_FROM_WIN32(GetLastError());
  673. ErrorTrace(TRACE_ID, "Failed to write new default printer: 0x%08x",
  674. hr);
  675. }
  676. // got to notify everyone in existance (well, all the top level windows
  677. // anyway) that we changed the default printer...
  678. SendMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0L,
  679. (LPARAM)(LPCTSTR)_T("windows"), SMTO_NORMAL, 1000,
  680. NULL);
  681. done:
  682. VariantClear(&var);
  683. TraceFunctLeave();
  684. return hr;
  685. }
  686. // ****************************************************************************
  687. // *** NOTE: this method doesn't work on WinNT cuz WinMgmt runs as a service
  688. // which has different printer settings / permissions than the user
  689. // account
  690. HRESULT CPrinter::TestPrinter(void)
  691. {
  692. TraceFunctEnter("CPrinter::TestPrinter");
  693. IWebBrowser2 *pwb = NULL;
  694. READYSTATE rs;
  695. VARIANT varFlags, varOpt, varURL;
  696. HRESULT hr = NOERROR;
  697. CLSID clsid;
  698. DWORD dwStart;
  699. TCHAR szDefault[1024];
  700. VariantInit(&varFlags);
  701. VariantInit(&varURL);
  702. VariantInit(&varOpt);
  703. if (m_pParamIn == NULL)
  704. {
  705. ErrorTrace(TRACE_ID, "Parameter object not set.");
  706. hr = E_FAIL;
  707. goto done;
  708. }
  709. if (m_pParamIn->GetVariant(c_wszURL, varURL) == FALSE)
  710. {
  711. ErrorTrace(TRACE_ID, "strURL parameter not present.");
  712. hr = E_FAIL;
  713. goto done;
  714. }
  715. hr = VariantChangeType(&varURL, &varURL, 0, VT_BSTR);
  716. if (FAILED(hr))
  717. {
  718. ErrorTrace(TRACE_ID, "unable to convert strURL to string");
  719. goto done;
  720. }
  721. // the URL should be at least 4 characters long in order for it to be a
  722. // valid file path. Need 3 characters for drive path & at least 1 for
  723. // the filename (as in 'd:\a')
  724. if (SysStringLen(V_BSTR(&varURL)) < 4)
  725. {
  726. ErrorTrace(TRACE_ID, "strURL parameter < 4 characters.");
  727. hr = E_INVALIDARG;
  728. goto done;
  729. }
  730. // we obviously need a web browser object, so make one
  731. hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
  732. IID_IWebBrowser2, (LPVOID *)&pwb);
  733. if (FAILED(hr))
  734. {
  735. ErrorTrace(TRACE_ID, "Unable to CoCreate web browser control: 0x%08x", hr);
  736. goto done;
  737. }
  738. // load the URL
  739. V_VT(&varFlags) = VT_I4;
  740. V_I4(&varFlags) = navNoHistory;
  741. V_VT(&varOpt) = VT_ERROR;
  742. V_ERROR(&varOpt) = DISP_E_PARAMNOTFOUND;
  743. hr = pwb->Navigate2(&varURL, &varOpt, &varOpt, &varOpt, &varOpt);
  744. if (FAILED(hr))
  745. {
  746. ErrorTrace(TRACE_ID, "Unable to Navigate to URL '%ls': 0x%08x",
  747. V_BSTR(&varURL), hr);
  748. goto done;
  749. }
  750. // wait for a maximum of 5 minutes for this URL to come in...
  751. for(dwStart = GetTickCount(); GetTickCount() - dwStart <= 300000;)
  752. {
  753. hr = pwb->get_ReadyState(&rs);
  754. if (FAILED(hr))
  755. {
  756. ErrorTrace(TRACE_ID, "Unable to get web browser state: 0x%08x", hr);
  757. goto done;
  758. }
  759. if (rs == READYSTATE_COMPLETE)
  760. break;
  761. }
  762. // make sure we didn't timeout...
  763. if (rs != READYSTATE_COMPLETE)
  764. {
  765. ErrorTrace(TRACE_ID, "Timeout waiting for browser to load URL");
  766. hr = E_FAIL;
  767. goto done;
  768. }
  769. // since we aren't prompting the user, we need to temporarily set the
  770. // default printer to be the one we want to test
  771. hr = this->SetAsDefault(szDefault, sizeof(szDefault) / sizeof(TCHAR), FALSE);
  772. if (FAILED(hr))
  773. goto done;
  774. // do the print
  775. hr = pwb->ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, &varOpt, &varOpt);
  776. if (FAILED(hr))
  777. {
  778. ErrorTrace(TRACE_ID, "Unable to print: 0x%08x", hr);
  779. goto done;
  780. }
  781. // revert back to the original printer
  782. hr = this->SetAsDefault(szDefault, sizeof(szDefault) / sizeof(TCHAR), TRUE);
  783. if (FAILED(hr))
  784. goto done;
  785. done:
  786. VariantClear(&varURL);
  787. if (pwb != NULL)
  788. pwb->Release();
  789. TraceFunctLeave();
  790. return hr;
  791. }
  792. // *****************************************************************************
  793. HRESULT CPrinter::EnableSpooler(void)
  794. {
  795. USES_CONVERSION;
  796. TraceFunctEnter("CPrinter::EnableSpooler");
  797. PRINTER_INFO_2 *pPrnInfo = NULL;
  798. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  799. VARIANT varEnable, varName;
  800. HRESULT hr = NOERROR;
  801. VariantInit(&varEnable);
  802. VariantInit(&varName);
  803. // get the parameter
  804. if (m_pParamIn == NULL || m_pCurrent == NULL)
  805. {
  806. ErrorTrace(TRACE_ID, "Parameter object not set.");
  807. hr = E_FAIL;
  808. goto done;
  809. }
  810. if (m_pParamIn->GetVariant(c_wszEnable, varEnable) == FALSE)
  811. {
  812. ErrorTrace(TRACE_ID, "strURL parameter not present.");
  813. hr = E_FAIL;
  814. goto done;
  815. }
  816. if (V_VT(&varEnable) != VT_BOOL)
  817. {
  818. hr = VariantChangeType(&varEnable, &varEnable, 0, VT_BOOL);
  819. if (FAILED(hr))
  820. {
  821. ErrorTrace(TRACE_ID, "unable to convert fEnable to bool: 0x%08x",
  822. hr);
  823. goto done;
  824. }
  825. }
  826. if (m_pCurrent->GetVariant(c_wszName, varName) == FALSE)
  827. {
  828. ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
  829. hr = E_FAIL;
  830. goto done;
  831. }
  832. if (V_VT(&varName) != VT_BSTR)
  833. {
  834. hr = VariantChangeType(&varName, &varName, 0, VT_BSTR);
  835. if (FAILED(hr))
  836. {
  837. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  838. goto done;
  839. }
  840. }
  841. hr = GetPrinterInfo(OLE2T(V_BSTR(&varName)), (LPBYTE *)&pPrnInfo,
  842. &hPrinter, 2);
  843. if (FAILED(hr))
  844. goto done;
  845. if (V_BOOL(&varEnable) == VARIANT_FALSE)
  846. pPrnInfo->Attributes &= ~PRINTER_ATTRIBUTE_DIRECT;
  847. else
  848. pPrnInfo->Attributes |= PRINTER_ATTRIBUTE_DIRECT;
  849. if (SetPrinter(hPrinter, 2, (LPBYTE)pPrnInfo, 0) == FALSE)
  850. {
  851. hr = HRESULT_FROM_WIN32(GetLastError());
  852. ErrorTrace(TRACE_ID, "SetPrinter failed: 0x%08x", hr);
  853. goto done;
  854. }
  855. done:
  856. VariantClear(&varName);
  857. VariantClear(&varEnable);
  858. if (pPrnInfo != NULL)
  859. MyFree(pPrnInfo);
  860. if (hPrinter != INVALID_HANDLE_VALUE)
  861. ClosePrinter(hPrinter);
  862. TraceFunctLeave();
  863. return hr;
  864. }
  865. // *****************************************************************************
  866. HRESULT CPrinter::SetTimeouts(void)
  867. {
  868. USES_CONVERSION;
  869. TraceFunctEnter("CPrinter::SetTimeouts");
  870. PRINTER_INFO_5 *pPrnInfo5 = NULL;
  871. HRESULT hr = NOERROR;
  872. VARIANT varName, varDNS, varTX;
  873. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  874. VariantInit(&varName);
  875. VariantInit(&varDNS);
  876. VariantInit(&varTX);
  877. // get the parameter
  878. if (m_pParamIn == NULL || m_pCurrent == NULL)
  879. {
  880. ErrorTrace(TRACE_ID, "Parameter object not set.");
  881. hr = E_FAIL;
  882. goto done;
  883. }
  884. // get uiTxTimeout
  885. if (m_pParamIn->GetVariant(c_wszTxTimeoutP, varTX) == FALSE)
  886. {
  887. ErrorTrace(TRACE_ID, "uiTxTimeout parameter not present.");
  888. hr = E_FAIL;
  889. goto done;
  890. }
  891. if (V_VT(&varTX) != VT_I4)
  892. {
  893. hr = VariantChangeType(&varTX, &varTX, 0, VT_I4);
  894. if (FAILED(hr))
  895. {
  896. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x",
  897. hr);
  898. goto done;
  899. }
  900. }
  901. // get uiDNSTimeout
  902. if (m_pParamIn->GetVariant(c_wszDNSTimeoutP, varDNS) == FALSE)
  903. {
  904. ErrorTrace(TRACE_ID, "uiDNSTimeout parameter not present.");
  905. hr = E_FAIL;
  906. goto done;
  907. }
  908. if (V_VT(&varDNS) != VT_I4)
  909. {
  910. hr = VariantChangeType(&varDNS, &varDNS, 0, VT_I4);
  911. if (FAILED(hr))
  912. {
  913. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x",
  914. hr);
  915. goto done;
  916. }
  917. }
  918. // get Name
  919. if (m_pCurrent->GetVariant(c_wszName, varName) == FALSE)
  920. {
  921. ErrorTrace(TRACE_ID, "Unable to fetch printer name from m_pCurrent");
  922. hr = E_FAIL;
  923. goto done;
  924. }
  925. if (V_VT(&varName) != VT_BSTR)
  926. {
  927. hr = VariantChangeType(&varName, &varName, 0, VT_BSTR);
  928. if (FAILED(hr))
  929. {
  930. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  931. goto done;
  932. }
  933. }
  934. hr = GetPrinterInfo(OLE2T(V_BSTR(&varName)), (LPBYTE *)&pPrnInfo5,
  935. &hPrinter, 5);
  936. if (FAILED(hr))
  937. goto done;
  938. pPrnInfo5->TransmissionRetryTimeout = V_I4(&varTX);
  939. pPrnInfo5->DeviceNotSelectedTimeout = V_I4(&varDNS);
  940. if (SetPrinter(hPrinter, 5, (LPBYTE)pPrnInfo5, 0) == FALSE)
  941. {
  942. hr = HRESULT_FROM_WIN32(GetLastError());
  943. ErrorTrace(TRACE_ID, "Unable to set printer info: 0x%08x", hr);
  944. goto done;
  945. }
  946. done:
  947. VariantClear(&varName);
  948. VariantClear(&varDNS);
  949. VariantClear(&varTX);
  950. if (pPrnInfo5 != NULL)
  951. MyFree(pPrnInfo5);
  952. if (hPrinter != INVALID_HANDLE_VALUE)
  953. ClosePrinter(hPrinter);
  954. TraceFunctLeave();
  955. return hr;
  956. }
  957. //////////////////////////////////////////////////////////////////////////////
  958. // exposed methods
  959. // *****************************************************************************
  960. HRESULT CPrinter::EnumerateInstances(MethodContext* pMethodContext, long lFlags)
  961. {
  962. USES_CONVERSION;
  963. TraceFunctEnter("CPrinter::EnumerateInstances");
  964. IEnumWbemClassObject *pEnumInst = NULL;
  965. IWbemClassObjectPtr pObj = NULL;
  966. CComBSTR bstrPrinterQuery;
  967. HRESULT hr = WBEM_S_NO_ERROR;
  968. ULONG ulPrinterRetVal = 0;
  969. // Execute the query to get DeviceID, PortName from the Win32_Printer class
  970. bstrPrinterQuery = L"Select DeviceID, PortName, SpoolEnabled, Status, Attributes FROM win32_printer";
  971. hr = ExecWQLQuery(&pEnumInst, bstrPrinterQuery);
  972. if (FAILED(hr))
  973. goto done;
  974. // Enumerate the instances from pEnumInstance
  975. while(pEnumInst->Next(WBEM_INFINITE, 1, &pObj, &ulPrinterRetVal) == WBEM_S_NO_ERROR)
  976. {
  977. // Create a new instance of PCH_PrinterDriver Class based on the
  978. // passed-in MethodContext
  979. CInstancePtr pInst(CreateNewInstance(pMethodContext), FALSE);
  980. // original code didn't really care if this failed, so neither do I...
  981. hr = GetInstanceData(pObj, pInst);
  982. // All the properties are set. Commit the instance
  983. hr = pInst->Commit();
  984. if(FAILED(hr))
  985. ErrorTrace(TRACE_ID, "Could not commit instance: 0x%08x", hr);
  986. // Ok, so WMI does not follow it's own docs on how GetObject
  987. // works. According to them, we should release this object here. But
  988. // if I try, winmgmt GPFs.
  989. // pObj->Release();
  990. pObj = NULL;
  991. }
  992. done:
  993. if (pEnumInst != NULL)
  994. pEnumInst->Release();
  995. TraceFunctLeave();
  996. return hr;
  997. }
  998. // *****************************************************************************
  999. HRESULT CPrinter::ExecMethod (const CInstance& Instance,
  1000. const BSTR bstrMethodName,
  1001. CInstance *pInParams, CInstance *pOutParams,
  1002. long lFlags)
  1003. {
  1004. TraceFunctEnter("CPrinter::ExecMethod");
  1005. HRESULT hr = NOERROR;
  1006. m_pCurrent = (CInstance *)&Instance;
  1007. m_pParamIn = pInParams;
  1008. m_pParamOut = pOutParams;
  1009. m_lFlags = lFlags;
  1010. if (_wcsicmp(bstrMethodName, L"SetAsDefault") == 0)
  1011. hr = this->SetAsDefault();
  1012. else if (_wcsicmp(bstrMethodName, L"PrinterProperties") == 0)
  1013. hr = this->PrinterProperties();
  1014. else if (_wcsicmp(bstrMethodName, L"RemovePause") == 0)
  1015. hr = this->RemovePause();
  1016. else if (_wcsicmp(bstrMethodName, L"TestPrinter") == 0)
  1017. hr = this->TestPrinter();
  1018. else if (_wcsicmp(bstrMethodName, L"ErrorStatus") == 0)
  1019. hr = this->GetStatus();
  1020. else if (_wcsicmp(bstrMethodName, L"EnableSpooler") == 0)
  1021. hr = this->EnableSpooler();
  1022. else if (_wcsicmp(bstrMethodName, L"SetTimeouts") == 0)
  1023. hr = this->SetTimeouts();
  1024. else
  1025. hr = WBEM_E_INVALID_METHOD;
  1026. if (FAILED(hr))
  1027. goto done;
  1028. done:
  1029. m_pCurrent = NULL;
  1030. m_pParamIn = NULL;
  1031. m_pParamOut = NULL;
  1032. m_lFlags = 0;
  1033. TraceFunctLeave();
  1034. return hr;
  1035. }
  1036. // *****************************************************************************
  1037. HRESULT CPrinter::GetObject(CInstance* pInstance, long lFlags)
  1038. {
  1039. TraceFunctEnter("CPrinter::GetObject");
  1040. IWbemClassObjectPtr pObj = NULL;
  1041. CComBSTR bstrPath;
  1042. HRESULT hr = NOERROR;
  1043. VARIANT var;
  1044. WCHAR wszBuffer[1024], *pwszPrn, *pwszBuf;
  1045. DWORD i;
  1046. BSTR bstrPrn;
  1047. VariantInit(&var);
  1048. if (pInstance == NULL)
  1049. {
  1050. hr = E_INVALIDARG;
  1051. goto done;
  1052. }
  1053. // get the name of the printer
  1054. if (pInstance->GetVariant(c_wszName, var) == FALSE)
  1055. {
  1056. ErrorTrace(TRACE_ID, "Unable to fetch printer name");
  1057. hr = E_FAIL;
  1058. goto done;
  1059. }
  1060. if (V_VT(&var) != VT_BSTR)
  1061. {
  1062. hr = VariantChangeType(&var, &var, 0, VT_BSTR);
  1063. if (FAILED(hr))
  1064. {
  1065. ErrorTrace(TRACE_ID, "VariantChangeType failed: 0x%08x", hr);
  1066. goto done;
  1067. }
  1068. }
  1069. // WMI!! It expects me to turn a printer with a name \\server\share
  1070. // into \\\\server\\share. (double '\'s)
  1071. bstrPrn = V_BSTR(&var);
  1072. if ((bstrPrn[0] != L'\\' && bstrPrn[1] != L'\\') ||
  1073. (bstrPrn[0] == L'\\' && bstrPrn[1] == L'\\' && bstrPrn[2] == L'\\' &&
  1074. bstrPrn[3] == L'\\'))
  1075. {
  1076. wcscpy(wszBuffer, bstrPrn);
  1077. }
  1078. else
  1079. {
  1080. // ok, here's the annoying part...
  1081. wcscpy(wszBuffer, L"\\\\\\\\");
  1082. pwszBuf = wszBuffer + 4;
  1083. pwszPrn = bstrPrn + 2;
  1084. // actually, we only need to scan to the first '\' cuz we've already
  1085. // taken care of the 1st two & this needs to fit into '\\server\share'
  1086. while (pwszPrn != L'\0')
  1087. {
  1088. if (*pwszPrn == L'\\')
  1089. {
  1090. *pwszBuf++ = L'\\';
  1091. break;
  1092. }
  1093. *pwszBuf++ = *pwszPrn++;
  1094. }
  1095. wcscpy(pwszBuf, pwszPrn);
  1096. }
  1097. // build the path to the object
  1098. bstrPath = L"\\\\.\\root\\cimv2:Win32_Printer.DeviceID=\"";
  1099. bstrPath.Append(wszBuffer);
  1100. bstrPath.Append("\"");
  1101. // fetch it
  1102. hr = GetCIMObj(bstrPath, &pObj, lFlags);
  1103. if (FAILED(hr))
  1104. goto done;
  1105. // populate the CInstance object
  1106. hr = GetInstanceData(pObj, pInstance);
  1107. if (FAILED(hr))
  1108. goto done;
  1109. // All the properties are set. Commit the instance
  1110. hr = pInstance->Commit();
  1111. if(FAILED(hr))
  1112. ErrorTrace(TRACE_ID, "Could not commit instance: 0x%08x", hr);
  1113. done:
  1114. VariantClear(&var);
  1115. // Ok, so WMI does not follow it's own docs on how GetObject
  1116. // works. According to them, we should release this object here. But
  1117. // if I try, winmgmt GPFs.
  1118. // if (pObj != NULL)
  1119. // pObj->Release();
  1120. TraceFunctLeave();
  1121. return hr;
  1122. }
  1123. // *****************************************************************************
  1124. HRESULT CPrinter::ExecQuery(MethodContext *pMethodContext,
  1125. CFrameworkQuery& Query, long lFlags)
  1126. {
  1127. return WBEM_E_PROVIDER_NOT_CAPABLE;
  1128. }
  1129. // *****************************************************************************
  1130. HRESULT CPrinter::PutInstance(const CInstance& Instance, long lFlags)
  1131. {
  1132. return WBEM_E_PROVIDER_NOT_CAPABLE;
  1133. }
  1134. // *****************************************************************************
  1135. HRESULT CPrinter::DeleteInstance(const CInstance& Instance, long lFlags)
  1136. {
  1137. return WBEM_E_PROVIDER_NOT_CAPABLE;
  1138. }