Source code of Windows XP (NT5)
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.

509 lines
15 KiB

  1. #include "stdinc.h"
  2. #include "dbt.h"
  3. #include "devguid.h"
  4. #include "dialogs.h"
  5. #include "CAssemblyRecoveryInfo.h"
  6. #include "protectionui.h"
  7. #include "recover.h"
  8. #include "SxsExceptionHandling.h"
  9. //
  10. // FAKERY
  11. //
  12. extern HINSTANCE g_hInstance;
  13. extern HANDLE g_hSxsLoginEvent;
  14. HDESK g_hDesktop = NULL;
  15. BOOL
  16. SxspSpinUntilValidDesktop()
  17. {
  18. FN_PROLOG_WIN32
  19. //
  20. // NTRAID#NTBUG9-219455-2000/12/13-MGrier Postponed to Blackcomb; the
  21. // current code does the same thing that WFP is doing; it's just that
  22. // we should really have them pass us the desktop.
  23. //
  24. // We should be relying on what WFP has already
  25. // found to be the 'proper' input desktop. Doing so, however requires a
  26. // change to the interface between SXS and SFC to pass along a pointer to
  27. // the WFP desktop handle. Not a bad thing, just .. not implemented yet.
  28. //
  29. while (g_hDesktop == NULL)
  30. {
  31. DWORD dwResult = ::WaitForSingleObject(g_hSxsLoginEvent, INFINITE);
  32. if (dwResult == WAIT_OBJECT_0)
  33. IFW32NULL_ORIGINATE_AND_EXIT(g_hDesktop = ::OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED));
  34. else if (dwResult == WAIT_FAILED)
  35. ORIGINATE_WIN32_FAILURE_AND_EXIT(WaitForSingleObject, ::FusionpGetLastWin32Error());
  36. }
  37. FN_EPILOG
  38. }
  39. CSXSMediaPromptDialog::CSXSMediaPromptDialog()
  40. : m_hOurWnd((HWND)INVALID_HANDLE_VALUE),
  41. m_pvDeviceChange(NULL),
  42. m_uiAutoRunMsg(0),
  43. m_DeviceChangeMask(0),
  44. m_DeviceChangeFlags(0),
  45. m_fIsCDROM(false),
  46. m_CodebaseInfo(NULL)
  47. {
  48. }
  49. CSXSMediaPromptDialog::~CSXSMediaPromptDialog()
  50. {
  51. }
  52. BOOL
  53. CSXSMediaPromptDialog::Initialize(
  54. const CCodebaseInformation* CodebaseInfo
  55. )
  56. {
  57. BOOL fSuccess = FALSE;
  58. FN_TRACE_WIN32(fSuccess);
  59. PARAMETER_CHECK(CodebaseInfo != NULL);
  60. SxsWFPResolveCodebase CodebaseType;
  61. IFW32FALSE_EXIT(CodebaseInfo->Win32GetType(CodebaseType));
  62. PARAMETER_CHECK(
  63. (CodebaseType == CODEBASE_RESOLVED_URLHEAD_FILE) ||
  64. (CodebaseType == CODEBASE_RESOLVED_URLHEAD_WINSOURCE) ||
  65. (CodebaseType == CODEBASE_RESOLVED_URLHEAD_CDROM));
  66. m_CodebaseInfo = CodebaseInfo;
  67. switch (CodebaseType)
  68. {
  69. case CODEBASE_RESOLVED_URLHEAD_CDROM:
  70. m_fIsCDROM = true;
  71. break;
  72. case CODEBASE_RESOLVED_URLHEAD_WINSOURCE:
  73. {
  74. CFusionRegKey hkSetupInfo;
  75. DWORD dwWasFromCDRom;
  76. IFREGFAILED_ORIGINATE_AND_EXIT(
  77. ::RegOpenKeyExW(
  78. HKEY_LOCAL_MACHINE,
  79. WINSXS_INSTALL_SOURCE_BASEDIR,
  80. 0,
  81. KEY_READ | FUSIONP_KEY_WOW64_64KEY,
  82. &hkSetupInfo));
  83. if (!::FusionpRegQueryDwordValueEx(
  84. 0,
  85. hkSetupInfo,
  86. WINSXS_INSTALL_SOURCE_IS_CDROM,
  87. &dwWasFromCDRom))
  88. {
  89. dwWasFromCDRom = 0;
  90. }
  91. m_fIsCDROM = (dwWasFromCDRom != 0);
  92. break;
  93. }
  94. case CODEBASE_RESOLVED_URLHEAD_FILE:
  95. {
  96. CSmallStringBuffer buffVolumePathName;
  97. IFW32FALSE_EXIT(
  98. ::SxspGetVolumePathName(
  99. 0,
  100. CodebaseInfo->GetCodebase(),
  101. buffVolumePathName));
  102. if (::GetDriveTypeW(buffVolumePathName) == DRIVE_CDROM)
  103. {
  104. m_fIsCDROM = true;
  105. }
  106. break;
  107. }
  108. }
  109. FN_EPILOG
  110. }
  111. BOOL
  112. CSXSMediaPromptDialog::DisplayMessage(
  113. HWND hDlg,
  114. UINT uContentText,
  115. UINT uDialogFlags,
  116. int &riResult
  117. )
  118. {
  119. FN_PROLOG_WIN32
  120. WCHAR wcTitle[MAX_PATH*2];
  121. WCHAR wcContent[MAX_PATH*2];
  122. int iResult = 0;
  123. IFW32ZERO_ORIGINATE_AND_EXIT(::LoadStringW(g_hInstance, uContentText, wcContent, NUMBER_OF(wcContent)));
  124. IFW32ZERO_ORIGINATE_AND_EXIT(::LoadStringW(g_hInstance, IDS_TITLE, wcTitle, NUMBER_OF(wcTitle)));
  125. IFW32ZERO_ORIGINATE_AND_EXIT(iResult = ::MessageBoxW(hDlg, wcContent, wcTitle, uDialogFlags));
  126. riResult = iResult;
  127. FN_EPILOG
  128. }
  129. BOOL
  130. CSXSMediaPromptDialog::ShowSelf(
  131. CSXSMediaPromptDialog::DialogResults &rResult
  132. )
  133. {
  134. FN_PROLOG_WIN32
  135. INT_PTR i;
  136. IFW32FALSE_EXIT(::SxspSpinUntilValidDesktop());
  137. IFW32FALSE_ORIGINATE_AND_EXIT(::SetThreadDesktop(g_hDesktop));
  138. i = ::DialogBoxParamW(
  139. g_hInstance,
  140. MAKEINTRESOURCEW(
  141. m_fIsCDROM ?
  142. IDD_SFC_CD_PROMPT :
  143. IDD_SFC_NETWORK_PROMPT),
  144. NULL,
  145. &CSXSMediaPromptDialog::OurDialogProc,
  146. (LPARAM)this);
  147. if (i == -1)
  148. ORIGINATE_WIN32_FAILURE_AND_EXIT(DialogBoxParamW, ::FusionpGetLastWin32Error());
  149. rResult = static_cast<DialogResults>(i);
  150. FN_EPILOG
  151. }
  152. BOOL
  153. SxspFindInstallWindowsSourcePath(
  154. OUT CBaseStringBuffer &rbuffTempStringBuffer
  155. )
  156. {
  157. FN_PROLOG_WIN32
  158. CFusionRegKey rhkInstallSource;
  159. rbuffTempStringBuffer.Clear();
  160. IFREGFAILED_ORIGINATE_AND_EXIT(
  161. ::RegOpenKeyExW(
  162. HKEY_LOCAL_MACHINE,
  163. WINSXS_INSTALL_SOURCE_BASEDIR,
  164. 0,
  165. KEY_READ | FUSIONP_KEY_WOW64_64KEY,
  166. &rhkInstallSource));
  167. IFW32FALSE_EXIT(
  168. ::FusionpRegQuerySzValueEx(
  169. FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING,
  170. rhkInstallSource,
  171. WINSXS_INSTALL_SOURCEPATH_REGKEY,
  172. rbuffTempStringBuffer));
  173. //
  174. // Now let's be really cheesy and find the fourth slash (\\foo\bar\), and
  175. // clip everything after that.
  176. //
  177. PCWSTR cursor = rbuffTempStringBuffer;
  178. ULONG ulSlashCount = 0;
  179. while ( *cursor && ulSlashCount < 4 )
  180. {
  181. if (*cursor == L'\\')
  182. ulSlashCount++;
  183. cursor++;
  184. }
  185. //
  186. // If we got 3 or less, then it's \\foo\bar or \\foo, which should be
  187. // illegal. Otherwise, clip everything off past this point.
  188. //
  189. if (ulSlashCount > 3)
  190. {
  191. rbuffTempStringBuffer.Left(cursor - rbuffTempStringBuffer);
  192. rbuffTempStringBuffer.RemoveTrailingPathSeparators();
  193. }
  194. FN_EPILOG
  195. }
  196. INT_PTR
  197. CALLBACK
  198. CSXSMediaPromptDialog::OurDialogProc(
  199. HWND hDlg,
  200. UINT uMsg,
  201. WPARAM wParam,
  202. LPARAM lParam
  203. )
  204. {
  205. FN_TRACE();
  206. INT_PTR iResult = 0;
  207. int iMessageBoxResult = 0;
  208. #define WM_TRYAGAIN (WM_USER + 1)
  209. static CSXSMediaPromptDialog *pThis = NULL;
  210. switch (uMsg)
  211. {
  212. case WM_INITDIALOG:
  213. {
  214. pThis = reinterpret_cast<CSXSMediaPromptDialog *>(lParam);
  215. FLASHWINFO winfo;
  216. ASSERT(pThis != NULL);
  217. ASSERT(pThis->m_hOurWnd == INVALID_HANDLE_VALUE);
  218. pThis->m_hOurWnd = hDlg;
  219. //
  220. // Center the window, bring it forward
  221. //
  222. {
  223. RECT rcWindow;
  224. LONG x, y, w, h;
  225. ::GetWindowRect(hDlg, &rcWindow); // error check?
  226. w = rcWindow.right - rcWindow.left + 1;
  227. h = rcWindow.bottom - rcWindow.top + 1;
  228. x = (::GetSystemMetrics(SM_CXSCREEN) - w) / 2; // error check?
  229. y = (::GetSystemMetrics(SM_CYSCREEN) - h) / 2; // error check?
  230. ::MoveWindow(hDlg, x, y, w, h, FALSE); // error check?
  231. winfo.cbSize = sizeof(winfo);
  232. winfo.hwnd = hDlg;
  233. winfo.dwFlags = FLASHW_ALL;
  234. winfo.uCount = 3;
  235. winfo.dwTimeout = 0;
  236. ::SetForegroundWindow(hDlg); // error check?
  237. ::FlashWindowEx(&winfo); // error check?
  238. }
  239. //
  240. // Create the device-change notification
  241. //
  242. if (pThis->m_pvDeviceChange == NULL)
  243. {
  244. DEV_BROADCAST_DEVICEINTERFACE_W FilterData = { 0 };
  245. FilterData.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  246. FilterData.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  247. FilterData.dbcc_classguid = GUID_DEVCLASS_CDROM;
  248. IFW32NULL_ORIGINATE_AND_EXIT(
  249. // Change this to RegisterDeviceNotificationW in Blackcomb.
  250. pThis->m_pvDeviceChange = ::RegisterDeviceNotification(
  251. hDlg,
  252. &FilterData,
  253. DEVICE_NOTIFY_WINDOW_HANDLE));
  254. }
  255. //
  256. // Turn off autorun
  257. //
  258. IFW32ZERO_ORIGINATE_AND_EXIT(pThis->m_uiAutoRunMsg = ::RegisterWindowMessageW(L"QueryCancelAutoPlay"));
  259. //
  260. // Fidget with the text in the popup dialog now
  261. //
  262. {
  263. CSmallStringBuffer sbFormatter;
  264. CSmallStringBuffer buffFormattedText;
  265. CStringBufferAccessor acc;
  266. //
  267. // It is ok if these memory allocations fail, the ui will degrade.
  268. // As well, that's a reason to leave the buffers "small" and not "tiny".
  269. // ?
  270. //
  271. sbFormatter.Win32ResizeBuffer(512, eDoNotPreserveBufferContents);
  272. buffFormattedText.Win32ResizeBuffer(512, eDoNotPreserveBufferContents);
  273. //
  274. // Set the "Insert your .... now"
  275. //
  276. sbFormatter.Clear();
  277. acc.Attach(&sbFormatter);
  278. ::GetDlgItemTextW( // error check?
  279. hDlg,
  280. IDC_MEDIA_NAME,
  281. acc,
  282. static_cast<DWORD>(sbFormatter.GetBufferCch()));
  283. acc.Detach();
  284. if (pThis->m_CodebaseInfo->GetPromptText().Cch() != 0)
  285. {
  286. IFW32FALSE_EXIT(buffFormattedText.Win32Format(
  287. sbFormatter,
  288. static_cast<PCWSTR>(pThis->m_CodebaseInfo->GetPromptText())));
  289. ::SetDlgItemTextW(hDlg, IDC_MEDIA_NAME, static_cast<PCWSTR>(buffFormattedText)); // error check?
  290. }
  291. else
  292. {
  293. #if DBG
  294. ::FusionpDbgPrintEx(
  295. FUSION_DBG_LEVEL_WFP,
  296. "SXS: %s - setting IDC_MEDIA_NAME to empty\n", __FUNCTION__);
  297. #endif
  298. ::SetDlgItemTextW(hDlg, IDC_MEDIA_NAME, L""); // error check?
  299. }
  300. //
  301. // Now, depending on what kind of box this is..
  302. //
  303. if (!pThis->m_fIsCDROM)
  304. {
  305. CSmallStringBuffer buffTempStringBuffer;
  306. SxsWFPResolveCodebase CodebaseType;
  307. sbFormatter.Clear();
  308. acc.Attach(&sbFormatter);
  309. ::GetDlgItemTextW( // error check?
  310. hDlg,
  311. IDC_NET_NAME,
  312. acc,
  313. static_cast<DWORD>(sbFormatter.GetBufferCch()));
  314. acc.Detach();
  315. IFW32FALSE_EXIT(pThis->m_CodebaseInfo->Win32GetType(CodebaseType));
  316. //
  317. // If this is the Windows install media, display something
  318. // pleasant to the user - \\server\share only!
  319. //
  320. if (CodebaseType == CODEBASE_RESOLVED_URLHEAD_WINSOURCE)
  321. {
  322. IFW32FALSE_EXIT(::SxspFindInstallWindowsSourcePath(buffTempStringBuffer));
  323. }
  324. else
  325. {
  326. IFW32FALSE_EXIT(buffTempStringBuffer.Win32Assign(pThis->m_CodebaseInfo->GetCodebase()));
  327. }
  328. if (buffTempStringBuffer.Cch() != 0)
  329. {
  330. IFW32FALSE_EXIT(buffFormattedText.Win32Format(sbFormatter, static_cast<PCWSTR>(buffTempStringBuffer)));
  331. IFW32FALSE_EXIT(::SetDlgItemTextW(hDlg, IDC_NET_NAME, buffFormattedText));
  332. }
  333. else
  334. {
  335. #if DBG
  336. ::FusionpDbgPrintEx(
  337. FUSION_DBG_LEVEL_WFP,
  338. "SXS: %s - setting IDC_NET_NAME to empty\n", __FUNCTION__);
  339. #endif
  340. IFW32FALSE_EXIT(::SetDlgItemTextW(hDlg, IDC_NET_NAME, L""));
  341. }
  342. }
  343. else
  344. {
  345. //
  346. // TODO (jonwis) : This is a CD-rom based install, so we should do
  347. // something sane about prompting for the windows CD.
  348. //
  349. }
  350. //
  351. // Now get the prompt from the resources.. we only have one, really.
  352. //
  353. sbFormatter.Clear();
  354. acc.Attach(&sbFormatter);
  355. ::LoadStringW( // error check?
  356. g_hInstance,
  357. IDS_RESTORE_TEXT,
  358. acc.GetBufferPtr(),
  359. acc.GetBufferCchAsDWORD());
  360. acc.Detach();
  361. ::SetDlgItemTextW(hDlg, IDC_PROMPT_TEXT, sbFormatter); // error check?
  362. }
  363. }
  364. break;
  365. case WM_COMMAND:
  366. switch (LOWORD(wParam))
  367. {
  368. case IDC_RETRY:
  369. pThis->m_DeviceChangeMask = static_cast<DWORD>(-1);
  370. pThis->m_DeviceChangeFlags = DBTF_MEDIA;
  371. // Change this to PostMessageW in Blackcomb.
  372. IFW32FALSE_EXIT(::PostMessage(hDlg, WM_TRYAGAIN, 0, 0));
  373. break;
  374. case IDC_INFO:
  375. IFW32FALSE_EXIT(
  376. pThis->DisplayMessage(
  377. NULL,
  378. pThis->m_fIsCDROM ? IDS_MORE_INFORMATION_CD : IDS_MORE_INFORMATION_NET,
  379. MB_ICONINFORMATION | MB_SERVICE_NOTIFICATION | MB_OK,
  380. iMessageBoxResult));
  381. break;
  382. case IDCANCEL:
  383. IFW32FALSE_EXIT(
  384. pThis->DisplayMessage(
  385. hDlg,
  386. IDS_CANCEL_CONFIRM,
  387. MB_APPLMODAL | MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING,
  388. iMessageBoxResult));
  389. if (iMessageBoxResult == IDYES)
  390. {
  391. ::UnregisterDeviceNotification(pThis->m_pvDeviceChange); // error check?
  392. ::EndDialog(hDlg, CSXSMediaPromptDialog::DialogCancelled); // error check?
  393. }
  394. break;
  395. }
  396. break; // WM_COMMAND
  397. case WM_DEVICECHANGE:
  398. if (wParam == DBT_DEVICEARRIVAL)
  399. {
  400. DEV_BROADCAST_VOLUME *dbv = reinterpret_cast<DEV_BROADCAST_VOLUME*>(lParam);
  401. ASSERT(dbv != NULL);
  402. if (dbv->dbcv_devicetype == DBT_DEVTYP_VOLUME)
  403. {
  404. pThis->m_DeviceChangeMask = dbv->dbcv_unitmask;
  405. pThis->m_DeviceChangeFlags = dbv->dbcv_flags;
  406. ::PostMessage(hDlg, WM_TRYAGAIN, 0, 0); // error check?
  407. }
  408. }
  409. break;
  410. case WM_TRYAGAIN:
  411. ::UnregisterDeviceNotification(pThis->m_pvDeviceChange); // error check?
  412. ::EndDialog(hDlg, CSXSMediaPromptDialog::DialogMediaFound); // error check?
  413. break;
  414. }
  415. Exit:
  416. return iResult;
  417. }