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.

616 lines
15 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. CPrint.cpp
  5. Abstract:
  6. Class that wraps the multi-topic printing process
  7. Revision History:
  8. Davide Massarenti (Dmassare) 05/07/2000
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. ////////////////////////////////////////////////////////////////////////////////
  13. static const DWORD c_MaxWait = 30000; // Max time to wait for temp file to change, before aborting.
  14. ////////////////////////////////////////////////////////////////////////////////
  15. static DWORD WaitMultipleObjectsWithMessageLoop( HANDLE* rgEvents, DWORD dwNum )
  16. {
  17. DWORD dwRet;
  18. MSG msg;
  19. while(1)
  20. {
  21. dwRet = ::MsgWaitForMultipleObjects( dwNum, rgEvents, FALSE, INFINITE, QS_ALLINPUT );
  22. if(/*dwRet >= WAIT_OBJECT_0 &&*/
  23. dwRet < WAIT_OBJECT_0 + dwNum)
  24. {
  25. return dwRet - WAIT_OBJECT_0; // An event was signaled.
  26. }
  27. if(dwRet >= WAIT_ABANDONED_0 &&
  28. dwRet < WAIT_ABANDONED_0 + dwNum )
  29. {
  30. return dwRet - WAIT_ABANDONED_0; // An event was abandoned.
  31. }
  32. if(dwRet != WAIT_OBJECT_0 + dwNum)
  33. {
  34. return -1;
  35. }
  36. // There is one or more window message available. Dispatch them
  37. while(PeekMessage( &msg, NULL, NULL, NULL, PM_REMOVE ))
  38. {
  39. TranslateMessage( &msg );
  40. DispatchMessage ( &msg );
  41. dwRet = ::WaitForMultipleObjects( dwNum, rgEvents, FALSE, 0 );
  42. if(/*dwRet >= WAIT_OBJECT_0 &&*/
  43. dwRet < WAIT_OBJECT_0 + dwNum)
  44. {
  45. return dwRet - WAIT_OBJECT_0; // An event was signaled.
  46. }
  47. if(dwRet >= WAIT_ABANDONED_0 &&
  48. dwRet < WAIT_ABANDONED_0 + dwNum )
  49. {
  50. return dwRet - WAIT_ABANDONED_0; // An event was abandoned.
  51. }
  52. }
  53. }
  54. return -1;
  55. }
  56. ////////////////////////////////////////////////////////////////////////////////
  57. Printing::Print::Print()
  58. {
  59. m_pCallback = NULL; // Notification* m_pCallback;
  60. //
  61. // MPC::WStringList m_lstURLs;
  62. //
  63. m_hwnd = NULL; // HWND m_hwnd;
  64. // WindowHandle m_wnd;
  65. // CComPtr<IWebBrowser2> m_spWebBrowser2;
  66. //
  67. // CComPtr<CDispatchSink> m_spObjDisp;
  68. m_eventDocComplete = NULL; // HANDLE m_eventDocComplete;
  69. m_eventAbortPrint = NULL; // HANDLE m_eventAbortPrint;
  70. //
  71. // CComPtr<IUnknown> m_spUnkControl;
  72. m_dwCookie = 0; // DWORD m_dwCookie;
  73. // CComPtr<IOleCommandTarget> m_spOleCmdTarg;
  74. // MPC::wstring m_szPrintDir;
  75. // MPC::wstring m_szPrintFile;
  76. //
  77. // CComPtr<IStream> m_streamPrintData;
  78. }
  79. Printing::Print::~Print()
  80. {
  81. Terminate();
  82. }
  83. ////////////////////////////////////////
  84. HRESULT Printing::Print::Initialize( /*[in]*/ HWND hwnd )
  85. {
  86. __HCP_FUNC_ENTRY( "Printing::Print::Initialize" );
  87. HRESULT hr;
  88. __MPC_EXIT_IF_METHOD_FAILS(hr, Terminate());
  89. m_hwnd = hwnd;
  90. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (m_eventDocComplete = ::CreateEvent( NULL, FALSE, FALSE, NULL )));
  91. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (m_eventAbortPrint = ::CreateEvent( NULL, FALSE, FALSE, NULL )));
  92. m_wnd.SetAbortEvent( m_eventAbortPrint );
  93. hr = S_OK;
  94. __HCP_FUNC_CLEANUP;
  95. __HCP_FUNC_EXIT(hr);
  96. }
  97. HRESULT Printing::Print::Terminate()
  98. {
  99. if(m_spObjDisp)
  100. {
  101. if(m_dwCookie != 0)
  102. {
  103. ::AtlUnadvise( m_spUnkControl, DIID_DWebBrowserEvents2, m_dwCookie );
  104. }
  105. m_spObjDisp.Release();
  106. }
  107. m_spWebBrowser2.Release();
  108. m_spUnkControl .Release();
  109. m_spOleCmdTarg .Release();
  110. if(m_wnd.m_hWnd)
  111. {
  112. m_wnd.DestroyWindow();
  113. }
  114. //
  115. // Delete temp files.
  116. //
  117. m_streamPrintData.Release();
  118. if(m_szPrintFile.size())
  119. {
  120. (void)MPC::DeleteFile( m_szPrintFile, true, true );
  121. m_szPrintFile.erase();
  122. }
  123. if(m_szPrintDir.size())
  124. {
  125. if(!::RemoveDirectoryW( m_szPrintDir.c_str() ))
  126. {
  127. (void)::MoveFileExW( m_szPrintDir.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
  128. }
  129. m_szPrintDir.erase();
  130. }
  131. return S_OK;
  132. }
  133. ////////////////////////////////////////////////////////////////////////////////
  134. HRESULT Printing::Print::AddUrl( /*[in]*/ LPCWSTR szUrl )
  135. {
  136. m_lstURLs.push_back( szUrl );
  137. return S_OK;
  138. }
  139. HRESULT Printing::Print::PrintAll( /*[in]*/ Notification* pCallback )
  140. {
  141. __HCP_FUNC_ENTRY( "Printing::Print::PrintAll" );
  142. HRESULT hr;
  143. int iLen = m_lstURLs.size();
  144. int iPos = 0;
  145. m_pCallback = pCallback;
  146. if(iLen > 0)
  147. {
  148. // Note: Printing to the printer directly!
  149. // By not setting the MultiTopic property PrintToFile is invoked - see PrintHost.cpp
  150. // Since we are not printing to file, also comment out all calls that create and manipulate temp files
  151. //__MPC_EXIT_IF_METHOD_FAILS(hr, PreparePrintFileLoc());
  152. //
  153. // Make sure the host window knows what's going on.
  154. //
  155. //m_wnd.SetMultiTopic ( true );
  156. //m_wnd.SetPrintFileName( m_szPrintFile.c_str() );
  157. for(MPC::WStringIter it = m_lstURLs.begin(); it != m_lstURLs.end(); it++, iPos++)
  158. {
  159. if(m_pCallback)
  160. {
  161. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pCallback->Progress( it->c_str(), iPos, iLen ));
  162. }
  163. __MPC_EXIT_IF_METHOD_FAILS(hr, PrintSingleURL( *it ));
  164. }
  165. //
  166. // ok, send it all to the printer...
  167. //
  168. //__MPC_EXIT_IF_METHOD_FAILS(hr, RawDataToPrinter());
  169. if(m_pCallback)
  170. {
  171. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pCallback->Progress( NULL, iLen, iLen ));
  172. }
  173. }
  174. hr = S_OK;
  175. __HCP_FUNC_CLEANUP;
  176. __HCP_FUNC_EXIT(hr);
  177. }
  178. ////////////////////////////////////////////////////////////////////////////////
  179. HRESULT Printing::Print::PrintSingleURL( /*[in]*/ MPC::wstring& szUrl )
  180. {
  181. __HCP_FUNC_ENTRY( "Printing::Print::PrintSingleURL" );
  182. HRESULT hr;
  183. //
  184. // Navigate to the url, creating the control if necessary
  185. //
  186. if(!m_wnd.m_hWnd)
  187. {
  188. RECT rect = { 0, 0, 800, 600 };
  189. DWORD dwStyles = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  190. if(m_hwnd) dwStyles |= WS_CHILD;
  191. if(!m_wnd.Create( m_hwnd, rect, szUrl.c_str(), dwStyles, WS_EX_CLIENTEDGE ))
  192. {
  193. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  194. }
  195. m_wnd.ShowWindow( SW_SHOW );
  196. __MPC_EXIT_IF_METHOD_FAILS(hr, HookUpEventSink());
  197. }
  198. else
  199. {
  200. if(!m_spWebBrowser2)
  201. {
  202. __MPC_EXIT_IF_METHOD_FAILS(hr, m_spUnkControl->QueryInterface( &m_spWebBrowser2 ));
  203. }
  204. __MPC_EXIT_IF_METHOD_FAILS(hr, m_spWebBrowser2->Navigate( CComBSTR( szUrl.c_str() ), NULL, NULL, NULL, NULL ));
  205. }
  206. //
  207. // Wait for document to be loaded
  208. //
  209. __MPC_EXIT_IF_METHOD_FAILS(hr, WaitForDocComplete());
  210. //
  211. // If the URL don't match, it means the URL doesn't exist...
  212. //
  213. if(MPC::StrICmp( szUrl, m_spObjDisp->GetCurrentURL() ))
  214. {
  215. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  216. }
  217. __MPC_EXIT_IF_METHOD_FAILS(hr, DoPrint());
  218. //
  219. // Since we now do a synchronous print operation, there's no need for snooping at the spool directory state.
  220. //
  221. //__MPC_EXIT_IF_METHOD_FAILS(hr, WaitForPrintComplete());
  222. //__MPC_EXIT_IF_METHOD_FAILS(hr, UpdatePrintBuffer());
  223. hr = S_OK;
  224. __HCP_FUNC_CLEANUP;
  225. if(m_wnd.GetAbortState() == true)
  226. {
  227. hr = E_ABORT;
  228. }
  229. __HCP_FUNC_EXIT(hr);
  230. }
  231. HRESULT Printing::Print::HookUpEventSink()
  232. {
  233. __HCP_FUNC_ENTRY( "Printing::Print::HookUpEventSink" );
  234. HRESULT hr;
  235. m_spUnkControl.Release();
  236. if(!m_wnd.m_hWnd)
  237. {
  238. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  239. }
  240. //
  241. // Hook up the connection point
  242. //
  243. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &m_spObjDisp ));
  244. m_spObjDisp->SetNotificationEvent( m_eventDocComplete );
  245. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wnd.QueryControl( &m_spUnkControl ));
  246. __MPC_EXIT_IF_METHOD_FAILS(hr, ::AtlAdvise( m_spUnkControl, m_spObjDisp, DIID_DWebBrowserEvents2, &m_dwCookie ));
  247. hr = S_OK;
  248. __HCP_FUNC_CLEANUP;
  249. __HCP_FUNC_EXIT(hr);
  250. }
  251. HRESULT Printing::Print::WaitForDocComplete()
  252. {
  253. __HCP_FUNC_ENTRY( "Printing::Print::WaitForDocComplete" );
  254. HRESULT hr;
  255. if(MPC::WaitForSingleObject( m_eventDocComplete ) != WAIT_OBJECT_0)
  256. {
  257. __MPC_SET_ERROR_AND_EXIT(hr, E_ABORT);
  258. }
  259. hr = S_OK;
  260. __HCP_FUNC_CLEANUP;
  261. __HCP_FUNC_EXIT(hr);
  262. }
  263. HRESULT Printing::Print::WaitForPrintComplete()
  264. {
  265. __HCP_FUNC_ENTRY( "Printing::Print::WaitForPrintComplete" );
  266. HRESULT hr;
  267. HANDLE hFileChangeNotify;
  268. HANDLE rgEventsToWait[2];
  269. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (hFileChangeNotify = ::FindFirstChangeNotificationW( m_szPrintDir.c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE )));
  270. rgEventsToWait[0] = hFileChangeNotify;
  271. rgEventsToWait[1] = m_eventAbortPrint;
  272. for(;;)
  273. {
  274. DWORD dwRet;
  275. dwRet = MPC::WaitForMultipleObjects( 2, rgEventsToWait, c_MaxWait );
  276. if(dwRet == WAIT_OBJECT_0)
  277. {
  278. HANDLE hFile = ::CreateFileW( m_szPrintFile.c_str(), GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
  279. if(hFile != INVALID_HANDLE_VALUE)
  280. {
  281. DWORD dwSize = ::GetFileSize( hFile, NULL );
  282. ::CloseHandle( hFile );
  283. if(dwSize != 0) break;
  284. }
  285. (void)::FindNextChangeNotification(hFileChangeNotify);
  286. }
  287. if(dwRet == WAIT_TIMEOUT ||
  288. dwRet == WAIT_OBJECT_0 + 1 )
  289. {
  290. __MPC_SET_ERROR_AND_EXIT(hr, E_ABORT);
  291. }
  292. }
  293. hr = S_OK;
  294. __HCP_FUNC_CLEANUP;
  295. if(hFileChangeNotify) ::FindCloseChangeNotification( hFileChangeNotify );
  296. __HCP_FUNC_EXIT(hr);
  297. }
  298. HRESULT Printing::Print::DoPrint()
  299. {
  300. __HCP_FUNC_ENTRY( "Printing::Print::DoPrint" );
  301. HRESULT hr;
  302. // send the command to print
  303. if(!m_spOleCmdTarg)
  304. {
  305. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wnd.QueryControl( &m_spOleCmdTarg ));
  306. }
  307. //
  308. // Make a synchronous print operation.
  309. //
  310. {
  311. VARIANT vArgIN;
  312. vArgIN.vt = VT_I2;
  313. vArgIN.iVal = PRINT_WAITFORCOMPLETION;
  314. __MPC_EXIT_IF_METHOD_FAILS(hr, m_spOleCmdTarg->Exec( NULL, OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, &vArgIN, NULL ));
  315. }
  316. hr = S_OK;
  317. __HCP_FUNC_CLEANUP;
  318. if(m_wnd.GetAbortState() == true)
  319. {
  320. hr = E_ABORT;
  321. }
  322. __HCP_FUNC_EXIT(hr);
  323. }
  324. HRESULT Printing::Print::PreparePrintFileLoc()
  325. {
  326. __HCP_FUNC_ENTRY( "Printing::Print::PreparePrintFileLoc" );
  327. HRESULT hr;
  328. MPC::wstring szWritablePath;
  329. MPC::wstring szPrintData;
  330. CComPtr<MPC::FileStream> stream;
  331. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( m_szPrintDir, HC_ROOT_HELPCTR L"\\Spool" ));
  332. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( m_szPrintFile, m_szPrintDir.c_str() ));
  333. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( szPrintData , m_szPrintDir.c_str() ));
  334. //
  335. // Create a stream for a temporary file.
  336. //
  337. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &stream ));
  338. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->InitForReadWrite( szPrintData.c_str() ));
  339. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->DeleteOnRelease ( ));
  340. m_streamPrintData = stream;
  341. hr = S_OK;
  342. __HCP_FUNC_CLEANUP;
  343. __HCP_FUNC_EXIT(hr);
  344. }
  345. HRESULT Printing::Print::UpdatePrintBuffer()
  346. {
  347. __HCP_FUNC_ENTRY( "Printing::Print::UpdatePrintBuffer" );
  348. HRESULT hr;
  349. CComPtr<MPC::FileStream> stream;
  350. //
  351. // Open the single-topic print file and copy it to the multi-topic print file.
  352. //
  353. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &stream ));
  354. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->InitForRead ( m_szPrintFile.c_str() ));
  355. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->DeleteOnRelease( ));
  356. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( stream, m_streamPrintData ));
  357. hr = S_OK;
  358. __HCP_FUNC_CLEANUP;
  359. __HCP_FUNC_EXIT(hr);
  360. }
  361. HRESULT Printing::Print::RawDataToPrinter()
  362. {
  363. __HCP_FUNC_ENTRY( "Printing::Print::RawDataToPrinter" );
  364. HRESULT hr;
  365. HANDLE hPrinter = NULL;
  366. DWORD dwJob = 0;
  367. //
  368. // Reset stream to beginning.
  369. //
  370. {
  371. LARGE_INTEGER li;
  372. li.LowPart = 0;
  373. li.HighPart = 0;
  374. __MPC_EXIT_IF_METHOD_FAILS(hr, m_streamPrintData->Seek( li, STREAM_SEEK_SET, NULL ));
  375. }
  376. //
  377. // Open the printer, create a job and copy all the data into it.
  378. //
  379. {
  380. DOC_INFO_1W docinfo;
  381. BYTE rgBuf[1024];
  382. ULONG dwRead;
  383. DWORD dwWritten;
  384. MPC::wstring strTitle; MPC::LocalizeString( IDS_HELPCTR_PRINT_TITLE, strTitle );
  385. // Fill in the structure with info about this "document."
  386. docinfo.pDocName = (LPWSTR)strTitle.c_str();;
  387. docinfo.pOutputFile = NULL;
  388. docinfo.pDatatype = L"RAW";
  389. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::OpenPrinterW( m_wnd.GetPrinterName(), &hPrinter, NULL ));
  390. // Inform the spooler the document is beginning.
  391. __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, (dwJob = ::StartDocPrinterW( hPrinter, 1, (LPBYTE)&docinfo )));
  392. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::StartPagePrinter( hPrinter ));
  393. while(1)
  394. {
  395. __MPC_EXIT_IF_METHOD_FAILS(hr, m_streamPrintData->Read( rgBuf, sizeof(rgBuf), &dwRead ));
  396. if(hr == S_FALSE || dwRead == 0) // End of File.
  397. {
  398. break;
  399. }
  400. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::WritePrinter( hPrinter, rgBuf, dwRead, &dwWritten ));
  401. }
  402. }
  403. hr = S_OK;
  404. __HCP_FUNC_CLEANUP;
  405. if(hPrinter)
  406. {
  407. if(dwJob)
  408. {
  409. // End the page.
  410. if(!::EndPagePrinter( hPrinter ))
  411. {
  412. if(SUCCEEDED(hr))
  413. {
  414. hr = HRESULT_FROM_WIN32(::GetLastError());
  415. }
  416. }
  417. // Inform the spooler that the document is ending.
  418. if(!::EndDocPrinter( hPrinter ))
  419. {
  420. if(SUCCEEDED(hr))
  421. {
  422. hr = HRESULT_FROM_WIN32(::GetLastError());
  423. }
  424. }
  425. }
  426. // Tidy up the printer handle.
  427. if(!::ClosePrinter( hPrinter ))
  428. {
  429. if(SUCCEEDED(hr))
  430. {
  431. hr = HRESULT_FROM_WIN32(::GetLastError());
  432. }
  433. }
  434. }
  435. __HCP_FUNC_EXIT(hr);
  436. }