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.

2967 lines
86 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. LUA.cpp
  5. Abstract:
  6. Implementation of the LUA wizard in CompatAdmin.
  7. Author:
  8. maonis
  9. --*/
  10. /*++
  11. The UI to customize the LUA shims lets you track and edit the list of files
  12. and directories passed as the command line to the LUA shims. Only the LUA
  13. FS shims are parameterized so the UI is for editing the list of files.
  14. Page 1: Tracking
  15. ================
  16. We apply the LUATrackFS shim to the executable. When the app finishes running,
  17. we get a log in AppPatch directory that tells us which files and directories
  18. the app attempted to write to.
  19. Next time when the sdb is loaded, the user can choose to discard the old result
  20. and start fresh, append the new data to the old one (with duplicates removed),
  21. or simply just edit the data collected last time.
  22. Scenario: if the user forgot to test some features, he would not want to check
  23. the "Override existing data" checkbox because he won't want to test all the
  24. features he already tested.
  25. Page 2: Extension exclusion list
  26. ================================
  27. By default we exclude a list of file extensions because files with these extensions
  28. are likely to be user data only. The list can be found as a value called
  29. LUADefaultExclusionList under the reg key
  30. HKLM\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags.
  31. This page gives you an option to modify this list.
  32. Page 3: Editing the redirect file list
  33. ======================================
  34. (We call it a file list, but really it includes files and directories. A directory
  35. is indicated by the trailing slash.)
  36. If an item is already exactly what you want, you simply check the checkbox before
  37. the file name. But sometimes you want to use wildcards or whatever, in which case
  38. you can either copy it to edit, or type in a new item name.
  39. Use the "Redirect to All User" checkbox to toggle between redirecting to the
  40. per-user directory and all-user directory. The default is to redirect to per-user.
  41. The xml looks like:
  42. <APP NAME="Some app" VENDOR="Some company">
  43. <EXE NAME="Some executable">
  44. <SHIM NAME="LUARedirectFS">
  45. <DATA NAME="AllUserDir" VALUETYPE="STRING"
  46. VALUE="%ALLUSERSPROFILE%\AllUserRedirect"/>
  47. <DATA NAME="PerUserDir" VALUETYPE="STRING"
  48. VALUE="%USERSPROFILE%\Redirect"/>
  49. <DATA NAME="StaticList" VALUETYPE="STRING"
  50. VALUE="AC-%APPDRIVE%\a\;PU-%APPPATH%\b.txt"/>
  51. <DATA NAME="DynamicList" VALUETYPE="STRING"
  52. VALUE="AC-%APPPATH%\b\;PU-c:\b\b.txt;AU-c:\c\"/>
  53. <DATA NAME="ExcludedExtensions" VALUETYPE="STRING"
  54. VALUE="doc txt gif"/>
  55. </SHIM>
  56. </EXE>
  57. </APP>
  58. A means to redirect to the all-user directory.
  59. P means to redirect to the per-user directory.
  60. C means the item is checked.
  61. U means the item is not checked.
  62. We use variables to make the sdb portable. We define 2 variables and the rest can
  63. be any enviorment variable.
  64. %APPPATH% - this is the path of the executable.
  65. eg, in c:\temp\notepad.exe, %APPPATH% is c:\temp
  66. %APPDRIVE% - this is the drive the executable is on.
  67. eg, in c:\temp\notepad.exe, %APPDRIVE% is c:
  68. The LUARedirectFS shim knows how to interpret the <DATA> sections.
  69. Page 4: Redirect paths
  70. ======================
  71. We show the user what the all-user and per-user redirect redirectories are - we use
  72. the app name as the directory name under the all-user and per-user profile directories
  73. and this can not be changed.
  74. --*/
  75. #include "precomp.h"
  76. extern HINSTANCE g_hInstance;
  77. #define NUM_PAGES_LUA 4
  78. #define PAGE_LUA_ACTION 0
  79. #define PAGE_LUA_EXCLUSION 1
  80. #define PAGE_LUA_EDIT_FILE_LIST 2
  81. #define PAGE_LUA_COMMON_PATHS 3
  82. #define IS_IN_COMMANDLINE 1
  83. #define IS_IN_DATA 2
  84. #define IS_IN_BOTH 3
  85. #define LUA_DATA_ALLUSERDIR L"AllUserDir"
  86. #define LUA_DATA_PERUSERDIR L"PerUserDir"
  87. #define LUA_DATA_STATICLIST L"StaticList"
  88. #define LUA_DATA_DYNAMICLIST L"DynamicList"
  89. #define LUA_DATA_EXCLUDEDEXTENSIONS L"ExcludedExtensions"
  90. typedef struct tagREDIRECT_ITEM {
  91. LIST_ENTRY entry;
  92. CSTRING strName;
  93. BOOL bChecked;
  94. BOOL bRedirectToAllUser;
  95. tagREDIRECT_ITEM()
  96. {
  97. bChecked = FALSE;
  98. bRedirectToAllUser = FALSE;
  99. }
  100. } REDIRECT_ITEM, *PREDIRECT_ITEM;
  101. typedef struct tagUNTOKENIZED_ITEM {
  102. LIST_ENTRY entry;
  103. CSTRING strName;
  104. } UNTOKENIZED_ITEM, *PUNTOKENIZED_ITEM;
  105. // The line type for the file generated by the LUATrackFS shim.
  106. typedef enum {
  107. LINE_INVALID,
  108. LINE_FILE_COUNT, // The file count line: Fn
  109. LINE_DIR_COUNT, // The directory count line: Dn
  110. } LINETYPE;
  111. typedef enum {
  112. LUA_TRACK_UNKNOWN = 0,
  113. LUA_TRACK_YES,
  114. LUA_TRACK_NO
  115. } LUA_TRACK_STATE;
  116. int g_iCurrentEditItem = -1;
  117. BOOL g_bNewListViewItem = FALSE;
  118. int g_nStaticItems = 0;
  119. HMENU g_hContextMenu = NULL;
  120. // The entry we currently work on.
  121. PDBENTRY g_pEntryLua;
  122. // Points to the shim that has the lua data.
  123. PSHIM_FIX_LIST g_psflLua = NULL;
  124. // This is *our* copy of the lua data so we don't overwrite the data in the entry
  125. // before the user presses Finish.
  126. LUADATA g_LuaData;
  127. BOOL g_bUseNewStaticList = TRUE;
  128. // List of items displayed in the 2nd page of the wizard.
  129. // This includs items that can and can not be edited.
  130. LIST_ENTRY g_OldStaticList;
  131. LIST_ENTRY g_NewStaticList;
  132. LIST_ENTRY g_DynamicList;
  133. BOOL g_bListsInitialized = FALSE;
  134. LIST_ENTRY g_UntokenizedList;
  135. // Has this executable been tracked using LUATrackFS shim yet?
  136. LUA_TRACK_STATE g_TrackState;
  137. BOOL g_bHasAppPathSet = FALSE;
  138. WCHAR g_wszAppPath[MAX_PATH] = L"";
  139. UINT g_cAppPath = 0;
  140. // If APPPATH is c:\x\y\z, this is 4.
  141. UINT g_cAppPath1stComp = 0;
  142. // We always display the files in Program Files\Common Files as
  143. // %ProgramFiles%\Common Files.
  144. WCHAR g_wszProgramFilesCommon[MAX_PATH] = L"";
  145. UINT g_czProgramFilesCommon = 0;
  146. #define COMMON_FILES L"\\Common Files\\"
  147. #define COMMON_FILES_LEN (sizeof(COMMON_FILES) / sizeof(WCHAR) - 1)
  148. BOOL g_bDuringUntokenize = FALSE;
  149. // The font for displaying up and down arrows.
  150. HFONT g_hArrowFont = NULL;
  151. // The database in which the entry being customized resides.
  152. static PDATABASE s_pDatabase;
  153. // This is where we store the default exclusion list in the registry under HKLM.
  154. #define LUA_APPCOMPAT_FLAGS_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags"
  155. #define LUA_DEFAULT_EXCLUSION_LIST L"LUADefaultExclusionList"
  156. // We are not freeing it here - it'll stay the whole time the process is running and
  157. // we'll let the process itself do the cleanup.
  158. LPWSTR g_pwszDefaultExclusionList = NULL;
  159. // We want to remember if the user wants to redirect any files at all to all user redirec
  160. // dir; if not we won't bother to create it.
  161. BOOL g_bAllUserDirUsed = FALSE;
  162. // This is for debugging purposes.
  163. void
  164. LuapDumpList(
  165. LPCWSTR pwsz,
  166. PLIST_ENTRY pHead
  167. )
  168. {
  169. OutputDebugString(pwsz);
  170. PREDIRECT_ITEM pItem;
  171. for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
  172. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  173. OutputDebugString(L"\t");
  174. OutputDebugString(pItem->strName);
  175. OutputDebugString(L"\n");
  176. }
  177. }
  178. BOOL
  179. LuapAddItem(
  180. PLIST_ENTRY pHead,
  181. LPCWSTR pwszName,
  182. BOOL bChecked,
  183. BOOL bRedirectToAllUser
  184. )
  185. {
  186. PREDIRECT_ITEM pItem = new REDIRECT_ITEM;
  187. if (pItem == NULL) {
  188. MEM_ERR;
  189. return FALSE;
  190. }
  191. pItem->strName = pwszName;
  192. pItem->bChecked = bChecked;
  193. pItem->bRedirectToAllUser = bRedirectToAllUser;
  194. InsertTailList(pHead, &pItem->entry);
  195. return TRUE;
  196. }
  197. void
  198. LuapDeleteList(
  199. PLIST_ENTRY pHead
  200. )
  201. {
  202. PREDIRECT_ITEM pItem;
  203. PLIST_ENTRY pTempEntry;
  204. for (PLIST_ENTRY pEntry = pHead->Flink; pEntry && pEntry != pHead; pEntry = pEntry->Flink) {
  205. pTempEntry = pEntry->Flink;
  206. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  207. RemoveEntryList(pEntry);
  208. delete pItem;
  209. pEntry = pTempEntry;
  210. }
  211. pHead->Flink = pHead->Blink = NULL;
  212. }
  213. PLIST_ENTRY
  214. LuapFindEntry(
  215. PLIST_ENTRY pHead,
  216. PLIST_ENTRY pEntryToFind
  217. )
  218. {
  219. PREDIRECT_ITEM pItem;
  220. PREDIRECT_ITEM pItemToFind = CONTAINING_RECORD(pEntryToFind, REDIRECT_ITEM, entry);
  221. for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
  222. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  223. if (!_wcsicmp(pItem->strName, pItemToFind->strName)) {
  224. return pEntry;
  225. }
  226. }
  227. return NULL;
  228. }
  229. PLIST_ENTRY
  230. LuapFindEntry(
  231. PLIST_ENTRY pHead,
  232. PREDIRECT_ITEM pItemToFind
  233. )
  234. {
  235. PREDIRECT_ITEM pItem;
  236. for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
  237. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  238. if (!_wcsicmp(pItem->strName, pItemToFind->strName)) {
  239. return pEntry;
  240. }
  241. }
  242. return NULL;
  243. }
  244. LINETYPE
  245. LuapGetLineType(
  246. LPCWSTR pwszLine
  247. )
  248. {
  249. if (pwszLine && *pwszLine) {
  250. WCHAR ch0, ch1;
  251. ch0 = *pwszLine;
  252. ch1 = *++pwszLine;
  253. if (ch0 == L'F' || ch0 == L'D') {
  254. if (ch1 >= L'0' && ch1 <= L'9') {
  255. return (ch0 == L'F' ? LINE_FILE_COUNT : LINE_DIR_COUNT);
  256. }
  257. }
  258. }
  259. return LINE_INVALID;
  260. }
  261. DWORD
  262. LuapGetListItemCount(
  263. LPCWSTR pwsz
  264. )
  265. {
  266. DWORD cItems = 0;
  267. while (*pwsz) {
  268. if (*pwsz == L';') {
  269. ++cItems;
  270. }
  271. ++pwsz;
  272. }
  273. return cItems;
  274. }
  275. BOOL
  276. LuapGenerateTrackXML(
  277. const PDBENTRY pEntry,
  278. CSTRINGLIST* strlXML
  279. )
  280. {
  281. CSTRING strTemp;
  282. if (!strlXML->AddString(TEXT("<?xml version=\"1.0\" encoding=\"UTF-16\"?>")) ||
  283. !strlXML->AddString(TEXT("<DATABASE NAME=\"Test database\">"))) {
  284. return FALSE;
  285. }
  286. strTemp.Sprintf(TEXT("\t<APP NAME=\"%s\" VENDOR=\"%s\">"),
  287. (LPCTSTR)(pEntry->strAppName.SpecialCharToXML()),
  288. (LPCTSTR)(pEntry->strVendor.SpecialCharToXML()));
  289. if (!strlXML->AddString(strTemp)) {
  290. return FALSE;
  291. }
  292. strTemp.Sprintf(TEXT("\t\t<EXE NAME=\"%s\">"),
  293. (LPCTSTR)pEntry->strExeName.SpecialCharToXML());
  294. if (!strlXML->AddString(strTemp)) {
  295. return FALSE;
  296. }
  297. if (!strlXML->AddString(TEXT("\t\t\t<SHIM NAME= \"LUATrackFS\"/>")) ||
  298. !strlXML->AddString(TEXT("\t\t</EXE>")) ||
  299. !strlXML->AddString(TEXT("\t</APP>")) ||
  300. !strlXML->AddString(TEXT("</DATABASE>"))) {
  301. return FALSE;
  302. }
  303. return TRUE;
  304. }
  305. // If we see a file begins with %ProgramFiles%\Common Files, we susbstitute it.
  306. BOOL
  307. LuapSubstituteProgramFilesCommon(
  308. LPCWSTR pwszItem,
  309. CSTRING& strItem
  310. )
  311. {
  312. if (g_wszProgramFilesCommon[0] != L'\0') {
  313. if (!_wcsnicmp(pwszItem, g_wszProgramFilesCommon, g_czProgramFilesCommon)) {
  314. strItem = L"%ProgramFiles%\\Common Files";
  315. strItem += CSTRING(pwszItem + g_czProgramFilesCommon);
  316. return TRUE;
  317. }
  318. }
  319. return FALSE;
  320. }
  321. // We check if we should display the path as relative to APPPATH -
  322. // we only do this when the item path has more than just the common
  323. // root with APPPATH.
  324. BOOL
  325. LuapGetRelativeName(
  326. LPCWSTR pwszItem,
  327. CSTRING& strItem
  328. )
  329. {
  330. if (g_cAppPath1stComp > 2 && !_wcsnicmp(pwszItem + 2, g_wszAppPath + 2, g_cAppPath1stComp - 2)) {
  331. CSTRING strTemp = pwszItem;
  332. CSTRING strAppPath(g_wszAppPath);
  333. strAppPath.Strcat(L"\\");
  334. if (strTemp.RelativeFile(strAppPath)) {
  335. strItem = L"%APPPATH%\\";
  336. strItem += strTemp;
  337. return TRUE;
  338. }
  339. }
  340. return FALSE;
  341. }
  342. BOOL
  343. LuapGetFileListFromFile(
  344. CSTRING& strExeName,
  345. PLIST_ENTRY pHead
  346. )
  347. {
  348. if (strExeName == NULL) {
  349. return FALSE;
  350. }
  351. CSTRING strLuaLog;
  352. LPWSTR pwszLuaLogContents = NULL;
  353. TCHAR szWindowsDir[MAX_PATH];
  354. *szWindowsDir = 0;
  355. //
  356. // Need to leave space for adding the trailing slash.
  357. //
  358. UINT cBufferLen = MAX_PATH - 1;
  359. UINT cWindowsDirLen = GetSystemWindowsDirectory(szWindowsDir, cBufferLen);
  360. if (cWindowsDirLen == 0 || cWindowsDirLen >= cBufferLen) {
  361. Dbg(dlError,"[LuapGetFileListFromFile] Error getting the windows directory");
  362. return FALSE;
  363. }
  364. ADD_PATH_SEPARATOR(szWindowsDir, ARRAYSIZE(szWindowsDir));
  365. CSTRING strTempExeName = strExeName;
  366. LPTSTR pszExtension = _tcsrchr(strTempExeName, TEXT('.'));
  367. //
  368. // If there's no extension we use the whole file name.
  369. //
  370. if (pszExtension) {
  371. *pszExtension = 0;
  372. }
  373. strLuaLog.Sprintf(TEXT("%sAppPatch\\%s.LUA.log"), (LPCTSTR)szWindowsDir, strTempExeName);
  374. //
  375. // Get the file list.
  376. //
  377. if (!GetFileContents(strLuaLog, &pwszLuaLogContents)) {
  378. return FALSE;
  379. }
  380. LPWSTR pwszNextLine = GetNextLine(pwszLuaLogContents);
  381. LPWSTR pwszItem;
  382. CSTRING strItem;
  383. DWORD cItems, i;
  384. LINETYPE LineType;
  385. while (pwszNextLine)
  386. {
  387. LineType = LuapGetLineType(pwszNextLine);
  388. if (LineType == LINE_INVALID) {
  389. Dbg(dlError,"[LuapGetFileListFromFile] Invalid line %S", pwszNextLine);
  390. return FALSE;
  391. }
  392. cItems = _wtoi(++pwszNextLine);
  393. for (i = 0; i < cItems; ++i) {
  394. pwszItem = GetNextLine(NULL);
  395. if (pwszItem == NULL) {
  396. Dbg(dlError,"[LuapGetFileListFromFile] count and actual files mismatch");
  397. return FALSE;
  398. }
  399. //
  400. // By now the apppath and appdrive should be set, so tokenize the item.
  401. //
  402. if (!_wcsnicmp(pwszItem, g_wszAppPath, 2)) {
  403. if (!LuapSubstituteProgramFilesCommon(pwszItem, strItem)) {
  404. if (!LuapGetRelativeName(pwszItem, strItem)) {
  405. strItem = L"%APPDRIVE%";
  406. strItem.Strcat(pwszItem + 2);
  407. }
  408. }
  409. } else {
  410. strItem = pwszItem;
  411. }
  412. if (!LuapAddItem(pHead, strItem, FALSE, FALSE)) {
  413. return FALSE;
  414. }
  415. }
  416. pwszNextLine = GetNextLine(NULL);
  417. }
  418. if (pwszLuaLogContents) {
  419. delete[] pwszLuaLogContents;
  420. pwszLuaLogContents = NULL;
  421. }
  422. return TRUE;
  423. }
  424. BOOL
  425. LuapFillInList(
  426. LPCWSTR pwszList,
  427. PLIST_ENTRY pHead
  428. )
  429. {
  430. if (pwszList) {
  431. //
  432. // Make a copy.
  433. //
  434. CSTRING strList = pwszList;
  435. LPWSTR pwsz = strList;
  436. LPWSTR pwszToken = pwsz;
  437. WCHAR ch;
  438. BOOL bChecked, bRedirectToAllUser;
  439. while (TRUE) {
  440. if (*pwsz == L';' || *pwsz == L'\0') {
  441. ch = *pwsz;
  442. *pwsz = L'\0';
  443. TrimLeadingSpaces(pwszToken);
  444. TrimTrailingSpaces(pwszToken);
  445. bChecked = (pwszToken[1] == L'C');
  446. bRedirectToAllUser = (pwszToken[0] == L'A');
  447. if (!LuapAddItem(pHead, pwszToken + 3, bChecked, bRedirectToAllUser)) {
  448. return FALSE;
  449. }
  450. pwszToken = pwsz + 1;
  451. if (ch == L'\0') {
  452. break;
  453. }
  454. }
  455. ++pwsz;
  456. }
  457. }
  458. return TRUE;
  459. }
  460. /*++
  461. Desc:
  462. The algorithm for append:
  463. for each item in the new static list, attempt to find it in the old static list
  464. if (FALSE)
  465. remove it from the new static list
  466. add it to the end of the old static list
  467. check if it exists in the dynamic list
  468. if (TRUE)
  469. copy the attributes from the dynamic list
  470. remove it from the dynamic list
  471. --*/
  472. void
  473. LuapTrackAppend(
  474. )
  475. {
  476. PREDIRECT_ITEM pItem, pDynamicItem;
  477. PLIST_ENTRY pDynamicEntry;
  478. PLIST_ENTRY pEntry = g_NewStaticList.Flink;
  479. PLIST_ENTRY pTempEntry;
  480. while (pEntry != &g_NewStaticList) {
  481. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  482. if (LuapFindEntry(&g_OldStaticList, pItem)) {
  483. pEntry = pEntry->Flink;
  484. } else {
  485. pTempEntry = pEntry->Flink;
  486. RemoveEntryList(pEntry);
  487. InsertTailList(&g_OldStaticList, pEntry);
  488. if (pDynamicEntry = LuapFindEntry(&g_DynamicList, pItem)) {
  489. pDynamicItem = CONTAINING_RECORD(pDynamicEntry, REDIRECT_ITEM, entry);
  490. pItem->bChecked = pDynamicItem->bChecked;
  491. pItem->bRedirectToAllUser = pDynamicItem->bRedirectToAllUser;
  492. RemoveEntryList(pDynamicEntry);
  493. }
  494. pEntry = pTempEntry;
  495. }
  496. }
  497. g_bUseNewStaticList = FALSE;
  498. }
  499. /*++
  500. Desc:
  501. The algorithm for start fresh:
  502. for each item in the new static list, attempt to find it in the dynamic list
  503. if (TRUE)
  504. copy the attributes from the dynamic list
  505. remove it from the dynamic list
  506. for each *checked* item in the old static list, attempt to find it in the new static list
  507. if (FALSE)
  508. add it to the tail of the dynamic list
  509. remove it from the old static list
  510. --*/
  511. void
  512. LuapTrackFresh(
  513. )
  514. {
  515. PREDIRECT_ITEM pItem, pDynamicItem;
  516. PLIST_ENTRY pEntry, pTempEntry, pDynamicEntry, pNewStaticEntry;
  517. for (pEntry = g_NewStaticList.Flink; pEntry != &g_NewStaticList; pEntry = pEntry->Flink) {
  518. if (pDynamicEntry = LuapFindEntry(&g_DynamicList, pEntry)) {
  519. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  520. pDynamicItem = CONTAINING_RECORD(pDynamicEntry, REDIRECT_ITEM, entry);
  521. pItem->bChecked = pDynamicItem->bChecked;
  522. pItem->bRedirectToAllUser = pDynamicItem->bRedirectToAllUser;
  523. RemoveEntryList(pDynamicEntry);
  524. }
  525. }
  526. pEntry = g_OldStaticList.Flink;
  527. while (pEntry != &g_OldStaticList) {
  528. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  529. if (pItem->bChecked) {
  530. if (pNewStaticEntry = LuapFindEntry(&g_NewStaticList, pItem)) {
  531. pTempEntry = pEntry->Flink;
  532. RemoveEntryList(pEntry);
  533. InsertTailList(&g_DynamicList, pEntry);
  534. pEntry = pTempEntry;
  535. continue;
  536. }
  537. }
  538. pEntry = pEntry->Flink;
  539. }
  540. }
  541. void
  542. LuapCleanup()
  543. {
  544. LuapDeleteList(&g_OldStaticList);
  545. LuapDeleteList(&g_NewStaticList);
  546. LuapDeleteList(&g_DynamicList);
  547. g_LuaData.Free();
  548. g_bHasAppPathSet = FALSE;
  549. g_bDuringUntokenize = FALSE;
  550. g_wszAppPath[0] = L'\0';
  551. g_cAppPath = 0;
  552. g_cAppPath1stComp = 0;
  553. g_wszProgramFilesCommon[0] = L'\0';
  554. g_czProgramFilesCommon = 0;
  555. //
  556. // Clear the enviornment variables.
  557. //
  558. SetEnvironmentVariable(L"APPPATH", NULL);
  559. SetEnvironmentVariable(L"APPDRIVE", NULL);
  560. }
  561. BOOL
  562. LuapInitializeOldLists(
  563. HWND hDlg
  564. )
  565. {
  566. InitializeListHead(&g_OldStaticList);
  567. InitializeListHead(&g_DynamicList);
  568. if (LuapFillInList(g_LuaData.strStaticList, &g_OldStaticList) &&
  569. LuapFillInList(g_LuaData.strDynamicList, &g_DynamicList)) {
  570. return TRUE;
  571. }
  572. MessageBox(hDlg,
  573. GetString(IDS_LUA_INIT_OLD_LISTS),
  574. g_pEntryLua->strAppName,
  575. MB_ICONERROR);
  576. return FALSE;
  577. }
  578. /*++
  579. Desc:
  580. Merges the list from <DATA> section and the COMMAND_LINE of LUARedirectFS.
  581. For each item in command line, look it up in <DATA> so we know how to display
  582. those items in <DATA> in the UI.
  583. --*/
  584. BOOL
  585. LuapMergeLists(
  586. BOOL bMergeOld, // Merge the old data from the <DATA> section.
  587. HWND hDlg
  588. )
  589. {
  590. g_bListsInitialized = TRUE;
  591. BOOL bIsSuccess = FALSE;
  592. if (!LuapInitializeOldLists(hDlg)) {
  593. return FALSE;
  594. }
  595. //
  596. // Initialize the new static list.
  597. //
  598. InitializeListHead(&g_NewStaticList);
  599. if (!LuapGetFileListFromFile(g_pEntryLua->strExeName, &g_NewStaticList)) {
  600. goto EXIT;
  601. }
  602. bMergeOld ? LuapTrackAppend() : LuapTrackFresh();
  603. bIsSuccess = TRUE;
  604. EXIT:
  605. if (!bIsSuccess) {
  606. LuapCleanup();
  607. }
  608. return bIsSuccess;
  609. }
  610. /*++
  611. Desc:
  612. Copy the data over - we don't want to modify the original copy until the user
  613. tells us to.
  614. --*/
  615. void
  616. LuapGetDataFromEntry(
  617. PLUADATA pLuaData
  618. )
  619. {
  620. //
  621. // We can set the redirect dirs now.
  622. //
  623. CSTRING strAllUserDir(L"%ALLUSERSPROFILE%\\Application Data\\");
  624. strAllUserDir += g_pEntryLua->strAppName;
  625. CSTRING strPerUserDir(L"%USERPROFILE%\\Application Data\\");
  626. strPerUserDir += g_pEntryLua->strAppName;
  627. g_LuaData.strAllUserDir = strAllUserDir;
  628. g_LuaData.strPerUserDir = strPerUserDir;
  629. if (pLuaData) {
  630. g_LuaData.strStaticList = pLuaData->strStaticList;
  631. g_LuaData.strDynamicList = pLuaData->strDynamicList;
  632. g_LuaData.strExcludedExtensions = pLuaData->strExcludedExtensions;
  633. g_TrackState = ((g_LuaData.strStaticList.isNULL() &&
  634. g_LuaData.strDynamicList.isNULL() &&
  635. g_LuaData.strExcludedExtensions.isNULL()) ?
  636. LUA_TRACK_NO :
  637. LUA_TRACK_YES);
  638. } else {
  639. g_TrackState = LUA_TRACK_NO;
  640. }
  641. }
  642. void
  643. LuapCopyItems(
  644. HWND hwndList
  645. )
  646. {
  647. int cItems = ListView_GetItemCount(hwndList);
  648. int iIndex = cItems;
  649. WCHAR wszItem[MAX_PATH] = L"";
  650. WCHAR wszRedirect[32] = L"";
  651. LVITEM lvi;
  652. int index;
  653. for (int i = 0 ; i < cItems; ++i) {
  654. if (ListView_GetItemState(hwndList, i, LVIS_SELECTED) == LVIS_SELECTED) {
  655. ListView_GetItemText(hwndList, i, 0, wszItem, MAX_PATH);
  656. ListView_GetItemText(hwndList, i, 1, wszRedirect, 32);
  657. //
  658. // Need to add the new item.
  659. //
  660. lvi.mask = LVIF_TEXT;
  661. lvi.lParam = 0;
  662. lvi.pszText = wszItem;
  663. lvi.iItem = iIndex++;
  664. lvi.iSubItem = 0;
  665. index = ListView_InsertItem(hwndList, &lvi);
  666. ListView_SetItemText(hwndList, index, 1, wszRedirect);
  667. }
  668. }
  669. }
  670. void
  671. LuapTokenizeItems(
  672. HWND hwndList,
  673. BOOL bUntokenize
  674. )
  675. {
  676. int cItems = ListView_GetItemCount(hwndList);
  677. WCHAR wszItem[MAX_PATH] = L"";
  678. WCHAR wszExpandItem[MAX_PATH] = L"";
  679. LPWSTR pwszUntokenizedItem = NULL;
  680. LVITEM lvi;
  681. int index;
  682. PLIST_ENTRY pEntry;
  683. PUNTOKENIZED_ITEM pItem;
  684. if (bUntokenize) {
  685. InitializeListHead(&g_UntokenizedList);
  686. } else {
  687. pEntry = g_UntokenizedList.Flink;
  688. }
  689. for (int i = 0 ; i < cItems; ++i) {
  690. ListView_GetItemText(hwndList, i, 0, wszItem, MAX_PATH);
  691. if (bUntokenize) {
  692. pItem = new UNTOKENIZED_ITEM;
  693. if (pItem == NULL) {
  694. MEM_ERR;
  695. return;
  696. }
  697. pItem->strName = wszItem;
  698. InsertTailList(&g_UntokenizedList, &pItem->entry);
  699. if (ExpandEnvironmentStrings(wszItem, wszExpandItem, MAX_PATH)) {
  700. pwszUntokenizedItem = wszExpandItem;
  701. } else {
  702. pwszUntokenizedItem = wszItem;
  703. }
  704. ListView_SetItemText(hwndList, i, 0, pwszUntokenizedItem);
  705. } else {
  706. pItem = CONTAINING_RECORD(pEntry, UNTOKENIZED_ITEM, entry);
  707. ListView_SetItemText(hwndList, i, 0, pItem->strName);
  708. pEntry = pEntry->Flink;
  709. }
  710. }
  711. if (!bUntokenize) {
  712. LuapDeleteList(&g_UntokenizedList);
  713. }
  714. }
  715. BOOL
  716. LuapSaveFileLists(
  717. HWND hwndList
  718. )
  719. {
  720. g_bListsInitialized = FALSE;
  721. BOOL bIsSuccess = FALSE;
  722. int nItems = ListView_GetItemCount(hwndList);
  723. int i, j;
  724. WCHAR wszItem[MAX_PATH + 3] = L"";
  725. WCHAR wszRedirect[MAX_PATH] = L"";
  726. BOOL bChecked, bRedirectAllUser;
  727. PLIST_ENTRY pHead = (g_bUseNewStaticList ? &g_NewStaticList : &g_OldStaticList);
  728. PLIST_ENTRY pEntry = pHead->Flink;
  729. PREDIRECT_ITEM pItem;
  730. //
  731. // For all the checked items we check if there are any duplicates.
  732. // Note that we don't allow duplicate items even if they are specified
  733. // to redirect to the same directory - because the position of the checked
  734. // items does matter (a checked item above another takes precedence over
  735. // that other one when redirected).
  736. //
  737. LPWSTR* ppTempCheckedItems = NULL;
  738. DWORD dwTempIndex = 0;
  739. g_LuaData.strStaticList.Release();
  740. g_LuaData.strDynamicList.Release();
  741. g_bAllUserDirUsed = FALSE;
  742. ppTempCheckedItems = new LPWSTR [nItems];
  743. if (!ppTempCheckedItems) {
  744. MEM_ERR;
  745. goto EXIT;
  746. }
  747. for (i = 0; i < nItems; ++i) {
  748. ListView_GetItemText(hwndList, i, 1, wszRedirect, MAX_PATH);
  749. bRedirectAllUser = !wcscmp(wszRedirect, GetString(IDS_LUA_RDIR_ALLUSER));
  750. wszItem[0] = (bRedirectAllUser ? L'A' : L'P');
  751. bChecked = ListView_GetCheckState(hwndList, i);
  752. wszItem[1] = (bChecked ? L'C' : L'U');
  753. wszItem[2] = L'-';
  754. wszItem[3] = L'\0';
  755. if (bRedirectAllUser && bChecked) {
  756. g_bAllUserDirUsed = TRUE;
  757. }
  758. if (bChecked) {
  759. ppTempCheckedItems[dwTempIndex] = new WCHAR [MAX_PATH];
  760. if (!ppTempCheckedItems[dwTempIndex]) {
  761. MEM_ERR;
  762. goto EXIT;
  763. }
  764. ++dwTempIndex;
  765. }
  766. if (i < g_nStaticItems) {
  767. pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  768. g_LuaData.strStaticList.Strcat(wszItem);
  769. g_LuaData.strStaticList.Strcat(pItem->strName);
  770. g_LuaData.strStaticList.Strcat(L";");
  771. if (bChecked) {
  772. StringCchCopy(
  773. ppTempCheckedItems[dwTempIndex - 1],
  774. MAX_PATH,
  775. pItem->strName);
  776. }
  777. pEntry = pEntry->Flink;
  778. } else {
  779. ListView_GetItemText(hwndList, i, 0, wszItem + 3, MAX_PATH);
  780. if (bChecked) {
  781. for (j = 0; j < dwTempIndex - 1; ++j) {
  782. if (!_wcsicmp(ppTempCheckedItems[j], wszItem + 3)) {
  783. CSTRING strMessage;
  784. strMessage.Sprintf(
  785. L"%s was already in the list. Please remove one.",
  786. wszItem + 3);
  787. MessageBox(
  788. NULL,
  789. strMessage,
  790. g_pEntryLua->strAppName,
  791. MB_ICONERROR);
  792. goto EXIT;
  793. }
  794. }
  795. StringCchCopy(
  796. ppTempCheckedItems[dwTempIndex - 1],
  797. MAX_PATH,
  798. wszItem + 3);
  799. }
  800. StringCchCat(wszItem, ARRAYSIZE(wszItem), L";");
  801. g_LuaData.strDynamicList.Strcat(wszItem);
  802. }
  803. }
  804. int cLen = g_LuaData.strStaticList.Length();
  805. g_LuaData.strStaticList.SetChar(cLen - 1, L'\0');
  806. cLen = g_LuaData.strDynamicList.Length();
  807. g_LuaData.strDynamicList.SetChar(cLen - 1, L'\0');
  808. bIsSuccess = TRUE;
  809. EXIT:
  810. for (i = 0; i < dwTempIndex; ++i) {
  811. delete [] ppTempCheckedItems[i];
  812. }
  813. if (ppTempCheckedItems) {
  814. delete [] ppTempCheckedItems;
  815. }
  816. if (bIsSuccess) {
  817. //
  818. // We want to keep the lists in case of failure because we
  819. // can come back and try again.
  820. //
  821. LuapDeleteList(&g_OldStaticList);
  822. LuapDeleteList(&g_NewStaticList);
  823. LuapDeleteList(&g_DynamicList);
  824. g_bUseNewStaticList = FALSE;
  825. }
  826. return bIsSuccess;
  827. }
  828. void
  829. LuapEditCell(
  830. HWND hwndList,
  831. int iItem,
  832. int iSubItem
  833. )
  834. {
  835. //
  836. // If the user holds down shift or control while clicking,
  837. // it means he wants to select multiple rows. We'll let
  838. // the listview handle it.
  839. //
  840. SHORT sStateShift = GetAsyncKeyState(VK_SHIFT);
  841. SHORT sStateControl = GetAsyncKeyState(VK_CONTROL);
  842. if (sStateShift & (1 << 15) ||
  843. sStateControl & (1 << 15)) {
  844. return;
  845. }
  846. if (iSubItem) {
  847. //
  848. // Before we display the combobox, we need to
  849. // de-select all items in the listview.
  850. //
  851. int index = -1;
  852. while ((index = ListView_GetNextItem(hwndList, index, LVIS_SELECTED)) != -1) {
  853. ListView_SetItemState(hwndList, index, 0, LVIS_SELECTED);
  854. }
  855. RECT rect, rectListView, rectParent;
  856. WCHAR szText[MAX_PATH];
  857. HWND hwnd = GetParent(hwndList);
  858. GetWindowRect(hwndList, &rectListView);
  859. GetWindowRect(hwnd, &rectParent);
  860. g_iCurrentEditItem = iItem;
  861. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
  862. LVITEM lvi;
  863. lvi.mask = LVIF_TEXT;
  864. lvi.lParam = 0;
  865. lvi.pszText = szText;
  866. lvi.cchTextMax = MAX_PATH;
  867. lvi.iItem = iItem;
  868. lvi.iSubItem = iSubItem;
  869. ListView_GetSubItemRect(hwndList, iItem, iSubItem, LVIR_LABEL, &rect);
  870. ListView_GetItem(hwndList, &lvi);
  871. //
  872. // Move the combobox to cover this item.
  873. //
  874. HWND hwndCombo = GetDlgItem(hwnd, IDC_LUA_RDIR);
  875. MoveWindow(hwndCombo,
  876. rect.left + rectListView.left - rectParent.left + 2,
  877. rect.top + rectListView.top - rectParent.top + 1,
  878. rect.right - rect.left,
  879. rect.bottom - rect.top - 7, TRUE);
  880. SetFocus(hwndCombo);
  881. ShowWindow(hwndCombo, SW_SHOW);
  882. ListView_SetItemState(hwndList, iItem, LVIS_FOCUSED, LVIS_FOCUSED);
  883. int nID = (wcscmp(lvi.pszText, GetString(IDS_LUA_RDIR_PERUSER)) ? 0 : 1);
  884. SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM)nID, 0);
  885. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
  886. }
  887. }
  888. BOOL
  889. LuapSetAppEnvVars(
  890. HWND hDlg)
  891. {
  892. BOOL bIsSuccess = TRUE;
  893. CSTRING strFullPath;
  894. LPWSTR pwsz = NULL;
  895. if (g_bHasAppPathSet) {
  896. goto EXIT;
  897. }
  898. strFullPath = g_pEntryLua->strFullpath;
  899. pwsz = strFullPath;
  900. if (g_pEntryLua->strFullpath.isNULL()) {
  901. goto EXIT;
  902. }
  903. bIsSuccess = FALSE;
  904. LPWSTR pwszLastSlash = wcsrchr(pwsz, L'\\');
  905. if (pwszLastSlash == NULL) {
  906. MessageBox(hDlg,
  907. L"The full path doesn't contain a '\\'?",
  908. g_pEntryLua->strAppName,
  909. MB_ICONERROR);
  910. goto EXIT;
  911. }
  912. *pwszLastSlash = L'\0';
  913. g_cAppPath = wcslen(pwsz);
  914. if (g_cAppPath >= ARRAYSIZE(g_wszAppPath)) {
  915. MessageBox(hDlg,
  916. L"Exe path too long - we don't handle it",
  917. g_pEntryLua->strAppName,
  918. MB_ICONERROR);
  919. g_cAppPath = 0;
  920. goto EXIT;
  921. }
  922. wcsncpy(g_wszAppPath, pwsz, g_cAppPath);
  923. g_wszAppPath[g_cAppPath] = L'\0';
  924. LPWSTR pwsz1stComp = wcschr(g_wszAppPath, L'\\');
  925. if (pwsz1stComp) {
  926. if (pwsz1stComp = wcschr(pwsz1stComp + 1, L'\\')) {
  927. g_cAppPath1stComp = pwsz1stComp - g_wszAppPath + 1;
  928. }
  929. }
  930. SetEnvironmentVariable(L"APPPATH", pwsz);
  931. *(pwsz + 2) = L'\0';
  932. SetEnvironmentVariable(L"APPDRIVE", pwsz);
  933. g_bHasAppPathSet = TRUE;
  934. bIsSuccess = TRUE;
  935. EXIT:
  936. return bIsSuccess;
  937. }
  938. INT_PTR
  939. CALLBACK
  940. LuapAction(
  941. HWND hDlg,
  942. UINT uMsg,
  943. WPARAM wParam,
  944. LPARAM lParam
  945. )
  946. {
  947. LPARAM buttons;
  948. switch (uMsg) {
  949. case WM_INITDIALOG:
  950. {
  951. HWND hwndParent = GetParent(hDlg);
  952. CenterWindow(GetParent(hwndParent), hwndParent);
  953. SetWindowText(hwndParent, GetString(IDS_LUA_WIZARD_TITLE));
  954. //
  955. // Fill in the executable name.
  956. //
  957. SetDlgItemText(hDlg, IDC_LUA_EXE, g_pEntryLua->strExeName);
  958. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_MODIFY_DATA), (g_TrackState == LUA_TRACK_YES));
  959. CheckDlgButton(hDlg,
  960. (g_TrackState == LUA_TRACK_YES ? IDC_LUA_MODIFY_DATA : IDC_LUA_RUN_PROGRAM),
  961. BST_CHECKED);
  962. //
  963. // Set the appropriate description
  964. //
  965. SetDlgItemText(hDlg, IDC_DESCRIPTION,
  966. (g_TrackState == LUA_TRACK_NO ?
  967. GetString(IDS_LUA_DESC_NODATA) :
  968. GetString(IDS_LUA_DESC_DATA)));
  969. buttons = 0;
  970. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  971. }
  972. break;
  973. case WM_NOTIFY:
  974. {
  975. NMHDR * pHdr = (NMHDR *) lParam;
  976. switch (pHdr->code) {
  977. case PSN_SETACTIVE:
  978. {
  979. buttons = PSWIZB_NEXT;
  980. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  981. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_MODIFY_DATA), (g_TrackState == LUA_TRACK_YES));
  982. if (g_TrackState == LUA_TRACK_YES &&
  983. IsDlgButtonChecked(hDlg, IDC_LUA_RUN_PROGRAM)) {
  984. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), TRUE);
  985. } else {
  986. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), FALSE);
  987. }
  988. }
  989. break;
  990. case PSN_WIZNEXT:
  991. {
  992. BOOL bIsSuccess = FALSE;
  993. g_bUseNewStaticList = TRUE;
  994. if (IsDlgButtonChecked(hDlg, IDC_LUA_RUN_PROGRAM) == BST_CHECKED) {
  995. buttons = PSWIZB_NEXT;
  996. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  997. BOOL bMergeOld = (g_TrackState == LUA_TRACK_YES &&
  998. IsDlgButtonChecked(hDlg, IDC_LUA_OVERRIDE) == BST_UNCHECKED);
  999. //
  1000. // Apply the LUATrackFS shim to the executable.
  1001. //
  1002. CSTRING strExeName = (g_pEntryLua->strFullpath.isNULL() ?
  1003. g_pEntryLua->strExeName :
  1004. g_pEntryLua->strFullpath);
  1005. CSTRINGLIST strlXML;
  1006. if (LuapGenerateTrackXML(g_pEntryLua, &strlXML)) {
  1007. if (TestRun(g_pEntryLua, &strExeName, NULL, hDlg, &strlXML)) {
  1008. //
  1009. // Set the new enviorment variables APPPATH and APPDRIVE.
  1010. //
  1011. if (g_pEntryLua->strFullpath.isNULL()) {
  1012. g_pEntryLua->strFullpath = strExeName;
  1013. }
  1014. if (!LuapSetAppEnvVars(hDlg)) {
  1015. goto RETURN;
  1016. }
  1017. //
  1018. // There should be a file generated by the LUATrackFS shim in AppPatch.
  1019. // We will merge this with the original data.
  1020. //
  1021. if (LuapMergeLists(bMergeOld, hDlg)) {
  1022. g_TrackState = LUA_TRACK_YES;
  1023. bIsSuccess = TRUE;
  1024. } else {
  1025. MessageBox(hDlg,
  1026. GetString(IDS_LUA_MERGE_LIST),
  1027. g_pEntryLua->strAppName,
  1028. MB_ICONERROR);
  1029. }
  1030. }
  1031. } else {
  1032. MessageBox(hDlg,
  1033. GetString(IDS_LUA_TRACKXML),
  1034. g_pEntryLua->strAppName,
  1035. MB_ICONERROR);
  1036. }
  1037. } else {
  1038. //
  1039. // Initialize the old static and the dynamic list.
  1040. //
  1041. if (LuapInitializeOldLists(hDlg)) {
  1042. g_bUseNewStaticList = FALSE;
  1043. bIsSuccess = TRUE;
  1044. }
  1045. }
  1046. RETURN:
  1047. //
  1048. // Prevent from going to the next page if any error occured.
  1049. //
  1050. if (!bIsSuccess) {
  1051. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
  1052. }
  1053. }
  1054. break;
  1055. }
  1056. }
  1057. break;
  1058. case WM_COMMAND:
  1059. switch (LOWORD(wParam)) {
  1060. case IDC_LUA_RUN_PROGRAM:
  1061. case IDC_LUA_MODIFY_DATA:
  1062. if (IsDlgButtonChecked(hDlg, IDC_LUA_RUN_PROGRAM) == BST_CHECKED) {
  1063. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), (g_TrackState == LUA_TRACK_YES));
  1064. }
  1065. if (IsDlgButtonChecked(hDlg, IDC_LUA_MODIFY_DATA) == BST_CHECKED) {
  1066. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), FALSE);
  1067. }
  1068. buttons = PSWIZB_NEXT;
  1069. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  1070. break;
  1071. }
  1072. default:
  1073. return FALSE;
  1074. }
  1075. return TRUE;
  1076. }
  1077. void
  1078. LuapAddItemToListView(
  1079. HWND hwndList,
  1080. PLIST_ENTRY pEntry,
  1081. int i
  1082. )
  1083. {
  1084. PREDIRECT_ITEM pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry);
  1085. LVITEM lvi;
  1086. int index;
  1087. lvi.mask = LVIF_TEXT;
  1088. lvi.lParam = 0;
  1089. lvi.pszText = pItem->strName;
  1090. lvi.iItem = i;
  1091. lvi.iSubItem = 0;
  1092. index = ListView_InsertItem(hwndList, &lvi);
  1093. ListView_SetItemText(
  1094. hwndList,
  1095. index,
  1096. 1,
  1097. pItem->bRedirectToAllUser ?
  1098. GetString(IDS_LUA_RDIR_ALLUSER) :
  1099. GetString(IDS_LUA_RDIR_PERUSER));
  1100. ListView_SetCheckState(hwndList, index, pItem->bChecked);
  1101. }
  1102. void
  1103. LuapDeleteSelectedItems(
  1104. HWND hwndList
  1105. )
  1106. {
  1107. int index = -1;
  1108. while ((index = ListView_GetNextItem(hwndList, g_nStaticItems - 1, LVNI_SELECTED)) != -1) {
  1109. ListView_DeleteItem(hwndList, index);
  1110. }
  1111. }
  1112. inline void
  1113. LuapGetRGB(
  1114. COLORREF cr,
  1115. BYTE* pR,
  1116. BYTE* pG,
  1117. BYTE* pB
  1118. )
  1119. {
  1120. *pR = GetRValue(cr);
  1121. *pG = GetGValue(cr);
  1122. *pB = GetBValue(cr);
  1123. }
  1124. inline void
  1125. LuapSwapColor(
  1126. BYTE* pFont,
  1127. BYTE* pBk
  1128. )
  1129. {
  1130. BYTE temp;
  1131. if (*pFont > *pBk) {
  1132. temp = *pFont;
  1133. *pFont = *pBk;
  1134. *pBk = temp;
  1135. }
  1136. }
  1137. // font is garanteed to be less than bk.
  1138. inline BYTE
  1139. LuapGetHalfColor(
  1140. BYTE font,
  1141. BYTE bk
  1142. )
  1143. {
  1144. return (font + (bk - font) / 2);
  1145. }
  1146. COLORREF
  1147. LuapGetHalfIntensity(
  1148. COLORREF crFont,
  1149. COLORREF crBk
  1150. )
  1151. {
  1152. BYTE rFont, gFont, bFont, rBk, gBk, bBk;
  1153. LuapGetRGB(crFont, &rFont, &gFont, &bFont);
  1154. LuapGetRGB(crBk, &rBk, &gBk, &bBk);
  1155. //
  1156. // if the value of the text is greater than that of the Bk, we swap them.
  1157. //
  1158. LuapSwapColor(&rFont, &rBk);
  1159. LuapSwapColor(&gFont, &gBk);
  1160. LuapSwapColor(&bFont, &bBk);
  1161. //
  1162. // The half color is computed as the lower value + half of the difference
  1163. // between the higher and the lower value.
  1164. BYTE rHalf = LuapGetHalfColor(rFont, rBk);
  1165. BYTE gHalf = LuapGetHalfColor(gFont, gBk);
  1166. BYTE bHalf = LuapGetHalfColor(bFont, bBk);
  1167. return RGB(rHalf, gHalf, bHalf);
  1168. }
  1169. typedef enum {
  1170. CM_SELECT,
  1171. CM_DESELECT,
  1172. CM_REDIRECT_ALLUSER,
  1173. CM_REDIRECT_PERUSER,
  1174. CM_REDIRECT_LASTINDEX
  1175. } LUA_CM_INDEX;
  1176. BOOL
  1177. LuapDisplayContextMenu(
  1178. HWND hwndList,
  1179. POINT* ppt)
  1180. {
  1181. int i;
  1182. if (g_hContextMenu == NULL) {
  1183. g_hContextMenu = CreatePopupMenu();
  1184. if (g_hContextMenu == NULL) {
  1185. MessageBox(
  1186. hwndList,
  1187. GetString(IDS_LUA_ERROR_CM),
  1188. g_pEntryLua->strAppName,
  1189. MB_ICONERROR);
  1190. return FALSE;
  1191. }
  1192. CSTRING strItems[CM_REDIRECT_LASTINDEX];
  1193. strItems[CM_SELECT] = GetString(IDS_LUA_CM_SELECT);
  1194. strItems[CM_DESELECT] = GetString(IDS_LUA_CM_DESELECT);
  1195. strItems[CM_REDIRECT_ALLUSER] = GetString(IDS_LUA_CM_REDIRECT_ALLUSER);
  1196. strItems[CM_REDIRECT_PERUSER] = GetString(IDS_LUA_CM_REDIRECT_PERUSER);
  1197. MENUITEMINFO mi = {0};
  1198. mi.cbSize = sizeof(MENUITEMINFO);
  1199. mi.fMask = MIIM_STRING | MIIM_ID;
  1200. for (i = 0; i < CM_REDIRECT_LASTINDEX; ++i) {
  1201. mi.dwTypeData = strItems[i];
  1202. mi.cch = wcslen(mi.dwTypeData);
  1203. mi.wID = i + 1;
  1204. InsertMenuItem(g_hContextMenu, i, TRUE, &mi);
  1205. }
  1206. }
  1207. //
  1208. // Disable the corresponding item in the context menu if all the selected items
  1209. // already have that attribute, eg, if all of them are checked already, "Select"
  1210. // should be disabled.
  1211. //
  1212. BOOL bChecked, bUnchecked, bPerUser, bAllUser;
  1213. bChecked = bUnchecked = bPerUser = bAllUser = TRUE;
  1214. int cItems = ListView_GetItemCount(hwndList);
  1215. WCHAR wszRedirect[32] = L"";
  1216. for (i = 0 ; i < cItems; ++i) {
  1217. if (ListView_GetItemState(hwndList, i, LVIS_SELECTED) == LVIS_SELECTED) {
  1218. if (ListView_GetCheckState(hwndList, i)) {
  1219. bUnchecked = FALSE;
  1220. } else {
  1221. bChecked = FALSE;
  1222. }
  1223. ListView_GetItemText(hwndList, i, 1, wszRedirect, 32);
  1224. if (!wcscmp(wszRedirect, GetString(IDS_LUA_RDIR_ALLUSER))) {
  1225. bPerUser = FALSE;
  1226. } else {
  1227. bAllUser = FALSE;
  1228. }
  1229. }
  1230. }
  1231. if (bChecked) {
  1232. EnableMenuItem(g_hContextMenu, CM_SELECT, MF_BYPOSITION | MF_GRAYED);
  1233. }
  1234. if (bUnchecked) {
  1235. EnableMenuItem(g_hContextMenu, CM_DESELECT, MF_BYPOSITION | MF_GRAYED);
  1236. }
  1237. if (bAllUser) {
  1238. EnableMenuItem(g_hContextMenu, CM_REDIRECT_ALLUSER, MF_BYPOSITION | MF_GRAYED);
  1239. }
  1240. if (bPerUser) {
  1241. EnableMenuItem(g_hContextMenu, CM_REDIRECT_PERUSER, MF_BYPOSITION | MF_GRAYED);
  1242. }
  1243. UINT nIDSelected = TrackPopupMenuEx(g_hContextMenu,
  1244. TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
  1245. ppt->x,
  1246. ppt->y,
  1247. hwndList,
  1248. NULL);
  1249. int iCheck, iRedirectAllUser;
  1250. iCheck = iRedirectAllUser = -1;
  1251. iCheck = (nIDSelected == CM_SELECT + 1 ? 1 :
  1252. nIDSelected == CM_DESELECT + 1 ? 0 : -1);
  1253. iRedirectAllUser = (nIDSelected == CM_REDIRECT_ALLUSER + 1 ? 1 :
  1254. nIDSelected == CM_REDIRECT_PERUSER + 1 ? 0 : -1);
  1255. for (i = 0 ; i < cItems; ++i) {
  1256. if (ListView_GetItemState(hwndList, i, LVIS_SELECTED) == LVIS_SELECTED) {
  1257. if (iCheck != -1) {
  1258. if (ListView_GetCheckState(hwndList, i) != (BOOL)iCheck) {
  1259. ListView_SetCheckState(hwndList, i, (BOOL)iCheck);
  1260. }
  1261. }
  1262. if (iRedirectAllUser != -1) {
  1263. ListView_GetItemText(hwndList, i, 1, wszRedirect, 32);
  1264. if (!wcscmp(wszRedirect, GetString(IDS_LUA_RDIR_ALLUSER)) !=
  1265. (BOOL)iRedirectAllUser) {
  1266. ListView_SetItemText(
  1267. hwndList,
  1268. i,
  1269. 1,
  1270. GetString((BOOL)iRedirectAllUser ?
  1271. IDS_LUA_RDIR_ALLUSER :
  1272. IDS_LUA_RDIR_PERUSER));
  1273. }
  1274. }
  1275. }
  1276. }
  1277. //
  1278. // Restore the state of menu items.
  1279. //
  1280. for (i = 0; i < CM_REDIRECT_LASTINDEX; ++i) {
  1281. EnableMenuItem(g_hContextMenu, i, MF_BYPOSITION | MF_ENABLED);
  1282. }
  1283. return TRUE;
  1284. }
  1285. //
  1286. // dwRefData stores the index of the item that this edit control covers.
  1287. //
  1288. LRESULT CALLBACK
  1289. ListViewEditControlSubclass(HWND hwndEdit, UINT uMsg, WPARAM wParam,
  1290. LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
  1291. {
  1292. if (uMsg == WM_SIZE) {
  1293. DefSubclassProc(hwndEdit, uMsg, wParam, lParam);
  1294. HWND hwndList = GetParent(hwndEdit);
  1295. RECT rect;
  1296. ListView_GetItemRect(hwndList, dwRefData, &rect, LVIR_LABEL);
  1297. MoveWindow(
  1298. hwndEdit,
  1299. rect.left,
  1300. rect.top,
  1301. rect.right - rect.left,
  1302. rect.bottom - rect.top, TRUE);
  1303. return TRUE;
  1304. }
  1305. return DefSubclassProc(hwndEdit, uMsg, wParam, lParam);
  1306. }
  1307. LRESULT CALLBACK
  1308. ListViewSubclass(HWND hwndList, UINT uMsg, WPARAM wParam,
  1309. LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
  1310. {
  1311. if (uMsg == WM_LBUTTONDOWN) {
  1312. LVHITTESTINFO lvhti;
  1313. GetCursorPos(&lvhti.pt);
  1314. ScreenToClient(hwndList, &lvhti.pt);
  1315. if (ListView_SubItemHitTest(hwndList, &lvhti) != -1 && lvhti.iSubItem != 0) {
  1316. ListView_SetItemState(hwndList, lvhti.iItem, 0, LVIS_SELECTED);
  1317. ListView_SetItemState(hwndList, lvhti.iItem, 0, LVIS_FOCUSED);
  1318. LuapEditCell(hwndList, lvhti.iItem, lvhti.iSubItem);
  1319. return TRUE;
  1320. }
  1321. } else if (uMsg == WM_VSCROLL) {
  1322. if (wParam == SB_PAGEUP || wParam == SB_PAGEDOWN || wParam == SB_LINEUP || wParam == SB_LINEDOWN) {
  1323. DefSubclassProc(hwndList, uMsg, wParam, lParam);
  1324. InvalidateRect(hwndList, NULL, FALSE);
  1325. return TRUE;
  1326. }
  1327. }
  1328. return DefSubclassProc(hwndList, uMsg, wParam, lParam);
  1329. }
  1330. BOOL
  1331. LuapIsItemDuplicate(
  1332. HWND hwndList,
  1333. LPCWSTR pszText,
  1334. int iItem
  1335. )
  1336. {
  1337. int cItems = ListView_GetItemCount(hwndList);
  1338. WCHAR wszItem[MAX_PATH] = L"";
  1339. LVITEM lvi;
  1340. for (int i = 0 ; i < cItems; ++i) {
  1341. if (i != iItem) {
  1342. ListView_GetItemText(hwndList, i, 0, wszItem, MAX_PATH);
  1343. if (!_wcsicmp(wszItem, pszText)) {
  1344. return TRUE;
  1345. }
  1346. }
  1347. }
  1348. return FALSE;
  1349. }
  1350. /*++
  1351. Desc:
  1352. Rules of moving an item up or down:
  1353. 1) We don't allow moving multiple items.
  1354. 2) If there's no items selected, this function simply does nothing.
  1355. 3) We don't change the static item list so you can't move a dynamic
  1356. item to inbetween 2 static ones.
  1357. --*/
  1358. void
  1359. LuapMoveListViewItem(
  1360. HWND hwndList,
  1361. int wCode
  1362. )
  1363. {
  1364. UINT cSelectedItems = ListView_GetSelectedCount(hwndList);
  1365. if (cSelectedItems > 1) {
  1366. MessageBox(
  1367. hwndList,
  1368. GetString(IDS_LUA_TOO_MANY_SELECTED),
  1369. g_pEntryLua->strAppName,
  1370. MB_ICONERROR);
  1371. return;
  1372. }
  1373. int iSelectedIndex = ListView_GetNextItem(
  1374. hwndList,
  1375. -1,
  1376. LVIS_SELECTED);
  1377. int cItems = ListView_GetItemCount(hwndList);
  1378. if (iSelectedIndex >= g_nStaticItems) {
  1379. if ((wCode == IDC_LUA_UP && iSelectedIndex == g_nStaticItems) ||
  1380. (wCode == IDC_LUA_DOWN && iSelectedIndex == (cItems - 1))) {
  1381. //
  1382. // Can't move the first item up or the last item down.
  1383. //
  1384. return;
  1385. }
  1386. int iNewIndex =
  1387. (wCode == IDC_LUA_UP ?
  1388. (iSelectedIndex - 1) :
  1389. (iSelectedIndex + 1));
  1390. BOOL bChecked = ListView_GetCheckState(hwndList, iSelectedIndex);
  1391. WCHAR wszText[MAX_PATH];
  1392. WCHAR wszRedirect[32];
  1393. ListView_GetItemText(hwndList, iSelectedIndex, 0, wszText, MAX_PATH);
  1394. ListView_GetItemText(hwndList, iSelectedIndex, 1, wszRedirect, 32);
  1395. ListView_DeleteItem(hwndList, iSelectedIndex);
  1396. LVITEM lvi;
  1397. lvi.mask = LVIF_TEXT;
  1398. lvi.lParam = 0;
  1399. lvi.pszText = wszText;
  1400. lvi.iItem = iNewIndex;
  1401. lvi.iSubItem = 0;
  1402. ListView_InsertItem(hwndList, &lvi);
  1403. ListView_SetItemText(hwndList, iNewIndex, 1, wszRedirect);
  1404. ListView_SetCheckState(hwndList, iNewIndex, bChecked);
  1405. SetFocus(hwndList);
  1406. ListView_SetItemState(hwndList, iNewIndex, LVIS_SELECTED, LVIS_SELECTED);
  1407. }
  1408. }
  1409. INT_PTR
  1410. CALLBACK
  1411. LuapEditFileList(
  1412. HWND hDlg,
  1413. UINT uMsg,
  1414. WPARAM wParam,
  1415. LPARAM lParam
  1416. )
  1417. {
  1418. int wCode = LOWORD(wParam);
  1419. int wNotifyCode = HIWORD(wParam);
  1420. switch (uMsg) {
  1421. case WM_INITDIALOG:
  1422. {
  1423. ShowWindow(GetDlgItem(hDlg, IDC_LUA_FILE_EDIT), SW_HIDE);
  1424. HWND hwndCombo = GetDlgItem(hDlg, IDC_LUA_RDIR);
  1425. SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)GetString(IDS_LUA_RDIR_PERUSER));
  1426. SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)GetString(IDS_LUA_RDIR_ALLUSER));
  1427. ShowWindow(hwndCombo, SW_HIDE);
  1428. ShowWindow(GetDlgItem(hDlg, IDC_LUA_EDIT_BROWSE), SW_HIDE);
  1429. HWND hwndUpButton = GetDlgItem(hDlg, IDC_LUA_UP);
  1430. HWND hwndDownButton = GetDlgItem(hDlg, IDC_LUA_DOWN);
  1431. SendMessage(hwndUpButton, WM_SETFONT, (WPARAM)g_hArrowFont, TRUE);
  1432. SendMessage(hwndDownButton, WM_SETFONT, (WPARAM)g_hArrowFont, TRUE);
  1433. SetWindowText(hwndUpButton, TEXT("\xE1"));
  1434. SetWindowText(hwndDownButton, TEXT("\xE2"));
  1435. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1436. SetWindowSubclass(hwndList, ListViewSubclass, 0, 0);
  1437. ListView_SetExtendedListViewStyleEx(
  1438. hwndList,
  1439. 0,
  1440. LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_GRIDLINES);
  1441. InsertColumnIntoListView(hwndList, CSTRING(IDS_LUA_FILEDIR_NAME), 0, 80);
  1442. InsertColumnIntoListView(hwndList, CSTRING(IDS_LUA_REDIRECT), 1, 20);
  1443. //
  1444. // Set the column width of the last column of the list view appropriately
  1445. // to cover the width of the list view
  1446. // Assumption: The list veiw has two columns
  1447. //
  1448. ListView_SetColumnWidth(hwndList,
  1449. 1,
  1450. LVSCW_AUTOSIZE_USEHEADER);
  1451. }
  1452. break;
  1453. case WM_NOTIFY:
  1454. {
  1455. NMHDR * pHdr = (NMHDR *) lParam;
  1456. switch (pHdr->code) {
  1457. case PSN_SETACTIVE:
  1458. {
  1459. if (!LuapSetAppEnvVars(hDlg)) {
  1460. //
  1461. // Prevent from going to the next page if any error occured.
  1462. //
  1463. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
  1464. break;
  1465. }
  1466. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UNTOK), g_bHasAppPathSet);
  1467. LPARAM buttons = PSWIZB_BACK | PSWIZB_NEXT;
  1468. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  1469. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1470. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
  1471. //
  1472. // First delete all items
  1473. //
  1474. int i;
  1475. int cItems = ListView_GetItemCount(hwndList);
  1476. for (i = 0; i < cItems; ++i) {
  1477. ListView_DeleteItem(hwndList, 0);
  1478. }
  1479. //
  1480. // If the lists are not there, it means we are back from the
  1481. // Exclusion or the Common Path page, regenerate the lists.
  1482. //
  1483. if (!g_bListsInitialized) {
  1484. LuapInitializeOldLists(hDlg);
  1485. }
  1486. //
  1487. //
  1488. // Populate the static items.
  1489. //
  1490. i = 0;
  1491. PLIST_ENTRY pHead = (g_bUseNewStaticList ?
  1492. &g_NewStaticList :
  1493. &g_OldStaticList);
  1494. for (PLIST_ENTRY pEntry = pHead->Flink;
  1495. pEntry != pHead;
  1496. pEntry = pEntry->Flink) {
  1497. LuapAddItemToListView(hwndList, pEntry, i);
  1498. ++i;
  1499. }
  1500. g_nStaticItems = i;
  1501. //
  1502. // Populate the dynamic items.
  1503. //
  1504. pHead = &g_DynamicList;
  1505. for (PLIST_ENTRY pEntry = pHead->Flink;
  1506. pEntry != pHead;
  1507. pEntry = pEntry->Flink) {
  1508. LuapAddItemToListView(hwndList, pEntry, i);
  1509. ++i;
  1510. }
  1511. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
  1512. g_TrackState = LUA_TRACK_YES;
  1513. }
  1514. break;
  1515. case PSN_WIZNEXT:
  1516. case PSN_WIZBACK:
  1517. {
  1518. //
  1519. // Save the static and the dynamic lists.
  1520. //
  1521. if (!LuapSaveFileLists(GetDlgItem(hDlg, IDC_LUA_FILE_LIST))) {
  1522. //
  1523. // Prevent from going to the next page if any error occured.
  1524. //
  1525. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
  1526. }
  1527. }
  1528. break;
  1529. case PSN_RESET:
  1530. {
  1531. LuapCleanup();
  1532. }
  1533. break;
  1534. case NM_CLICK:
  1535. {
  1536. if (g_bDuringUntokenize) {
  1537. //
  1538. // When we show the items untokenized, we don't allow the users
  1539. // to edit anything.
  1540. //
  1541. break;
  1542. }
  1543. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1544. LVHITTESTINFO lvhti;
  1545. GetCursorPos(&lvhti.pt);
  1546. ScreenToClient(hwndList, &lvhti.pt);
  1547. if (ListView_SubItemHitTest(hwndList, &lvhti) != -1) {
  1548. //
  1549. // If the user clicked on a subitem, we need to show the combo box.
  1550. //
  1551. LuapEditCell(hwndList, lvhti.iItem, lvhti.iSubItem);
  1552. } else {
  1553. //
  1554. // Check if the user clicked on the row right below the last item,
  1555. // which means he wants to add a new row.
  1556. //
  1557. int iLastItem = ListView_GetItemCount(hwndList);
  1558. RECT rect;
  1559. g_bNewListViewItem = FALSE;
  1560. if (iLastItem == 0) {
  1561. g_bNewListViewItem = TRUE;
  1562. } else {
  1563. ListView_GetItemRect(
  1564. hwndList,
  1565. iLastItem - 1,
  1566. &rect,
  1567. LVIR_LABEL);
  1568. LONG x = lvhti.pt.x;
  1569. LONG y = lvhti.pt.y;
  1570. LONG height = rect.bottom - rect.top;
  1571. if (x > rect.left &&
  1572. x < rect.right &&
  1573. y > rect.bottom &&
  1574. y < (rect.bottom + height)) {
  1575. g_bNewListViewItem = TRUE;
  1576. }
  1577. }
  1578. if (g_bNewListViewItem) {
  1579. LVITEM lvi;
  1580. int index;
  1581. lvi.mask = LVIF_TEXT;
  1582. lvi.lParam = 0;
  1583. lvi.pszText = L"";
  1584. lvi.iItem = iLastItem;
  1585. lvi.iSubItem = 0;
  1586. index = ListView_InsertItem(hwndList, &lvi);
  1587. ListView_SetItemText(
  1588. hwndList,
  1589. index,
  1590. 1,
  1591. GetString(IDS_LUA_RDIR_PERUSER));
  1592. SetFocus(hwndList);
  1593. ListView_EditLabel(hwndList, index);
  1594. g_iCurrentEditItem = iLastItem;
  1595. }
  1596. }
  1597. }
  1598. break;
  1599. case NM_RCLICK:
  1600. {
  1601. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1602. LVHITTESTINFO lvhti;
  1603. GetCursorPos(&lvhti.pt);
  1604. //
  1605. // Display a context menu for the user to (de)select the items
  1606. // and change the selection of the redirect dir.
  1607. //
  1608. LuapDisplayContextMenu(hwndList, &lvhti.pt);
  1609. }
  1610. break;
  1611. case LVN_ITEMCHANGED:
  1612. {
  1613. //
  1614. // If nothing is selected, the up/down and copy buttons will
  1615. // be disabled.
  1616. //
  1617. int index = -1;
  1618. BOOL bNoneSelected = TRUE;
  1619. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1620. while ((index = ListView_GetNextItem(hwndList, index, LVIS_SELECTED)) != -1) {
  1621. bNoneSelected = FALSE;
  1622. break;
  1623. }
  1624. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UP), !bNoneSelected && !g_bDuringUntokenize);
  1625. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_DOWN), !bNoneSelected && !g_bDuringUntokenize);
  1626. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_COPY), !bNoneSelected && !g_bDuringUntokenize);
  1627. }
  1628. break;
  1629. case LVN_BEGINSCROLL:
  1630. {
  1631. //
  1632. // When the scrolling begins, we need to hide the combobox.
  1633. //
  1634. ShowWindow(GetDlgItem(hDlg, IDC_LUA_RDIR), SW_HIDE);
  1635. SetFocus(GetDlgItem(hDlg, IDC_LUA_FILE_LIST));
  1636. }
  1637. break;
  1638. case LVN_KEYDOWN:
  1639. {
  1640. NMLVKEYDOWN* pnkd = (NMLVKEYDOWN*)lParam;
  1641. if (pnkd->wVKey == VK_DELETE) {
  1642. //
  1643. // Delete all the selected items.
  1644. //
  1645. LuapDeleteSelectedItems(GetDlgItem(hDlg, IDC_LUA_FILE_LIST));
  1646. }
  1647. }
  1648. break;
  1649. case LVN_BEGINLABELEDIT:
  1650. {
  1651. NMLVDISPINFO FAR *pdi = (NMLVDISPINFO FAR *) lParam;
  1652. LVITEM lvi = pdi->item;
  1653. BOOL bRet = (lvi.iItem < g_nStaticItems || g_bDuringUntokenize);
  1654. HWND hwndList = pdi->hdr.hwndFrom;
  1655. HWND hwndListViewEdit = ListView_GetEditControl(hwndList);
  1656. SendMessage(
  1657. hwndListViewEdit,
  1658. EM_LIMITTEXT,
  1659. (WPARAM)(MAX_PATH - 1),
  1660. (LPARAM)0);
  1661. SetWindowSubclass(hwndListViewEdit, ListViewEditControlSubclass, 0, lvi.iItem);
  1662. SHAutoComplete(hwndListViewEdit, AUTOCOMPLETE);
  1663. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)bRet);
  1664. return bRet;
  1665. }
  1666. case LVN_ENDLABELEDIT:
  1667. {
  1668. NMLVDISPINFO FAR *pdi = (NMLVDISPINFO FAR *) lParam;
  1669. LVITEM lvi = pdi->item;
  1670. BOOL bRet = FALSE;
  1671. if (lvi.iItem >= g_nStaticItems) {
  1672. int iLastItem = ListView_GetItemCount(pdi->hdr.hwndFrom) - 1;
  1673. if (g_bNewListViewItem && lvi.iItem == iLastItem &&
  1674. (lvi.pszText == NULL || lvi.pszText[0] == L'\0')) {
  1675. //
  1676. // if we are adding a new row, we delete it whether
  1677. // the user cancelled or typed in something then deleted
  1678. // it.
  1679. //
  1680. ListView_DeleteItem(pdi->hdr.hwndFrom, iLastItem);
  1681. g_bNewListViewItem = FALSE;
  1682. return bRet;
  1683. }
  1684. if (lvi.pszText && lvi.pszText[0] == L'\0') {
  1685. ListView_DeleteItem(pdi->hdr.hwndFrom, lvi.iItem);
  1686. } else {
  1687. CSTRING strCurrentItem = lvi.pszText;
  1688. if (lvi.pszText == NULL) {
  1689. if (!g_bNewListViewItem) {
  1690. //
  1691. // If the user cancelled editing, we should still check if it's a duplicated
  1692. // in case the user was editing a copied item.
  1693. //
  1694. WCHAR wszItem[MAX_PATH];
  1695. ListView_GetItemText(
  1696. pdi->hdr.hwndFrom,
  1697. lvi.iItem,
  1698. 0,
  1699. wszItem,
  1700. MAX_PATH);
  1701. strCurrentItem = wszItem;
  1702. }
  1703. } else {
  1704. if (g_bHasAppPathSet) {
  1705. //
  1706. // Tokenize it.
  1707. //
  1708. LPWSTR pwszItem = lvi.pszText;
  1709. if (!_wcsnicmp(pwszItem, g_wszAppPath, 2)) {
  1710. if (!LuapSubstituteProgramFilesCommon(pwszItem, strCurrentItem)) {
  1711. if (!LuapGetRelativeName(pwszItem, strCurrentItem)) {
  1712. strCurrentItem = L"%APPDRIVE%";
  1713. strCurrentItem.Strcat(pwszItem + 2);
  1714. }
  1715. }
  1716. }
  1717. }
  1718. }
  1719. if (strCurrentItem == TEXT("")) {
  1720. ListView_DeleteItem(pdi->hdr.hwndFrom, lvi.iItem);
  1721. } else {
  1722. ListView_SetItemText(pdi->hdr.hwndFrom, lvi.iItem, 0, strCurrentItem);
  1723. }
  1724. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)FALSE);
  1725. }
  1726. }
  1727. g_iCurrentEditItem = -1;
  1728. g_bNewListViewItem = FALSE;
  1729. }
  1730. break;
  1731. case NM_CUSTOMDRAW:
  1732. {
  1733. if (pHdr->hwndFrom == GetDlgItem(hDlg, IDC_LUA_FILE_LIST)) {
  1734. NMLVCUSTOMDRAW* pcd = (NMLVCUSTOMDRAW*)lParam;
  1735. switch (pcd->nmcd.dwDrawStage) {
  1736. case CDDS_PREPAINT:
  1737. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)CDRF_NOTIFYITEMDRAW);
  1738. return CDRF_NOTIFYITEMDRAW;
  1739. case CDDS_ITEMPREPAINT:
  1740. {
  1741. //
  1742. // If it's a dynamic item we just let the control draw itself.
  1743. //
  1744. if (pcd->nmcd.dwItemSpec >= g_nStaticItems) {
  1745. return CDRF_DODEFAULT;
  1746. }
  1747. //
  1748. // Use half of the intensity of the default font to draw the static items.
  1749. //
  1750. HDC hdc = pcd->nmcd.hdc;
  1751. COLORREF crFont = GetTextColor(hdc);
  1752. COLORREF crBk = GetBkColor(hdc);
  1753. pcd->clrText = LuapGetHalfIntensity(crFont, crBk);
  1754. return CDRF_NEWFONT;
  1755. }
  1756. }
  1757. return CDRF_DODEFAULT;
  1758. }
  1759. break;
  1760. }
  1761. }
  1762. break;
  1763. }
  1764. case WM_COMMAND:
  1765. if ((wNotifyCode == CBN_KILLFOCUS || wNotifyCode == CBN_SELCHANGE) &&
  1766. wCode == IDC_LUA_RDIR) {
  1767. HWND hwndCombo = GetDlgItem(hDlg, IDC_LUA_RDIR);
  1768. SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
  1769. ShowWindow(hwndCombo, SW_HIDE);
  1770. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1771. WCHAR wszText[MAX_PATH];
  1772. SendMessage(hwndCombo, WM_GETTEXT, MAX_PATH, (LPARAM)wszText);
  1773. ListView_SetItemText(hwndList, g_iCurrentEditItem, 1, wszText);
  1774. g_iCurrentEditItem = -1;
  1775. break;
  1776. }
  1777. if (wCode == IDC_LUA_UP || wCode == IDC_LUA_DOWN) {
  1778. LuapMoveListViewItem(GetDlgItem(hDlg, IDC_LUA_FILE_LIST), wCode);
  1779. break;
  1780. }
  1781. if (wCode == IDC_LUA_COPY) {
  1782. //
  1783. // Copy the selected items to the bottom of the list view.
  1784. //
  1785. g_bNewListViewItem = FALSE;
  1786. LuapCopyItems(GetDlgItem(hDlg, IDC_LUA_FILE_LIST));
  1787. break;
  1788. }
  1789. if (wCode == IDC_LUA_UNTOK) {
  1790. LPARAM buttons;
  1791. HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST);
  1792. //
  1793. // The "Show Untokenized" is only for convenience purposes so
  1794. // if the user check this checkbox, we need to disable the NEXT button,
  1795. // and disble editing, and prevent the user from going backward or forward
  1796. // in the wizard.
  1797. //
  1798. if (IsDlgButtonChecked(hDlg, IDC_LUA_UNTOK) == BST_CHECKED) {
  1799. buttons = 0;
  1800. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_COPY), FALSE);
  1801. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UP), FALSE);
  1802. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_DOWN), FALSE);
  1803. g_bDuringUntokenize = TRUE;
  1804. LuapTokenizeItems(hwndList, TRUE);
  1805. } else {
  1806. buttons = PSWIZB_BACK | PSWIZB_NEXT;
  1807. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_COPY), TRUE);
  1808. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UP), TRUE);
  1809. ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_DOWN), TRUE);
  1810. g_bDuringUntokenize = FALSE;
  1811. LuapTokenizeItems(hwndList, FALSE);
  1812. }
  1813. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  1814. }
  1815. default:
  1816. return FALSE;
  1817. }
  1818. return TRUE;
  1819. }
  1820. LONG
  1821. GetDefaultExclusionList()
  1822. {
  1823. HKEY hKey;
  1824. LONG lRet;
  1825. if ((lRet = RegOpenKeyEx(
  1826. HKEY_LOCAL_MACHINE,
  1827. LUA_APPCOMPAT_FLAGS_PATH,
  1828. 0,
  1829. KEY_QUERY_VALUE,
  1830. &hKey)) == ERROR_SUCCESS)
  1831. {
  1832. DWORD dwSize = 0;
  1833. if ((lRet = RegQueryValueEx(
  1834. hKey,
  1835. LUA_DEFAULT_EXCLUSION_LIST,
  1836. NULL,
  1837. NULL,
  1838. NULL,
  1839. &dwSize)) == ERROR_SUCCESS)
  1840. {
  1841. //
  1842. // Prefix problem. I mean prefix is a problem :-)
  1843. //
  1844. try{
  1845. g_pwszDefaultExclusionList = new WCHAR [dwSize];
  1846. } catch(...) {
  1847. g_pwszDefaultExclusionList = NULL;
  1848. }
  1849. if (g_pwszDefaultExclusionList)
  1850. {
  1851. if ((lRet = RegQueryValueEx(
  1852. hKey,
  1853. LUA_DEFAULT_EXCLUSION_LIST,
  1854. NULL,
  1855. NULL,
  1856. (LPBYTE)g_pwszDefaultExclusionList,
  1857. &dwSize)) != ERROR_SUCCESS)
  1858. {
  1859. delete [] g_pwszDefaultExclusionList;
  1860. g_pwszDefaultExclusionList = NULL;
  1861. }
  1862. }
  1863. else
  1864. {
  1865. MEM_ERR;
  1866. lRet = ERROR_NOT_ENOUGH_MEMORY;
  1867. }
  1868. }
  1869. REGCLOSEKEY(hKey);
  1870. }
  1871. return lRet;
  1872. }
  1873. INT_PTR
  1874. CALLBACK
  1875. LuapExclusion(
  1876. HWND hDlg,
  1877. UINT uMsg,
  1878. WPARAM wParam,
  1879. LPARAM lParam
  1880. )
  1881. {
  1882. int wCode = LOWORD(wParam);
  1883. int wNotifyCode = HIWORD(wParam);
  1884. switch (uMsg) {
  1885. case WM_INITDIALOG:
  1886. {
  1887. SendMessage(
  1888. GetDlgItem(hDlg, IDC_LUA_EXTS),
  1889. EM_LIMITTEXT,
  1890. (WPARAM)(MAX_STRING_SIZE - 1),
  1891. (LPARAM)0);
  1892. }
  1893. break;
  1894. case WM_NOTIFY:
  1895. {
  1896. NMHDR * pHdr = (NMHDR *) lParam;
  1897. switch (pHdr->code) {
  1898. case PSN_SETACTIVE:
  1899. {
  1900. LPARAM buttons = PSWIZB_BACK | PSWIZB_NEXT;
  1901. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  1902. LPWSTR pwszExcludedExtensions = L"";
  1903. if (g_LuaData.strExcludedExtensions.isNULL()) {
  1904. //
  1905. // We don't have lua data from the SDB, so display the default
  1906. // exclusion list.
  1907. //
  1908. if (!g_pwszDefaultExclusionList) {
  1909. //
  1910. // Don't need to check the return value - if we can't get
  1911. // it, just display an empty string.
  1912. //
  1913. GetDefaultExclusionList();
  1914. }
  1915. if (g_pwszDefaultExclusionList) {
  1916. pwszExcludedExtensions = g_pwszDefaultExclusionList;
  1917. }
  1918. } else {
  1919. pwszExcludedExtensions = g_LuaData.strExcludedExtensions;
  1920. }
  1921. SetDlgItemText(
  1922. hDlg,
  1923. IDC_LUA_EXTS,
  1924. pwszExcludedExtensions);
  1925. }
  1926. break;
  1927. case PSN_WIZNEXT:
  1928. case PSN_WIZBACK:
  1929. {
  1930. TCHAR szExcludedExtensions[MAX_STRING_SIZE];
  1931. GetDlgItemText(
  1932. hDlg,
  1933. IDC_LUA_EXTS,
  1934. szExcludedExtensions,
  1935. ARRAYSIZE(szExcludedExtensions));
  1936. g_LuaData.strExcludedExtensions = szExcludedExtensions;
  1937. }
  1938. break;
  1939. case PSN_RESET:
  1940. {
  1941. LuapCleanup();
  1942. }
  1943. break;
  1944. }
  1945. }
  1946. default:
  1947. return FALSE;
  1948. }
  1949. return TRUE;
  1950. }
  1951. void
  1952. LuapGetRedirectDirs(
  1953. HWND hDlg
  1954. )
  1955. {
  1956. WCHAR wszPath[MAX_PATH];
  1957. g_LuaData.strPerUserDir.Release();
  1958. g_LuaData.strAllUserDir.Release();
  1959. GetDlgItemText(hDlg, IDC_LUA_PERUSER_DIR, wszPath, ARRAYSIZE(wszPath));
  1960. if (wszPath[0] != L'\0') {
  1961. g_LuaData.strPerUserDir = wszPath;
  1962. }
  1963. GetDlgItemText(hDlg, IDC_LUA_ALLUSER_DIR, wszPath, ARRAYSIZE(wszPath));
  1964. if (wszPath[0] != L'\0') {
  1965. g_LuaData.strAllUserDir = wszPath;
  1966. }
  1967. }
  1968. INT_PTR
  1969. CALLBACK
  1970. LuapCommonPaths(
  1971. HWND hDlg,
  1972. UINT uMsg,
  1973. WPARAM wParam,
  1974. LPARAM lParam
  1975. )
  1976. {
  1977. int wCode = LOWORD(wParam);
  1978. int wNotifyCode = HIWORD(wParam);
  1979. LPARAM buttons;
  1980. switch (uMsg) {
  1981. case WM_NOTIFY:
  1982. {
  1983. NMHDR * pHdr = (NMHDR *) lParam;
  1984. switch (pHdr->code) {
  1985. case PSN_SETACTIVE:
  1986. {
  1987. buttons = PSWIZB_BACK | PSWIZB_FINISH;
  1988. SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons);
  1989. SetDlgItemText(hDlg, IDC_LUA_PERUSER_DIR, g_LuaData.strPerUserDir);
  1990. SetDlgItemText(hDlg, IDC_LUA_ALLUSER_DIR, g_LuaData.strAllUserDir);
  1991. }
  1992. break;
  1993. case PSN_WIZFINISH:
  1994. {
  1995. //
  1996. // Save everything we have changed.
  1997. //
  1998. BOOL bChanged = FALSE;
  1999. //LuapGetRedirectDirs(hDlg);
  2000. if (!g_bAllUserDirUsed) {
  2001. //
  2002. // If the user didn't want to redirect any files to
  2003. // the all user redirect dir, we need to record this.
  2004. //
  2005. g_LuaData.strAllUserDir.Release();
  2006. }
  2007. PLUADATA pOriginalLuaData = g_psflLua->pLuaData;
  2008. if (pOriginalLuaData == NULL) {
  2009. if (!g_LuaData.strAllUserDir.isNULL() ||
  2010. !g_LuaData.strPerUserDir.isNULL() ||
  2011. !g_LuaData.strStaticList.isNULL() ||
  2012. !g_LuaData.strDynamicList.isNULL()) {
  2013. pOriginalLuaData = new LUADATA;
  2014. if (!pOriginalLuaData) {
  2015. MEM_ERR;
  2016. break;
  2017. }
  2018. bChanged = TRUE;
  2019. }
  2020. } else {
  2021. if (!pOriginalLuaData->IsEqual(g_LuaData)) {
  2022. bChanged = TRUE;
  2023. }
  2024. }
  2025. if (bChanged) {
  2026. pOriginalLuaData->Copy(g_LuaData);
  2027. g_psflLua->pLuaData = pOriginalLuaData;
  2028. }
  2029. if (s_pDatabase != g_pPresentDataBase) {
  2030. //
  2031. // g_pPresentDataBase can change because the query and search
  2032. // windows can be used to select some entry in some other database.
  2033. // The TVN_SELCHANGE event changes g_pPresentDataBase
  2034. // These dialogs are modeless
  2035. //
  2036. g_pPresentDataBase = s_pDatabase;
  2037. }
  2038. if (!g_pPresentDataBase->bChanged) {
  2039. g_pPresentDataBase->bChanged = bChanged;
  2040. SetCaption();
  2041. }
  2042. LuapCleanup();
  2043. }
  2044. break;
  2045. }
  2046. }
  2047. break;
  2048. default:
  2049. return FALSE;
  2050. }
  2051. return TRUE;
  2052. }
  2053. /*++
  2054. Desc:
  2055. This functions is called when we select the menu item for configuring the LUA for the selectd
  2056. entry.
  2057. Return:
  2058. TRUE : if changes made are to be preserved.
  2059. FALSE : if the changes should not be saved.
  2060. --*/
  2061. BOOL
  2062. LuaBeginWizard(
  2063. HWND hParent,
  2064. PDBENTRY pEntry, // Entry for which we are setting the LUA params
  2065. PDATABASE pDatabase // The present database
  2066. )
  2067. {
  2068. s_pDatabase = pDatabase;
  2069. if (pEntry == NULL || pDatabase == NULL) {
  2070. assert(FALSE);
  2071. return FALSE;
  2072. }
  2073. //
  2074. // If we haven't gotten the value of %ProgramFiles%\Common Files, get it now.
  2075. // This is not going to change anyway so we only get it once.
  2076. //
  2077. if (g_wszProgramFilesCommon[0] == L'\0') {
  2078. DWORD cBufferLen = MAX_PATH - COMMON_FILES_LEN;
  2079. if ((g_czProgramFilesCommon = GetEnvironmentVariableW(
  2080. L"ProgramFiles",
  2081. g_wszProgramFilesCommon,
  2082. cBufferLen)) &&
  2083. g_czProgramFilesCommon < cBufferLen) {
  2084. wcsncat(g_wszProgramFilesCommon, COMMON_FILES, COMMON_FILES_LEN);
  2085. g_czProgramFilesCommon += COMMON_FILES_LEN;
  2086. g_wszProgramFilesCommon[g_czProgramFilesCommon] = L'\0';
  2087. } else {
  2088. MessageBoxA(
  2089. hParent,
  2090. "Failed to get the value of %ProgramFiles% or it's too long",
  2091. "Error",
  2092. MB_ICONERROR);
  2093. g_wszProgramFilesCommon[0] = L'\0';
  2094. g_czProgramFilesCommon = 0;
  2095. return FALSE;
  2096. }
  2097. }
  2098. g_bAllUserDirUsed = FALSE;
  2099. g_bUseNewStaticList = TRUE;
  2100. g_TrackState = LUA_TRACK_UNKNOWN;
  2101. g_psflLua = NULL;
  2102. g_pEntryLua = pEntry;
  2103. g_psflLua = IsLUARedirectFSPresent(pEntry);
  2104. if (g_psflLua == NULL) {
  2105. assert(FALSE);
  2106. return FALSE;
  2107. }
  2108. LuapGetDataFromEntry(g_psflLua->pLuaData);
  2109. if (g_TrackState == LUA_TRACK_UNKNOWN) {
  2110. //
  2111. // We shouldn't get here!!!
  2112. //
  2113. MessageBox(
  2114. hParent,
  2115. GetString(IDS_LUA_ERROR_FIND),
  2116. pEntry->strAppName,
  2117. MB_ICONERROR);
  2118. return FALSE;
  2119. }
  2120. if (g_hArrowFont == NULL) {
  2121. g_hArrowFont = CreateFont(
  2122. 14,
  2123. 0,
  2124. 0,
  2125. 0,
  2126. FW_DONTCARE,
  2127. 0,
  2128. 0,
  2129. 0,
  2130. DEFAULT_CHARSET,
  2131. OUT_DEFAULT_PRECIS,
  2132. CLIP_DEFAULT_PRECIS,
  2133. DEFAULT_QUALITY,
  2134. DEFAULT_PITCH,
  2135. TEXT("Wingdings"));
  2136. if (g_hArrowFont == NULL) {
  2137. MessageBox(
  2138. NULL,
  2139. GetString(IDS_LUA_ARROW_FONT),
  2140. g_pEntryLua->strAppName,
  2141. MB_ICONERROR);
  2142. return FALSE;
  2143. }
  2144. }
  2145. PROPSHEETPAGE Pages[NUM_PAGES_LUA] = {0};
  2146. ZeroMemory(Pages, sizeof(Pages));
  2147. //
  2148. // Begin the wizard
  2149. //
  2150. PROPSHEETHEADER Header = {0};
  2151. Header.dwSize = sizeof(PROPSHEETHEADER);
  2152. Header.dwFlags = PSH_WIZARD97 | PSH_HEADER | PSH_WATERMARK | PSH_PROPSHEETPAGE;
  2153. Header.hwndParent = hParent;
  2154. Header.hInstance = g_hInstance;
  2155. Header.nStartPage = 0;
  2156. Header.ppsp = Pages;
  2157. Header.nPages = NUM_PAGES_LUA;
  2158. Header.pszbmHeader = MAKEINTRESOURCE(IDB_WIZBMP);
  2159. Header.pszbmWatermark = MAKEINTRESOURCE(IDB_TOOL);
  2160. Pages[PAGE_LUA_ACTION].dwSize = sizeof(PROPSHEETPAGE);
  2161. Pages[PAGE_LUA_ACTION].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
  2162. Pages[PAGE_LUA_ACTION].hInstance = g_hInstance;
  2163. Pages[PAGE_LUA_ACTION].pszTemplate = MAKEINTRESOURCE(IDD_LUA_ACTION);
  2164. Pages[PAGE_LUA_ACTION].pfnDlgProc = LuapAction;
  2165. Pages[PAGE_LUA_ACTION].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_TRACK_FILES);
  2166. Pages[PAGE_LUA_ACTION].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_TRACK_FILES_SUBHEADING);
  2167. Pages[PAGE_LUA_EXCLUSION].dwSize = sizeof(PROPSHEETPAGE);
  2168. Pages[PAGE_LUA_EXCLUSION].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
  2169. Pages[PAGE_LUA_EXCLUSION].hInstance = g_hInstance;
  2170. Pages[PAGE_LUA_EXCLUSION].pszTemplate = MAKEINTRESOURCE(IDD_LUA_EXCLUSION);
  2171. Pages[PAGE_LUA_EXCLUSION].pfnDlgProc = LuapExclusion;
  2172. Pages[PAGE_LUA_EXCLUSION].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_EXCLUSION_HEADING);
  2173. Pages[PAGE_LUA_EXCLUSION].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_EXCLUSION_SUBHEADING);
  2174. Pages[PAGE_LUA_EDIT_FILE_LIST].dwSize = sizeof(PROPSHEETPAGE);
  2175. Pages[PAGE_LUA_EDIT_FILE_LIST].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
  2176. Pages[PAGE_LUA_EDIT_FILE_LIST].hInstance = g_hInstance;
  2177. Pages[PAGE_LUA_EDIT_FILE_LIST].pszTemplate = MAKEINTRESOURCE(IDD_LUA_TRACKED_FILES);
  2178. Pages[PAGE_LUA_EDIT_FILE_LIST].pfnDlgProc = LuapEditFileList;
  2179. Pages[PAGE_LUA_EDIT_FILE_LIST].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_EDIT_FILE_LIST);
  2180. Pages[PAGE_LUA_EDIT_FILE_LIST].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_EDIT_FILE_LIST_SUBHEADING);
  2181. Pages[PAGE_LUA_COMMON_PATHS].dwSize = sizeof(PROPSHEETPAGE);
  2182. Pages[PAGE_LUA_COMMON_PATHS].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
  2183. Pages[PAGE_LUA_COMMON_PATHS].hInstance = g_hInstance;
  2184. Pages[PAGE_LUA_COMMON_PATHS].pszTemplate = MAKEINTRESOURCE(IDD_LUA_COMMON_PATHS);
  2185. Pages[PAGE_LUA_COMMON_PATHS].pfnDlgProc = LuapCommonPaths;
  2186. Pages[PAGE_LUA_COMMON_PATHS].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_COMMON_PATHS_HEADING);
  2187. Pages[PAGE_LUA_COMMON_PATHS].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_COMMON_PATHS_SUBHEADING);
  2188. if (PropertySheet(&Header) < 0) {
  2189. return FALSE;
  2190. }
  2191. return TRUE;
  2192. }
  2193. BOOL
  2194. GetDBStringData(
  2195. const PDB pdb,
  2196. const TAGID tiFix,
  2197. LPCWSTR pwszName,
  2198. CSTRING& strValue
  2199. )
  2200. {
  2201. WCHAR wsz[32];
  2202. DWORD dwDataType, cSize = 0;
  2203. if (SdbQueryDataExTagID(pdb,
  2204. tiFix,
  2205. pwszName,
  2206. &dwDataType,
  2207. NULL,
  2208. &cSize,
  2209. NULL) != ERROR_INSUFFICIENT_BUFFER) {
  2210. Dbg(dlWarning,"Cannot get the size for DATA named %S\n", pwszName);
  2211. return FALSE;
  2212. }
  2213. LPWSTR pwszValue = new WCHAR [cSize / sizeof(WCHAR)];
  2214. if (pwszValue == NULL) {
  2215. MEM_ERR;
  2216. return FALSE;
  2217. }
  2218. if (SdbQueryDataExTagID(
  2219. pdb,
  2220. tiFix,
  2221. pwszName,
  2222. &dwDataType,
  2223. pwszValue,
  2224. &cSize,
  2225. NULL) != ERROR_SUCCESS) {
  2226. Dbg(dlWarning,"Cannot read the VALUE of DATA named %S\n", pwszName);
  2227. return FALSE;
  2228. }
  2229. strValue = pwszValue;
  2230. delete [] pwszValue;
  2231. return TRUE;
  2232. }
  2233. /*++
  2234. Desc:
  2235. This function gets the pdb and the tagid for the layer or the shim and creates a LUADATA*
  2236. and returns it back.
  2237. This function is invoked when we are reading in the .SDB file.
  2238. Return:
  2239. Valid LUADATA* if there is one
  2240. NULL: Otherwise.
  2241. --*/
  2242. PLUADATA
  2243. LuaProcessLUAData(
  2244. const PDB pdb,
  2245. const TAGID tiFix
  2246. )
  2247. {
  2248. PLUADATA pLuaData = new LUADATA;
  2249. if (pLuaData == NULL) {
  2250. MEM_ERR;
  2251. } else {
  2252. GetDBStringData(pdb, tiFix, LUA_DATA_ALLUSERDIR, pLuaData->strAllUserDir);
  2253. GetDBStringData(pdb, tiFix, LUA_DATA_PERUSERDIR, pLuaData->strPerUserDir);
  2254. GetDBStringData(pdb, tiFix, LUA_DATA_STATICLIST, pLuaData->strStaticList);
  2255. GetDBStringData(pdb, tiFix, LUA_DATA_DYNAMICLIST, pLuaData->strDynamicList);
  2256. GetDBStringData(pdb, tiFix, LUA_DATA_EXCLUDEDEXTENSIONS, pLuaData->strExcludedExtensions);
  2257. }
  2258. return pLuaData;
  2259. }
  2260. BOOL
  2261. LuapAddDataNode(
  2262. LPCWSTR pwszName,
  2263. CSTRING& strValue,
  2264. CSTRINGLIST& strlXML
  2265. )
  2266. {
  2267. CSTRING strSpecialChar;
  2268. TCHAR szSpace[64];
  2269. INT iszSpaceSize = 0;
  2270. *szSpace = 0;
  2271. iszSpaceSize = ARRAYSIZE(szSpace);
  2272. if (!strValue.isNULL() && strValue.pszString[0] != 0) {
  2273. CSTRING strTemp;
  2274. strTemp.Sprintf(TEXT("%s<DATA NAME=\"%s\" VALUETYPE=\"STRING\""),
  2275. GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
  2276. pwszName);
  2277. if (!strlXML.AddString(strTemp)) {
  2278. return FALSE;
  2279. }
  2280. strSpecialChar = strValue.SpecialCharToXML();
  2281. strTemp.Sprintf(TEXT("%sVALUE=\""), GetSpace(szSpace, TAB_SIZE * 5, iszSpaceSize));
  2282. strTemp.Strcat(strValue.SpecialCharToXML().pszString);
  2283. strTemp.Strcat(TEXT("\"/>"));
  2284. if (!strlXML.AddString(strTemp)) {
  2285. return FALSE;
  2286. }
  2287. }
  2288. return TRUE;
  2289. }
  2290. /*++
  2291. Desc:
  2292. This function is called when we are about to write out the data to an XML file.
  2293. Return:
  2294. TRUE : If valid added has been added to strlXML
  2295. FALSE: Otherwise
  2296. --*/
  2297. BOOL
  2298. LuaGenerateXML(
  2299. PLUADATA pLuaData,
  2300. CSTRINGLIST& strlXML
  2301. )
  2302. {
  2303. return (LuapAddDataNode(LUA_DATA_ALLUSERDIR, pLuaData->strAllUserDir, strlXML) &&
  2304. LuapAddDataNode(LUA_DATA_PERUSERDIR, pLuaData->strPerUserDir, strlXML) &&
  2305. LuapAddDataNode(LUA_DATA_STATICLIST, pLuaData->strStaticList, strlXML) &&
  2306. LuapAddDataNode(LUA_DATA_DYNAMICLIST, pLuaData->strDynamicList, strlXML) &&
  2307. LuapAddDataNode(LUA_DATA_EXCLUDEDEXTENSIONS, pLuaData->strExcludedExtensions, strlXML));
  2308. }