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.

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