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.

1359 lines
38 KiB

  1. // oleInst.cpp : Implementation of COleInstall
  2. #include "stdafx.h"
  3. #include <strsafe.h>
  4. #include "prnsec.h"
  5. #include "oleprn.h"
  6. #include "oleInst.h"
  7. #include "printer.h"
  8. /////////////////////////////////////////////////////////////////////////////
  9. // COleInstall
  10. const TCHAR * const g_szWindowClassName = TEXT("Ole Install Control");
  11. const TCHAR * const g_fmtSpoolSSPipe = TEXT("\\\\%s\\PIPE\\SPOOLSS");
  12. const DWORD cdwSucessExitCode = 0xFFFFFFFF;
  13. typedef DWORD (*pfnPrintUIEntry)(HWND,HINSTANCE,LPCTSTR,UINT);
  14. OleInstallData::OleInstallData (
  15. LPTSTR pPrinterUncName,
  16. LPTSTR pPrinterUrl,
  17. HWND hwnd,
  18. BOOL bRPC)
  19. :m_lCount (2),
  20. m_pPrinterUncName (NULL),
  21. m_pPrinterUrl (NULL),
  22. m_pszTempWebpnpFile (NULL),
  23. m_hwnd (hwnd),
  24. m_bValid (FALSE),
  25. m_bRPC(bRPC)
  26. {
  27. if (AssignString (m_pPrinterUncName, pPrinterUncName)
  28. && AssignString (m_pPrinterUrl, pPrinterUrl))
  29. m_bValid = TRUE;
  30. }
  31. OleInstallData::~OleInstallData ()
  32. {
  33. if (m_pszTempWebpnpFile) {
  34. DeleteFile (m_pszTempWebpnpFile);
  35. LocalFree (m_pszTempWebpnpFile);
  36. }
  37. LocalFree (m_pPrinterUncName);
  38. LocalFree (m_pPrinterUrl);
  39. }
  40. COleInstall::COleInstall()
  41. : m_hwnd (NULL),
  42. m_pPrinterUncName (NULL),
  43. m_pPrinterUrl (NULL),
  44. m_pThreadData (NULL)
  45. {
  46. DisplayUIonDisallow(FALSE); // We don't want IE displaying UI.
  47. }
  48. COleInstall::~COleInstall()
  49. {
  50. if(m_hwnd)
  51. {
  52. if (m_pThreadData) {
  53. m_pThreadData->m_hwnd = NULL;
  54. }
  55. ::DestroyWindow(m_hwnd);
  56. m_hwnd = NULL;
  57. }
  58. LocalFree (m_pPrinterUncName);
  59. LocalFree (m_pPrinterUrl);
  60. if (m_pThreadData) {
  61. if (InterlockedDecrement (& (m_pThreadData->m_lCount)) == 0) {
  62. delete (m_pThreadData);
  63. }
  64. }
  65. }
  66. HRESULT
  67. COleInstall::OnDraw(
  68. ATL_DRAWINFO& di)
  69. {
  70. return S_OK;
  71. }
  72. BOOL
  73. COleInstall::UpdateUI (
  74. OleInstallData *pData,
  75. UINT message,
  76. WPARAM wParam)
  77. {
  78. BOOL bRet = FALSE;
  79. if (pData->m_hwnd) {
  80. ::SendMessage (pData->m_hwnd, message, wParam, NULL);
  81. bRet = TRUE;
  82. }
  83. return bRet;
  84. }
  85. BOOL
  86. COleInstall::UpdateProgress (
  87. OleInstallData *pData,
  88. DWORD dwProgress)
  89. {
  90. return UpdateUI (pData, WM_ON_PROGRESS, dwProgress);
  91. }
  92. BOOL
  93. COleInstall::UpdateError (
  94. OleInstallData *pData)
  95. {
  96. return UpdateUI (pData, WM_INSTALL_ERROR, GetLastError ());
  97. }
  98. HRESULT
  99. COleInstall::InitWin (BOOL bRPC)
  100. {
  101. HRESULT hr = E_FAIL;
  102. DWORD dwThreadId;
  103. HANDLE hThread = NULL;
  104. WNDCLASS wc;
  105. // Create Window Class
  106. if (!::GetClassInfo(_Module.GetModuleInstance(), g_szWindowClassName, &wc))
  107. {
  108. wc.style = 0;
  109. wc.lpfnWndProc = COleInstall::WndProc;
  110. wc.cbClsExtra = 0;
  111. wc.cbWndExtra = 0;
  112. wc.hInstance = _Module.GetModuleInstance();
  113. wc.hIcon = NULL;
  114. wc.hCursor = NULL;
  115. wc.hbrBackground = NULL;
  116. wc.lpszMenuName = NULL;
  117. wc.lpszClassName = g_szWindowClassName;
  118. if (!RegisterClass(&wc)) {
  119. return hr;
  120. }
  121. }
  122. m_hwnd = CreateWindow(g_szWindowClassName,
  123. NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
  124. CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
  125. _Module.GetModuleInstance(), this);
  126. if (m_hwnd) {
  127. m_pThreadData = new OleInstallData (m_pPrinterUncName,
  128. m_pPrinterUrl,
  129. m_hwnd,
  130. bRPC);
  131. if (m_pThreadData && m_pThreadData->m_bValid) {
  132. if (hThread = ::CreateThread (NULL,
  133. 0,
  134. (LPTHREAD_START_ROUTINE) &COleInstall::WorkingThread,
  135. m_pThreadData,
  136. 0,
  137. &dwThreadId)) {
  138. CloseHandle (hThread);
  139. hr = S_OK;
  140. }
  141. }
  142. }
  143. return hr;
  144. }
  145. BOOL
  146. COleInstall::WorkingThread(
  147. void * param)
  148. {
  149. OleInstallData * pThreadData = (OleInstallData *) param;
  150. BOOL bRet = FALSE;
  151. if (pThreadData) {
  152. bRet = StartInstall (pThreadData);
  153. }
  154. return bRet;
  155. }
  156. BOOL
  157. COleInstall::StartInstall(
  158. OleInstallData *pThreadData)
  159. {
  160. HANDLE hServer = NULL;
  161. PRINTER_DEFAULTS pd = {NULL, NULL, SERVER_ALL_ACCESS};
  162. BOOL bRet = FALSE;
  163. CPrinter Printer;
  164. HANDLE hPrinter;
  165. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  166. LPTSTR lpszPrinterURL = NULL;
  167. // Working thread
  168. if (!UpdateProgress (pThreadData, 0))
  169. goto Cleanup;
  170. //
  171. // Check if we are to try RPC or HTTP
  172. //
  173. if (pThreadData->m_bRPC)
  174. {
  175. // Check RPC connections at first
  176. if (::AddPrinterConnection( (BSTR)pThreadData->m_pPrinterUncName))
  177. {
  178. UpdateProgress (pThreadData, 50);
  179. if (CheckAndSetDefaultPrinter ())
  180. {
  181. UpdateProgress (pThreadData, 100);
  182. bRet = TRUE;
  183. }
  184. goto Cleanup;
  185. }
  186. }
  187. else
  188. {
  189. //
  190. // Install using HTTP
  191. //
  192. // Since http installation always requires
  193. // administrator privilidge, We have to do a access check before we
  194. // try to down load the cab file
  195. if (!OpenPrinter (NULL, &hServer, &pd))
  196. {
  197. // If this fails and it is because we do not have access, we should send a better error
  198. // message to the local user telling them that the do not have the ability to create
  199. // printers on the local machine
  200. if (GetLastError() == ERROR_ACCESS_DENIED)
  201. {
  202. SetLastError(ERROR_LOCAL_PRINTER_ACCESS);
  203. }
  204. goto Cleanup;
  205. }
  206. else
  207. ClosePrinter (hServer);
  208. //
  209. // Try the local CAB installation instead of downloading the cab, etc.
  210. // Need admin privaleges.
  211. //
  212. if ( NULL != (lpszPrinterURL = RemoveURLVars( pThreadData->m_pPrinterUrl )) &&
  213. Printer.Open( lpszPrinterURL, &hPrinter ) )
  214. {
  215. LPTSTR lpszInfName = NULL;
  216. LPTSTR lpszPrinterName = NULL;
  217. pPrinterInfo2 = Printer.GetPrinterInfo2();
  218. if ((pPrinterInfo2 == NULL) && (GetLastError () == ERROR_ACCESS_DENIED))
  219. {
  220. if (!ConfigurePort( NULL, pThreadData->m_hwnd, lpszPrinterURL ))
  221. {
  222. bRet = FALSE;
  223. goto Cleanup;
  224. }
  225. pPrinterInfo2 = Printer.GetPrinterInfo2();
  226. }
  227. if ( (NULL != pPrinterInfo2) &&
  228. (NULL != (lpszInfName = GetNTPrint())) &&
  229. (NULL != (lpszPrinterName = CreatePrinterBaseName(lpszPrinterURL, pPrinterInfo2->pPrinterName))) )
  230. {
  231. LPTSTR lpszCmd = NULL;
  232. DWORD dwLength = 0;
  233. TCHAR szCmdString[] = _TEXT("/if /x /b \"%s\" /r \"%s\" /m \"%s\" /n \"%s\" /f %s /q");
  234. HMODULE hPrintUI = NULL;
  235. pfnPrintUIEntry PrintUIEntry;
  236. dwLength = lstrlen( szCmdString ) +
  237. lstrlen( lpszPrinterName ) +
  238. lstrlen( pPrinterInfo2->pPortName ) +
  239. lstrlen( pPrinterInfo2->pDriverName ) +
  240. lstrlen( pThreadData->m_pPrinterUncName ) +
  241. lstrlen( lpszInfName ) + 1;
  242. if ( (lpszCmd = (LPTSTR)LocalAlloc( LPTR, dwLength*sizeof(TCHAR) )) &&
  243. (hPrintUI = LoadLibraryFromSystem32( TEXT("printui.dll") )) )
  244. {
  245. StringCchPrintf( lpszCmd,
  246. dwLength,
  247. szCmdString,
  248. lpszPrinterName,
  249. pPrinterInfo2->pPortName,
  250. pPrinterInfo2->pDriverName,
  251. pThreadData->m_pPrinterUncName,
  252. lpszInfName );
  253. if ( PrintUIEntry = (pfnPrintUIEntry)GetProcAddress(hPrintUI, "PrintUIEntryW") )
  254. {
  255. if ( ERROR_SUCCESS == (*PrintUIEntry)( NULL,
  256. 0,
  257. lpszCmd,
  258. SW_HIDE ) )
  259. {
  260. UpdateProgress (pThreadData, 50);
  261. if (CheckAndSetDefaultPrinter ())
  262. {
  263. UpdateProgress (pThreadData, 100);
  264. bRet = TRUE;
  265. }
  266. }
  267. }
  268. }
  269. if ( lpszCmd )
  270. LocalFree( lpszCmd );
  271. if ( hPrintUI )
  272. FreeLibrary( hPrintUI );
  273. }
  274. if ( lpszInfName )
  275. LocalFree( lpszInfName );
  276. if ( lpszPrinterName )
  277. LocalFree( lpszPrinterName );
  278. }
  279. if ( lpszPrinterURL )
  280. LocalFree(lpszPrinterURL);
  281. if ( bRet )
  282. goto Cleanup;
  283. if (UpdateProgress (pThreadData, 25))
  284. {
  285. // Step two, the Local CAB install failed so download a driver and install
  286. if (GetHttpPrinterFile (pThreadData, pThreadData->m_pPrinterUrl))
  287. {
  288. if (UpdateProgress (pThreadData, 60))
  289. {
  290. if (InstallHttpPrinter (pThreadData))
  291. {
  292. if (UpdateProgress (pThreadData, 90))
  293. {
  294. if (CheckAndSetDefaultPrinter ())
  295. {
  296. UpdateProgress (pThreadData, 100);
  297. bRet = TRUE;
  298. }
  299. }
  300. }
  301. }
  302. }
  303. }
  304. }
  305. Cleanup:
  306. if (!bRet)
  307. {
  308. UpdateError (pThreadData);
  309. }
  310. // Cleanup the ThreadData
  311. if (InterlockedDecrement (& (pThreadData->m_lCount)) == 0)
  312. {
  313. delete (pThreadData);
  314. }
  315. return bRet;
  316. }
  317. LRESULT CALLBACK
  318. COleInstall::WndProc(
  319. HWND hWnd,
  320. UINT uMsg,
  321. WPARAM wParam,
  322. LPARAM lParam)
  323. {
  324. COleInstall *ptc = (COleInstall *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
  325. switch(uMsg)
  326. {
  327. case WM_CREATE:
  328. {
  329. ptc = (COleInstall *)((CREATESTRUCT *)lParam)->lpCreateParams;
  330. ::SetWindowLongPtr(hWnd, GWLP_USERDATA, (UINT_PTR) ptc);
  331. }
  332. break;
  333. case WM_ON_PROGRESS:
  334. if (ptc)
  335. ptc->Fire_OnProgress ((long) wParam);
  336. break;
  337. case WM_INSTALL_ERROR:
  338. if (ptc)
  339. ptc->Fire_InstallError ((long) wParam);
  340. break;
  341. case WM_DESTROY:
  342. // ignore late messages
  343. if(ptc)
  344. {
  345. MSG msg;
  346. while(PeekMessage(&msg, hWnd, WM_ON_PROGRESS, WM_INSTALL_ERROR, PM_REMOVE));
  347. ::SetWindowLongPtr (hWnd, GWLP_USERDATA, NULL);
  348. }
  349. break;
  350. default:
  351. return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
  352. }
  353. return 0;
  354. }
  355. STDMETHODIMP
  356. COleInstall::InstallPrinter(
  357. BSTR bstrUncName,
  358. BSTR bstrUrl)
  359. {
  360. HRESULT hr = bstrUncName && bstrUrl ? S_OK : E_POINTER;
  361. if (SUCCEEDED(hr))
  362. {
  363. // When using an ATL string conversion Macro, spedcify the USES_CONVERSION macro
  364. // to avoid compiler error
  365. USES_CONVERSION;
  366. hr = AssignString(m_pPrinterUncName, OLE2T(bstrUncName)) && AssignString(m_pPrinterUrl, OLE2T(bstrUrl)) ? S_OK : E_OUTOFMEMORY;
  367. }
  368. if (SUCCEEDED(hr))
  369. {
  370. hr = CanIInstallRPC(m_pPrinterUncName); // Determine whether to use RPC or HTTP.
  371. }
  372. if (SUCCEEDED(hr))
  373. {
  374. BOOL bRPC = hr == S_OK;
  375. LPTSTR lpszDisplay = NULL;
  376. LPTSTR lpszTemp = NULL;
  377. DWORD cchSize = 0;
  378. if (bRPC)
  379. {
  380. cchSize = lstrlen(m_pPrinterUncName) + 1;
  381. lpszDisplay = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * cchSize);
  382. hr = lpszDisplay ? S_OK : E_OUTOFMEMORY;
  383. if (SUCCEEDED(hr))
  384. {
  385. hr = StringCchCopy(lpszDisplay, cchSize, m_pPrinterUncName);
  386. }
  387. }
  388. else
  389. {
  390. //
  391. // If it's a URL printer name, we need to remove any variables embedded in the
  392. // URL and also decode it to remove those ~-escaped characters.
  393. //
  394. lpszTemp = RemoveURLVars(m_pPrinterUrl);
  395. hr = lpszTemp ? S_OK : E_OUTOFMEMORY;
  396. if (SUCCEEDED(hr))
  397. {
  398. //
  399. // This call is to ask for the required size for this decoding. It has to fail and
  400. // return ERROR_INSUFFICIENT_BUFFER, otherwise, something is wrong.
  401. //
  402. hr = DecodePrinterName(lpszTemp, NULL, &cchSize) ? E_FAIL : GetLastErrorAsHResultAndFail();
  403. if (FAILED(hr) && HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)
  404. {
  405. lpszDisplay = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * cchSize);
  406. hr = lpszDisplay ? S_OK : E_OUTOFMEMORY;
  407. }
  408. }
  409. if (SUCCEEDED(hr))
  410. {
  411. hr = DecodePrinterName(lpszTemp, lpszDisplay, &cchSize) ? S_OK : GetLastErrorAsHResultAndFail();
  412. }
  413. }
  414. if (SUCCEEDED(hr))
  415. {
  416. hr = PromptUser(bRPC ? AddPrinterConnection : AddWebPrinterConnection, lpszDisplay);
  417. }
  418. LocalFree(lpszTemp);
  419. LocalFree(lpszDisplay);
  420. if (hr == S_OK)
  421. {
  422. hr = InitWin(bRPC);
  423. }
  424. else if (hr == S_FALSE)
  425. {
  426. hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
  427. }
  428. }
  429. return hr;
  430. }
  431. STDMETHODIMP
  432. COleInstall::OpenPrintersFolder()
  433. {
  434. HRESULT hr;
  435. if (FAILED(hr = CanIOpenPrintersFolder()))
  436. return hr; // We allow JAVALOW/JAVAMEDIUM to open the printers folder
  437. LPITEMIDLIST pidl = NULL;
  438. HWND hwnd = GetDesktopWindow ();
  439. hr = SHGetSpecialFolderLocation( hwnd, CSIDL_PRINTERS, &pidl );
  440. if (SUCCEEDED(hr))
  441. {
  442. SHELLEXECUTEINFO ei = {0};
  443. ei.cbSize = sizeof(SHELLEXECUTEINFO);
  444. ei.fMask = SEE_MASK_IDLIST;
  445. ei.hwnd = hwnd;
  446. ei.lpIDList = (LPVOID)pidl;
  447. ei.nShow = SW_SHOWNORMAL;
  448. if (!ShellExecuteEx(&ei))
  449. hr = E_FAIL;
  450. }
  451. return hr;
  452. }
  453. /////////////////////////////////////////////////////////////////////////////
  454. // Private Member Functions
  455. /////////////////////////////////////////////////////////////////////////////
  456. BOOL
  457. COleInstall::SyncExecute(
  458. LPTSTR pszFileName,
  459. int nShow)
  460. {
  461. SHELLEXECUTEINFO shellExeInfo;
  462. DWORD dwErrorCode;
  463. BOOL bRet = FALSE;
  464. HWND hWndForeground, hWndParent, hWndOwner, hWndLastPopup;
  465. //
  466. // We need to get the window handle of the current process to pass to the installation code,
  467. // otherwise any UI (e.g. driver signing pop ups) won't have focus of the IE frame.
  468. //
  469. // get the foreground window first
  470. hWndForeground = ::GetForegroundWindow();
  471. // climb up to the top parent in case it's a child window...
  472. hWndParent = hWndForeground;
  473. while( hWndParent = ::GetParent(hWndParent) ) {
  474. hWndForeground = hWndParent;
  475. }
  476. // get the owner in case the top parent is owned
  477. hWndOwner = ::GetWindow(::GetParent(hWndForeground), GW_OWNER);
  478. if( hWndOwner ) {
  479. hWndForeground = hWndOwner;
  480. }
  481. // get the last popup of the owner window
  482. hWndLastPopup = ::GetLastActivePopup(hWndForeground);
  483. ZeroMemory (&shellExeInfo, sizeof (SHELLEXECUTEINFO));
  484. shellExeInfo.cbSize = sizeof (SHELLEXECUTEINFO);
  485. shellExeInfo.hwnd = hWndLastPopup;
  486. shellExeInfo.lpVerb = TEXT ("open");
  487. shellExeInfo.lpFile = pszFileName;
  488. shellExeInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
  489. shellExeInfo.nShow = nShow;
  490. if (ShellExecuteEx (&shellExeInfo) &&
  491. (UINT_PTR) shellExeInfo.hInstApp > 32) {
  492. // Wait until it is done
  493. if (!WaitForSingleObject (shellExeInfo.hProcess , INFINITE) &&
  494. GetExitCodeProcess (shellExeInfo.hProcess, &dwErrorCode)) {
  495. if (dwErrorCode == cdwSucessExitCode) {
  496. bRet = TRUE;
  497. }
  498. else {
  499. if (!dwErrorCode) {
  500. // This means that wpnpinst was terminated abnormally
  501. // So we have to setup an customized error code here.
  502. dwErrorCode = ERROR_WPNPINST_TERMINATED;
  503. }
  504. SetLastError (dwErrorCode);
  505. }
  506. }
  507. if (shellExeInfo.hProcess) {
  508. ::CloseHandle(shellExeInfo.hProcess);
  509. }
  510. }
  511. return bRet;
  512. }
  513. DWORD
  514. COleInstall::GetWebpnpFile(
  515. OleInstallData *pData,
  516. LPTSTR pszURL,
  517. LPTSTR *ppErrMsg)
  518. {
  519. HINTERNET hUrlWebpnp = NULL;
  520. HINTERNET hHandle = NULL;
  521. HANDLE hFile = INVALID_HANDLE_VALUE;
  522. DWORD dwSize = 0;
  523. DWORD dwWritten = 0;
  524. LPTSTR pszHeader = NULL;
  525. BOOL bRet;
  526. BOOL bRetry = TRUE;
  527. DWORD dwRet = RET_OTHER_ERROR;
  528. DWORD dwError = ERROR_SUCCESS;
  529. DWORD dwLastError;
  530. DWORD i;
  531. BYTE buf[FILEBUFSIZE];
  532. *ppErrMsg = NULL;
  533. if (! (hHandle = InternetOpen (TEXT ("Internet Add Printer"),
  534. INTERNET_OPEN_TYPE_PRECONFIG,
  535. NULL, NULL, 0)))
  536. goto Cleanup;
  537. for (i = 0; bRetry ; i++) {
  538. DWORD dwCode;
  539. DWORD dwBufSize = sizeof (DWORD);
  540. hUrlWebpnp = InternetOpenUrl (hHandle, pszURL, NULL, 0, 0, 0);
  541. if (!HttpQueryInfo(hUrlWebpnp,
  542. HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
  543. &dwCode,
  544. &dwBufSize,
  545. NULL))
  546. goto Cleanup;
  547. switch (dwCode) {
  548. case HTTP_STATUS_OK :
  549. bRetry = FALSE;
  550. break;
  551. case HTTP_STATUS_SERVER_ERROR :
  552. // Errors are returned by the server
  553. // Try to get the error string
  554. dwBufSize = 0;
  555. bRet = HttpQueryInfo(hUrlWebpnp,
  556. HTTP_QUERY_STATUS_TEXT,
  557. NULL,
  558. &dwBufSize,
  559. NULL);
  560. if (!bRet && GetLastError () == ERROR_INSUFFICIENT_BUFFER) {
  561. if (!(pszHeader = (LPTSTR) LocalAlloc( LPTR, dwBufSize)))
  562. goto Cleanup;
  563. *ppErrMsg = pszHeader;
  564. if (! HttpQueryInfo(hUrlWebpnp,
  565. HTTP_QUERY_STATUS_TEXT,
  566. pszHeader,
  567. &dwBufSize,
  568. NULL))
  569. goto Cleanup;
  570. dwRet = RET_SERVER_ERROR;
  571. goto Cleanup;
  572. }
  573. else
  574. goto Cleanup;
  575. break;
  576. case HTTP_STATUS_DENIED :
  577. case HTTP_STATUS_PROXY_AUTH_REQ :
  578. dwError = InternetErrorDlg(GetDesktopWindow(), hUrlWebpnp,
  579. hUrlWebpnp? ERROR_SUCCESS : GetLastError(),
  580. FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
  581. FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
  582. FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
  583. NULL);
  584. switch (dwError) {
  585. case ERROR_INTERNET_FORCE_RETRY:
  586. if (i >= MAX_INET_RETRY) {
  587. goto Cleanup;
  588. }
  589. break;
  590. case ERROR_SUCCESS:
  591. bRetry = FALSE;
  592. break;
  593. case ERROR_CANCELLED:
  594. default:
  595. goto Cleanup;
  596. }
  597. break;
  598. default:
  599. goto Cleanup;
  600. }
  601. }
  602. if (!UpdateProgress (pData, 35))
  603. goto Cleanup;
  604. if ( INVALID_HANDLE_VALUE ==
  605. (hFile = GetTempFile(TEXT (".webpnp"), &(pData->m_pszTempWebpnpFile))))
  606. goto Cleanup;
  607. dwSize = FILEBUFSIZE;
  608. while (dwSize == FILEBUFSIZE) {
  609. if (! InternetReadFile (hUrlWebpnp, (LPVOID)buf, FILEBUFSIZE, &dwSize)) {
  610. goto Cleanup;
  611. }
  612. if (! (pData->m_hwnd)) {
  613. goto Cleanup;
  614. }
  615. if (! WriteFile (hFile, buf, dwSize, &dwWritten, NULL)) {
  616. goto Cleanup;
  617. }
  618. }
  619. CloseHandle (hFile);
  620. hFile = INVALID_HANDLE_VALUE;
  621. dwRet = RET_SUCCESS;
  622. Cleanup:
  623. dwLastError = GetLastError ();
  624. if (hFile != INVALID_HANDLE_VALUE)
  625. CloseHandle (hFile);
  626. if (hUrlWebpnp)
  627. InternetCloseHandle (hUrlWebpnp);
  628. if (hHandle)
  629. InternetCloseHandle (hHandle);
  630. SetLastError (dwLastError);
  631. if (dwRet == RET_OTHER_ERROR && GetLastError () == ERROR_SUCCESS) {
  632. SetLastError (ERROR_ACCESS_DENIED);
  633. }
  634. return dwRet;
  635. }
  636. HANDLE
  637. COleInstall::GetTempFile(
  638. LPTSTR pExtension,
  639. LPTSTR * ppFileName)
  640. {
  641. HANDLE hServer = NULL;
  642. PRINTER_DEFAULTS prDefaults = {0}; // Used to test access rights to the printer
  643. DWORD dwType = 0; // This is the type of the string
  644. HANDLE hFile = INVALID_HANDLE_VALUE;
  645. LPTSTR pszTempDir = NULL;
  646. LPTSTR pszTempFname = NULL;
  647. GUID guid = GUID_NULL;
  648. LPOLESTR pszGUID = NULL;
  649. DWORD dwAllocated = 0; // This is the total number of characters allocated (not byte-size).
  650. DWORD dwTempLen = 0; // This is the new size of the string
  651. DWORD dwTempSize = 0; // This is the Size of the return String
  652. // First we want to open the local print server and ensure that we have access to it
  653. prDefaults.pDatatype = NULL;
  654. prDefaults.pDevMode = NULL;
  655. prDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
  656. *ppFileName = NULL;
  657. // Open the local spooler to get a handle to it
  658. if (!OpenPrinter( NULL, &hServer, &prDefaults)) {
  659. hServer = NULL; // Open Printer returns NULL and not INVALID_HANDLE_VALUE for a failure
  660. goto Cleanup; // OpenPrinter will SetLastError to the reason why we couldn't open
  661. }
  662. // Get the size of the buffer we will need to copy the printer data
  663. if (ERROR_MORE_DATA !=
  664. GetPrinterData( hServer, SPLREG_DEFAULT_SPOOL_DIRECTORY, &dwType, NULL, 0, &dwTempSize)) {
  665. goto Cleanup;
  666. }
  667. // If it's something other than a simple string, set the error to a database error
  668. if (dwType != REG_SZ) {
  669. SetLastError(ERROR_BADDB);
  670. goto Cleanup;
  671. }
  672. // Allocate memory for the directory string.
  673. if (! (pszTempDir = (LPTSTR) LocalAlloc( LPTR, dwTempSize )))
  674. goto Cleanup;
  675. if (ERROR_SUCCESS !=
  676. GetPrinterData( hServer, SPLREG_DEFAULT_SPOOL_DIRECTORY, &dwType, (LPBYTE)pszTempDir,
  677. dwTempSize, &dwTempLen))
  678. goto Cleanup; // For some reason we could not get the data
  679. ClosePrinter(hServer);
  680. hServer = NULL;
  681. if ( FAILED( ::CoCreateGuid( &guid )))
  682. goto Cleanup;
  683. if ( FAILED( ::StringFromCLSID( guid, &pszGUID )))
  684. goto Cleanup;
  685. dwAllocated = lstrlen( pszTempDir ) + 1 + lstrlen( pszGUID ) + lstrlen ( pExtension ) + 1;
  686. if (! (pszTempFname = (LPTSTR) LocalAlloc( LPTR, sizeof (TCHAR) * dwAllocated )) )
  687. goto Cleanup;
  688. if ( FAILED ( StringCchPrintf( pszTempFname,
  689. dwAllocated,
  690. TEXT("%s\\%s%s"),
  691. pszTempDir,
  692. pszGUID,
  693. pExtension )))
  694. goto Cleanup;
  695. hFile = CreateFile( pszTempFname,
  696. GENERIC_READ | GENERIC_WRITE,
  697. 0,
  698. NULL,
  699. CREATE_NEW,
  700. FILE_ATTRIBUTE_NORMAL,
  701. NULL );
  702. if ( !hFile || hFile == INVALID_HANDLE_VALUE)
  703. goto Cleanup;
  704. LocalFree (pszTempDir);
  705. ::CoTaskMemFree(pszGUID);
  706. *ppFileName = pszTempFname;
  707. return hFile;
  708. Cleanup:
  709. if (pszTempDir)
  710. LocalFree (pszTempDir);
  711. if (pszTempFname)
  712. LocalFree (pszTempFname);
  713. if (pszGUID)
  714. ::CoTaskMemFree(pszGUID);
  715. if (hServer)
  716. ClosePrinter(hServer);
  717. return INVALID_HANDLE_VALUE;
  718. }
  719. BOOL
  720. COleInstall::IsHttpPreferred(void)
  721. {
  722. DWORD dwVal;
  723. DWORD dwType = REG_DWORD;
  724. DWORD dwSize = sizeof (DWORD);
  725. HKEY hHandle = NULL;
  726. BOOL bRet = FALSE;
  727. if (ERROR_SUCCESS != RegOpenKey (HKEY_CURRENT_USER,
  728. TEXT ("Printers\\Settings"),
  729. &hHandle))
  730. goto Cleanup;
  731. if (ERROR_SUCCESS == RegQueryValueEx (hHandle,
  732. TEXT ("PreferredConnection"),
  733. NULL,
  734. &dwType,
  735. (LPBYTE) &dwVal,
  736. &dwSize)) {
  737. bRet = (dwVal == 0) ? TRUE : FALSE;
  738. }
  739. Cleanup:
  740. if (hHandle) {
  741. RegCloseKey (hHandle);
  742. }
  743. return bRet;
  744. }
  745. BOOL
  746. COleInstall::GetHttpPrinterFile(
  747. OleInstallData *pData,
  748. LPTSTR pbstrURL)
  749. {
  750. LPTSTR pszErrMsg = NULL;
  751. BOOL bRet = FALSE;
  752. DWORD dwError;
  753. if (!pbstrURL) {
  754. return FALSE;
  755. }
  756. switch (GetWebpnpFile(pData, pbstrURL, &pszErrMsg)) {
  757. case RET_SUCCESS:
  758. bRet = TRUE;
  759. break;
  760. case RET_SERVER_ERROR:
  761. dwError = _ttol (pszErrMsg);
  762. if (dwError == 0) {
  763. // This is a server internal error
  764. dwError = ERROR_INTERNAL_SERVER;
  765. }
  766. SetLastError (dwError);
  767. break;
  768. case RET_OTHER_ERROR:
  769. default:
  770. break;
  771. }
  772. if (pszErrMsg) {
  773. LocalFree (pszErrMsg);
  774. }
  775. return bRet;
  776. }
  777. BOOL
  778. COleInstall::InstallHttpPrinter(
  779. OleInstallData *pData)
  780. {
  781. BOOL bRet = FALSE;
  782. if (SyncExecute(pData->m_pszTempWebpnpFile, SW_SHOWNORMAL))
  783. bRet = TRUE;
  784. return bRet;
  785. }
  786. BOOL
  787. COleInstall::CheckAndSetDefaultPrinter()
  788. {
  789. DWORD dwSize = 0;
  790. BOOL bRet = TRUE;
  791. if (!GetDefaultPrinterW (NULL, &dwSize)) {
  792. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  793. // No default printer is set
  794. // We pass a NULL to SetDefaultPrinter to set the first printer in the device list to
  795. // be the default one
  796. bRet = SetDefaultPrinter (NULL);
  797. }
  798. }
  799. return bRet;
  800. }
  801. HRESULT COleInstall::CanIOpenPrintersFolder(void) {
  802. DWORD dwPolicy;
  803. HRESULT hr = GetActionPolicy(URLACTION_JAVA_PERMISSIONS, dwPolicy );
  804. if (SUCCEEDED(hr)) {
  805. hr = (dwPolicy == URLPOLICY_JAVA_MEDIUM ||
  806. dwPolicy == URLPOLICY_JAVA_LOW ||
  807. dwPolicy == URLPOLICY_ALLOW) ? S_OK : HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED);
  808. }
  809. if (FAILED(hr)) {
  810. hr = GetActionPolicy(URLACTION_SHELL_INSTALL_DTITEMS, dwPolicy);
  811. if (SUCCEEDED(hr))
  812. hr = dwPolicy == URLPOLICY_DISALLOW ? HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED) : S_OK;
  813. }
  814. return hr;
  815. }
  816. HRESULT
  817. COleInstall::CanIInstallRPC(
  818. IN LPTSTR lpszPrinterUNC
  819. )
  820. /*++
  821. Routine Description:
  822. Examine Secuiry Policies to determine whether we should install the printer or not
  823. Arguments:
  824. lpszPrinterUNC - The UNC of the printer that we want to install
  825. Return Value:
  826. S_OK - Install via RPC
  827. S_FALSE - Install via Web Pnp
  828. HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED) - IE security does not allow this action
  829. Other HRESULT error code.
  830. --*/
  831. {
  832. DWORD dwPolicyJava;
  833. DWORD dwPolicyDTI;
  834. HRESULT hrRet = S_FALSE;
  835. HRESULT hr = GetActionPolicy(URLACTION_JAVA_PERMISSIONS, dwPolicyJava);
  836. _ASSERTE(lpszPrinterUNC);
  837. //
  838. // Before checking anything, we should check the HTTP install registry setting
  839. // If it is don;t even check the other stuff.
  840. //
  841. if (IsHttpPreferred())
  842. {
  843. hr = S_FALSE;
  844. goto Cleanup;
  845. }
  846. if (FAILED(hr))
  847. {
  848. // There is no JAVA Security Manager, or something went wrong,
  849. // then we decide whether to use Web PnP instead or just fail.
  850. hrRet = S_OK;
  851. }
  852. switch (dwPolicyJava)
  853. {
  854. case URLPOLICY_JAVA_LOW:
  855. case URLPOLICY_JAVA_MEDIUM:
  856. hr = S_OK;
  857. break;
  858. default: // We must do Web PnP
  859. hr = GetActionPolicy(URLACTION_SHELL_INSTALL_DTITEMS, dwPolicyDTI );
  860. if (FAILED(hr)) // Couldn't get the policy on installing Desk Top Items
  861. goto Cleanup;
  862. switch (dwPolicyDTI)
  863. {
  864. case URLPOLICY_ALLOW:
  865. case URLPOLICY_QUERY:
  866. hr = hrRet;
  867. break;
  868. case URLPOLICY_DISALLOW:
  869. hr = HRESULT_FROM_WIN32(ERROR_IE_SECURITY_DENIED);
  870. break;
  871. }
  872. }
  873. //
  874. // If it looks like we can install via RPC then check if the UNC is valid
  875. //
  876. if (S_OK == hr)
  877. {
  878. //
  879. // Find ther Server name from the UNC
  880. //
  881. LPTSTR pszServer = NULL;
  882. hr = GetServerNameFromUNC( lpszPrinterUNC, &pszServer );
  883. if (S_OK == hr)
  884. {
  885. hr = CheckServerForSpooler(pszServer);
  886. }
  887. if (pszServer)
  888. LocalFree(pszServer);
  889. }
  890. Cleanup:
  891. return hr;
  892. }
  893. /*++
  894. Routine Name:
  895. GetServerNameFromUNC
  896. Description:
  897. This returns the server name from the given UNC path
  898. Arguments:
  899. pszUNC - The UNC name,
  900. ppszServerName - The server name.
  901. Return Value:
  902. An HRESULT.
  903. --*/
  904. HRESULT
  905. COleInstall::GetServerNameFromUNC(
  906. IN LPTSTR pszUNC,
  907. OUT LPTSTR *ppszServerName
  908. )
  909. {
  910. HRESULT hr = pszUNC && ppszServerName ? S_OK : S_FALSE;
  911. PWSTR pszServer = NULL;
  912. if (S_OK==hr)
  913. {
  914. hr = *pszUNC++ == L'\\' && *pszUNC++ == L'\\' ? S_OK : S_FALSE;
  915. }
  916. if (S_OK==hr)
  917. {
  918. hr = AssignString(pszServer, pszUNC) ? S_OK : E_OUTOFMEMORY;
  919. }
  920. if (S_OK==hr)
  921. {
  922. PWSTR pszSlash = wcschr(&pszServer[0], L'\\');
  923. //
  924. // If there was no second slash, then what we have is the server name.
  925. //
  926. if (pszSlash)
  927. {
  928. *pszSlash = L'\0';
  929. }
  930. *ppszServerName = pszServer;
  931. pszServer = NULL;
  932. }
  933. LocalFree(pszServer);
  934. return hr;
  935. }
  936. HRESULT
  937. COleInstall::CheckServerForSpooler(
  938. IN LPTSTR pszServerName
  939. )
  940. {
  941. HRESULT hr;
  942. //
  943. // Build a string with the Server Name and the name of the spooler
  944. // named pipe
  945. //
  946. LPTSTR pszSpoolerPipe = NULL;
  947. DWORD dwStrLen = lstrlen(pszServerName) + lstrlen(g_fmtSpoolSSPipe) + 1;
  948. pszSpoolerPipe = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * dwStrLen);
  949. hr = pszSpoolerPipe ? S_OK : E_OUTOFMEMORY;
  950. if (SUCCEEDED(hr))
  951. {
  952. hr = StringCchPrintf(pszSpoolerPipe, dwStrLen, g_fmtSpoolSSPipe, pszServerName);
  953. }
  954. if (SUCCEEDED(hr))
  955. {
  956. //
  957. // Now try to connect to the pipe with Anonymous Access
  958. //
  959. HANDLE hSpoolerPipe = INVALID_HANDLE_VALUE;
  960. hSpoolerPipe = CreateFile(pszSpoolerPipe, 0, 0, NULL, OPEN_EXISTING,
  961. (FILE_ATTRIBUTE_NORMAL | SECURITY_ANONYMOUS), NULL);
  962. if (hSpoolerPipe != INVALID_HANDLE_VALUE)
  963. {
  964. // Pipe Exists try RPC
  965. hr = S_OK;
  966. CloseHandle(hSpoolerPipe);
  967. }
  968. else
  969. {
  970. // Check to see if failure is ACCESS_DENIED
  971. DWORD dwError = GetLastError();
  972. if (ERROR_ACCESS_DENIED == dwError)
  973. {
  974. // The pipe exists, but we don't have permissions
  975. hr = S_OK;
  976. }
  977. else
  978. hr = S_FALSE;
  979. }
  980. }
  981. if (pszSpoolerPipe)
  982. LocalFree(pszSpoolerPipe);
  983. return hr;
  984. }
  985. LPTSTR COleInstall::RemoveURLVars(IN LPTSTR lpszPrinter) {
  986. _ASSERTE(lpszPrinter);
  987. LPTSTR lpszStripped = NULL;
  988. DWORD dwIndex = _tcscspn( lpszPrinter, TEXT("?") );
  989. lpszStripped = (LPTSTR)LocalAlloc( LPTR, (dwIndex + 1) * sizeof(TCHAR) );
  990. if (NULL == lpszStripped)
  991. goto Cleanup;
  992. _tcsncpy( lpszStripped, lpszPrinter, dwIndex );
  993. lpszStripped[dwIndex] = NULL; // NULL terminate it.
  994. Cleanup:
  995. return lpszStripped;
  996. }
  997. /*
  998. Function: GetNTPrint
  999. Purpose: Returns a LPTSTR with the path to %windir%\inf\ntprint.inf
  1000. Caller must free the returned string.
  1001. */
  1002. LPTSTR
  1003. COleInstall::GetNTPrint(void)
  1004. {
  1005. UINT uiSize = 0;
  1006. UINT uiAllocSize = 0;
  1007. PTCHAR pData = NULL;
  1008. LPTSTR lpszNTPrintInf = NULL;
  1009. LPCTSTR gcszNTPrint = _TEXT("\\inf\\ntprint.inf");
  1010. //
  1011. // Get %windir%
  1012. // If the return is 0 - the call failed.
  1013. //
  1014. if( !(uiSize = GetSystemWindowsDirectory( lpszNTPrintInf, 0 )))
  1015. goto Cleanup;
  1016. uiAllocSize += uiSize + _tcslen( gcszNTPrint ) + 1;
  1017. if( NULL == (lpszNTPrintInf = (LPTSTR)LocalAlloc( LPTR, uiAllocSize*sizeof(TCHAR) )))
  1018. goto Cleanup;
  1019. if ( GetSystemWindowsDirectory( lpszNTPrintInf, uiSize ) > uiSize )
  1020. {
  1021. LocalFree(lpszNTPrintInf);
  1022. lpszNTPrintInf = NULL;
  1023. goto Cleanup;
  1024. }
  1025. //
  1026. // Determine if we have a \ on the end remove it.
  1027. //
  1028. pData = &lpszNTPrintInf[ _tcslen(lpszNTPrintInf)-1 ];
  1029. if( *pData == _TEXT('\\') )
  1030. *pData = 0;
  1031. //
  1032. // Copy the inf\ntprint.inf string onto the end of the %windir%\ string.
  1033. //
  1034. StringCchCat( lpszNTPrintInf, uiAllocSize, gcszNTPrint );
  1035. Cleanup:
  1036. return lpszNTPrintInf;
  1037. }
  1038. //
  1039. // Creates the printer base name from the printerURL and printer name.
  1040. // Form is : "\\http://url\printer name"
  1041. //
  1042. LPTSTR
  1043. COleInstall::CreatePrinterBaseName(
  1044. LPCTSTR lpszPrinterURL,
  1045. LPCTSTR lpszPrinterName
  1046. )
  1047. {
  1048. LPTSTR lpszFullPrinterName = NULL;
  1049. PTCHAR pWhack = NULL,
  1050. pFriendlyName = NULL;
  1051. DWORD cchBufSize = 0;
  1052. //
  1053. // lpszPrinterName should be of the form "server\printer name"
  1054. // We need to get only the "printer name" part.
  1055. //
  1056. if( NULL != ( pFriendlyName = _tcsrchr( lpszPrinterName, _TEXT('\\') ))) {
  1057. //
  1058. // Move off the \
  1059. //
  1060. pFriendlyName++;
  1061. } else {
  1062. pFriendlyName = (PTCHAR)lpszPrinterName;
  1063. }
  1064. //
  1065. // Worst case size - the size of the two strings plus the "\\" plus "\" and
  1066. // a NULL terminator
  1067. //
  1068. cchBufSize = lstrlen(lpszPrinterURL) + lstrlen(pFriendlyName) + 4;
  1069. lpszFullPrinterName = (LPTSTR)LocalAlloc( LPTR, cchBufSize * sizeof(TCHAR) );
  1070. if( lpszFullPrinterName ){
  1071. StringCchCopy( lpszFullPrinterName, cchBufSize, _TEXT("\\\\") );
  1072. StringCchCat( lpszFullPrinterName, cchBufSize, lpszPrinterURL );
  1073. pWhack = _tcschr( lpszFullPrinterName, _TEXT('/') );
  1074. if( pWhack ) {
  1075. if( *(pWhack+1) == _TEXT('/') ) {
  1076. //
  1077. // We've got a //, find the next /
  1078. //
  1079. pWhack = _tcschr( pWhack+2, _TEXT('/') );
  1080. }
  1081. }
  1082. if( !pWhack ) {
  1083. pWhack = &lpszFullPrinterName[ lstrlen( lpszFullPrinterName ) ];
  1084. }
  1085. *pWhack++ = _TEXT('\\');
  1086. *pWhack = 0;
  1087. StringCchCat( lpszFullPrinterName, cchBufSize, pFriendlyName );
  1088. }
  1089. return lpszFullPrinterName;
  1090. }
  1091. /****************************************************************************************
  1092. ** End of File (oleinst.cpp)
  1093. ****************************************************************************************/