Leaked source code of windows server 2003
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.

759 lines
18 KiB

  1. /*****************************************************************************\
  2. * MODULE: splapi.cpp
  3. *
  4. * PURPOSE: Implementation of COM interface for BidiSpooler
  5. *
  6. * Copyright (C) 2000 Microsoft Corporation
  7. *
  8. * History:
  9. *
  10. * 03/09/00 Weihai Chen (weihaic) Created
  11. *
  12. \*****************************************************************************/
  13. #include "precomp.h"
  14. #include "priv.h"
  15. TBidiSpl::TBidiSpl():
  16. m_bValid (FALSE),
  17. m_cRef (1),
  18. m_CritSec (),
  19. m_hPrinter (NULL),
  20. m_pfnSendRecvBidiData (NULL),
  21. m_pfnRouterFreeBidiResponseContainer (NULL)
  22. {
  23. HMODULE hModule = NULL;
  24. InterlockedIncrement(&g_cComponents) ;
  25. if (m_CritSec.bValid ()) {
  26. hModule = GetModuleHandle (_T ("winspool.drv"));
  27. if (hModule) {
  28. m_pfnSendRecvBidiData = (PFN_SENDRECVBIDIDATA) GetProcAddress (
  29. hModule, MAKEINTRESOURCEA (222));
  30. m_pfnRouterFreeBidiResponseContainer = (PFN_ROUTERFREEBIDIRESPONSECONTAINER) GetProcAddress (
  31. hModule, MAKEINTRESOURCEA (223));
  32. if (m_pfnSendRecvBidiData && m_pfnRouterFreeBidiResponseContainer) {
  33. m_bValid = TRUE;
  34. }
  35. }
  36. }
  37. DBGMSG(DBG_TRACE,("TBidiSpl Created\n"));
  38. }
  39. TBidiSpl::~TBidiSpl()
  40. {
  41. UnbindDevice ();
  42. InterlockedDecrement(&g_cComponents) ;
  43. DBGMSG(DBG_TRACE,("TBidiSpl Dstroy self\n"));
  44. }
  45. STDMETHODIMP
  46. TBidiSpl::QueryInterface (
  47. REFIID iid,
  48. void** ppv)
  49. {
  50. HRESULT hr = S_OK;
  51. DBGMSG(DBG_TRACE,("Enter TBidiSpl QI\n"));
  52. if (iid == IID_IUnknown) {
  53. *ppv = static_cast<IBidiSpl*>(this) ;
  54. }
  55. else if (iid == IID_IBidiSpl) {
  56. *ppv = static_cast<IBidiSpl*>(this) ;
  57. }
  58. else {
  59. *ppv = NULL ;
  60. hr = E_NOINTERFACE ;
  61. }
  62. if (*ppv) {
  63. reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
  64. }
  65. DBGMSG(DBG_TRACE,("Leave TBidiSpl QI hr=%x\n", hr));
  66. return hr ;
  67. }
  68. STDMETHODIMP_ (ULONG)
  69. TBidiSpl::AddRef ()
  70. {
  71. DBGMSG(DBG_TRACE,("Enter TBidiSpl::AddRef ref= %d\n", m_cRef));
  72. return InterlockedIncrement(&m_cRef) ;
  73. }
  74. STDMETHODIMP_ (ULONG)
  75. TBidiSpl::Release ()
  76. {
  77. DBGMSG(DBG_TRACE,("Enter TBidiSpl::Release ref= %d\n", m_cRef));
  78. if (InterlockedDecrement(&m_cRef) == 0)
  79. {
  80. delete this ;
  81. return 0 ;
  82. }
  83. return m_cRef ;
  84. }
  85. STDMETHODIMP
  86. TBidiSpl::BindDevice (
  87. IN CONST LPCWSTR pszDeviceName,
  88. IN CONST DWORD dwAccess)
  89. {
  90. HRESULT hr (E_FAIL);
  91. HANDLE hPrinter = NULL;
  92. HANDLE hOldPrinter = NULL;
  93. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, 0};
  94. BOOL bRet;
  95. if (m_bValid) {
  96. if (pszDeviceName) {
  97. if (dwAccess == BIDI_ACCESS_ADMINISTRATOR ) {
  98. PrinterDefault.DesiredAccess = PRINTER_ALL_ACCESS;
  99. }
  100. else if (dwAccess == BIDI_ACCESS_USER) {
  101. PrinterDefault.DesiredAccess = PRINTER_ACCESS_USE;
  102. }
  103. else {
  104. hr = E_INVALIDARG;
  105. }
  106. if (hr != E_INVALIDARG) {
  107. bRet = OpenPrinter ((LPWSTR)pszDeviceName, &hPrinter, &PrinterDefault);
  108. if (bRet) {
  109. TAutoCriticalSection CritSec (m_CritSec);
  110. bRet = CritSec.bValid ();
  111. if (bRet) {
  112. if (m_hPrinter != NULL) {
  113. // Opened before
  114. // Do not cache the handle, since the calling thread may
  115. // impersonate different user credentials
  116. //
  117. hOldPrinter = m_hPrinter;
  118. }
  119. m_hPrinter = hPrinter;
  120. hPrinter = NULL;
  121. hr = S_OK;
  122. }
  123. }
  124. if (hOldPrinter) {
  125. ClosePrinter (hOldPrinter);
  126. }
  127. if (hPrinter) {
  128. ClosePrinter (hPrinter);
  129. }
  130. if (FAILED (hr)) {
  131. hr = LastError2HRESULT ();
  132. }
  133. }
  134. }
  135. else
  136. hr = E_INVALIDARG;
  137. }
  138. else
  139. hr = E_HANDLE;
  140. return hr;
  141. }
  142. STDMETHODIMP
  143. TBidiSpl::UnbindDevice ()
  144. {
  145. HRESULT hr;
  146. BOOL bRet;
  147. HANDLE hPrinter = NULL;
  148. if (m_bValid) {
  149. {
  150. TAutoCriticalSection CritSec (m_CritSec);
  151. bRet = CritSec.bValid ();
  152. if (bRet) {
  153. if (hPrinter = m_hPrinter) {
  154. m_hPrinter = NULL;
  155. }
  156. else {
  157. // Nothing to unbind
  158. bRet = FALSE;
  159. SetLastError (ERROR_INVALID_HANDLE_STATE);
  160. }
  161. }
  162. }
  163. // Leave Critical Section
  164. if (hPrinter) {
  165. bRet = ClosePrinter (hPrinter);
  166. }
  167. if (bRet) {
  168. hr = S_OK;
  169. }
  170. else {
  171. hr = LastError2HRESULT();
  172. }
  173. }
  174. else
  175. hr = E_HANDLE;
  176. return hr;
  177. }
  178. STDMETHODIMP
  179. TBidiSpl::SendRecv (
  180. IN CONST LPCWSTR pszAction,
  181. IN IBidiRequest * pRequest)
  182. {
  183. IBidiRequestContainer * pIReqContainer = NULL ;
  184. HRESULT hr;
  185. hr = ValidateContext();
  186. if (FAILED (hr)) goto Failed;
  187. if (!pRequest) {
  188. hr = E_POINTER;
  189. goto Failed;
  190. }
  191. hr = ::CoCreateInstance(CLSID_BidiRequestContainer,
  192. NULL,
  193. CLSCTX_INPROC_SERVER,
  194. IID_IBidiRequestContainer,
  195. (void**)&pIReqContainer) ;
  196. if (FAILED (hr)) goto Failed;
  197. hr = pIReqContainer->AddRequest (pRequest);
  198. if (FAILED (hr)) goto Failed;
  199. hr = MultiSendRecv (pszAction, pIReqContainer);
  200. if (FAILED (hr)) goto Failed;
  201. Failed:
  202. if (pIReqContainer) {
  203. pIReqContainer->Release ();
  204. }
  205. return hr;
  206. }
  207. STDMETHODIMP
  208. TBidiSpl::MultiSendRecv (
  209. IN CONST LPCWSTR pszAction,
  210. IN IBidiRequestContainer * pRequestContainer)
  211. {
  212. DWORD dwTotal;
  213. DWORD dwRet;
  214. IBidiRequestContainer * pIReqContainer = NULL;
  215. PBIDI_RESPONSE_CONTAINER pResponse = NULL;
  216. TRequestContainer * pReqContainer = NULL;
  217. HRESULT hr;
  218. hr = ValidateContext();
  219. if (FAILED (hr)) goto Failed;
  220. if (!pRequestContainer) {
  221. hr = E_POINTER;
  222. goto Failed;
  223. }
  224. hr = pRequestContainer->QueryInterface (
  225. IID_IBidiRequestContainer,
  226. (void **) & pIReqContainer);
  227. if (FAILED (hr)) goto Failed;
  228. hr = pIReqContainer->GetRequestCount (&dwTotal);
  229. if (FAILED (hr)) goto Failed;
  230. if (dwTotal == 0 && lstrcmpi (BIDI_ACTION_ENUM_SCHEMA, pszAction)) {
  231. // There is no request in the container
  232. //
  233. hr = E_INVALIDARG;
  234. DBGMSG (DBG_INFO, ("No request in an action"));
  235. goto Failed;
  236. }
  237. hr = ComposeRequestData (pRequestContainer, &pReqContainer);
  238. if (FAILED (hr)) goto Failed;
  239. dwRet = (*m_pfnSendRecvBidiData) (m_hPrinter,
  240. pszAction,
  241. pReqContainer->GetContainerPointer (),
  242. &pResponse);
  243. if (!dwRet && pResponse) {
  244. hr = ComposeReponseData (
  245. pIReqContainer,
  246. (PBIDI_RESPONSE_CONTAINER) pResponse);
  247. (*m_pfnRouterFreeBidiResponseContainer) (pResponse);
  248. }
  249. else
  250. hr = WinError2HRESULT (dwRet);
  251. Failed:
  252. if (pReqContainer)
  253. delete pReqContainer;
  254. if (pIReqContainer)
  255. pIReqContainer ->Release ();
  256. return hr;
  257. }
  258. HRESULT
  259. TBidiSpl::ValidateContext ()
  260. {
  261. BOOL bRet;
  262. HRESULT hr;
  263. if (m_bValid) {
  264. TAutoCriticalSection CritSec (m_CritSec);
  265. bRet = CritSec.bValid ();
  266. if (bRet) {
  267. if (m_hPrinter == NULL) {
  268. // The application has not called BindDevice yet.
  269. hr = E_HANDLE;
  270. }
  271. else
  272. hr = S_OK;
  273. }
  274. else
  275. hr = LastError2HRESULT ();
  276. }
  277. else
  278. hr = E_HANDLE;
  279. return hr;
  280. }
  281. HRESULT
  282. TBidiSpl::ComposeRequestData (
  283. IN IBidiRequestContainer *pIReqContainer,
  284. IN TRequestContainer **ppReqContainer)
  285. {
  286. DWORD dwFetched;
  287. DWORD dwSize;
  288. DWORD dwTotal;
  289. DWORD dwType;
  290. DWORD i;
  291. LPWSTR pszSchema;
  292. PBYTE pData = NULL;
  293. IBidiRequestSpl * pISpl = NULL;
  294. IEnumUnknown * pEnumIunk = NULL;
  295. IUnknown * pIunk = NULL;
  296. TRequestContainer * pReqContainer = NULL;
  297. BOOL bRet;
  298. HRESULT hr;
  299. *ppReqContainer = NULL;
  300. hr = pIReqContainer->GetEnumObject (&pEnumIunk) ;
  301. if (FAILED (hr)) goto Failed;
  302. hr = pIReqContainer->GetRequestCount (&dwTotal) ;
  303. if (FAILED (hr)) goto Failed;
  304. pReqContainer = new TRequestContainer (dwTotal);
  305. *ppReqContainer = pReqContainer;
  306. if (! (pReqContainer && pReqContainer->bValid ())) {
  307. hr = LastError2HRESULT();
  308. goto Failed;
  309. }
  310. for (i = 0; i < dwTotal; i++){
  311. hr = pEnumIunk->Next (1, &pIunk, &dwFetched);
  312. if (FAILED (hr)) goto Failed;
  313. if (dwFetched != 1) {
  314. hr = E_INVALIDARG;
  315. goto Failed;
  316. }
  317. hr = pIunk->QueryInterface (IID_IBidiRequestSpl, (void **) & pISpl);
  318. if (FAILED (hr)) goto Failed;
  319. pIunk->Release ();
  320. pIunk = NULL;
  321. // Create the request
  322. hr = pISpl->GetSchema (&pszSchema);
  323. if (FAILED (hr)) goto Failed;
  324. hr = pISpl->GetInputData (&dwType, &pData, &dwSize);
  325. if (FAILED (hr)) goto Failed;
  326. bRet = pReqContainer->AddRequest (i, pszSchema, (BIDI_TYPE) dwType, pData, dwSize);
  327. if (!bRet) {
  328. hr = LastError2HRESULT();
  329. goto Failed;
  330. }
  331. pISpl->Release ();
  332. pISpl = NULL;
  333. }
  334. hr = S_OK;
  335. Failed:
  336. if (pISpl)
  337. pISpl->Release ();
  338. if (pEnumIunk)
  339. pEnumIunk->Release ();
  340. if (pIunk)
  341. pIunk->Release();
  342. return hr;
  343. }
  344. HRESULT
  345. TBidiSpl::SetData (
  346. IN IBidiRequestSpl *pISpl,
  347. IN PBIDI_RESPONSE_DATA pResponseData)
  348. {
  349. HRESULT hr;
  350. hr = pISpl->SetResult (pResponseData->dwResult);
  351. if (!SUCCEEDED (hr)) {
  352. return hr;
  353. }
  354. PBIDI_DATA pData = & (pResponseData->data);
  355. switch (pData->dwBidiType) {
  356. case BIDI_NULL:
  357. break;
  358. case BIDI_INT:
  359. hr = pISpl->AppendOutputData (pResponseData->pSchema,
  360. pData->dwBidiType,
  361. (PBYTE) & pData->u.iData,
  362. sizeof (ULONG));
  363. break;
  364. case BIDI_BOOL:
  365. hr = pISpl->AppendOutputData (pResponseData->pSchema,
  366. pData->dwBidiType,
  367. (PBYTE) & pData->u.bData,
  368. sizeof (BOOL));
  369. break;
  370. case BIDI_FLOAT:
  371. hr = pISpl->AppendOutputData (pResponseData->pSchema,
  372. pData->dwBidiType,
  373. (PBYTE) & pData->u.fData,
  374. sizeof (FLOAT));
  375. break;
  376. case BIDI_TEXT:
  377. case BIDI_ENUM:
  378. case BIDI_STRING:
  379. if (pData->u.sData)
  380. {
  381. hr = pISpl->AppendOutputData (pResponseData->pSchema,
  382. pData->dwBidiType,
  383. (PBYTE) pData->u.sData,
  384. sizeof (WCHAR) * (lstrlen (pData->u.sData) + 1));
  385. }
  386. else
  387. {
  388. hr = pISpl->AppendOutputData (pResponseData->pSchema,
  389. pData->dwBidiType,
  390. NULL,
  391. 0);
  392. }
  393. break;
  394. case BIDI_BLOB:
  395. hr = pISpl->AppendOutputData (pResponseData->pSchema,
  396. pData->dwBidiType,
  397. pData->u.biData.pData,
  398. pData->u.biData.cbBuf);
  399. break;
  400. default:
  401. hr = E_INVALIDARG;
  402. break;
  403. }
  404. return hr;
  405. }
  406. HRESULT
  407. TBidiSpl::ComposeReponseData (
  408. IN IBidiRequestContainer *pIReqContainer,
  409. IN PBIDI_RESPONSE_CONTAINER pResponse)
  410. {
  411. HRESULT hr;
  412. IEnumUnknown* pEnumIunk = NULL;
  413. hr = pIReqContainer->GetEnumObject (&pEnumIunk) ;
  414. if (SUCCEEDED (hr)) {
  415. hr = pEnumIunk->Reset ();
  416. if (SUCCEEDED (hr)) {
  417. DWORD dwReqIndex = 0;
  418. BOOL bGotInterface = FALSE;;
  419. for (DWORD i = 0; i < pResponse->Count; i++) {
  420. PBIDI_RESPONSE_DATA pResponseData = & (pResponse->aData[i]);
  421. // Locate the request
  422. if (dwReqIndex <= pResponse->aData[i].dwReqNumber) {
  423. hr = pEnumIunk->Skip (pResponse->aData[i].dwReqNumber - dwReqIndex);
  424. dwReqIndex = pResponse->aData[i].dwReqNumber;
  425. if (FAILED (hr)) {
  426. goto Failed;
  427. }
  428. bGotInterface = FALSE;
  429. }
  430. else if (dwReqIndex > pResponse->aData[i].dwReqNumber) {
  431. hr = pEnumIunk->Reset ();
  432. if (FAILED (hr)) {
  433. goto Failed;
  434. }
  435. hr = pEnumIunk->Skip (pResponse->aData[i].dwReqNumber);
  436. dwReqIndex = pResponse->aData[i].dwReqNumber;
  437. if (FAILED (hr)) {
  438. goto Failed;
  439. }
  440. bGotInterface = FALSE;
  441. }
  442. IUnknown *pIunk = NULL;
  443. if (!bGotInterface) {
  444. DWORD dwFetched;
  445. hr = pEnumIunk->Next (1, &pIunk, &dwFetched);
  446. dwReqIndex++;
  447. if (FAILED (hr)) {
  448. goto Failed;
  449. }
  450. if (dwFetched != 1) {
  451. hr = E_INVALIDARG;
  452. goto Failed;
  453. }
  454. bGotInterface = TRUE;
  455. }
  456. IBidiRequestSpl *pISpl;
  457. hr = pIunk->QueryInterface (IID_IBidiRequestSpl,
  458. (void **) & pISpl);
  459. pIunk->Release();
  460. if (SUCCEEDED (hr)) {
  461. hr = SetData (pISpl, pResponseData);
  462. pISpl->Release ();
  463. }
  464. }
  465. }
  466. }
  467. Failed:
  468. if (pEnumIunk)
  469. pEnumIunk->Release ();
  470. return hr;
  471. }
  472. TBidiSpl::TRequestContainer::TRequestContainer (
  473. DWORD dwCount):
  474. m_bValid (FALSE)
  475. {
  476. DWORD dwSize = sizeof (BIDI_REQUEST_CONTAINER) + (dwCount - 1) * sizeof (BIDI_REQUEST_DATA);
  477. m_pContainer = (PBIDI_REQUEST_CONTAINER) new BYTE [dwSize];
  478. if (m_pContainer) {
  479. ZeroMemory (m_pContainer, dwSize);
  480. m_pContainer->Version = 1;
  481. m_pContainer->Count = dwCount;
  482. m_bValid = TRUE;
  483. }
  484. }
  485. TBidiSpl::TRequestContainer::~TRequestContainer ()
  486. {
  487. if (m_pContainer) {
  488. PBIDI_DATA pBidiData;
  489. for (DWORD i = 0; i < m_pContainer->Count; i++) {
  490. pBidiData = & (m_pContainer->aData[i].data);
  491. switch (pBidiData->dwBidiType) {
  492. case BIDI_STRING:
  493. case BIDI_TEXT:
  494. case BIDI_ENUM:
  495. if (pBidiData->u.sData)
  496. CoTaskMemFree (pBidiData->u.sData);
  497. break;
  498. case BIDI_BLOB:
  499. if (pBidiData->u.biData.pData) {
  500. CoTaskMemFree (pBidiData->u.biData.pData);
  501. }
  502. break;
  503. default:
  504. break;
  505. }
  506. }
  507. delete [] m_pContainer;
  508. }
  509. }
  510. BOOL
  511. TBidiSpl::TRequestContainer::AddRequest (
  512. IN CONST DWORD dwIndex,
  513. IN CONST LPCWSTR pszSchema,
  514. IN CONST BIDI_TYPE dwDataType,
  515. IN PBYTE pData,
  516. IN CONST DWORD dwSize)
  517. {
  518. BOOL bRet (FALSE);
  519. BOOL bFreeData;
  520. if (m_pContainer) {
  521. PBIDI_DATA pBidiData;
  522. bFreeData = TRUE;
  523. m_pContainer->aData[dwIndex].dwReqNumber = dwIndex;
  524. m_pContainer->aData[dwIndex].pSchema = (LPWSTR) pszSchema;
  525. m_pContainer->aData[dwIndex].data.dwBidiType = dwDataType;
  526. pBidiData = & (m_pContainer->aData[dwIndex].data);
  527. switch (pBidiData->dwBidiType) {
  528. case BIDI_NULL:
  529. bRet = TRUE;
  530. break;
  531. case BIDI_BOOL:
  532. bRet = dwSize == BIDI_BOOL_SIZE;
  533. if(bRet) {
  534. pBidiData->u.iData = *(PBOOL)pData;
  535. }
  536. break;
  537. case BIDI_INT:
  538. bRet = dwSize == BIDI_INT_SIZE;
  539. if (bRet) {
  540. pBidiData->u.iData = *(PINT)pData;
  541. bRet = TRUE;
  542. }
  543. break;
  544. case BIDI_FLOAT:
  545. bRet = dwSize == BIDI_FLOAT_SIZE;
  546. if (bRet) {
  547. pBidiData->u.iData = *(PINT)pData;
  548. }
  549. break;
  550. case BIDI_STRING:
  551. case BIDI_TEXT:
  552. case BIDI_ENUM:
  553. pBidiData->u.sData = (LPWSTR) pData;
  554. bFreeData = FALSE;
  555. bRet = TRUE;
  556. break;
  557. case BIDI_BLOB:
  558. pBidiData->u.biData.pData = pData;
  559. pBidiData->u.biData.cbBuf = dwSize;
  560. bFreeData = FALSE;
  561. bRet = TRUE;
  562. break;
  563. default:
  564. bRet = FALSE;
  565. }
  566. if (pData && bFreeData) {
  567. CoTaskMemFree (pData);
  568. }
  569. }
  570. if (!bRet) {
  571. SetLastError (ERROR_INVALID_PARAMETER);
  572. }
  573. return bRet;
  574. }