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.

410 lines
11 KiB

  1. #include "inspch.h"
  2. #include "insobj.h"
  3. //=--------------------------------------------------------------------------=
  4. // Function name here
  5. //=--------------------------------------------------------------------------=
  6. // Function description
  7. //
  8. // Parameters:
  9. //
  10. // Returns:
  11. //
  12. // Notes:
  13. //
  14. CInstaller::CInstaller(CInstallEngine *p) : CTimeTracker(60000)
  15. {
  16. _pInsEng = p;
  17. _hkProg = NULL;
  18. _hMutex = NULL;
  19. _hStatus = NULL;
  20. _cRef = 1;
  21. DllAddRef();
  22. }
  23. CInstaller::~CInstaller()
  24. {
  25. DllRelease();
  26. }
  27. //=--------------------------------------------------------------------------=
  28. // Function name here
  29. //=--------------------------------------------------------------------------=
  30. // Function description
  31. //
  32. // Parameters:
  33. //
  34. // Returns:
  35. //
  36. // Notes:
  37. //
  38. STDMETHODIMP_(ULONG) CInstaller::AddRef()
  39. {
  40. return(++_cRef);
  41. }
  42. //=--------------------------------------------------------------------------=
  43. // Function name here
  44. //=--------------------------------------------------------------------------=
  45. // Function description
  46. //
  47. // Parameters:
  48. //
  49. // Returns:
  50. //
  51. // Notes:
  52. //
  53. STDMETHODIMP_(ULONG) CInstaller::Release()
  54. {
  55. if(!--_cRef)
  56. {
  57. delete this;
  58. return(0);
  59. }
  60. return( _cRef );
  61. }
  62. HRESULT CInstaller::Abort()
  63. {
  64. if(_hMutex)
  65. {
  66. WaitForMutex(_hMutex);
  67. if(_hkProg)
  68. {
  69. DWORD dwCancel = 1;
  70. RegSetValueEx(_hkProg, CANCEL_VALUENAME, 0, REG_DWORD, (BYTE *) &dwCancel, sizeof(dwCancel));
  71. }
  72. ReleaseMutex(_hMutex);
  73. }
  74. return NOERROR;
  75. }
  76. HRESULT CInstaller::Suspend()
  77. {
  78. // assume no install going on
  79. HRESULT hr = S_OK;
  80. // if we have a mutex grab it and check for safe
  81. if(_hMutex)
  82. {
  83. // there is an install, assume it isn't safe to cancel it
  84. hr = S_FALSE;
  85. WaitForMutex(_hMutex);
  86. if(_hkProg)
  87. {
  88. DWORD dwSafe = 0;
  89. DWORD dwSize = sizeof(dwSafe);
  90. if(RegQueryValueEx(_hkProg, SAFE_VALUENAME, NULL, NULL, (BYTE *) &dwSafe, &dwSize) == ERROR_SUCCESS)
  91. {
  92. if(dwSafe == 1)
  93. hr = S_OK;
  94. }
  95. }
  96. }
  97. return hr;
  98. }
  99. HRESULT CInstaller::Resume()
  100. {
  101. // if we have a mutex release it
  102. if(_hMutex)
  103. ReleaseMutex(_hMutex);
  104. return NOERROR;
  105. }
  106. HRESULT CInstaller::DoInstall(LPCSTR pszDir, LPSTR pszCmd, LPSTR pszArgs, LPCSTR pszProg, LPCSTR pszCancel,
  107. UINT uType, LPDWORD pdwStatus, IMyDownloadCallback *pcb)
  108. {
  109. char szFileName[MAX_PATH + 128];
  110. char szBuf[MAX_PATH];
  111. HANDLE hProc = NULL;
  112. HMODULE hAdvpack;
  113. HRESULT hr = S_OK;
  114. DWORD dwTemp;
  115. INF_ARGUEMENTS InsArgs;
  116. _uTotalProgress = 0;
  117. // create progress key if we need to
  118. if(pszProg && pszCancel)
  119. {
  120. lstrcpy(szBuf, REGSTR_PROGRESS_KEY);
  121. lstrcat(szBuf, pszProg);
  122. RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, NULL,0, KEY_READ | KEY_WRITE,NULL, &_hkProg, &dwTemp);
  123. lstrcpy(szBuf, pszCancel);
  124. lstrcat(szBuf, "Mutex");
  125. _hMutex = CreateMutex(NULL, FALSE, szBuf);
  126. lstrcpy(szBuf, pszCancel);
  127. lstrcat(szBuf, "Event");
  128. _hStatus = CreateEvent(NULL, FALSE, FALSE, szBuf);
  129. }
  130. // copy the advpack we are using into the temp dir of what we want to launch
  131. // this insures that we always get a "good" copy of advpack
  132. hAdvpack = GetModuleHandle("advpack.dll");
  133. if(hAdvpack)
  134. {
  135. if(GetModuleFileName(hAdvpack, szBuf, sizeof(szBuf)))
  136. {
  137. lstrcpy(szFileName, pszDir);
  138. AddPath(szFileName, "advpack.dll");
  139. CopyFile(szBuf, szFileName, TRUE);
  140. szBuf[0] = 0;
  141. szFileName[0] = 0;
  142. }
  143. }
  144. switch(uType)
  145. {
  146. case InfCommand:
  147. case InfExCommand:
  148. GetStringField(pszCmd, 0, szBuf, sizeof(szBuf));
  149. // ParseURLA below is to ensure we only run inf out of our temp dir
  150. lstrcpy(szFileName, pszDir);
  151. AddPath(szFileName, ParseURLA(szBuf));
  152. GetStringField(pszCmd, 1, szBuf, sizeof(szBuf));
  153. lstrcpy(InsArgs.szInfname, szFileName);
  154. lstrcpy(InsArgs.szSection, szBuf);
  155. lstrcpy(InsArgs.szDir, pszDir);
  156. InsArgs.dwType = uType;
  157. if(uType == InfCommand)
  158. {
  159. InsArgs.dwFlags = RSC_FLAG_INF | RSC_FLAG_NGCONV;
  160. if(_pInsEng->GetCommandMode() == 0)
  161. InsArgs.dwFlags |= RSC_FLAG_QUIET;
  162. }
  163. if(uType == InfExCommand)
  164. {
  165. // add cab name
  166. lstrcpy(InsArgs.szCab, "");
  167. InsArgs.dwFlags = AtoL(pszArgs);
  168. }
  169. if(_pInsEng->GetStatus() & STOPINSTALL_REBOOTNEEDED)
  170. InsArgs.dwFlags |= RSC_FLAG_DELAYREGISTEROCX;
  171. wsprintf(szLogBuf, "Launching Inf - inf: %s, section: %s\r\n", szFileName, lstrlen(szBuf) ? szBuf : "Default");
  172. _pInsEng->WriteToLog(szLogBuf, TRUE);
  173. hProc = CreateThread(NULL, 0, LaunchInfCommand, &InsArgs, 0, &dwTemp);
  174. hr = E_FAIL;
  175. if(hProc)
  176. {
  177. _WaitAndPumpProgress(hProc, pcb);
  178. DWORD dwRet;
  179. if(GetExitCodeThread(hProc, &dwRet))
  180. {
  181. hr = dwRet;
  182. if(SUCCEEDED(hr))
  183. {
  184. if(hr == ERROR_SUCCESS_REBOOT_REQUIRED)
  185. *pdwStatus |= STOPINSTALL_REBOOTNEEDED;
  186. }
  187. else
  188. {
  189. wsprintf(szLogBuf, "Inf failed - return code %x\r\n", dwRet);
  190. _pInsEng->WriteToLog(szLogBuf, TRUE);
  191. }
  192. }
  193. else
  194. _pInsEng->WriteToLog("Failed to get exit code\r\n", TRUE);
  195. }
  196. else
  197. _pInsEng->WriteToLog("Create thread failed\r\n", TRUE);
  198. break;
  199. case WExtractExe:
  200. case Win32Exe:
  201. case HRESULTWin32Exe:
  202. // ParseURLA below is to ensure we only run exe out of our temp dir
  203. wsprintf(szFileName, CMDLINE, pszDir, ParseURLA(pszCmd), pszArgs);
  204. wsprintf(szLogBuf, "Launching exe: command: %s\r\n", szFileName);
  205. _pInsEng->WriteToLog(szLogBuf, TRUE);
  206. hr = LaunchProcess(szFileName, &hProc, pszDir, SW_SHOWNORMAL);
  207. if(SUCCEEDED(hr))
  208. _WaitAndPumpProgress(hProc, pcb);
  209. if(SUCCEEDED(hr))
  210. {
  211. // BUGBUG: Trace this path with WEXTRACT > 1140
  212. if ( (uType == WExtractExe) || (uType == HRESULTWin32Exe) )
  213. {
  214. DWORD dwRet;
  215. hr = E_FAIL;
  216. if(GetExitCodeProcess(hProc, &dwRet))
  217. {
  218. wsprintf(szLogBuf, "Exe return code: %x\r\n", dwRet);
  219. _pInsEng->WriteToLog(szLogBuf, TRUE);
  220. hr = (HRESULT) dwRet;
  221. if (uType == WExtractExe)
  222. {
  223. if(SUCCEEDED(hr))
  224. {
  225. if(hr == ERROR_SUCCESS_REBOOT_REQUIRED)
  226. *pdwStatus |= STOPINSTALL_REBOOTNEEDED;
  227. }
  228. }
  229. }
  230. else
  231. _pInsEng->WriteToLog("Failed to get exit code\r\n", TRUE);
  232. }
  233. }
  234. else
  235. _pInsEng->WriteToLog("Create process failed\r\n", TRUE);
  236. break;
  237. default:
  238. // whatever
  239. hr = E_INVALIDARG;
  240. }
  241. if (_hkProg)
  242. {
  243. RegCloseKey(_hkProg);
  244. _hkProg = NULL;
  245. }
  246. if (_hMutex)
  247. {
  248. CloseHandle(_hMutex);
  249. _hMutex = NULL;
  250. }
  251. if (_hStatus)
  252. {
  253. CloseHandle(_hStatus);
  254. _hStatus = NULL;
  255. }
  256. return hr;
  257. }
  258. #define PROGRESS_INTERVAL 1000
  259. #define SEARCHFORCONFLICT_INTERVAL 3
  260. void CInstaller::_WaitAndPumpProgress(HANDLE hProc, IMyDownloadCallback *pcb)
  261. {
  262. HANDLE pHandles[2] = {hProc, _hStatus};
  263. DWORD dwStartTick = GetTickCount();
  264. DWORD dwOldTick = dwStartTick;
  265. DWORD dwTickChange = 0;
  266. DWORD dwProgress;
  267. DWORD dwCurrentTick;
  268. BOOL fQuit = FALSE;
  269. DWORD dwRet;
  270. DWORD dwSearchCount = 0;
  271. HWND hLastVersionConflict = NULL;
  272. HWND hVersionConflict = NULL;
  273. while(!fQuit)
  274. {
  275. dwRet = MsgWaitForMultipleObjects(_hStatus ? 2 : 1, pHandles, FALSE, 1000, QS_ALLINPUT);
  276. dwCurrentTick = GetTickCount();
  277. dwTickChange = dwCurrentTick - dwOldTick;
  278. if(dwOldTick > dwCurrentTick)
  279. dwTickChange = ~dwTickChange;
  280. if(dwTickChange > PROGRESS_INTERVAL)
  281. {
  282. dwSearchCount++;
  283. if(dwSearchCount > SEARCHFORCONFLICT_INTERVAL || hLastVersionConflict)
  284. {
  285. hVersionConflict = GetVersionConflictHWND();
  286. if(hVersionConflict)
  287. {
  288. if(hVersionConflict != hLastVersionConflict)
  289. {
  290. if(GetForegroundWindow() == _pInsEng->GetHWND())
  291. SetForegroundWindow(hVersionConflict);
  292. BOOL foo = MessageBeep(MB_ICONASTERISK);
  293. }
  294. }
  295. hLastVersionConflict = hVersionConflict;
  296. dwSearchCount = 0;
  297. }
  298. // if there is a version conflict, we assume you made no progress during the last time period
  299. if(!hLastVersionConflict)
  300. {
  301. dwProgress = (dwTickChange / 1000) * GetBytesPerSecond();
  302. dwProgress >>= 10;
  303. _uTotalProgress += dwProgress;
  304. pcb->OnProgress(_uTotalProgress, NULL);
  305. }
  306. dwOldTick = dwCurrentTick;
  307. }
  308. // Handle Message or done
  309. if(dwRet == WAIT_OBJECT_0)
  310. {
  311. fQuit = TRUE;
  312. }
  313. else if ( (dwRet == WAIT_OBJECT_0 + 1) && (_hStatus != 0)) // update jobexec's status msg
  314. {
  315. if (!(fQuit = WaitForMutex(_hMutex)))
  316. {
  317. if (_hkProg != NULL)
  318. {
  319. char szBuf[MAX_PATH];
  320. DWORD dwSize = sizeof(szBuf);
  321. if (RegQueryValueEx(_hkProg, PROGRESS_DISPLAY, NULL, NULL, (LPBYTE) szBuf, &dwSize) == ERROR_SUCCESS)
  322. pcb->OnProgress(_uTotalProgress, szBuf);
  323. }
  324. ReleaseMutex(_hMutex);
  325. }
  326. }
  327. else
  328. {
  329. MSG msg;
  330. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  331. {
  332. // if it's a quit message we're out of here
  333. if (msg.message == WM_QUIT)
  334. fQuit = TRUE;
  335. else
  336. {
  337. // otherwise dispatch it
  338. DispatchMessage(&msg);
  339. } // end of PeekMessage while loop
  340. }
  341. }
  342. }
  343. }