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.

12473 lines
350 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. CompatAdmin.cpp
  5. Abstract:
  6. This module handles most of the GUI for the application. It contains the message loop and
  7. WinMain
  8. Notes:
  9. 1. Has a global try catch, so if the Program AVs we will get a "Out of Memory" Error
  10. 2. This is a Unicode app
  11. 3. The code was written with tab size of 4
  12. 4. Please go through the data strctures and their explainations as in CompatAdmin.h
  13. 5. The documentation in the code assumes that you are familiar with the basic understanding of
  14. the SdbApis and the lay out of the xml that is compiled into the .sdb database format
  15. 6. Tools/stuff you should use or know about:
  16. a) shimdbc : Shim database compiler. Compiles a xml into database. Owner: markder, vadimb
  17. b) dumpsdb : Used to view a .sdb as a text file. Owner: dmunsil
  18. c) sdbapis : All our sdb apis. Owner: dmunsil
  19. d) shimengine : The shim infrastructure core component. Owner: clupu
  20. Usage:
  21. CompatAdmin.exe [/x]. The /x switch is for enabling expert mode. In expert mode
  22. we show the non-general shims as well and the parameters for shims and flags can be
  23. configured
  24. Author:
  25. kinshu created July 2, 2001
  26. Revision History:
  27. --*/
  28. #include "precomp.h"
  29. #include <richedit.h>
  30. //////////////////////// Extern variables /////////////////////////////////////
  31. extern DATABASE GlobalDataBase;
  32. extern PDATABASE g_pPresentDataBase;
  33. extern BOOL g_bEntryConflictDonotShow;
  34. extern HWND g_hdlgSearchDB;
  35. ///////////////////////////////////////////////////////////////////////////////
  36. //////////////////////// Defines //////////////////////////////////////////////
  37. #define STR_NEW_LINE_CHARS TEXT("\r\n")
  38. #define STR_APPPATCH_CUSTOM TEXT("AppPatch\\Custom\\")
  39. // Buffer allocation size in TCHARS for the common dialog that lets us open multiple files
  40. #define MAX_BUFF_OPENMULTIPLE_FILES MAX_PATH * 10
  41. // Width and height of the buttons in the toolbar
  42. #define IMAGE_WIDTH 24
  43. #define IMAGE_HEIGHT 24
  44. // Number of buttons in the toolbar. This includes the separators as well.
  45. #define BUTTON_COUNT 11
  46. //
  47. // Defines for the context menus (position)
  48. #define MENU_CONTEXT_DATABASE 0
  49. #define MENU_CONTEXT_APP_LAYER 1
  50. #define MENU_CONTEXT_FIX 2
  51. #define MENU_CONTEXT_LIST 4
  52. #define MENU_CONTEXT_DATABASE_ALL 5
  53. // defines for the colums used in the event dialog
  54. #define EVENTS_COLUMN_TIME 0
  55. #define EVENTS_COLUMN_MSG 1
  56. //
  57. // Number of controls in the main window which have to be resized. This is passed as a
  58. // paramreter to BeginDeferWindowPos()
  59. #define MAIN_WINDOW_CONTROL_COUNT 6
  60. // We need to cleanup if we are checking for leaks
  61. #define HELP_BOUND_CHECK 1
  62. // Maximum number of chars that we show for the file name in MRU. Does not include the extension
  63. #define MAX_FILE_SHOW 20
  64. // Maximum number of chars that we show for the drive and dir of the path in MRU
  65. #define MAX_DIR_SHOW 20
  66. // Maximum length of a string that can be shown as the File menu MRU.
  67. #define MAX_LENGTH_MRU_MENUITEM (MAX_FILE_SHOW + MAX_DIR_SHOW + 4) // 4 is for the extension .sdb
  68. // The redraw type passed to DeferWindowPos() in OnMoveSplitter()
  69. #define REDRAW_TYPE SWP_NOZORDER | SWP_NOACTIVATE
  70. ///////////////////////////////////////////////////////////////////////////////
  71. //////////////////////// Global Variables /////////////////////////////////////
  72. //
  73. // We are going to delete the contents of the entry tree by callign TreeDeleteAll().
  74. // We need to handle this because we should not be processing any TVN_SELTCHANGE
  75. // messages when we are deleting the entry tree. If we have by mistake delete the contents
  76. // of the LPARAM of a entry tree and then we delete the entry tree, that item can get the
  77. // focus and then we will try to make use of the LPARAM of the tree item and this can cause
  78. // an access violation as the item has been deleted already. As a general rule, delete
  79. // the tree item first and then delete the data structure that is referenced by some
  80. // pointer that is in the LPARAM for the tree item
  81. //
  82. BOOL g_bDeletingEntryTree;
  83. //
  84. // If we have some wizard window open then we do not want that we should be able
  85. // to change the present database by double clicking the search or query results
  86. BOOL g_bSomeWizardActive;
  87. // The clipboad
  88. CLIPBOARD gClipBoard;
  89. //
  90. // We do not want the installed database list to be updated when we are installing a
  91. // database in the process of test run
  92. BOOL g_bUpdateInstalledRequired = TRUE;
  93. // The index of the item that is presently selected in the Contents List
  94. INT g_iContentsListSelectIndex = -1;
  95. //
  96. // This will contain the function pointer of the original tree view proc. We are subclassing
  97. // both of the tree views
  98. WNDPROC g_PrevTreeProc = NULL;
  99. //
  100. // This will contain the function pointer of the original list view proc. We are subclassing
  101. // the list views
  102. WNDPROC g_PrevListProc = NULL;
  103. //
  104. // The array of the keys on which we will be listening for changes. Used for automatic update of
  105. // the per-user compatibility list and the installed databases list
  106. HKEY g_hKeyNotify[2];
  107. // Event Handles to wait for the Per User and All Users settings to change
  108. HANDLE g_arrhEventNotify[2];
  109. // Handle to the toolbar
  110. HWND g_hwndToolBar;
  111. // Stringlist that holds the most recently used files.
  112. CSTRINGLIST g_strlMRU;
  113. // The name of the application
  114. TCHAR g_szAppName[128];
  115. // Misc. data to be passed to dialogs as arg (when we are already using the LPARAM)
  116. TCHAR g_szData[1024];
  117. //The new URL should now point to the location from where we can get the SP3
  118. TCHAR g_szW2KUrl[] = TEXT("http://www.microsoft.com/windows2000/downloads/tools/appcompat/");
  119. // URL for the toolkit. Shown in the description window when we do not have any other description
  120. // Bonus !
  121. TCHAR g_szToolkitURL[] = _T("http://msdn.microsoft.com/compatibility");
  122. // Is service pack greater than 2
  123. BOOL g_fSPGreaterThan2;
  124. // The accelerator handle
  125. HACCEL g_hAccelerator;
  126. // Are we on Win2000
  127. BOOL g_bWin2K = FALSE;
  128. //Specifies whether the contents of ClipBoard are because of cut or copy.
  129. BOOL g_bIsCut = FALSE;
  130. // The module handle
  131. HINSTANCE g_hInstance;
  132. // The handle to the main dialog window
  133. HWND g_hDlg;
  134. // Handle to the window of the entry tree, displayed in the contents pane
  135. HWND g_hwndEntryTree;
  136. // Handle to the window of the contents list, displayed in the contemts pane
  137. HWND g_hwndContentsList;
  138. // Handle to the status bar
  139. HWND g_hwndStatus;
  140. // Handle to In-place edit control for the DB tree and the contents list
  141. HWND g_hwndEditText;
  142. //
  143. // Handle to the image list. This image list is used by all except the matching wizard page,
  144. // and the toolbar
  145. HIMAGELIST g_hImageList;
  146. // BUGBUG: Bad stuff, use a map instead
  147. UINT g_uImageRedirector[1024];
  148. // EXE selected in the Entry Tree
  149. PDBENTRY g_pSelEntry;
  150. // First EXE of the Selected App in the DataBase Tree
  151. PDBENTRY g_pEntrySelApp;
  152. // Spefies if the contents list is visible, FALSE implies the entry tree is visible
  153. BOOL g_bIsContentListVisible;
  154. //
  155. // The width, height of the main dialog window. Used when we handle WM_SIZE
  156. int g_cWidth;
  157. int g_cHeight;
  158. // The X position where the mouse was last pressed.
  159. int g_iMousePressedX;
  160. // If the mouse is pressed: used when we handle the split bar
  161. BOOL g_bDrag;
  162. // Whether the system apps, tree item has been expanded.
  163. BOOL g_bMainAppExpanded = FALSE;
  164. // Used for giving default names to the .SDB files in the DataBase constructor
  165. UINT g_uNextDataBaseIndex = 1;
  166. // Used for painting the split bar.
  167. RECT g_rectBar;
  168. // The db tree that constitutes the root-pane. This is the LHS tree control
  169. DatabaseTree DBTree;
  170. //
  171. // Used to tell if the description window is shown. Is true by default. User can make it
  172. // false using menu
  173. BOOL g_bDescWndOn = TRUE;
  174. // The list control for the events dialog
  175. HWND g_hwndEventsWnd;
  176. // The event count. This is used as the index into the event list view.
  177. INT g_iEventCount;
  178. // Buffer used to update the content of the richedit description window
  179. TCHAR g_szDesc[1024];
  180. // Handle to rich edit control
  181. HWND g_hwndRichEdit;
  182. //
  183. // The expert mode. Is the /x switch on? In expert mode the user can see all the shims and flags
  184. // and can change the paramters of the shims
  185. BOOL g_bExpert;
  186. // Does the user have admin rights
  187. BOOL g_bAdmin = TRUE;
  188. // The handle to the thread that handles the updates to the installed databases
  189. // and the per-user settings
  190. HANDLE g_hThreadWait;
  191. // Help cookie that is returned while initializing and is used when uninitalizing
  192. DWORD g_dwCookie = 0;
  193. //
  194. // The path of CompatAdmin. This is required so that we can load the help file appropriately.
  195. // Buffer size is made MAX_PATH + 1, becasue GetModuleFileName does not NULL terminate.
  196. TCHAR g_szAppPath[MAX_PATH + 1];
  197. // The critical section that controls which call to ShowMainEntries(); gets through.
  198. CRITICAL_SECTION g_critsectShowMain;
  199. // The critical section that guards the variable that tells us if somebody is already trying to
  200. // populate the global app list.
  201. CRITICAL_SECTION s_csExpanding;
  202. //
  203. // The critical section that protects the installed database datastructure.
  204. // The installed datastructure is iterated when we are querying the datastructure and
  205. // the query is done in a separate thread
  206. CRITICAL_SECTION g_csInstalledList;
  207. // Is somebody trying to populate the main database entries
  208. BOOL g_bExpanding = FALSE;
  209. // The presently selected database
  210. PDATABASE g_pPresentDataBase;
  211. // Height and width of the event window
  212. static int s_cEventWidth;
  213. static int s_cEventHeight;
  214. // The imagelist for the toolbar
  215. static HIMAGELIST s_hImageListToolBar;
  216. // The hot imagelist for the toolbar
  217. static HIMAGELIST s_hImageListToolBarHot;
  218. // If we are about to exit CompatAdmin. It will surely exit now.
  219. static BOOL s_bProcessExiting;
  220. ///////////////////////////////////////////////////////////////////////////////
  221. //////////////////////// Function Declarations ////////////////////////////////
  222. INT
  223. GetContentsListIndex(
  224. HWND hwndList,
  225. LPARAM lParam
  226. );
  227. void
  228. HandleMRUActivation(
  229. WPARAM wCode
  230. );
  231. BOOL
  232. EndListViewLabelEdit(
  233. LPARAM lparam
  234. );
  235. void
  236. OnEntryTreeSelChange(
  237. LPARAM lParam
  238. );
  239. void
  240. ShowExcludeStatusMessage(
  241. HWND hwndTree,
  242. HTREEITEM hItem
  243. );
  244. void
  245. ShowIncludeStatusMessage(
  246. HWND hwndTree,
  247. HTREEITEM hItem
  248. );
  249. void
  250. ShowEventsWindow(
  251. void
  252. );
  253. void
  254. SetStatusDBItems(
  255. IN HTREEITEM hItem
  256. );
  257. void
  258. OnExitCleanup(
  259. void
  260. );
  261. void
  262. EventsWindowSize(
  263. HWND hDlf
  264. );
  265. void
  266. ShowHelp(
  267. HWND hdlg,
  268. WPARAM wCode
  269. );
  270. INT_PTR
  271. CALLBACK
  272. EventDlgProc(
  273. HWND hdlg,
  274. UINT uMsg,
  275. WPARAM wParam,
  276. LPARAM lParam
  277. );
  278. INT
  279. ShowMainEntries(
  280. HWND hdlg
  281. );
  282. BOOL
  283. HandleDBTreeSelChange(
  284. HTREEITEM hItem
  285. );
  286. void
  287. CopyToClipBoard(
  288. WPARAM wCode
  289. );
  290. void
  291. LuapCleanup(
  292. void
  293. );
  294. BOOL
  295. LoadInstalledDataBases(
  296. void
  297. );
  298. INT
  299. LoadSpecificInstalledDatabaseGuid(
  300. PCTSTR pszGuid
  301. );
  302. void
  303. ContextMenuExeTree(
  304. LPARAM lParam
  305. );
  306. void
  307. SetTBButtonStatus(
  308. HWND hwndTB
  309. );
  310. void
  311. SetTBButtonStatus(
  312. HWND hwndTB,
  313. HWND hwndControl
  314. );
  315. void
  316. DrawSplitter(
  317. HWND hdlg
  318. );
  319. BOOL
  320. AddRegistryKeys(
  321. void
  322. );
  323. void
  324. ShowToolBarToolTips(
  325. HWND hdlg,
  326. LPARAM lParam
  327. );
  328. INT_PTR
  329. CALLBACK
  330. QueryDBDlg(
  331. HWND hdlg,
  332. UINT uMsg,
  333. WPARAM wParam,
  334. LPARAM lParam
  335. );
  336. DWORD
  337. WINAPI
  338. ThreadEventKeyNotify(
  339. PVOID pVoid
  340. );
  341. void
  342. PasteFromClipBoard(
  343. void
  344. );
  345. void
  346. AddMRUToFileMenu(
  347. HMENU hmenuFile
  348. );
  349. LRESULT
  350. CALLBACK
  351. ListViewProc(
  352. HWND hWnd,
  353. UINT uMsg,
  354. WPARAM wParam,
  355. LPARAM lParam
  356. );
  357. LRESULT
  358. CALLBACK
  359. TreeViewProc(
  360. HWND hWnd,
  361. UINT uMsg,
  362. WPARAM wParam,
  363. LPARAM lParam
  364. );
  365. void
  366. LoadDisplaySettings(
  367. void
  368. );
  369. void
  370. OnMoveSplitter(
  371. HWND hwnd,
  372. LPARAM lParam,
  373. BOOL bDoTheDrag,
  374. INT iDiff
  375. );
  376. INT_PTR
  377. CALLBACK
  378. MsgBoxDlgProc(
  379. HWND hdlg,
  380. UINT uMsg,
  381. WPARAM wParam,
  382. LPARAM lParam
  383. );
  384. BOOL
  385. CheckProperSP(
  386. void
  387. );
  388. void
  389. LoadPerUserSettings(
  390. void
  391. );
  392. void
  393. PopulateContentsList(
  394. HTREEITEM hItem
  395. );
  396. void
  397. CreateNewAppHelp(
  398. void
  399. );
  400. void
  401. ModifyAppHelp(
  402. void
  403. );
  404. void
  405. CreateNewAppFix(
  406. void
  407. );
  408. void
  409. ModifyAppFix(
  410. void
  411. );
  412. void
  413. CreateNewLayer(
  414. void
  415. );
  416. void
  417. OnDelete(
  418. );
  419. void
  420. CreateNewDatabase(
  421. void
  422. );
  423. void
  424. DatabaseSaveAll(
  425. void
  426. );
  427. void
  428. OnDatabaseClose(
  429. void
  430. );
  431. void
  432. ChangeEnableStatus(
  433. void
  434. );
  435. BOOL
  436. ModifyLayer(
  437. void
  438. );
  439. void
  440. OnRename(
  441. void
  442. );
  443. void
  444. ProcessSwitches(
  445. void
  446. );
  447. INT_PTR
  448. CALLBACK
  449. ShowDBPropertiesDlgProc(
  450. HWND hdlg,
  451. UINT uMsg,
  452. WPARAM wParam,
  453. LPARAM lParam
  454. );
  455. ///////////////////////////////////////////////////////////////////////////////
  456. void
  457. HandlePopUp(
  458. IN HWND hDlg,
  459. IN WPARAM wParam,
  460. IN LPARAM lParam
  461. )
  462. /*++
  463. HandlePopUp
  464. Desc: Handles pop down menu (WM_INITMENUPOPUP). Disables items as necessary
  465. Params:
  466. IN HWND hDlg: The window that received WM_INITMENUPOPUP
  467. IN WPARAM wParam: As with WM_INITMENUPOPUP
  468. IN LPARAM lParam: As with WM_INITMENUPOPUP
  469. Notes: The tool bar buttons are NOT diasbled/enabled in this routine. For that the function
  470. SetTBButtonStatus() is used
  471. --*/
  472. {
  473. HWND hwndFocus = GetFocus();
  474. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  475. //
  476. // SelectAll, Invert Selection
  477. //
  478. int iEnable = MF_GRAYED;
  479. HMENU hMenu = (HMENU)wParam;
  480. if (g_bIsContentListVisible
  481. && ListView_GetItemCount(g_hwndContentsList) > 0
  482. && hwndFocus == g_hwndContentsList) {
  483. iEnable = MF_ENABLED;
  484. }
  485. EnableMenuItem(hMenu, ID_EDIT_SELECTALL, iEnable);
  486. EnableMenuItem(hMenu, ID_EDIT_INVERTSELECTION, iEnable);
  487. //
  488. // Change Status menu item
  489. //
  490. HTREEITEM hItem = TreeView_GetSelection(DBTree.m_hLibraryTree);
  491. TYPE typeSelectedItemDB = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItem);
  492. MENUITEMINFO Info = {0};
  493. Info.cbSize = sizeof(MENUITEMINFO);
  494. Info.fMask = MIIM_STRING;
  495. if (g_pSelEntry && g_pSelEntry->bDisablePerMachine == FALSE) {
  496. Info.dwTypeData = GetString(IDS_DISABLE);
  497. } else {
  498. Info.dwTypeData = GetString(IDS_ENABLE);
  499. }
  500. SetMenuItemInfo(hMenu, ID_FIX_CHANGEENABLESTATUS, MF_BYCOMMAND, &Info);
  501. //
  502. // Set the text for edit/add apphelp
  503. //
  504. if (g_pSelEntry && g_pSelEntry->appHelp.bPresent) {
  505. Info.dwTypeData = GetString(IDS_EDITAPPHELP);
  506. } else {
  507. Info.dwTypeData = GetString(IDS_CREATEAPPHELP);
  508. }
  509. SetMenuItemInfo(hMenu, ID_MODIFY_APPHELPMESSAGE, MF_BYCOMMAND, &Info);
  510. //
  511. // Set the text for edit/add app fix
  512. //
  513. if (g_pSelEntry &&
  514. (g_pSelEntry->pFirstFlag
  515. || g_pSelEntry->pFirstLayer
  516. || g_pSelEntry->pFirstPatch
  517. || g_pSelEntry->pFirstShim)) {
  518. Info.dwTypeData = GetString(IDS_EDITFIX);
  519. } else {
  520. Info.dwTypeData = GetString(IDS_CREATEFIX);
  521. }
  522. SetMenuItemInfo(hMenu, ID_MODIFY_APPLICATIONFIX, MF_BYCOMMAND, &Info);
  523. //
  524. // Set the text and id for install/uninstall menu item
  525. //
  526. Info.fMask = MIIM_STRING;
  527. if (pCurrentSelectedDB && pCurrentSelectedDB->type != DATABASE_TYPE_WORKING) {
  528. Info.dwTypeData = GetString(IDS_MENU_UINSTALL);
  529. } else {
  530. Info.dwTypeData = GetString(IDS_MENU_INSTALL);
  531. }
  532. SetMenuItemInfo(hMenu, ID_DATABASE_INSTALL_UNINSTALL, MF_BYCOMMAND, &Info);
  533. BOOL bReadOnly = (pCurrentSelectedDB && pCurrentSelectedDB->type != DATABASE_TYPE_WORKING);
  534. if (pCurrentSelectedDB == NULL) {
  535. bReadOnly = TRUE;
  536. }
  537. //
  538. // Close
  539. //
  540. iEnable = (pCurrentSelectedDB && pCurrentSelectedDB->type == DATABASE_TYPE_WORKING) ? MF_ENABLED : MF_GRAYED ;
  541. EnableMenuItem(hMenu, ID_DATABASE_CLOSE, iEnable);
  542. //
  543. // Disable the items for the global and Installed databases
  544. //
  545. iEnable = (bReadOnly) ? MF_GRAYED : MF_ENABLED;
  546. EnableMenuItem(hMenu, ID_FILE_SAVE, iEnable);
  547. EnableMenuItem(hMenu, ID_FILE_SAVEAS, iEnable);
  548. EnableMenuItem(hMenu, ID_FIX_CREATEANAPPLICATIONFIX, iEnable);
  549. EnableMenuItem(hMenu, ID_FIX_CREATENEWLAYER, iEnable);
  550. //
  551. // AppHelp mechanism is not supported in win2k
  552. //
  553. EnableMenuItem(hMenu,
  554. ID_FIX_CREATEANEWAPPHELPMESSAGE,
  555. (g_bWin2K) ? MF_GRAYED : iEnable);
  556. //
  557. // Save all and close all
  558. //
  559. if (!bReadOnly || typeSelectedItemDB == TYPE_GUI_DATABASE_WORKING_ALL) {
  560. iEnable = MF_ENABLED;
  561. } else {
  562. iEnable = MF_GRAYED;
  563. }
  564. EnableMenuItem(hMenu, ID_DATABASE_SAVEALL, iEnable);
  565. EnableMenuItem(hMenu, ID_DATABASE_CLOSEALL, iEnable);
  566. //
  567. // Paste menu item
  568. //
  569. if (bReadOnly) {
  570. EnableMenuItem(hMenu, ID_EDIT_PASTE, MF_GRAYED);
  571. } else {
  572. int iEnablePaste = (gClipBoard.pClipBoardHead) ? MF_ENABLED : MF_GRAYED;
  573. if (iEnablePaste == MF_ENABLED) {
  574. //
  575. // Check if the item that we have in the clipboard can be pasted in the item that we have got selected
  576. //
  577. if (gClipBoard.type == FIX_SHIM || gClipBoard.type == FIX_FLAG) {
  578. //
  579. // The focus should be on the db tree and a layer should be selected
  580. // in the db tree or the focus should be on the contents list and then
  581. // the root of all layes should be selected in the dbtree or a layer should
  582. // be selected.
  583. //
  584. if (hwndFocus == DBTree.m_hLibraryTree
  585. && typeSelectedItemDB == FIX_LAYER) {
  586. iEnablePaste = MF_ENABLED;
  587. } else if (hwndFocus == g_hwndContentsList
  588. && (typeSelectedItemDB == FIX_LAYER
  589. || typeSelectedItemDB == TYPE_GUI_LAYERS)) {
  590. //
  591. // We have focus on the contents list, we can paste shims if a layer is selected
  592. // or the root of all layers is selected in the db tree
  593. //
  594. iEnablePaste = MF_ENABLED;
  595. } else {
  596. iEnablePaste = MF_GRAYED;
  597. }
  598. } else if (gClipBoard.type == FIX_LAYER || gClipBoard.type == TYPE_GUI_LAYERS) {
  599. //
  600. // In the db tree we should have a database or the all layers item selected
  601. //
  602. if (typeSelectedItemDB == TYPE_GUI_LAYERS || typeSelectedItemDB == DATABASE_TYPE_WORKING) {
  603. iEnablePaste = MF_ENABLED;
  604. } else {
  605. iEnablePaste = MF_GRAYED;
  606. }
  607. } else if (gClipBoard.type == TYPE_ENTRY) {
  608. //
  609. // If we have copied an entry from the entry tree, in the db tree the focus can be
  610. // on a database, an application, or all application node
  611. //
  612. if (typeSelectedItemDB == DATABASE_TYPE_WORKING
  613. || (typeSelectedItemDB == TYPE_ENTRY && gClipBoard.SourceType == ENTRY_TREE)
  614. || typeSelectedItemDB == TYPE_GUI_APPS) {
  615. iEnablePaste = MF_ENABLED;
  616. } else {
  617. iEnablePaste = MF_GRAYED;
  618. }
  619. }
  620. }
  621. EnableMenuItem(hMenu, ID_EDIT_PASTE, iEnablePaste);
  622. }
  623. BOOL bEnableCopy = FALSE, bEnableModify = FALSE;
  624. HWND hwndGetFocus = GetFocus();
  625. HTREEITEM hItemSelected = NULL;
  626. TYPE type = TYPE_UNKNOWN;
  627. //
  628. // First get the type of the selected tree item and the corresponding type
  629. //
  630. if (hwndGetFocus == DBTree.m_hLibraryTree || hwndFocus == g_hwndEntryTree) {
  631. //
  632. // For the db tree or the entry tree
  633. //
  634. hItemSelected = TreeView_GetSelection(hwndGetFocus);
  635. type = (TYPE)GetItemType(hwndGetFocus, hItemSelected);
  636. } else {
  637. //
  638. // For the contents list, the tree item is the item that is selected in the db tree
  639. //
  640. hItemSelected = TreeView_GetSelection(DBTree.m_hLibraryTree);
  641. type = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItemSelected);
  642. }
  643. //
  644. // Copy will be enabled only if the presently selected item is copy-able
  645. //
  646. if (hwndGetFocus == DBTree.m_hLibraryTree) {
  647. //
  648. // For the db tree
  649. //
  650. if (hItemSelected) {
  651. if (type == TYPE_ENTRY
  652. || type == FIX_LAYER
  653. || type == FIX_SHIM
  654. || type == FIX_FLAG
  655. || type == TYPE_GUI_APPS
  656. || type == TYPE_GUI_LAYERS) {
  657. bEnableCopy = TRUE;
  658. }
  659. }
  660. } else if (hwndGetFocus == g_hwndEntryTree) {
  661. //
  662. // For the entry tree
  663. //
  664. if (hItemSelected) {
  665. if (type == TYPE_ENTRY) {
  666. bEnableCopy = TRUE;
  667. }
  668. }
  669. } else if (hwndFocus == g_hwndContentsList) {
  670. //
  671. // For the contents list
  672. //
  673. if (type == TYPE_GUI_APPS
  674. || type == TYPE_GUI_LAYERS
  675. || type == FIX_LAYER
  676. || type == TYPE_GUI_SHIMS) {
  677. //
  678. // Make sure atleast one is selected
  679. //
  680. if (ListView_GetSelectedCount(g_hwndContentsList) > 0) {
  681. bEnableCopy = TRUE;
  682. }
  683. }
  684. }
  685. iEnable = (bEnableCopy && pCurrentSelectedDB) ? MF_ENABLED : MF_GRAYED;
  686. EnableMenuItem(hMenu, ID_EDIT_COPY, iEnable);
  687. iEnable = (bReadOnly) ? MF_GRAYED : iEnable;
  688. //
  689. // Cut Menu
  690. //
  691. if (bReadOnly) {
  692. iEnable = MF_GRAYED;
  693. }
  694. if (hwndFocus == DBTree.m_hLibraryTree) {
  695. if (type == TYPE_GUI_SHIMS || type == FIX_SHIM || type == FIX_FLAG) {
  696. iEnable = MF_GRAYED;
  697. }
  698. } else if (hwndFocus == g_hwndContentsList) {
  699. //
  700. // Cut is not available for the shims
  701. //
  702. if (type == TYPE_GUI_SHIMS || type == FIX_LAYER) {
  703. iEnable = MF_GRAYED;
  704. }
  705. }
  706. EnableMenuItem(hMenu, ID_EDIT_CUT, iEnable);
  707. //
  708. // Delete Menu
  709. //
  710. if (hwndFocus == g_hwndEntryTree) {
  711. //
  712. // For the entry tree, If the db is not readonly, everything except the commandline for the shim and the
  713. // in-exclude items are prone to deletion
  714. //
  715. if (bReadOnly
  716. || type == TYPE_GUI_COMMANDLINE
  717. || type == TYPE_GUI_EXCLUDE
  718. || type == TYPE_GUI_INCLUDE
  719. || g_pSelEntry == NULL) {
  720. EnableMenuItem(hMenu, ID_EDIT_DELETE, MF_GRAYED);
  721. } else {
  722. EnableMenuItem(hMenu, ID_EDIT_DELETE, MF_ENABLED);
  723. }
  724. } else {
  725. //
  726. // If we are not on the entry tree, then what can be cut can be deleted as well
  727. //
  728. EnableMenuItem(hMenu, ID_EDIT_DELETE, iEnable);
  729. }
  730. EnableMenuItem(hMenu, ID_MODIFY_APPLICATIONFIX, MF_GRAYED);
  731. EnableMenuItem(hMenu, ID_MODIFY_APPHELPMESSAGE, MF_GRAYED);
  732. EnableMenuItem(hMenu, ID_MODIFY_COMPATIBILITYMODE, MF_GRAYED);
  733. //
  734. // Modify Menu
  735. //
  736. if (!bReadOnly && hwndGetFocus == g_hwndEntryTree && type == TYPE_ENTRY) {
  737. EnableMenuItem(hMenu, ID_MODIFY_APPLICATIONFIX, MF_ENABLED);
  738. //
  739. // AppHelp mechanism is not supported in win2k
  740. //
  741. EnableMenuItem(hMenu,
  742. ID_MODIFY_APPHELPMESSAGE,
  743. (g_bWin2K) ? MF_GRAYED : MF_ENABLED);
  744. }
  745. if (!bReadOnly && hwndGetFocus == DBTree.m_hLibraryTree && type == FIX_LAYER) {
  746. EnableMenuItem(hMenu, ID_MODIFY_COMPATIBILITYMODE, MF_ENABLED);
  747. }
  748. //
  749. // Install / Un-install menu should be enabled iff we are not on the system db and g_pPresentDatabase is valid
  750. //
  751. iEnable = (pCurrentSelectedDB && (pCurrentSelectedDB->type != DATABASE_TYPE_GLOBAL)) ? MF_ENABLED : MF_GRAYED;
  752. EnableMenuItem(hMenu, ID_DATABASE_INSTALL_UNINSTALL, iEnable);
  753. //
  754. // If no entry has been selected
  755. //
  756. iEnable = (g_pSelEntry == NULL) ? MF_GRAYED : MF_ENABLED;
  757. EnableMenuItem(hMenu, ID_FIX_CHANGEENABLESTATUS, iEnable);
  758. EnableMenuItem(hMenu, ID_FIX_EXECUTEAPPLICATION, iEnable);
  759. //
  760. // Rename
  761. //
  762. iEnable = MF_GRAYED;
  763. if (!bReadOnly && (hwndGetFocus == DBTree.m_hLibraryTree)) {
  764. if (type == TYPE_ENTRY || type == FIX_LAYER || type == DATABASE_TYPE_WORKING) {
  765. iEnable = MF_ENABLED;
  766. }
  767. } else if (!bReadOnly && (hwndGetFocus == g_hwndContentsList)) {
  768. if (type == TYPE_GUI_APPS
  769. || type == TYPE_GUI_LAYERS) {
  770. iEnable = MF_ENABLED;
  771. }
  772. }
  773. EnableMenuItem(hMenu, ID_EDIT_RENAME, iEnable);
  774. //
  775. // Configure LUA. Can be true when on entry-fix only
  776. //
  777. iEnable = !bReadOnly
  778. && (hwndFocus == g_hwndEntryTree)
  779. && (type == TYPE_ENTRY)
  780. && IsLUARedirectFSPresent(g_pSelEntry) ? MF_ENABLED : MF_GRAYED;
  781. EnableMenuItem(hMenu, ID_EDIT_CONFIGURELUA, iEnable);
  782. //
  783. // The db properties. We do not want this to be enabled, if we are on the
  784. // system database and somebody else is trying to load the exe entries of the
  785. // system datbase.
  786. // The reason is that for showing the properties we will
  787. // have to load the system database exe entries and we do not want 2 threads to load
  788. // the system database entries
  789. //
  790. (pCurrentSelectedDB && !(pCurrentSelectedDB->type == DATABASE_TYPE_GLOBAL && g_bExpanding)) ?
  791. (iEnable) = MF_ENABLED : MF_GRAYED;
  792. EnableMenuItem(hMenu, ID_FILE_PROPERTIES, iEnable);
  793. }
  794. void
  795. DoInstallUnInstall(
  796. void
  797. )
  798. /*++
  799. DoInstallUninstall
  800. Desc: Will install or uinstall the presently selected database, depending
  801. upon if the present database is a workign database or an installed
  802. database
  803. Params:
  804. void
  805. Return:
  806. void
  807. --*/
  808. {
  809. BOOL bReturn = FALSE;
  810. PDATABASE pDatabaseTemp = NULL;
  811. PDATABASE pPresentDatabase = GetCurrentDB();
  812. if (pPresentDatabase == NULL) {
  813. Dbg(dlError, "[DoInstallUnInstall], pPresentDatabase is NULL %d ");
  814. return;
  815. }
  816. //
  817. // Non admins cannot do a install-uintsall because we need to invoke
  818. // sdbinst.exe and sdbinst.exe cannot be invoked if we
  819. // do not have admin rights
  820. //
  821. if (g_bAdmin == FALSE) {
  822. MessageBox(g_hDlg,
  823. GetString(IDS_ERRORNOTADMIN),
  824. g_szAppName,
  825. MB_ICONINFORMATION);
  826. return;
  827. }
  828. if (pPresentDatabase->type == DATABASE_TYPE_INSTALLED) {
  829. //
  830. // This will uninstall the database
  831. //
  832. bReturn = InstallDatabase(CSTRING(pPresentDatabase->strPath),
  833. TEXT("-u -q"),
  834. TRUE);
  835. if (bReturn) {
  836. pDatabaseTemp = InstalledDataBaseList.FindDB(pPresentDatabase);
  837. if (pDatabaseTemp) {
  838. DBTree.RemoveDataBase(pDatabaseTemp->hItemDB, DATABASE_TYPE_INSTALLED, FALSE);
  839. InstalledDataBaseList.Remove(pDatabaseTemp);
  840. } else {
  841. assert(FALSE);
  842. }
  843. }
  844. } else {
  845. //
  846. // Check if we have the complete path of the database, that is this has at least been saved once earlier
  847. // Also check if this is presently dirty, we prompt the user to save the database
  848. //
  849. if (NotCompletePath(pPresentDatabase->strPath) ||
  850. pPresentDatabase->bChanged) {
  851. MessageBox(g_hDlg,
  852. GetString(IDS_NOTSAVEDBEFOREINSTALL),
  853. g_szAppName,
  854. MB_ICONINFORMATION);
  855. return;
  856. }
  857. //
  858. // Install the database
  859. //
  860. bReturn = InstallDatabase(CSTRING(pPresentDatabase->strPath),
  861. TEXT("-q"),
  862. TRUE);
  863. if (bReturn == TRUE) {
  864. //
  865. // Check if we have this database already in the DB tree view
  866. //
  867. pDatabaseTemp = InstalledDataBaseList.FindDBByGuid(pPresentDatabase->szGUID);
  868. if (pDatabaseTemp) {
  869. //
  870. // Remove the pre-exising database
  871. //
  872. DBTree.RemoveDataBase(pDatabaseTemp->hItemDB, DATABASE_TYPE_INSTALLED, FALSE);
  873. InstalledDataBaseList.Remove(pDatabaseTemp);
  874. }
  875. //
  876. // Load the newly installed database
  877. //
  878. LoadSpecificInstalledDatabaseGuid(pPresentDatabase->szGUID);
  879. }
  880. }
  881. SetFocus(g_hDlg);
  882. }
  883. BOOL
  884. SearchGroupForSID(
  885. IN DWORD dwGroup,
  886. OUT BOOL* pfIsMember
  887. )
  888. /*++
  889. SearchGroupForSID
  890. Desc: Checks if the current user is a part of a group
  891. Params:
  892. IN DWORD dwGroup: Is the user a part of this group
  893. OUT BOOL* pfIsMember: Will be true if the user is a member of the specified group
  894. FALSE otherwise
  895. Return:
  896. TRUE: The value in pfIsMember is valid, the function executed successfully
  897. FALSE: Otherwise
  898. --*/
  899. {
  900. PSID pSID = NULL;
  901. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  902. BOOL fRes = TRUE;
  903. if (!AllocateAndInitializeSid(&SIDAuth,
  904. 2,
  905. SECURITY_BUILTIN_DOMAIN_RID,
  906. dwGroup,
  907. 0,
  908. 0,
  909. 0,
  910. 0,
  911. 0,
  912. 0,
  913. &pSID)) {
  914. fRes = FALSE;
  915. }
  916. if (!CheckTokenMembership(NULL, pSID, pfIsMember)) {
  917. fRes = FALSE;
  918. }
  919. if (pSID) {
  920. FreeSid(pSID);
  921. pSID = NULL;
  922. }
  923. return fRes;
  924. }
  925. BOOL
  926. IsAdmin(
  927. OUT BOOL* pbGuest
  928. )
  929. /*++
  930. IsAdmin
  931. Desc: Checks if the current user has administrative rights
  932. Params:
  933. OUT BOOL* pbGuest: Is this is a guest account
  934. Return:
  935. TRUE: The current user has admin rights
  936. FALSE: Otherwise
  937. --*/
  938. {
  939. BOOL bIsAdmin = FALSE, bReturn = TRUE;
  940. if (pbGuest) {
  941. *pbGuest = TRUE;
  942. }
  943. bReturn = SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &bIsAdmin);
  944. if (pbGuest) {
  945. bReturn &= SearchGroupForSID(DOMAIN_ALIAS_RID_GUESTS, pbGuest);
  946. }
  947. if (bReturn == FALSE) {
  948. Dbg(dlError, "[IsAdmin] SearchGroupForSID failed");
  949. return FALSE;
  950. }
  951. return (bIsAdmin);
  952. }
  953. void
  954. SetCaption(
  955. IN BOOL bIncludeDataBaseName, // (TRUE)
  956. IN PDATABASE pDataBase, // (NULL)
  957. IN BOOL bOnlyTreeItem // (FALSE)
  958. )
  959. /*++
  960. SetCaption
  961. Desc: Sets the caption of the main dialog. It may also set the text of the
  962. database item in the tree if it is needed.
  963. This will be needed when we have
  964. a) Changed the name of the database
  965. b) We have changed the "save" status of the database so the "*" will
  966. either need to be added or removed.
  967. Params:
  968. IN BOOL bIncludeDataBaseName (TRUE): Should the name of the database be
  969. included in the caption? This will be false when we have focus on say the
  970. "Installed databases" or "Working databases" or "Per-User Settings" tree items
  971. in the database tree (lhs)
  972. IN PDATABASE pDataBase (NULL): If this is NULL, we will set caption
  973. for the present database. Note that in some circumstances like when
  974. we have the focus on "Installed databases" or "Working databases"
  975. or "Per-User Settings" tree items in the database tree (lhs),
  976. g_pPresentDataBase will be NULL.
  977. IN BOOL bOnlyTreeItem (FALSE): Do we only want to change the text for
  978. the database tree item? This will be true when we handle rename for
  979. the database. This is used when we do a cut and we only want to indicate that
  980. the database from which we did a cut has changed by changing its tree label.
  981. At the time of cut our selected database will be the database
  982. in which we are doing the paste and we do not want to change the window caption
  983. --*/
  984. {
  985. CSTRING strDefaultCaption(IDS_DEFCAPTION);
  986. if (pDataBase == NULL) {
  987. pDataBase = g_pPresentDataBase;
  988. }
  989. if (bIncludeDataBaseName) {
  990. CSTRING strCaption;
  991. CSTRING strDBItemCaption;
  992. if (pDataBase && (pDataBase->type == DATABASE_TYPE_WORKING)) {
  993. if (pDataBase->bChanged) {
  994. strCaption.Sprintf(TEXT("%s - %s [%s] *"),
  995. strDefaultCaption.pszString,
  996. pDataBase->strName.pszString,
  997. pDataBase->strPath.pszString);
  998. strDBItemCaption.Sprintf(TEXT("%s [%s] *"),
  999. pDataBase->strName.pszString,
  1000. pDataBase->strPath.pszString);
  1001. } else {
  1002. strCaption.Sprintf(TEXT("%s - %s [%s]"),
  1003. strDefaultCaption.pszString,
  1004. pDataBase->strName.pszString,
  1005. pDataBase->strPath.pszString);
  1006. strDBItemCaption.Sprintf(TEXT("%s [%s]"),
  1007. pDataBase->strName.pszString,
  1008. pDataBase->strPath.pszString);
  1009. }
  1010. //
  1011. // Change the text for the database in the DB Tree
  1012. //
  1013. TVITEM Item;
  1014. Item.mask = TVIF_TEXT;
  1015. Item.pszText = strDBItemCaption;
  1016. Item.hItem = pDataBase->hItemDB;
  1017. TreeView_SetItem(DBTree.m_hLibraryTree, &Item);
  1018. if (bOnlyTreeItem) {
  1019. return;
  1020. }
  1021. } else if (pDataBase && (pDataBase->type == DATABASE_TYPE_INSTALLED)) {
  1022. strCaption.Sprintf(TEXT("%s - %s "), strDefaultCaption.pszString,
  1023. GetString(IDS_CAPTION2));
  1024. strCaption.Strcat(GetString(IDS_READONLY));
  1025. } else if (pDataBase && (pDataBase->type == DATABASE_TYPE_GLOBAL)) {
  1026. strCaption.Sprintf(TEXT("%s - %s "), strDefaultCaption.pszString,
  1027. GetString(IDS_CAPTION3));
  1028. strCaption.Strcat(GetString(IDS_READONLY));
  1029. }
  1030. SetWindowText(g_hDlg, strCaption);
  1031. } else {
  1032. //
  1033. // The focus is on one of the items for which the caption of the
  1034. // main dialog should be the name of the app only. e.g. of such items
  1035. // are: The "System Database" item, the "Installed Databases" item etc.
  1036. //
  1037. SetWindowText(g_hDlg, (LPCTSTR)strDefaultCaption);
  1038. }
  1039. }
  1040. void
  1041. Dbg(
  1042. IN DEBUGLEVEL debugLevel,
  1043. IN LPSTR pszFmt
  1044. ...
  1045. )
  1046. /*++
  1047. LogMsg
  1048. Desc: Debugging spew
  1049. Params:
  1050. IN DEBUGLEVEL debugLevel: The debugging level. See values in DEBUGLEVEL enum
  1051. IN LPSTR pszFmt : Format string that has to be passed to va_start
  1052. Return:
  1053. void
  1054. --*/
  1055. {
  1056. K_SIZE k_sz = 1024;
  1057. CHAR szMessage[k_sz];
  1058. va_list arglist;
  1059. va_start(arglist, pszFmt);
  1060. StringCchVPrintfA(szMessage, k_sz, pszFmt, arglist);
  1061. va_end(arglist);
  1062. switch (debugLevel) {
  1063. case dlPrint:
  1064. DbgPrint("[MSG ] ");
  1065. break;
  1066. case dlError:
  1067. DbgPrint("[FAIL] ");
  1068. break;
  1069. case dlWarning:
  1070. DbgPrint("[WARN] ");
  1071. break;
  1072. case dlInfo:
  1073. DbgPrint("[INFO] ");
  1074. break;
  1075. default:
  1076. DbgPrint("[XXXX] ");
  1077. break;
  1078. }
  1079. DbgPrint(szMessage);
  1080. DbgPrint("\n");
  1081. }
  1082. void
  1083. InsertColumnIntoListView(
  1084. IN HWND hWnd,
  1085. IN LPTSTR lpszColumn,
  1086. IN INT iCol,
  1087. IN DWORD widthPercent
  1088. )
  1089. /*++
  1090. InsertColumnIntoListView
  1091. Desc: Inserts a new column to the list view
  1092. Params:
  1093. IN HWND hWnd: Handle to the list view
  1094. IN LPTSTR lpszColumn: The heading of the column to be added
  1095. IN INT iCol: The sub item, first is 0
  1096. IN DWORD widthPercent: The percentage width of this column
  1097. Return:
  1098. void
  1099. --*/
  1100. {
  1101. LVCOLUMN lvc;
  1102. RECT rcClient;
  1103. DWORD width;
  1104. GetWindowRect(hWnd, &rcClient);
  1105. width = rcClient.right - rcClient.left - GetSystemMetrics(SM_CXVSCROLL);
  1106. width = width * widthPercent / 100;
  1107. lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
  1108. lvc.fmt = LVCFMT_LEFT;
  1109. lvc.iSubItem = iCol;
  1110. lvc.cx = width;
  1111. lvc.pszText = lpszColumn;
  1112. ListView_InsertColumn(hWnd, iCol, &lvc);
  1113. }
  1114. UINT
  1115. LookupFileImage(
  1116. IN HIMAGELIST hImageList,
  1117. IN LPCTSTR szFilename,
  1118. IN UINT uDefault,
  1119. IN OUT UINT *puArray,
  1120. IN UINT uArrayCount
  1121. )
  1122. /*++
  1123. <TODO>: Re-write this code to use a map
  1124. LookupFileImage
  1125. Desc: Adds the icon for the file szFilename in imagelist hImageList
  1126. Params:
  1127. IN HIMAGELIST hImageList: The imagelist in which we want to add the
  1128. icon for the file
  1129. IN LPCTSTR szFilename: Path of the file
  1130. IN UINT uDefault: Default icon to be loaded if no icon is found
  1131. IN OUT UINT *puArray: The array that stores the mapping between the
  1132. index of the icon in the system imagelist and that in the imagelist specified
  1133. by hImageList. puArray[X] == A means that the image with Info.iIcon is stored
  1134. at index A in the local imagelist hImageList. It is assumed that caller
  1135. will have a puArray, hImageList pair
  1136. IN UINT uArrayCount: Number of elements that can be stored in
  1137. puArray
  1138. Return: Index of the image in hImageList
  1139. --*/
  1140. {
  1141. SHFILEINFO Info;
  1142. HIMAGELIST hList;
  1143. UINT uImage = 0;
  1144. INT iPos = 0;
  1145. ZeroMemory(&Info, sizeof(Info));
  1146. hList = (HIMAGELIST)SHGetFileInfo(szFilename,
  1147. FILE_ATTRIBUTE_NORMAL,
  1148. &Info,
  1149. sizeof(Info),
  1150. SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
  1151. if (hList && Info.hIcon) {
  1152. if (puArray == NULL || Info.iIcon >= uArrayCount) {
  1153. uImage = ImageList_AddIcon(hImageList, Info.hIcon);
  1154. goto End;
  1155. }
  1156. if (puArray[Info.iIcon] == 0) {
  1157. iPos = ImageList_AddIcon(hImageList, Info.hIcon);
  1158. if (iPos != -1) {
  1159. puArray[Info.iIcon] = iPos;
  1160. }
  1161. }
  1162. uImage = puArray[Info.iIcon];
  1163. } else {
  1164. uImage = uDefault;
  1165. }
  1166. End:
  1167. if (Info.hIcon) {
  1168. DestroyIcon(Info.hIcon);
  1169. }
  1170. ImageList_Destroy(hList);
  1171. return uImage;
  1172. }
  1173. void
  1174. AddSingleEntry(
  1175. IN HWND hwndTree,
  1176. IN PDBENTRY pEntry
  1177. )
  1178. /*++
  1179. AddSingleEntry
  1180. Desc: Adds a single exe entry to the Exe Tree.
  1181. Entries are sorted by name in the tree
  1182. Params:
  1183. IN HWND hwndTree: The entry tree, this should be g_hwndEntryTree always.
  1184. IN PDBENTRY pEntry: The entry that has to be shown in the entry tree
  1185. Notes: The entry tree will eventually show all the entries for an app.
  1186. The entries are sorted by name in non-descending order
  1187. --*/
  1188. {
  1189. HTREEITEM hItemExe;
  1190. HTREEITEM hMatchItem;
  1191. HTREEITEM hItemMatchingFiles;
  1192. HTREEITEM hItemShims;
  1193. HTREEITEM hItemSingleShim;
  1194. PMATCHINGFILE pMatch;
  1195. TVINSERTSTRUCT is;
  1196. TCHAR szText[MAX_PATH];
  1197. UINT uImage; // Image to be displayed in the tree
  1198. if (hwndTree == NULL || pEntry == NULL) {
  1199. Dbg(dlError, "[AddSingleEntry] Invalid arguments");
  1200. return;
  1201. }
  1202. *szText = 0;
  1203. SafeCpyN(szText, (LPCTSTR)pEntry->strExeName, ARRAYSIZE(szText));
  1204. //
  1205. // Get the image for the entry
  1206. //
  1207. if (pEntry->bDisablePerUser || pEntry->bDisablePerMachine) {
  1208. uImage =IMAGE_WARNING;
  1209. } else {
  1210. uImage = LookupFileImage(g_hImageList,
  1211. pEntry->strExeName,
  1212. IMAGE_APPLICATION,
  1213. g_uImageRedirector,
  1214. ARRAYSIZE(g_uImageRedirector));
  1215. }
  1216. is.hParent = TVI_ROOT;
  1217. is.hInsertAfter = TVI_SORT;
  1218. is.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  1219. is.item.stateMask = TVIS_EXPANDED;
  1220. is.item.lParam = (LPARAM)pEntry;
  1221. is.item.pszText = szText;
  1222. is.item.iImage = uImage;
  1223. is.item.iSelectedImage = uImage;
  1224. //
  1225. // Insert the item for the entry
  1226. //
  1227. pEntry->hItemExe = hItemExe = TreeView_InsertItem(hwndTree, &is);
  1228. TreeView_SetItemState(hwndTree, hItemExe, TVIS_BOLD, TVIS_BOLD);
  1229. //
  1230. // Add apphelp item if apphelp is present
  1231. //
  1232. if (pEntry->appHelp.bPresent) {
  1233. TCHAR szAppHelpType[128];
  1234. *szAppHelpType = 0;
  1235. switch(pEntry->appHelp.severity) {
  1236. case APPTYPE_NONE:
  1237. GetString(IDS_NONE, szAppHelpType, ARRAYSIZE(szAppHelpType));
  1238. break;
  1239. case APPTYPE_INC_NOBLOCK:
  1240. GetString(IDS_NOBLOCK, szAppHelpType, ARRAYSIZE(szAppHelpType));
  1241. break;
  1242. case APPTYPE_INC_HARDBLOCK:
  1243. GetString(IDS_HARDBLOCK, szAppHelpType, ARRAYSIZE(szAppHelpType));
  1244. break;
  1245. case APPTYPE_MINORPROBLEM:
  1246. GetString(IDS_MINORPROBLEM, szAppHelpType, ARRAYSIZE(szAppHelpType));
  1247. break;
  1248. case APPTYPE_REINSTALL:
  1249. GetString(IDS_REINSTALL, szAppHelpType, ARRAYSIZE(szAppHelpType));
  1250. break;
  1251. }
  1252. *szText = 0;
  1253. if (StringCchPrintf(szText,
  1254. ARRAYSIZE(szText),
  1255. TEXT("%s - %s"),
  1256. CSTRING(IDS_APPHELP).pszString,
  1257. szAppHelpType) != S_OK) {
  1258. Dbg(dlError, "[AddSingleEntry]: szText has insufficent space");
  1259. }
  1260. is.hParent = hItemExe;
  1261. is.item.lParam = (LPARAM)pEntry->appHelp.pAppHelpinLib;
  1262. is.item.pszText = szText;
  1263. is.item.iImage = IMAGE_APPHELP;
  1264. is.item.iSelectedImage = IMAGE_APPHELP;
  1265. TreeView_InsertItem(hwndTree, &is);
  1266. }
  1267. //
  1268. // Add any shims or flags that are applied to the entry
  1269. //
  1270. if (pEntry->pFirstShim || pEntry->pFirstFlag) {
  1271. //
  1272. // For the user the shims and the flags are the same and so we do not
  1273. // distinguish between shims and flags in the UI
  1274. //
  1275. is.hParent = hItemExe;
  1276. is.hInsertAfter = TVI_SORT;
  1277. is.item.lParam = (TYPE)TYPE_GUI_SHIMS;
  1278. is.item.pszText = GetString(IDS_COMPATFIXES);
  1279. is.item.iImage = IMAGE_SHIM;
  1280. is.item.iSelectedImage = IMAGE_SHIM;
  1281. hItemShims = TreeView_InsertItem(hwndTree, &is);
  1282. is.hParent = hItemShims;
  1283. PSHIM_FIX_LIST pFixList = pEntry->pFirstShim;
  1284. //
  1285. // Add all the shims for this entry
  1286. //
  1287. while (pFixList) {
  1288. CSTRING strCommand;
  1289. if (pFixList->pShimFix == NULL) {
  1290. Dbg(dlError, "[AddSingleEntry]: pFixList->pShimFix == NULL");
  1291. goto Next_Shim;
  1292. }
  1293. is.hParent = hItemShims;
  1294. is.item.lParam = (LPARAM)pFixList->pShimFix;
  1295. is.item.pszText = pFixList->pShimFix->strName;
  1296. is.item.iImage = IMAGE_SHIM;
  1297. is.item.iSelectedImage = IMAGE_SHIM;
  1298. hItemSingleShim = TreeView_InsertItem(hwndTree, &is);
  1299. //
  1300. // Now add the include exclude list (Expert Mode only)
  1301. //
  1302. if (g_bExpert && (!pFixList->strlInExclude.IsEmpty()
  1303. || !pFixList->pShimFix->strlInExclude.IsEmpty())) {
  1304. is.hParent = hItemSingleShim;
  1305. //
  1306. // Include-Exclude lists are not shown in a sorted manner and are shown as is..
  1307. //
  1308. is.hInsertAfter = TVI_LAST;
  1309. PSTRLIST listTemp;
  1310. if (pFixList->strlInExclude.m_pHead) {
  1311. listTemp = pFixList->strlInExclude.m_pHead;
  1312. } else {
  1313. listTemp = pFixList->pShimFix->strlInExclude.m_pHead;
  1314. }
  1315. while (listTemp) {
  1316. if (listTemp->data == INCLUDE) {
  1317. is.item.iImage = IMAGE_INCLUDE;
  1318. is.item.iSelectedImage = IMAGE_INCLUDE;
  1319. is.item.lParam = TYPE_GUI_INCLUDE;
  1320. } else {
  1321. is.item.iImage = IMAGE_EXCLUDE;
  1322. is.item.iSelectedImage = IMAGE_EXCLUDE;
  1323. is.item.lParam = TYPE_GUI_EXCLUDE;
  1324. }
  1325. is.item.pszText = (LPTSTR)listTemp->szStr;
  1326. listTemp = listTemp->pNext;
  1327. TreeView_InsertItem(hwndTree, &is);
  1328. }
  1329. }
  1330. //
  1331. // Now add the command line
  1332. //
  1333. if (g_bExpert && pFixList->strCommandLine.Length()) {
  1334. strCommand.Sprintf(CSTRING(IDS_COMMANDLINE),
  1335. pFixList->strCommandLine);
  1336. } else if (g_bExpert && pFixList->pShimFix->strCommandLine.Length()) {
  1337. strCommand.Sprintf(CSTRING(IDS_COMMANDLINE),
  1338. pFixList->pShimFix->strCommandLine);
  1339. }
  1340. if (strCommand.Length()) {
  1341. is.hParent = hItemSingleShim;
  1342. is.item.lParam = TYPE_GUI_COMMANDLINE;
  1343. is.item.pszText = strCommand;
  1344. is.item.iImage = IMAGE_COMMANDLINE;
  1345. is.item.iSelectedImage = IMAGE_COMMANDLINE;
  1346. TreeView_InsertItem(hwndTree, &is);
  1347. }
  1348. //
  1349. // This might have got changed if we had a InExclude list as they have to
  1350. // be shown as is
  1351. //
  1352. is.hInsertAfter = TVI_SORT;
  1353. Next_Shim:
  1354. pFixList = pFixList->pNext;
  1355. }
  1356. TreeView_Expand(hwndTree, hItemShims, TVE_EXPAND);
  1357. }
  1358. //
  1359. // Add any patches for this entry
  1360. //
  1361. if (pEntry->pFirstPatch) {
  1362. HTREEITEM hItemPatches;
  1363. is.hParent = hItemExe;
  1364. is.hInsertAfter = TVI_SORT;
  1365. is.item.lParam = (TYPE)TYPE_GUI_PATCHES;
  1366. is.item.pszText = GetString(IDS_COMPATPATCHES);
  1367. is.item.iImage = IMAGE_PATCHES;
  1368. is.item.iSelectedImage = IMAGE_PATCHES;
  1369. hItemPatches = TreeView_InsertItem(hwndTree, &is);
  1370. is.hParent = hItemPatches;
  1371. PPATCH_FIX_LIST pFixList = pEntry->pFirstPatch;
  1372. while (pFixList) {
  1373. if (pFixList->pPatchFix == NULL) {
  1374. Dbg(dlError, "[AddSingleEntry]: pFixList->pPatchFix == NULL");
  1375. goto Next_Patch;
  1376. }
  1377. is.item.lParam = (LPARAM)pFixList->pPatchFix;
  1378. is.item.pszText = pFixList->pPatchFix->strName;
  1379. TreeView_InsertItem(hwndTree, &is);
  1380. Next_Patch:
  1381. pFixList = pFixList->pNext;
  1382. }
  1383. TreeView_Expand(hwndTree, hItemPatches, TVE_EXPAND);
  1384. }
  1385. //
  1386. // Add all the flags for this entry
  1387. //
  1388. if (pEntry->pFirstFlag) {
  1389. is.hParent = hItemShims;
  1390. is.hInsertAfter = TVI_SORT;
  1391. is.item.iImage = IMAGE_SHIM;
  1392. is.item.iSelectedImage = IMAGE_SHIM;
  1393. PFLAG_FIX_LIST pFixList = pEntry->pFirstFlag;
  1394. HTREEITEM hItemSingleFlag = NULL;
  1395. CSTRING strCommand;
  1396. while (pFixList) {
  1397. if (pFixList->pFlagFix == NULL) {
  1398. Dbg(dlError, "[AddSingleEntry]: pFixList->pFlagFix == NULL");
  1399. goto Next_Flag;
  1400. }
  1401. is.item.lParam = (LPARAM)pFixList->pFlagFix;
  1402. is.item.pszText = pFixList->pFlagFix->strName;
  1403. hItemSingleFlag = TreeView_InsertItem(hwndTree, &is);
  1404. //
  1405. // Now add the command line
  1406. //
  1407. strCommand.Release();
  1408. if (g_bExpert) {
  1409. if (pFixList->strCommandLine.Length()) {
  1410. strCommand.Sprintf(CSTRING(IDS_COMMANDLINE),
  1411. pFixList->strCommandLine);
  1412. } else if (pFixList->pFlagFix->strCommandLine.Length()) {
  1413. strCommand.Sprintf(CSTRING(IDS_COMMANDLINE),
  1414. pFixList->pFlagFix->strCommandLine);
  1415. }
  1416. if (strCommand.Length()) {
  1417. is.hParent = hItemSingleFlag;
  1418. is.item.lParam = TYPE_GUI_COMMANDLINE;
  1419. is.item.pszText = strCommand;
  1420. is.item.iImage = IMAGE_COMMANDLINE;
  1421. is.item.iSelectedImage = IMAGE_COMMANDLINE;
  1422. TreeView_InsertItem(hwndTree, &is);
  1423. }
  1424. }
  1425. Next_Flag:
  1426. pFixList = pFixList->pNext;
  1427. }
  1428. TreeView_Expand(hwndTree, hItemShims, TVE_EXPAND);
  1429. }
  1430. //
  1431. // Add any layers that are applied to the entry
  1432. //
  1433. if (pEntry->pFirstLayer) {
  1434. HTREEITEM hItemLayers;
  1435. is.hParent = hItemExe;
  1436. is.hInsertAfter = TVI_SORT;
  1437. is.item.lParam = TYPE_GUI_LAYERS;
  1438. is.item.pszText = GetString(IDS_COMPATMODES);
  1439. is.item.iImage = IMAGE_LAYERS;
  1440. is.item.iSelectedImage = IMAGE_LAYERS;
  1441. hItemLayers = TreeView_InsertItem(hwndTree, &is);
  1442. is.hParent = hItemLayers;
  1443. PLAYER_FIX_LIST pFixList = pEntry->pFirstLayer;
  1444. while (pFixList) {
  1445. if (pFixList->pLayerFix == NULL) {
  1446. Dbg(dlError, "[AddSingleEntry]: pFixList->pLayerFix == NULL");
  1447. goto Next_Layer;
  1448. }
  1449. is.item.pszText = pFixList->pLayerFix->strName.pszString;
  1450. is.item.lParam = (LPARAM)pFixList->pLayerFix;
  1451. TreeView_InsertItem(hwndTree, &is);
  1452. Next_Layer:
  1453. pFixList = pFixList->pNext;
  1454. }
  1455. TreeView_Expand(hwndTree, hItemLayers, TVE_EXPAND);
  1456. }
  1457. //
  1458. // There will be atleast one matching file the program itself
  1459. //
  1460. pMatch = pEntry->pFirstMatchingFile;
  1461. is.hParent = hItemExe;
  1462. is.item.lParam = TYPE_GUI_MATCHING_FILES;
  1463. is.item.pszText = GetString(IDS_MATCHINGFILES);
  1464. is.item.iImage = IMAGE_MATCHGROUP;
  1465. is.item.iSelectedImage = IMAGE_MATCHGROUP;
  1466. hItemMatchingFiles = TreeView_InsertItem(hwndTree, &is);
  1467. //
  1468. // Add all the matching files for this entry
  1469. //
  1470. while (pMatch) {
  1471. TCHAR* pszMatchName;
  1472. if (lstrcmpi(pMatch->strMatchName, TEXT("*")) == 0) {
  1473. pszMatchName = pEntry->strExeName;
  1474. } else {
  1475. pszMatchName = pMatch->strMatchName;
  1476. }
  1477. uImage = LookupFileImage(g_hImageList,
  1478. pszMatchName,
  1479. IMAGE_APPLICATION,
  1480. g_uImageRedirector,
  1481. ARRAYSIZE(g_uImageRedirector));
  1482. is.hInsertAfter = TVI_SORT;
  1483. is.hParent = hItemMatchingFiles;
  1484. is.item.pszText = pszMatchName;
  1485. is.item.iImage = uImage;
  1486. is.item.iSelectedImage = uImage;
  1487. is.item.lParam = (LPARAM)pMatch;
  1488. hMatchItem = TreeView_InsertItem(hwndTree, &is);
  1489. is.hParent = hMatchItem;
  1490. is.hInsertAfter = TVI_LAST;
  1491. is.item.iImage = IMAGE_MATCHINFO;
  1492. is.item.iSelectedImage = IMAGE_MATCHINFO;
  1493. //
  1494. // Add the individual attributes of the matching file
  1495. //
  1496. PATTRINFO_NEW pAttr = pMatch->attributeList.pAttribute;
  1497. if (pAttr == NULL) {
  1498. Dbg(dlError, "[AddSingleEntry]: pAttr == NULL");
  1499. goto Next_MatchingFile;
  1500. }
  1501. for (DWORD dwIndex = 0; dwIndex < ATTRIBUTE_COUNT; ++dwIndex) {
  1502. *szText = 0;
  1503. DWORD dwPos = TagToIndex(pAttr[dwIndex].tAttrID);
  1504. if ((pAttr[dwIndex].dwFlags & ATTRIBUTE_AVAILABLE)
  1505. && dwPos != -1
  1506. && (pMatch->dwMask & (1 << (dwPos + 1)))) {
  1507. switch (pAttr[dwIndex].tAttrID) {
  1508. case TAG_BIN_PRODUCT_VERSION:
  1509. case TAG_BIN_FILE_VERSION:
  1510. case TAG_UPTO_BIN_PRODUCT_VERSION:
  1511. case TAG_UPTO_BIN_FILE_VERSION:
  1512. {
  1513. //
  1514. // Do our own formatting because SdbFormatAttribute does not
  1515. // show X.FFFF.FFFF.FFFF properly
  1516. // TODO: Remove this once SdbFormatAttribute is corrected
  1517. //
  1518. size_t cchRemaining = 0;
  1519. TCHAR* pchEnd = NULL;
  1520. if (StringCchPrintfEx(szText,
  1521. ARRAYSIZE(szText),
  1522. &pchEnd,
  1523. &cchRemaining,
  1524. 0,
  1525. TEXT("%s="), SdbTagToString(pAttr[dwIndex].tAttrID)) != S_OK) {
  1526. //
  1527. // Insufficient space
  1528. //
  1529. Dbg(dlError, "[AddSingleEntry] Do not have sufficient space in buffer");
  1530. break;
  1531. }
  1532. FormatVersion(pAttr[dwIndex].ullAttr, pchEnd, cchRemaining);
  1533. break;
  1534. }
  1535. default:
  1536. SdbFormatAttribute(&pAttr[dwIndex], szText, sizeof(szText)/sizeof(TCHAR));
  1537. }
  1538. is.item.pszText = szText;
  1539. is.item.lParam = TYPE_NULL + 1 + (1 << (dwPos + 1));
  1540. TreeView_InsertItem(hwndTree, &is);
  1541. }
  1542. }
  1543. TreeView_Expand(hwndTree, hMatchItem, TVE_EXPAND);
  1544. Next_MatchingFile:
  1545. pMatch = pMatch->pNext;
  1546. }
  1547. TreeView_Expand(hwndTree, hItemMatchingFiles, TVE_EXPAND);
  1548. TreeView_Expand(hwndTree, hItemExe, TVE_EXPAND);
  1549. }
  1550. void
  1551. UpdateEntryTreeView(
  1552. IN PDBENTRY pApps,
  1553. IN HWND hwndTree
  1554. )
  1555. /*++
  1556. UpdateEntryTreeView
  1557. Desc: Shows the entries for the App: pApps in the tree
  1558. Params:
  1559. IN PDBENTRY pApps: The app
  1560. IN HWND hwndTree: The handle to a tree
  1561. Return:
  1562. void
  1563. --*/
  1564. {
  1565. TCHAR szStatus[MAX_PATH];
  1566. PDBENTRY pEntry;
  1567. UINT uCount;
  1568. if (pApps == NULL || hwndTree == NULL) {
  1569. Dbg(dlError, "[UpdateEntryTreeView] Invalid arguments");
  1570. return;
  1571. }
  1572. //
  1573. // Now we are going to show the entry tree on the right hand side
  1574. // instead of the contents list
  1575. //
  1576. g_bIsContentListVisible = FALSE;
  1577. //
  1578. // Remove all the images of the preceeding app's entries and matching files.
  1579. //
  1580. if (hwndTree == g_hwndEntryTree) {
  1581. ZeroMemory(g_uImageRedirector, sizeof(g_uImageRedirector));
  1582. //
  1583. // Remove the images added by the previous app.
  1584. //
  1585. ImageList_SetImageCount(g_hImageList, IMAGE_LAST);
  1586. ShowWindow(g_hwndContentsList, SW_HIDE);
  1587. ShowWindow(g_hwndEntryTree, SW_SHOWNORMAL);
  1588. }
  1589. TreeDeleteAll(hwndTree);
  1590. //
  1591. // We need to set WM_SETREDRAW false after calling TreeDeleteAll because
  1592. // TreeDeleteAll will first set WM_SETREDRAW false before removing the tree items
  1593. // and then will again set it to true. But since we want to make
  1594. // WM_SETREDRAW false, we must explicitely set it to FALSE *AFTER* calling
  1595. // TreeDeleteAll()
  1596. //
  1597. SendMessage(hwndTree, WM_SETREDRAW, FALSE, 0);
  1598. pEntry = pApps;
  1599. uCount = 0;
  1600. //
  1601. // Add all the entries for this application to the entry tree
  1602. //
  1603. while(pEntry) {
  1604. AddSingleEntry(hwndTree, pEntry);
  1605. uCount++;
  1606. pEntry = pEntry->pSameAppExe;
  1607. }
  1608. SendMessage(hwndTree, WM_NCPAINT, 1, 0);
  1609. SendMessage(hwndTree, WM_SETREDRAW, TRUE, 0);
  1610. //
  1611. // Select the first item
  1612. //
  1613. HTREEITEM hItem= TreeView_GetChild(hwndTree, TVI_ROOT);
  1614. if (hItem) {
  1615. TreeView_SelectItem(hwndTree, hItem);
  1616. }
  1617. //
  1618. // Because tree view has a bug and sometimes the scroll bars are not painted properly
  1619. //
  1620. SendMessage(hwndTree, WM_NCPAINT, 1, 0);
  1621. *szStatus = 0;
  1622. StringCchPrintf(szStatus,
  1623. ARRAYSIZE(szStatus),
  1624. GetString(IDS_STA_ENTRYCOUNT),
  1625. pApps->strAppName.pszString,
  1626. uCount);
  1627. SetStatus(szStatus);
  1628. }
  1629. BOOL
  1630. CheckAndSave(
  1631. IN PDATABASE pDataBase
  1632. )
  1633. /*++
  1634. CheckAndSave
  1635. Desc: Saves a database if it is not saved
  1636. Params:
  1637. IN PDATABASE pDataBase. The database that has to be saved.
  1638. Return:
  1639. TRUE: If the database was properly saved
  1640. FALSE: If there were errors while saving. Error can be because of read-only file
  1641. or if the XML is invalid.
  1642. if the user pressed cancel, we return FALSE
  1643. --*/
  1644. {
  1645. CSTRING strDBName;
  1646. if (pDataBase == NULL) {
  1647. Dbg(dlError, "Invalid parameter passed %X", pDataBase);
  1648. return FALSE;
  1649. }
  1650. if (pDataBase && pDataBase->bChanged && pDataBase->type == DATABASE_TYPE_WORKING) {
  1651. strDBName.Sprintf(CSTRING(IDS_ASKSAVE).pszString,
  1652. pDataBase->strName);
  1653. int nResult = MessageBox(g_hDlg,
  1654. strDBName,
  1655. g_szAppName,
  1656. MB_YESNOCANCEL | MB_ICONWARNING);
  1657. if (nResult == IDCANCEL) {
  1658. return FALSE;
  1659. }
  1660. if (nResult == IDYES) {
  1661. BOOL bReturn;
  1662. //
  1663. // We check here that do we have the complete path of the .sdb?
  1664. // When we create a new database then we actually give it a name
  1665. // like Untitled_x, where x is an integer starting from 1.
  1666. // So if this is a new database, then we have to prompt for the file
  1667. // name in which this database has to be saved into
  1668. //
  1669. if (NotCompletePath(pDataBase->strPath)) {
  1670. bReturn = SaveDataBaseAs(pDataBase);
  1671. } else {
  1672. bReturn = SaveDataBase(pDataBase, pDataBase->strPath);
  1673. }
  1674. if (!bReturn) {
  1675. return FALSE;
  1676. }
  1677. pDataBase->bChanged = FALSE;
  1678. SetCaption();
  1679. }
  1680. }
  1681. return TRUE;
  1682. }
  1683. void
  1684. SetDefaultDescription(
  1685. void
  1686. )
  1687. /*++
  1688. SetDefaultDescription
  1689. Desc: Sets the text for the rich edit control when we have focus on a non-shim/non-flag
  1690. tree/list item or the shim/flag does not have a description
  1691. Params:
  1692. void
  1693. Return:
  1694. void
  1695. --*/
  1696. {
  1697. CHARFORMAT cf;
  1698. HWND hwndRichEdit = GetDlgItem(g_hDlg, IDC_DESCRIPTION);
  1699. TCHAR szCaption[128];
  1700. TCHAR szToolkit[256];
  1701. *szCaption = *szToolkit = 0;
  1702. //
  1703. // Handle "No Information case"
  1704. //
  1705. SafeCpyN(szCaption, GetString(IDS_NODESC), ARRAYSIZE(szCaption));
  1706. SafeCpyN(szToolkit, GetString(IDS_LATEST_TOOLKIT), ARRAYSIZE(szToolkit));
  1707. StringCchPrintf(g_szDesc,
  1708. ARRAYSIZE(g_szDesc),
  1709. TEXT("%s\r\n\r\n%s"),
  1710. szCaption,
  1711. szToolkit);
  1712. SetWindowText(hwndRichEdit, g_szDesc);
  1713. memset(&cf, 0, sizeof(CHARFORMAT));
  1714. cf.cbSize = sizeof(CHARFORMAT);
  1715. cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_UNDERLINE | CFM_LINK;
  1716. cf.crTextColor = RGB(0, 0, 0);
  1717. cf.dwEffects = 0;
  1718. SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
  1719. CHARRANGE cr;
  1720. cr.cpMin = 0;
  1721. cr.cpMax = wcslen(szCaption);
  1722. SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
  1723. memset(&cf, 0, sizeof(CHARFORMAT));
  1724. cf.cbSize = sizeof(CHARFORMAT);
  1725. cf.dwMask = CFM_COLOR | CFM_BOLD;
  1726. cf.crTextColor = RGB(0, 0, 127);
  1727. cf.dwEffects = CFE_BOLD;
  1728. SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  1729. cr.cpMin = 4 + wcslen(szCaption);
  1730. cr.cpMax = 4 + wcslen(szCaption) + wcslen(szToolkit);
  1731. SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
  1732. memset(&cf, 0, sizeof(CHARFORMAT));
  1733. cf.cbSize = sizeof(CHARFORMAT);
  1734. cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_LINK | CFM_UNDERLINE;
  1735. cf.crTextColor = RGB(0, 0, 255);
  1736. cf.dwEffects = CFE_LINK | CFE_UNDERLINE;
  1737. SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  1738. SendMessage(hwndRichEdit, EM_SETEVENTMASK, 0, ENM_LINK);
  1739. cr.cpMin = 0;
  1740. cr.cpMax = 0;
  1741. SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
  1742. }
  1743. void
  1744. SetDescription(
  1745. IN PCTSTR pszCaption,
  1746. IN PCTSTR pszTip
  1747. )
  1748. /*++
  1749. SetDescription
  1750. Desc: Sets the text for the rich edit descripotion window
  1751. Params:
  1752. IN TCHAR* pszCaption: The caption. This will be shown in the first line of the rich edit control
  1753. IN TCHAR* pszTip: The remaining text for the rich edit control
  1754. Return:
  1755. void
  1756. --*/
  1757. {
  1758. CHARFORMAT cf;
  1759. HWND hwndRichEdit = GetDlgItem(g_hDlg, IDC_DESCRIPTION);
  1760. if (pszCaption == NULL) {
  1761. SetDefaultDescription();
  1762. return;
  1763. }
  1764. //
  1765. // We have a valid caption, there is a shim whose description has to be shown or may be some
  1766. // apphelp whose message and URL we want to show
  1767. //
  1768. StringCchPrintf(g_szDesc, ARRAYSIZE(g_szDesc), TEXT("%s\r\n\r\n%s"), pszCaption, pszTip);
  1769. SetWindowText(hwndRichEdit, g_szDesc);
  1770. memset(&cf, 0, sizeof(CHARFORMAT));
  1771. cf.cbSize = sizeof(CHARFORMAT);
  1772. cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_UNDERLINE;
  1773. cf.crTextColor = RGB(0, 0, 0);
  1774. cf.dwEffects = 0;
  1775. SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
  1776. CHARRANGE cr;
  1777. cr.cpMin = 0;
  1778. cr.cpMax = wcslen(pszCaption);
  1779. SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
  1780. memset(&cf, 0, sizeof(CHARFORMAT));
  1781. cf.cbSize = sizeof(CHARFORMAT);
  1782. cf.dwMask = CFM_COLOR | CFM_BOLD;
  1783. cf.crTextColor = RGB(0, 0, 127);
  1784. cf.dwEffects = CFE_BOLD;
  1785. SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  1786. SendMessage(hwndRichEdit, EM_SETEVENTMASK, 0, 0);
  1787. cr.cpMin = 0;
  1788. cr.cpMax = 0;
  1789. SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
  1790. }
  1791. BOOL
  1792. HandleNotifyContentsList(
  1793. IN HWND hdlg,
  1794. IN LPARAM lParam
  1795. )
  1796. /*++
  1797. HandleNotifyContentsList
  1798. Desc: Handles the notification messages for the contents list (RHS)
  1799. Params:
  1800. IN HWND hdlg: The main dialog box for the app
  1801. IN LPARAM lParam: The lParam associated with WM_NOTIFY
  1802. --*/
  1803. {
  1804. LPNMHDR pnm = (LPNMHDR)lParam;
  1805. LV_DISPINFO* pnmv = (LV_DISPINFO FAR *)lParam;
  1806. if (pnmv == NULL) {
  1807. Dbg(dlError, "Invalid Input parameter lParam == NULL");
  1808. return FALSE;
  1809. }
  1810. switch (pnm->code) {
  1811. case LVN_BEGINLABELEDIT:
  1812. {
  1813. g_hwndEditText = (HWND)SendMessage(g_hwndContentsList,
  1814. LVM_GETEDITCONTROL,
  1815. 0,
  1816. 0);
  1817. if (g_hwndEditText) {
  1818. SendMessage(g_hwndEditText,
  1819. EM_LIMITTEXT,
  1820. (WPARAM)LIMIT_APP_NAME,
  1821. 0);
  1822. }
  1823. break;
  1824. }
  1825. case LVN_ENDLABELEDIT:
  1826. EndListViewLabelEdit(lParam);
  1827. break;
  1828. case LVN_KEYDOWN:
  1829. {
  1830. NMLVKEYDOWN FAR *plvkd = (NMLVKEYDOWN FAR*)lParam;
  1831. if (plvkd && plvkd->wVKey == 13) {
  1832. //
  1833. // Enter was pressed. We will send it the double click message.
  1834. //
  1835. NMITEMACTIVATE nmactivate;
  1836. nmactivate.hdr.hwndFrom = g_hwndContentsList;
  1837. nmactivate.hdr.idFrom = IDC_CONTENTSLIST;
  1838. nmactivate.hdr.code = NM_DBLCLK;
  1839. nmactivate.iItem = g_iContentsListSelectIndex;
  1840. SendMessage(GetParent(g_hwndContentsList),
  1841. WM_NOTIFY,
  1842. IDC_ENTRY,
  1843. (LPARAM)&nmactivate);
  1844. }
  1845. }
  1846. break;
  1847. case LVN_ITEMCHANGED:
  1848. {
  1849. LPNMLISTVIEW pnmlv = (LPNMLISTVIEW)lParam;
  1850. if (pnmlv && (pnmlv->uChanged & LVIF_STATE)) {
  1851. if (pnmlv->uNewState & LVIS_SELECTED) {
  1852. g_iContentsListSelectIndex = pnmlv->iItem;
  1853. TCHAR szText[256];
  1854. *szText = 0;
  1855. LVITEM lvItem;
  1856. lvItem.mask = TVIF_PARAM | LVIF_TEXT;
  1857. lvItem.iItem = pnmlv->iItem;
  1858. lvItem.iSubItem = 0;
  1859. lvItem.pszText = szText;
  1860. lvItem.cchTextMax = ARRAYSIZE(szText);
  1861. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  1862. Dbg(dlWarning, "[HandleNotifyContentsList] could not get listview item");
  1863. break;
  1864. }
  1865. if (GetFocus() == g_hwndContentsList) {
  1866. //
  1867. // Set the text in the status bar, as if we had selected the corresponding
  1868. // htreeitem in the db tree.
  1869. //
  1870. HTREEITEM hItemInDBTree = DBTree.FindChild(TreeView_GetSelection(DBTree.m_hLibraryTree),
  1871. lvItem.lParam);
  1872. SetStatusStringDBTree(hItemInDBTree);
  1873. }
  1874. //
  1875. // BUGBUG: This is only required if we ever show the databases in
  1876. // the contents list. Presently we do not show them in the
  1877. // contents list.
  1878. //
  1879. TYPE type = ConvertLparam2Type(lvItem.lParam);
  1880. if (type == DATABASE_TYPE_INSTALLED || type == DATABASE_TYPE_WORKING) {
  1881. g_pPresentDataBase = (PDATABASE) lvItem.lParam;
  1882. }
  1883. CSTRING strToolTip;
  1884. GetDescriptionString(lvItem.lParam,
  1885. strToolTip,
  1886. NULL,
  1887. szText,
  1888. NULL,
  1889. g_hwndContentsList,
  1890. pnmlv->iItem);
  1891. if (strToolTip.Length() > 0) {
  1892. SetDescription(szText, strToolTip.pszString);
  1893. } else {
  1894. SetDescription(NULL, TEXT(""));
  1895. }
  1896. }
  1897. }
  1898. break;
  1899. }
  1900. case NM_DBLCLK:
  1901. {
  1902. LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
  1903. if (lpnmitem == NULL) {
  1904. break;
  1905. }
  1906. LVITEM lvItem;
  1907. lvItem.mask = TVIF_PARAM;
  1908. lvItem.iItem = lpnmitem->iItem;
  1909. lvItem.iSubItem = 0;
  1910. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  1911. break;
  1912. }
  1913. TYPE type = ConvertLparam2Type(lvItem.lParam);
  1914. if (type == TYPE_ENTRY
  1915. || type == FIX_LAYER
  1916. || type == FIX_SHIM) {
  1917. HTREEITEM hItem = DBTree.FindChild(TreeView_GetSelection(DBTree.m_hLibraryTree),
  1918. lvItem.lParam);
  1919. if (hItem) {
  1920. TreeView_SelectItem(DBTree.m_hLibraryTree, hItem);
  1921. }
  1922. }
  1923. break;
  1924. }
  1925. default: return FALSE;
  1926. }
  1927. return TRUE;
  1928. }
  1929. BOOL
  1930. HandleNotifyDBTree(
  1931. IN HWND hdlg,
  1932. IN LPARAM lParam
  1933. )
  1934. /*++
  1935. HandleNotifyDBTree
  1936. Desc: Handles the notification messages for the db tree (LHS)
  1937. Params:
  1938. IN HWND hdlg: The main dialog box for the app
  1939. IN LPARAM lParam: The lParam associated with WM_NOTIFY
  1940. --*/
  1941. {
  1942. LPNMHDR pnm = (LPNMHDR)lParam;
  1943. LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
  1944. switch (pnm->code) {
  1945. case NM_RCLICK:
  1946. {
  1947. HWND hwndTree = pnm->hwndFrom;
  1948. TVHITTESTINFO ht;
  1949. GetCursorPos(&ht.pt);
  1950. ScreenToClient(hwndTree, &ht.pt);
  1951. TreeView_HitTest(hwndTree, &ht);
  1952. if (0 != ht.hItem) {
  1953. TreeView_SelectItem(hwndTree, ht.hItem);
  1954. }
  1955. break;
  1956. }
  1957. case TVN_SELCHANGED:
  1958. {
  1959. //
  1960. // Warning: Do not change the code so that we do a post message for UpdateEntryTreeView
  1961. //
  1962. // BOOL DatabaseTree::AddNewExe() Selects an app and assumes that the entry tree will be
  1963. // populated with correct values after TreeView_SelectItem() returns
  1964. //
  1965. TCHAR szText[256];
  1966. CSTRING strDesc;
  1967. LPARAM lParamTreeItem;
  1968. if (pnmtv == NULL) {
  1969. break;
  1970. }
  1971. *szText = 0;
  1972. if(pnmtv->itemNew.hItem != 0) {
  1973. HandleDBTreeSelChange(pnmtv->itemNew.hItem);
  1974. CTree::GetTreeItemText(DBTree.m_hLibraryTree,
  1975. pnmtv->itemNew.hItem,
  1976. szText,
  1977. ARRAYSIZE(szText));
  1978. DBTree.GetLParam(pnmtv->itemNew.hItem, &lParamTreeItem);
  1979. //
  1980. // Get the description string
  1981. //
  1982. GetDescriptionString(lParamTreeItem,
  1983. strDesc,
  1984. NULL,
  1985. szText,
  1986. pnmtv->itemNew.hItem,
  1987. DBTree.m_hLibraryTree);
  1988. if (strDesc.Length() > 0) {
  1989. SetDescription(szText, strDesc.pszString);
  1990. } else {
  1991. SetDescription(NULL, TEXT(""));
  1992. }
  1993. }
  1994. SetStatusStringDBTree(pnmtv->itemNew.hItem);
  1995. //
  1996. // Some buttons need to be disabled/enabled depending upon
  1997. // what database we are on
  1998. //
  1999. SetTBButtonStatus(g_hwndToolBar, DBTree.m_hLibraryTree);
  2000. break;
  2001. }
  2002. case TVN_ITEMEXPANDING:
  2003. {
  2004. if (pnmtv->action & TVE_EXPAND) {
  2005. if (pnmtv->itemNew.hItem == GlobalDataBase.hItemAllApps
  2006. && !g_bMainAppExpanded) {
  2007. //
  2008. // If we have not already loaded the apps for the main database then
  2009. // load it. When we start up we load only the library section of the main
  2010. // database and the layers in the main database. There are lots
  2011. // of apps in the system database and loading them at start up time
  2012. // will take some time and also consume lots of memory. Also
  2013. // normally people will not need to look at the system database
  2014. //
  2015. SetCursor(LoadCursor(NULL, IDC_WAIT));
  2016. INT iResult = ShowMainEntries(hdlg);
  2017. if (iResult == -1) {
  2018. //
  2019. // It is being loaded by somebody else. If we are using the query
  2020. // database feature then there we have a modeless window that
  2021. // creates a thread that calls ShowMainEntries(). We
  2022. // do not want that we should have two threads calling
  2023. // ShowMainEntries() at any given time
  2024. //
  2025. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, TRUE);
  2026. //
  2027. // The status message for the main dialog is changed to normal
  2028. // when we finish ShowMainEntries()
  2029. //
  2030. SetStatus(g_hwndStatus, CSTRING(IDS_LOADINGMAIN));
  2031. SetCursor(LoadCursor(NULL, IDC_WAIT));
  2032. } else {
  2033. SetCursor(LoadCursor(NULL, IDC_ARROW));
  2034. }
  2035. }
  2036. }
  2037. break;
  2038. }
  2039. case TVN_BEGINLABELEDIT:
  2040. {
  2041. if (g_pPresentDataBase == NULL || g_pPresentDataBase->type != DATABASE_TYPE_WORKING) {
  2042. return TRUE;
  2043. }
  2044. LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam;
  2045. if (ptvdi == NULL) {
  2046. break;
  2047. }
  2048. HTREEITEM hItem = ptvdi->item.hItem;
  2049. if (hItem == NULL) {
  2050. break;
  2051. }
  2052. TYPE type = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItem);
  2053. switch(type) {
  2054. case TYPE_ENTRY:
  2055. case FIX_LAYER:
  2056. case DATABASE_TYPE_WORKING:
  2057. g_hwndEditText = (HWND)SendMessage(DBTree.m_hLibraryTree,
  2058. TVM_GETEDITCONTROL,
  2059. 0,
  2060. 0);
  2061. break;
  2062. default: return TRUE;
  2063. }
  2064. if (g_hwndEditText) {
  2065. SendMessage(g_hwndEditText, EM_LIMITTEXT, (WPARAM)LIMIT_APP_NAME, (LPARAM)0);
  2066. } else {
  2067. break;
  2068. }
  2069. if (type == DATABASE_TYPE_WORKING) {
  2070. SetWindowText(g_hwndEditText, g_pPresentDataBase->strName);
  2071. //
  2072. // Select the text
  2073. //
  2074. SendMessage(g_hwndEditText, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  2075. }
  2076. return FALSE; // Allow the editting
  2077. break;
  2078. }
  2079. case TVN_ENDLABELEDIT:
  2080. {
  2081. g_hwndEditText = NULL;
  2082. LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam;
  2083. BOOL fValid = TRUE;
  2084. if (ptvdi == NULL || g_pPresentDataBase == NULL) {
  2085. Dbg(dlError, "[HandleNotifyDBTree] ptvdi == NULL || g_pPresentDataBase == NULL");
  2086. break;
  2087. }
  2088. HTREEITEM hItem = ptvdi->item.hItem;
  2089. if (hItem == NULL) {
  2090. break;
  2091. }
  2092. if (ptvdi->item.pszText == NULL) {
  2093. fValid = FALSE;
  2094. goto end;
  2095. }
  2096. TYPE type = (TYPE)GetItemType(DBTree.m_hLibraryTree, ptvdi->item.hItem);
  2097. TCHAR szText[256];
  2098. *szText = 0;
  2099. SafeCpyN(szText, ptvdi->item.pszText, ARRAYSIZE(szText));
  2100. if (CSTRING::Trim(szText) == 0) {
  2101. fValid = FALSE;
  2102. goto end;
  2103. }
  2104. switch (type) {
  2105. case TYPE_ENTRY:
  2106. {
  2107. PDBENTRY pEntry = (PDBENTRY)ptvdi->item.lParam;
  2108. PDBENTRY pApp = g_pPresentDataBase->pEntries;
  2109. if (!IsValidAppName(szText)) {
  2110. //
  2111. // The app name contains invalid chars
  2112. //
  2113. DisplayInvalidAppNameMessage(g_hDlg);
  2114. break;
  2115. }
  2116. while (pApp) {
  2117. if (pApp->strAppName == szText) {
  2118. //
  2119. // There already exists an app of the same name
  2120. // in the present database
  2121. //
  2122. MessageBox(g_hDlg,
  2123. GetString(IDS_SAMEAPPEXISTS),
  2124. g_szAppName,
  2125. MB_ICONWARNING);
  2126. fValid = FALSE;
  2127. }
  2128. pApp = pApp->pNext;
  2129. }
  2130. while (pEntry) {
  2131. pEntry->strAppName = szText;
  2132. pEntry = pEntry->pSameAppExe;
  2133. }
  2134. }
  2135. break;
  2136. case FIX_LAYER:
  2137. {
  2138. PLAYER_FIX plf = (PLAYER_FIX)ptvdi->item.lParam;
  2139. if (plf == NULL) {
  2140. assert(FALSE);
  2141. break;
  2142. }
  2143. if (FindFix(szText, FIX_LAYER, g_pPresentDataBase)) {
  2144. //
  2145. // A layer of this name already exists in the system database
  2146. // or the present database
  2147. //
  2148. MessageBox(g_hDlg,
  2149. GetString(IDS_LAYEREXISTS),
  2150. g_szAppName,
  2151. MB_ICONWARNING);
  2152. return FALSE;
  2153. }
  2154. plf->strName = szText;
  2155. }
  2156. break;
  2157. case DATABASE_TYPE_WORKING:
  2158. g_pPresentDataBase->strName = szText;
  2159. break;
  2160. default: fValid = FALSE;
  2161. }
  2162. end:
  2163. INT_PTR iStyle = GetWindowLongPtr(DBTree.m_hLibraryTree, GWL_STYLE);
  2164. iStyle &= ~TVS_EDITLABELS;
  2165. //
  2166. // Disable label editing. We need to do this, other
  2167. // wise whenever we have focus on some tree item after some time
  2168. // the edit box will appear there. We want that to appear only if we
  2169. // actually want to rename the stuff. The rename menu will be enabled
  2170. // only for items that can be renamed. We cannot rename anything that is in
  2171. // the system or the installed database
  2172. //
  2173. SetWindowLongPtr(DBTree.m_hLibraryTree, GWL_STYLE, iStyle);
  2174. if (fValid) {
  2175. //
  2176. // The handler for this message will now do the actual renaming of the tree
  2177. // item
  2178. //
  2179. g_pPresentDataBase->bChanged;
  2180. PostMessage(hdlg,
  2181. WM_USER_REPAINT_TREEITEM,
  2182. (WPARAM)ptvdi->item.hItem,
  2183. (LPARAM)ptvdi->item.lParam);
  2184. } else {
  2185. return FALSE;
  2186. }
  2187. break;
  2188. }
  2189. default: return FALSE;
  2190. }
  2191. return TRUE;
  2192. }
  2193. void
  2194. HandleNotifyExeTree(
  2195. IN HWND hdlg,
  2196. IN LPARAM lParam
  2197. )
  2198. /*++
  2199. HandleNotifyExeTree
  2200. Desc: Handles the notification messages for the entry tree (RHS)
  2201. Params:
  2202. IN HWND hdlg: The main dialog box for the app
  2203. IN LPARAM lParam: The lParam associated with WM_NOTIFY
  2204. --*/
  2205. {
  2206. LPNMHDR pnm = (LPNMHDR)lParam;
  2207. if (pnm == NULL) {
  2208. assert(FALSE);
  2209. Dbg(dlError, "[HandleNotifyExeTree] pnm == NULL");
  2210. return;
  2211. }
  2212. switch (pnm->code) {
  2213. case NM_RCLICK:
  2214. {
  2215. HWND hwndTree = pnm->hwndFrom;
  2216. TVHITTESTINFO ht;
  2217. GetCursorPos(&ht.pt);
  2218. ScreenToClient(hwndTree, &ht.pt);
  2219. TreeView_HitTest(hwndTree, &ht);
  2220. if (0 != ht.hItem) {
  2221. TreeView_SelectItem(hwndTree, ht.hItem);
  2222. }
  2223. break;
  2224. }
  2225. case TVN_SELCHANGED:
  2226. if (g_bDeletingEntryTree == FALSE) {
  2227. OnEntryTreeSelChange(lParam);
  2228. } else {
  2229. Dbg(dlWarning, "HandleNotifyExeTree : Got TVN_SELCHANGED for entry tree when we were deleting the entry tree");
  2230. }
  2231. break;
  2232. }
  2233. }
  2234. BOOL
  2235. GetFileName(
  2236. IN HWND hWnd,
  2237. IN LPCTSTR szTitle,
  2238. IN LPCTSTR szFilter,
  2239. IN LPCTSTR szDefaultFile,
  2240. IN LPCTSTR szDefExt,
  2241. IN DWORD dwFlags,
  2242. IN BOOL bOpen,
  2243. OUT CSTRING& szStr,
  2244. IN BOOL bDoNotVerifySDB // DEF = FALSE
  2245. )
  2246. /*++
  2247. Desc: Wrapper for GetOpenFileName() and GetSaveFileName()
  2248. Params:
  2249. IN HWND hWnd: Parent for the dialog
  2250. IN LPCTSTR szTitle:
  2251. IN LPCTSTR szFilter:
  2252. IN LPCTSTR szDefaultFile:
  2253. IN LPCTSTR szDefExt:
  2254. IN DWORD dwFlags:
  2255. IN BOOL bOpen: Whether we should show the open or save dialog
  2256. OUT CSTRING& szStr: This variable stores the name of the file
  2257. IN BOOL bDoNotVerifySDB (FALSE): When we use this routine to
  2258. get the file name with bOpen == FALSE, then this varible
  2259. determines whether we should check and add a .sdb at the end
  2260. of the file name, in case there is none.
  2261. --*/
  2262. {
  2263. OPENFILENAME ofn;
  2264. TCHAR szFilename[MAX_PATH_BUFFSIZE];
  2265. BOOL bResult;
  2266. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  2267. SafeCpyN(szFilename, szDefaultFile, ARRAYSIZE(szFilename));
  2268. ofn.lStructSize = sizeof(OPENFILENAME);
  2269. ofn.hwndOwner = hWnd;
  2270. ofn.hInstance = g_hInstance;
  2271. ofn.lpstrFilter = szFilter;
  2272. ofn.lpstrFile = szFilename;
  2273. ofn.nMaxFile = MAX_PATH;
  2274. ofn.lpstrInitialDir = szDefaultFile;
  2275. ofn.lpstrTitle = szTitle;
  2276. ofn.Flags = dwFlags | OFN_NOREADONLYRETURN | OFN_HIDEREADONLY;
  2277. ofn.lpstrDefExt = szDefExt;
  2278. ofn.lpstrCustomFilter = NULL;
  2279. ofn.nMaxCustFilter = 0;
  2280. ofn.nFilterIndex = 0;
  2281. BOOL valid = FALSE; // Whether path is too long / ends with .SDB or not. Applicable for save mode only
  2282. while (!valid) {
  2283. if (bOpen) {
  2284. bResult = GetOpenFileName(&ofn);
  2285. } else {
  2286. bResult = GetSaveFileName(&ofn);
  2287. }
  2288. if (!bResult) {
  2289. return FALSE;
  2290. }
  2291. szStr = szFilename;
  2292. if (bOpen || bDoNotVerifySDB) {
  2293. return TRUE;
  2294. }
  2295. //
  2296. // Do stuff to make sure that the file being saved has a .SDB extension
  2297. // and the filename is not too long so that a .SDB file name cannot
  2298. // not get appended to it.
  2299. //
  2300. if (szStr.Length() == 0) {
  2301. continue;
  2302. }
  2303. if (!szStr.EndsWith(TEXT(".sdb"))) {
  2304. if (szStr.Length() <= (MAX_PATH - 1 - 4)) {
  2305. szStr.Strcat(TEXT(".sdb"));
  2306. valid = TRUE;
  2307. }
  2308. } else {
  2309. valid = TRUE;
  2310. }
  2311. if (!valid) {
  2312. //
  2313. // The path did not have a .sdb extension and we were not able to append one, because it was
  2314. // a long path
  2315. //
  2316. CSTRING message(IDS_PATHENTERED1);
  2317. message.Strcat(szStr);
  2318. message.Strcat(GetString(IDS_PATHENTERED2));
  2319. MessageBox(hWnd, message, g_szAppName, MB_ICONWARNING);
  2320. }
  2321. }
  2322. return TRUE;
  2323. }
  2324. BOOL
  2325. OpenDatabaseFiles(
  2326. IN HWND hdlg
  2327. )
  2328. /*++
  2329. OpenDatabaseFiles
  2330. Desc: Shows the open common dialog box and opens the database file(s)
  2331. selected
  2332. Params:
  2333. IN HWND hdlg: Parent for the open common dialog box
  2334. Return:
  2335. TRUE: The user selected a sdb file and at least one sdb was opened,
  2336. or highlighted because it was already opened.
  2337. FALSE: Otherwise
  2338. --*/
  2339. {
  2340. OPENFILENAME ofn;
  2341. TCHAR szCaption[128];
  2342. TCHAR szFilter[128];
  2343. TCHAR szExt[8];
  2344. CSTRINGLIST strlPaths;
  2345. TCHAR szFullPath[MAX_PATH * 2];
  2346. PSTRLIST pstrlIndex = NULL;
  2347. BOOL bRemaining = TRUE;
  2348. PCTSTR pszIndex = NULL;
  2349. INT iIndexToInsert = 0;
  2350. INT iLengthFileName = 0;
  2351. BOOL bOk = FALSE;
  2352. PTSTR pszFilesList = NULL;
  2353. K_SIZE k_pszFilesList = MAX_BUFF_OPENMULTIPLE_FILES;
  2354. pszFilesList = new TCHAR[k_pszFilesList];
  2355. if (pszFilesList == NULL) {
  2356. MEM_ERR;
  2357. goto End;
  2358. }
  2359. *szCaption = *pszFilesList = *szFilter = *szExt = 0;
  2360. GetString(IDS_OPENDATABASE, szCaption, ARRAYSIZE(szCaption));
  2361. ofn.lStructSize = sizeof(OPENFILENAME);
  2362. ofn.hwndOwner = hdlg;
  2363. ofn.hInstance = NULL;
  2364. ofn.lpstrFilter = GetString(IDS_FILTER, szFilter, ARRAYSIZE(szFilter));
  2365. ofn.lpstrCustomFilter = NULL;
  2366. ofn.nMaxCustFilter = 0;
  2367. ofn.nFilterIndex = 0;
  2368. ofn.lpstrFile = pszFilesList;
  2369. ofn.nMaxFile = k_pszFilesList;
  2370. ofn.lpstrFileTitle = NULL;
  2371. ofn.nMaxFileTitle = 0;
  2372. ofn.lpstrInitialDir = NULL;
  2373. ofn.lpstrTitle = szCaption;
  2374. ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
  2375. ofn.lpstrDefExt = GetString(IDS_FILTER, szExt, ARRAYSIZE(szExt));
  2376. if (GetOpenFileName(&ofn)) {
  2377. //
  2378. // If the database is a big one, then the open dialog box stays put, so
  2379. // we update the controls forcibly
  2380. //
  2381. UpdateControls();
  2382. if (pszFilesList[ofn.nFileOffset - 1] == 0) {
  2383. //
  2384. // User has selected more than one file
  2385. //
  2386. SafeCpyN(szFullPath, pszFilesList, MAX_PATH);
  2387. ADD_PATH_SEPARATOR(szFullPath, ARRAYSIZE(szFullPath));
  2388. iIndexToInsert = lstrlen(szFullPath);
  2389. }
  2390. //
  2391. // Point to the first file
  2392. //
  2393. pszIndex = pszFilesList + ofn.nFileOffset;
  2394. while (bRemaining) {
  2395. if (pszFilesList[ofn.nFileOffset - 1] != 0) {
  2396. //
  2397. // User has selected only a single file
  2398. //
  2399. bRemaining = FALSE;
  2400. SafeCpyN(szFullPath, pszFilesList, MAX_PATH);
  2401. } else {
  2402. iLengthFileName = lstrlen(pszIndex);
  2403. if (*(pszIndex + iLengthFileName + 1) == 0) {
  2404. //
  2405. // This is the last component
  2406. //
  2407. bRemaining = FALSE;
  2408. }
  2409. SafeCpyN(szFullPath + iIndexToInsert, pszIndex, ARRAYSIZE(szFullPath) - iIndexToInsert);
  2410. }
  2411. //
  2412. // Test to see if we have the database open already.
  2413. // If it is open, we just highlight that and return
  2414. //
  2415. PDATABASE pDataBase = DataBaseList.pDataBaseHead;
  2416. while (pDataBase) {
  2417. if (pDataBase->strPath == szFullPath) {
  2418. TreeView_SelectItem(DBTree.m_hLibraryTree, pDataBase->hItemDB);
  2419. bOk = TRUE;
  2420. goto Next_File;
  2421. }
  2422. pDataBase = pDataBase->pNext;
  2423. }
  2424. //
  2425. // Read the database
  2426. //
  2427. pDataBase = new DATABASE(DATABASE_TYPE_WORKING);
  2428. if (pDataBase == NULL) {
  2429. MEM_ERR;
  2430. return FALSE;
  2431. }
  2432. BOOL bReturn = GetDatabaseEntries(szFullPath, pDataBase);
  2433. if (!bReturn) {
  2434. //
  2435. // Cleanup has been called in GetDatabaseEntries
  2436. //
  2437. delete pDataBase;
  2438. pDataBase = NULL;
  2439. goto Next_File;
  2440. }
  2441. if (!DBTree.AddWorking(pDataBase)) {
  2442. CleanupDbSupport(pDataBase);
  2443. delete pDataBase;
  2444. pDataBase = NULL;
  2445. goto Next_File;
  2446. }
  2447. if (g_pPresentDataBase) {
  2448. //
  2449. // g_PresentDataBase is set properly in GetDatabaseEntries. This will be set to pDatabase
  2450. //
  2451. AddToMRU(g_pPresentDataBase->strPath);
  2452. bOk = TRUE;
  2453. }
  2454. Next_File:
  2455. if (bRemaining) {
  2456. pszIndex = pszIndex + iLengthFileName + 1;
  2457. }
  2458. }
  2459. } else {
  2460. if (CommDlgExtendedError() == FNERR_BUFFERTOOSMALL) {
  2461. //
  2462. // We cannot select so many files at one go...
  2463. //
  2464. MessageBox(hdlg, GetString(IDS_TOO_MANYFILES), g_szAppName, MB_ICONINFORMATION);
  2465. bOk = FALSE;
  2466. }
  2467. }
  2468. End:
  2469. if (pszFilesList) {
  2470. delete[] pszFilesList;
  2471. pszFilesList = NULL;
  2472. }
  2473. RefreshMRUMenu();
  2474. SetCaption();
  2475. return bOk;
  2476. }
  2477. BOOL
  2478. SaveMRUList(
  2479. void
  2480. )
  2481. /*++
  2482. SaveMRUList
  2483. Desc: Saves the list of MRU files in the registry.
  2484. Should be called just before exiting. When this is called we are sure
  2485. that we are going to exit, databases have already been closed
  2486. --*/
  2487. {
  2488. HKEY hKey = NULL, hSubKey = NULL;
  2489. BOOL bOk = TRUE;
  2490. DWORD dwDisposition;
  2491. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  2492. APPCOMPAT_KEY_PATH,
  2493. 0,
  2494. KEY_READ,
  2495. &hKey)) {
  2496. assert(FALSE);
  2497. bOk = FALSE;
  2498. goto End;
  2499. }
  2500. if (ERROR_SUCCESS != RegCreateKeyEx(hKey,
  2501. TEXT("CompatAdmin"),
  2502. 0,
  2503. NULL,
  2504. REG_OPTION_NON_VOLATILE,
  2505. KEY_ALL_ACCESS,
  2506. NULL,
  2507. &hSubKey,
  2508. &dwDisposition)) {
  2509. REGCLOSEKEY(hKey);
  2510. Dbg(dlError, "[SaveMRUList] Could not create key for CompatAdmin");
  2511. bOk = FALSE;
  2512. goto End;
  2513. }
  2514. REGCLOSEKEY(hKey);
  2515. hKey = hSubKey;
  2516. SHDeleteKey(hKey, TEXT("MRU"));
  2517. if (ERROR_SUCCESS != RegCreateKeyEx(hKey,
  2518. TEXT("MRU"),
  2519. 0,
  2520. NULL,
  2521. REG_OPTION_NON_VOLATILE,
  2522. KEY_ALL_ACCESS,
  2523. NULL,
  2524. &hSubKey,
  2525. &dwDisposition)) {
  2526. REGCLOSEKEY(hKey);
  2527. Dbg(dlError, "[SaveMRUList] Could not create key for MRU");
  2528. bOk = FALSE;
  2529. goto End;
  2530. }
  2531. REGCLOSEKEY(hKey);
  2532. hKey = hSubKey;
  2533. UINT uCount = 0;
  2534. TCHAR szCount[3];
  2535. *szCount = 0;
  2536. PSTRLIST pStrListHead = g_strlMRU.m_pHead;
  2537. while (pStrListHead && uCount < MAX_MRU_COUNT) {
  2538. //
  2539. // Now add this to the registry.
  2540. //
  2541. *szCount = 0;
  2542. if (ERROR_SUCCESS != RegSetValueEx(hKey,
  2543. _itot(uCount, szCount, 10),
  2544. 0,
  2545. REG_SZ,
  2546. (LPBYTE)pStrListHead->szStr.pszString,
  2547. (pStrListHead->szStr.Length() + 1) * sizeof(TCHAR))) {
  2548. REGCLOSEKEY(hKey);
  2549. Dbg(dlError, "[SaveMRUList] Could not save MRU settings");
  2550. bOk = FALSE;
  2551. goto End;
  2552. }
  2553. ++uCount;
  2554. pStrListHead = pStrListHead->pNext;
  2555. }
  2556. REGCLOSEKEY(hKey);
  2557. End:
  2558. return bOk;
  2559. }
  2560. BOOL
  2561. SaveDisplaySettings(
  2562. void
  2563. )
  2564. /*++
  2565. SaveDisplaySettings
  2566. Desc: Saves the display settings in the registry
  2567. Return:
  2568. FALSE: If there was some error
  2569. TRUE: Otherwise
  2570. --*/
  2571. {
  2572. HKEY hKey = NULL, hSubKey = NULL;
  2573. DWORD dwDisposition;
  2574. RECT r, rectDBTree;
  2575. DWORD dwPos;
  2576. BOOL bOk = TRUE;
  2577. if (IsIconic(g_hDlg)) {
  2578. //
  2579. // We do not want to save the settings when we are minimized
  2580. //
  2581. return TRUE;
  2582. }
  2583. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  2584. APPCOMPAT_KEY_PATH,
  2585. 0,
  2586. KEY_READ,
  2587. &hKey)) {
  2588. bOk = FALSE;
  2589. Dbg(dlError, "[SaveMRUList] Could not open key for APPCOMPAT_KEY_PATH");
  2590. goto End;
  2591. }
  2592. if (ERROR_SUCCESS != RegCreateKeyEx(hKey,
  2593. TEXT("CompatAdmin"),
  2594. 0,
  2595. NULL,
  2596. REG_OPTION_NON_VOLATILE,
  2597. KEY_ALL_ACCESS,
  2598. NULL,
  2599. &hSubKey,
  2600. &dwDisposition)) {
  2601. bOk = FALSE;
  2602. Dbg(dlError, "[SaveMRUList] Could not create key for CompatAdmin");
  2603. goto End;
  2604. }
  2605. REGCLOSEKEY(hKey);
  2606. hKey = hSubKey;
  2607. if (ERROR_SUCCESS != RegCreateKeyEx(hKey,
  2608. TEXT("Display"),
  2609. 0,
  2610. NULL,
  2611. REG_OPTION_NON_VOLATILE,
  2612. KEY_ALL_ACCESS,
  2613. NULL,
  2614. &hSubKey,
  2615. &dwDisposition)) {
  2616. bOk = FALSE;
  2617. Dbg(dlError, "[SaveMRUList] Could not create key for Display");
  2618. goto End;
  2619. }
  2620. REGCLOSEKEY(hKey);
  2621. hKey = hSubKey;
  2622. //
  2623. // Now save the settings in the key
  2624. //
  2625. //
  2626. // Fist the left-top
  2627. //
  2628. GetWindowRect(g_hDlg, &r);
  2629. dwPos = r.left;
  2630. if (ERROR_SUCCESS != RegSetValueEx(hKey,
  2631. TEXT("LEFT"),
  2632. 0,
  2633. REG_DWORD,
  2634. (CONST BYTE*)&dwPos,
  2635. sizeof(DWORD))) {
  2636. bOk = FALSE;
  2637. Dbg(dlError, "[SaveMRUList] Could not save value for left");
  2638. goto End;
  2639. }
  2640. dwPos = r.top;
  2641. if (ERROR_SUCCESS != RegSetValueEx(hKey,
  2642. TEXT("TOP"),
  2643. 0,
  2644. REG_DWORD,
  2645. (CONST BYTE*)&dwPos,
  2646. sizeof(DWORD))) {
  2647. bOk = FALSE;
  2648. Dbg(dlError, "[SaveMRUList] Could not save value for top");
  2649. goto End;
  2650. }
  2651. //
  2652. // Then the right bottom
  2653. //
  2654. dwPos = r.right;
  2655. if (ERROR_SUCCESS != RegSetValueEx(hKey,
  2656. TEXT("RIGHT"),
  2657. 0,
  2658. REG_DWORD,
  2659. (CONST BYTE*)&dwPos,
  2660. sizeof(DWORD))) {
  2661. bOk = FALSE;
  2662. Dbg(dlError, "[SaveMRUList] Could not save value for right");
  2663. goto End;
  2664. }
  2665. dwPos = r.bottom;
  2666. if (ERROR_SUCCESS != RegSetValueEx(hKey,
  2667. TEXT("BOTTOM"),
  2668. 0,
  2669. REG_DWORD,
  2670. (CONST BYTE*)&dwPos,
  2671. sizeof(DWORD))) {
  2672. bOk = FALSE;
  2673. Dbg(dlError, "[SaveMRUList] Could not save value for bottom");
  2674. goto End;
  2675. }
  2676. //
  2677. // Percentage Width of the db tree next.
  2678. //
  2679. GetWindowRect(DBTree.m_hLibraryTree, &rectDBTree);
  2680. dwPos = (rectDBTree.right-rectDBTree.left) ;
  2681. if (ERROR_SUCCESS != RegSetValueEx(hKey,
  2682. TEXT("DBTREE-WIDTH"),
  2683. 0,
  2684. REG_DWORD,
  2685. (CONST BYTE*)&dwPos,
  2686. sizeof(DWORD))) {
  2687. bOk = FALSE;
  2688. Dbg(dlError, "[SaveMRUList] Could not save value for DBTREE-WIDTH");
  2689. goto End;
  2690. }
  2691. End:
  2692. REGCLOSEKEY(hKey);
  2693. return bOk;
  2694. }
  2695. void
  2696. LoadDisplaySettings(
  2697. void
  2698. )
  2699. /*++
  2700. LoadDisplaySettings
  2701. Desc: Loads the positional settings from the registry.
  2702. Also adjusts the splitter bar.
  2703. Warn: Even if we do some error handling and bail out, make sure that this routine
  2704. calls MoveWindow() for the main dialog window so that it gets a WM_SIZE
  2705. We arrange the controls on the handler of WM_SIZE, so it is important
  2706. that it gets a WM_SIZE from here
  2707. --*/
  2708. {
  2709. RECT r, rectDBTree;
  2710. DWORD dwType = 0;
  2711. DWORD cbData = 0;
  2712. DWORD dwFinalDBWidth = 0;
  2713. DWORD dwInitialWidth = 0;
  2714. DWORD dwInitialHeight = 0;
  2715. HKEY hKey = NULL;
  2716. LONG lResult = -1;
  2717. MENUITEMINFO mii = {0};
  2718. //
  2719. // Set the default width, height and postition etc. If this is the first
  2720. // time that the user is running CompatAdmin, CompatAdmin will start with
  2721. // these settings. The next time the user runs CompatAdmin, we will make
  2722. // the position and size as it was the last time the user ran it
  2723. //
  2724. dwInitialHeight = GetSystemMetrics(SM_CYSCREEN) / 2 + 100;
  2725. dwInitialWidth = GetSystemMetrics(SM_CXSCREEN) / 2 + 200;
  2726. r.left = 0;
  2727. r.top = 0;
  2728. r.right = r.left + dwInitialWidth;
  2729. r.bottom = r.top + dwInitialHeight;
  2730. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
  2731. DISPLAY_KEY,
  2732. 0,
  2733. KEY_READ,
  2734. &hKey)) {
  2735. dwType = REG_DWORD;
  2736. cbData = sizeof(DWORD);
  2737. lResult = RegQueryValueEx(hKey,
  2738. TEXT("LEFT"),
  2739. NULL,
  2740. &dwType,
  2741. (LPBYTE)&r.left,
  2742. &cbData);
  2743. if (lResult != ERROR_SUCCESS || dwType != REG_DWORD) {
  2744. goto End;
  2745. }
  2746. lResult = RegQueryValueEx(hKey,
  2747. TEXT("TOP"),
  2748. NULL,
  2749. &dwType,
  2750. (LPBYTE)&r.top,
  2751. &cbData);
  2752. if (lResult != ERROR_SUCCESS || dwType != REG_DWORD) {
  2753. goto End;
  2754. }
  2755. lResult = RegQueryValueEx(hKey,
  2756. TEXT("RIGHT"),
  2757. NULL,
  2758. &dwType,
  2759. (LPBYTE)&r.right,
  2760. &cbData);
  2761. if (lResult != ERROR_SUCCESS || dwType != REG_DWORD) {
  2762. goto End;
  2763. }
  2764. lResult = RegQueryValueEx(hKey,
  2765. TEXT("BOTTOM"),
  2766. NULL,
  2767. &dwType,
  2768. (LPBYTE)&r.bottom,
  2769. &cbData);
  2770. if (lResult != ERROR_SUCCESS || dwType != REG_DWORD) {
  2771. goto End;
  2772. }
  2773. lResult = RegQueryValueEx(hKey,
  2774. TEXT("DBTREE-WIDTH"),
  2775. NULL,
  2776. &dwType,
  2777. (LPBYTE)&dwFinalDBWidth,
  2778. &cbData);
  2779. if (lResult != ERROR_SUCCESS || dwType != REG_DWORD) {
  2780. goto End;
  2781. }
  2782. }
  2783. //
  2784. // We are doing this so that we do get a WM_SIZE now. Otherwise the controls do
  2785. // not appear properly
  2786. //
  2787. MoveWindow(g_hDlg,
  2788. r.left,
  2789. r.top,
  2790. r.right - r.left,
  2791. r.bottom - r.top,
  2792. TRUE);
  2793. if (dwFinalDBWidth != 0) {
  2794. GetWindowRect(DBTree.m_hLibraryTree, &rectDBTree);
  2795. dwInitialWidth = rectDBTree.right - rectDBTree.left;
  2796. LPARAM lParam = rectDBTree.top + 2;
  2797. lParam = lParam << 16; // The y pos of the imaginary mouse
  2798. lParam |= rectDBTree.right + 2; //The x pos of the imaginary mouse
  2799. //
  2800. // Position the split bar proerply
  2801. //
  2802. OnMoveSplitter(g_hDlg, lParam, TRUE, dwFinalDBWidth - dwInitialWidth);
  2803. }
  2804. End:
  2805. REGCLOSEKEY(hKey);
  2806. }
  2807. INT
  2808. LoadSpecificInstalledDatabasePath(
  2809. IN PCTSTR pszPath
  2810. )
  2811. /*++
  2812. LoadSpecificInstalledDatabasePath
  2813. Desc: Loads an installed database from the AppPatch\custom directory
  2814. and shows that on UI
  2815. Params:
  2816. IN PCTSTR pszPath: The full path of the database in the AppPatch\custom directory
  2817. that we want to load
  2818. Return:
  2819. 0: There was some critical error, like memory allocation failure,
  2820. could not add to the UI etc
  2821. -1: The database does not exist at the specified location
  2822. 1: Successful
  2823. *****************************************************************************************
  2824. Warning: This routine is called by LoadInstalledDataBases(...), which has done a
  2825. EnterCriticalSection(&g_csInstalledList) before calling this, so do not do a
  2826. EnterCriticalSection(&g_csInstalledList) anywhere in this routine
  2827. *****************************************************************************************
  2828. --*/
  2829. {
  2830. INT iReturn = 1;
  2831. PDATABASE pOldPresentDatabase = NULL;
  2832. PDATABASE pDataBase = NULL;
  2833. BOOL bReturn = FALSE;
  2834. HCURSOR hCursor;
  2835. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2836. pDataBase = new DATABASE(DATABASE_TYPE_INSTALLED);
  2837. if (pDataBase == NULL) {
  2838. MEM_ERR;
  2839. iReturn = 0;
  2840. goto End;
  2841. }
  2842. //
  2843. // NOTE: If GetDatabaseEntries() returns succeeds then it set the g_pPresentDataBase to pDataBase,
  2844. // so after it returns successfully, the g_pPresentDataBase is changed.
  2845. //
  2846. pOldPresentDatabase = g_pPresentDataBase;
  2847. bReturn = GetDatabaseEntries(pszPath, pDataBase);
  2848. g_pPresentDataBase = pOldPresentDatabase;
  2849. if (bReturn == FALSE) {
  2850. if (pDataBase) {
  2851. //
  2852. // Cleanup done in GetDatabaseEntries()
  2853. //
  2854. delete pDataBase;
  2855. }
  2856. //
  2857. // User might have manually deleted the file
  2858. //
  2859. return -1;
  2860. }
  2861. InstalledDataBaseList.Add(pDataBase);
  2862. if (!DBTree.AddInstalled(pDataBase)) {
  2863. InstalledDataBaseList.Remove(pDataBase);
  2864. if (pDataBase) {
  2865. delete pDataBase;
  2866. pDataBase = NULL;
  2867. }
  2868. iReturn = 0;
  2869. }
  2870. End:
  2871. hCursor ? SetCursor(hCursor) : SetCursor(LoadCursor(NULL, IDC_ARROW));
  2872. return iReturn;
  2873. }
  2874. INT
  2875. LoadSpecificInstalledDatabaseGuid(
  2876. IN PCTSTR pszGuid
  2877. )
  2878. /*++
  2879. LoadSpecificInstalledDatabaseGuid
  2880. Desc: Loads an installed database given a GUID
  2881. Params:
  2882. IN PCTSTR pszGuid: The guid of the database that we want to load
  2883. Return:
  2884. 0: Failure
  2885. Otherwise returns LoadSpecificInstalledDatabasePath(...)
  2886. */
  2887. {
  2888. TCHAR szPath[MAX_PATH * 2];
  2889. INT iLength = 0;
  2890. INT ichSizeRemaining = 0;
  2891. UINT uResult = 0;
  2892. *szPath = 0;
  2893. if (pszGuid == NULL) {
  2894. assert(FALSE);
  2895. Dbg(dlError, "LoadSpecificInstalledDatabaseGuid NULL Guid passed");
  2896. return 0;
  2897. }
  2898. uResult = GetSystemWindowsDirectory(szPath, MAX_PATH);
  2899. if (uResult == 0 || uResult >= MAX_PATH) {
  2900. Dbg(dlError, "LoadSpecificInstalledDatabaseGuid GetSystemWindowsDirectory failed");
  2901. return 0;
  2902. }
  2903. ADD_PATH_SEPARATOR(szPath, ARRAYSIZE(szPath));
  2904. iLength = lstrlen(szPath);
  2905. ichSizeRemaining = ARRAYSIZE(szPath) - iLength;
  2906. StringCchPrintf(szPath + iLength, ichSizeRemaining, TEXT("AppPatch\\Custom\\%s.sdb"), pszGuid);
  2907. return LoadSpecificInstalledDatabasePath(szPath);
  2908. }
  2909. BOOL
  2910. LoadInstalledDataBases(
  2911. void
  2912. )
  2913. /*++
  2914. LoadInstalledDataBases
  2915. Desc: First of all removes the list of installed databases, and re-loads it
  2916. Params:
  2917. void
  2918. Return:
  2919. TRUE: If the list of databases could be reloaded
  2920. FALSE: Otherwise
  2921. --*/
  2922. {
  2923. TCHAR szFileName[MAX_PATH];
  2924. TCHAR szwName[MAX_PATH];
  2925. DWORD dwchSizeSubKeyName;
  2926. HKEY hKey = NULL, hSubKey = NULL;
  2927. LPARAM lParam;
  2928. PDATABASE pOldPresentDatabase = NULL;
  2929. BOOL bOk = TRUE;
  2930. *szFileName = 0;
  2931. SetCursor(LoadCursor(NULL, IDC_WAIT));
  2932. EnterCriticalSection(&g_csInstalledList);
  2933. //
  2934. // Remove the Installed Database All Items
  2935. //
  2936. if (DBTree.m_hItemAllInstalled) {
  2937. TreeView_DeleteItem(DBTree.m_hLibraryTree, DBTree.m_hItemAllInstalled);
  2938. InstalledDataBaseList.RemoveAll();
  2939. DBTree.m_hItemAllInstalled = NULL;
  2940. }
  2941. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2942. APPCOMPAT_KEY_PATH_INSTALLEDSDB,
  2943. 0,
  2944. KEY_READ,
  2945. &hKey)) {
  2946. bOk = FALSE;
  2947. Dbg(dlWarning, "[LoadInstalledDataBases] Could not open APPCOMPAT_KEY_PATH_INSTALLEDSDB");
  2948. goto End;
  2949. }
  2950. DWORD dwIndex = 0;
  2951. while (TRUE) {
  2952. dwchSizeSubKeyName = ARRAYSIZE(szwName);
  2953. *szwName = 0;
  2954. if (ERROR_SUCCESS != RegEnumKeyEx(hKey,
  2955. dwIndex++,
  2956. szwName,
  2957. &dwchSizeSubKeyName,
  2958. 0,
  2959. 0,
  2960. 0,
  2961. 0)) {
  2962. break;
  2963. }
  2964. if (ERROR_SUCCESS != RegOpenKeyEx(hKey,
  2965. szwName,
  2966. 0,
  2967. KEY_READ,
  2968. &hSubKey)) {
  2969. bOk = FALSE;
  2970. goto End;
  2971. }
  2972. *szFileName = 0;
  2973. DWORD dwType = REG_SZ;
  2974. DWORD dwFileNameSize = sizeof(szFileName);
  2975. LONG lResult = 0;
  2976. lResult = RegQueryValueEx(hSubKey,
  2977. TEXT("DatabasePath"),
  2978. 0,
  2979. &dwType,
  2980. (LPBYTE)szFileName,
  2981. &dwFileNameSize);
  2982. if (lResult != ERROR_SUCCESS || dwType != REG_SZ) {
  2983. bOk = FALSE;
  2984. goto End;
  2985. }
  2986. if (LoadSpecificInstalledDatabasePath(szFileName) == 0) {
  2987. bOk = FALSE;
  2988. goto End;
  2989. }
  2990. REGCLOSEKEY(hSubKey);
  2991. hSubKey = NULL;
  2992. }
  2993. End:
  2994. REGCLOSEKEY(hKey);
  2995. if (hSubKey) {
  2996. REGCLOSEKEY(hSubKey);
  2997. hSubKey = NULL;
  2998. }
  2999. LeaveCriticalSection(&g_csInstalledList);
  3000. if (g_hdlgSearchDB || g_hdlgQueryDB) {
  3001. //
  3002. // Either the query or the search window is open, we should prompt
  3003. // that for installed databases, some results might now show up correctly as the
  3004. // entire list has been refreshed.
  3005. // The database and entries now will have different pointer values
  3006. //
  3007. MessageBox(g_hDlg,
  3008. GetString(IDS_SOMESEARCHWINDOW),
  3009. g_szAppName,
  3010. MB_ICONINFORMATION);
  3011. }
  3012. SetCursor(LoadCursor(NULL, IDC_ARROW));
  3013. return bOk;
  3014. }
  3015. void
  3016. SetImageList(
  3017. void
  3018. )
  3019. /*++
  3020. SetImageList
  3021. Desc: Create our global ImageList and Add images to the ImageList and associate it
  3022. with the tree controls
  3023. --*/
  3024. {
  3025. g_hImageList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 30, 1);
  3026. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FIXES)));
  3027. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_HELP)));
  3028. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MODE)));
  3029. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_PATCHES)));
  3030. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ATTRIBUTE)));
  3031. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MATCHHEAD)));
  3032. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DISABLED)));
  3033. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_GLOBAL)));
  3034. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_LOCAL)));
  3035. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_CMDLINE)));
  3036. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_INCLUDE)));
  3037. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_EXCLUDE)));
  3038. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APP)));
  3039. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_INSTALLED)));
  3040. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DATABASE)));
  3041. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SINGLEAPP)));
  3042. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICONALLUSERS)));
  3043. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICONSINGLEUSER)));
  3044. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FILE)));
  3045. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_EV_ERROR)));
  3046. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_EV_WARNING)));
  3047. ImageList_AddIcon(g_hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_EV_INFO)));
  3048. }
  3049. HWND
  3050. InitToolBar(
  3051. IN HWND hwndParent
  3052. )
  3053. /*++
  3054. InitToolBar
  3055. Desc: Creates the tool bar for the app
  3056. Params:
  3057. IN HWND hwndParent: The parent for the tool bar
  3058. Return: The handle to the tool bar window
  3059. --*/
  3060. {
  3061. HWND hwndTB;
  3062. TBBUTTON tbbAr[BUTTON_COUNT];
  3063. DEVMODE dm;
  3064. //
  3065. // Create a toolbar that has a ToolTip associated with it.
  3066. //
  3067. hwndTB = CreateWindowEx(WS_EX_TOOLWINDOW,
  3068. TOOLBARCLASSNAME,
  3069. NULL,
  3070. WS_CHILD | WS_CLIPCHILDREN | TBSTYLE_TOOLTIPS
  3071. | CCS_ADJUSTABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT
  3072. | TBSTYLE_FLAT,
  3073. 0,
  3074. 0,
  3075. 0,
  3076. 0,
  3077. hwndParent,
  3078. (HMENU)ID_TOOLBAR,
  3079. g_hInstance,
  3080. NULL);
  3081. //
  3082. // Send the TB_BUTTONSTRUCTSIZE message, which is required for
  3083. // backward compatibility
  3084. //
  3085. SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
  3086. //
  3087. // Add the strings for the tool bar buttons text
  3088. //
  3089. int iIndexes[] = {
  3090. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_NEW)),
  3091. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_OPEN)),
  3092. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_SAVE)),
  3093. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_CREATEFIX)),
  3094. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_CREATEAPPHELP)),
  3095. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_CREATEMODE)),
  3096. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_RUN)),
  3097. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_SEARCH)),
  3098. SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)GetString(IDS_TB_QUERY)),
  3099. };
  3100. dm.dmSize = sizeof(dm);
  3101. EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm);
  3102. if (dm.dmBitsPerPel >= 32) {
  3103. //
  3104. // The present settings can support >= 32 bit colors
  3105. //
  3106. //
  3107. // Create the imagelist for the toolbar and set the bitmap
  3108. //
  3109. s_hImageListToolBar = ImageList_Create(IMAGE_WIDTH,
  3110. IMAGE_HEIGHT,
  3111. ILC_COLOR32 | ILC_MASK,
  3112. 8,
  3113. 1);
  3114. ImageList_Add(s_hImageListToolBar,
  3115. LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_TOOLBAR)),
  3116. NULL);
  3117. SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)(HIMAGELIST)s_hImageListToolBar);
  3118. //
  3119. // Create the hot imagelist for the toolbar and set the bitmap
  3120. //
  3121. s_hImageListToolBarHot = ImageList_Create(IMAGE_WIDTH,
  3122. IMAGE_HEIGHT,
  3123. ILC_COLOR32 | ILC_MASK,
  3124. 8,
  3125. 1);
  3126. ImageList_Add(s_hImageListToolBarHot,
  3127. LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_TOOLBAR_HOT)),
  3128. NULL);
  3129. SendMessage(hwndTB, TB_SETHOTIMAGELIST, 0, (LPARAM)(HIMAGELIST)s_hImageListToolBarHot);
  3130. } else {
  3131. //
  3132. // The present settings cannot support >= 32 bit colors
  3133. //
  3134. //
  3135. // Get the normal imagelist for the tool bar when we are on low colors
  3136. //
  3137. s_hImageListToolBar = ImageList_LoadImage(g_hInstance,
  3138. MAKEINTRESOURCE(IDB_256NORMAL),
  3139. IMAGE_WIDTH,
  3140. 0,
  3141. CLR_DEFAULT,
  3142. IMAGE_BITMAP,
  3143. LR_CREATEDIBSECTION);
  3144. SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)(HIMAGELIST)s_hImageListToolBar);
  3145. //
  3146. // Get the hot imagelist for the tool bar when we are on low colors
  3147. //
  3148. s_hImageListToolBarHot = ImageList_LoadImage(g_hInstance,
  3149. MAKEINTRESOURCE(IDB_256HOT),
  3150. IMAGE_WIDTH,
  3151. 0,
  3152. CLR_DEFAULT,
  3153. IMAGE_BITMAP,
  3154. LR_CREATEDIBSECTION);
  3155. SendMessage(hwndTB, TB_SETHOTIMAGELIST, 0, (LPARAM)(HIMAGELIST)s_hImageListToolBarHot);
  3156. }
  3157. INT iIndex = 0, iStringIndex = 0;
  3158. // New DataBase
  3159. tbbAr[iIndex].iBitmap = IMAGE_TB_NEW;
  3160. tbbAr[iIndex].idCommand = ID_FILE_NEW;
  3161. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3162. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3163. tbbAr[iIndex].dwData = 0;
  3164. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3165. // Open Database
  3166. tbbAr[iIndex].iBitmap = IMAGE_TB_OPEN;
  3167. tbbAr[iIndex].idCommand = ID_FILE_OPEN;
  3168. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3169. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3170. tbbAr[iIndex].dwData = 0;
  3171. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3172. // Save Database
  3173. tbbAr[iIndex].iBitmap = IMAGE_TB_SAVE;
  3174. tbbAr[iIndex].idCommand = ID_FILE_SAVE;
  3175. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3176. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3177. tbbAr[iIndex].dwData = 0;
  3178. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3179. // Add the separator
  3180. tbbAr[iIndex].iBitmap = 0;
  3181. tbbAr[iIndex].idCommand = 0;
  3182. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3183. tbbAr[iIndex].fsStyle = BTNS_SEP;
  3184. tbbAr[iIndex].dwData = 0;
  3185. tbbAr[iIndex++].iString = 0;
  3186. // Create Fix
  3187. tbbAr[iIndex].iBitmap = IMAGE_TB_NEWFIX;
  3188. tbbAr[iIndex].idCommand = ID_FIX_CREATEANAPPLICATIONFIX;
  3189. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3190. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3191. tbbAr[iIndex].dwData = 0;
  3192. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3193. // Create AppHelp
  3194. tbbAr[iIndex].iBitmap = IMAGE_TB_NEWAPPHELP;
  3195. tbbAr[iIndex].idCommand = ID_FIX_CREATEANEWAPPHELPMESSAGE;
  3196. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3197. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3198. tbbAr[iIndex].dwData = 0;
  3199. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3200. // Create mode
  3201. tbbAr[iIndex].iBitmap = IMAGE_TB_NEWMODE;
  3202. tbbAr[iIndex].idCommand = ID_FIX_CREATENEWLAYER;
  3203. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3204. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3205. tbbAr[iIndex].dwData = 0;
  3206. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3207. // Run
  3208. tbbAr[iIndex].iBitmap = IMAGE_TB_RUN;
  3209. tbbAr[iIndex].idCommand = ID_FIX_EXECUTEAPPLICATION;
  3210. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3211. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3212. tbbAr[iIndex].dwData = 0;
  3213. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3214. // Add the separator
  3215. tbbAr[iIndex].iBitmap = 0;
  3216. tbbAr[iIndex].idCommand = 0;
  3217. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3218. tbbAr[iIndex].fsStyle = BTNS_SEP;
  3219. tbbAr[iIndex].dwData = 0;
  3220. tbbAr[iIndex++].iString = 0;
  3221. // Search
  3222. tbbAr[iIndex].iBitmap = IMAGE_TB_SEARCH;
  3223. tbbAr[iIndex].idCommand = ID_TOOLS_SEARCHFORFIXES;
  3224. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3225. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3226. tbbAr[iIndex].dwData = 0;
  3227. tbbAr[iIndex++].iString = iIndexes[iStringIndex++];
  3228. // Query
  3229. tbbAr[iIndex].iBitmap = IMAGE_TB_QUERY;
  3230. tbbAr[iIndex].idCommand = ID_SEARCH_QUERYDATABASE;
  3231. tbbAr[iIndex].fsState = TBSTATE_ENABLED;
  3232. tbbAr[iIndex].fsStyle = BTNS_SHOWTEXT;
  3233. tbbAr[iIndex].dwData = 0;
  3234. tbbAr[iIndex++].iString = iIndexes[iStringIndex];
  3235. SendMessage(hwndTB, TB_ADDBUTTONS, BUTTON_COUNT, (LPARAM) (LPTBBUTTON)tbbAr);
  3236. SendMessage(hwndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
  3237. SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
  3238. ShowWindow(hwndTB, SW_SHOWNORMAL);
  3239. return hwndTB;
  3240. }
  3241. void
  3242. DoInitDialog(
  3243. IN HWND hdlg
  3244. )
  3245. /*++
  3246. DoInitDialog
  3247. Desc: Does a lot of initialization stuff, loads up the library section of the
  3248. system database.
  3249. Also sets up the status bar, loads the list of installed databases,
  3250. loads the display settings
  3251. Params:
  3252. IN HWND hdlg: The main dialog.
  3253. --*/
  3254. {
  3255. HICON hIcon;
  3256. HMENU hMenu, hSubMenu;
  3257. RECT r;
  3258. RECT rectMainClient, rect;
  3259. PDATABASE pCurrentDatabase = NULL;
  3260. GetClientRect(hdlg, &rectMainClient);
  3261. //
  3262. // Check if the APPCOMPAT keys are there if not add them.
  3263. //
  3264. AddRegistryKeys();
  3265. SetImageList();
  3266. g_hwndToolBar = InitToolBar(hdlg);
  3267. GetWindowRect(g_hwndToolBar, &rect);
  3268. INT iHeightToolbar = rect.bottom - rect.top;
  3269. g_hwndStatus = CreateWindowEx(0,
  3270. STATUSCLASSNAME,
  3271. (LPCTSTR) NULL,
  3272. SBARS_SIZEGRIP |
  3273. WS_CHILD | WS_VISIBLE,
  3274. 0,
  3275. 0,
  3276. 0,
  3277. 0,
  3278. hdlg,
  3279. (HMENU)IDC_STATUSBAR,
  3280. g_hInstance,
  3281. NULL);
  3282. GetWindowRect(g_hwndStatus, &rect);
  3283. INT iHeightStatusbar = rect.bottom - rect.top;
  3284. DBTree.Init(hdlg, iHeightToolbar, iHeightStatusbar, &rectMainClient);
  3285. g_hDlg = hdlg;
  3286. g_hwndEntryTree = GetDlgItem(hdlg, IDC_ENTRY);
  3287. TreeView_SetImageList(g_hwndEntryTree, g_hImageList, TVSIL_NORMAL);
  3288. g_hwndContentsList = GetDlgItem(hdlg, IDC_CONTENTSLIST);
  3289. ListView_SetImageList(g_hwndContentsList, g_hImageList, LVSIL_SMALL);
  3290. ListView_SetExtendedListViewStyleEx(g_hwndContentsList,
  3291. 0,
  3292. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
  3293. g_hwndRichEdit = GetDlgItem(hdlg, IDC_DESCRIPTION);
  3294. //
  3295. // Show the app icon.
  3296. //
  3297. hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APPICON));
  3298. SetClassLongPtr(hdlg, GCLP_HICON, (LONG_PTR)hIcon);
  3299. hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MENU));
  3300. //
  3301. // Get the file sub menu
  3302. //
  3303. hSubMenu = GetSubMenu(hMenu, 0);
  3304. AddMRUToFileMenu(hSubMenu);
  3305. SetMenu(hdlg, hMenu);
  3306. GetWindowRect(hdlg, &r);
  3307. g_cWidth = r.right - r.left;
  3308. g_cHeight = r.bottom - r.top;
  3309. if (!ReadMainDataBase()) {
  3310. MessageBox(g_hDlg,
  3311. GetString(IDS_UNABLETO_OPEN),
  3312. g_szAppName,
  3313. MB_ICONERROR);
  3314. PostQuitMessage(0);
  3315. return;
  3316. }
  3317. DBTree.PopulateLibraryTreeGlobal();
  3318. //
  3319. // Load the Installed databases
  3320. //
  3321. LoadInstalledDataBases();
  3322. //
  3323. // Create the first empty database, and initialize pCurrentDatabase
  3324. //
  3325. pCurrentDatabase = new DATABASE(DATABASE_TYPE_WORKING);
  3326. if (pCurrentDatabase == NULL) {
  3327. MEM_ERR;
  3328. return;
  3329. }
  3330. DataBaseList.Add(pCurrentDatabase);
  3331. pCurrentDatabase->bChanged = FALSE;
  3332. g_pEntrySelApp = NULL;
  3333. g_pSelEntry = NULL;
  3334. //
  3335. // Increase the index. The next new database will have the default path of say UNTITLED_2.SDB
  3336. //
  3337. ++g_uNextDataBaseIndex;
  3338. SetCaption();
  3339. //
  3340. // Now update the screen
  3341. //
  3342. DBTree.AddWorking(pCurrentDatabase);
  3343. SetCaption();
  3344. //
  3345. // Set the new procs for the tree views and the content list, to handle the tab.
  3346. //
  3347. g_PrevTreeProc = (WNDPROC)GetWindowLongPtr(g_hwndEntryTree, GWLP_WNDPROC);
  3348. g_PrevListProc = (WNDPROC)GetWindowLongPtr(g_hwndContentsList, GWLP_WNDPROC);
  3349. SetWindowLongPtr(g_hwndEntryTree, GWLP_WNDPROC,(LONG_PTR) TreeViewProc);
  3350. SetWindowLongPtr(DBTree.m_hLibraryTree, GWLP_WNDPROC,(LONG_PTR) TreeViewProc);
  3351. SetWindowLongPtr(g_hwndContentsList, GWLP_WNDPROC,(LONG_PTR) ListViewProc);
  3352. //
  3353. // The events for the per-user and the installed datbase modifications
  3354. //
  3355. g_arrhEventNotify[IND_PERUSER] = CreateEvent(NULL, FALSE, FALSE, NULL);
  3356. g_arrhEventNotify[IND_ALLUSERS] = CreateEvent(NULL, FALSE, FALSE, NULL);
  3357. //
  3358. // Listen for changes in the per-user settings
  3359. //
  3360. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  3361. APPCOMPAT_KEY_PATH,
  3362. 0,
  3363. KEY_READ,
  3364. &g_hKeyNotify[IND_PERUSER]) == ERROR_SUCCESS) {
  3365. RegNotifyChangeKeyValue(g_hKeyNotify[IND_PERUSER],
  3366. TRUE,
  3367. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
  3368. REG_NOTIFY_CHANGE_LAST_SET,
  3369. g_arrhEventNotify[IND_PERUSER],
  3370. TRUE);
  3371. }
  3372. //
  3373. // Listen for installation or un-installation of databases
  3374. //
  3375. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3376. APPCOMPAT_KEY_PATH_INSTALLEDSDB,
  3377. 0,
  3378. KEY_READ,
  3379. &g_hKeyNotify[IND_ALLUSERS]) == ERROR_SUCCESS) {
  3380. RegNotifyChangeKeyValue(g_hKeyNotify[IND_ALLUSERS],
  3381. TRUE,
  3382. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
  3383. REG_NOTIFY_CHANGE_LAST_SET,
  3384. g_arrhEventNotify[IND_ALLUSERS],
  3385. TRUE);
  3386. }
  3387. //
  3388. // Create the thread that will do the action if the registry keys on which we
  3389. // are listening gets modified
  3390. //
  3391. if (g_hKeyNotify[IND_PERUSER] || g_hKeyNotify[IND_ALLUSERS]) {
  3392. DWORD dwId;
  3393. g_hThreadWait = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START)ThreadEventKeyNotify, NULL, 0, (unsigned int*)&dwId);
  3394. }
  3395. //
  3396. // Size the main app window as it was the last time CompatAdmin was used and position the
  3397. // split bar just as it was the last time
  3398. //
  3399. LoadDisplaySettings();
  3400. //
  3401. // We will always have focus on a working database, so set the status bar to that
  3402. //
  3403. SetStatus(IDS_STA_WORKINGDB);
  3404. //
  3405. // Initialize html help
  3406. //
  3407. HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD_PTR)&g_dwCookie);
  3408. }
  3409. void
  3410. HandleSizing(
  3411. IN HWND hDlg
  3412. )
  3413. /*++
  3414. HandleSizing
  3415. Desc: Handles the WM_SIZE for the main app dialog
  3416. Params:
  3417. IN HWND hDlg: The main dialog window
  3418. Return:
  3419. void
  3420. --*/
  3421. {
  3422. int nWidth;
  3423. int nHeight;
  3424. int nStatusbarTop;
  3425. int nWidthEntryTree; // Width of the entry tree, contents list and the rich edit
  3426. RECT rDlg;
  3427. if (g_cWidth == 0 || g_cHeight == 0) {
  3428. return;
  3429. }
  3430. GetWindowRect(hDlg, &rDlg);
  3431. nWidth = rDlg.right - rDlg.left;
  3432. nHeight = rDlg.bottom - rDlg.top;
  3433. int deltaW = nWidth - g_cWidth;
  3434. int deltaH = nHeight - g_cHeight;
  3435. HWND hwnd;
  3436. RECT r;
  3437. LONG height;
  3438. HDWP hdwp = BeginDeferWindowPos(MAIN_WINDOW_CONTROL_COUNT);
  3439. if (hdwp == NULL) {
  3440. //
  3441. // NULL indicates that insufficient system resources are available to
  3442. // allocate the structure. To get extended error information, call GetLastError.
  3443. //
  3444. assert(FALSE);
  3445. goto End;
  3446. }
  3447. //
  3448. // Status Bar
  3449. //
  3450. hwnd = GetDlgItem(hDlg, IDC_STATUSBAR);
  3451. GetWindowRect(hwnd, &r);
  3452. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  3453. DeferWindowPos(hdwp,
  3454. hwnd,
  3455. NULL,
  3456. r.left,
  3457. nStatusbarTop = r.top + deltaH,
  3458. r.right - r.left + deltaW,
  3459. r.bottom - r.top,
  3460. SWP_NOZORDER | SWP_NOACTIVATE);
  3461. //
  3462. // DataBase Tree
  3463. //
  3464. hwnd = GetDlgItem(hDlg, IDC_LIBRARY);
  3465. GetWindowRect(hwnd, &r);
  3466. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  3467. DeferWindowPos(hdwp,
  3468. hwnd,
  3469. NULL,
  3470. r.left,
  3471. r.top,
  3472. r.right - r.left,
  3473. nStatusbarTop - r.top,
  3474. SWP_NOZORDER | SWP_NOACTIVATE);
  3475. height = r.bottom - r.top + deltaH;
  3476. if (g_bDescWndOn) {
  3477. height -= 100;
  3478. }
  3479. //
  3480. // Entry Tree. NOTE that the the code for sizing the contents list and the
  3481. // rich edit control should immediately follow the code for resizing the
  3482. // entry tree
  3483. //
  3484. hwnd = GetDlgItem(hDlg, IDC_ENTRY);
  3485. GetWindowRect(hwnd, &r);
  3486. //
  3487. // Note that we must calculate the width this way before
  3488. // we Map the coords of the Entry tree wrt to the dialog box.
  3489. // I had to get the width this way and forcibly set the width rather than
  3490. // using r.right - r.left + deltaW where r is the mapped cords of the entry
  3491. // tree, because there were some problems with 640x480 resol, in which
  3492. // the entry tree, contents list and the rich edit control were getting out
  3493. // of the dialog box on their right hand side. So we have to make sure that
  3494. // they do not overrun the dialog box anyway anytime
  3495. //
  3496. nWidthEntryTree = rDlg.right - r.left - GetSystemMetrics(SM_CXBORDER) - 1;
  3497. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  3498. DeferWindowPos(hdwp,
  3499. hwnd,
  3500. NULL,
  3501. r.left,
  3502. r.top,
  3503. nWidthEntryTree,
  3504. height,
  3505. SWP_NOZORDER | SWP_NOACTIVATE);
  3506. //
  3507. // Contents list.
  3508. //
  3509. hwnd = GetDlgItem(hDlg, IDC_CONTENTSLIST);
  3510. DeferWindowPos(hdwp,
  3511. hwnd,
  3512. NULL,
  3513. r.left,
  3514. r.top,
  3515. nWidthEntryTree,
  3516. height,
  3517. SWP_NOZORDER | SWP_NOACTIVATE);
  3518. //
  3519. // Description control
  3520. //
  3521. hwnd = GetDlgItem(hDlg, IDC_DESCRIPTION);
  3522. if (g_bDescWndOn) {
  3523. DeferWindowPos(hdwp,
  3524. hwnd,
  3525. NULL,
  3526. r.left,
  3527. r.top + height,
  3528. nWidthEntryTree,
  3529. 100,
  3530. SWP_NOZORDER | SWP_NOACTIVATE);
  3531. } else {
  3532. DeferWindowPos(hdwp,
  3533. hwnd,
  3534. NULL,
  3535. 0,
  3536. 0,
  3537. 0,
  3538. 0,
  3539. SWP_NOZORDER | SWP_NOACTIVATE);
  3540. }
  3541. //
  3542. // ToolBar
  3543. //
  3544. hwnd = GetDlgItem(hDlg, ID_TOOLBAR);
  3545. GetWindowRect(hwnd, &r);
  3546. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  3547. DeferWindowPos(hdwp,
  3548. hwnd,
  3549. NULL,
  3550. r.left,
  3551. r.top,
  3552. r.right - r.left + deltaW,
  3553. r.bottom - r.top,
  3554. SWP_NOZORDER | SWP_NOACTIVATE);
  3555. EndDeferWindowPos(hdwp);
  3556. //
  3557. // The rich edit sometimes does not paint itself properly
  3558. //
  3559. hwnd = GetDlgItem(hDlg, IDC_DESCRIPTION);
  3560. InvalidateRect(hwnd, NULL, TRUE);
  3561. UpdateWindow(hwnd);
  3562. //
  3563. // Set the column width of the list view appropriately to cover the width of the list view
  3564. //
  3565. ListView_SetColumnWidth(GetDlgItem(hDlg, IDC_CONTENTSLIST), 0, LVSCW_AUTOSIZE_USEHEADER);
  3566. InvalidateRect(hDlg, NULL, TRUE);
  3567. UpdateWindow(hDlg);
  3568. g_cWidth = nWidth;
  3569. g_cHeight = nHeight;
  3570. End:
  3571. return;
  3572. }
  3573. void
  3574. ContextMenuContentsList(
  3575. IN LPARAM lParam
  3576. )
  3577. /*++
  3578. ContextMenuContentsList
  3579. Desc: Pops up the context menu when we right click on the contents list.
  3580. This is the list view that shows up in the RHS
  3581. Params:
  3582. IN LPARAM lParam: the lParam of WM_CONTEXTMENU.
  3583. Horizontal and vertical position of the cursor, in screen coordinates,
  3584. at the time of the mouse click.
  3585. --*/
  3586. {
  3587. TYPE type;
  3588. UINT uX = LOWORD(lParam);
  3589. UINT uY = HIWORD(lParam);
  3590. HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_CONTEXT));
  3591. if (hMenu == NULL) {
  3592. return;
  3593. }
  3594. HMENU hContextMenu = NULL;
  3595. //
  3596. // BUGBUG: This is only required if we ever show the databases in
  3597. // the contents list. Presently we do not show them in the
  3598. // contents list.
  3599. //
  3600. LPARAM lParamOfSelectedItem = NULL;
  3601. LVITEM lvi;
  3602. lvi.mask = LVIF_PARAM;
  3603. lvi.iItem = ListView_GetSelectionMark(g_hwndContentsList);
  3604. lvi.iSubItem = 0;
  3605. if (!ListView_GetItem(g_hwndContentsList, &lvi)) {
  3606. assert(FALSE);
  3607. goto End;
  3608. }
  3609. type = ConvertLparam2Type(lvi.lParam);
  3610. if (type == DATABASE_TYPE_INSTALLED || type == DATABASE_TYPE_WORKING) {
  3611. //
  3612. // If we ever decide to show the datbases in the context list
  3613. // presently we do not
  3614. //
  3615. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_DATABASE);
  3616. } else {
  3617. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_LIST);
  3618. }
  3619. TrackPopupMenuEx(hContextMenu,
  3620. TPM_LEFTALIGN | TPM_TOPALIGN,
  3621. uX,
  3622. uY,
  3623. g_hDlg,
  3624. NULL);
  3625. End:
  3626. DestroyMenu(hMenu);
  3627. }
  3628. void
  3629. ContextMenuExeTree(
  3630. IN LPARAM lParam
  3631. )
  3632. /*++
  3633. ContextMenuExeTree
  3634. Desc: Pops up the context menu when we right click on the contents tree.
  3635. This is the tree view that shows up in the RHS
  3636. Params:
  3637. IN LPARAM lParam: the lParam of WM_CONTEXTMENU.
  3638. Horizontal and vertical position of the cursor, in screen coordinates,
  3639. at the time of the mouse click.
  3640. --*/
  3641. {
  3642. UINT uX = LOWORD(lParam);
  3643. UINT uY = HIWORD(lParam);
  3644. HTREEITEM hItem = TreeView_GetSelection(g_hwndEntryTree);
  3645. if ((TYPE)GetItemType(g_hwndEntryTree, hItem) != TYPE_ENTRY) {
  3646. return;
  3647. }
  3648. HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_CONTEXT));
  3649. if (hMenu == NULL) {
  3650. return;
  3651. }
  3652. HMENU hContextMenu = NULL;
  3653. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_FIX);
  3654. TrackPopupMenuEx(hContextMenu,
  3655. TPM_LEFTALIGN | TPM_TOPALIGN,
  3656. uX,
  3657. uY,
  3658. g_hDlg,
  3659. NULL);
  3660. DestroyMenu(hMenu);
  3661. }
  3662. void
  3663. ContextMenuLib(
  3664. IN LPARAM lParam
  3665. )
  3666. /*++
  3667. ContextMenuLib
  3668. Desc: Pops up the context menu when we right click on the db tree.
  3669. This is the tree view that shows up in the LHS
  3670. Params:
  3671. IN LPARAM lParam: the lParam of WM_CONTEXTMENU.
  3672. Horizontal and vertical position of the cursor,
  3673. in screen coordinates, at the time of the mouse click.
  3674. --*/
  3675. {
  3676. UINT uX = LOWORD(lParam);
  3677. UINT uY = HIWORD(lParam);
  3678. HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_CONTEXT)), hContextMenu = NULL;
  3679. if (hMenu == NULL) {
  3680. return;
  3681. }
  3682. HTREEITEM hItemSelected = TreeView_GetSelection(DBTree.m_hLibraryTree);
  3683. if (hItemSelected == NULL) {
  3684. goto END;
  3685. }
  3686. TYPE type = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItemSelected);
  3687. switch (type) {
  3688. case DATABASE_TYPE_INSTALLED:
  3689. case DATABASE_TYPE_GLOBAL:
  3690. case DATABASE_TYPE_WORKING:
  3691. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_DATABASE);
  3692. break;
  3693. case FIX_SHIM:
  3694. case FIX_FLAG:
  3695. case FIX_LAYER:
  3696. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_APP_LAYER);
  3697. if (type == FIX_LAYER) {
  3698. //
  3699. // A layer can be modified as well.
  3700. //
  3701. InsertMenu(hContextMenu,
  3702. ID_EDIT_RENAME,
  3703. MF_BYCOMMAND,
  3704. ID_MODIFY_COMPATIBILITYMODE,
  3705. CSTRING(IDS_MODIFY));
  3706. }
  3707. break;
  3708. case TYPE_ENTRY:
  3709. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_APP_LAYER);
  3710. break;
  3711. case TYPE_GUI_APPS:
  3712. case TYPE_GUI_LAYERS:
  3713. //
  3714. // We cannot rename if the focus is on the root of applications or layers
  3715. //
  3716. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_APP_LAYER);
  3717. EnableMenuItem(hContextMenu, ID_EDIT_RENAME, MF_GRAYED);
  3718. break;
  3719. case TYPE_GUI_DATABASE_WORKING_ALL:
  3720. hContextMenu = GetSubMenu(hMenu, MENU_CONTEXT_DATABASE_ALL);
  3721. break;
  3722. }
  3723. if (hContextMenu == NULL) {
  3724. goto END;
  3725. }
  3726. TrackPopupMenuEx(hContextMenu,
  3727. TPM_LEFTALIGN | TPM_TOPALIGN,
  3728. uX,
  3729. uY,
  3730. g_hDlg,
  3731. NULL);
  3732. END:
  3733. DestroyMenu(hMenu);
  3734. }
  3735. BOOL
  3736. HandleDBTreeSelChange(
  3737. IN HTREEITEM hItem
  3738. )
  3739. /*++
  3740. HandleDBTreeSelChange
  3741. Desc: Handles the TVN_SELCHANGE for the database tree (LHS)
  3742. Params:
  3743. IN HTREEITEM hItem: The newly selected tree item
  3744. Return:
  3745. FALSE: If some error occurs, like invalid hItem
  3746. TRUE: Otherwise
  3747. Notes: A new item has been selected. If this item is an app,
  3748. then we set the g_pSelEntry and set the focus to the first entry of the EXE tree.
  3749. Anyway we move till we find a DATABASE HTREEITEM and if the type of the database is
  3750. TYPE_DATABASE_WORKING, then we check if the database is the same as the
  3751. g_pPresentDataBase.
  3752. If not then we change the g_pPresentDataBase, and also
  3753. delete all the items on the EXE Tree. and set both the g_pSelEntry and the
  3754. g_pEntrySelApp to NULL.
  3755. --*/
  3756. {
  3757. HTREEITEM hItemTemp = hItem;
  3758. PDATABASE pDataBase = NULL;
  3759. LPARAM lParam;
  3760. PDBENTRY pApp;
  3761. TYPE type;
  3762. type = TYPE_UNKNOWN;
  3763. //
  3764. // If the selected item is not an app/entry then we need to disable the run
  3765. // and the change enable status options. We do this by making the pointers to the currently
  3766. // selected app or entry as NULL so that everybody knows that we are not on an app
  3767. //
  3768. type = GetItemType(DBTree.m_hLibraryTree, hItem);
  3769. if (type != TYPE_ENTRY) {
  3770. //
  3771. // We are not on some application node
  3772. //
  3773. g_pSelEntry = NULL;
  3774. g_pEntrySelApp = NULL;
  3775. }
  3776. while (hItemTemp) {
  3777. if (!DBTree.GetLParam(hItemTemp, &lParam)) {
  3778. return FALSE;
  3779. }
  3780. type = (TYPE)lParam;
  3781. if (type > TYPE_NULL) {
  3782. type = ((PDS_TYPE)lParam)->type;
  3783. }
  3784. if (type == DATABASE_TYPE_WORKING
  3785. || type == DATABASE_TYPE_INSTALLED
  3786. || type == DATABASE_TYPE_GLOBAL) {
  3787. pDataBase = (PDATABASE)lParam;
  3788. g_pPresentDataBase = pDataBase;
  3789. SetCaption();
  3790. break;
  3791. } else {
  3792. hItemTemp = TreeView_GetParent(DBTree.m_hLibraryTree, hItemTemp);
  3793. }
  3794. }
  3795. if (hItemTemp == NULL) {
  3796. //
  3797. // Selected item is above the database, such as the "Working DataBases" Item etc.
  3798. //
  3799. g_pPresentDataBase = NULL;
  3800. g_pEntrySelApp = g_pSelEntry = NULL;
  3801. SetCaption(FALSE);
  3802. }
  3803. if (hItemTemp == NULL) {
  3804. TreeDeleteAll(g_hwndEntryTree);
  3805. g_pEntrySelApp = g_pSelEntry = NULL;
  3806. }
  3807. //
  3808. // If the selected item is an app then we have to update the g_hwndEntryTree
  3809. //
  3810. if (!DBTree.GetLParam(hItem, &lParam)) {
  3811. return FALSE;
  3812. }
  3813. type = (TYPE)lParam;
  3814. if (type > TYPE_NULL) {
  3815. type = ((PDS_TYPE)lParam)->type;
  3816. if (type == TYPE_ENTRY) {
  3817. pApp = (PDBENTRY)lParam;
  3818. SetCursor(LoadCursor(NULL, IDC_WAIT));
  3819. UpdateEntryTreeView(pApp, g_hwndEntryTree);
  3820. SetCursor(LoadCursor(NULL, IDC_ARROW));
  3821. g_pEntrySelApp = pApp;
  3822. }
  3823. }
  3824. if (hItem == GlobalDataBase.hItemAllApps && !g_bMainAppExpanded) {
  3825. //
  3826. // We have clicked on the "Applications" tree item of the main database
  3827. // and we have not loaded the exe entries of the main database as
  3828. // yet, so let's do it now
  3829. //
  3830. SetCursor(LoadCursor(NULL, IDC_WAIT));
  3831. INT iResult = ShowMainEntries(g_hDlg);
  3832. if (iResult == -1) {
  3833. //
  3834. // It is being loaded by somebody else. If we are using the query
  3835. // database feature then there we have a modeless window that
  3836. // creates a thread that calls ShowMainEntries(). We
  3837. // do not want that we should have two threads calling
  3838. // ShowMainEntries() at any given time
  3839. //
  3840. //
  3841. // The status message for the main dialog is changed to normal
  3842. // when we finish ShowMainEntries()
  3843. //
  3844. SetStatus(g_hwndStatus, CSTRING(IDS_LOADINGMAIN));
  3845. return TRUE;
  3846. } else {
  3847. SetCursor(LoadCursor(NULL, IDC_ARROW));
  3848. }
  3849. }
  3850. if (type != TYPE_ENTRY) {
  3851. //
  3852. // The entry tree will need to be shown if type == TYPE_ENTRY
  3853. //
  3854. PostMessage(g_hDlg, WM_USER_POPULATECONTENTSLIST, 0, (LPARAM)hItem);
  3855. }
  3856. return TRUE;
  3857. }
  3858. void
  3859. UpdateDescWindowStatus(
  3860. void
  3861. )
  3862. /*++
  3863. UpdateDescWindowStatus
  3864. Desc: Shows/hides the rich edit control aka Description window.
  3865. This will depend on the value of g_bDescWndOn.
  3866. If this is TRUE, we need to show the control otherwise
  3867. hide it
  3868. --*/
  3869. {
  3870. HWND hwnd;
  3871. RECT r;
  3872. LONG height;
  3873. hwnd = GetDlgItem(g_hDlg, IDC_LIBRARY);
  3874. GetWindowRect(hwnd, &r);
  3875. height = r.bottom - r.top;
  3876. if (g_bDescWndOn) {
  3877. height -= 100;
  3878. }
  3879. //
  3880. // ENTRY TREE
  3881. //
  3882. hwnd = GetDlgItem(g_hDlg, IDC_ENTRY);
  3883. GetWindowRect(hwnd, &r);
  3884. MapWindowPoints(NULL, g_hDlg, (LPPOINT)&r, 2);
  3885. MoveWindow(hwnd,
  3886. r.left,
  3887. r.top,
  3888. r.right - r.left,
  3889. height,
  3890. TRUE);
  3891. //
  3892. // Contents list.
  3893. //
  3894. hwnd = GetDlgItem(g_hDlg, IDC_CONTENTSLIST);
  3895. MoveWindow(hwnd,
  3896. r.left,
  3897. r.top,
  3898. r.right - r.left,
  3899. height,
  3900. TRUE);
  3901. hwnd = GetDlgItem(g_hDlg, IDC_DESCRIPTION);
  3902. if (g_bDescWndOn) {
  3903. MoveWindow(hwnd,
  3904. r.left,
  3905. r.top + height + 1,
  3906. r.right - r.left,
  3907. 100,
  3908. TRUE);
  3909. //
  3910. // We need to show the control again if it was hidden.
  3911. //
  3912. ShowWindow(hwnd, SW_SHOWNORMAL);
  3913. } else {
  3914. MoveWindow(hwnd,
  3915. 0,
  3916. 0,
  3917. 0,
  3918. 0,
  3919. TRUE);
  3920. //
  3921. // We need to hide the control so that the tab ordering
  3922. // is done properly
  3923. //
  3924. ShowWindow(hwnd, SW_HIDE);
  3925. }
  3926. }
  3927. INT_PTR CALLBACK
  3928. CompatAdminDlgProc(
  3929. IN HWND hdlg,
  3930. IN UINT uMsg,
  3931. IN WPARAM wParam,
  3932. IN LPARAM lParam
  3933. )
  3934. /*++
  3935. CompatAdminDlgProc
  3936. Desc: The main message handler for the app. This routine handles the
  3937. messages for the main modeless dialog box
  3938. Params: Standard dialog handler parameters
  3939. IN HWND hDlg
  3940. IN UINT uMsg
  3941. IN WPARAM wParam
  3942. IN LPARAM lParam
  3943. Return: Standard dialog handler return
  3944. --*/
  3945. {
  3946. UINT uMRUSelPos = 0;
  3947. int wCode = LOWORD(wParam);
  3948. int wNotifyCode = HIWORD(wParam);
  3949. switch (uMsg) {
  3950. case WM_INITDIALOG:
  3951. ProcessSwitches();
  3952. InitializeCriticalSection(&g_critsectShowMain);
  3953. InitializeCriticalSection(&s_csExpanding);
  3954. InitializeCriticalSection(&g_csInstalledList);
  3955. DoInitDialog(hdlg);
  3956. //
  3957. // Load any databases that were passed through the command line
  3958. //
  3959. PostMessage(hdlg, WM_USER_LOAD_COMMANDLINE_DATABASES, 0, 0);
  3960. //
  3961. // Load per-user settings.
  3962. //
  3963. LoadPerUserSettings();
  3964. SetFocus(DBTree.m_hLibraryTree);
  3965. break;
  3966. case WM_USER_LOAD_COMMANDLINE_DATABASES:
  3967. {
  3968. int iArgc = 0;
  3969. SetCursor(LoadCursor(NULL, IDC_WAIT));
  3970. LPWSTR* arParams = CommandLineToArgvW(GetCommandLineW(), &iArgc);
  3971. if (arParams) {
  3972. for (int iIndex = 1; iIndex < iArgc; ++iIndex) {
  3973. if (arParams[iIndex][0] == TEXT('-') || arParams[iIndex][0] == TEXT('/')) {
  3974. //
  3975. // Ignore the switches
  3976. //
  3977. continue;
  3978. }
  3979. LoadDataBase(arParams[iIndex]);
  3980. }
  3981. GlobalFree(arParams);
  3982. arParams = NULL;
  3983. }
  3984. SetCursor(LoadCursor(NULL, IDC_ARROW));
  3985. break;
  3986. }
  3987. case WM_USER_ACTIVATE:
  3988. //
  3989. // Some thread asked us to become the active window
  3990. //
  3991. SetActiveWindow(hdlg);
  3992. SetFocus(hdlg);
  3993. break;
  3994. case WM_USER_UPDATEPERUSER:
  3995. LoadPerUserSettings();
  3996. break;
  3997. case WM_USER_UPDATEINSTALLED:
  3998. //
  3999. // We should not update the list if we are doing a test run.
  4000. // Note that because of this, if the installed database list gets changed when
  4001. // we are doing a test run, we will not be able to see the changes, till the
  4002. // next time we will have to refresh the list
  4003. //
  4004. if (!g_bUpdateInstalledRequired) {
  4005. g_bUpdateInstalledRequired = TRUE;
  4006. break;
  4007. }
  4008. LoadInstalledDataBases();
  4009. break;
  4010. case WM_USER_POPULATECONTENTSLIST:
  4011. PopulateContentsList((HTREEITEM)lParam);
  4012. break;
  4013. case WM_INITMENUPOPUP:
  4014. HandlePopUp(hdlg, wParam, lParam);
  4015. break;
  4016. case WM_USER_REPAINT_LISTITEM:
  4017. {
  4018. //
  4019. // Here we will actually do the renaming of items of
  4020. // the items in the contents list view
  4021. //
  4022. LVITEM lvItem;
  4023. lvItem.iItem = (INT)wParam;
  4024. lvItem.iSubItem = 0;
  4025. lvItem.mask = LVIF_PARAM;
  4026. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  4027. break;
  4028. }
  4029. TYPE type = ConvertLparam2Type(lvItem.lParam);
  4030. TCHAR* pchText = NULL;
  4031. switch (type) {
  4032. case TYPE_ENTRY:
  4033. pchText = ((PDBENTRY)lParam)->strAppName.pszString;
  4034. break;
  4035. case FIX_LAYER:
  4036. pchText = ((PLAYER_FIX)lParam)->strName.pszString;
  4037. break;
  4038. }
  4039. ListView_SetItemText(g_hwndContentsList, lvItem.iItem, 0, pchText);
  4040. break;
  4041. }
  4042. case WM_USER_REPAINT_TREEITEM:
  4043. {
  4044. //
  4045. // Here we will actually do the renaming of items of
  4046. // the items in the db tree (LHS)
  4047. //
  4048. HTREEITEM hItem = (HTREEITEM)wParam;
  4049. TCHAR* pszText = NULL;
  4050. TYPE type = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItem);
  4051. switch (type) {
  4052. case TYPE_ENTRY:
  4053. pszText = ((PDBENTRY)lParam)->strAppName.pszString;
  4054. break;
  4055. case FIX_LAYER:
  4056. pszText = ((PLAYER_FIX)lParam)->strName.pszString;
  4057. break;
  4058. }
  4059. TVITEM Item;
  4060. Item.mask = TVIF_TEXT;
  4061. Item.pszText = pszText;
  4062. Item.hItem = hItem;
  4063. TreeView_SetItem(DBTree.m_hLibraryTree, &Item);
  4064. if (g_pPresentDataBase) {
  4065. g_pPresentDataBase->bChanged = TRUE;
  4066. //
  4067. // We might need to change the caption to show that
  4068. // the database has changed. i.e. put a * there
  4069. //
  4070. SetCaption();
  4071. }
  4072. break;
  4073. }
  4074. case WM_CONTEXTMENU:
  4075. {
  4076. HWND hWnd = (HWND)wParam;
  4077. if (hWnd == g_hwndEntryTree) {
  4078. ContextMenuExeTree(lParam);
  4079. } else if (hWnd == DBTree.m_hLibraryTree) {
  4080. ContextMenuLib(lParam);
  4081. } else if (hWnd == g_hwndContentsList) {
  4082. ContextMenuContentsList(lParam);
  4083. }
  4084. break;
  4085. }
  4086. case WM_LBUTTONDOWN:
  4087. {
  4088. RECT rectDBTree, rectEntryTree;
  4089. GetWindowRect(GetDlgItem(hdlg, IDC_LIBRARY), &rectDBTree);
  4090. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectDBTree, 2);
  4091. GetWindowRect(GetDlgItem(hdlg, IDC_ENTRY), &rectEntryTree);
  4092. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectEntryTree, 2);
  4093. int iMX = (int)LOWORD(lParam);
  4094. int iMY = (int)HIWORD(lParam);
  4095. //
  4096. // Check if we are on top of the split bar
  4097. //
  4098. if (iMX > rectDBTree.right &&
  4099. iMX < rectEntryTree.left &&
  4100. iMY > rectDBTree.top &&
  4101. iMY < rectDBTree.bottom) {
  4102. SetCapture(hdlg);
  4103. g_bDrag = TRUE;
  4104. //
  4105. // We need this to calculate how much and in which
  4106. // direction we are moving the split bar
  4107. //
  4108. g_iMousePressedX = iMX;
  4109. SetCursor(LoadCursor(NULL, IDC_SIZEWE));
  4110. } else {
  4111. g_bDrag = FALSE;
  4112. }
  4113. break;
  4114. }
  4115. case WM_MOUSEMOVE:
  4116. //
  4117. // If g_bDrag is true then this routine will drag the split bar,
  4118. // otherwise it will change the cursor to an WE arrow if we are on top
  4119. // of the split bar
  4120. //
  4121. OnMoveSplitter(hdlg,
  4122. lParam,
  4123. (wParam & MK_LBUTTON) && g_bDrag,
  4124. LOWORD(lParam) - g_iMousePressedX);
  4125. break;
  4126. case WM_LBUTTONUP:
  4127. if (g_bDrag) {
  4128. g_bDrag = FALSE;
  4129. ReleaseCapture();
  4130. //
  4131. // Set the column width of the list view appropriately to cover the width
  4132. // of the list view
  4133. //
  4134. ListView_SetColumnWidth(g_hwndContentsList,
  4135. 0,
  4136. LVSCW_AUTOSIZE_USEHEADER);
  4137. }
  4138. break;
  4139. case WM_NOTIFY:
  4140. {
  4141. LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
  4142. LPNMHDR lpnmhdr = (LPNMHDR)lParam;
  4143. if (lpnmhdr == NULL) {
  4144. break;
  4145. }
  4146. if (lpnmhdr->code == TTN_GETDISPINFO) {
  4147. ShowToolBarToolTips(hdlg, lParam);
  4148. break;
  4149. }
  4150. if (lpnmhdr->idFrom == IDC_ENTRY) {
  4151. HandleNotifyExeTree(hdlg, lParam);
  4152. break;
  4153. }
  4154. if (lpnmhdr->idFrom == IDC_LIBRARY) {
  4155. return HandleNotifyDBTree(hdlg, lParam);
  4156. }
  4157. if (lpnmhdr->idFrom == IDC_CONTENTSLIST) {
  4158. return HandleNotifyContentsList(hdlg, lParam);
  4159. }
  4160. if (lpnmhdr->idFrom == IDC_DESCRIPTION) {
  4161. if (lpnmhdr->code == EN_LINK) {
  4162. ENLINK* penl = (ENLINK*)lParam;
  4163. if (penl->msg == WM_LBUTTONUP) {
  4164. SHELLEXECUTEINFO sei = { 0 };
  4165. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  4166. sei.fMask = SEE_MASK_DOENVSUBST;
  4167. sei.hwnd = hdlg;
  4168. sei.nShow = SW_SHOWNORMAL;
  4169. sei.lpFile = g_szToolkitURL;
  4170. //
  4171. // Get more information about CompatAdmin stuff
  4172. //
  4173. ShellExecuteEx(&sei);
  4174. }
  4175. }
  4176. }
  4177. break;
  4178. }
  4179. case WM_SIZE:
  4180. if (wParam != SIZE_MINIMIZED) {
  4181. HandleSizing(hdlg);
  4182. if (wParam == SIZE_RESTORED) {
  4183. //
  4184. // We might have got minimized because some other
  4185. // app came at the top. So when we again become
  4186. // the top-level window, the user pressed alt-tab or clicked
  4187. // on the icon in the taskbar then we should show the other
  4188. // modeless dialog boxes as well, if they were visible earlier
  4189. //
  4190. if (g_hdlgSearchDB) {
  4191. ShowWindow(g_hdlgSearchDB, SW_RESTORE);
  4192. }
  4193. if (g_hdlgQueryDB) {
  4194. ShowWindow(g_hdlgQueryDB, SW_RESTORE);
  4195. }
  4196. if (g_hwndEventsWnd) {
  4197. ShowWindow(g_hwndEventsWnd, SW_RESTORE);
  4198. }
  4199. RECT r;
  4200. if (g_hwndToolBar) {
  4201. //
  4202. // This is required to handle the case when we restore
  4203. // the window after minimizing and changing the theme
  4204. //
  4205. SendMessage(g_hwndToolBar, WM_SIZE, wParam, lParam);
  4206. SendMessage(g_hwndStatus, WM_SIZE, wParam, lParam);
  4207. }
  4208. }
  4209. } else {
  4210. //
  4211. // If the main app window is getting minimized the other modeless
  4212. // dialog boxes should also get minimized. We have to handled it this
  4213. // way because our modeless dialog boxes have the desktop as their parent
  4214. // This was needed so that we could tab between our main window and
  4215. // the other windows
  4216. //
  4217. if (g_hdlgSearchDB) {
  4218. ShowWindow(g_hdlgSearchDB, SW_MINIMIZE);
  4219. }
  4220. if (g_hdlgQueryDB) {
  4221. ShowWindow(g_hdlgQueryDB, SW_MINIMIZE);
  4222. }
  4223. if (g_hwndEventsWnd) {
  4224. ShowWindow(g_hwndEventsWnd, SW_MINIMIZE);
  4225. }
  4226. return FALSE;
  4227. }
  4228. break;
  4229. case WM_CLOSE:
  4230. SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_FILE_EXIT, 0);
  4231. break;
  4232. case WM_PAINT:
  4233. DrawSplitter(hdlg);
  4234. return FALSE;
  4235. case WM_GETMINMAXINFO:
  4236. {
  4237. //
  4238. // Limit the minimum size of the app window
  4239. //
  4240. MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
  4241. pmmi->ptMinTrackSize.x = 300;
  4242. pmmi->ptMinTrackSize.y = 300;
  4243. return 0;
  4244. }
  4245. case WM_COMMAND:
  4246. switch (wCode) {
  4247. case ID_FILE_MRU1:
  4248. case ID_FILE_MRU2:
  4249. case ID_FILE_MRU3:
  4250. case ID_FILE_MRU4:
  4251. case ID_FILE_MRU5:
  4252. HandleMRUActivation(wCode);
  4253. break;
  4254. case ID_FILE_OPEN:
  4255. OpenDatabaseFiles(hdlg);
  4256. break;
  4257. case ID_FIX_CREATEANEWAPPHELPMESSAGE:
  4258. g_bSomeWizardActive = TRUE;
  4259. CreateNewAppHelp();
  4260. g_bSomeWizardActive = FALSE;
  4261. break;
  4262. case ID_MODIFY_APPHELPMESSAGE:
  4263. g_bSomeWizardActive = TRUE;
  4264. ModifyAppHelp();
  4265. g_bSomeWizardActive = FALSE;
  4266. break;
  4267. case ID_FIX_CREATEANAPPLICATIONFIX:
  4268. g_bSomeWizardActive = TRUE;
  4269. CreateNewAppFix();
  4270. g_bSomeWizardActive = FALSE;
  4271. break;
  4272. case ID_FIX_EXECUTEAPPLICATION:
  4273. if (g_bAdmin == FALSE) {
  4274. //
  4275. // Non admins cannot do a test run because we need to invoke sdbinst.exe
  4276. // to install the test database and sdbinst.exe cannot be invoked if we
  4277. // do not have admin rights
  4278. //
  4279. MessageBox(hdlg,
  4280. GetString(IDS_ERRORNOTADMIN),
  4281. g_szAppName,
  4282. MB_ICONINFORMATION);
  4283. break;
  4284. }
  4285. if (g_pSelEntry) {
  4286. TestRun(g_pSelEntry, &g_pSelEntry->strFullpath, NULL, g_hDlg);
  4287. SetActiveWindow(hdlg);
  4288. SetFocus(hdlg);
  4289. }
  4290. break;
  4291. case ID_FIX_CHANGEENABLESTATUS:
  4292. if (g_bAdmin) {
  4293. ChangeEnableStatus();
  4294. } else {
  4295. //
  4296. // Non admins cannot change the enable-disable status
  4297. // because they do not have rights to HKLM reg key
  4298. //
  4299. MessageBox(hdlg,
  4300. GetString(IDS_ERRORNOTADMIN),
  4301. g_szAppName,
  4302. MB_ICONINFORMATION);
  4303. }
  4304. break;
  4305. case ID_MODIFY_APPLICATIONFIX:
  4306. g_bSomeWizardActive = TRUE;
  4307. ModifyAppFix();
  4308. g_bSomeWizardActive = FALSE;
  4309. break;
  4310. case ID_FIX_CREATENEWLAYER:
  4311. g_bSomeWizardActive = TRUE;
  4312. CreateNewLayer();
  4313. g_bSomeWizardActive = FALSE;
  4314. break;
  4315. case ID_FILE_SAVE:
  4316. {
  4317. BOOL bReturn;
  4318. if (g_pPresentDataBase &&
  4319. (g_pPresentDataBase->bChanged
  4320. || NotCompletePath(g_pPresentDataBase->strPath))) {
  4321. //
  4322. // Error message will be displayed in the SaveDataBase func.
  4323. //
  4324. if (NotCompletePath(g_pPresentDataBase->strPath)) {
  4325. bReturn = SaveDataBaseAs(g_pPresentDataBase);
  4326. } else {
  4327. bReturn = SaveDataBase(g_pPresentDataBase, g_pPresentDataBase->strPath);
  4328. }
  4329. }
  4330. break;
  4331. }
  4332. case ID_VIEW_EVENTS:
  4333. ShowEventsWindow();
  4334. break;
  4335. case ID_HELP_INDEX:
  4336. case ID_HELP_SEARCH:
  4337. case ID_HELP_TOPICS:
  4338. ShowHelp(hdlg, wCode);
  4339. break;
  4340. case ID_HELP_ABOUT:
  4341. ShellAbout(hdlg,
  4342. GetString(IDS_APPLICATION_NAME),
  4343. NULL,
  4344. LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APPICON)));
  4345. break;
  4346. case ID_DATABASE_INSTALL_UNINSTALL:
  4347. DoInstallUnInstall();
  4348. break;
  4349. case ID_FILE_SAVEAS:
  4350. PreprocessForSaveAs(g_pPresentDataBase);
  4351. SaveDataBaseAs(g_pPresentDataBase);
  4352. break;
  4353. case IDCANCEL:
  4354. TreeView_EndEditLabelNow(DBTree.m_hLibraryTree, TRUE);
  4355. break;
  4356. case ID_FILE_EXIT:
  4357. TreeView_Expand(DBTree.m_hLibraryTree, DBTree.m_hItemGlobal, TVE_COLLAPSE);
  4358. if (!CloseAllDatabases()) {
  4359. //
  4360. // Select the database that the user refused to save. (Pressed CANCEL)
  4361. //
  4362. TreeView_SelectItem(DBTree.m_hLibraryTree, g_pPresentDataBase->hItemDB);
  4363. } else {
  4364. s_bProcessExiting = TRUE;
  4365. SaveDisplaySettings();
  4366. SaveMRUList();
  4367. CoUninitialize();
  4368. DestroyWindow(hdlg);
  4369. PostQuitMessage(0);
  4370. HtmlHelp(NULL, NULL, HH_CLOSE_ALL, 0) ;
  4371. HtmlHelp(NULL, NULL, HH_UNINITIALIZE, (DWORD)g_dwCookie);
  4372. g_hDlg = NULL;
  4373. #ifdef HELP_BOUND_CHECK
  4374. OnExitCleanup();
  4375. #endif
  4376. }
  4377. break;
  4378. case ID_EDIT_DELETE:
  4379. OnDelete();
  4380. break;
  4381. case ID_FILE_PROPERTIES:
  4382. DialogBoxParam(g_hInstance,
  4383. MAKEINTRESOURCE(IDD_DBPROPERTIES),
  4384. g_hDlg,
  4385. ShowDBPropertiesDlgProc,
  4386. (LPARAM)g_pPresentDataBase);
  4387. break;
  4388. case ID_FILE_NEW:
  4389. CreateNewDatabase();
  4390. break;
  4391. case ID_TOOLS_SEARCHFORFIXES:
  4392. {
  4393. if (g_hdlgSearchDB) {
  4394. //
  4395. // We must not allow more than one instance of
  4396. // the search window, because we use some global variables there.
  4397. // If it is already there set the focus to the search window
  4398. //
  4399. ShowWindow(g_hdlgSearchDB, SW_SHOWNORMAL);
  4400. SetFocus(g_hdlgSearchDB);
  4401. } else {
  4402. //
  4403. // This object is deleted in the WM_DESTROY of the search dialog box.
  4404. // Note that this has to be allocated on the heap, because this object
  4405. // is used in the UI for the search dialog, which is implemented as
  4406. // a modeless dialog box. So the lifetime of this object exceeds that
  4407. // of the block in which it is defined
  4408. //
  4409. CSearch* pSearch = new CSearch;
  4410. if (pSearch == NULL) {
  4411. MEM_ERR;
  4412. break;
  4413. }
  4414. pSearch->Begin();
  4415. }
  4416. break;
  4417. }
  4418. case ID_DATABASE_CLOSE:
  4419. OnDatabaseClose();
  4420. break;
  4421. case ID_SEARCH_QUERYDATABASE:
  4422. if (g_hdlgQueryDB) {
  4423. //
  4424. // We must not allow more than one instance of
  4425. // the query window, because we use some global variables there.
  4426. // If it is already there set the focus to the search window
  4427. //
  4428. ShowWindow(g_hdlgQueryDB, SW_SHOWNORMAL);
  4429. SetFocus(g_hdlgQueryDB);
  4430. } else {
  4431. HWND hwnd = CreateDialog(g_hInstance,
  4432. MAKEINTRESOURCE(IDD_QDB),
  4433. GetDesktopWindow(),
  4434. QueryDBDlg);
  4435. ShowWindow(hwnd, SW_SHOWNORMAL);
  4436. }
  4437. break;
  4438. case ID_DATABASE_CLOSEALL:
  4439. {
  4440. HTREEITEM hItemSelected = TreeView_GetSelection(DBTree.m_hLibraryTree);
  4441. //
  4442. // Note that it is possible that this function returns false.
  4443. // This will happen if the user presses CANCEL for "Database Saveas"
  4444. // dialog for some "untitled_x" database
  4445. //
  4446. if (!CloseAllDatabases()) {
  4447. //
  4448. // Select the database that the user refused to save.
  4449. //
  4450. TreeView_SelectItem(DBTree.m_hLibraryTree, g_pPresentDataBase->hItemDB);
  4451. }
  4452. break;
  4453. }
  4454. case ID_DATABASE_SAVEALL:
  4455. DatabaseSaveAll();
  4456. break;
  4457. case ID_EDIT_SELECTALL:
  4458. if (g_bIsContentListVisible) {
  4459. ListViewSelectAll(g_hwndContentsList);
  4460. }
  4461. break;
  4462. case ID_EDIT_INVERTSELECTION:
  4463. if (g_bIsContentListVisible) {
  4464. ListViewInvertSelection(g_hwndContentsList);
  4465. }
  4466. break;
  4467. case ID_EDIT_CUT:
  4468. case ID_EDIT_COPY:
  4469. SetCursor(LoadCursor(NULL, IDC_WAIT));
  4470. CopyToClipBoard(wCode);
  4471. SetCursor(LoadCursor(NULL, IDC_ARROW));
  4472. break;
  4473. case ID_EDIT_PASTE:
  4474. {
  4475. //
  4476. // This variable is presently not used
  4477. //
  4478. g_bEntryConflictDonotShow = FALSE;
  4479. PasteFromClipBoard();
  4480. //
  4481. // Now we may need to refresh the contents list.
  4482. //
  4483. HTREEITEM hItem = TreeView_GetSelection(DBTree.m_hLibraryTree);
  4484. TYPE type = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItem);
  4485. if (type == TYPE_GUI_APPS || type == TYPE_GUI_LAYERS || type == FIX_LAYER) {
  4486. PopulateContentsList(hItem);
  4487. SetStatusStringDBTree(hItem);
  4488. }
  4489. break;
  4490. }
  4491. case ID_MODIFY_COMPATIBILITYMODE:
  4492. g_bSomeWizardActive = TRUE;
  4493. ModifyLayer();
  4494. g_bSomeWizardActive = FALSE;
  4495. break;
  4496. case ID_EDIT_RENAME:
  4497. OnRename();
  4498. break;
  4499. case ID_EDIT_CONFIGURELUA:
  4500. if (g_bAdmin == FALSE) {
  4501. MessageBox(hdlg, GetString(IDS_ERRORNOTADMIN), g_szAppName, MB_ICONINFORMATION);
  4502. break;
  4503. }
  4504. //
  4505. // Start the LUA Wizard.
  4506. //
  4507. if (g_pSelEntry == NULL) {
  4508. assert(FALSE);
  4509. break;
  4510. }
  4511. g_bSomeWizardActive = TRUE;
  4512. LuaBeginWizard(g_hDlg, g_pSelEntry, g_pPresentDataBase);
  4513. g_bSomeWizardActive = FALSE;
  4514. break;
  4515. case ID_VIEW_DESCRIPTION:
  4516. {
  4517. HMENU hMenu = GetMenu(g_hDlg);
  4518. HMENU hMenuView = GetSubMenu(hMenu, 2);
  4519. MENUITEMINFO mii = {0};
  4520. mii.cbSize = sizeof(mii);
  4521. mii.fMask = MIIM_STATE;
  4522. GetMenuItemInfo(hMenu, ID_VIEW_DESCRIPTION, FALSE, &mii);
  4523. if (mii.fState & MFS_CHECKED) {
  4524. mii.fState &= ~MFS_CHECKED;
  4525. } else {
  4526. mii.fState |= MFS_CHECKED;
  4527. }
  4528. g_bDescWndOn = !g_bDescWndOn;
  4529. SetMenuItemInfo(hMenu, ID_VIEW_DESCRIPTION, FALSE, &mii);
  4530. UpdateDescWindowStatus();
  4531. break;
  4532. }
  4533. case ID_VIEW_LOG:
  4534. if (g_bAdmin == FALSE) {
  4535. MessageBox(hdlg,
  4536. GetString(IDS_ERRORNOTADMIN),
  4537. g_szAppName,
  4538. MB_ICONINFORMATION);
  4539. break;
  4540. }
  4541. ShowShimLog();
  4542. break;
  4543. default:
  4544. return FALSE;
  4545. }
  4546. break;
  4547. default:
  4548. return FALSE;
  4549. }
  4550. return TRUE;
  4551. }
  4552. int
  4553. WINAPI
  4554. WinMain(
  4555. IN HINSTANCE hInstance,
  4556. IN HINSTANCE hPrevInstance,
  4557. IN LPSTR lpCmdLine,
  4558. IN int nCmdShow
  4559. )
  4560. /*++
  4561. WinMain
  4562. Desc: The WinMain
  4563. Params: Standard WinMain params
  4564. IN HINSTANCE hInstance
  4565. IN HINSTANCE hPrevInstance
  4566. IN LPSTR lpCmdLine
  4567. IN int nCmdShow
  4568. Return: Standard WinMain return
  4569. --*/
  4570. {
  4571. HINSTANCE hmodRichEdit = NULL;
  4572. TCHAR szLibPath[MAX_PATH * 2];
  4573. BOOL bIsGuest = TRUE;
  4574. UINT uResult = 0;
  4575. //
  4576. // Let the system handle data misalignment on Itanium.
  4577. //
  4578. SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
  4579. *szLibPath = 0;
  4580. uResult = GetSystemDirectory(szLibPath, MAX_PATH);
  4581. if (uResult == 0 || uResult >= MAX_PATH) {
  4582. assert(FALSE);
  4583. Dbg(dlError, "WinMain", "GetSytemDirectory failed");
  4584. //
  4585. // We do NOT eject out from here as this is not critical
  4586. //
  4587. } else {
  4588. ADD_PATH_SEPARATOR(szLibPath, ARRAYSIZE(szLibPath));
  4589. StringCchCat(szLibPath, ARRAYSIZE(szLibPath), TEXT("RICHED32.DLL"));
  4590. hmodRichEdit = LoadLibrary(szLibPath);
  4591. }
  4592. //
  4593. // The App Name
  4594. //
  4595. LoadString(g_hInstance, IDS_COMPATADMIN, g_szAppName, ARRAYSIZE(g_szAppName));
  4596. if (!IsAdmin(&bIsGuest)) {
  4597. if (bIsGuest) {
  4598. //
  4599. // Ok, guests cannot run compatadmin.
  4600. //
  4601. MessageBox(NULL, GetString(IDS_GUEST), g_szAppName, MB_ICONINFORMATION);
  4602. goto End;
  4603. }
  4604. //
  4605. // Not an admin, some features are disabled. Cannot do a test run and install databases
  4606. //
  4607. MessageBox(NULL, GetString(IDS_NEEDTOBEADMIN), g_szAppName, MB_ICONINFORMATION);
  4608. g_bAdmin = FALSE;
  4609. }
  4610. g_hInstance = hInstance;
  4611. INITCOMMONCONTROLSEX icex;
  4612. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  4613. icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_TAB_CLASSES | ICC_INTERNET_CLASSES | ICC_BAR_CLASSES ;
  4614. if (!InitCommonControlsEx(&icex)) {
  4615. InitCommonControls();
  4616. }
  4617. //
  4618. // Check if the OS is Win2k
  4619. //
  4620. OSVERSIONINFOEX osvi;
  4621. ZeroMemory(&osvi, sizeof (OSVERSIONINFOEX));
  4622. g_fSPGreaterThan2 = FALSE;
  4623. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  4624. GetVersionEx((LPOSVERSIONINFO)&osvi);
  4625. if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) {
  4626. g_bWin2K = TRUE;
  4627. if (osvi.wServicePackMajor > 2) {
  4628. g_fSPGreaterThan2 = TRUE;
  4629. }
  4630. }
  4631. //
  4632. // Attempt to locate the SDB in the AppPatch directory.
  4633. //
  4634. if (!CheckForSDB()) {
  4635. if (g_bWin2K) {
  4636. DialogBoxParam(g_hInstance,
  4637. MAKEINTRESOURCE(IDD_MSGBOX_SDB),
  4638. NULL,
  4639. MsgBoxDlgProc,
  4640. (LPARAM)0);
  4641. goto End;
  4642. } else {
  4643. MessageBox(GetDesktopWindow(),
  4644. GetString(IDS_XP_NO_SDB),
  4645. g_szAppName,
  4646. MB_OK | MB_ICONEXCLAMATION);
  4647. goto End;
  4648. }
  4649. }
  4650. if (g_bWin2K && !CheckProperSP()) {
  4651. DialogBoxParam(g_hInstance,
  4652. MAKEINTRESOURCE(IDD_MSGBOX_SDB),
  4653. GetDesktopWindow(),
  4654. MsgBoxDlgProc,
  4655. (LPARAM)0);
  4656. goto End;
  4657. }
  4658. CoInitialize(NULL);
  4659. g_hAccelerator = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCL));
  4660. MSG msg ;
  4661. WNDCLASS wndclass ;
  4662. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  4663. wndclass.lpfnWndProc = (WNDPROC)CompatAdminDlgProc;
  4664. wndclass.cbClsExtra = 0;
  4665. wndclass.cbWndExtra = 0;
  4666. wndclass.hInstance = g_hInstance;
  4667. wndclass.hIcon = NULL;
  4668. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  4669. wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  4670. wndclass.lpszMenuName = NULL;
  4671. wndclass.lpszClassName = g_szAppName;
  4672. if (!RegisterClass (&wndclass)) {
  4673. MessageBox (NULL,
  4674. GetString(IDS_INVALIDOS),
  4675. g_szAppName,
  4676. MB_ICONERROR) ;
  4677. goto End;
  4678. }
  4679. g_hDlg = CreateDialog(g_hInstance,
  4680. MAKEINTRESOURCE(IDD_DIALOG),
  4681. GetDesktopWindow(),
  4682. CompatAdminDlgProc);
  4683. ShowWindow(g_hDlg, SW_SHOWNORMAL);
  4684. BOOL bProcessMessage = TRUE;
  4685. HWND hwndActiveWindow;
  4686. //try {
  4687. while (GetMessage(&msg, NULL, 0, 0) > 0) {
  4688. bProcessMessage = TRUE;
  4689. if (g_hdlgSearchDB && IsDialogMessage(g_hdlgSearchDB, &msg)) {
  4690. //
  4691. // This is a message for the Search modeless dialog box
  4692. //
  4693. bProcessMessage = FALSE;
  4694. } else if (g_hdlgQueryDB && IsDialogMessage(g_hdlgQueryDB, &msg)) {
  4695. //
  4696. // This is a message for the Query modeless dialog box
  4697. //
  4698. bProcessMessage = FALSE;
  4699. } else if (g_hwndEventsWnd && IsDialogMessage(g_hwndEventsWnd, &msg)) {
  4700. //
  4701. // This is a message for the Events modeless dialog box
  4702. //
  4703. bProcessMessage = FALSE;
  4704. }
  4705. if (bProcessMessage) {
  4706. //
  4707. // Check if we have the text box for in-place renaming. If yes, we must
  4708. // not call TranslateAccelerator() for the main app window.
  4709. //
  4710. if (GetFocus() == g_hwndRichEdit) {
  4711. //
  4712. // If we are on the rich edit control, we want to be able to do copy
  4713. // but also we want the tabs to be processed by IsDialogMessage()
  4714. //
  4715. if (g_hDlg && IsDialogMessage(g_hDlg, &msg)) {
  4716. //
  4717. // It was possibly a tab or a shift-tab
  4718. //
  4719. continue;
  4720. } else {
  4721. //
  4722. // Process all other rich edit messages
  4723. //
  4724. goto Translate;
  4725. }
  4726. }
  4727. if (!g_hwndEditText) {
  4728. if (TranslateAccelerator(g_hDlg, g_hAccelerator, &msg)) {
  4729. //
  4730. // Accelerator for the main window, do not process this message.
  4731. //
  4732. continue;
  4733. }
  4734. //
  4735. // Process the tabs for the main window
  4736. //
  4737. if (g_hDlg && IsDialogMessage(g_hDlg, &msg)) {
  4738. continue;
  4739. }
  4740. }
  4741. Translate:
  4742. TranslateMessage(&msg);
  4743. DispatchMessage(&msg);
  4744. }
  4745. }
  4746. /*} catch (...) {
  4747. MessageBox(GetDesktopWindow(),
  4748. GetString(IDS_EXCEPTION),
  4749. g_szAppName,
  4750. MB_ICONERROR);
  4751. }*/
  4752. End:
  4753. if (hmodRichEdit) {
  4754. FreeLibrary(hmodRichEdit);
  4755. }
  4756. return 0;
  4757. }
  4758. BOOL
  4759. HandleFirstEntryofAppDeletion(
  4760. IN PDATABASE pDataBase,
  4761. IN PDBENTRY pApp,
  4762. IN BOOL bDelete
  4763. )
  4764. /*++
  4765. HandleFirstEntryofAppDeletion
  4766. Desc: Handles the special case, when the entry being deleted because of a cut
  4767. or a delete is the first entry for the application
  4768. Params:
  4769. IN PDATABASE pDataBase: The database
  4770. IN PDBENTRY pApp: The application whose first enty is being deleted
  4771. IN BOOL bDelete: TRUE, if this function has been called because of
  4772. a delete, FALSE if this function has been called because of a cut.If we
  4773. are removing the entry because of a cut,
  4774. then we should not change the value of g_pEntrySelApp. If bCut is true that
  4775. means focus is on some other app (may be in same diff. database) and we should
  4776. be changing any focus etc.
  4777. Return:
  4778. FALSE: There was some error
  4779. TRUE: Otherwise
  4780. Notes: This is a special case because when we are deleting the first entry of an
  4781. app, we have to check whether this is the only entry and if yes, then we might
  4782. need to delete the entire app from the db tree.
  4783. Otherwise: The app tree item in the db tree contain a pointer to the first entry
  4784. of the app in its lParam, this will need to be modified to point to the next item
  4785. --*/
  4786. {
  4787. if (pApp == NULL || pDataBase == NULL) {
  4788. assert(FALSE);
  4789. Dbg(dlError, "[HandleFirstEntryofAppDeletion] Invalid Arguments");
  4790. return FALSE;
  4791. }
  4792. HTREEITEM hItemApp = DBTree.FindChild(pDataBase->hItemAllApps, (LPARAM)pApp);
  4793. PDBENTRY pEntryTemp = pDataBase->pEntries;
  4794. PDBENTRY pEntryPrev = NULL;
  4795. //
  4796. // Find the App Prev. to the one whose first entry is being deleted
  4797. //
  4798. while (pEntryTemp) {
  4799. if (pEntryTemp == pApp) {
  4800. break;
  4801. }
  4802. pEntryPrev = pEntryTemp;
  4803. pEntryTemp = pEntryTemp->pNext;
  4804. }
  4805. if (pEntryPrev == NULL) {
  4806. //
  4807. // First Entry and first app.
  4808. //
  4809. if (pApp->pSameAppExe) {
  4810. pDataBase->pEntries = pApp->pSameAppExe;
  4811. pApp->pSameAppExe->pNext = pApp->pNext;
  4812. } else {
  4813. pDataBase->pEntries = pApp->pNext;
  4814. }
  4815. } else {
  4816. //
  4817. // The next pointer of the app previous to the pApp should now point
  4818. // to the second entry for pApp as we are removing the first entry of pApp.
  4819. // if pApp has only one entry then we should make sure that the next pointer
  4820. // to the app prev to pApp should point to the next app after pApp
  4821. //
  4822. if (pApp->pSameAppExe) {
  4823. pEntryPrev->pNext = pApp->pSameAppExe;
  4824. pApp->pSameAppExe->pNext = pApp->pNext;
  4825. } else {
  4826. pEntryPrev->pNext = pApp->pNext;
  4827. }
  4828. }
  4829. if (pApp->pSameAppExe == NULL) {
  4830. //
  4831. // This was the only entry. We have to delete the application from the database tree
  4832. //
  4833. g_pEntrySelApp = NULL;
  4834. DBTree.DeleteAppLayer(pDataBase, TRUE, hItemApp);
  4835. --pDataBase->uAppCount;
  4836. } else {
  4837. //
  4838. // We have to set the lParam of the app properly
  4839. //
  4840. DBTree.SetLParam(hItemApp, (LPARAM)pApp->pSameAppExe);
  4841. if (bDelete) {
  4842. //
  4843. // If the deletion is because of a cut do not modify g_pEntrySelApp.
  4844. // Because focus is on some other app (may be in some other database) and
  4845. // we do not want to change the present active app pointer.
  4846. // Please note that we do the actual deletion part of a cut-paste after we
  4847. // have done the paste. So when this routine gets called because of a cut,
  4848. // then we already have focus on the newly pasted item and g_pEntrySelApp
  4849. // will be set to the first entry of the app in which the entry was pasted
  4850. // This is correct, verified and needed. Do not change this.
  4851. //
  4852. g_pEntrySelApp = pApp->pSameAppExe;
  4853. }
  4854. }
  4855. return TRUE;
  4856. }
  4857. void
  4858. GetDescriptionString(
  4859. IN LPARAM itemlParam,
  4860. OUT CSTRING& strDesc,
  4861. IN HWND hwndToolTip,
  4862. IN PCTSTR pszCaption, // (NULL)
  4863. IN HTREEITEM hItem, // (NULL)
  4864. IN HWND hwnd, // (NULL)
  4865. IN INT iListViewIndex // (-1)
  4866. )
  4867. /*++
  4868. GetDescriptionString
  4869. Desc: Gets the description for the tree item hItem in tree hwnd or for the element
  4870. at index iListViewIndex in list view hwnd.
  4871. Params:
  4872. IN LPARAM itemlParam: In case we are using a list view, the lParam of the item
  4873. OUT CSTRING& strDesc: The description will be stored in this
  4874. IN HWND hwndToolTip: In case the description has to be shown in a tool-tip
  4875. the handle to the tool tip window
  4876. IN PCTSTR pszCaption (NULL): In case the description has to be shown in a tool-tip
  4877. the caption of the tool-tip window
  4878. IN HTREEITEM hItem (NULL): If we want to get the description of a tree item, the handle
  4879. to the tree item.
  4880. IN HWND hwnd (NULL): The handle to the list view or the tree view
  4881. IN INT iListViewIndex (-1): In case we are using a list view, the index of the item
  4882. for which we want to get the description
  4883. Notes: If we are calling this routine for a list view, we must set correct iListViewIndex
  4884. and itemlParam.
  4885. itemlParam is ignored if we calling this routine for a tree view
  4886. --*/
  4887. {
  4888. TYPE type;
  4889. LPARAM lParam = itemlParam;
  4890. strDesc = TEXT("");
  4891. if (hItem) {
  4892. if (hwnd == NULL) {
  4893. assert(FALSE);
  4894. goto End;
  4895. }
  4896. type = GetItemType(hwnd, hItem);
  4897. CTree::GetLParam(hwnd, hItem, &lParam);
  4898. } else {
  4899. if (iListViewIndex != -1) {
  4900. if (ListView_GetItemState(hwnd, iListViewIndex, LVIS_SELECTED) != LVIS_SELECTED) {
  4901. if (hwndToolTip) {
  4902. SendMessage(hwndToolTip, TTM_SETTITLE, 0, (LPARAM)NULL);
  4903. }
  4904. return;
  4905. }
  4906. }
  4907. if (lParam) {
  4908. type = ConvertLparam2Type(lParam);
  4909. } else {
  4910. assert(FALSE);
  4911. }
  4912. }
  4913. switch (type) {
  4914. case FIX_LIST_SHIM:
  4915. if (lParam) {
  4916. lParam = (LPARAM)((PSHIM_FIX_LIST)lParam)->pShimFix;
  4917. }
  4918. //
  4919. // CAUTION: case FIX_LIST_SHIM and FIX_SHIM should be one after another.
  4920. // NO break; The next FIX_SHIM case will now handle this.
  4921. //
  4922. case FIX_SHIM:
  4923. {
  4924. PSHIM_FIX pFix = (PSHIM_FIX)lParam;
  4925. if (pFix == NULL) {
  4926. assert(FALSE);
  4927. goto End;
  4928. }
  4929. strDesc = (pFix->strDescription.Length() > 0) ? pFix->strDescription : TEXT("");
  4930. break;
  4931. }
  4932. case FIX_LIST_FLAG:
  4933. if (lParam) {
  4934. lParam = (LPARAM)((PFLAG_FIX_LIST)lParam)->pFlagFix;
  4935. }
  4936. //
  4937. // CAUTION: case FIX_LIST_FLAG and FIX_FLAG should be one after another.
  4938. // NO break; The next FIX_FLAG case will now handle this.
  4939. //
  4940. case FIX_FLAG:
  4941. {
  4942. PFLAG_FIX pFix = (PFLAG_FIX)lParam;
  4943. if (pFix == NULL) {
  4944. assert(FALSE);
  4945. goto End;
  4946. }
  4947. strDesc = (pFix->strDescription.Length() > 0) ? pFix->strDescription : TEXT("");
  4948. break;
  4949. }
  4950. case FIX_PATCH:
  4951. {
  4952. PPATCH_FIX pFix = (PPATCH_FIX)lParam;
  4953. if (pFix == NULL) {
  4954. assert(FALSE);
  4955. goto End;
  4956. }
  4957. strDesc = (pFix->strDescription.Length() > 0) ? pFix->strDescription : TEXT("");
  4958. break;
  4959. }
  4960. case FIX_LAYER:
  4961. {
  4962. PLAYER_FIX pFix = (PLAYER_FIX)lParam;
  4963. if (pFix == NULL) {
  4964. assert(FALSE);
  4965. goto End;
  4966. }
  4967. strDesc = TEXT("");
  4968. break;
  4969. }
  4970. case TYPE_APPHELP_ENTRY:
  4971. {
  4972. PAPPHELP pAppHelp = (PAPPHELP)lParam;
  4973. if (pAppHelp == NULL) {
  4974. break;
  4975. }
  4976. if (g_pPresentDataBase->type == DATABASE_TYPE_GLOBAL) {
  4977. //
  4978. // The AppHelp for the system database has to be picked up. This is not
  4979. // kept in the sysmain.sdb.
  4980. // Also we do not keep this in the database data structure.
  4981. // The apphelp messages for custom are kept in the .sdb and also they
  4982. // are kept in the database data structure.
  4983. //
  4984. PDB pdbAppHelp = SdbOpenApphelpDetailsDatabase(NULL);
  4985. APPHELP_DATA AppHelpData;
  4986. ZeroMemory(&AppHelpData, sizeof(APPHELP_DATA));
  4987. if (g_pSelEntry == NULL) {
  4988. break;
  4989. }
  4990. AppHelpData.dwHTMLHelpID = g_pSelEntry->appHelp.HTMLHELPID;
  4991. if (pdbAppHelp == NULL) {
  4992. strDesc = TEXT("");
  4993. break;
  4994. }
  4995. if (!SdbReadApphelpDetailsData(pdbAppHelp, &AppHelpData)) {
  4996. strDesc = TEXT("");
  4997. break;
  4998. }
  4999. strDesc.Sprintf(TEXT("%s %s"), CSTRING(IDS_DESC_APPHELP1).pszString, AppHelpData.szDetails);
  5000. if (AppHelpData.szURL) {
  5001. strDesc.Strcat(CSTRING(IDS_DESC_APPHELP2));
  5002. strDesc.Strcat(AppHelpData.szURL);
  5003. }
  5004. if (pdbAppHelp) {
  5005. SdbCloseDatabase(pdbAppHelp);
  5006. }
  5007. } else {
  5008. //
  5009. // This is a custom database and we have the apphelp message loaded with the
  5010. // database
  5011. //
  5012. strDesc.Sprintf(TEXT("%s %s"), CSTRING(IDS_DESC_APPHELP1).pszString, pAppHelp->strMessage);
  5013. if (pAppHelp->strURL.Length()) {
  5014. strDesc.Strcat(CSTRING(IDS_DESC_APPHELP2));
  5015. strDesc.Strcat(pAppHelp->strURL);
  5016. }
  5017. }
  5018. if (g_pSelEntry == NULL) {
  5019. assert(FALSE);
  5020. break;
  5021. }
  5022. switch (g_pSelEntry->appHelp.severity) {
  5023. case APPTYPE_INC_HARDBLOCK:
  5024. strDesc.Strcat(CSTRING(IDS_APPHELP_DESC_HARDBLOCK));
  5025. break;
  5026. case APPTYPE_NONE:
  5027. strDesc.Strcat(CSTRING(IDS_APPHELP_DESC_NONE));
  5028. break;
  5029. default:
  5030. strDesc.Strcat(CSTRING(IDS_APPHELP_DESC_SOFTBLOCK));
  5031. break;
  5032. }
  5033. break;
  5034. }
  5035. default:
  5036. strDesc = TEXT("");
  5037. break;
  5038. }
  5039. if (strDesc.Length() && pszCaption && hwndToolTip) {
  5040. //
  5041. // We have a valid caption, so set it only if we have a tooltip
  5042. //
  5043. SendMessage(hwndToolTip, TTM_SETTITLE, 1, (LPARAM)pszCaption);
  5044. } else if (hwndToolTip) {
  5045. //
  5046. // We do not have a caption, so tell the tool-tip that
  5047. // we do not want to have any caption
  5048. //
  5049. SendMessage(hwndToolTip, TTM_SETTITLE, 0, (LPARAM)NULL);
  5050. }
  5051. End:
  5052. return;
  5053. }
  5054. INT
  5055. ShowMainEntries(
  5056. IN HWND hdlg
  5057. )
  5058. /*++
  5059. ShowMainEntries
  5060. Desc: Loads the PDBENTRY elements for the system database
  5061. Params:
  5062. IN HWND hdlg: The main app window
  5063. Return:
  5064. -1: Some other thread has called this function and is not done as yet
  5065. 0: There was some error
  5066. 1: Either we loaded it successfully or we already had the main entries loaded
  5067. Warn: No two threads should call this function at the same time
  5068. Note: We can call ShowMainEntries() from a thread in query database modeless
  5069. dialog box. When we are doing the query we disable the main dialog box. We still
  5070. have protection using critical sections here.
  5071. When we call ShowMainEntries() from the main window, then we will not be able
  5072. to invoke the search or query dialog because the main thread will be busy and no
  5073. messages will be processed
  5074. --*/
  5075. {
  5076. INT iOk = 1;
  5077. BOOL bReturn = FALSE;
  5078. PDATABASE pOldPresentDatabase = NULL;
  5079. EnterCriticalSection(&s_csExpanding);
  5080. if (g_bExpanding) {
  5081. //
  5082. // Some other thread is already trying to load the system database
  5083. //
  5084. LeaveCriticalSection(&s_csExpanding);
  5085. return -1;
  5086. } else {
  5087. g_bExpanding = TRUE;
  5088. }
  5089. LeaveCriticalSection(&s_csExpanding);
  5090. EnterCriticalSection(&g_critsectShowMain);
  5091. if (g_bMainAppExpanded) {
  5092. goto End;
  5093. }
  5094. pOldPresentDatabase = g_pPresentDataBase;
  5095. bReturn = GetDatabaseEntries(NULL, &GlobalDataBase);
  5096. //
  5097. // GetDatabaseEntries will change the g_pPresentDataBase, so revert back
  5098. //
  5099. g_pPresentDataBase = pOldPresentDatabase;
  5100. if (bReturn == FALSE) {
  5101. MessageBox(hdlg, CSTRING(IDS_ERROROPEN), g_szAppName, MB_ICONERROR);
  5102. iOk = 0;
  5103. goto End;
  5104. }
  5105. //
  5106. // Delete the dummy node
  5107. //
  5108. HTREEITEM hItemTemp = TreeView_GetChild(DBTree.m_hLibraryTree,
  5109. GlobalDataBase.hItemAllApps);
  5110. if (hItemTemp) {
  5111. TreeView_DeleteItem(DBTree.m_hLibraryTree, hItemTemp);
  5112. }
  5113. //
  5114. // Load only the apps as the lib has already been loaded when the system started
  5115. //
  5116. DBTree.PopulateLibraryTree(GlobalDataBase.hItemAllApps, &GlobalDataBase, FALSE, TRUE);
  5117. g_bMainAppExpanded = TRUE;
  5118. SetCaption();
  5119. End:
  5120. LeaveCriticalSection(&g_critsectShowMain);
  5121. EnterCriticalSection(&s_csExpanding);
  5122. g_bExpanding = FALSE;
  5123. LeaveCriticalSection(&s_csExpanding);
  5124. SetStatus(g_hwndStatus, CSTRING(IDS_MAINLOADED));
  5125. if (g_hdlgSearchDB) {
  5126. //
  5127. // If somebody clicked on the search modeless window while we were loading the
  5128. // system db then the search window will show in its status message that we are loading the system db, we need
  5129. // to change the status message when we are done
  5130. //
  5131. SetStatus(GetDlgItem(g_hdlgSearchDB, IDC_STATUSBAR), GetString(IDS_SEARCHCOMPLETE));
  5132. }
  5133. return iOk;
  5134. }
  5135. void
  5136. DrawSplitter(
  5137. IN HWND hdlg
  5138. )
  5139. /*++
  5140. DrawSplitter
  5141. Desc: Draws the vertical. split bar.
  5142. We call this function when we are moving the mouse with the LBUTTON pressed
  5143. and the mouse button was initially pressed on top of the split bar
  5144. We also call this function when we need to position the
  5145. vert. split bar when we start up and have to position the split bar
  5146. as it was during the last session
  5147. Params:
  5148. IN HWND hdlg: The main dialog box.
  5149. --*/
  5150. {
  5151. RECT rectDBTree, rectEntryTree;
  5152. PAINTSTRUCT ps;
  5153. HDC hDC;
  5154. GetWindowRect(GetDlgItem(hdlg, IDC_LIBRARY), &rectDBTree);
  5155. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectDBTree, 2);
  5156. GetWindowRect(GetDlgItem(hdlg, IDC_ENTRY), &rectEntryTree);
  5157. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectEntryTree, 2);
  5158. hDC = BeginPaint(hdlg, &ps);
  5159. RECT rectDraw, rectBar;
  5160. if (!g_bDrag) {
  5161. //
  5162. // The mouse is not being dragged. We also call this function when we need to
  5163. // position the vert. split bar when we start up and have to position the split bar
  5164. // as it was during the last session
  5165. //
  5166. rectBar.left = rectDBTree.right + 1;
  5167. rectBar.top = rectDBTree.top;
  5168. rectBar.right = rectEntryTree.left - 1;
  5169. rectBar.bottom = rectDBTree.bottom;
  5170. } else {
  5171. //
  5172. // The mouse is being dragged
  5173. //
  5174. rectBar = g_rectBar;
  5175. }
  5176. //
  5177. // Fill the entire with gray. This is required because otherwise we had
  5178. // to draw a rectangle, and change the default pen before this.
  5179. // This would have painted the inside with the default brush.
  5180. //
  5181. SetRect(&rectDraw, rectBar.left - 1, rectBar.top, rectBar.right + 1, rectBar.bottom);
  5182. FillRect(hDC, &rectDraw, (HBRUSH)GetStockObject(GRAY_BRUSH));
  5183. SetRect(&rectDraw, rectBar.left - 1, rectBar.top + 1, rectBar.left, rectBar.bottom - 1);
  5184. FillRect(hDC, &rectDraw, (HBRUSH)(HBRUSH)GetStockObject(WHITE_BRUSH));
  5185. SetRect(&rectDraw, rectBar.left, rectBar.top + 1, rectBar.right, rectBar.bottom - 1);
  5186. FillRect(hDC, &rectDraw, (HBRUSH)(HBRUSH)GetStockObject(LTGRAY_BRUSH));
  5187. EndPaint(hdlg, &ps);
  5188. }
  5189. BOOL
  5190. CloseAllDatabases(
  5191. void
  5192. )
  5193. /*++
  5194. CloseAllDatabases
  5195. Desc: Closes all the working databases
  5196. Return:
  5197. TRUE: All the databases were not closed
  5198. FALSE: All the databases were not closed, either because of some error
  5199. Or the user selected cancel on the prompt for some unsaved database
  5200. --*/
  5201. {
  5202. PDATABASE pDatabase = DataBaseList.pDataBaseHead;
  5203. while (pDatabase) {
  5204. HTREEITEM hItemDB = pDatabase->hItemDB;
  5205. if (pDatabase->bChanged) {
  5206. TreeView_SelectItem(DBTree.m_hLibraryTree, hItemDB);
  5207. }
  5208. if (!CloseDataBase(pDatabase)) {
  5209. break;
  5210. }
  5211. //
  5212. // The DataBaseList.pDataBaseHead now points to the next database
  5213. //
  5214. pDatabase = DataBaseList.pDataBaseHead;
  5215. }
  5216. if (pDatabase != NULL) {
  5217. //
  5218. // Was Cancel pressed in between.
  5219. //
  5220. g_pPresentDataBase = pDatabase;
  5221. TreeView_SelectItem(DBTree.m_hLibraryTree, pDatabase->hItemDB);
  5222. return FALSE;
  5223. }
  5224. return TRUE;
  5225. }
  5226. INT_PTR
  5227. CALLBACK
  5228. HandleConflictEntry(
  5229. IN HWND hdlg,
  5230. IN UINT uMsg,
  5231. IN WPARAM wParam,
  5232. IN LPARAM lParam
  5233. )
  5234. /*++
  5235. HandleConflictEntry
  5236. Desc: The handler for the entry conflict dialog box
  5237. Params: Standard dialog handler parameters
  5238. IN HWND hDlg
  5239. IN UINT uMsg
  5240. IN WPARAM wParam
  5241. IN LPARAM lParam
  5242. Return: Standard dialog handler return
  5243. --*/
  5244. {
  5245. switch (uMsg) {
  5246. case WM_INITDIALOG:
  5247. CenterWindow(g_hDlg, hdlg);
  5248. SetDlgItemText(hdlg, IDC_CONFLICT_MSG, (TCHAR*)lParam);
  5249. break;
  5250. case WM_COMMAND:
  5251. switch (LOWORD (wParam)) {
  5252. case IDNO:
  5253. case IDCANCEL:
  5254. case IDYES:
  5255. EndDialog(hdlg, LOWORD (wParam));
  5256. break;
  5257. default: return FALSE;
  5258. }
  5259. default:
  5260. return FALSE;
  5261. }
  5262. return TRUE;
  5263. }
  5264. TYPE
  5265. ConvertLparam2Type(
  5266. IN LPARAM lParam
  5267. )
  5268. /*++
  5269. ConvertLparam2Type
  5270. Desc: Converts the lParam to a TYPE
  5271. Params:
  5272. IN LPARAM lParam: The lParam that has to be converted
  5273. Return: Converts the lParam to a TYPE
  5274. Warn: Do not use this routine for lParams of the entry tree.
  5275. The entry tree has attribute items whose lParams are the index in a bit array.
  5276. So for them we see if the parent has type TYPE_MATCHIING_FILE and handle them
  5277. differently.
  5278. For trees, GetItemType() instead.
  5279. --*/
  5280. {
  5281. if (lParam > TYPE_NULL) {
  5282. PDS_TYPE pds = (PDS_TYPE)lParam;
  5283. if (pds) {
  5284. return (pds->type);
  5285. } else {
  5286. assert(FALSE);
  5287. }
  5288. }
  5289. return (TYPE)lParam;
  5290. }
  5291. TYPE
  5292. ConvertLpVoid2Type(
  5293. IN LPVOID lpVoid
  5294. )
  5295. /*++
  5296. ConvertLpVoid2Type
  5297. Desc: Converts the lpVoid to a TYPE
  5298. Params:
  5299. IN LPVOID lpVoid: The lpVoid that has to be converted
  5300. Return: Converts the lpVoid to a TYPE
  5301. Warn: Do not use this routine for lParams of the entry tree.
  5302. The entry tree has attribute items whose lParams are the index in a bit array.
  5303. So for them we see if the parent has type TYPE_MATCHIING_FILE and handle them
  5304. differently.
  5305. For trees, use GetItemType() instead.
  5306. --*/
  5307. {
  5308. if ((LPARAM)lpVoid > TYPE_NULL) {
  5309. PDS_TYPE pds = (PDS_TYPE)lpVoid;
  5310. if (pds) {
  5311. return (pds->type);
  5312. } else {
  5313. assert(FALSE);
  5314. }
  5315. }
  5316. return (TYPE)(LPARAM)lpVoid;
  5317. }
  5318. TYPE
  5319. GetItemType(
  5320. IN HWND hwndTree,
  5321. IN HTREEITEM hItem
  5322. )
  5323. /*++
  5324. Desc: For the HTREEITEM hItem in tree view hwndTree, finds the data type of the item
  5325. For the list of possible data types see CompatAdmin.h
  5326. Params:
  5327. IN HWND hwndTree: Handle to the tree view, should be one of
  5328. g_hwndTree or DBTree.m_hLibraryTree
  5329. IN HTREEITEM hItem: The HTREITEM whose type we need to find
  5330. Notes: The type can be either a GUI type or a data structure type or attribute type
  5331. (If it is a child of a matching file, applicable only to entry tree[RHS])
  5332. This routine should be the preferred method for getting the type of tree items,
  5333. over Convert*2Type routines, which should be used for the list view items
  5334. --*/
  5335. {
  5336. TVITEM Item;
  5337. Item.mask = TVIF_PARAM;
  5338. Item.hItem = hItem;
  5339. if (!TreeView_GetItem(hwndTree, &Item)) {
  5340. return TYPE_UNKNOWN;
  5341. }
  5342. HTREEITEM hItemParent = TreeView_GetParent(hwndTree, hItem);
  5343. if (hItemParent != NULL) {
  5344. if (GetItemType(hwndTree, hItemParent) == TYPE_MATCHING_FILE) {
  5345. return TYPE_MATCHING_ATTRIBUTE;
  5346. }
  5347. }
  5348. if (Item.lParam > TYPE_NULL) {
  5349. PDS_TYPE pds = (PDS_TYPE)Item.lParam;
  5350. if (pds) {
  5351. return (pds->type);
  5352. } else {
  5353. assert(FALSE);
  5354. }
  5355. }
  5356. return (TYPE)Item.lParam;
  5357. }
  5358. void
  5359. DoTheCutEntryTree(
  5360. IN PDATABASE pDataBase,
  5361. IN TYPE type,
  5362. IN SOURCE_TYPE SourceType,
  5363. IN LPVOID lpData,
  5364. IN HTREEITEM hItem,
  5365. IN BOOL bDelete
  5366. )
  5367. /*++
  5368. DoTheCutEntryTree
  5369. Desc: This function does the cut part for the entry tree (LHS).
  5370. This routine is also called when we want to delete.
  5371. Params:
  5372. IN PDATABASE pDataBase: The database where we are doing a cut/delete
  5373. IN TYPE type: The type of the element that has to be deleted
  5374. IN SOURCE_TYPE SourceType: Where the cut/delete was performed. Always: ENTRY_TREE
  5375. IN LPVOID lpData: The pointer to the element that has to be deleted
  5376. IN HTREEITEM hItem: The tree item, if there is some
  5377. IN BOOL bDelete: Is this because of a delete or a cut. True if delete
  5378. Note: If we have done a cut and attempt to do the paste on the same database,
  5379. the ID_EDIT_PASTE handler returns before doing any paste.
  5380. Also then this function WILL NOT get called.
  5381. *********************
  5382. Important
  5383. *********************
  5384. As of now only Entries can be cut from the entry tree,
  5385. individual shims, layers, apphelp etc.
  5386. of entries cannot be cut. So if the type is anything other than TYPE_ENTRY
  5387. then we should have the focus on the entry tree and the operation should be
  5388. a delete and NOT a cut
  5389. We use g_pSelEntry here when we remove the shims, layers, matching files etc.
  5390. This is based on the assumption that for non-entries we have the focus on a a
  5391. item under g_pSelEntry
  5392. --*/
  5393. {
  5394. HWND hwndFocus = GetFocus();
  5395. LPARAM LPARAMFirstFix = NULL;
  5396. if (bDelete == FALSE && type != TYPE_ENTRY) {
  5397. //
  5398. // For entry tree only entries can be cut, others can be deleted but not cut.
  5399. //
  5400. assert(FALSE);
  5401. Dbg(dlError, "[DoTheCutEntryTree]: Trying to cut a non-entry item in the entry tree");
  5402. return;
  5403. }
  5404. switch(type) {
  5405. case TYPE_ENTRY:
  5406. {
  5407. PDBENTRY pApp = NULL;
  5408. //
  5409. // Get the app for this entry.
  5410. //
  5411. pApp = GetAppForEntry(pDataBase, (PDBENTRY)lpData);
  5412. if (pApp) {
  5413. RemoveEntry(pDataBase, (PDBENTRY)lpData, pApp, bDelete);
  5414. }
  5415. break;
  5416. }
  5417. case TYPE_APPHELP_ENTRY:
  5418. {
  5419. if (g_pSelEntry == NULL) {
  5420. assert(FALSE);
  5421. break;
  5422. }
  5423. //
  5424. // If the entry has only apphelp and we are deleting the
  5425. // apphelp the entry has to be deleted
  5426. //
  5427. if (g_pSelEntry->pFirstFlag
  5428. || g_pSelEntry->pFirstLayer
  5429. || g_pSelEntry->pFirstPatch
  5430. || g_pSelEntry->pFirstShim) {
  5431. //
  5432. // The entry has some other stuff besides apphelp
  5433. //
  5434. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5435. if (DeleteAppHelp(pDataBase, g_pSelEntry->appHelp.HTMLHELPID)) {
  5436. g_pSelEntry->appHelp.bPresent = FALSE;
  5437. g_pSelEntry->appHelp.bBlock = FALSE;
  5438. g_pSelEntry->appHelp.severity = APPTYPE_NONE;
  5439. } else {
  5440. assert(FALSE);
  5441. }
  5442. } else {
  5443. //
  5444. // Prompt the user, want to delete the entry ?
  5445. //
  5446. int nResult = MessageBox(g_hDlg,
  5447. GetString(IDS_DELETE_VERIFY),
  5448. g_szAppName,
  5449. MB_YESNO | MB_ICONQUESTION);
  5450. if (nResult == IDYES) {
  5451. DoTheCutEntryTree(pDataBase,
  5452. TYPE_ENTRY,
  5453. SourceType,
  5454. g_pSelEntry,
  5455. g_pSelEntry->hItemExe,
  5456. bDelete);
  5457. }
  5458. }
  5459. }
  5460. break;
  5461. case TYPE_MATCHING_FILE:
  5462. {
  5463. if (!g_pSelEntry) {
  5464. assert(FALSE);
  5465. break;
  5466. }
  5467. PMATCHINGFILE pMatch = (PMATCHINGFILE)lpData;
  5468. if (!pMatch) {
  5469. assert(FALSE);
  5470. break;
  5471. }
  5472. if (pMatch->strMatchName == TEXT("*")) {
  5473. //
  5474. // Main file must not be deleted
  5475. //
  5476. MessageBox(g_hDlg,
  5477. GetString(IDS_REQUIREDFORMATCHING),
  5478. g_szAppName,
  5479. MB_ICONWARNING);
  5480. } else {
  5481. DeleteMatchingFile(&g_pSelEntry->pFirstMatchingFile,
  5482. pMatch,
  5483. g_hwndEntryTree,
  5484. hItem);
  5485. }
  5486. }
  5487. break;
  5488. case TYPE_MATCHING_ATTRIBUTE:
  5489. {
  5490. HTREEITEM hItemParent = TreeView_GetParent(g_hwndEntryTree, hItem);
  5491. LPARAM lParam;
  5492. if (hItemParent == NULL) {
  5493. assert(FALSE);
  5494. break;
  5495. }
  5496. if (!DBTree.GetLParam(hItemParent, &lParam)) {
  5497. break;
  5498. }
  5499. PMATCHINGFILE pMatch = PMATCHINGFILE(lParam);
  5500. if (!pMatch) {
  5501. assert(FALSE);
  5502. break;
  5503. }
  5504. //
  5505. // Set off the bit for this attribute in the mask, so we know that
  5506. // this is no longer in use
  5507. // The lParam of the attributes items which are sub-items of the matching file tree
  5508. // item contain the type of the attribute
  5509. // The mask for a matching file specifies which attributes of this matching file
  5510. // are in use
  5511. // the lParam of the attributes is : TYPE_NULL + 1 + (1 << (dwPos + 1));
  5512. // where dwPos is the index of the attribute in the attribute array: g_Attributes
  5513. // which is defined in dbsupport.cpp
  5514. //
  5515. pMatch->dwMask &= ~ ((ULONG_PTR)lpData - (TYPE_NULL + 1));
  5516. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5517. }
  5518. break;
  5519. case TYPE_GUI_MATCHING_FILES:
  5520. MessageBeep(MB_ICONEXCLAMATION);
  5521. break;
  5522. case FIX_LAYER:
  5523. {
  5524. if (!g_pSelEntry) {
  5525. assert(FALSE);
  5526. break;
  5527. }
  5528. PLAYER_FIX plfTobeRemoved = (PLAYER_FIX)lpData;
  5529. if (g_pSelEntry->pFirstLayer == NULL || plfTobeRemoved == NULL) {
  5530. assert(FALSE);
  5531. break;
  5532. }
  5533. if (g_pSelEntry->pFirstLayer->pNext) {
  5534. //
  5535. // We have more than one layer
  5536. //
  5537. PLAYER_FIX_LIST plflTemp = g_pSelEntry->pFirstLayer, plflPrev = NULL;
  5538. while (plflTemp) {
  5539. if (plflTemp->pLayerFix == plfTobeRemoved) {
  5540. break;
  5541. }
  5542. plflPrev = plflTemp;
  5543. plflTemp = plflTemp->pNext;
  5544. }
  5545. if (plflTemp) {
  5546. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5547. if (plflPrev == NULL) {
  5548. g_pSelEntry->pFirstLayer = plflTemp->pNext;
  5549. } else {
  5550. plflPrev->pNext = plflTemp->pNext;
  5551. }
  5552. delete plflTemp;
  5553. plflTemp = NULL;
  5554. }
  5555. } else {
  5556. //
  5557. // Same as if we are trying to remove the root of the layers
  5558. //
  5559. DoTheCutEntryTree(pDataBase,
  5560. TYPE_GUI_LAYERS,
  5561. SourceType,
  5562. NULL,
  5563. TreeView_GetParent(g_hwndEntryTree, hItem),
  5564. bDelete);
  5565. }
  5566. }
  5567. break;
  5568. case FIX_SHIM:
  5569. {
  5570. if (!g_pSelEntry) {
  5571. assert(FALSE);
  5572. break;
  5573. }
  5574. PSHIM_FIX psfTobeRemoved = (PSHIM_FIX)lpData;
  5575. if (g_pSelEntry->pFirstShim == NULL || psfTobeRemoved == NULL) {
  5576. assert(FALSE);
  5577. break;
  5578. }
  5579. if (g_pSelEntry->pFirstShim->pNext || g_pSelEntry->pFirstFlag) {
  5580. //
  5581. // We have more than one item under the "Compatibility Fixes" tree item
  5582. //
  5583. PSHIM_FIX_LIST psflTemp = g_pSelEntry->pFirstShim, psflPrev = NULL;
  5584. while (psflTemp) {
  5585. if (psflTemp->pShimFix == psfTobeRemoved) {
  5586. break;
  5587. }
  5588. psflPrev = psflTemp;
  5589. psflTemp = psflTemp->pNext;
  5590. }
  5591. if (psflTemp) {
  5592. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5593. if (psflPrev == NULL) {
  5594. g_pSelEntry->pFirstShim = psflTemp->pNext;
  5595. } else {
  5596. psflPrev->pNext = psflTemp->pNext;
  5597. }
  5598. delete psflTemp;
  5599. }
  5600. } else {
  5601. //
  5602. // Same as we are trying to remove the root of the shims
  5603. //
  5604. DoTheCutEntryTree(pDataBase,
  5605. TYPE_GUI_SHIMS,
  5606. SourceType,
  5607. NULL,
  5608. TreeView_GetParent(g_hwndEntryTree, hItem),
  5609. bDelete);
  5610. }
  5611. }
  5612. break;
  5613. case FIX_FLAG:
  5614. {
  5615. if (!g_pSelEntry) {
  5616. assert(FALSE);
  5617. break;
  5618. }
  5619. PFLAG_FIX pffTobeRemoved = (PFLAG_FIX)lpData;
  5620. if (g_pSelEntry->pFirstFlag == NULL || pffTobeRemoved == NULL) {
  5621. assert(FALSE);
  5622. break;
  5623. }
  5624. if (g_pSelEntry->pFirstFlag->pNext || g_pSelEntry->pFirstShim) {
  5625. //
  5626. // We have more than one item under the "Compatibility Fixes" tree item
  5627. //
  5628. PFLAG_FIX_LIST pfflTemp = g_pSelEntry->pFirstFlag, pfflPrev = NULL;
  5629. while (pfflTemp) {
  5630. if (pfflTemp->pFlagFix == pffTobeRemoved) {
  5631. break;
  5632. }
  5633. pfflPrev = pfflTemp;
  5634. pfflTemp = pfflTemp->pNext;
  5635. }
  5636. if (pfflTemp) {
  5637. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5638. if (pfflPrev == NULL) {
  5639. g_pSelEntry->pFirstFlag = pfflTemp->pNext;
  5640. } else {
  5641. pfflPrev->pNext = pfflTemp->pNext;
  5642. }
  5643. delete pfflTemp;
  5644. }
  5645. } else {
  5646. //
  5647. // Same as we are trying to remove the root of the flags
  5648. //
  5649. DoTheCutEntryTree(pDataBase,
  5650. TYPE_GUI_SHIMS,
  5651. SourceType,
  5652. NULL,
  5653. TreeView_GetParent(g_hwndEntryTree, hItem),
  5654. bDelete);
  5655. }
  5656. }
  5657. break;
  5658. case FIX_PATCH:
  5659. {
  5660. if (!g_pSelEntry) {
  5661. assert(FALSE);
  5662. break;
  5663. }
  5664. PPATCH_FIX pPatchTobeRemoved = (PPATCH_FIX)lpData;
  5665. if (g_pSelEntry->pFirstPatch == NULL || pPatchTobeRemoved == NULL) {
  5666. assert(FALSE);
  5667. break;
  5668. }
  5669. if (g_pSelEntry->pFirstPatch->pNext || g_pSelEntry->pFirstShim) {
  5670. PPATCH_FIX_LIST pPatchTemp = g_pSelEntry->pFirstPatch, pPatchflPrev = NULL;
  5671. while (pPatchTemp) {
  5672. pPatchflPrev = pPatchTemp;
  5673. if (pPatchTemp->pPatchFix == pPatchTobeRemoved) {
  5674. break;
  5675. }
  5676. pPatchTemp = pPatchTemp->pNext;
  5677. }
  5678. if (pPatchTemp) {
  5679. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5680. if (pPatchflPrev == NULL) {
  5681. g_pSelEntry->pFirstPatch = pPatchTemp->pNext;
  5682. } else {
  5683. pPatchflPrev->pNext = pPatchTemp->pNext;
  5684. }
  5685. delete pPatchTemp;
  5686. }
  5687. } else {
  5688. //
  5689. // Same as we are trying to remove the root of the patches
  5690. //
  5691. DoTheCutEntryTree(pDataBase,
  5692. TYPE_GUI_PATCHES,
  5693. SourceType,
  5694. NULL,
  5695. TreeView_GetParent(g_hwndEntryTree, hItem),
  5696. bDelete);
  5697. }
  5698. }
  5699. break;
  5700. case TYPE_GUI_LAYERS:
  5701. {
  5702. if (!g_pSelEntry) {
  5703. assert(FALSE);
  5704. break;
  5705. }
  5706. //
  5707. // If the entry has only layers and we are deleting it the
  5708. // entry has to be deleted
  5709. //
  5710. if (g_pSelEntry->pFirstFlag
  5711. || g_pSelEntry->pFirstPatch
  5712. || g_pSelEntry->appHelp.bPresent
  5713. || g_pSelEntry->pFirstShim) {
  5714. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5715. DeleteLayerFixList(g_pSelEntry->pFirstLayer);
  5716. g_pSelEntry->pFirstLayer = NULL;
  5717. } else {
  5718. //
  5719. // Prompt the user, want to delete the entry ?
  5720. //
  5721. int nResult = MessageBox(g_hDlg,
  5722. GetString(IDS_DELETE_VERIFY),
  5723. g_szAppName,
  5724. MB_YESNO | MB_ICONQUESTION);
  5725. if (nResult == IDYES) {
  5726. DoTheCutEntryTree(pDataBase,
  5727. TYPE_ENTRY,
  5728. SourceType,
  5729. g_pSelEntry,
  5730. g_pSelEntry->hItemExe,
  5731. bDelete);
  5732. }
  5733. }
  5734. }
  5735. break;
  5736. case TYPE_GUI_PATCHES:
  5737. {
  5738. if (!g_pSelEntry) {
  5739. assert(FALSE);
  5740. break;
  5741. }
  5742. //
  5743. // If the entry has only patches and we are deleting it the entry has
  5744. // to be deleted
  5745. //
  5746. if (g_pSelEntry->pFirstFlag
  5747. || g_pSelEntry->appHelp.bPresent
  5748. || g_pSelEntry->pFirstLayer
  5749. || g_pSelEntry->pFirstShim) {
  5750. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5751. DeletePatchFixList(g_pSelEntry->pFirstPatch);
  5752. g_pSelEntry->pFirstPatch = NULL;
  5753. } else {
  5754. //
  5755. // Prompt the user, want to delete the entry ?
  5756. //
  5757. int nResult = MessageBox(g_hDlg,
  5758. GetString(IDS_DELETE_VERIFY),
  5759. g_szAppName,
  5760. MB_YESNO | MB_ICONQUESTION);
  5761. if (nResult == IDYES) {
  5762. DoTheCutEntryTree(pDataBase,
  5763. TYPE_ENTRY,
  5764. SourceType,
  5765. g_pSelEntry,
  5766. g_pSelEntry->hItemExe,
  5767. bDelete);
  5768. }
  5769. }
  5770. }
  5771. break;
  5772. case TYPE_GUI_SHIMS:
  5773. {
  5774. if (!g_pSelEntry) {
  5775. assert(FALSE);
  5776. break;
  5777. }
  5778. //
  5779. // If the entry has only shims & flags and we are deleting it the entry
  5780. // has to be deleted
  5781. //
  5782. if (g_pSelEntry->pFirstPatch
  5783. || g_pSelEntry->appHelp.bPresent
  5784. || g_pSelEntry->pFirstLayer) {
  5785. TreeView_DeleteItem(g_hwndEntryTree, hItem);
  5786. DeleteShimFixList(g_pSelEntry->pFirstShim);
  5787. g_pSelEntry->pFirstShim = NULL;
  5788. DeleteFlagFixList(g_pSelEntry->pFirstFlag);
  5789. g_pSelEntry->pFirstFlag = NULL;
  5790. } else {
  5791. //
  5792. // Prompt the user, want to delete the entry ?
  5793. //
  5794. int nResult = MessageBox(g_hDlg,
  5795. GetString(IDS_DELETE_VERIFY),
  5796. g_szAppName,
  5797. MB_YESNO | MB_ICONQUESTION);
  5798. if (nResult == IDYES) {
  5799. DoTheCutEntryTree(pDataBase,
  5800. TYPE_ENTRY,
  5801. SourceType,
  5802. g_pSelEntry,
  5803. g_pSelEntry->hItemExe,
  5804. bDelete);
  5805. }
  5806. }
  5807. }
  5808. break;
  5809. }
  5810. }
  5811. void
  5812. DoTheCut(
  5813. IN PDATABASE pDataBase,
  5814. IN TYPE type,
  5815. IN SOURCE_TYPE SourceType,
  5816. IN LPVOID lpData, // To be removed
  5817. IN HTREEITEM hItem,
  5818. IN BOOL bDelete
  5819. )
  5820. /*++
  5821. DoTheCut
  5822. Desc: This function does the cut part. This routine is also called when we want
  5823. to delete.
  5824. Params:
  5825. IN PDATABASE pDataBase : The database where we are doing a cut/delete
  5826. IN TYPE type : The type of the element that has to be deleted
  5827. IN SOURCE_TYPE SourceType : Where the cut/delete was performed. One of:
  5828. a) ENTRY_TREE
  5829. b) ENTRY_LIST
  5830. c) LIB_TREE
  5831. IN LPVOID lpData: The pointer to the element that has to be deleted
  5832. IN HTREEITEM hItem: The tree item, if there is some
  5833. IN BOOL bDelete: If this is true that means that this routine has been
  5834. called because of a delete operation. Deletion is a bit different than cut because
  5835. when we delete then we might need to repaint the UI. When doing a cut, the actual
  5836. cut is done only after paste has been successful. In that case the newly pasted
  5837. item is shown in the UI and we should not try to update the UI.
  5838. Note: If we have done a cut and attempt to do the paste on the same database,
  5839. the ID_EDIT_PASTE handler returns before doing any paste.
  5840. Also then this function WILL NOT get called.
  5841. --*/
  5842. {
  5843. INT iIndex = -1;
  5844. HWND hwndFocus;
  5845. hwndFocus = GetFocus();
  5846. if (SourceType == ENTRY_TREE) {
  5847. DoTheCutEntryTree(pDataBase,
  5848. type,
  5849. SourceType,
  5850. lpData,
  5851. hItem,
  5852. bDelete);
  5853. return;
  5854. }
  5855. switch (type) {
  5856. case TYPE_ENTRY:
  5857. if (SourceType == LIB_TREE || SourceType == ENTRY_LIST) {
  5858. //
  5859. // Must delete the tree item before actually removing the
  5860. // entry using RemoveApp/RemoveEntry
  5861. //
  5862. if (bDelete) {
  5863. TreeDeleteAll(g_hwndEntryTree);
  5864. g_pEntrySelApp = g_pSelEntry = NULL;
  5865. }
  5866. if (SourceType == ENTRY_LIST && bDelete) {
  5867. iIndex = GetContentsListIndex(g_hwndContentsList, (LPARAM)lpData);
  5868. if (iIndex > -1) {
  5869. ListView_DeleteItem(g_hwndContentsList, iIndex);
  5870. }
  5871. }
  5872. DBTree.DeleteAppLayer(pDataBase, TRUE, hItem, bDelete);
  5873. RemoveApp(pDataBase, (PDBENTRY)lpData);
  5874. if (bDelete && pDataBase->hItemAllApps) {
  5875. //
  5876. // Show that we now have one less entry/app
  5877. //
  5878. SetStatusStringDBTree(pDataBase->hItemAllApps);
  5879. }
  5880. }
  5881. break;
  5882. case TYPE_GUI_APPS:
  5883. TreeView_DeleteItem(DBTree.m_hLibraryTree, pDataBase->hItemAllApps);
  5884. RemoveAllApps(pDataBase);
  5885. pDataBase->hItemAllApps = NULL;
  5886. break;
  5887. case FIX_LAYER:
  5888. if (RemoveLayer(pDataBase, (PLAYER_FIX)lpData, NULL)) {
  5889. //
  5890. // This function will return FALSE, if the layer in in use
  5891. //
  5892. if (SourceType == ENTRY_LIST && bDelete && type == FIX_LAYER) {
  5893. iIndex = GetContentsListIndex(g_hwndContentsList, (LPARAM)lpData);
  5894. if (iIndex > -1) {
  5895. ListView_DeleteItem(g_hwndContentsList, iIndex);
  5896. }
  5897. }
  5898. DBTree.DeleteAppLayer(pDataBase, FALSE, hItem, bDelete);
  5899. //
  5900. // Show that we now have one less layer
  5901. //
  5902. if (bDelete && pDataBase->hItemAllLayers) {
  5903. SetStatusStringDBTree(pDataBase->hItemAllLayers);
  5904. }
  5905. }
  5906. break;
  5907. case TYPE_GUI_LAYERS:
  5908. {
  5909. BOOL fAllDeleted = TRUE;
  5910. while (pDataBase->pLayerFixes && fAllDeleted) {
  5911. fAllDeleted = fAllDeleted && RemoveLayer(pDataBase,
  5912. pDataBase->pLayerFixes,
  5913. NULL);
  5914. }
  5915. if (fAllDeleted) {
  5916. TreeView_DeleteItem(DBTree.m_hLibraryTree, pDataBase->hItemAllLayers);
  5917. pDataBase->hItemAllLayers = NULL;
  5918. }
  5919. }
  5920. break;
  5921. }
  5922. }
  5923. LRESULT
  5924. CALLBACK
  5925. ListViewProc(
  5926. IN HWND hWnd,
  5927. IN UINT uMsg,
  5928. IN WPARAM wParam,
  5929. IN LPARAM lParam
  5930. )
  5931. /*++
  5932. ListViewProc
  5933. Desc: Subclasses the message proc for the contents list view (RHS)
  5934. Params: Standard dialog handler parameters
  5935. IN HWND hDlg
  5936. IN UINT uMsg
  5937. IN WPARAM wParam
  5938. IN LPARAM lParam
  5939. Return: Standard handler return
  5940. --*/
  5941. {
  5942. switch (uMsg) {
  5943. case WM_SETFOCUS:
  5944. {
  5945. LVITEM lvi;
  5946. ZeroMemory(&lvi, sizeof(lvi));
  5947. lvi.mask = LVIF_PARAM;
  5948. lvi.iItem = g_iContentsListSelectIndex;
  5949. lvi.iSubItem = 0;
  5950. if (ListView_GetItem(hWnd, &lvi)) {
  5951. HTREEITEM hItemInDBTree = NULL;
  5952. hItemInDBTree = DBTree.FindChild(TreeView_GetSelection(DBTree.m_hLibraryTree),
  5953. lvi.lParam);
  5954. SetStatusStringDBTree(hItemInDBTree);
  5955. }
  5956. }
  5957. break;
  5958. }
  5959. return CallWindowProc(g_PrevListProc, hWnd, uMsg, wParam, lParam);
  5960. }
  5961. LRESULT
  5962. CALLBACK
  5963. TreeViewProc(
  5964. HWND hWnd,
  5965. UINT uMsg,
  5966. WPARAM wParam,
  5967. LPARAM lParam
  5968. )
  5969. /*++
  5970. TreeViewProc
  5971. Desc: Subclasses the message proc for both the tree views
  5972. Params: Standard dialog handler parameters
  5973. IN HWND hDlg
  5974. IN UINT uMsg
  5975. IN WPARAM wParam
  5976. IN LPARAM lParam
  5977. Return: Standard handler return
  5978. --*/
  5979. {
  5980. switch (uMsg)
  5981. case WM_SETFOCUS:
  5982. {
  5983. HTREEITEM hItem= TreeView_GetSelection(hWnd);
  5984. if (hItem) {
  5985. if (hWnd && hWnd == DBTree.m_hLibraryTree) {
  5986. SetStatusStringDBTree(hItem);
  5987. } else if (hWnd && hWnd == g_hwndEntryTree) {
  5988. SetStatusStringEntryTree(hItem);
  5989. }
  5990. }
  5991. break;
  5992. }
  5993. return CallWindowProc(g_PrevTreeProc, hWnd, uMsg, wParam, lParam);
  5994. }
  5995. void
  5996. PopulateContentsList(
  5997. IN HTREEITEM hItem
  5998. )
  5999. /*++
  6000. PopulateContentsList
  6001. Desc: Populates the contents list with the children of hItem in the DB Tree
  6002. At the moment we show the items in the contents list only if the type of
  6003. hItem is of:
  6004. TYPE_GUI_APPS
  6005. TYPE_GUI_LAYERS
  6006. TYPE_GUI_SHIMS
  6007. FIX_LAYER
  6008. Params:
  6009. IN HTREEITEM hItem: A tree item in the db tree.
  6010. Return:
  6011. void
  6012. Notes: This routine will not/should not be called when the user has selected a
  6013. an app in the Lib Tree.
  6014. --*/
  6015. {
  6016. TCHAR szBuffer[512];
  6017. TYPE type = (TYPE)GetItemType(DBTree.m_hLibraryTree, hItem);
  6018. TVITEM Item;
  6019. UINT uIndex = 0;
  6020. LVITEM lvi;
  6021. if (type == TYPE_GUI_APPS
  6022. || type == TYPE_GUI_LAYERS
  6023. || type == TYPE_GUI_SHIMS
  6024. || type == FIX_LAYER) {
  6025. ShowWindow(g_hwndEntryTree, SW_HIDE);
  6026. TreeDeleteAll(g_hwndEntryTree);
  6027. g_bIsContentListVisible = TRUE;
  6028. ListView_DeleteAllItems(g_hwndContentsList);
  6029. //
  6030. // ASSUMPTION: We are assuming (this is correct at the moment), that we
  6031. // have only one column in the list view
  6032. //
  6033. ListView_DeleteColumn(g_hwndContentsList, 0);
  6034. ShowWindow(g_hwndContentsList, SW_SHOW);
  6035. SendMessage(g_hwndContentsList, WM_SETREDRAW, TRUE, 0);
  6036. *szBuffer = 0;
  6037. Item.mask = TVIF_TEXT;
  6038. Item.hItem = hItem;
  6039. Item.pszText = szBuffer;
  6040. Item.cchTextMax = ARRAYSIZE(szBuffer);
  6041. if (!TreeView_GetItem(DBTree.m_hLibraryTree, &Item)) {
  6042. assert(FALSE);
  6043. goto End;
  6044. }
  6045. //
  6046. // Set the column text as the text of the item in the tree view
  6047. //
  6048. InsertColumnIntoListView(g_hwndContentsList, szBuffer, 0, 100);
  6049. //
  6050. // Add all the children of the selected item in the tree view
  6051. //
  6052. hItem = TreeView_GetChild(DBTree.m_hLibraryTree, hItem);
  6053. Item.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_TEXT;
  6054. Item.pszText = szBuffer;
  6055. Item.cchTextMax = ARRAYSIZE(szBuffer);
  6056. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  6057. while (hItem) {
  6058. *szBuffer = 0;
  6059. Item.hItem = hItem;
  6060. if (!TreeView_GetItem(DBTree.m_hLibraryTree, &Item)) {
  6061. assert(FALSE);
  6062. return;
  6063. }
  6064. lvi.pszText = Item.pszText;
  6065. lvi.iSubItem = 0;
  6066. lvi.lParam = Item.lParam;
  6067. lvi.iImage = Item.iImage;
  6068. lvi.iItem = uIndex;
  6069. ListView_InsertItem(g_hwndContentsList, &lvi);
  6070. UpdateWindow(g_hwndContentsList);
  6071. uIndex++;
  6072. hItem = TreeView_GetNextSibling(DBTree.m_hLibraryTree, hItem);
  6073. }
  6074. //
  6075. // Set the selection mark for the first element.
  6076. //
  6077. ListView_SetSelectionMark(g_hwndContentsList, 0);
  6078. ListView_SetItemState(g_hwndContentsList,
  6079. 0,
  6080. LVIS_FOCUSED | LVIS_SELECTED ,
  6081. LVIS_FOCUSED | LVIS_SELECTED);
  6082. //
  6083. // Set the column width of the list view appropriately to cover the width of the
  6084. // list view
  6085. // Assumption: The list view has only one column
  6086. //
  6087. ListView_SetColumnWidth(g_hwndContentsList, 0, LVSCW_AUTOSIZE_USEHEADER);
  6088. } else {
  6089. //
  6090. // Clear the contents pane. This is the only way.
  6091. //
  6092. TreeDeleteAll(g_hwndEntryTree);
  6093. g_pSelEntry = g_pEntrySelApp = NULL;
  6094. ShowWindow(g_hwndContentsList, SW_HIDE);
  6095. g_bIsContentListVisible = FALSE;
  6096. ShowWindow(g_hwndEntryTree, SW_SHOW);
  6097. }
  6098. End:
  6099. return;
  6100. }
  6101. void
  6102. LoadPerUserSettings(
  6103. void
  6104. )
  6105. /*++
  6106. LoadPerUserSettings
  6107. Desc: Loads the list of per-user settings
  6108. Params:
  6109. void
  6110. Return:
  6111. void
  6112. --*/
  6113. {
  6114. WCHAR szwName[1024];
  6115. TCHAR szUserName[256], szDomainName[256];
  6116. TCHAR szValueName[MAX_PATH];
  6117. HKEY hKey = NULL;
  6118. PSID pSid = NULL;
  6119. DWORD dwIndex = 0;
  6120. LPTSTR pszData = NULL;
  6121. DWORD dwIndexValue = 0;
  6122. INT iLength = 0;
  6123. SID_NAME_USE sid_type;
  6124. TVINSERTSTRUCT is;
  6125. *szwName = 0;
  6126. SendMessage(DBTree.m_hLibraryTree, WM_SETREDRAW, FALSE, 0);
  6127. //
  6128. // Remove the tree item for per-user settings if it exists. We
  6129. // repopulate the entire list.
  6130. //
  6131. if (DBTree.m_hPerUserHead) {
  6132. TreeView_DeleteItem(DBTree.m_hLibraryTree, DBTree.m_hPerUserHead);
  6133. DBTree.m_hPerUserHead = NULL;
  6134. }
  6135. DWORD dwchSizeSubKeyName = sizeof(szwName)/sizeof(WCHAR);
  6136. //
  6137. // Enumerate the sub-keys under HKEY_USERS.
  6138. //
  6139. while (ERROR_SUCCESS == RegEnumKey(HKEY_USERS,
  6140. dwIndex,
  6141. szwName,
  6142. dwchSizeSubKeyName)) {
  6143. dwIndex++;
  6144. pSid = NULL;
  6145. if (!ConvertStringSidToSid(szwName, &pSid)) {
  6146. if (pSid) {
  6147. LocalFree(pSid);
  6148. pSid = NULL;
  6149. }
  6150. continue;
  6151. }
  6152. DWORD dwchSizeofUserName = ARRAYSIZE(szUserName);
  6153. DWORD dwchSizeDomainName = ARRAYSIZE(szDomainName);
  6154. *szUserName = *szDomainName = 0;
  6155. if (!LookupAccountSid(NULL,
  6156. pSid,
  6157. szUserName,
  6158. &dwchSizeofUserName,
  6159. szDomainName,
  6160. &dwchSizeDomainName,
  6161. &sid_type)) {
  6162. if (pSid) {
  6163. LocalFree(pSid);
  6164. pSid = NULL;
  6165. }
  6166. continue;
  6167. }
  6168. if (sid_type != SidTypeUser) {
  6169. if (pSid) {
  6170. LocalFree(pSid);
  6171. pSid = NULL;
  6172. }
  6173. continue;
  6174. }
  6175. if (pSid) {
  6176. LocalFree(pSid);
  6177. pSid = NULL;
  6178. }
  6179. iLength = lstrlen(szwName);
  6180. SafeCpyN(szwName + iLength, APPCOMPAT_PERM_LAYER_PATH, ARRAYSIZE(szwName) - iLength);
  6181. if (RegOpenKeyEx(HKEY_USERS, szwName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  6182. //
  6183. // enumerate the values
  6184. //
  6185. *szValueName = 0;
  6186. DWORD dwchSizeofValueName;
  6187. DWORD dwSizeofData;
  6188. DWORD dwType = REG_SZ;
  6189. LONG lReturn;
  6190. HTREEITEM hItemSingleUser = NULL, hItemApp = NULL;
  6191. while (TRUE) {
  6192. dwchSizeofValueName = ARRAYSIZE(szValueName);
  6193. dwSizeofData = 512;
  6194. dwType = REG_SZ;
  6195. pszData = new TCHAR[dwSizeofData / sizeof(TCHAR)];
  6196. if (pszData == NULL) {
  6197. MEM_ERR;
  6198. break;
  6199. }
  6200. lReturn = RegEnumValue(hKey,
  6201. dwIndexValue,
  6202. szValueName,
  6203. &dwchSizeofValueName,
  6204. NULL,
  6205. &dwType,
  6206. (LPBYTE)pszData,
  6207. &dwSizeofData);
  6208. if (lReturn == ERROR_NO_MORE_ITEMS) {
  6209. break;
  6210. }
  6211. if (lReturn != ERROR_SUCCESS || dwType != REG_SZ) {
  6212. assert(FALSE);
  6213. break;
  6214. }
  6215. if (DBTree.m_hPerUserHead == NULL) {
  6216. //
  6217. // Make the first node.
  6218. //
  6219. is.hParent = TVI_ROOT;
  6220. is.hInsertAfter = (DBTree.m_hItemAllInstalled) ? DBTree.m_hItemAllInstalled : DBTree.m_hItemGlobal;
  6221. is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE ;
  6222. is.item.stateMask = TVIS_EXPANDED;
  6223. is.item.pszText = GetString(IDS_PERUSER);
  6224. is.item.iImage = IMAGE_ALLUSERS;
  6225. is.item.iSelectedImage = IMAGE_ALLUSERS;
  6226. DBTree.m_hPerUserHead = TreeView_InsertItem(DBTree.m_hLibraryTree, &is);
  6227. }
  6228. if (dwIndexValue == 0) {
  6229. //
  6230. // First app, we have to create the user icon as well
  6231. //
  6232. is.hParent = DBTree.m_hPerUserHead;
  6233. is.hInsertAfter = TVI_SORT;
  6234. is.item.pszText = szUserName;
  6235. is.item.iImage = IMAGE_SINGLEUSER;
  6236. is.item.iSelectedImage = IMAGE_SINGLEUSER;
  6237. hItemSingleUser = TreeView_InsertItem(DBTree.m_hLibraryTree, &is);
  6238. }
  6239. //
  6240. // Now add the app for the user.
  6241. //
  6242. is.hInsertAfter = TVI_SORT;
  6243. is.hParent = hItemSingleUser;
  6244. is.item.pszText = szValueName;
  6245. is.item.iImage = IMAGE_SINGLEAPP;
  6246. is.item.iSelectedImage = IMAGE_SINGLEAPP;
  6247. hItemApp = TreeView_InsertItem(DBTree.m_hLibraryTree, &is);
  6248. //
  6249. // Now we have to add all the layers for this app.
  6250. //
  6251. is.hParent = hItemApp;
  6252. is.item.iImage = IMAGE_LAYERS;
  6253. is.item.iSelectedImage = IMAGE_LAYERS;
  6254. LPCTSTR pszLayerName = NULL;
  6255. //
  6256. // Get the individual mode names that have been applied to the app (BO)
  6257. //
  6258. pszLayerName = _tcstok(pszData, TEXT(" "));
  6259. while (pszLayerName) {
  6260. PLAYER_FIX plf = (PLAYER_FIX)FindFix(pszLayerName,
  6261. FIX_LAYER,
  6262. &GlobalDataBase);
  6263. if (plf) {
  6264. is.item.pszText = plf->strName.pszString;
  6265. TreeView_InsertItem(DBTree.m_hLibraryTree, &is);
  6266. }
  6267. pszLayerName = _tcstok(NULL, TEXT(" "));
  6268. }
  6269. ++dwIndexValue;
  6270. if (pszData) {
  6271. delete[] pszData;
  6272. pszData = NULL;
  6273. }
  6274. }
  6275. REGCLOSEKEY(hKey);
  6276. //
  6277. // We might come here if we had some error and we break off the while loop
  6278. //
  6279. if (pszData) {
  6280. delete[] pszData;
  6281. pszData = NULL;
  6282. }
  6283. }
  6284. }
  6285. SendMessage(DBTree.m_hLibraryTree, WM_SETREDRAW, TRUE, 0);
  6286. return;
  6287. }
  6288. INT_PTR
  6289. CALLBACK
  6290. MsgBoxDlgProc(
  6291. IN HWND hdlg,
  6292. IN UINT uMsg,
  6293. IN WPARAM wParam,
  6294. IN LPARAM lParam
  6295. )
  6296. /*++
  6297. MsgBoxDlgProc
  6298. Desc: Displays a message box dialog so we can use the hyperlink.
  6299. Params: Standard dialog handler parameters
  6300. IN HWND hDlg
  6301. IN UINT uMsg
  6302. IN WPARAM wParam
  6303. IN LPARAM lParam
  6304. Return: Standard dialog handler return
  6305. --*/
  6306. {
  6307. int wCode = LOWORD(wParam);
  6308. int wNotifyCode = HIWORD(wParam);
  6309. switch (uMsg) {
  6310. case WM_INITDIALOG:
  6311. {
  6312. TCHAR szLink[MAX_PATH];
  6313. UINT uNoSDB;
  6314. uNoSDB = (UINT)lParam;
  6315. //
  6316. // Use the parameter to determine what text to display.
  6317. //
  6318. if (uNoSDB) {
  6319. LoadString(g_hInstance, IDS_W2K_NO_SDB, szLink, ARRAYSIZE(szLink));
  6320. SetDlgItemText(hdlg, IDC_MESSAGE, szLink);
  6321. } else {
  6322. LoadString(g_hInstance, IDS_SP2_SDB, szLink, ARRAYSIZE(szLink));
  6323. SetDlgItemText(hdlg, IDC_MESSAGE, szLink);
  6324. }
  6325. LoadString(g_hInstance, IDS_MSG_LINK, szLink, ARRAYSIZE(szLink));
  6326. SetDlgItemText(hdlg, IDC_MSG_LINK, szLink);
  6327. ShowWindow(hdlg, SW_SHOWNORMAL);
  6328. break;
  6329. }
  6330. case WM_NOTIFY:
  6331. {
  6332. NMHDR* pHdr = (NMHDR*)lParam;
  6333. if (pHdr->idFrom == IDC_MSG_LINK) {
  6334. if (pHdr->code == NM_CLICK || pHdr->code == NM_RETURN) {
  6335. SHELLEXECUTEINFO sei = { 0 };
  6336. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  6337. sei.fMask = SEE_MASK_DOENVSUBST;
  6338. sei.hwnd = hdlg;
  6339. sei.nShow = SW_SHOWNORMAL;
  6340. sei.lpFile = g_szW2KUrl;
  6341. ShellExecuteEx(&sei);
  6342. }
  6343. }
  6344. break;
  6345. }
  6346. case WM_COMMAND:
  6347. switch (wCode) {
  6348. case IDCANCEL:
  6349. EndDialog(hdlg, FALSE);
  6350. break;
  6351. case ID_UPDATE:
  6352. {
  6353. SHELLEXECUTEINFO sei = { 0 };
  6354. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  6355. sei.fMask = SEE_MASK_DOENVSUBST;
  6356. sei.hwnd = NULL;
  6357. sei.nShow = SW_SHOWNORMAL;
  6358. sei.lpFile = g_szW2KUrl;
  6359. ShellExecuteEx(&sei);
  6360. EndDialog(hdlg, TRUE);
  6361. }
  6362. break;
  6363. default:
  6364. return FALSE;
  6365. }
  6366. break;
  6367. default:
  6368. return FALSE;
  6369. }
  6370. return TRUE;
  6371. }
  6372. BOOL
  6373. CheckProperSP(
  6374. void
  6375. )
  6376. /*++
  6377. CheckProperSP
  6378. Returns:
  6379. TRUE: If the service pack is more than two
  6380. FALSE: Otherwise
  6381. --*/
  6382. {
  6383. if (g_fSPGreaterThan2) {
  6384. return TRUE;
  6385. }
  6386. return FALSE;
  6387. }
  6388. void
  6389. CopyToClipBoard(
  6390. IN WPARAM wCode
  6391. )
  6392. /*++
  6393. CopyToClipBoard
  6394. Desc: Copies data into our Clipboard data structure. (Not the windows clipboard)
  6395. Params:
  6396. IN WPARAMS wCode:
  6397. One of:
  6398. ID_EDIT_CUT: This is a cut
  6399. ID_EDIT_COPY: This is a copy
  6400. --*/
  6401. {
  6402. TCHAR szBuffer[256];
  6403. TYPE type;
  6404. HGLOBAL hGlobal = NULL;
  6405. HWND hwndFocus = GetFocus();
  6406. LPARAM lParam = NULL;
  6407. TCHAR* pszGlobal = NULL;
  6408. CopyStruct* pCopyTemp = NULL;
  6409. HTREEITEM hItem;
  6410. TVITEM Item;
  6411. SIZE_T chBuffersize;
  6412. *szBuffer = 0;
  6413. gClipBoard.RemoveAll();
  6414. g_bIsCut = (wCode == ID_EDIT_CUT);
  6415. gClipBoard.pDataBase = g_pPresentDataBase;
  6416. if (hwndFocus == g_hwndEntryTree || hwndFocus == DBTree.m_hLibraryTree) {
  6417. //
  6418. // Copy/Cut is on some tree.
  6419. //
  6420. pCopyTemp= new CopyStruct;
  6421. if (pCopyTemp == NULL) {
  6422. MEM_ERR;
  6423. goto End;
  6424. }
  6425. hItem = TreeView_GetSelection(hwndFocus);
  6426. Item.mask = TVIF_PARAM | TVIF_TEXT;
  6427. Item.pszText = szBuffer;
  6428. Item.cchTextMax = ARRAYSIZE(szBuffer);
  6429. Item.hItem = hItem;
  6430. if (!TreeView_GetItem(hwndFocus, &Item) || Item.lParam == NULL) {
  6431. assert(FALSE);
  6432. if (pCopyTemp) {
  6433. delete pCopyTemp;
  6434. pCopyTemp = NULL;
  6435. }
  6436. goto End;
  6437. }
  6438. lParam = Item.lParam;
  6439. //
  6440. // Copy text to Windows clipboard
  6441. //
  6442. chBuffersize = ARRAYSIZE(szBuffer);
  6443. hGlobal = GlobalAlloc(GHND | GMEM_SHARE, chBuffersize * sizeof(TCHAR));
  6444. if (hGlobal) {
  6445. pszGlobal = (TCHAR*)GlobalLock(hGlobal);
  6446. SafeCpyN(pszGlobal, szBuffer, chBuffersize);
  6447. }
  6448. GlobalUnlock(hGlobal);
  6449. if (OpenClipboard(g_hDlg)) {
  6450. EmptyClipboard();
  6451. SetClipboardData(CF_UNICODETEXT, hGlobal);
  6452. CloseClipboard();
  6453. }
  6454. //
  6455. // Now copy the data to our own clipboard, which is nothing but a linked list
  6456. //
  6457. type = GetItemType(hwndFocus, hItem);
  6458. gClipBoard.type = type;
  6459. //
  6460. // Set the source type. This will indicate on which control out copy-cut operation
  6461. // took place
  6462. //
  6463. if (hwndFocus == g_hwndEntryTree) {
  6464. gClipBoard.SourceType = ENTRY_TREE;
  6465. } else if(hwndFocus == DBTree.m_hLibraryTree) {
  6466. gClipBoard.SourceType = LIB_TREE;
  6467. }
  6468. pCopyTemp->hItem = hItem;
  6469. pCopyTemp->lpData = (LPVOID)lParam;
  6470. gClipBoard.Add(pCopyTemp);
  6471. } else if (hwndFocus == g_hwndContentsList) {
  6472. //
  6473. // We can have multiple selects here.
  6474. //
  6475. gClipBoard.SourceType = ENTRY_LIST;
  6476. //
  6477. // Get the type of the items for the content list at the moment.
  6478. //
  6479. LVITEM lvItem;
  6480. lvItem.mask = LVIF_PARAM;
  6481. lvItem.iItem = 0;
  6482. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  6483. assert(FALSE);
  6484. goto End;
  6485. }
  6486. assert(lvItem.lParam);
  6487. if (lvItem.lParam > TYPE_NULL) {
  6488. PDS_TYPE pdsType = (PDS_TYPE)lvItem.lParam;
  6489. type = pdsType->type;
  6490. } else {
  6491. type = (TYPE)lvItem.lParam;
  6492. }
  6493. gClipBoard.type = type;
  6494. UINT uSelectedCount = ListView_GetSelectedCount(g_hwndContentsList);
  6495. INT iTotalCount = ListView_GetItemCount(g_hwndContentsList);
  6496. INT iIndex = 0;
  6497. UINT uState = 0;
  6498. LONG lSizeofClipboard = 0;
  6499. HTREEITEM hParent; // This will be either the AllApps item or the AllLayers Item
  6500. CSTRINGLIST strlListContents;
  6501. lvItem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
  6502. lvItem.stateMask = LVIS_SELECTED;
  6503. for (UINT uFoundSelected = 1;
  6504. iIndex < iTotalCount && uFoundSelected <= uSelectedCount;
  6505. iIndex++) {
  6506. *szBuffer = 0;
  6507. lvItem.iItem = iIndex;
  6508. lvItem.iSubItem = 0;
  6509. lvItem.pszText = szBuffer;
  6510. lvItem.cchTextMax = ARRAYSIZE(szBuffer) - ARRAYSIZE(STR_NEW_LINE_CHARS);
  6511. if(!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  6512. assert(FALSE);
  6513. continue;
  6514. }
  6515. if (lvItem.state & LVIS_SELECTED) {
  6516. pCopyTemp = new CopyStruct;
  6517. if (pCopyTemp == NULL) {
  6518. MEM_ERR;
  6519. goto End;
  6520. }
  6521. INT iItemLength = lstrlen(szBuffer);
  6522. //
  6523. // See below: + 2 for the TEXT("\r\n") characters. Note that we are
  6524. // adding 2 because lSizeofClipboard represents the number of
  6525. // characters and not the size.
  6526. // Do NOT change this to sizeof(TCHAR)
  6527. //
  6528. lSizeofClipboard += iItemLength + 2;
  6529. if (((ARRAYSIZE(szBuffer) - 1) - iItemLength) >= (ARRAYSIZE(STR_NEW_LINE_CHARS) - 1)) {
  6530. //
  6531. // Make sure we have sufficient space
  6532. //
  6533. SafeCpyN(szBuffer + iItemLength, STR_NEW_LINE_CHARS, ARRAYSIZE(szBuffer) - iItemLength);
  6534. } else {
  6535. assert(FALSE);
  6536. }
  6537. strlListContents.AddString(szBuffer);
  6538. if (type == TYPE_ENTRY) {
  6539. hParent = g_pPresentDataBase->hItemAllApps;
  6540. } else if (type == FIX_LAYER) {
  6541. hParent = g_pPresentDataBase->hItemAllLayers;
  6542. } else if (type == FIX_SHIM || type == FIX_FLAG) {
  6543. hParent = DBTree.FindChild(g_pPresentDataBase->hItemDB,
  6544. TYPE_GUI_SHIMS);
  6545. } else {
  6546. assert(FALSE);
  6547. }
  6548. pCopyTemp->hItem = DBTree.FindChild(hParent, lvItem.lParam);
  6549. pCopyTemp->lpData = (LPVOID)lvItem.lParam;
  6550. gClipBoard.Add(pCopyTemp);
  6551. uFoundSelected++;
  6552. }
  6553. }
  6554. //
  6555. // Copy text to the Windows clipboard
  6556. //
  6557. if (lSizeofClipboard) {
  6558. chBuffersize = lSizeofClipboard + 1; // The last + 1 for the last NULL character
  6559. hGlobal = GlobalAlloc(GHND | GMEM_SHARE, chBuffersize * sizeof(TCHAR));
  6560. if (hGlobal) {
  6561. pszGlobal = (TCHAR*)GlobalLock(hGlobal);
  6562. if (pszGlobal == NULL) {
  6563. assert(FALSE);
  6564. goto End;
  6565. }
  6566. PSTRLIST pHead = strlListContents.m_pHead;
  6567. *pszGlobal = 0;
  6568. while (pHead) {
  6569. StringCchCat(pszGlobal, chBuffersize, pHead->szStr.pszString );
  6570. pHead = pHead->pNext;
  6571. }
  6572. GlobalUnlock(hGlobal);
  6573. if (OpenClipboard(g_hDlg)) {
  6574. EmptyClipboard();
  6575. SetClipboardData(CF_UNICODETEXT, hGlobal);
  6576. CloseClipboard();
  6577. }
  6578. } else {
  6579. assert(FALSE);
  6580. }
  6581. }
  6582. }
  6583. End:;
  6584. }
  6585. void
  6586. PasteFromClipBoard(
  6587. void
  6588. )
  6589. /*++
  6590. PasteFromClipBoard
  6591. Desc: Pastes from our own CLIPBOARD data structure. This routine will also do the cut part. We will
  6592. cut an entry if the entry was cut instead of being copied. Once we have successfully pasted an entry
  6593. at the destination then we proceed with our cut.
  6594. Note: 1. If the source and the dest. databases are same, and the operation involves a cut
  6595. for an application or a layer and the source is the DB tree do nothing
  6596. 2. If the source is the entry tree then we do allow cut for the same database.
  6597. Assumption: Only entries can be copied/cut from the entry tree. If you allow
  6598. non-entries to be copied as well, but do not allow cut for them, it
  6599. will be a mess
  6600. Copy proceeds normally but for cut we have to do something extra. If this
  6601. is a cut operation then when we check for conflicts we will definitely find
  6602. the entry being cut as a conflict (we do not cut the
  6603. entry until after it has been pasted successfully), so we must leave that
  6604. entry when we check for conflicts and we must delete that entry at
  6605. the end of paste.
  6606. Note that cut is not allowed for shims / flags in any case
  6607. --*/
  6608. {
  6609. //
  6610. // If we are doing a cut and the source and the destination databases are the same and
  6611. // the source of the cut is either the db tree or the entry list then there is no need to do a paste
  6612. // But the situation is different if we are doing a cut in the entry tree. Because in this case we
  6613. // should allow users to cut an entry and paste it in a different application. If the user tries to
  6614. // paste in the same application then we do not do anything
  6615. //
  6616. if (g_bIsCut && gClipBoard.pDataBase == g_pPresentDataBase &&
  6617. (gClipBoard.SourceType == LIB_TREE || gClipBoard.SourceType == ENTRY_LIST) &&
  6618. (gClipBoard.type == TYPE_ENTRY
  6619. || gClipBoard.type == TYPE_GUI_APPS
  6620. || gClipBoard.type == TYPE_GUI_LAYERS
  6621. || gClipBoard.type == FIX_LAYER)) {
  6622. return;
  6623. }
  6624. HWND hwndFocus = GetFocus();
  6625. TYPE typeTemp = TYPE_UNKNOWN;
  6626. switch (gClipBoard.type) {
  6627. case TYPE_ENTRY:
  6628. {
  6629. HTREEITEM hItem = NULL;
  6630. if (hwndFocus != g_hwndContentsList) {
  6631. hItem = TreeView_GetSelection(DBTree.m_hLibraryTree);
  6632. } else {
  6633. LVITEM lvItem;
  6634. lvItem.mask = LVIF_PARAM | LVIF_STATE ;
  6635. lvItem.stateMask = LVIS_SELECTED;
  6636. lvItem.iItem = ListView_GetSelectionMark(g_hwndContentsList);
  6637. lvItem.iSubItem = 0;
  6638. if (g_pPresentDataBase == NULL) {
  6639. assert(FALSE);
  6640. break;
  6641. }
  6642. if (ListView_GetItem(g_hwndContentsList, &lvItem) &&
  6643. (lvItem.state & LVIS_SELECTED)) {
  6644. //
  6645. // Check that the selected item is an App
  6646. //
  6647. typeTemp = ConvertLparam2Type(lvItem.lParam);
  6648. if (typeTemp != TYPE_ENTRY) {
  6649. //
  6650. // We needed a entry to be selected in the contents list
  6651. //
  6652. assert(FALSE);
  6653. break;
  6654. }
  6655. hItem = DBTree.FindChild(g_pPresentDataBase->hItemAllApps, lvItem.lParam);
  6656. } else {
  6657. hItem = g_pPresentDataBase->hItemAllApps;
  6658. }
  6659. if (hItem == NULL) {
  6660. assert(FALSE);
  6661. break;
  6662. }
  6663. }
  6664. //
  6665. // We selected an entry from the tree on the right and we have also selected an app on the left.
  6666. // That means we wish to put the selected entry into the selected app on the left.
  6667. // Note that if we have selected some app from the contents list, we find the corresponding
  6668. // tree item in the db tree for that app and proceed as if we had tried to do paste
  6669. // on that tree item
  6670. //
  6671. if (gClipBoard.SourceType == ENTRY_TREE &&
  6672. GetItemType(DBTree.m_hLibraryTree, hItem) == TYPE_ENTRY) {
  6673. LPARAM lParam;
  6674. if(!DBTree.GetLParam(hItem, &lParam)) {
  6675. break;
  6676. }
  6677. //
  6678. // If we are doing a cut and the the destination app is the same as the app of the
  6679. // entry being cut, do nothing
  6680. //
  6681. if (g_bIsCut && (PDBENTRY)lParam == GetAppForEntry(gClipBoard.pDataBase,
  6682. (PDBENTRY)gClipBoard.pClipBoardHead->lpData)) {
  6683. goto End;
  6684. }
  6685. PasteSingleApp((PDBENTRY)gClipBoard.pClipBoardHead->lpData,
  6686. g_pPresentDataBase,
  6687. gClipBoard.pDataBase,
  6688. FALSE,
  6689. ((PDBENTRY)lParam)->strAppName.pszString);
  6690. SendMessage(g_hwndEntryTree, WM_SETREDRAW, TRUE, 0);
  6691. } else if (gClipBoard.SourceType == ENTRY_TREE) {
  6692. //
  6693. // Paste this in the database itself, we do not have any specific app
  6694. // in which we can paste this
  6695. //
  6696. PasteSingleApp((PDBENTRY)gClipBoard.pClipBoardHead->lpData,
  6697. g_pPresentDataBase,
  6698. gClipBoard.pDataBase,
  6699. FALSE);
  6700. SendMessage(g_hwndEntryTree, WM_SETREDRAW, TRUE, 0);
  6701. } else {
  6702. PasteMultipleApps(g_pPresentDataBase);
  6703. SendMessage(g_hwndEntryTree, WM_SETREDRAW, TRUE, 0);
  6704. }
  6705. }
  6706. break;
  6707. case TYPE_GUI_APPS:
  6708. PasteAllApps(g_pPresentDataBase);
  6709. break;
  6710. case FIX_LAYER:
  6711. PasteMultipleLayers(g_pPresentDataBase);
  6712. break;
  6713. case TYPE_GUI_LAYERS:
  6714. PasteAllLayers(g_pPresentDataBase);
  6715. break;
  6716. case FIX_FLAG:
  6717. case FIX_SHIM:
  6718. PasteShimsFlags(g_pPresentDataBase);
  6719. break;
  6720. default: assert(FALSE);
  6721. }
  6722. if (g_bIsCut) {
  6723. //
  6724. // If this routine was called because of a cut, then we do the actual cut here
  6725. //
  6726. CopyStruct* pCopyTemp = gClipBoard.pClipBoardHead;
  6727. CopyStruct* pCopyTempNext = NULL;
  6728. while (pCopyTemp) {
  6729. pCopyTempNext = pCopyTemp->pNext;
  6730. DoTheCut(gClipBoard.pDataBase,
  6731. gClipBoard.type,
  6732. gClipBoard.SourceType,
  6733. pCopyTemp->lpData,
  6734. pCopyTemp->hItem,
  6735. FALSE);
  6736. //
  6737. // NOTE: The gClipBoard.pClipBoardHead might have got changed in ValidateClipboard()
  6738. //
  6739. if (gClipBoard.pClipBoardHead == pCopyTemp) {
  6740. //
  6741. // We were not able to remove this entry, that is cut must have failed.
  6742. // An example situation is when we are trying to cut a layer that is in use by some
  6743. // entry
  6744. //
  6745. break;
  6746. } else {
  6747. pCopyTemp = gClipBoard.pClipBoardHead;
  6748. }
  6749. }
  6750. gClipBoard.pDataBase->bChanged = TRUE;
  6751. //
  6752. // Set the caption only for the tree item
  6753. //
  6754. SetCaption(TRUE, gClipBoard.pDataBase, TRUE);
  6755. gClipBoard.RemoveAll();
  6756. }
  6757. if (!g_pPresentDataBase->bChanged) {
  6758. g_pPresentDataBase->bChanged = TRUE;
  6759. SetCaption();
  6760. }
  6761. if (g_pEntrySelApp && gClipBoard.SourceType == ENTRY_TREE) {
  6762. //
  6763. // We will now try to set focus to the last entry pasted. The focus will
  6764. // be set in the entry tree.
  6765. //
  6766. TreeView_SelectItem(g_hwndEntryTree, g_pEntrySelApp->hItemExe);
  6767. } else if (gClipBoard.SourceType == LIB_TREE) {
  6768. //
  6769. // Select the first entry.
  6770. //
  6771. TreeView_SelectItem(g_hwndEntryTree, TreeView_GetRoot(g_hwndEntryTree));
  6772. }
  6773. //
  6774. // The refresh of the content list is handled in ID_EDIT_PASTE
  6775. //
  6776. End:;
  6777. }
  6778. void
  6779. ListViewSelectAll(
  6780. IN HWND hwndList
  6781. )
  6782. /*++
  6783. ListViewInvertSelection
  6784. Desc: Selects all the items for the list view
  6785. Params:
  6786. IN HWND hwndList: The handle to the list view
  6787. Return:
  6788. void
  6789. --*/
  6790. {
  6791. INT iLastindex = ListView_GetItemCount(hwndList) - 1;
  6792. if (iLastindex > -1) {
  6793. for (iLastindex; iLastindex >= 0; iLastindex--) {
  6794. ListView_SetItemState(g_hwndContentsList,
  6795. iLastindex,
  6796. LVIS_SELECTED,
  6797. LVIS_SELECTED);
  6798. }
  6799. }
  6800. }
  6801. void
  6802. ListViewInvertSelection(
  6803. IN HWND hwndList
  6804. )
  6805. /*++
  6806. ListViewInvertSelection
  6807. Desc: Inverts the selection for the list view
  6808. Params:
  6809. IN HWND hwndList: The handle to the list view
  6810. Return:
  6811. void
  6812. --*/
  6813. {
  6814. INT iLastindex = ListView_GetItemCount(hwndList) - 1;
  6815. if (iLastindex > -1) {
  6816. for (iLastindex; iLastindex >= 0; iLastindex--) {
  6817. UINT uState = ListView_GetItemState(g_hwndContentsList, iLastindex, LVIS_SELECTED);
  6818. (uState == LVIS_SELECTED) ? (uState = 0) : (uState = LVIS_SELECTED);
  6819. ListView_SetItemState(g_hwndContentsList, iLastindex, uState, LVIS_SELECTED);
  6820. }
  6821. }
  6822. }
  6823. BOOL
  6824. DeleteMatchingFile(
  6825. IN OUT PMATCHINGFILE* ppMatchFirst,
  6826. IN PMATCHINGFILE pMatchToDelete,
  6827. IN HWND hwndTree,
  6828. IN HTREEITEM hItem
  6829. )
  6830. /*++
  6831. DeleteMatchingFile
  6832. Desc: Deletes a matching file tree item from the entry tree.
  6833. Params:
  6834. IN OUT PMATCHINGFILE* ppMatchFirst: The address of g_pSelEntry->pFirstMatchingFile
  6835. IN PMATCHINGFILE pMatchToDelete: The matching file that has to be deleted
  6836. IN HWND hwndTree: The handle to the entry tree
  6837. IN HTREEITEM hItem: The matching tree item that has to be deleted
  6838. --*/
  6839. {
  6840. if (ppMatchFirst == NULL || pMatchToDelete == NULL) {
  6841. assert(FALSE);
  6842. Dbg(dlError, "[DeleteMatchingFile] Invalid parameters");
  6843. return FALSE;
  6844. }
  6845. PMATCHINGFILE pMatchTemp = *ppMatchFirst, pMatchPrev = NULL;
  6846. while (NULL != pMatchTemp) {
  6847. if (pMatchTemp == pMatchToDelete) {
  6848. break;
  6849. }
  6850. pMatchPrev = pMatchTemp;
  6851. pMatchTemp = pMatchTemp->pNext;
  6852. }
  6853. if (pMatchTemp == NULL) {
  6854. return FALSE;
  6855. }
  6856. if (pMatchPrev == NULL) {
  6857. //
  6858. //Delete first matching file
  6859. //
  6860. *ppMatchFirst = pMatchTemp->pNext;
  6861. } else {
  6862. pMatchPrev->pNext = pMatchTemp->pNext;
  6863. }
  6864. TreeView_DeleteItem(hwndTree, hItem);
  6865. delete pMatchTemp;
  6866. pMatchTemp = NULL;
  6867. return TRUE;
  6868. }
  6869. BOOL
  6870. CheckInstalled(
  6871. IN PCTSTR pszPath,
  6872. IN PCTSTR pszGUID
  6873. )
  6874. /*++
  6875. CheckInstalled
  6876. Desc: Checks if the database with path szPath and guid szGuid is an installed database
  6877. That is to say that it checks if the file exists in the %windir%AppPatch\Custom
  6878. Directory and has the same file-name as the guid. (Plus a .sdb)
  6879. Params:
  6880. IN PCTSTR szPath: The path of the database that has to be checked
  6881. IN PCTSTR szGUID: The guid of the database
  6882. --*/
  6883. {
  6884. Dbg(dlInfo, "File Name = %S", pszPath);
  6885. TCHAR szDrive[MAX_PATH],
  6886. szDir[MAX_PATH],
  6887. szFile[MAX_PATH];
  6888. CSTRING strAppPatchCustom;
  6889. CSTRING strPath;
  6890. *szDir = *szDrive = *szFile = 0;
  6891. _tsplitpath(pszPath, szDrive, szDir, szFile, NULL);
  6892. strPath = szDrive;
  6893. strPath += szDir;
  6894. if (!strAppPatchCustom.GetSystemWindowsDirectory()) {
  6895. assert(FALSE);
  6896. return FALSE;
  6897. }
  6898. strAppPatchCustom += TEXT("AppPatch\\Custom\\");
  6899. if (strAppPatchCustom == strPath && lstrcmpi(pszGUID, szFile) == 0) {
  6900. return TRUE;
  6901. }
  6902. return FALSE;
  6903. }
  6904. DWORD WINAPI
  6905. ThreadEventKeyNotify(
  6906. LPVOID pVoid
  6907. )
  6908. /*++
  6909. ThreadEventKeyNotify
  6910. Desc: Thread routine that is responsible for automatic updating of the
  6911. Installed databases list and the per user settings list
  6912. Params:
  6913. LPVOID pVoid: Not used
  6914. Return:
  6915. void
  6916. --*/
  6917. {
  6918. DWORD dwInd;
  6919. while (TRUE) {
  6920. #ifdef HELP_BOUND_CHECK
  6921. if (s_bProcessExiting) {
  6922. if (g_hKeyNotify[IND_PERUSER]) {
  6923. REGCLOSEKEY(g_hKeyNotify[IND_PERUSER]);
  6924. }
  6925. if (g_hKeyNotify[IND_ALLUSERS]) {
  6926. REGCLOSEKEY(g_hKeyNotify[IND_ALLUSERS]);
  6927. }
  6928. return 0;
  6929. }
  6930. #endif
  6931. dwInd = WaitForMultipleObjects(2, g_arrhEventNotify, FALSE, INFINITE);
  6932. switch (dwInd) {
  6933. case WAIT_OBJECT_0:
  6934. //
  6935. // We use PostMessage, so that if we get the two events in quick succession
  6936. // we do not mess up our data structures
  6937. //
  6938. PostMessage(g_hDlg, WM_USER_UPDATEPERUSER, 0, 0);
  6939. RegNotifyChangeKeyValue(g_hKeyNotify[IND_PERUSER],
  6940. TRUE,
  6941. REG_NOTIFY_CHANGE_NAME
  6942. | REG_NOTIFY_CHANGE_ATTRIBUTES
  6943. | REG_NOTIFY_CHANGE_LAST_SET,
  6944. g_arrhEventNotify[IND_PERUSER],
  6945. TRUE);
  6946. break;
  6947. case WAIT_OBJECT_0 + 1:
  6948. //
  6949. // We use PostMessage, so that if we get the two events in quick succession
  6950. // we do not mess up our data structures
  6951. //
  6952. PostMessage(g_hDlg, WM_USER_UPDATEINSTALLED, 0, 0);
  6953. RegNotifyChangeKeyValue(g_hKeyNotify[IND_ALLUSERS],
  6954. TRUE,
  6955. REG_NOTIFY_CHANGE_NAME
  6956. | REG_NOTIFY_CHANGE_ATTRIBUTES
  6957. | REG_NOTIFY_CHANGE_LAST_SET,
  6958. g_arrhEventNotify[IND_ALLUSERS],
  6959. TRUE);
  6960. break;
  6961. default:
  6962. break;
  6963. }
  6964. }
  6965. }
  6966. void
  6967. SetStatus(
  6968. IN INT iCode
  6969. )
  6970. /*++
  6971. SetStatus
  6972. Desc: Sets the text for the status control in the main window
  6973. Params:
  6974. IN INT iCode: This is the resource id of the string in the string table that
  6975. has to be displayed in the status control
  6976. Return:
  6977. void
  6978. --*/
  6979. {
  6980. SetWindowText(GetDlgItem(g_hDlg, IDC_STATUSBAR), GetString(iCode));
  6981. }
  6982. void
  6983. SetStatus(
  6984. IN PCTSTR pszMessage
  6985. )
  6986. /*++
  6987. SetStatus
  6988. Desc: Sets the text for the status control in the main window
  6989. Params:
  6990. IN PCTSTR pszMessage: The text that has to be displayed in the status control
  6991. Return:
  6992. void
  6993. --*/
  6994. {
  6995. SetWindowText(GetDlgItem(g_hDlg, IDC_STATUSBAR), pszMessage);
  6996. }
  6997. void
  6998. SetStatus(
  6999. IN HWND hwndStatus,
  7000. IN PCTSTR pszMessage
  7001. )
  7002. /*++
  7003. SetStatus
  7004. Desc: Sets the text for a status control
  7005. Params:
  7006. IN HWND hwndStatus: The handle to the status window
  7007. IN PCTSTR pszMessage: The text that has to be displayed in the status control
  7008. Return:
  7009. void
  7010. --*/
  7011. {
  7012. SetWindowText(hwndStatus, pszMessage);
  7013. }
  7014. void
  7015. SetStatus(
  7016. IN HWND hwndStatus,
  7017. IN INT iCode
  7018. )
  7019. /*++
  7020. SetStatus
  7021. Desc: Sets the text for a status control
  7022. Params:
  7023. IN INT iCode: This is the resource id of the string in the string table that
  7024. has to be displayed in the status control
  7025. Return:
  7026. void
  7027. --*/
  7028. {
  7029. SetWindowText(hwndStatus, GetString(iCode));
  7030. }
  7031. void
  7032. SetStatusDBItems(
  7033. IN HTREEITEM hItem
  7034. )
  7035. /*++
  7036. SetStausDBItems
  7037. Desc: Sets the main window status control, when the user selects some item
  7038. in the db tree(LHS)
  7039. Params:
  7040. IN HTREEITEM hItem: The tree item that the user selected
  7041. Return:
  7042. void
  7043. --*/
  7044. {
  7045. TCHAR szStatus[512];
  7046. TYPE type = GetItemType(DBTree.m_hLibraryTree, hItem);
  7047. UINT uCount = ARRAYSIZE(szStatus);
  7048. switch (type) {
  7049. case TYPE_ENTRY:
  7050. {
  7051. LPARAM lParam;
  7052. if (DBTree.GetLParam(hItem, &lParam)) {
  7053. PDBENTRY pApp = (PDBENTRY)lParam;
  7054. UINT uEntryCount = GetAppEntryCount(pApp);
  7055. *szStatus = 0;
  7056. StringCchPrintf(szStatus,
  7057. uCount,
  7058. GetString(IDS_STA_ENTRYCOUNT),
  7059. pApp->strAppName.pszString,
  7060. uEntryCount);
  7061. SetStatus(szStatus);
  7062. }
  7063. }
  7064. break;
  7065. case FIX_SHIM:
  7066. SetStatus(IDS_STA_SHIM);
  7067. break;
  7068. case TYPE_GUI_COMMANDLINE:
  7069. SetStatus(IDS_STA_COMMANDLINE);
  7070. break;
  7071. case TYPE_GUI_EXCLUDE:
  7072. ShowExcludeStatusMessage(DBTree.m_hLibraryTree, hItem);
  7073. break;
  7074. case TYPE_GUI_INCLUDE:
  7075. ShowIncludeStatusMessage(DBTree.m_hLibraryTree, hItem);
  7076. break;
  7077. case TYPE_GUI_APPS:
  7078. if (g_pPresentDataBase) {
  7079. StringCchPrintf(szStatus,
  7080. uCount,
  7081. GetString(IDS_STA_POPCONTENTS_GUI_APPS),
  7082. g_pPresentDataBase->uAppCount);
  7083. SetStatus(szStatus);
  7084. }
  7085. break;
  7086. case TYPE_GUI_LAYERS:
  7087. if (g_pPresentDataBase) {
  7088. StringCchPrintf(szStatus,
  7089. uCount,
  7090. GetString(IDS_STA_POPCONTENTS_GUI_LAYERS),
  7091. GetLayerCount((LPARAM)g_pPresentDataBase, g_pPresentDataBase->type));
  7092. SetStatus(szStatus);
  7093. }
  7094. break;
  7095. case FIX_LAYER:
  7096. {
  7097. LPARAM lParam;
  7098. PLAYER_FIX plf;
  7099. DBTree.GetLParam(hItem, &lParam);
  7100. plf = (PLAYER_FIX)lParam;
  7101. if (plf) {
  7102. StringCchPrintf(szStatus,
  7103. uCount,
  7104. GetString(IDS_STA_POPCONTENTS_GUI_SHIMS),
  7105. GetShimFlagCount((LPARAM)plf, FIX_LAYER));
  7106. SetStatus(szStatus);
  7107. }
  7108. }
  7109. break;
  7110. case TYPE_GUI_SHIMS:
  7111. if (g_pPresentDataBase) {
  7112. StringCchPrintf(szStatus,
  7113. uCount,
  7114. GetString(IDS_STA_POPCONTENTS_GUI_SHIMS),
  7115. g_pPresentDataBase->uShimCount);
  7116. SetStatus(szStatus);
  7117. }
  7118. break;
  7119. }
  7120. }
  7121. void
  7122. SetStatusStringDBTree(
  7123. IN HTREEITEM hItem
  7124. )
  7125. /*++
  7126. SetStatusStringDBTree
  7127. Desc: Given a hItem from the db tree, determines the status string to be displayed
  7128. in the status control.
  7129. Params:
  7130. IN HTREEITEM hItem: The tree item whose status string we want to display
  7131. --*/
  7132. {
  7133. HWND hwndFocus = GetFocus();
  7134. INT iCode = 0;
  7135. if (hItem == DBTree.m_hItemAllInstalled) {
  7136. iCode = IDS_STA_INSTALLED;
  7137. } else if (hItem == DBTree.m_hItemAllWorking) {
  7138. iCode = IDS_STA_WORKING;
  7139. } else if (hItem == DBTree.m_hPerUserHead) {
  7140. iCode = IDS_STA_PERUSER;
  7141. } else {
  7142. if (g_pPresentDataBase && hItem == g_pPresentDataBase->hItemDB) {
  7143. if (g_pPresentDataBase->type == DATABASE_TYPE_INSTALLED) {
  7144. iCode = IDS_DESC_INSTALLED;
  7145. } else if (g_pPresentDataBase->type == DATABASE_TYPE_WORKING) {
  7146. iCode = IDS_STA_WORKINGDB;
  7147. } else if (g_pPresentDataBase->type == DATABASE_TYPE_GLOBAL) {
  7148. iCode = IDS_SYSDB;
  7149. }
  7150. } else {
  7151. SetStatusDBItems(hItem);
  7152. }
  7153. }
  7154. if (iCode) {
  7155. SetStatus(iCode);
  7156. }
  7157. }
  7158. void
  7159. SetStatusStringEntryTree(
  7160. IN HTREEITEM hItem
  7161. )
  7162. /*++
  7163. SetStatusStringEntryTree
  7164. Desc: Given a hItem from the db tree, determines the status string to be displayed
  7165. in the status control.
  7166. Params:
  7167. IN HTREEITEM hItem: The tree item whose status string we want to display
  7168. --*/
  7169. {
  7170. HWND hwndFocus = GetFocus();
  7171. if (hwndFocus != g_hwndEntryTree) {
  7172. //
  7173. // We can come here if we we selected some item programmatically.
  7174. // But we want to show the status message in the context of the control that
  7175. // is presently selected. So do not put an assert() here.
  7176. //
  7177. return;
  7178. }
  7179. TYPE type = GetItemType(g_hwndEntryTree, hItem);
  7180. TCHAR szStatus[256];
  7181. *szStatus = 0;
  7182. if (g_pSelEntry == NULL) {
  7183. assert(FALSE);
  7184. return;
  7185. }
  7186. switch (type) {
  7187. case TYPE_ENTRY:
  7188. StringCchPrintf(szStatus,
  7189. ARRAYSIZE(szStatus),
  7190. GetString(IDS_STA_TYPE_ENTRY),
  7191. g_pSelEntry->strExeName.pszString,
  7192. g_pSelEntry->strAppName.pszString,
  7193. g_pSelEntry->strVendor.pszString);
  7194. SetStatus(szStatus);
  7195. break;
  7196. case TYPE_APPHELP_ENTRY:
  7197. SetStatus (IDS_STA_TYPE_APPHELP);
  7198. break;
  7199. case FIX_LAYER:
  7200. SetStatus (IDS_STA_FIX_LAYER);
  7201. break;
  7202. case FIX_FLAG:
  7203. case FIX_SHIM:
  7204. SetStatus (IDS_STA_FIX_SHIM);
  7205. break;
  7206. case FIX_PATCH:
  7207. SetStatus (IDS_STA_FIX_PATCH);
  7208. break;
  7209. case TYPE_GUI_PATCHES:
  7210. StringCchPrintf(szStatus,
  7211. ARRAYSIZE(szStatus),
  7212. GetString(IDS_STA_FIX_PATCHES),
  7213. g_pSelEntry->strExeName);
  7214. SetStatus(szStatus);
  7215. break;
  7216. case TYPE_GUI_LAYERS:
  7217. StringCchPrintf(szStatus,
  7218. ARRAYSIZE(szStatus),
  7219. GetString(IDS_STA_FIX_LAYERS),
  7220. g_pSelEntry->strExeName);
  7221. SetStatus(szStatus);
  7222. break;
  7223. case TYPE_GUI_SHIMS:
  7224. StringCchPrintf(szStatus,
  7225. ARRAYSIZE(szStatus),
  7226. GetString(IDS_STA_FIX_SHIMS),
  7227. g_pSelEntry->strExeName);
  7228. SetStatus(szStatus);
  7229. break;
  7230. case TYPE_GUI_MATCHING_FILES:
  7231. StringCchPrintf(szStatus,
  7232. ARRAYSIZE(szStatus),
  7233. GetString(IDS_STA_MATCHINGFILES),
  7234. g_pSelEntry->strExeName);
  7235. SetStatus(szStatus);
  7236. break;
  7237. case TYPE_MATCHING_FILE:
  7238. SetStatus (IDS_STA_MATCHINGFILE);
  7239. break;
  7240. case TYPE_MATCHING_ATTRIBUTE:
  7241. SetStatus(IDS_STA_MATCHINGATTRIBUTE);
  7242. break;
  7243. case TYPE_GUI_EXCLUDE:
  7244. ShowExcludeStatusMessage(g_hwndEntryTree, hItem);
  7245. break;
  7246. case TYPE_GUI_INCLUDE:
  7247. ShowIncludeStatusMessage(g_hwndEntryTree, hItem);
  7248. break;
  7249. case TYPE_GUI_COMMANDLINE:
  7250. SetStatus(IDS_STA_COMMANDLINE);
  7251. break;
  7252. default: SetStatus(TEXT(""));
  7253. }
  7254. }
  7255. void
  7256. OnMoveSplitter(
  7257. IN HWND hdlg,
  7258. IN LPARAM lParam,
  7259. IN BOOL bDoTheDrag,
  7260. IN INT iDiff
  7261. )
  7262. /*++
  7263. OnMoveSplitter
  7264. Desc: May move the vertical split bar (if bDoTheDrag is true),
  7265. iDiff pixels +ve units to the right. Changes the mouse cursor to
  7266. horiz. arrow if it is over the split bar
  7267. Params:
  7268. IN HWND hdlg: The main app window
  7269. IN LPARAM lParam: The mouse position
  7270. IN BOOL bDoTheDrag: Should we move the split bar
  7271. IN INT iDiff: The distance in pixels that the split bar has to
  7272. to be moved. +ve right, -ve left. Relevant only if bDoTheDrag is
  7273. TRUE
  7274. Return:
  7275. void
  7276. --*/
  7277. {
  7278. RECT rectDlg, rectEntryTree, rectDBTree;
  7279. HWND hwndDBTree, hwndEntryTree;
  7280. hwndDBTree = GetDlgItem(hdlg, IDC_LIBRARY);
  7281. GetWindowRect(hwndDBTree, &rectDBTree);
  7282. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectDBTree, 2);
  7283. hwndEntryTree = GetDlgItem(hdlg, IDC_ENTRY);
  7284. GetWindowRect(hwndEntryTree, &rectEntryTree);
  7285. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectEntryTree, 2);
  7286. GetWindowRect(hdlg, &rectDlg);
  7287. int iMX = (int)LOWORD(lParam);
  7288. int iMY = (int)HIWORD(lParam);
  7289. if (iMX > rectDBTree.right && iMX < rectEntryTree.left && iMY > rectDBTree.top && iMY < rectDBTree.bottom) {
  7290. SetCursor(LoadCursor(NULL, IDC_SIZEWE));
  7291. }
  7292. if (bDoTheDrag) {
  7293. int iDlgWidth = rectDlg.right - rectDlg.left;
  7294. //
  7295. // Enforce left and right limit
  7296. //
  7297. if ((rectDBTree.right - rectDBTree.left < 0.20 * iDlgWidth && (iDiff <= 0)) || // Not too much left
  7298. (rectDBTree.right - rectDBTree.left > 0.80 * iDlgWidth && (iDiff >= 0))) { // Not too much right
  7299. return;
  7300. } else if (iMX < iDlgWidth) {
  7301. //
  7302. // Note: We get +ve values when the mouse goes out of the window. -1 becomes 65535
  7303. //
  7304. g_iMousePressedX = iMX;
  7305. RECT rectRedraw;
  7306. SetRect(&rectRedraw, rectDBTree.left, rectDBTree.top, rectEntryTree.right, rectDBTree.bottom);
  7307. InvalidateRect(hdlg, &rectRedraw, TRUE);
  7308. SetRect(&g_rectBar,
  7309. rectDBTree.right + iDiff + 1,
  7310. rectDBTree.top,
  7311. rectEntryTree.left + iDiff - 1,
  7312. rectDBTree.bottom);
  7313. //
  7314. // Move the db tree
  7315. //
  7316. HDWP hdwp = BeginDeferWindowPos(MAIN_WINDOW_CONTROL_COUNT);
  7317. DeferWindowPos(hdwp,
  7318. hwndDBTree,
  7319. NULL,
  7320. rectDBTree.left,
  7321. rectDBTree.top,
  7322. rectDBTree.right - rectDBTree.left + iDiff ,
  7323. rectDBTree.bottom - rectDBTree.top,
  7324. REDRAW_TYPE);
  7325. //
  7326. // Move the exe tree
  7327. //
  7328. DeferWindowPos(hdwp,
  7329. hwndEntryTree,
  7330. NULL,
  7331. rectEntryTree.left + iDiff,
  7332. rectEntryTree.top,
  7333. rectEntryTree.right - rectEntryTree.left - iDiff ,
  7334. rectEntryTree.bottom - rectEntryTree.top,
  7335. REDRAW_TYPE);
  7336. //
  7337. // Move the contents list.
  7338. //
  7339. DeferWindowPos(hdwp,
  7340. GetDlgItem(hdlg, IDC_CONTENTSLIST),
  7341. NULL,
  7342. rectEntryTree.left + iDiff,
  7343. rectEntryTree.top,
  7344. rectEntryTree.right - rectEntryTree.left - iDiff ,
  7345. rectEntryTree.bottom - rectEntryTree.top,
  7346. REDRAW_TYPE);
  7347. //
  7348. // Move the description window.
  7349. //
  7350. if (g_bDescWndOn) {
  7351. HWND hwndDesc;
  7352. RECT rectDesc;
  7353. hwndDesc = GetDlgItem(hdlg, IDC_DESCRIPTION);
  7354. GetWindowRect(hwndDesc, &rectDesc);
  7355. MapWindowPoints(NULL, hdlg, (LPPOINT)&rectDesc, 2);
  7356. DeferWindowPos(hdwp,
  7357. GetDlgItem(hdlg, IDC_DESCRIPTION),
  7358. NULL,
  7359. rectDesc.left + iDiff,
  7360. rectDesc.top,
  7361. rectDesc.right - rectDesc.left - iDiff ,
  7362. 100,
  7363. REDRAW_TYPE);
  7364. InvalidateRect(hwndDesc, NULL, TRUE);
  7365. UpdateWindow(hwndDesc);
  7366. }
  7367. EndDeferWindowPos(hdwp);
  7368. }
  7369. }
  7370. }
  7371. UINT
  7372. GetAppEntryCount(
  7373. IN PDBENTRY pEntry
  7374. )
  7375. /*++
  7376. Desc: Gets the number of entries in an app
  7377. Params:
  7378. IN PDBENTRY pEntry: The pointer to the first entry in the app
  7379. Return: Number of entries which are in same app as pEntry.
  7380. pEntry should point to the first entry in the app.
  7381. --*/
  7382. {
  7383. UINT uCount = 0;
  7384. while (pEntry) {
  7385. ++uCount;
  7386. pEntry = pEntry->pSameAppExe;
  7387. }
  7388. return uCount;
  7389. }
  7390. void
  7391. AddToMRU(
  7392. IN CSTRING& strPath
  7393. )
  7394. /*++
  7395. AddToMRU
  7396. Desc: Adds the file name to the MRU (Most recently used files).
  7397. 1. First of all tries to remove the file from the MRU.
  7398. 2. Then checks if the count in the MRU is equal or greater than the
  7399. MAX_MRU_COUNT.
  7400. a) If yes, then it removes the last from the MRU
  7401. 3. Adds the new file name to the MRU.
  7402. Params:
  7403. IN CSTRING& strPath: The full path of the program that has to be added
  7404. --*/
  7405. {
  7406. assert(g_strlMRU.m_uCount <= MAX_MRU_COUNT);
  7407. g_strlMRU.Remove(strPath);
  7408. if (g_strlMRU.m_uCount >= MAX_MRU_COUNT) {
  7409. g_strlMRU.RemoveLast();
  7410. }
  7411. g_strlMRU.AddStringAtBeg(strPath);
  7412. }
  7413. void
  7414. AddMRUItemsToMenu(
  7415. IN HMENU hMenu,
  7416. IN int iPos
  7417. )
  7418. /*++
  7419. AddMRUItemsToMenu
  7420. Desc: Adds the MRU menus items for the File menu
  7421. Params:
  7422. IN HMENU hMenu: The File top-level menu
  7423. IN int iPos: Position of the menu item before which to insert
  7424. the new item
  7425. Return:
  7426. void
  7427. --*/
  7428. {
  7429. TCHAR szRetPath[MAX_PATH];
  7430. TCHAR* pszMenuString;
  7431. MENUITEMINFO menuItem = {0};
  7432. INT iId = ID_FILE_MRU1, iIndex = 0;
  7433. PSTRLIST pHead = g_strlMRU.m_pHead;
  7434. menuItem.cbSize = sizeof (MENUITEMINFO);
  7435. menuItem.fMask = MIIM_TYPE | MIIM_ID;
  7436. menuItem.fType = MFT_STRING;
  7437. while (pHead) {
  7438. //
  7439. // Now add this to the menuItem.
  7440. //
  7441. *szRetPath = 0;
  7442. pszMenuString = FormatMRUString(pHead->szStr.pszString,
  7443. iIndex + 1,
  7444. szRetPath,
  7445. ARRAYSIZE(szRetPath));
  7446. menuItem.dwTypeData = pszMenuString;
  7447. menuItem.cch = lstrlen(pszMenuString);
  7448. menuItem.wID = iId;
  7449. InsertMenuItem(hMenu,
  7450. iPos,
  7451. TRUE,
  7452. &menuItem);
  7453. ++iId;
  7454. ++iPos;
  7455. ++iIndex;
  7456. pHead = pHead->pNext;
  7457. }
  7458. }
  7459. void
  7460. AddMRUToFileMenu(
  7461. IN HMENU hmenuFile
  7462. )
  7463. /*++
  7464. AddMRUToFileMenu
  7465. Desc: Populates the MRU
  7466. Params:
  7467. IN HMENU hmenuFile: The File top level menu
  7468. --*/
  7469. {
  7470. HKEY hKey = NULL;
  7471. DWORD dwType = REG_SZ;
  7472. MENUITEMINFO minfo = {0};
  7473. INT iPos = 0;
  7474. LONG lResult = 0;
  7475. BOOL bValid = FALSE;
  7476. TCHAR szData[MAX_PATH + 1], szValueName[MAX_PATH + 1];
  7477. DWORD dwchSizeofValueName, dwIndexValue;
  7478. DWORD dwSizeofData;
  7479. g_strlMRU.DeleteAll();
  7480. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  7481. MRU_KEY,
  7482. 0,
  7483. KEY_READ,
  7484. &hKey)) {
  7485. Dbg(dlInfo, "[AddMRUToFileMenu]: No MRU items exist, could not open - Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\CompatAdmin\\MRU");
  7486. return;
  7487. }
  7488. dwIndexValue = 0;
  7489. while (TRUE && iPos < MAX_MRU_COUNT) {
  7490. //
  7491. // Note that the values are not ordered in any particular way !
  7492. //
  7493. dwchSizeofValueName = ARRAYSIZE(szValueName);
  7494. dwSizeofData = sizeof(szData);
  7495. *szData = 0;
  7496. *szValueName = 0;
  7497. lResult = RegEnumValue(hKey,
  7498. dwIndexValue,
  7499. szValueName,
  7500. &dwchSizeofValueName,
  7501. NULL,
  7502. &dwType,
  7503. (LPBYTE)szData,
  7504. &dwSizeofData);
  7505. if (lResult == ERROR_NO_MORE_ITEMS) {
  7506. break;
  7507. }
  7508. if (ERROR_SUCCESS != lResult || dwType != REG_SZ) {
  7509. assert(FALSE);
  7510. break;
  7511. }
  7512. iPos = Atoi(szValueName, &bValid);
  7513. if (iPos >= 0 && bValid) {
  7514. g_strlMRU.AddStringInOrder(szData, iPos);
  7515. } else {
  7516. assert(FALSE);
  7517. }
  7518. ++dwIndexValue;
  7519. }
  7520. //
  7521. // The MRU has been populated, now add these to the "File" menu Item
  7522. //
  7523. if (g_strlMRU.IsEmpty() == FALSE) {
  7524. //
  7525. // Add the separator
  7526. //
  7527. minfo.cbSize = sizeof(MENUITEMINFO);
  7528. minfo.fMask = MIIM_TYPE;
  7529. minfo.fType = MFT_SEPARATOR;
  7530. INT iPosSeparator = GetMenuItemCount(hmenuFile) - 2; // -1 for the exit menu and -1 for the separator above it
  7531. InsertMenuItem(hmenuFile,
  7532. iPosSeparator,
  7533. TRUE,
  7534. &minfo);
  7535. AddMRUItemsToMenu(hmenuFile, iPosSeparator + 1);
  7536. }
  7537. if (hKey) {
  7538. REGCLOSEKEY(hKey);
  7539. }
  7540. }
  7541. TCHAR*
  7542. FormatMRUString(
  7543. IN PCTSTR pszPath,
  7544. IN INT iIndex,
  7545. OUT PTSTR pszRetPath,
  7546. IN UINT cchRetPath
  7547. )
  7548. /*++
  7549. Desc: Formats szPath so that we can show it as a menu item in Files
  7550. Max. length of the returned string is MAX_LENGTH_MRU_MENUITEM
  7551. Params: IN PCTSTR pszPath: The complete path of the .sdb file
  7552. IN INT iIndex: The index of this MRU item. This will also serve
  7553. as the short-cut key. First MRU item will have index as 1 and number of
  7554. mru items is limited by MAX_MRU_COUNT
  7555. OUT PTSTR pzRetPath: This will have the formatted string
  7556. IN UINT cchRetPath: Number of chars that can be stored in cchRetpath.
  7557. This will include the NULL char as well.
  7558. To be safe it should be greater than 128
  7559. Return: Fills up pszPath with the formatted file name and returns a pointer to it
  7560. --*/
  7561. {
  7562. assert(cchRetPath > 128);
  7563. if (pszRetPath) {
  7564. *pszRetPath = 0;
  7565. } else {
  7566. assert(FALSE);
  7567. return TEXT("");
  7568. }
  7569. if (iIndex < 1 || iIndex > MAX_MRU_COUNT) {
  7570. assert(FALSE);
  7571. return TEXT("");
  7572. }
  7573. TCHAR szResult[MAX_PATH * 2],
  7574. szDir[MAX_PATH],
  7575. szFileName[MAX_PATH],
  7576. szExt[MAX_PATH];
  7577. szResult[0] = TEXT('&');
  7578. //
  7579. // We have already checked that iIndex is a valid +ve integer and is within proper bounds
  7580. //
  7581. _itot(iIndex, szResult + 1, 10);
  7582. StringCchCat(szResult, ARRAYSIZE(szResult), TEXT(" "));
  7583. if (lstrlen(pszPath) <= MAX_LENGTH_MRU_MENUITEM) {
  7584. StringCchCat(szResult, ARRAYSIZE(szResult), pszPath);
  7585. goto End;
  7586. }
  7587. _tsplitpath(pszPath,
  7588. szResult + lstrlen(szResult),
  7589. szDir,
  7590. szFileName,
  7591. szExt);
  7592. //
  7593. // Now for the directory. Start from the front and add MAX_DIR_SHOW chars to szResult.
  7594. //
  7595. _tcsncat(szResult, szDir, MAX_DIR_SHOW);
  7596. if (lstrlen(szDir) > MAX_DIR_SHOW) {
  7597. StringCchCat(szResult, ARRAYSIZE(szResult), TEXT("...\\"));
  7598. }
  7599. //
  7600. // For the file-name get the first MAX_FILE_SHOW chars and then append ... to the file name, after that put the .SDB
  7601. //
  7602. _tcsncat(szResult, szFileName, MAX_FILE_SHOW);
  7603. if (lstrlen(szFileName) <= MAX_FILE_SHOW) {
  7604. StringCchCat(szResult, ARRAYSIZE(szResult), szExt);
  7605. } else {
  7606. StringCchCat(szResult, ARRAYSIZE(szResult), TEXT("..."));
  7607. }
  7608. End:
  7609. SafeCpyN(pszRetPath, szResult, cchRetPath);
  7610. return pszRetPath;
  7611. }
  7612. void
  7613. RefreshMRUMenu(
  7614. void
  7615. )
  7616. /*++
  7617. RefreshMRUMenu
  7618. Desc: Refreshes the "File" menu contents (the MRU), this is called when we
  7619. open a new database or save, save as an existing one.
  7620. --*/
  7621. {
  7622. HMENU hMenu = GetMenu(g_hDlg);
  7623. MENUITEMINFO minfo = {0};
  7624. //
  7625. // Get the file menu
  7626. //
  7627. hMenu = GetSubMenu(hMenu, 0);
  7628. //
  7629. // Delete all the MRU items from the menu
  7630. //
  7631. for (UINT uCount = 0; uCount < g_strlMRU.m_uCount; ++uCount) {
  7632. DeleteMenu(hMenu, ID_FILE_MRU1 + uCount, MF_BYCOMMAND);
  7633. }
  7634. INT iItemCount = GetMenuItemCount(hMenu);
  7635. //
  7636. // Check if the separator for the top of the MRU list exists or not, if not add it
  7637. //
  7638. minfo.cbSize = sizeof(minfo);
  7639. minfo.fMask = MIIM_TYPE;
  7640. if (GetMenuItemID(hMenu, iItemCount - 3) == ID_FILE_PROPERTIES) {
  7641. //
  7642. // There was no MRU file in the MRU menu, so we have to add the separator
  7643. //
  7644. minfo.fType = MFT_SEPARATOR;
  7645. InsertMenuItem(hMenu,
  7646. iItemCount - 2, // Before the sep. of the Exit menu
  7647. TRUE,
  7648. &minfo);
  7649. ++iItemCount;
  7650. }
  7651. AddMRUItemsToMenu(hMenu, iItemCount - 2); // -1 for the EXIT, -1 for the separator above that
  7652. DrawMenuBar(g_hDlg);
  7653. }
  7654. BOOL
  7655. LoadDataBase(
  7656. IN TCHAR* szPath
  7657. )
  7658. /*++
  7659. LoadDataBase
  7660. Desc: Load the database file with szPath as its path
  7661. Params:
  7662. IN TCHAR* szPath: Path of the database to be loaded
  7663. Return:
  7664. FALSE: If the database could not be loadd
  7665. TRUE: False otherwise
  7666. --*/
  7667. {
  7668. PDATABASE pOldPresentDatabase = NULL;
  7669. PDATABASE pDataBase = new DATABASE(DATABASE_TYPE_WORKING);
  7670. if (pDataBase == NULL) {
  7671. MEM_ERR;
  7672. return FALSE;
  7673. }
  7674. //
  7675. // NOTE: If GetDatabaseEntries() returns succeeds then it set the g_pPresentDataBase to pDataBase,
  7676. // so after it returns successfully, the g_pPresentDataBase is changed.
  7677. //
  7678. pOldPresentDatabase = g_pPresentDataBase;
  7679. BOOL bReturn = GetDatabaseEntries(szPath, pDataBase);
  7680. g_pPresentDataBase = pOldPresentDatabase;
  7681. if (!bReturn) {
  7682. delete pDataBase;
  7683. return FALSE;
  7684. }
  7685. if (!DBTree.AddWorking(pDataBase)) {
  7686. delete pDataBase;
  7687. return FALSE;
  7688. }
  7689. pDataBase->bChanged = FALSE;
  7690. return TRUE;
  7691. }
  7692. BOOL
  7693. AddRegistryKeys(
  7694. void
  7695. )
  7696. /*++
  7697. AddRegistryKeys
  7698. Desc: Adds the necessary registry keys so that we can listen on them.
  7699. If they are not there, we cannot listen on them and update the
  7700. list of all installed databases and the per-user settings
  7701. Return:
  7702. void
  7703. --*/
  7704. {
  7705. HKEY hKey = NULL, hKeySub = NULL;
  7706. DWORD dwDisposition;
  7707. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  7708. KEY_BASE,
  7709. 0,
  7710. KEY_ALL_ACCESS,
  7711. &hKey)) {
  7712. assert(FALSE);
  7713. return FALSE;
  7714. }
  7715. if (ERROR_SUCCESS != RegCreateKeyEx(hKey,
  7716. TEXT("AppCompatFlags"),
  7717. 0,
  7718. NULL,
  7719. REG_OPTION_NON_VOLATILE,
  7720. KEY_ALL_ACCESS,
  7721. NULL,
  7722. &hKeySub,
  7723. &dwDisposition)) {
  7724. REGCLOSEKEY(hKey);
  7725. return FALSE;
  7726. }
  7727. REGCLOSEKEY(hKey);
  7728. hKey = hKeySub;
  7729. if (ERROR_SUCCESS != RegCreateKeyEx(hKey,
  7730. TEXT("InstalledSDB"),
  7731. 0,
  7732. NULL,
  7733. REG_OPTION_NON_VOLATILE,
  7734. KEY_ALL_ACCESS,
  7735. NULL,
  7736. &hKeySub,
  7737. &dwDisposition)) {
  7738. REGCLOSEKEY(hKey);
  7739. return FALSE;
  7740. }
  7741. REGCLOSEKEY(hKey);
  7742. REGCLOSEKEY(hKeySub);
  7743. return TRUE;
  7744. }
  7745. void
  7746. SetTBButtonStatus(
  7747. IN HWND hwndTB,
  7748. IN HWND hwndControl
  7749. )
  7750. {
  7751. /*++
  7752. SetTBButtonStatus
  7753. Desc: This routine is called when the selection changes for DB Tree or the
  7754. Entry Tree. This routine enables/disables some of the tool bar buttons as
  7755. deemed necessary.
  7756. Params:
  7757. IN HWND hwndTB: The handle to the tool bar
  7758. IN HWND hwndControl: The control on which the sel change has taken place
  7759. Return:
  7760. void
  7761. --*/
  7762. TYPE typeDB = TYPE_UNKNOWN;
  7763. BOOL bEnable;
  7764. if (hwndControl == DBTree.m_hLibraryTree) {
  7765. if (g_pPresentDataBase) {
  7766. typeDB = g_pPresentDataBase->type;
  7767. }
  7768. bEnable = g_pPresentDataBase && typeDB == DATABASE_TYPE_WORKING;
  7769. //
  7770. // Set the options as for working databases
  7771. //
  7772. EnableToolBarButton(hwndTB, ID_FILE_SAVE, bEnable);
  7773. EnableToolBarButton(hwndTB, ID_DATABASE_CLOSE, bEnable);
  7774. EnableToolBarButton(hwndTB, ID_FIX_CREATEANAPPLICATIONFIX, bEnable);
  7775. //
  7776. // AppHelp mechanism is not supported in win2k
  7777. //
  7778. EnableToolBarButton(hwndTB,
  7779. ID_FIX_CREATEANEWAPPHELPMESSAGE,
  7780. (g_bWin2K) ? FALSE : bEnable);
  7781. EnableToolBarButton(hwndTB, ID_FIX_CREATENEWLAYER, bEnable);
  7782. bEnable = (g_pSelEntry != NULL);
  7783. EnableToolBarButton(hwndTB, ID_FIX_EXECUTEAPPLICATION, bEnable);
  7784. } else if (hwndControl == g_hwndEntryTree) {
  7785. //
  7786. // Run Program button
  7787. //
  7788. bEnable = (g_pSelEntry != NULL);
  7789. EnableToolBarButton(hwndTB, ID_FIX_EXECUTEAPPLICATION, bEnable);
  7790. }
  7791. }
  7792. void
  7793. ShowToolBarToolTips(
  7794. IN HWND hdlg,
  7795. IN LPARAM lParam
  7796. )
  7797. /*++
  7798. ShowToolBarToolTips
  7799. Desc: Gets the text for the tool bar tool tips
  7800. Params:
  7801. IN HWND hdlg: The main app window
  7802. IN LPARAM lParam: The lParam for WM_NOTIFY
  7803. Return:
  7804. void
  7805. --*/
  7806. {
  7807. LPTOOLTIPTEXT lpttt;
  7808. INT idStringResource = 0;
  7809. lpttt = (LPTOOLTIPTEXT)lParam;
  7810. if (lpttt == NULL) {
  7811. assert(FALSE);
  7812. return;
  7813. }
  7814. lpttt->hinst = g_hInstance;
  7815. //
  7816. // Specify the resource identifier of the descriptive
  7817. // text for the given button.
  7818. //
  7819. switch (lpttt->hdr.idFrom) {
  7820. case ID_FILE_NEW:
  7821. idStringResource = IDS_TB_TT_NEW;
  7822. break;
  7823. case ID_FILE_OPEN:
  7824. idStringResource = IDS_TB_TT_OPEN;
  7825. break;
  7826. case ID_FILE_SAVE:
  7827. idStringResource = IDS_TB_TT_SAVE;
  7828. break;
  7829. case ID_FIX_CREATEANAPPLICATIONFIX:
  7830. idStringResource = IDS_TB_TT_CREATEFIX;
  7831. break;
  7832. case ID_FIX_CREATEANEWAPPHELPMESSAGE:
  7833. idStringResource = IDS_TB_TT_CREATEAPPHELP;
  7834. break;
  7835. case ID_FIX_CREATENEWLAYER:
  7836. idStringResource = IDS_TB_TT_CREATEMODE;
  7837. break;
  7838. case ID_FIX_EXECUTEAPPLICATION:
  7839. idStringResource = IDS_TB_TT_RUN;
  7840. break;
  7841. case ID_TOOLS_SEARCHFORFIXES:
  7842. idStringResource = IDS_TB_TT_SEARCH;
  7843. break;
  7844. case ID_SEARCH_QUERYDATABASE:
  7845. idStringResource = IDS_TB_TT_QUERY;
  7846. break;
  7847. }
  7848. lpttt->lpszText = MAKEINTRESOURCE(idStringResource);
  7849. }
  7850. PSHIM_FIX_LIST
  7851. IsLUARedirectFSPresent(
  7852. IN PDBENTRY pEntry
  7853. )
  7854. /*++
  7855. IsLUARedirectFSPresent
  7856. Desc: Checks if the entry pEntry has LUARedirectFS shim applied to it
  7857. Params:
  7858. IN PDBENTRY pEntry: The entry for which we want to make the check
  7859. Return:
  7860. PSHIM_FIX_LIST for LUARedirectFS: if the entry has LUARedirectFS applied
  7861. NULL: otherwise
  7862. Notes: Because we always add the shims in the LUA layer individually,
  7863. we only check in the shim fix list of this entry.
  7864. --*/
  7865. {
  7866. if (pEntry == NULL) {
  7867. assert(FALSE);
  7868. return NULL;
  7869. }
  7870. PSHIM_FIX_LIST psfl = pEntry->pFirstShim;
  7871. while (psfl) {
  7872. if (psfl->pShimFix->strName == TEXT("LUARedirectFS")) {
  7873. return psfl;
  7874. }
  7875. psfl = psfl->pNext;
  7876. }
  7877. return NULL;
  7878. }
  7879. void
  7880. CreateNewAppHelp(
  7881. void
  7882. )
  7883. /*++
  7884. CreateNewAppHelp
  7885. Desc: Creates a new AppHelp fix. This routine starts up the wizard to do the job
  7886. and if an entry has been created (the user pressed finish button) adds the entry
  7887. into the database
  7888. --*/
  7889. {
  7890. CAppHelpWizard wizAppHelp;
  7891. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  7892. BOOL bReturn = FALSE;
  7893. if (pCurrentSelectedDB == NULL) {
  7894. assert(FALSE);
  7895. return;
  7896. }
  7897. bReturn = wizAppHelp.BeginWizard(g_hDlg, NULL, pCurrentSelectedDB);
  7898. if (bReturn == FALSE) {
  7899. return;
  7900. }
  7901. PDBENTRY pEntry = new DBENTRY;
  7902. if (pEntry == NULL) {
  7903. MEM_ERR;
  7904. return;
  7905. }
  7906. //
  7907. // This will point to the entry that conflicts.
  7908. //
  7909. PDBENTRY pEntryConflict = NULL;
  7910. if (CheckIfConflictingEntry(pCurrentSelectedDB,
  7911. &wizAppHelp.m_Entry,
  7912. NULL,
  7913. &pEntryConflict)) {
  7914. StringCchPrintf(g_szData,
  7915. ARRAYSIZE(g_szData),
  7916. GetString(IDS_CONFLICT_CREATE_EDIT),
  7917. pEntryConflict->strExeName.pszString,
  7918. pEntryConflict->strAppName.pszString);
  7919. if (IDNO == MessageBox(g_hDlg,
  7920. g_szData,
  7921. g_szAppName,
  7922. MB_ICONQUESTION | MB_YESNO)) {
  7923. return;
  7924. }
  7925. }
  7926. //
  7927. // NOTE: "=" is overloaded. Does not modify the pNext member.
  7928. //
  7929. *pEntry = wizAppHelp.m_Entry;
  7930. PDBENTRY pApp;
  7931. BOOL bNew;
  7932. pApp = AddExeInApp(pEntry, &bNew, pCurrentSelectedDB);
  7933. if (bNew == TRUE) {
  7934. //
  7935. // This means that this is going to be a new application. There does not
  7936. // exist anyt app with this name in the database
  7937. //
  7938. pApp = NULL;
  7939. }
  7940. DBTree.AddNewExe(pCurrentSelectedDB, pEntry, pApp);
  7941. if (!pCurrentSelectedDB->bChanged) {
  7942. pCurrentSelectedDB->bChanged = TRUE;
  7943. SetCaption();
  7944. }
  7945. }
  7946. void
  7947. ModifyAppHelp(
  7948. void
  7949. )
  7950. /*++
  7951. ModifyAppHelp
  7952. Desc: Modifies or adds a new apphelp entry for the presently selected
  7953. application fix
  7954. --*/
  7955. {
  7956. PDBENTRY pEntry = g_pSelEntry;
  7957. CAppHelpWizard Wiz;
  7958. PDBENTRY pEntryConflict = NULL;
  7959. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  7960. BOOL bRet = FALSE;
  7961. if (pEntry == NULL || pCurrentSelectedDB == NULL) {
  7962. assert(FALSE);
  7963. return;
  7964. }
  7965. bRet = Wiz.BeginWizard(g_hDlg, pEntry, pCurrentSelectedDB);
  7966. if (bRet) {
  7967. if (CheckIfConflictingEntry(pCurrentSelectedDB,
  7968. &Wiz.m_Entry,
  7969. pEntry,
  7970. &pEntryConflict)) {
  7971. *g_szData = 0;
  7972. StringCchPrintf(g_szData,
  7973. ARRAYSIZE(g_szData),
  7974. GetString(IDS_ENTRYCONFLICT),
  7975. pEntryConflict->strExeName.pszString,
  7976. pEntryConflict->strAppName.pszString);
  7977. if (IDNO == MessageBox(g_hDlg,
  7978. g_szData,
  7979. g_szAppName,
  7980. MB_ICONQUESTION | MB_YESNO)) {
  7981. return;
  7982. }
  7983. }
  7984. //
  7985. // NOTE: "=" is overloaded. Does not modify the pNext member.
  7986. //
  7987. *pEntry = Wiz.m_Entry;
  7988. SetCursor(LoadCursor(NULL, IDC_WAIT));
  7989. UpdateEntryTreeView(g_pEntrySelApp, g_hwndEntryTree);
  7990. SetCursor(LoadCursor(NULL, IDC_ARROW));
  7991. if (!pCurrentSelectedDB->bChanged) {
  7992. pCurrentSelectedDB->bChanged = TRUE;
  7993. SetCaption();
  7994. }
  7995. }
  7996. }
  7997. void
  7998. CreateNewAppFix(
  7999. void
  8000. )
  8001. /*++
  8002. CreateNewAppFix
  8003. Desc: Creates a new application fix.
  8004. --*/
  8005. {
  8006. CShimWizard Wiz;
  8007. BOOL bShouldStartLUAWizard;
  8008. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  8009. BOOL bReturn = FALSE;
  8010. PDBENTRY pEntryConflict = NULL;
  8011. if (pCurrentSelectedDB == NULL) {
  8012. assert(FALSE);
  8013. return;
  8014. }
  8015. bReturn = Wiz.BeginWizard(g_hDlg, NULL, pCurrentSelectedDB, &bShouldStartLUAWizard);
  8016. if (bReturn == FALSE) {
  8017. return;
  8018. }
  8019. if (CheckIfConflictingEntry(pCurrentSelectedDB,
  8020. &Wiz.m_Entry,
  8021. NULL,
  8022. &pEntryConflict)) {
  8023. *g_szData = 0;
  8024. StringCchPrintf(g_szData,
  8025. ARRAYSIZE(g_szData),
  8026. GetString(IDS_CONFLICT_CREATE_EDIT),
  8027. pEntryConflict->strExeName.pszString,
  8028. pEntryConflict->strAppName.pszString);
  8029. if (IDNO == MessageBox(g_hDlg,
  8030. g_szData,
  8031. g_szAppName,
  8032. MB_ICONQUESTION | MB_YESNO)) {
  8033. return;
  8034. }
  8035. }
  8036. PDBENTRY pEntry = new DBENTRY;
  8037. if (pEntry == NULL) {
  8038. MEM_ERR;
  8039. return;
  8040. }
  8041. //
  8042. // "=" is overloaded. Does not modify the pNext member.
  8043. //
  8044. *pEntry = Wiz.m_Entry;
  8045. BOOL bNew;
  8046. PDBENTRY pApp = AddExeInApp(pEntry, &bNew, pCurrentSelectedDB);
  8047. if (bNew == TRUE) {
  8048. pApp = NULL;
  8049. }
  8050. DBTree.AddNewExe(pCurrentSelectedDB, pEntry, pApp);
  8051. if (!pCurrentSelectedDB->bChanged) {
  8052. pCurrentSelectedDB->bChanged = TRUE;
  8053. SetCaption();
  8054. }
  8055. if (bShouldStartLUAWizard) {
  8056. LuaBeginWizard(g_hDlg, pEntry, pCurrentSelectedDB);
  8057. }
  8058. }
  8059. void
  8060. ChangeEnableStatus(
  8061. void
  8062. )
  8063. /*++
  8064. ChangeEnableStatus
  8065. Desc: Toggles the status of the presently selected entry.
  8066. If the entry is disabled, the fixes will no longer be applied to it.
  8067. Notes: No point in calling this function if the user is not an admin
  8068. --*/
  8069. {
  8070. if (g_pSelEntry == NULL) {
  8071. ASSERT(FALSE);
  8072. return;
  8073. }
  8074. BOOL bFlags = !g_pSelEntry->bDisablePerMachine;
  8075. if (SetDisabledStatus(HKEY_LOCAL_MACHINE, g_pSelEntry->szGUID, bFlags)) {
  8076. if (bFlags == FALSE) {
  8077. //
  8078. // We have enabled the fix, we need too flush the cache
  8079. //
  8080. FlushCache();
  8081. }
  8082. g_pSelEntry->bDisablePerMachine = bFlags;
  8083. //
  8084. // Just update the icon
  8085. //
  8086. TVITEM Item;
  8087. Item.mask = TVIF_SELECTEDIMAGE | TVIF_IMAGE;
  8088. Item.hItem = g_pSelEntry->hItemExe;
  8089. if (bFlags) {
  8090. //
  8091. // This is disabled
  8092. //
  8093. Item.iImage = IMAGE_WARNING;
  8094. Item.iSelectedImage = IMAGE_WARNING;
  8095. SetStatus(GetString(IDS_STA_DISABLED));
  8096. } else {
  8097. Item.iImage = LookupFileImage(g_hImageList,
  8098. g_pSelEntry->strExeName,
  8099. IMAGE_APPLICATION,
  8100. g_uImageRedirector,
  8101. ARRAYSIZE(g_uImageRedirector));
  8102. Item.iSelectedImage = Item.iImage;
  8103. SetStatus(GetString(IDS_STA_ENABLED));
  8104. }
  8105. TreeView_SetItem(g_hwndEntryTree, &Item);
  8106. }
  8107. return;
  8108. }
  8109. void
  8110. ModifyAppFix(
  8111. void
  8112. )
  8113. /*++
  8114. ModifyAppFix
  8115. Desc: Modifies the selected entry in the Entry Tree. This routine will either modify the
  8116. app fix or might create a new one if the selected entry had only AppHelp.
  8117. This routine calls the CShimWizard::BeginWizard to do the job
  8118. --*/
  8119. {
  8120. CShimWizard Wiz;
  8121. BOOL bShouldStartLUAWizard;
  8122. PDBENTRY pEntryConflict = NULL;
  8123. PDBENTRY pEntry = g_pSelEntry;
  8124. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  8125. BOOL bRet = FALSE;
  8126. if (g_pSelEntry == NULL || pCurrentSelectedDB == NULL) {
  8127. assert(FALSE);
  8128. return;
  8129. }
  8130. bRet = Wiz.BeginWizard(g_hDlg, pEntry, pCurrentSelectedDB, &bShouldStartLUAWizard);
  8131. if (bRet) {
  8132. if (CheckIfConflictingEntry(pCurrentSelectedDB,
  8133. &Wiz.m_Entry,
  8134. pEntry,
  8135. &pEntryConflict)) {
  8136. *g_szData = 0;
  8137. StringCchPrintf(g_szData,
  8138. ARRAYSIZE(g_szData),
  8139. GetString(IDS_CONFLICT_CREATE_EDIT),
  8140. pEntryConflict->strExeName.pszString,
  8141. pEntryConflict->strAppName.pszString);
  8142. if (IDNO == MessageBox(g_hDlg,
  8143. g_szData,
  8144. g_szAppName,
  8145. MB_ICONQUESTION | MB_YESNO)) {
  8146. return;
  8147. }
  8148. }
  8149. SetCursor(LoadCursor(NULL, IDC_WAIT));
  8150. *pEntry = Wiz.m_Entry;
  8151. UpdateEntryTreeView(g_pEntrySelApp, g_hwndEntryTree);
  8152. SetCursor(LoadCursor(NULL, IDC_ARROW));
  8153. if (!pCurrentSelectedDB->bChanged) {
  8154. pCurrentSelectedDB->bChanged = TRUE;
  8155. SetCaption();
  8156. }
  8157. if (bShouldStartLUAWizard) {
  8158. LuaBeginWizard(g_hDlg, pEntry, pCurrentSelectedDB);
  8159. }
  8160. }
  8161. return;
  8162. }
  8163. void
  8164. CreateNewLayer(
  8165. void
  8166. )
  8167. /*++
  8168. CreateNewLayer
  8169. Desc: Calls CCustomLayer::AddCustomLayer to create a new layer (compatibility mode)
  8170. Calls DBTree.AddNewLayer() to add the new layer to the tree
  8171. --*/
  8172. {
  8173. CCustomLayer CustomLayer;
  8174. HWND hWnd = GetFocus();
  8175. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  8176. PLAYER_FIX plfNew = NULL;
  8177. if (pCurrentSelectedDB == NULL) {
  8178. assert(FALSE);
  8179. return;
  8180. }
  8181. plfNew = new LAYER_FIX(TRUE);
  8182. if (plfNew == NULL) {
  8183. MEM_ERR;
  8184. return;
  8185. }
  8186. if (CustomLayer.AddCustomLayer(plfNew, pCurrentSelectedDB)) {
  8187. //
  8188. // Add this new layer in the datbase.
  8189. //
  8190. plfNew->pNext = pCurrentSelectedDB->pLayerFixes;
  8191. pCurrentSelectedDB->pLayerFixes = plfNew;
  8192. if (!pCurrentSelectedDB->bChanged) {
  8193. pCurrentSelectedDB->bChanged = TRUE;
  8194. SetCaption();
  8195. }
  8196. DBTree.AddNewLayer(pCurrentSelectedDB, plfNew, TRUE);
  8197. } else {
  8198. delete plfNew;
  8199. }
  8200. SetFocus(hWnd);
  8201. }
  8202. void
  8203. OnDelete(
  8204. void
  8205. )
  8206. /*++
  8207. OnDelete
  8208. Desc: Handles the ID_EDIT_DELETE message to delete an entry.
  8209. The entry can be either in the entry-tree, db tree or the contents list.
  8210. --*/
  8211. {
  8212. HWND hwndFocus = GetFocus();
  8213. SOURCE_TYPE srcType;
  8214. HTREEITEM hItem = NULL;
  8215. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  8216. if (pCurrentSelectedDB == NULL) {
  8217. assert(FALSE);
  8218. return;
  8219. }
  8220. if (hwndFocus == DBTree.m_hLibraryTree || hwndFocus == g_hwndEntryTree) {
  8221. hItem = TreeView_GetSelection(hwndFocus);
  8222. TYPE type = (TYPE)GetItemType(hwndFocus, hItem);
  8223. if (hwndFocus == g_hwndEntryTree) {
  8224. srcType = ENTRY_TREE;
  8225. } else {
  8226. srcType = LIB_TREE;
  8227. }
  8228. LPARAM lParam;
  8229. CTree::GetLParam(hwndFocus, hItem, &lParam);
  8230. DoTheCut(pCurrentSelectedDB, type, srcType, (LPVOID)lParam, hItem, TRUE);
  8231. } else {
  8232. //
  8233. // Handle delete for the contents list.
  8234. //
  8235. HTREEITEM hParent = NULL;
  8236. LVITEM lvItem;
  8237. TYPE type;
  8238. lvItem.mask = LVIF_PARAM;
  8239. lvItem.iItem = 0;
  8240. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  8241. assert(FALSE);
  8242. return;
  8243. }
  8244. if (lvItem.lParam > TYPE_NULL) {
  8245. PDS_TYPE pdsType = (PDS_TYPE)lvItem.lParam;
  8246. type = pdsType->type;
  8247. } else {
  8248. type = (TYPE)lvItem.lParam;
  8249. }
  8250. if (type == TYPE_ENTRY) {
  8251. hParent = pCurrentSelectedDB->hItemAllApps;
  8252. } else if (type == FIX_LAYER) {
  8253. hParent = pCurrentSelectedDB->hItemAllLayers;
  8254. } else {
  8255. assert(FALSE);
  8256. return;
  8257. }
  8258. //
  8259. // Get the selected items and then delete them
  8260. //
  8261. UINT uSelectedCount = ListView_GetSelectedCount(g_hwndContentsList);
  8262. INT iLastIndex = ListView_GetItemCount(g_hwndContentsList) - 1;
  8263. lvItem.mask = LVIF_PARAM | LVIF_STATE;
  8264. lvItem.stateMask = LVIS_SELECTED;
  8265. for (UINT uFoundSelected = 1;
  8266. iLastIndex >= 0 && uFoundSelected <= uSelectedCount;
  8267. --iLastIndex) {
  8268. lvItem.iItem = iLastIndex;
  8269. lvItem.iSubItem = 0;
  8270. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  8271. assert(FALSE);
  8272. break;
  8273. }
  8274. if (lvItem.state & LVIS_SELECTED) {
  8275. hItem = DBTree.FindChild(hParent, lvItem.lParam);
  8276. assert(hItem);
  8277. DoTheCut(pCurrentSelectedDB, type, ENTRY_LIST, (LPVOID)lvItem.lParam, hItem, TRUE);
  8278. uFoundSelected++;
  8279. }
  8280. }
  8281. }
  8282. pCurrentSelectedDB->bChanged = TRUE;
  8283. SetCaption(TRUE, pCurrentSelectedDB);
  8284. }
  8285. void
  8286. CreateNewDatabase(
  8287. void
  8288. )
  8289. /*++
  8290. CreateNewDatabase
  8291. Desc: Creates a new database and adds it to the db tree
  8292. calling DBTree.AddWorking()
  8293. --*/
  8294. {
  8295. PDATABASE pDatabaseNew = new DATABASE(DATABASE_TYPE_WORKING);
  8296. if (pDatabaseNew == NULL) {
  8297. MEM_ERR;
  8298. return;
  8299. }
  8300. pDatabaseNew->bChanged = FALSE;
  8301. DataBaseList.Add(pDatabaseNew);
  8302. g_pEntrySelApp = g_pSelEntry = NULL;
  8303. SetCaption();
  8304. ++g_uNextDataBaseIndex;
  8305. //
  8306. // Now update the screen
  8307. //
  8308. DBTree.AddWorking(pDatabaseNew);
  8309. TreeDeleteAll(g_hwndEntryTree);
  8310. SetFocus(DBTree.m_hLibraryTree);
  8311. }
  8312. void
  8313. OnDatabaseClose(
  8314. void
  8315. )
  8316. /*++
  8317. OnDatabaseClose
  8318. Desc: Calls CloseDataBase to close a database.
  8319. This is called on ID_DATABASE_CLOSE message
  8320. --*/
  8321. {
  8322. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  8323. if (pCurrentSelectedDB == NULL) {
  8324. MessageBox(g_hDlg,
  8325. GetString(IDS_CANNOTBECLOSED),
  8326. g_szAppName,
  8327. MB_ICONWARNING);
  8328. return;
  8329. }
  8330. TYPE typeDB = pCurrentSelectedDB->type;
  8331. if (typeDB == DATABASE_TYPE_WORKING) {
  8332. CloseDataBase(pCurrentSelectedDB);
  8333. }
  8334. }
  8335. void
  8336. DatabaseSaveAll(
  8337. void
  8338. )
  8339. /*++
  8340. DatabaseSaveAll
  8341. Desc: Saves all the working databases
  8342. --*/
  8343. {
  8344. PDATABASE g_pOldPresentDataBase = g_pPresentDataBase;
  8345. g_pPresentDataBase = DataBaseList.pDataBaseHead;
  8346. while (g_pPresentDataBase) {
  8347. if (g_pPresentDataBase->bChanged
  8348. || NotCompletePath(g_pPresentDataBase->strPath)) {
  8349. BOOL bReturn = TRUE;
  8350. if (NotCompletePath(g_pPresentDataBase->strPath)) {
  8351. bReturn = SaveDataBaseAs(g_pPresentDataBase);
  8352. } else {
  8353. bReturn = SaveDataBase(g_pPresentDataBase,
  8354. g_pPresentDataBase->strPath);
  8355. }
  8356. if (bReturn == FALSE) {
  8357. CSTRING strMessage;
  8358. strMessage.Sprintf(GetString(IDS_NOTSAVED), g_pPresentDataBase->strName);
  8359. if (g_hDlg && strMessage.pszString) {
  8360. MessageBox(g_hDlg,
  8361. strMessage.pszString,
  8362. g_szAppName,
  8363. MB_ICONWARNING);
  8364. }
  8365. }
  8366. }
  8367. g_pPresentDataBase = g_pPresentDataBase->pNext;
  8368. }
  8369. g_pPresentDataBase = g_pOldPresentDataBase;
  8370. if (g_pPresentDataBase) {
  8371. TreeView_SelectItem(DBTree.m_hLibraryTree, g_pPresentDataBase->hItemDB);
  8372. } else {
  8373. TreeView_SelectItem(DBTree.m_hLibraryTree, DBTree.m_hLibraryTree);
  8374. }
  8375. }
  8376. BOOL
  8377. ModifyLayer(
  8378. void
  8379. )
  8380. /*++
  8381. ModifyLayer
  8382. Desc: Modifies a layer. Calls CustomLayer.EditCustomLayer to do the actual job
  8383. --*/
  8384. {
  8385. CCustomLayer clayer;
  8386. BOOL bOk = FALSE;
  8387. HWND hwndGetFocus = GetFocus();
  8388. PDATABASE pCurrentSelectedDB = GetCurrentDB();
  8389. if (hwndGetFocus == DBTree.m_hLibraryTree) {
  8390. HTREEITEM hSelectedItem = TreeView_GetSelection(hwndGetFocus);
  8391. if (hSelectedItem && GetItemType(DBTree.m_hLibraryTree, hSelectedItem) == FIX_LAYER) {
  8392. LPARAM lParamMode;
  8393. if (DBTree.GetLParam(hSelectedItem, &lParamMode)) {
  8394. bOk = clayer.EditCustomLayer((PLAYER_FIX)lParamMode, pCurrentSelectedDB);
  8395. }
  8396. if (bOk) {
  8397. //
  8398. // We have to refresh all the layers. We have to refresh all the layers
  8399. // Because the UI provides the user the flexibility to edit more than one layer :(
  8400. //
  8401. if (!pCurrentSelectedDB->bChanged) {
  8402. pCurrentSelectedDB->bChanged = TRUE;
  8403. SetCaption();
  8404. }
  8405. DBTree.RefreshAllLayers(pCurrentSelectedDB);
  8406. hSelectedItem = DBTree.FindChild(pCurrentSelectedDB->hItemAllLayers,
  8407. lParamMode);
  8408. TreeView_SelectItem(DBTree.m_hLibraryTree, hSelectedItem);
  8409. SetStatusStringDBTree(hSelectedItem);
  8410. }
  8411. }
  8412. }
  8413. SetFocus(hwndGetFocus);
  8414. return bOk;
  8415. }
  8416. void
  8417. OnRename(
  8418. void
  8419. )
  8420. /*++
  8421. OnRename
  8422. Desc: Processes the ID_EDIT_RENAME message to handle renaming of databases,
  8423. compatibility modes and applications.
  8424. --*/
  8425. {
  8426. HWND hwndFocus = GetFocus();
  8427. INT_PTR iStyle;
  8428. TYPE type;
  8429. if (hwndFocus == DBTree.m_hLibraryTree) {
  8430. HTREEITEM hItemSelected = TreeView_GetSelection(hwndFocus);
  8431. if (hItemSelected == NULL) {
  8432. return;
  8433. }
  8434. iStyle = GetWindowLongPtr(hwndFocus, GWL_STYLE);
  8435. iStyle |= TVS_EDITLABELS;
  8436. SetWindowLongPtr(hwndFocus, GWL_STYLE, iStyle);
  8437. HWND hwndText = NULL;
  8438. type = (TYPE)GetItemType(hwndFocus, hItemSelected);
  8439. switch(type) {
  8440. case TYPE_ENTRY:
  8441. case FIX_LAYER:
  8442. case DATABASE_TYPE_WORKING:
  8443. hwndText = TreeView_EditLabel(hwndFocus, hItemSelected);
  8444. break;
  8445. }
  8446. } else if (hwndFocus == g_hwndContentsList) {
  8447. INT iSelected = ListView_GetSelectionMark(g_hwndContentsList);
  8448. if (iSelected == -1) {
  8449. return;
  8450. }
  8451. iStyle = GetWindowLongPtr(hwndFocus, GWL_STYLE);
  8452. iStyle |= LVS_EDITLABELS;
  8453. SetWindowLongPtr(hwndFocus, GWL_STYLE, iStyle);
  8454. LVITEM lvItem;
  8455. lvItem.mask = LVIF_PARAM;
  8456. lvItem.iItem = iSelected;
  8457. lvItem.iSubItem = 0;
  8458. if(!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  8459. return;
  8460. }
  8461. assert(lvItem.lParam);
  8462. type = (TYPE)ConvertLparam2Type(lvItem.lParam);
  8463. if (type == TYPE_ENTRY || type == FIX_LAYER) {
  8464. ListView_EditLabel(g_hwndContentsList, iSelected);
  8465. }
  8466. }
  8467. }
  8468. INT_PTR
  8469. ShowDBPropertiesDlgProcOnInitDialog(
  8470. IN HWND hdlg,
  8471. IN LPARAM lParam
  8472. )
  8473. /*++
  8474. ShowDBPropertiesDlgProcOnInitDialog
  8475. Desc: Handles the WM_INITDIALOG for the database properties dialog box
  8476. Params:
  8477. IN HWND hdlg: The database properties dialog box
  8478. IN LPARAM lParam: The database pointer whose properties we want to see
  8479. Return:
  8480. TRUE
  8481. --*/
  8482. {
  8483. PDATABASE pDatabase = (PDATABASE)lParam;
  8484. FILETIME localtime;
  8485. SYSTEMTIME systime;
  8486. WIN32_FILE_ATTRIBUTE_DATA attr;
  8487. TCHAR szBuffer[MAX_PATH];
  8488. PDBENTRY pApp;
  8489. PDBENTRY pEntry;
  8490. INT iAppCount = 0;
  8491. INT iEntryCount = 0;
  8492. *szBuffer = 0;
  8493. if (pDatabase == NULL) {
  8494. assert(FALSE);
  8495. goto End;
  8496. }
  8497. //
  8498. // If we are trying to show the properties of the system database, the apps must be
  8499. // loaded first
  8500. //
  8501. if (pDatabase->type == DATABASE_TYPE_GLOBAL && !g_bMainAppExpanded) {
  8502. SetCursor(LoadCursor(NULL, IDC_WAIT));
  8503. INT iResult = ShowMainEntries(hdlg);
  8504. if (iResult == -1) {
  8505. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, TRUE);
  8506. SetStatus(g_hwndStatus, CSTRING(IDS_LOADINGMAIN));
  8507. SetCursor(LoadCursor(NULL, IDC_WAIT));
  8508. } else {
  8509. SetCursor(LoadCursor(NULL, IDC_ARROW));
  8510. }
  8511. }
  8512. //
  8513. // Show the friendly name
  8514. //
  8515. SetDlgItemText(hdlg, IDC_NAME, pDatabase->strName);
  8516. //
  8517. // Show the path
  8518. //
  8519. SetDlgItemText(hdlg, IDC_PATH, pDatabase->strPath);
  8520. //
  8521. // Show the GUID
  8522. //
  8523. SetDlgItemText(hdlg, IDC_GUID, pDatabase->szGUID);
  8524. //
  8525. // Show the various dates: creation, modification and access dates
  8526. //
  8527. if (GetFileAttributesEx(pDatabase->strPath, GetFileExInfoStandard, &attr)) {
  8528. //
  8529. // Creation date-time
  8530. //
  8531. FileTimeToLocalFileTime(&attr.ftCreationTime, &localtime);
  8532. FileTimeToSystemTime(&localtime, &systime);
  8533. FormatDate(&systime, szBuffer, ARRAYSIZE(szBuffer));
  8534. SetDlgItemText(hdlg, IDC_DATE_CREATED, szBuffer);
  8535. //
  8536. // Modification date-time
  8537. //
  8538. FileTimeToLocalFileTime(&attr.ftLastWriteTime, &localtime);
  8539. FileTimeToSystemTime(&localtime, &systime);
  8540. FormatDate(&systime, szBuffer, ARRAYSIZE(szBuffer));
  8541. SetDlgItemText(hdlg, IDC_DATE_MODIFIED, szBuffer);
  8542. //
  8543. // Access date-time
  8544. //
  8545. FileTimeToLocalFileTime(&attr.ftLastAccessTime, &localtime);
  8546. FileTimeToSystemTime(&localtime, &systime);
  8547. FormatDate(&systime, szBuffer, ARRAYSIZE(szBuffer));
  8548. SetDlgItemText(hdlg, IDC_DATE_ACCESSED, szBuffer);
  8549. } else {
  8550. //
  8551. // New database: does not exist on disk.
  8552. //
  8553. SetDlgItemText(hdlg, IDC_DATE_CREATED, GetString(IDS_NOTCREATED));
  8554. SetDlgItemText(hdlg, IDC_DATE_MODIFIED, TEXT(""));
  8555. SetDlgItemText(hdlg, IDC_DATE_ACCESSED, TEXT(""));
  8556. }
  8557. //
  8558. // Get Application count and entry count
  8559. //
  8560. pApp = pDatabase->pEntries;
  8561. while (pApp) {
  8562. ++iAppCount;
  8563. pEntry = pApp;
  8564. while (pEntry) {
  8565. iEntryCount++;
  8566. pEntry = pEntry->pSameAppExe;
  8567. }
  8568. pApp = pApp->pNext;
  8569. }
  8570. //
  8571. // App-Count
  8572. //
  8573. *szBuffer = 0;
  8574. SetDlgItemText(hdlg, IDC_APP_COUNT, _itot(iAppCount, szBuffer, 10));
  8575. //
  8576. // Entry-Count
  8577. //
  8578. *szBuffer = 0;
  8579. SetDlgItemText(hdlg, IDC_ENTRY_COUNT, _itot(iEntryCount, szBuffer, 10));
  8580. //
  8581. // Get the number of custom compatibility modes
  8582. //
  8583. INT iModeCount = 0;
  8584. PLAYER_FIX plf = pDatabase->pLayerFixes;
  8585. while (plf) {
  8586. ++iModeCount;
  8587. plf = plf->pNext;
  8588. }
  8589. //
  8590. // Layer count
  8591. //
  8592. *szBuffer = 0;
  8593. SetDlgItemText(hdlg, IDC_MODE_COUNT, _itot(iModeCount, szBuffer, 10));
  8594. //
  8595. // We need to have protected access because, the installed list data structure
  8596. // might get modified if somebody does a (un)install when we are iterating
  8597. // the list in CheckIfInstalledDB()
  8598. //
  8599. // ********** Warning *****************************************************
  8600. //
  8601. // Do not do EnterCriticalSection(g_csInstalledList) in CheckIfInstalledDB()
  8602. // because CheckIfInstalledDB() is called by Qyery db as well when it tries
  8603. // to evaluate expressions and it might already have done a
  8604. // EnterCriticalSection(g_csInstalledList)
  8605. // and then we will get a deadlock
  8606. //
  8607. // *************************************************************************
  8608. //
  8609. EnterCriticalSection(&g_csInstalledList);
  8610. //
  8611. // Installed
  8612. //
  8613. SetDlgItemText(hdlg,
  8614. IDC_INSTALLED,
  8615. CheckIfInstalledDB(pDatabase->szGUID) ? GetString(IDS_YES):GetString(IDS_NO));
  8616. LeaveCriticalSection(&g_csInstalledList);
  8617. End:
  8618. return TRUE;
  8619. }
  8620. INT_PTR
  8621. CALLBACK
  8622. ShowDBPropertiesDlgProc(
  8623. IN HWND hdlg,
  8624. IN UINT uMsg,
  8625. IN WPARAM wParam,
  8626. IN LPARAM lParam
  8627. )
  8628. /*++
  8629. ShowDBPropertiesDlgProc
  8630. Desc: Shows the properties of the selected database
  8631. Params: Standard dialog handler parameters
  8632. IN HWND hDlg
  8633. IN UINT uMsg
  8634. IN WPARAM wParam
  8635. IN LPARAM lParam: contains the pointer to the selected database
  8636. Return: Standard dialog handler return
  8637. --*/
  8638. {
  8639. int wCode = LOWORD(wParam);
  8640. int wNotifyCode = HIWORD(wParam);
  8641. switch (uMsg) {
  8642. case WM_INITDIALOG:
  8643. ShowDBPropertiesDlgProcOnInitDialog(hdlg, lParam);
  8644. break;
  8645. case WM_COMMAND:
  8646. {
  8647. switch (wCode) {
  8648. case IDOK:
  8649. case IDCANCEL:
  8650. EndDialog(hdlg, TRUE);
  8651. break;
  8652. default: return FALSE;
  8653. }
  8654. break;
  8655. }
  8656. default: return FALSE;
  8657. }
  8658. return TRUE;
  8659. }
  8660. INT_PTR
  8661. CALLBACK
  8662. EventDlgProc(
  8663. IN HWND hdlg,
  8664. IN UINT uMsg,
  8665. IN WPARAM wParam,
  8666. IN LPARAM lParam
  8667. )
  8668. /*++
  8669. Desc: Dialog Proc for the events dialog.
  8670. Params: Standard dialog handler parameters
  8671. IN HWND hDlg
  8672. IN UINT uMsg
  8673. IN WPARAM wParam
  8674. IN LPARAM lParam
  8675. Return: Standard dialog handler return
  8676. --*/
  8677. {
  8678. int wCode = LOWORD(wParam);
  8679. int wNotifyCode = HIWORD(wParam);
  8680. switch (uMsg) {
  8681. case WM_INITDIALOG:
  8682. {
  8683. g_hwndEventsWnd = hdlg;
  8684. HWND hwndEventsList = GetDlgItem(g_hwndEventsWnd, IDC_LIST);
  8685. g_iEventCount = 0;
  8686. ListView_SetImageList(hwndEventsList, g_hImageList, LVSIL_SMALL);
  8687. ListView_SetExtendedListViewStyleEx(hwndEventsList,
  8688. 0,
  8689. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
  8690. InsertColumnIntoListView(hwndEventsList,
  8691. GetString(IDS_EVENT_COL_TIME),
  8692. EVENTS_COLUMN_TIME,
  8693. 30);
  8694. InsertColumnIntoListView(hwndEventsList,
  8695. GetString(IDS_EVENT_COL_MSG),
  8696. EVENTS_COLUMN_MSG,
  8697. 70);
  8698. ListView_SetColumnWidth(hwndEventsList, 1, LVSCW_AUTOSIZE_USEHEADER);
  8699. RECT r;
  8700. GetWindowRect(hdlg, &r);
  8701. s_cEventWidth = r.right - r.left;
  8702. s_cEventHeight = r.bottom - r.top;
  8703. //
  8704. // Disable the min/maximize menu in the system window. This is needed because otherwise
  8705. // the user can minimize the events window and if he maximizes and restores the
  8706. // main window, our events window will pop-up.
  8707. //
  8708. // The events window gets popped up if it has been created when we do a restore
  8709. // for the main window
  8710. //
  8711. HMENU hSysmenu = GetSystemMenu(hdlg, FALSE);
  8712. EnableMenuItem(hSysmenu, SC_MINIMIZE, MF_GRAYED);
  8713. EnableMenuItem(hSysmenu, SC_MAXIMIZE, MF_GRAYED);
  8714. SetFocus(hwndEventsList);
  8715. break;
  8716. }
  8717. case WM_SIZE:
  8718. EventsWindowSize(hdlg);
  8719. break;
  8720. case WM_GETMINMAXINFO:
  8721. {
  8722. MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
  8723. pmmi->ptMinTrackSize.x = 300;
  8724. pmmi->ptMinTrackSize.y = 100;
  8725. return 0;
  8726. }
  8727. case WM_COMMAND:
  8728. switch (wCode) {
  8729. case IDCANCEL:
  8730. g_hwndEventsWnd = NULL;
  8731. DestroyWindow(hdlg);
  8732. break;
  8733. default: return FALSE;
  8734. }
  8735. break;
  8736. default: return FALSE;
  8737. }
  8738. return TRUE;
  8739. }
  8740. BOOL
  8741. AppendEvent(
  8742. IN INT iType,
  8743. IN TCHAR* pszTimestamp,
  8744. IN TCHAR* pszMsg,
  8745. IN BOOL bAddToFile // DEF = FALSE
  8746. )
  8747. /*++
  8748. AppendEvent
  8749. Desc: Adds a new description to the events window, if it is visible also opens
  8750. events log file and appends it to that
  8751. Params:
  8752. IN INT iType: The type of the event.
  8753. One of: EVENT_LAYER_COPYOK
  8754. EVENT_ENTRY_COPYOK
  8755. EVENT_SYSTEM_RENAME
  8756. EVENT_CONFLICT_ENTRY
  8757. IN TCHAR* pszTimestamp: Timestamp when the event occurred
  8758. IN TCHAR* pszMsg: The message to be displayed
  8759. IN BOOL bAddToFile(FALSE): Whether we want to append the event to the log file
  8760. As of now always FALSE
  8761. --*/
  8762. {
  8763. TCHAR szTime[256];
  8764. LVITEM lvi;
  8765. INT iIndex = -1;
  8766. ZeroMemory(&lvi, sizeof(lvi));
  8767. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  8768. if (pszTimestamp == NULL) {
  8769. //
  8770. // Get the time
  8771. //
  8772. SYSTEMTIME st;
  8773. GetLocalTime(&st);
  8774. *szTime = 0;
  8775. FormatDate(&st, szTime, ARRAYSIZE(szTime));
  8776. pszTimestamp = szTime;
  8777. }
  8778. if (g_hwndEventsWnd) {
  8779. HWND hwndEventsList = GetDlgItem(g_hwndEventsWnd, IDC_LIST);
  8780. switch (iType) {
  8781. case EVENT_LAYER_COPYOK:
  8782. case EVENT_ENTRY_COPYOK:
  8783. lvi.iImage = IMAGE_EVENT_INFO;
  8784. break;
  8785. case EVENT_SYSTEM_RENAME:
  8786. lvi.iImage = IMAGE_EVENT_WARNING;
  8787. break;
  8788. case EVENT_CONFLICT_ENTRY:
  8789. lvi.iImage = IMAGE_EVENT_ERROR;
  8790. break;
  8791. }
  8792. lvi.pszText = pszTimestamp;
  8793. lvi.iSubItem = EVENTS_COLUMN_TIME;
  8794. lvi.lParam = iType;
  8795. lvi.iItem = 0;
  8796. iIndex = ListView_InsertItem(hwndEventsList, &lvi);
  8797. ListView_SetItemText(hwndEventsList, iIndex, EVENTS_COLUMN_MSG, pszMsg);
  8798. }
  8799. if (bAddToFile) {
  8800. //
  8801. // So append this to the file
  8802. //
  8803. FILE* fp = _tfopen(TEXT("events.log"), TEXT("a+"));
  8804. if (fp == NULL) {
  8805. return FALSE;
  8806. }
  8807. fwprintf(fp, TEXT("%d %s; %s;"), iType, pszTimestamp, pszMsg);
  8808. fclose(fp);
  8809. }
  8810. return TRUE;
  8811. }
  8812. void
  8813. EventsWindowSize(
  8814. IN HWND hDlg
  8815. )
  8816. /*++
  8817. Desc: Handles the WM_SIZE for the event dialog
  8818. Params:
  8819. IN HWND hDlg: The events dialog
  8820. --*/
  8821. {
  8822. RECT rDlg;
  8823. if (s_cEventHeight == 0 || s_cEventWidth == 0) {
  8824. return;
  8825. }
  8826. GetWindowRect(hDlg, &rDlg);
  8827. int nWidth = rDlg.right - rDlg.left;
  8828. int nHeight = rDlg.bottom - rDlg.top;
  8829. int deltaW = nWidth - s_cEventWidth;
  8830. int deltaH = nHeight - s_cEventHeight;
  8831. HWND hwnd;
  8832. RECT r;
  8833. //
  8834. // List
  8835. //
  8836. hwnd = GetDlgItem(hDlg, IDC_LIST);
  8837. GetWindowRect(hwnd, &r);
  8838. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  8839. MoveWindow(hwnd,
  8840. r.left,
  8841. r.top,
  8842. r.right - r.left + deltaW,
  8843. r.bottom - r.top + deltaH,
  8844. TRUE);
  8845. s_cEventHeight = nHeight;
  8846. s_cEventWidth = nWidth;
  8847. ListView_SetColumnWidth(hwnd, 1, LVSCW_AUTOSIZE_USEHEADER);
  8848. }
  8849. void
  8850. UpdateControls(
  8851. void
  8852. )
  8853. /*++
  8854. UpdateControls
  8855. Desc: Updates/redraws the controls when we need to update them, this will be needed
  8856. when we show the save as dialog box or the open dialog box.
  8857. The controls below the dialog box need to be repainted.
  8858. --*/
  8859. {
  8860. UpdateWindow(DBTree.m_hLibraryTree);
  8861. UpdateWindow(g_hwndToolBar);
  8862. UpdateWindow(g_hwndStatus);
  8863. UpdateWindow(g_hwndRichEdit);
  8864. if (g_bIsContentListVisible) {
  8865. UpdateWindow(g_hwndContentsList);
  8866. } else {
  8867. UpdateWindow(g_hwndEntryTree);
  8868. }
  8869. }
  8870. void
  8871. ProcessSwitches(
  8872. void
  8873. )
  8874. /*++
  8875. ProcessSwitches
  8876. Desc: Processes the various switches. The switches have to be prefixed with
  8877. either a '-' or a '/'
  8878. Present switches are:
  8879. 1. x: Expert mode
  8880. --*/
  8881. {
  8882. INT iArgc = 0;
  8883. LPWSTR* arParams = CommandLineToArgvW(GetCommandLineW(), &iArgc);
  8884. if (arParams) {
  8885. *g_szAppPath = 0;
  8886. GetModuleFileName(g_hInstance, g_szAppPath, ARRAYSIZE(g_szAppPath) - 1);
  8887. for (int iIndex = 1; iIndex < iArgc; ++iIndex) {
  8888. if (arParams[iIndex][0] == TEXT('-') || arParams[iIndex][0] == TEXT('/')) {
  8889. switch (arParams[iIndex][1]) {
  8890. case TEXT('X'):
  8891. case TEXT('x'):
  8892. g_bExpert = TRUE;
  8893. break;
  8894. }
  8895. }
  8896. }
  8897. GlobalFree(arParams);
  8898. }
  8899. }
  8900. void
  8901. OnExitCleanup(
  8902. void
  8903. )
  8904. /*++
  8905. OnExitCleanup
  8906. Desc: Does cleaning up of critical sections, other stuff.
  8907. This module is called when we are sure that we are going to exit
  8908. --*/
  8909. {
  8910. g_strlMRU.DeleteAll();
  8911. InstalledDataBaseList.RemoveAll();
  8912. CleanupDbSupport(&GlobalDataBase);
  8913. //
  8914. // NOTE: It is possible that after we have deleted the cs, some other thread might try
  8915. // to use it.
  8916. // So this function should not be called in the release bits.
  8917. // HELP_BOUND_CHECK should not be defined.
  8918. //
  8919. DeleteCriticalSection(&g_critsectShowMain);
  8920. DeleteCriticalSection(&s_csExpanding);
  8921. DeleteCriticalSection(&g_csInstalledList);
  8922. if (g_arrhEventNotify[IND_PERUSER]) {
  8923. CloseHandle(g_arrhEventNotify[IND_PERUSER]);
  8924. }
  8925. if (g_arrhEventNotify[IND_ALLUSERS]) {
  8926. CloseHandle(g_arrhEventNotify[IND_ALLUSERS]);
  8927. }
  8928. if (g_hThreadWait) {
  8929. CloseHandle(g_hThreadWait);
  8930. }
  8931. ImageList_Destroy(g_hImageList);
  8932. ImageList_Destroy(s_hImageListToolBar);
  8933. ImageList_Destroy(s_hImageListToolBarHot);
  8934. }
  8935. void
  8936. ShowIncludeStatusMessage(
  8937. IN HWND hwndTree,
  8938. IN HTREEITEM hItem
  8939. )
  8940. /*++
  8941. ShowIncludeStatusMessage
  8942. Desc: Sets the status message when the htree item in question is an "include" item
  8943. Params:
  8944. IN HWND hwndTree: The handle to the tree. Should be one of
  8945. g_hwndTree or DBTree.m_hLibraryTree
  8946. IN HTREEITEM hItem: The tree-item for which we need the status message
  8947. --*/
  8948. {
  8949. TVITEM tvi;
  8950. *g_szData = 0;
  8951. tvi.mask = TVIF_TEXT;
  8952. tvi.hItem = hItem;
  8953. tvi.pszText = g_szData;
  8954. tvi.cchTextMax = ARRAYSIZE(g_szData);
  8955. if (TreeView_GetItem(hwndTree, &tvi)) {
  8956. //
  8957. // Special status messages if we have * or .EXE
  8958. //
  8959. if (lstrcmpi(g_szData, TEXT("*")) == 0) {
  8960. SetStatus(IDS_STA_ALL_INCLUDED);
  8961. } else if (lstrcmpi(g_szData, GetString(IDS_INCLUDEMODULE)) == 0) {
  8962. SetStatus(IDS_STA_EXE_INCLUDED);
  8963. } else {
  8964. //
  8965. // Default inlude message
  8966. //
  8967. SetStatus(IDS_STA_INCLUDE);
  8968. }
  8969. }
  8970. }
  8971. void
  8972. ShowExcludeStatusMessage(
  8973. IN HWND hwndTree,
  8974. IN HTREEITEM hItem
  8975. )
  8976. /*++
  8977. ShowExcludeStatusMessage
  8978. Desc: Sets the status message when the htree item in question is a "exclude" item
  8979. Params:
  8980. IN HWND hwndTree: The handle to the tree. Should be one of
  8981. g_hwndTree or DBTree.m_hLibraryTree
  8982. IN HTREEITEM hItem: The tree-item for which we need the status message
  8983. --*/
  8984. {
  8985. TVITEM tvi;
  8986. *g_szData = 0;
  8987. tvi.mask = TVIF_TEXT;
  8988. tvi.hItem = hItem;
  8989. tvi.pszText = g_szData;
  8990. tvi.cchTextMax = ARRAYSIZE(g_szData);
  8991. if (TreeView_GetItem(DBTree.m_hLibraryTree, &tvi)) {
  8992. //
  8993. // Special status messages if we have * or .EXE
  8994. //
  8995. if (lstrcmpi(g_szData, TEXT("*")) == 0) {
  8996. SetStatus(IDS_STA_ALL_EXCLUDED);
  8997. } else if (lstrcmpi(g_szData, GetString(IDS_INCLUDEMODULE)) == 0) {
  8998. SetStatus(IDS_STA_EXE_EXCLUDED);
  8999. } else {
  9000. //
  9001. // Default exclude message
  9002. //
  9003. SetStatus(IDS_STA_EXCLUDE);
  9004. }
  9005. }
  9006. }
  9007. void
  9008. ShowHelp(
  9009. IN HWND hdlg,
  9010. IN WPARAM wCode
  9011. )
  9012. /*++
  9013. ShowHelp
  9014. Desc: Shows the help window(s) for CompatAdmin
  9015. Params:
  9016. IN HWND hdlg: The main app window
  9017. IN WPARAM wCode: The menu item chosen
  9018. Return:
  9019. void
  9020. --*/
  9021. {
  9022. TCHAR szDrive[MAX_PATH * 2], szDir[MAX_PATH];
  9023. INT iType = 0;
  9024. *szDir = *szDrive = 0;
  9025. _tsplitpath(g_szAppPath, szDrive, szDir, NULL, NULL);
  9026. StringCchCat(szDrive, ARRAYSIZE(szDrive), szDir);
  9027. StringCchCat(szDrive, ARRAYSIZE(szDrive), TEXT("CompatAdmin.chm"));
  9028. switch (wCode) {
  9029. case ID_HELP_TOPICS:
  9030. iType = HH_DISPLAY_TOC;
  9031. break;
  9032. case ID_HELP_INDEX:
  9033. iType = HH_DISPLAY_INDEX;
  9034. break;
  9035. case ID_HELP_SEARCH:
  9036. iType = HH_DISPLAY_SEARCH;
  9037. break;
  9038. default:
  9039. assert(FALSE);
  9040. break;
  9041. }
  9042. if (iType != HH_DISPLAY_SEARCH) {
  9043. HtmlHelp(GetDesktopWindow(), szDrive, iType, 0);
  9044. } else {
  9045. HH_FTS_QUERY Query;
  9046. ZeroMemory(&Query, sizeof(Query));
  9047. Query.cbStruct = sizeof(Query);
  9048. HtmlHelp(GetDesktopWindow(), szDrive, iType, (DWORD_PTR)&Query);
  9049. }
  9050. }
  9051. void
  9052. ShowEventsWindow(
  9053. void
  9054. )
  9055. /*++
  9056. ShowEventsWindow
  9057. Desc: Shows the events window. (This is not the same as the shim log)
  9058. Params:
  9059. void
  9060. Return:
  9061. void
  9062. --*/
  9063. {
  9064. HWND hwnd = NULL;
  9065. if (g_hwndEventsWnd) {
  9066. //
  9067. // If we have the events window already, then just display it and
  9068. // set the focus to it
  9069. //
  9070. ShowWindow(g_hwndEventsWnd, SW_SHOWNORMAL);
  9071. SetFocus(GetDlgItem(g_hwndEventsWnd, IDC_LIST));
  9072. } else {
  9073. //
  9074. // We need to create the events window
  9075. //
  9076. hwnd = CreateDialog(g_hInstance,
  9077. MAKEINTRESOURCE(IDD_EVENTS),
  9078. GetDesktopWindow(),
  9079. EventDlgProc);
  9080. ShowWindow(hwnd, SW_NORMAL);
  9081. }
  9082. }
  9083. void
  9084. OnEntryTreeSelChange(
  9085. IN LPARAM lParam
  9086. )
  9087. /*++
  9088. OnEntryTreeSelChange
  9089. Desc: Handles the TVN_SELCHANGED for the entry tree (RHS)
  9090. Params:
  9091. IN LPARAM lParam: The lParam that comes with WM_NOTIFY
  9092. Return:
  9093. void
  9094. --*/
  9095. {
  9096. LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
  9097. if (pnmtv == NULL) {
  9098. return;
  9099. }
  9100. HTREEITEM hItem = pnmtv->itemNew.hItem;
  9101. if (hItem != 0) {
  9102. //
  9103. // Now we have to find the root entry, because that is the exe
  9104. //
  9105. HTREEITEM hItemParent = TreeView_GetParent(g_hwndEntryTree, hItem);
  9106. while (hItemParent != NULL) {
  9107. hItem = hItemParent;
  9108. hItemParent = TreeView_GetParent(g_hwndEntryTree, hItem);
  9109. }
  9110. TVITEM Item;
  9111. Item.mask = TVIF_PARAM;
  9112. Item.hItem = hItem;
  9113. if (!TreeView_GetItem(g_hwndEntryTree, &Item)) {
  9114. goto End;
  9115. }
  9116. TYPE type = (TYPE)GetItemType(g_hwndEntryTree, hItem);
  9117. if (type == TYPE_UNKNOWN) {
  9118. goto End;
  9119. }
  9120. if (type == TYPE_ENTRY) {
  9121. PDBENTRY pEntry = (PDBENTRY)Item.lParam;
  9122. g_pSelEntry = pEntry;
  9123. } else {
  9124. //
  9125. // CAUTION: Note that when we shut down CompatAdmin, then it is possible
  9126. // that we have deleted all the entries from the database, but not
  9127. // from the entry tree. In this case if we get focus there then
  9128. // the lParam will point to some invalid entry.
  9129. //
  9130. goto End;
  9131. }
  9132. SetStatusStringEntryTree(pnmtv->itemNew.hItem);
  9133. SetTBButtonStatus(g_hwndToolBar, g_hwndEntryTree);
  9134. CSTRING strToolTip;
  9135. TCHAR szText[256];
  9136. *szText = 0;
  9137. CTree::GetTreeItemText(g_hwndEntryTree,
  9138. pnmtv->itemNew.hItem,
  9139. szText,
  9140. ARRAYSIZE(szText));
  9141. LPARAM lParamTreeItem;
  9142. CTree::GetLParam(g_hwndEntryTree, pnmtv->itemNew.hItem, &lParamTreeItem);
  9143. GetDescriptionString(lParamTreeItem,
  9144. strToolTip,
  9145. NULL,
  9146. szText,
  9147. pnmtv->itemNew.hItem,
  9148. g_hwndEntryTree);
  9149. if (strToolTip.Length() > 0) {
  9150. SetDescription(szText, strToolTip.pszString);
  9151. } else {
  9152. SetDescription(NULL, TEXT(""));
  9153. }
  9154. }
  9155. End:
  9156. return;
  9157. }
  9158. BOOL
  9159. EndListViewLabelEdit(
  9160. IN LPARAM lParam
  9161. )
  9162. /*++
  9163. EndListViewLabelEdit
  9164. Desc: Processes LVN_ENDLABELEDIT message for the contents list
  9165. Params:
  9166. EndListViewLabelEdit: The lParam that comes with WM_NOTIFY
  9167. Return:
  9168. void
  9169. --*/
  9170. {
  9171. g_hwndEditText = NULL;
  9172. NMLVDISPINFO FAR* pLvd = (NMLVDISPINFO FAR*)lParam;
  9173. LVITEM lvItem;
  9174. BOOL fValid = TRUE;
  9175. if (pLvd == NULL) {
  9176. fValid = FALSE;
  9177. goto end;
  9178. }
  9179. lvItem = pLvd->item;
  9180. if (lvItem.pszText == NULL) {
  9181. fValid = FALSE;
  9182. goto end;
  9183. }
  9184. TCHAR szText[256];
  9185. *szText = 0;
  9186. SafeCpyN(szText, lvItem.pszText, ARRAYSIZE(szText));
  9187. if (CSTRING::Trim(szText) == 0) {
  9188. fValid = FALSE;
  9189. goto end;
  9190. }
  9191. lvItem.lParam = NULL;
  9192. lvItem.mask = LVIF_PARAM;
  9193. if (!ListView_GetItem(g_hwndContentsList, &lvItem)) {
  9194. assert(FALSE);
  9195. fValid = FALSE;
  9196. goto end;
  9197. }
  9198. TYPE type = ConvertLparam2Type(lvItem.lParam);
  9199. switch (type) {
  9200. case TYPE_ENTRY:
  9201. {
  9202. PDBENTRY pEntry = (PDBENTRY)lvItem.lParam;
  9203. assert(pEntry);
  9204. PDBENTRY pApp = g_pPresentDataBase->pEntries;
  9205. if (!IsValidAppName(szText)) {
  9206. //
  9207. // The app name contains invalid chars
  9208. //
  9209. DisplayInvalidAppNameMessage(g_hDlg);
  9210. break;
  9211. }
  9212. //
  9213. // Check if we have some app of the same name that we are trying to give...
  9214. //
  9215. while (pApp) {
  9216. if (pApp->strAppName == szText) {
  9217. //
  9218. // Yes, we have, so do not allow this name
  9219. //
  9220. MessageBox(g_hDlg, GetString(IDS_SAMEAPPEXISTS), g_szAppName, MB_ICONWARNING);
  9221. fValid = FALSE;
  9222. }
  9223. pApp = pApp->pNext;
  9224. }
  9225. //
  9226. // Now change the name of all the entries for this app
  9227. //
  9228. while (pEntry) {
  9229. pEntry->strAppName = szText;
  9230. pEntry = pEntry->pSameAppExe;
  9231. }
  9232. }
  9233. break;
  9234. case FIX_LAYER:
  9235. {
  9236. PLAYER_FIX plf = (PLAYER_FIX)lvItem.lParam;
  9237. if (plf == NULL) {
  9238. assert(FALSE);
  9239. return FALSE;
  9240. }
  9241. if (FindFix(szText, FIX_LAYER, g_pPresentDataBase)) {
  9242. //
  9243. // A layer with the same name already exists in the system or the
  9244. // present database
  9245. //
  9246. MessageBox(g_hDlg,
  9247. GetString(IDS_LAYEREXISTS),
  9248. g_szAppName,
  9249. MB_ICONWARNING);
  9250. return FALSE;
  9251. }
  9252. plf->strName = szText;
  9253. }
  9254. break;
  9255. default: fValid = FALSE;
  9256. }// switch
  9257. end:
  9258. INT_PTR iStyle = GetWindowLongPtr(g_hwndContentsList, GWL_STYLE);
  9259. iStyle &= ~LVS_EDITLABELS;
  9260. SetWindowLongPtr(g_hwndContentsList, GWL_STYLE, iStyle);
  9261. if (fValid) {
  9262. g_pPresentDataBase->bChanged;
  9263. HTREEITEM hParent;
  9264. if (type == TYPE_ENTRY) {
  9265. hParent = g_pPresentDataBase->hItemAllApps;
  9266. } else if (type == FIX_LAYER) {
  9267. hParent = g_pPresentDataBase->hItemAllLayers;
  9268. } else {
  9269. assert(FALSE);
  9270. }
  9271. HTREEITEM hItem = DBTree.FindChild(hParent, lvItem.lParam);
  9272. assert(hItem);
  9273. //
  9274. // Refresh the entry in the tree
  9275. //
  9276. PostMessage(g_hDlg,
  9277. WM_USER_REPAINT_TREEITEM,
  9278. (WPARAM)hItem,
  9279. (LPARAM)lvItem.lParam);
  9280. PostMessage(g_hDlg,
  9281. WM_USER_REPAINT_LISTITEM,
  9282. (WPARAM)lvItem.iItem,
  9283. (LPARAM)lvItem.lParam);
  9284. return TRUE;
  9285. } else {
  9286. return FALSE;
  9287. }
  9288. }
  9289. void
  9290. HandleMRUActivation(
  9291. IN WPARAM wCode
  9292. )
  9293. /*++
  9294. HandleMRUActivation
  9295. Desc: The user wishes to open a database that is in the MRU list. If this
  9296. database is already open then we simply select this database in the
  9297. database tree. (LHS)
  9298. Params:
  9299. IN WPARAM wCode: The LOWORD(wParam) that comes with WM_COMMAND. This will
  9300. identify which MRU menu item was activated
  9301. Return:
  9302. void
  9303. --*/
  9304. {
  9305. CSTRING strPath;
  9306. if (!g_strlMRU.GetElement(wCode - ID_FILE_FIRST_MRU, strPath)) {
  9307. assert(FALSE);
  9308. return;
  9309. }
  9310. //
  9311. // Test to see if we have the database open already.
  9312. // If it is open, we just highlight that and return
  9313. //
  9314. PDATABASE pDataBase = DataBaseList.pDataBaseHead;
  9315. BOOL bFound = FALSE;
  9316. while (pDataBase) {
  9317. if (pDataBase->strPath == strPath) {
  9318. TreeView_SelectItem(DBTree.m_hLibraryTree, pDataBase->hItemDB);
  9319. bFound = TRUE;
  9320. break;
  9321. }
  9322. pDataBase = pDataBase->pNext;
  9323. }
  9324. BOOL bLoaded = FALSE;
  9325. if (!bFound) {
  9326. SetCursor(LoadCursor(NULL, IDC_WAIT));
  9327. bLoaded = LoadDataBase((LPTSTR)strPath);
  9328. if (bLoaded) {
  9329. SetCursor(LoadCursor(NULL, IDC_ARROW));
  9330. AddToMRU(g_pPresentDataBase->strPath);
  9331. RefreshMRUMenu();
  9332. SetCaption();
  9333. }
  9334. }
  9335. }
  9336. void
  9337. OnDbRenameInitDialog(
  9338. IN HWND hdlg
  9339. )
  9340. /*++
  9341. OnDbRenameInitDialog
  9342. Description: Processes WM_INITDIALOG for IDD_DBRENAME.
  9343. Limits the text field
  9344. Params:
  9345. IN HWND hdlg: The handle to the rename dialog box
  9346. --*/
  9347. {
  9348. SendMessage(GetDlgItem(hdlg, IDC_NAME),
  9349. EM_LIMITTEXT,
  9350. (WPARAM)LIMIT_APP_NAME,
  9351. (LPARAM)0);
  9352. if (g_pPresentDataBase) {
  9353. SetDlgItemText(hdlg, IDC_NAME, (LPCTSTR)g_pPresentDataBase->strName);
  9354. }
  9355. CenterWindow(GetParent(hdlg), hdlg);
  9356. }
  9357. void
  9358. OnDbRenameOnCommandIDC_NAME(
  9359. IN HWND hdlg,
  9360. IN WPARAM wParam
  9361. )
  9362. /*++
  9363. OnDbRenameOnCommandIDC_NAME
  9364. Description: Processes WM_COMMAND for the text box in IDD_DBRENAME.
  9365. Disables the OK button if we do not have any text in there.
  9366. Params:
  9367. IN HWND hdlg: The handle to the rename dialog box
  9368. IN WPARAM wParam: The WPARAM that comes with WM_COMMAND
  9369. --*/
  9370. {
  9371. BOOL bEnable;
  9372. TCHAR szDBName[LIMIT_APP_NAME + 1];
  9373. if (hdlg == NULL) {
  9374. return;
  9375. }
  9376. if (EN_CHANGE == HIWORD(wParam)) {
  9377. *szDBName = 0;
  9378. GetWindowText(GetDlgItem(hdlg, IDC_NAME), szDBName, ARRAYSIZE(szDBName));
  9379. bEnable = ValidInput(szDBName);
  9380. //
  9381. // Enable the OK button only if we have some text in the box
  9382. //
  9383. ENABLEWINDOW(GetDlgItem(hdlg, IDOK), bEnable);
  9384. }
  9385. }
  9386. void
  9387. OnDbRenameOnCommandIDOK(
  9388. IN HWND hdlg,
  9389. OUT CSTRING* pstrString
  9390. )
  9391. /*++
  9392. OnDbRenameOnCommandIDOK
  9393. Description: Handles the pressing of OK button in IDD_DBRENAME. Gets the text
  9394. from the text box and stores that in g_szData
  9395. Params:
  9396. IN HWND hdlg: The handle to the dialog rename window: IDD_DBRENAME
  9397. OUT CSTRING* pstrString: The pointer to the CSTRING that should contain the new name
  9398. --*/
  9399. {
  9400. TCHAR szDBName[LIMIT_APP_NAME + 1];
  9401. *szDBName = 0;
  9402. GetDlgItemText(hdlg, IDC_NAME, szDBName, ARRAYSIZE(szDBName));
  9403. CSTRING::Trim(szDBName);
  9404. //
  9405. // Change the name
  9406. //
  9407. *pstrString = szDBName;
  9408. }
  9409. INT_PTR CALLBACK
  9410. DatabaseRenameDlgProc(
  9411. IN HWND hdlg,
  9412. IN UINT uMsg,
  9413. IN WPARAM wParam,
  9414. IN LPARAM lParam
  9415. )
  9416. /*++
  9417. DatabaseRenameProc
  9418. Description: Handles messages for the database rename option
  9419. Params: Standard dialog handler parameters
  9420. IN HWND hDlg
  9421. IN UINT uMsg
  9422. IN WPARAM wParam
  9423. IN LPARAM lParam: This will be a pointer to a CSTRING that should contain the new string
  9424. Return: Standard dialog handler return
  9425. --*/
  9426. {
  9427. int wCode = LOWORD(wParam);
  9428. int wNotifyCode = HIWORD(wParam);
  9429. static CSTRING* s_pstrParam = NULL;
  9430. switch (uMsg) {
  9431. case WM_INITDIALOG:
  9432. OnDbRenameInitDialog(hdlg);
  9433. s_pstrParam = (CSTRING*)lParam;
  9434. break;
  9435. case WM_COMMAND:
  9436. switch (wCode) {
  9437. case IDOK:
  9438. OnDbRenameOnCommandIDOK(hdlg, s_pstrParam);
  9439. EndDialog(hdlg, TRUE);
  9440. break;
  9441. case IDC_NAME:
  9442. OnDbRenameOnCommandIDC_NAME(hdlg, wParam);
  9443. break;
  9444. case IDCANCEL:
  9445. EndDialog(hdlg, FALSE);
  9446. break;
  9447. }
  9448. break;
  9449. default: return FALSE;
  9450. }
  9451. return TRUE;
  9452. }
  9453. PDATABASE
  9454. GetCurrentDB(
  9455. void
  9456. )
  9457. {
  9458. return g_pPresentDataBase;
  9459. }
  9460. void
  9461. DisplayInvalidAppNameMessage(
  9462. IN HWND hdlg
  9463. )
  9464. /*++
  9465. DisplayInvalidAppNameMessage
  9466. Desc: If the app name contains one of the chars that cannot
  9467. be part of a dir name we will show this message.
  9468. Params:
  9469. IN HWND hdlg: The window where this dialog message should be shown.
  9470. )
  9471. --*/
  9472. {
  9473. CSTRING strMessage(IDS_ERROR_DEFAULTNAME);
  9474. strMessage.Strcat(TEXT(" \""));
  9475. MessageBox(hdlg,
  9476. strMessage,
  9477. g_szAppName,
  9478. MB_ICONWARNING);
  9479. }
  9480. INT
  9481. GetContentsListIndex(
  9482. IN HWND hwndList,
  9483. IN LPARAM lParam
  9484. )
  9485. /*++
  9486. GetContentsListIndex
  9487. Desc: Gets the index of a item that has the LPARAM of lParam
  9488. Params:
  9489. IN HWND hwndList: The list view
  9490. IN LPARAM lParam: The LPARAM
  9491. Return:
  9492. The index of the item that has a LPARAM of lParam
  9493. or -1 if that does not exist
  9494. --*/
  9495. {
  9496. LVFINDINFO lvFind;
  9497. INT iIndex = 0;
  9498. lvFind.flags = LVFI_PARAM;
  9499. lvFind.lParam = lParam;
  9500. return ListView_FindItem(hwndList, -1, &lvFind);
  9501. }
  9502. BOOL
  9503. DeleteFromContentsList(
  9504. IN HWND hwndList,
  9505. IN LPARAM lParam
  9506. )
  9507. /*++
  9508. DeleteFromContentsList
  9509. Desc: Deletesan element with LPARAM of lParam from the ListView hwndList
  9510. Params:
  9511. IN HWND hwndList: The list view from which we want to delete
  9512. IN LPARAM lParam: The LPARAM of the item that we want to delete
  9513. Return:
  9514. TRUE: The item was deleted successfully
  9515. FALSE: Otherwise
  9516. --*/
  9517. {
  9518. INT iIndex = -1;
  9519. BOOL bOk = FALSE;
  9520. iIndex = GetContentsListIndex(hwndList, lParam);
  9521. if (iIndex > -1) {
  9522. bOk = ListView_DeleteItem(hwndList, iIndex);
  9523. } else {
  9524. assert(FALSE);
  9525. Dbg(dlError, "DeleteFromContentsList", "Could not find Element with lParam = %X", lParam);
  9526. bOk = FALSE;
  9527. }
  9528. return bOk;
  9529. }