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.

230 lines
8.4 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. clusupg.cxx
  6. Purpose:
  7. Upgrade printer drivers for clusters spoolers
  8. Author:
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /*++
  14. Routine Name:
  15. PSetupUpgradeClusterDriversW
  16. Routine Description:
  17. Upgrade function. Called by a cluster spooler to upgrade its drivers. This function
  18. is called the first time when the cluster spooler fails over to a node that was
  19. upgraded. SplCreatespooler spins a thread executing SplCreateSpoolerWorkerThread.
  20. So SplCreateSpoolerWorkerThread runs in the context of the spooler process, which
  21. is local system. This function then creates a rundll32 process (with CreateProcess)
  22. that invokes PSetupUpgradeClusterDrivers and thus runs in local system context.
  23. PSetupUpgradeClusterDrivers enumerates all the printer drivers, loads printui.dll
  24. and calls the function PrintUIEntryW in printui.dll.
  25. Arguments:
  26. hwnd - Window handle of stub window.
  27. hInstance, - Rundll instance handle.
  28. pszCmdLine - Pointer to command line.
  29. nCmdShow - Show command value always TRUE.
  30. Return Value:
  31. Returns the last error code. This can be read by the spooler by getting the return code from the process.
  32. --*/
  33. DWORD
  34. PSetupUpgradeClusterDriversW(
  35. IN HWND hWnd,
  36. IN HINSTANCE hInstance,
  37. IN LPCTSTR pszCmdLine,
  38. IN UINT nCmdShow
  39. )
  40. {
  41. LPBYTE pDriverEnum = NULL;
  42. DWORD cbNeeded;
  43. DWORD cStrucs;
  44. DWORD dwError = ERROR_INVALID_PARAMETER;
  45. LPTSTR pszServer = const_cast<LPTSTR>(pszCmdLine);
  46. if (pszServer)
  47. {
  48. //
  49. // Enumerate all the drivers on the server
  50. //
  51. dwError = EnumPrinterDrivers(pszServer,
  52. _T("all"),
  53. 6,
  54. NULL,
  55. 0,
  56. &cbNeeded,
  57. &cStrucs) ? ERROR_SUCCESS : GetLastError();
  58. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  59. {
  60. if (pDriverEnum = static_cast<LPBYTE>(LocalAllocMem(cbNeeded)))
  61. {
  62. if (EnumPrinterDrivers(pszServer,
  63. _T("all"),
  64. 6,
  65. pDriverEnum,
  66. cbNeeded,
  67. &cbNeeded,
  68. &cStrucs))
  69. {
  70. dwError = ERROR_SUCCESS;
  71. }
  72. else
  73. {
  74. LocalFreeMem(pDriverEnum);
  75. pDriverEnum = NULL;
  76. dwError = GetLastError();
  77. }
  78. }
  79. else
  80. {
  81. dwError = GetLastError();
  82. }
  83. }
  84. if (dwError==ERROR_SUCCESS && cStrucs)
  85. {
  86. DRIVER_INFO_6 *pDrv = NULL;
  87. UINT uIndex = 0;
  88. HINSTANCE hLibrary = NULL;
  89. typedef (* PFNENTRY)(HWND, HINSTANCE, LPCTSTR, UINT);
  90. PFNENTRY pfnEntry;
  91. //
  92. // Load printui and get the entry point
  93. //
  94. if ((hLibrary = LoadLibraryUsingFullPath(_T("printui.dll"))) &&
  95. (pfnEntry = (PFNENTRY)GetProcAddress(hLibrary, "PrintUIEntryW"))
  96. )
  97. {
  98. //
  99. // Loop through drivers and try to upgrade them using the cab
  100. //
  101. for (uIndex = 0, pDrv=reinterpret_cast<LPDRIVER_INFO_6>(pDriverEnum);
  102. dwError == ERROR_SUCCESS && uIndex < cStrucs;
  103. uIndex++, pDrv++
  104. )
  105. {
  106. TString strCommand;
  107. DWORD cbNeeded = 0;
  108. LPCTSTR pszFormat = _T("/q /Gw /ia /K /c \"%ws\" /m \"%ws\" /h \"%ws\" /v %u");
  109. //
  110. // Format the string that will be used as aparameter for printui
  111. //
  112. if (strCommand.bFormat(pszFormat, pszServer, pDrv->pName, pDrv->pEnvironment, pDrv->cVersion))
  113. {
  114. //
  115. // The printer we install will never have a print processor associated
  116. // with it.
  117. // The call into printui goes thrgouh the following path:
  118. // PSetupUpgradeClusterDriversW -> PrintUIEntryW -> bDoCommand ->
  119. // bExecuteCommand( XX, kInstallDriverWithInf, XX ) -> bDoInfPrinterInstall ->
  120. // PnPInterface(kInfInstall, XX) -> bInfInstall
  121. //
  122. //
  123. // This will try to upgrade the driver/ We don't care about the error. Even if a driver
  124. // couldn't be upgraded, we still want to loop and try to upgrade the other drivers
  125. //
  126. dwError = (pfnEntry)(hWnd, hInstance, strCommand, 0);
  127. DBGMSG(DBG_WARN, ("Command %ws dwError from printui %u\n", (LPCTSTR)strCommand, dwError));
  128. //
  129. // The case statements reperesent errors where we cannot continue executing the
  130. // printer driver update. This is when the spooler dies or the cluster group
  131. // becomes active on a different node
  132. //
  133. switch (dwError)
  134. {
  135. case RPC_S_SERVER_UNAVAILABLE:
  136. //
  137. // We can get access deined when the cluster group moves to a different node.
  138. // Since this process executes in the local system acocunt, this account doesn't
  139. // have permissins to install printer drivers on a remote machine
  140. //
  141. case ERROR_ACCESS_DENIED:
  142. //
  143. // The spooler returns this error when it cannot create temporary directories
  144. // for driver upgrade
  145. //
  146. case ERROR_NO_SYSTEM_RESOURCES:
  147. //
  148. // printui returns this error when it cannot do OpenPrinter(\\server name).
  149. // This means the cluster group is off line (inaccessible)
  150. //
  151. case ERROR_INVALID_PRINTER_NAME:
  152. //
  153. // We will exit the loop since dwError is not error success
  154. //
  155. break;
  156. default:
  157. //
  158. // We continue looping
  159. //
  160. dwError = ERROR_SUCCESS;
  161. }
  162. }
  163. }
  164. }
  165. else
  166. {
  167. dwError = GetLastError();
  168. }
  169. if (hLibrary)
  170. {
  171. FreeLibrary(hLibrary);
  172. }
  173. }
  174. LocalFreeMem(pDriverEnum);
  175. pDriverEnum = NULL;
  176. }
  177. DBGMSG(DBG_WARN, ("PSetupClusterDrivers Error %u \n", dwError));
  178. //
  179. // If an error occurs we call ExitProcess. Then the spooler picks up the
  180. // error code using GetExitCodeProcess. If no error occurs, then we
  181. // terminate normally
  182. //
  183. if (dwError != ERROR_SUCCESS)
  184. {
  185. ExitProcess(dwError);
  186. }
  187. return dwError;
  188. }