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.

715 lines
20 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. lnkstub.c
  5. Abstract:
  6. Implements a simple application that replaces incompatible applications
  7. detected dynamically during Win9x upgrade to Windows 2000.
  8. Author:
  9. Calin Negreanu (calinn) 25-Feb-1999
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #include "resource.h"
  14. #include "msg.h"
  15. #include <winbasep.h>
  16. #include <shellapi.h>
  17. //
  18. // Globals
  19. //
  20. HINSTANCE g_hInst;
  21. HANDLE g_hHeap;
  22. BOOL g_RemoveLnk = FALSE;
  23. BOOL g_RestoreLnk = FALSE;
  24. BOOL g_RunOrgApp = FALSE;
  25. HICON g_hIcon = NULL;
  26. BOOL g_ReportAvailable = FALSE;
  27. BOOL g_StartAppAvailable = FALSE;
  28. BOOL g_RemoveLnkAvailable = FALSE;
  29. BOOL g_RestoreLnkAvailable = FALSE;
  30. PCTSTR g_ReportPath = NULL;
  31. DWORD g_Announcement = ACT_INC_NOBADAPPS;
  32. DWORD g_Availability = 1;
  33. PCTSTR g_ActualLnkName = NULL;
  34. //
  35. // Library prototypes
  36. //
  37. BOOL
  38. WINAPI
  39. MigUtil_Entry (
  40. HINSTANCE hInstance,
  41. DWORD dwReason,
  42. PVOID lpReserved
  43. );
  44. //
  45. // Local prototypes
  46. //
  47. BOOL
  48. CALLBACK
  49. DialogProc (
  50. HWND hdlg,
  51. UINT uMsg,
  52. WPARAM wParam,
  53. LPARAM lParam
  54. );
  55. //
  56. // Implementation
  57. //
  58. VOID
  59. pSetProgramIcon (
  60. PCTSTR OrigIconPath,
  61. INT OrigIconNr
  62. )
  63. {
  64. HINSTANCE iconFile;
  65. iconFile = LoadLibraryEx (OrigIconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
  66. if (iconFile) {
  67. g_hIcon = LoadIcon (iconFile, MAKEINTRESOURCE(OrigIconNr));
  68. FreeLibrary (iconFile);
  69. }
  70. if (g_hIcon == NULL) {
  71. g_hIcon = LoadIcon (NULL, IDI_EXCLAMATION);
  72. }
  73. }
  74. BOOL
  75. pIsFileAccessible (
  76. IN PCTSTR FileName,
  77. IN DWORD DesiredAccess
  78. )
  79. {
  80. HANDLE fileHandle;
  81. fileHandle = CreateFile (
  82. FileName,
  83. DesiredAccess,
  84. FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
  85. NULL,
  86. OPEN_EXISTING,
  87. FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING,
  88. NULL
  89. );
  90. if (fileHandle == INVALID_HANDLE_VALUE) {
  91. return FALSE;
  92. }
  93. CloseHandle (fileHandle);
  94. return TRUE;
  95. }
  96. BOOL
  97. pRestoreLnk (
  98. IN PCTSTR LnkName,
  99. IN PCTSTR LnkTarget,
  100. IN PCTSTR LnkArgs,
  101. IN PCTSTR LnkWorkDir,
  102. IN PCTSTR LnkIconPath,
  103. IN INT LnkIconNr,
  104. IN INT ShowMode
  105. )
  106. {
  107. IShellLink *psl = NULL;
  108. IPersistFile *ppf = NULL;
  109. BOOL result = FALSE;
  110. HRESULT comResult;
  111. comResult = CoInitialize (NULL);
  112. if (FAILED (comResult)) {
  113. return FALSE;
  114. }
  115. __try {
  116. if (!DoesFileExist (LnkName)) {
  117. __leave;
  118. }
  119. if (((LnkTarget == NULL) || (LnkTarget [0] == 0)) &&
  120. ((LnkWorkDir == NULL) || (LnkWorkDir [0] == 0)) &&
  121. ((LnkIconPath == NULL) || (LnkIconPath [0] == 0)) &&
  122. (LnkIconNr == 0)
  123. ) {
  124. __leave;
  125. }
  126. comResult = CoCreateInstance (
  127. &CLSID_ShellLink,
  128. NULL,
  129. CLSCTX_INPROC_SERVER,
  130. &IID_IShellLink,
  131. (void **) &psl);
  132. if (comResult != S_OK) {
  133. __leave;
  134. }
  135. comResult = psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, (void **) &ppf);
  136. if (comResult != S_OK) {
  137. __leave;
  138. }
  139. //
  140. // We only load if the file was really a LNK
  141. //
  142. comResult = ppf->lpVtbl->Load(ppf, LnkName, STGM_READ);
  143. if (comResult != S_OK) {
  144. __leave;
  145. }
  146. if (LnkTarget != NULL) {
  147. comResult = psl->lpVtbl->SetPath (psl, LnkTarget);
  148. if (comResult != S_OK) {
  149. __leave;
  150. }
  151. }
  152. if (LnkArgs != NULL) {
  153. comResult = psl->lpVtbl->SetArguments (psl, LnkArgs);
  154. if (comResult != S_OK) {
  155. __leave;
  156. }
  157. }
  158. if (LnkWorkDir != NULL) {
  159. comResult = psl->lpVtbl->SetWorkingDirectory (psl, LnkWorkDir);
  160. if (comResult != S_OK) {
  161. __leave;
  162. }
  163. }
  164. if (LnkIconPath != NULL) {
  165. comResult = psl->lpVtbl->SetIconLocation (psl, LnkIconPath, LnkIconNr);
  166. if (comResult != S_OK) {
  167. __leave;
  168. }
  169. }
  170. comResult = psl->lpVtbl->SetShowCmd (psl, ShowMode);
  171. if (comResult != S_OK) {
  172. __leave;
  173. }
  174. comResult = ppf->lpVtbl->Save (ppf, LnkName, FALSE);
  175. if (comResult != S_OK) {
  176. __leave;
  177. }
  178. comResult = ppf->lpVtbl->SaveCompleted (ppf, LnkName);
  179. if (comResult != S_OK) {
  180. __leave;
  181. }
  182. result = TRUE;
  183. }
  184. __finally {
  185. if (ppf != NULL) {
  186. ppf->lpVtbl->Release (ppf);
  187. ppf = NULL;
  188. }
  189. if (psl != NULL) {
  190. psl->lpVtbl->Release (psl);
  191. psl = NULL;
  192. }
  193. CoUninitialize ();
  194. }
  195. return result;
  196. }
  197. INT
  198. WINAPI
  199. WinMain (
  200. HINSTANCE hInstance,
  201. HINSTANCE hPrevInstance,
  202. PSTR AnsiCmdLine,
  203. INT CmdShow
  204. )
  205. /*++
  206. Routine Description:
  207. The entry point to lnkstub.exe. All the work is done in a dialog box,
  208. so no message loop is necessary.
  209. Arguments:
  210. hInstance - The instance handle of this EXE
  211. hPrevInstance - The previous instance handle of this EXE if it is
  212. running, or NULL if no other instances exist.
  213. AnsiCmdLine - The command line (ANSI version)
  214. CmdShow - The ShowWindow command passed by the shell
  215. Return Value:
  216. Returns -1 if an error occurred, or 0 if the exe completed.
  217. --*/
  218. {
  219. UINT Result;
  220. TCHAR winDir [MAX_PATH];
  221. STARTUPINFO startInfo;
  222. PCTSTR OrigLnkName = NULL;
  223. PCTSTR OrigTarget = NULL;
  224. PCTSTR OrigArgs = NULL;
  225. PCTSTR OrigWorkDir = NULL;
  226. PCTSTR OrigIconPath = NULL;
  227. INT OrigIconNr = 0;
  228. INT OrigShowMode = SW_NORMAL;
  229. PCTSTR LnkStubDatFile = NULL;
  230. PBYTE LnkStubDatPtr = NULL;
  231. PBYTE LnkStubDatPtrTmp = NULL;
  232. HANDLE StubMapHandle = NULL;
  233. HANDLE StubFileHandle = NULL;
  234. INT ofsHeader;
  235. PDWORD offset;
  236. FILETIME fileTime;
  237. FILETIME reqFileTime;
  238. WIN32_FIND_DATA findData;
  239. BOOL shouldRestoreLnk = FALSE;
  240. PCTSTR reqFilePath = NULL;
  241. PCTSTR reqFileFullPath = NULL;
  242. PCTSTR oldFileSpec = NULL;
  243. PTSTR oldFilePtr = NULL;
  244. INITCOMMONCONTROLSEX init = {sizeof (INITCOMMONCONTROLSEX), 0};
  245. InitCommonControlsEx (&init);
  246. g_hInst = hInstance;
  247. g_hHeap = GetProcessHeap();
  248. MigUtil_Entry (hInstance, DLL_PROCESS_ATTACH, NULL);
  249. if (GetWindowsDirectory (winDir, MAX_PATH)) {
  250. g_ReportPath = JoinPaths (winDir, S_UPGRADEHTM);
  251. g_ReportAvailable = DoesFileExist (g_ReportPath) && pIsFileAccessible (g_ReportPath, GENERIC_READ);
  252. LnkStubDatFile = JoinPaths (winDir, S_LNKSTUB_DAT);
  253. }
  254. // let's see if we can get the LNK that launched us.
  255. GetStartupInfo (&startInfo);
  256. if (startInfo.dwFlags & STARTF_TITLEISLINKNAME) {
  257. g_ActualLnkName = DuplicatePathString (startInfo.lpTitle, 0);
  258. g_RemoveLnkAvailable = DoesFileExist (g_ActualLnkName) && pIsFileAccessible (g_ActualLnkName, GENERIC_READ|GENERIC_WRITE);
  259. }
  260. // now let's see if we can find data about our original LNK
  261. if (LnkStubDatFile) {
  262. __try {
  263. LnkStubDatPtr = MapFileIntoMemoryEx (LnkStubDatFile, &StubMapHandle, &StubFileHandle, TRUE);
  264. if (LnkStubDatPtr) {
  265. ofsHeader = atoi (AnsiCmdLine) - 1;
  266. if (ofsHeader >= 0) {
  267. //
  268. // Read details about original LNK. See w95upgnt\filemig.c
  269. // for format of lnkstub.dat
  270. //
  271. offset = (PDWORD) (LnkStubDatPtr + ofsHeader * sizeof (DWORD));
  272. OrigLnkName = (PCTSTR) (LnkStubDatPtr + *offset);
  273. OrigTarget = GetEndOfString (OrigLnkName) + 1;
  274. OrigArgs = GetEndOfString (OrigTarget) + 1;
  275. OrigWorkDir = GetEndOfString (OrigArgs) + 1;
  276. OrigIconPath = GetEndOfString (OrigWorkDir) + 1;
  277. LnkStubDatPtrTmp = (PBYTE) (GetEndOfString (OrigIconPath) + 1);
  278. OrigIconNr = *((PINT) LnkStubDatPtrTmp);
  279. LnkStubDatPtrTmp += sizeof (INT);
  280. OrigShowMode = *((PINT) LnkStubDatPtrTmp);
  281. LnkStubDatPtrTmp += sizeof (INT);
  282. g_Announcement = *((PDWORD) LnkStubDatPtrTmp);
  283. LnkStubDatPtrTmp += sizeof (DWORD);
  284. g_Availability = *((PDWORD) LnkStubDatPtrTmp);
  285. LnkStubDatPtrTmp += sizeof (DWORD);
  286. fileTime.dwLowDateTime = *((PDWORD) LnkStubDatPtrTmp);
  287. LnkStubDatPtrTmp += sizeof (DWORD);
  288. fileTime.dwHighDateTime = *((PDWORD) LnkStubDatPtrTmp);
  289. LnkStubDatPtrTmp += sizeof (DWORD);
  290. reqFilePath = (PTSTR)LnkStubDatPtrTmp;
  291. //
  292. // Continue reading [in a loop] the list of required
  293. // files. This is how lnkstub detects changes from a
  294. // reinstall or uninstall, and auto-removes itself.
  295. //
  296. shouldRestoreLnk = FALSE;
  297. while (reqFilePath [0]) {
  298. if (!shouldRestoreLnk) {
  299. oldFileSpec = DuplicatePathString (OrigTarget, 0);
  300. oldFilePtr = (PTSTR)GetFileNameFromPath (oldFileSpec);
  301. if (oldFilePtr) {
  302. *oldFilePtr = 0;
  303. }
  304. reqFileFullPath = JoinPaths (oldFileSpec, reqFilePath);
  305. if (!DoesFileExistEx (reqFileFullPath, &findData)) {
  306. shouldRestoreLnk = FALSE;
  307. }
  308. FreePathString (reqFileFullPath);
  309. FreePathString (oldFileSpec);
  310. }
  311. LnkStubDatPtrTmp = (PBYTE) (GetEndOfString (reqFilePath) + 1);
  312. reqFileTime.dwLowDateTime = *((PDWORD) LnkStubDatPtrTmp);
  313. LnkStubDatPtrTmp += sizeof (DWORD);
  314. reqFileTime.dwHighDateTime = *((PDWORD) LnkStubDatPtrTmp);
  315. LnkStubDatPtrTmp += sizeof (DWORD);
  316. reqFilePath = (PTSTR)LnkStubDatPtrTmp;
  317. if (!shouldRestoreLnk) {
  318. if ((findData.ftLastWriteTime.dwLowDateTime != reqFileTime.dwLowDateTime) ||
  319. (findData.ftLastWriteTime.dwHighDateTime != reqFileTime.dwHighDateTime)
  320. ) {
  321. shouldRestoreLnk = TRUE;
  322. }
  323. }
  324. }
  325. //
  326. // Save data from memory mapped lnkstub.dat into path pool
  327. //
  328. OrigLnkName = DuplicatePathString (OrigLnkName, 0);
  329. OrigTarget = DuplicatePathString (OrigTarget, 0);
  330. OrigArgs = DuplicatePathString (OrigArgs, 0);
  331. OrigWorkDir = DuplicatePathString (OrigWorkDir, 0);
  332. OrigIconPath = DuplicatePathString (OrigIconPath, 0);
  333. g_StartAppAvailable = DoesFileExistEx (OrigTarget, &findData);
  334. g_RestoreLnkAvailable = g_RemoveLnkAvailable && g_StartAppAvailable;
  335. if (!shouldRestoreLnk) {
  336. if ((findData.ftLastWriteTime.dwLowDateTime != fileTime.dwLowDateTime) ||
  337. (findData.ftLastWriteTime.dwHighDateTime != fileTime.dwHighDateTime)
  338. ) {
  339. shouldRestoreLnk = TRUE;
  340. }
  341. }
  342. shouldRestoreLnk = shouldRestoreLnk && g_StartAppAvailable;
  343. }
  344. }
  345. } __except (1) {
  346. UnmapFile (LnkStubDatPtr, StubMapHandle, StubFileHandle);
  347. LnkStubDatPtr = NULL;
  348. OrigLnkName = NULL;
  349. OrigTarget = NULL;
  350. OrigArgs = NULL;
  351. OrigWorkDir = NULL;
  352. OrigIconPath = NULL;
  353. g_StartAppAvailable = FALSE;
  354. g_RestoreLnkAvailable = FALSE;
  355. }
  356. if (LnkStubDatPtr) {
  357. UnmapFile (LnkStubDatPtr, StubMapHandle, StubFileHandle);
  358. LnkStubDatPtr = NULL;
  359. }
  360. }
  361. if (OrigIconPath && *OrigIconPath) {
  362. pSetProgramIcon (OrigIconPath, OrigIconNr);
  363. } else {
  364. pSetProgramIcon (OrigTarget, OrigIconNr);
  365. }
  366. if (shouldRestoreLnk) {
  367. g_RestoreLnk = TRUE;
  368. g_RunOrgApp = TRUE;
  369. } else {
  370. switch (g_Announcement) {
  371. case ACT_REINSTALL:
  372. case ACT_REINSTALL_BLOCK:
  373. Result = DialogBox (
  374. hInstance,
  375. MAKEINTRESOURCE(IDD_REINST_DLG),
  376. NULL,
  377. DialogProc
  378. );
  379. break;
  380. case ACT_INC_PREINSTUTIL:
  381. Result = DialogBox (
  382. hInstance,
  383. MAKEINTRESOURCE(IDD_PREINSTUTIL_DLG),
  384. NULL,
  385. DialogProc
  386. );
  387. break;
  388. case ACT_INC_SIMILAROSFUNC:
  389. Result = DialogBox (
  390. hInstance,
  391. MAKEINTRESOURCE(IDD_SIMILAROSFUNCT_DLG),
  392. NULL,
  393. DialogProc
  394. );
  395. break;
  396. case ACT_INC_IHVUTIL:
  397. Result = DialogBox (
  398. hInstance,
  399. MAKEINTRESOURCE(IDD_IHVUTIL_DLG),
  400. NULL,
  401. DialogProc
  402. );
  403. break;
  404. default:
  405. Result = DialogBox (
  406. hInstance,
  407. MAKEINTRESOURCE(IDD_INCOMP_DLG),
  408. NULL,
  409. DialogProc
  410. );
  411. break;
  412. }
  413. }
  414. if (g_RestoreLnk) {
  415. MYASSERT (!g_RemoveLnk);
  416. if (!pRestoreLnk (
  417. g_ActualLnkName,
  418. OrigTarget,
  419. OrigArgs,
  420. OrigWorkDir,
  421. OrigIconPath,
  422. OrigIconNr-1,
  423. OrigShowMode
  424. )) {
  425. DEBUGMSG ((DBG_ERROR, "Cannot restore %s", g_ActualLnkName));
  426. }
  427. }
  428. if (g_RunOrgApp) {
  429. MYASSERT (!g_RemoveLnk);
  430. if (ShellExecute (NULL, NULL, OrigTarget, OrigArgs, OrigWorkDir, SW_SHOWDEFAULT) <= (HINSTANCE)32) {
  431. DEBUGMSG ((DBG_ERROR, "Cannot start %s", OrigTarget));
  432. }
  433. }
  434. if (g_RemoveLnk) {
  435. if (!DeleteFile (g_ActualLnkName)) {
  436. DEBUGMSG ((DBG_ERROR, "Cannot remove %s", g_ActualLnkName));
  437. }
  438. }
  439. if (OrigIconPath) {
  440. FreePathString (OrigIconPath);
  441. }
  442. if (OrigWorkDir) {
  443. FreePathString (OrigWorkDir);
  444. }
  445. if (OrigArgs) {
  446. FreePathString (OrigArgs);
  447. }
  448. if (OrigTarget) {
  449. FreePathString (OrigTarget);
  450. }
  451. if (OrigLnkName) {
  452. FreePathString (OrigLnkName);
  453. }
  454. if (g_ActualLnkName) {
  455. FreePathString (g_ActualLnkName);
  456. g_ActualLnkName = NULL;
  457. }
  458. if (LnkStubDatFile) {
  459. FreePathString (LnkStubDatFile);
  460. }
  461. if (g_ReportPath) {
  462. FreePathString (g_ReportPath);
  463. }
  464. MigUtil_Entry (hInstance, DLL_PROCESS_DETACH, NULL);
  465. return 0;
  466. }
  467. BOOL
  468. CALLBACK
  469. DialogProc (
  470. HWND hdlg,
  471. UINT uMsg,
  472. WPARAM wParam,
  473. LPARAM lParam
  474. )
  475. /*++
  476. Routine Description:
  477. DialogProc is the dialog procedure for the main dialog.
  478. Arguments:
  479. hdlg - Dialog window handle
  480. uMsg - Message to process
  481. wParam - Message-specific
  482. lParam - Message-specific
  483. Return Value:
  484. TRUE if the message was processed, or FALSE if the message should be
  485. processed by the OS.
  486. --*/
  487. {
  488. static RECT LargeWndRect;
  489. static RECT SmallWndRect;
  490. static TCHAR LargeCaption[128];
  491. static TCHAR SmallCaption[128];
  492. static BOOL LargeWnd;
  493. RECT ButtonRect;
  494. PTSTR lnkName = NULL;
  495. PTSTR extPtr = NULL;
  496. BOOL showReport = TRUE;
  497. HINSTANCE result;
  498. switch (uMsg) {
  499. case WM_INITDIALOG:
  500. if (g_ActualLnkName) {
  501. lnkName = DuplicatePathString (GetFileNameFromPath (g_ActualLnkName), 0);
  502. if (lnkName) {
  503. extPtr = (PTSTR)GetFileExtensionFromPath (lnkName);
  504. if (extPtr) {
  505. extPtr = _tcsdec (lnkName, extPtr);
  506. if (extPtr) {
  507. *extPtr = 0;
  508. SetWindowText (hdlg, lnkName);
  509. }
  510. }
  511. FreePathString (lnkName);
  512. }
  513. }
  514. showReport = g_Availability && g_ReportAvailable;
  515. GetWindowText (GetDlgItem (hdlg, IDC_OPTIONS), LargeCaption, 125);
  516. GetWindowText (GetDlgItem (hdlg, IDC_OPTIONS), SmallCaption, 125);
  517. _tcscat (LargeCaption, TEXT(" <<"));
  518. _tcscat (SmallCaption, TEXT(" >>"));
  519. SetDlgItemText (hdlg, IDC_OPTIONS, SmallCaption);
  520. GetWindowRect (hdlg, &LargeWndRect);
  521. GetWindowRect (GetDlgItem (hdlg, IDC_DLG_SIZE_SEPARATOR), &ButtonRect);
  522. CopyMemory (&SmallWndRect, &LargeWndRect, sizeof (RECT));
  523. SmallWndRect.bottom = ButtonRect.bottom;
  524. SetWindowPos (
  525. hdlg,
  526. NULL,
  527. 0,
  528. 0,
  529. SmallWndRect.right-SmallWndRect.left,
  530. SmallWndRect.bottom-SmallWndRect.top,
  531. SWP_NOMOVE|SWP_NOZORDER
  532. );
  533. EnableWindow (GetDlgItem (hdlg, IDC_START), FALSE);
  534. EnableWindow (GetDlgItem (hdlg, IDC_REMOVE), FALSE);
  535. EnableWindow (GetDlgItem (hdlg, IDC_RESTORE), FALSE);
  536. LargeWnd = FALSE;
  537. if (!showReport) {
  538. EnableWindow (GetDlgItem (hdlg, IDC_REPORTBUTTON), FALSE);
  539. ShowWindow (GetDlgItem (hdlg, IDC_REPORTTEXT), SW_HIDE);
  540. } else {
  541. EnableWindow (GetDlgItem (hdlg, IDC_REPORTBUTTON), TRUE);
  542. ShowWindow (GetDlgItem (hdlg, IDC_REPORTTEXT), SW_SHOW);
  543. }
  544. SendDlgItemMessage (hdlg, IDC_PROGICON, STM_SETICON, (LPARAM)g_hIcon, 0);
  545. return FALSE;
  546. case WM_COMMAND:
  547. switch (LOWORD(wParam)) {
  548. case IDCANCEL:
  549. EndDialog (hdlg, LOWORD (wParam));
  550. break;
  551. case IDC_REPORTBUTTON:
  552. if (HIWORD (wParam) == BN_CLICKED) {
  553. result = ShellExecute (
  554. hdlg,
  555. NULL,
  556. g_ReportPath,
  557. NULL,
  558. NULL,
  559. SW_SHOW
  560. );
  561. }
  562. break;
  563. case IDC_OPTIONS:
  564. if (HIWORD (wParam) == BN_CLICKED) {
  565. LargeWnd = !LargeWnd;
  566. SetWindowPos (
  567. hdlg,
  568. NULL,
  569. 0,
  570. 0,
  571. LargeWnd?LargeWndRect.right-LargeWndRect.left:SmallWndRect.right-SmallWndRect.left,
  572. LargeWnd?LargeWndRect.bottom-LargeWndRect.top:SmallWndRect.bottom-SmallWndRect.top,
  573. SWP_NOMOVE|SWP_NOZORDER
  574. );
  575. SetDlgItemText (hdlg, IDC_OPTIONS, LargeWnd?LargeCaption:SmallCaption);
  576. EnableWindow (GetDlgItem (hdlg, IDC_START), LargeWnd & g_StartAppAvailable);
  577. EnableWindow (GetDlgItem (hdlg, IDC_REMOVE), LargeWnd & g_RemoveLnkAvailable);
  578. EnableWindow (GetDlgItem (hdlg, IDC_RESTORE), LargeWnd & g_RestoreLnkAvailable);
  579. }
  580. break;
  581. case IDC_START:
  582. if (HIWORD (wParam) == BN_CLICKED) {
  583. g_RunOrgApp = TRUE;
  584. EndDialog (hdlg, LOWORD (wParam));
  585. }
  586. break;
  587. case IDC_REMOVE:
  588. if (HIWORD (wParam) == BN_CLICKED) {
  589. g_RemoveLnk = TRUE;
  590. EndDialog (hdlg, LOWORD (wParam));
  591. }
  592. break;
  593. case IDC_RESTORE:
  594. if (HIWORD (wParam) == BN_CLICKED) {
  595. g_RestoreLnk = TRUE;
  596. EndDialog (hdlg, LOWORD (wParam));
  597. }
  598. break;
  599. }
  600. break;
  601. case WM_DESTROY:
  602. break;
  603. }
  604. return FALSE;
  605. }