/*++ Copyright (c) 1989-2001 Microsoft Corporation Module Name: LUA.cpp Abstract: Implementation of the LUA wizard in CompatAdmin. Author: maonis --*/ /*++ The UI to customize the LUA shims lets you track and edit the list of files and directories passed as the command line to the LUA shims. Only the LUA FS shims are parameterized so the UI is for editing the list of files. Page 1: Tracking ================ We apply the LUATrackFS shim to the executable. When the app finishes running, we get a log in AppPatch directory that tells us which files and directories the app attempted to write to. Next time when the sdb is loaded, the user can choose to discard the old result and start fresh, append the new data to the old one (with duplicates removed), or simply just edit the data collected last time. Scenario: if the user forgot to test some features, he would not want to check the "Override existing data" checkbox because he won't want to test all the features he already tested. Page 2: Extension exclusion list ================================ By default we exclude a list of file extensions because files with these extensions are likely to be user data only. The list can be found as a value called LUADefaultExclusionList under the reg key HKLM\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags. This page gives you an option to modify this list. Page 3: Editing the redirect file list ====================================== (We call it a file list, but really it includes files and directories. A directory is indicated by the trailing slash.) If an item is already exactly what you want, you simply check the checkbox before the file name. But sometimes you want to use wildcards or whatever, in which case you can either copy it to edit, or type in a new item name. Use the "Redirect to All User" checkbox to toggle between redirecting to the per-user directory and all-user directory. The default is to redirect to per-user. The xml looks like: A means to redirect to the all-user directory. P means to redirect to the per-user directory. C means the item is checked. U means the item is not checked. We use variables to make the sdb portable. We define 2 variables and the rest can be any enviorment variable. %APPPATH% - this is the path of the executable. eg, in c:\temp\notepad.exe, %APPPATH% is c:\temp %APPDRIVE% - this is the drive the executable is on. eg, in c:\temp\notepad.exe, %APPDRIVE% is c: The LUARedirectFS shim knows how to interpret the sections. Page 4: Redirect paths ====================== We show the user what the all-user and per-user redirect redirectories are - we use the app name as the directory name under the all-user and per-user profile directories and this can not be changed. --*/ #include "precomp.h" extern HINSTANCE g_hInstance; #define NUM_PAGES_LUA 4 #define PAGE_LUA_ACTION 0 #define PAGE_LUA_EXCLUSION 1 #define PAGE_LUA_EDIT_FILE_LIST 2 #define PAGE_LUA_COMMON_PATHS 3 #define IS_IN_COMMANDLINE 1 #define IS_IN_DATA 2 #define IS_IN_BOTH 3 #define LUA_DATA_ALLUSERDIR L"AllUserDir" #define LUA_DATA_PERUSERDIR L"PerUserDir" #define LUA_DATA_STATICLIST L"StaticList" #define LUA_DATA_DYNAMICLIST L"DynamicList" #define LUA_DATA_EXCLUDEDEXTENSIONS L"ExcludedExtensions" typedef struct tagREDIRECT_ITEM { LIST_ENTRY entry; CSTRING strName; BOOL bChecked; BOOL bRedirectToAllUser; tagREDIRECT_ITEM() { bChecked = FALSE; bRedirectToAllUser = FALSE; } } REDIRECT_ITEM, *PREDIRECT_ITEM; typedef struct tagUNTOKENIZED_ITEM { LIST_ENTRY entry; CSTRING strName; } UNTOKENIZED_ITEM, *PUNTOKENIZED_ITEM; // The line type for the file generated by the LUATrackFS shim. typedef enum { LINE_INVALID, LINE_FILE_COUNT, // The file count line: Fn LINE_DIR_COUNT, // The directory count line: Dn } LINETYPE; typedef enum { LUA_TRACK_UNKNOWN = 0, LUA_TRACK_YES, LUA_TRACK_NO } LUA_TRACK_STATE; int g_iCurrentEditItem = -1; BOOL g_bNewListViewItem = FALSE; int g_nStaticItems = 0; HMENU g_hContextMenu = NULL; // The entry we currently work on. PDBENTRY g_pEntryLua; // Points to the shim that has the lua data. PSHIM_FIX_LIST g_psflLua = NULL; // This is *our* copy of the lua data so we don't overwrite the data in the entry // before the user presses Finish. LUADATA g_LuaData; BOOL g_bUseNewStaticList = TRUE; // List of items displayed in the 2nd page of the wizard. // This includs items that can and can not be edited. LIST_ENTRY g_OldStaticList; LIST_ENTRY g_NewStaticList; LIST_ENTRY g_DynamicList; BOOL g_bListsInitialized = FALSE; LIST_ENTRY g_UntokenizedList; // Has this executable been tracked using LUATrackFS shim yet? LUA_TRACK_STATE g_TrackState; BOOL g_bHasAppPathSet = FALSE; WCHAR g_wszAppPath[MAX_PATH] = L""; UINT g_cAppPath = 0; // If APPPATH is c:\x\y\z, this is 4. UINT g_cAppPath1stComp = 0; // We always display the files in Program Files\Common Files as // %ProgramFiles%\Common Files. WCHAR g_wszProgramFilesCommon[MAX_PATH] = L""; UINT g_czProgramFilesCommon = 0; #define COMMON_FILES L"\\Common Files\\" #define COMMON_FILES_LEN (sizeof(COMMON_FILES) / sizeof(WCHAR) - 1) BOOL g_bDuringUntokenize = FALSE; // The font for displaying up and down arrows. HFONT g_hArrowFont = NULL; // The database in which the entry being customized resides. static PDATABASE s_pDatabase; // This is where we store the default exclusion list in the registry under HKLM. #define LUA_APPCOMPAT_FLAGS_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags" #define LUA_DEFAULT_EXCLUSION_LIST L"LUADefaultExclusionList" // We are not freeing it here - it'll stay the whole time the process is running and // we'll let the process itself do the cleanup. LPWSTR g_pwszDefaultExclusionList = NULL; // We want to remember if the user wants to redirect any files at all to all user redirec // dir; if not we won't bother to create it. BOOL g_bAllUserDirUsed = FALSE; // This is for debugging purposes. void LuapDumpList( LPCWSTR pwsz, PLIST_ENTRY pHead ) { OutputDebugString(pwsz); PREDIRECT_ITEM pItem; for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); OutputDebugString(L"\t"); OutputDebugString(pItem->strName); OutputDebugString(L"\n"); } } BOOL LuapAddItem( PLIST_ENTRY pHead, LPCWSTR pwszName, BOOL bChecked, BOOL bRedirectToAllUser ) { PREDIRECT_ITEM pItem = new REDIRECT_ITEM; if (pItem == NULL) { MEM_ERR; return FALSE; } pItem->strName = pwszName; pItem->bChecked = bChecked; pItem->bRedirectToAllUser = bRedirectToAllUser; InsertTailList(pHead, &pItem->entry); return TRUE; } void LuapDeleteList( PLIST_ENTRY pHead ) { PREDIRECT_ITEM pItem; PLIST_ENTRY pTempEntry; for (PLIST_ENTRY pEntry = pHead->Flink; pEntry && pEntry != pHead; pEntry = pEntry->Flink) { pTempEntry = pEntry->Flink; pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); RemoveEntryList(pEntry); delete pItem; pEntry = pTempEntry; } pHead->Flink = pHead->Blink = NULL; } PLIST_ENTRY LuapFindEntry( PLIST_ENTRY pHead, PLIST_ENTRY pEntryToFind ) { PREDIRECT_ITEM pItem; PREDIRECT_ITEM pItemToFind = CONTAINING_RECORD(pEntryToFind, REDIRECT_ITEM, entry); for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); if (!_wcsicmp(pItem->strName, pItemToFind->strName)) { return pEntry; } } return NULL; } PLIST_ENTRY LuapFindEntry( PLIST_ENTRY pHead, PREDIRECT_ITEM pItemToFind ) { PREDIRECT_ITEM pItem; for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); if (!_wcsicmp(pItem->strName, pItemToFind->strName)) { return pEntry; } } return NULL; } LINETYPE LuapGetLineType( LPCWSTR pwszLine ) { if (pwszLine && *pwszLine) { WCHAR ch0, ch1; ch0 = *pwszLine; ch1 = *++pwszLine; if (ch0 == L'F' || ch0 == L'D') { if (ch1 >= L'0' && ch1 <= L'9') { return (ch0 == L'F' ? LINE_FILE_COUNT : LINE_DIR_COUNT); } } } return LINE_INVALID; } DWORD LuapGetListItemCount( LPCWSTR pwsz ) { DWORD cItems = 0; while (*pwsz) { if (*pwsz == L';') { ++cItems; } ++pwsz; } return cItems; } BOOL LuapGenerateTrackXML( const PDBENTRY pEntry, CSTRINGLIST* strlXML ) { CSTRING strTemp; if (!strlXML->AddString(TEXT("")) || !strlXML->AddString(TEXT(""))) { return FALSE; } strTemp.Sprintf(TEXT("\t"), (LPCTSTR)(pEntry->strAppName.SpecialCharToXML()), (LPCTSTR)(pEntry->strVendor.SpecialCharToXML())); if (!strlXML->AddString(strTemp)) { return FALSE; } strTemp.Sprintf(TEXT("\t\t"), (LPCTSTR)pEntry->strExeName.SpecialCharToXML()); if (!strlXML->AddString(strTemp)) { return FALSE; } if (!strlXML->AddString(TEXT("\t\t\t")) || !strlXML->AddString(TEXT("\t\t")) || !strlXML->AddString(TEXT("\t")) || !strlXML->AddString(TEXT(""))) { return FALSE; } return TRUE; } // If we see a file begins with %ProgramFiles%\Common Files, we susbstitute it. BOOL LuapSubstituteProgramFilesCommon( LPCWSTR pwszItem, CSTRING& strItem ) { if (g_wszProgramFilesCommon[0] != L'\0') { if (!_wcsnicmp(pwszItem, g_wszProgramFilesCommon, g_czProgramFilesCommon)) { strItem = L"%ProgramFiles%\\Common Files"; strItem += CSTRING(pwszItem + g_czProgramFilesCommon); return TRUE; } } return FALSE; } // We check if we should display the path as relative to APPPATH - // we only do this when the item path has more than just the common // root with APPPATH. BOOL LuapGetRelativeName( LPCWSTR pwszItem, CSTRING& strItem ) { if (g_cAppPath1stComp > 2 && !_wcsnicmp(pwszItem + 2, g_wszAppPath + 2, g_cAppPath1stComp - 2)) { CSTRING strTemp = pwszItem; CSTRING strAppPath(g_wszAppPath); strAppPath.Strcat(L"\\"); if (strTemp.RelativeFile(strAppPath)) { strItem = L"%APPPATH%\\"; strItem += strTemp; return TRUE; } } return FALSE; } BOOL LuapGetFileListFromFile( CSTRING& strExeName, PLIST_ENTRY pHead ) { if (strExeName == NULL) { return FALSE; } CSTRING strLuaLog; LPWSTR pwszLuaLogContents = NULL; TCHAR szWindowsDir[MAX_PATH]; *szWindowsDir = 0; // // Need to leave space for adding the trailing slash. // UINT cBufferLen = MAX_PATH - 1; UINT cWindowsDirLen = GetSystemWindowsDirectory(szWindowsDir, cBufferLen); if (cWindowsDirLen == 0 || cWindowsDirLen >= cBufferLen) { Dbg(dlError,"[LuapGetFileListFromFile] Error getting the windows directory"); return FALSE; } ADD_PATH_SEPARATOR(szWindowsDir, ARRAYSIZE(szWindowsDir)); CSTRING strTempExeName = strExeName; LPTSTR pszExtension = _tcsrchr(strTempExeName, TEXT('.')); // // If there's no extension we use the whole file name. // if (pszExtension) { *pszExtension = 0; } strLuaLog.Sprintf(TEXT("%sAppPatch\\%s.LUA.log"), (LPCTSTR)szWindowsDir, strTempExeName); // // Get the file list. // if (!GetFileContents(strLuaLog, &pwszLuaLogContents)) { return FALSE; } LPWSTR pwszNextLine = GetNextLine(pwszLuaLogContents); LPWSTR pwszItem; CSTRING strItem; DWORD cItems, i; LINETYPE LineType; while (pwszNextLine) { LineType = LuapGetLineType(pwszNextLine); if (LineType == LINE_INVALID) { Dbg(dlError,"[LuapGetFileListFromFile] Invalid line %S", pwszNextLine); return FALSE; } cItems = _wtoi(++pwszNextLine); for (i = 0; i < cItems; ++i) { pwszItem = GetNextLine(NULL); if (pwszItem == NULL) { Dbg(dlError,"[LuapGetFileListFromFile] count and actual files mismatch"); return FALSE; } // // By now the apppath and appdrive should be set, so tokenize the item. // if (!_wcsnicmp(pwszItem, g_wszAppPath, 2)) { if (!LuapSubstituteProgramFilesCommon(pwszItem, strItem)) { if (!LuapGetRelativeName(pwszItem, strItem)) { strItem = L"%APPDRIVE%"; strItem.Strcat(pwszItem + 2); } } } else { strItem = pwszItem; } if (!LuapAddItem(pHead, strItem, FALSE, FALSE)) { return FALSE; } } pwszNextLine = GetNextLine(NULL); } if (pwszLuaLogContents) { delete[] pwszLuaLogContents; pwszLuaLogContents = NULL; } return TRUE; } BOOL LuapFillInList( LPCWSTR pwszList, PLIST_ENTRY pHead ) { if (pwszList) { // // Make a copy. // CSTRING strList = pwszList; LPWSTR pwsz = strList; LPWSTR pwszToken = pwsz; WCHAR ch; BOOL bChecked, bRedirectToAllUser; while (TRUE) { if (*pwsz == L';' || *pwsz == L'\0') { ch = *pwsz; *pwsz = L'\0'; TrimLeadingSpaces(pwszToken); TrimTrailingSpaces(pwszToken); bChecked = (pwszToken[1] == L'C'); bRedirectToAllUser = (pwszToken[0] == L'A'); if (!LuapAddItem(pHead, pwszToken + 3, bChecked, bRedirectToAllUser)) { return FALSE; } pwszToken = pwsz + 1; if (ch == L'\0') { break; } } ++pwsz; } } return TRUE; } /*++ Desc: The algorithm for append: for each item in the new static list, attempt to find it in the old static list if (FALSE) remove it from the new static list add it to the end of the old static list check if it exists in the dynamic list if (TRUE) copy the attributes from the dynamic list remove it from the dynamic list --*/ void LuapTrackAppend( ) { PREDIRECT_ITEM pItem, pDynamicItem; PLIST_ENTRY pDynamicEntry; PLIST_ENTRY pEntry = g_NewStaticList.Flink; PLIST_ENTRY pTempEntry; while (pEntry != &g_NewStaticList) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); if (LuapFindEntry(&g_OldStaticList, pItem)) { pEntry = pEntry->Flink; } else { pTempEntry = pEntry->Flink; RemoveEntryList(pEntry); InsertTailList(&g_OldStaticList, pEntry); if (pDynamicEntry = LuapFindEntry(&g_DynamicList, pItem)) { pDynamicItem = CONTAINING_RECORD(pDynamicEntry, REDIRECT_ITEM, entry); pItem->bChecked = pDynamicItem->bChecked; pItem->bRedirectToAllUser = pDynamicItem->bRedirectToAllUser; RemoveEntryList(pDynamicEntry); } pEntry = pTempEntry; } } g_bUseNewStaticList = FALSE; } /*++ Desc: The algorithm for start fresh: for each item in the new static list, attempt to find it in the dynamic list if (TRUE) copy the attributes from the dynamic list remove it from the dynamic list for each *checked* item in the old static list, attempt to find it in the new static list if (FALSE) add it to the tail of the dynamic list remove it from the old static list --*/ void LuapTrackFresh( ) { PREDIRECT_ITEM pItem, pDynamicItem; PLIST_ENTRY pEntry, pTempEntry, pDynamicEntry, pNewStaticEntry; for (pEntry = g_NewStaticList.Flink; pEntry != &g_NewStaticList; pEntry = pEntry->Flink) { if (pDynamicEntry = LuapFindEntry(&g_DynamicList, pEntry)) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); pDynamicItem = CONTAINING_RECORD(pDynamicEntry, REDIRECT_ITEM, entry); pItem->bChecked = pDynamicItem->bChecked; pItem->bRedirectToAllUser = pDynamicItem->bRedirectToAllUser; RemoveEntryList(pDynamicEntry); } } pEntry = g_OldStaticList.Flink; while (pEntry != &g_OldStaticList) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); if (pItem->bChecked) { if (pNewStaticEntry = LuapFindEntry(&g_NewStaticList, pItem)) { pTempEntry = pEntry->Flink; RemoveEntryList(pEntry); InsertTailList(&g_DynamicList, pEntry); pEntry = pTempEntry; continue; } } pEntry = pEntry->Flink; } } void LuapCleanup() { LuapDeleteList(&g_OldStaticList); LuapDeleteList(&g_NewStaticList); LuapDeleteList(&g_DynamicList); g_LuaData.Free(); g_bHasAppPathSet = FALSE; g_bDuringUntokenize = FALSE; g_wszAppPath[0] = L'\0'; g_cAppPath = 0; g_cAppPath1stComp = 0; g_wszProgramFilesCommon[0] = L'\0'; g_czProgramFilesCommon = 0; // // Clear the enviornment variables. // SetEnvironmentVariable(L"APPPATH", NULL); SetEnvironmentVariable(L"APPDRIVE", NULL); } BOOL LuapInitializeOldLists( HWND hDlg ) { InitializeListHead(&g_OldStaticList); InitializeListHead(&g_DynamicList); if (LuapFillInList(g_LuaData.strStaticList, &g_OldStaticList) && LuapFillInList(g_LuaData.strDynamicList, &g_DynamicList)) { return TRUE; } MessageBox(hDlg, GetString(IDS_LUA_INIT_OLD_LISTS), g_pEntryLua->strAppName, MB_ICONERROR); return FALSE; } /*++ Desc: Merges the list from section and the COMMAND_LINE of LUARedirectFS. For each item in command line, look it up in so we know how to display those items in in the UI. --*/ BOOL LuapMergeLists( BOOL bMergeOld, // Merge the old data from the section. HWND hDlg ) { g_bListsInitialized = TRUE; BOOL bIsSuccess = FALSE; if (!LuapInitializeOldLists(hDlg)) { return FALSE; } // // Initialize the new static list. // InitializeListHead(&g_NewStaticList); if (!LuapGetFileListFromFile(g_pEntryLua->strExeName, &g_NewStaticList)) { goto EXIT; } bMergeOld ? LuapTrackAppend() : LuapTrackFresh(); bIsSuccess = TRUE; EXIT: if (!bIsSuccess) { LuapCleanup(); } return bIsSuccess; } /*++ Desc: Copy the data over - we don't want to modify the original copy until the user tells us to. --*/ void LuapGetDataFromEntry( PLUADATA pLuaData ) { // // We can set the redirect dirs now. // CSTRING strAllUserDir(L"%ALLUSERSPROFILE%\\Application Data\\"); strAllUserDir += g_pEntryLua->strAppName; CSTRING strPerUserDir(L"%USERPROFILE%\\Application Data\\"); strPerUserDir += g_pEntryLua->strAppName; g_LuaData.strAllUserDir = strAllUserDir; g_LuaData.strPerUserDir = strPerUserDir; if (pLuaData) { g_LuaData.strStaticList = pLuaData->strStaticList; g_LuaData.strDynamicList = pLuaData->strDynamicList; g_LuaData.strExcludedExtensions = pLuaData->strExcludedExtensions; g_TrackState = ((g_LuaData.strStaticList.isNULL() && g_LuaData.strDynamicList.isNULL() && g_LuaData.strExcludedExtensions.isNULL()) ? LUA_TRACK_NO : LUA_TRACK_YES); } else { g_TrackState = LUA_TRACK_NO; } } void LuapCopyItems( HWND hwndList ) { int cItems = ListView_GetItemCount(hwndList); int iIndex = cItems; WCHAR wszItem[MAX_PATH] = L""; WCHAR wszRedirect[32] = L""; LVITEM lvi; int index; for (int i = 0 ; i < cItems; ++i) { if (ListView_GetItemState(hwndList, i, LVIS_SELECTED) == LVIS_SELECTED) { ListView_GetItemText(hwndList, i, 0, wszItem, MAX_PATH); ListView_GetItemText(hwndList, i, 1, wszRedirect, 32); // // Need to add the new item. // lvi.mask = LVIF_TEXT; lvi.lParam = 0; lvi.pszText = wszItem; lvi.iItem = iIndex++; lvi.iSubItem = 0; index = ListView_InsertItem(hwndList, &lvi); ListView_SetItemText(hwndList, index, 1, wszRedirect); } } } void LuapTokenizeItems( HWND hwndList, BOOL bUntokenize ) { int cItems = ListView_GetItemCount(hwndList); WCHAR wszItem[MAX_PATH] = L""; WCHAR wszExpandItem[MAX_PATH] = L""; LPWSTR pwszUntokenizedItem = NULL; LVITEM lvi; int index; PLIST_ENTRY pEntry; PUNTOKENIZED_ITEM pItem; if (bUntokenize) { InitializeListHead(&g_UntokenizedList); } else { pEntry = g_UntokenizedList.Flink; } for (int i = 0 ; i < cItems; ++i) { ListView_GetItemText(hwndList, i, 0, wszItem, MAX_PATH); if (bUntokenize) { pItem = new UNTOKENIZED_ITEM; if (pItem == NULL) { MEM_ERR; return; } pItem->strName = wszItem; InsertTailList(&g_UntokenizedList, &pItem->entry); if (ExpandEnvironmentStrings(wszItem, wszExpandItem, MAX_PATH)) { pwszUntokenizedItem = wszExpandItem; } else { pwszUntokenizedItem = wszItem; } ListView_SetItemText(hwndList, i, 0, pwszUntokenizedItem); } else { pItem = CONTAINING_RECORD(pEntry, UNTOKENIZED_ITEM, entry); ListView_SetItemText(hwndList, i, 0, pItem->strName); pEntry = pEntry->Flink; } } if (!bUntokenize) { LuapDeleteList(&g_UntokenizedList); } } BOOL LuapSaveFileLists( HWND hwndList ) { g_bListsInitialized = FALSE; BOOL bIsSuccess = FALSE; int nItems = ListView_GetItemCount(hwndList); int i, j; WCHAR wszItem[MAX_PATH + 3] = L""; WCHAR wszRedirect[MAX_PATH] = L""; BOOL bChecked, bRedirectAllUser; PLIST_ENTRY pHead = (g_bUseNewStaticList ? &g_NewStaticList : &g_OldStaticList); PLIST_ENTRY pEntry = pHead->Flink; PREDIRECT_ITEM pItem; // // For all the checked items we check if there are any duplicates. // Note that we don't allow duplicate items even if they are specified // to redirect to the same directory - because the position of the checked // items does matter (a checked item above another takes precedence over // that other one when redirected). // LPWSTR* ppTempCheckedItems = NULL; DWORD dwTempIndex = 0; g_LuaData.strStaticList.Release(); g_LuaData.strDynamicList.Release(); g_bAllUserDirUsed = FALSE; ppTempCheckedItems = new LPWSTR [nItems]; if (!ppTempCheckedItems) { MEM_ERR; goto EXIT; } for (i = 0; i < nItems; ++i) { ListView_GetItemText(hwndList, i, 1, wszRedirect, MAX_PATH); bRedirectAllUser = !wcscmp(wszRedirect, GetString(IDS_LUA_RDIR_ALLUSER)); wszItem[0] = (bRedirectAllUser ? L'A' : L'P'); bChecked = ListView_GetCheckState(hwndList, i); wszItem[1] = (bChecked ? L'C' : L'U'); wszItem[2] = L'-'; wszItem[3] = L'\0'; if (bRedirectAllUser && bChecked) { g_bAllUserDirUsed = TRUE; } if (bChecked) { ppTempCheckedItems[dwTempIndex] = new WCHAR [MAX_PATH]; if (!ppTempCheckedItems[dwTempIndex]) { MEM_ERR; goto EXIT; } ++dwTempIndex; } if (i < g_nStaticItems) { pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); g_LuaData.strStaticList.Strcat(wszItem); g_LuaData.strStaticList.Strcat(pItem->strName); g_LuaData.strStaticList.Strcat(L";"); if (bChecked) { StringCchCopy( ppTempCheckedItems[dwTempIndex - 1], MAX_PATH, pItem->strName); } pEntry = pEntry->Flink; } else { ListView_GetItemText(hwndList, i, 0, wszItem + 3, MAX_PATH); if (bChecked) { for (j = 0; j < dwTempIndex - 1; ++j) { if (!_wcsicmp(ppTempCheckedItems[j], wszItem + 3)) { CSTRING strMessage; strMessage.Sprintf( L"%s was already in the list. Please remove one.", wszItem + 3); MessageBox( NULL, strMessage, g_pEntryLua->strAppName, MB_ICONERROR); goto EXIT; } } StringCchCopy( ppTempCheckedItems[dwTempIndex - 1], MAX_PATH, wszItem + 3); } StringCchCat(wszItem, ARRAYSIZE(wszItem), L";"); g_LuaData.strDynamicList.Strcat(wszItem); } } int cLen = g_LuaData.strStaticList.Length(); g_LuaData.strStaticList.SetChar(cLen - 1, L'\0'); cLen = g_LuaData.strDynamicList.Length(); g_LuaData.strDynamicList.SetChar(cLen - 1, L'\0'); bIsSuccess = TRUE; EXIT: for (i = 0; i < dwTempIndex; ++i) { delete [] ppTempCheckedItems[i]; } if (ppTempCheckedItems) { delete [] ppTempCheckedItems; } if (bIsSuccess) { // // We want to keep the lists in case of failure because we // can come back and try again. // LuapDeleteList(&g_OldStaticList); LuapDeleteList(&g_NewStaticList); LuapDeleteList(&g_DynamicList); g_bUseNewStaticList = FALSE; } return bIsSuccess; } void LuapEditCell( HWND hwndList, int iItem, int iSubItem ) { // // If the user holds down shift or control while clicking, // it means he wants to select multiple rows. We'll let // the listview handle it. // SHORT sStateShift = GetAsyncKeyState(VK_SHIFT); SHORT sStateControl = GetAsyncKeyState(VK_CONTROL); if (sStateShift & (1 << 15) || sStateControl & (1 << 15)) { return; } if (iSubItem) { // // Before we display the combobox, we need to // de-select all items in the listview. // int index = -1; while ((index = ListView_GetNextItem(hwndList, index, LVIS_SELECTED)) != -1) { ListView_SetItemState(hwndList, index, 0, LVIS_SELECTED); } RECT rect, rectListView, rectParent; WCHAR szText[MAX_PATH]; HWND hwnd = GetParent(hwndList); GetWindowRect(hwndList, &rectListView); GetWindowRect(hwnd, &rectParent); g_iCurrentEditItem = iItem; SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); LVITEM lvi; lvi.mask = LVIF_TEXT; lvi.lParam = 0; lvi.pszText = szText; lvi.cchTextMax = MAX_PATH; lvi.iItem = iItem; lvi.iSubItem = iSubItem; ListView_GetSubItemRect(hwndList, iItem, iSubItem, LVIR_LABEL, &rect); ListView_GetItem(hwndList, &lvi); // // Move the combobox to cover this item. // HWND hwndCombo = GetDlgItem(hwnd, IDC_LUA_RDIR); MoveWindow(hwndCombo, rect.left + rectListView.left - rectParent.left + 2, rect.top + rectListView.top - rectParent.top + 1, rect.right - rect.left, rect.bottom - rect.top - 7, TRUE); SetFocus(hwndCombo); ShowWindow(hwndCombo, SW_SHOW); ListView_SetItemState(hwndList, iItem, LVIS_FOCUSED, LVIS_FOCUSED); int nID = (wcscmp(lvi.pszText, GetString(IDS_LUA_RDIR_PERUSER)) ? 0 : 1); SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM)nID, 0); SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); } } BOOL LuapSetAppEnvVars( HWND hDlg) { BOOL bIsSuccess = TRUE; CSTRING strFullPath; LPWSTR pwsz = NULL; if (g_bHasAppPathSet) { goto EXIT; } strFullPath = g_pEntryLua->strFullpath; pwsz = strFullPath; if (g_pEntryLua->strFullpath.isNULL()) { goto EXIT; } bIsSuccess = FALSE; LPWSTR pwszLastSlash = wcsrchr(pwsz, L'\\'); if (pwszLastSlash == NULL) { MessageBox(hDlg, L"The full path doesn't contain a '\\'?", g_pEntryLua->strAppName, MB_ICONERROR); goto EXIT; } *pwszLastSlash = L'\0'; g_cAppPath = wcslen(pwsz); if (g_cAppPath >= ARRAYSIZE(g_wszAppPath)) { MessageBox(hDlg, L"Exe path too long - we don't handle it", g_pEntryLua->strAppName, MB_ICONERROR); g_cAppPath = 0; goto EXIT; } wcsncpy(g_wszAppPath, pwsz, g_cAppPath); g_wszAppPath[g_cAppPath] = L'\0'; LPWSTR pwsz1stComp = wcschr(g_wszAppPath, L'\\'); if (pwsz1stComp) { if (pwsz1stComp = wcschr(pwsz1stComp + 1, L'\\')) { g_cAppPath1stComp = pwsz1stComp - g_wszAppPath + 1; } } SetEnvironmentVariable(L"APPPATH", pwsz); *(pwsz + 2) = L'\0'; SetEnvironmentVariable(L"APPDRIVE", pwsz); g_bHasAppPathSet = TRUE; bIsSuccess = TRUE; EXIT: return bIsSuccess; } INT_PTR CALLBACK LuapAction( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { LPARAM buttons; switch (uMsg) { case WM_INITDIALOG: { HWND hwndParent = GetParent(hDlg); CenterWindow(GetParent(hwndParent), hwndParent); SetWindowText(hwndParent, GetString(IDS_LUA_WIZARD_TITLE)); // // Fill in the executable name. // SetDlgItemText(hDlg, IDC_LUA_EXE, g_pEntryLua->strExeName); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_MODIFY_DATA), (g_TrackState == LUA_TRACK_YES)); CheckDlgButton(hDlg, (g_TrackState == LUA_TRACK_YES ? IDC_LUA_MODIFY_DATA : IDC_LUA_RUN_PROGRAM), BST_CHECKED); // // Set the appropriate description // SetDlgItemText(hDlg, IDC_DESCRIPTION, (g_TrackState == LUA_TRACK_NO ? GetString(IDS_LUA_DESC_NODATA) : GetString(IDS_LUA_DESC_DATA))); buttons = 0; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); } break; case WM_NOTIFY: { NMHDR * pHdr = (NMHDR *) lParam; switch (pHdr->code) { case PSN_SETACTIVE: { buttons = PSWIZB_NEXT; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_MODIFY_DATA), (g_TrackState == LUA_TRACK_YES)); if (g_TrackState == LUA_TRACK_YES && IsDlgButtonChecked(hDlg, IDC_LUA_RUN_PROGRAM)) { ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), TRUE); } else { ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), FALSE); } } break; case PSN_WIZNEXT: { BOOL bIsSuccess = FALSE; g_bUseNewStaticList = TRUE; if (IsDlgButtonChecked(hDlg, IDC_LUA_RUN_PROGRAM) == BST_CHECKED) { buttons = PSWIZB_NEXT; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); BOOL bMergeOld = (g_TrackState == LUA_TRACK_YES && IsDlgButtonChecked(hDlg, IDC_LUA_OVERRIDE) == BST_UNCHECKED); // // Apply the LUATrackFS shim to the executable. // CSTRING strExeName = (g_pEntryLua->strFullpath.isNULL() ? g_pEntryLua->strExeName : g_pEntryLua->strFullpath); CSTRINGLIST strlXML; if (LuapGenerateTrackXML(g_pEntryLua, &strlXML)) { if (TestRun(g_pEntryLua, &strExeName, NULL, hDlg, &strlXML)) { // // Set the new enviorment variables APPPATH and APPDRIVE. // if (g_pEntryLua->strFullpath.isNULL()) { g_pEntryLua->strFullpath = strExeName; } if (!LuapSetAppEnvVars(hDlg)) { goto RETURN; } // // There should be a file generated by the LUATrackFS shim in AppPatch. // We will merge this with the original data. // if (LuapMergeLists(bMergeOld, hDlg)) { g_TrackState = LUA_TRACK_YES; bIsSuccess = TRUE; } else { MessageBox(hDlg, GetString(IDS_LUA_MERGE_LIST), g_pEntryLua->strAppName, MB_ICONERROR); } } } else { MessageBox(hDlg, GetString(IDS_LUA_TRACKXML), g_pEntryLua->strAppName, MB_ICONERROR); } } else { // // Initialize the old static and the dynamic list. // if (LuapInitializeOldLists(hDlg)) { g_bUseNewStaticList = FALSE; bIsSuccess = TRUE; } } RETURN: // // Prevent from going to the next page if any error occured. // if (!bIsSuccess) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); } } break; } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_LUA_RUN_PROGRAM: case IDC_LUA_MODIFY_DATA: if (IsDlgButtonChecked(hDlg, IDC_LUA_RUN_PROGRAM) == BST_CHECKED) { ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), (g_TrackState == LUA_TRACK_YES)); } if (IsDlgButtonChecked(hDlg, IDC_LUA_MODIFY_DATA) == BST_CHECKED) { ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_OVERRIDE), FALSE); } buttons = PSWIZB_NEXT; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); break; } default: return FALSE; } return TRUE; } void LuapAddItemToListView( HWND hwndList, PLIST_ENTRY pEntry, int i ) { PREDIRECT_ITEM pItem = CONTAINING_RECORD(pEntry, REDIRECT_ITEM, entry); LVITEM lvi; int index; lvi.mask = LVIF_TEXT; lvi.lParam = 0; lvi.pszText = pItem->strName; lvi.iItem = i; lvi.iSubItem = 0; index = ListView_InsertItem(hwndList, &lvi); ListView_SetItemText( hwndList, index, 1, pItem->bRedirectToAllUser ? GetString(IDS_LUA_RDIR_ALLUSER) : GetString(IDS_LUA_RDIR_PERUSER)); ListView_SetCheckState(hwndList, index, pItem->bChecked); } void LuapDeleteSelectedItems( HWND hwndList ) { int index = -1; while ((index = ListView_GetNextItem(hwndList, g_nStaticItems - 1, LVNI_SELECTED)) != -1) { ListView_DeleteItem(hwndList, index); } } inline void LuapGetRGB( COLORREF cr, BYTE* pR, BYTE* pG, BYTE* pB ) { *pR = GetRValue(cr); *pG = GetGValue(cr); *pB = GetBValue(cr); } inline void LuapSwapColor( BYTE* pFont, BYTE* pBk ) { BYTE temp; if (*pFont > *pBk) { temp = *pFont; *pFont = *pBk; *pBk = temp; } } // font is garanteed to be less than bk. inline BYTE LuapGetHalfColor( BYTE font, BYTE bk ) { return (font + (bk - font) / 2); } COLORREF LuapGetHalfIntensity( COLORREF crFont, COLORREF crBk ) { BYTE rFont, gFont, bFont, rBk, gBk, bBk; LuapGetRGB(crFont, &rFont, &gFont, &bFont); LuapGetRGB(crBk, &rBk, &gBk, &bBk); // // if the value of the text is greater than that of the Bk, we swap them. // LuapSwapColor(&rFont, &rBk); LuapSwapColor(&gFont, &gBk); LuapSwapColor(&bFont, &bBk); // // The half color is computed as the lower value + half of the difference // between the higher and the lower value. BYTE rHalf = LuapGetHalfColor(rFont, rBk); BYTE gHalf = LuapGetHalfColor(gFont, gBk); BYTE bHalf = LuapGetHalfColor(bFont, bBk); return RGB(rHalf, gHalf, bHalf); } typedef enum { CM_SELECT, CM_DESELECT, CM_REDIRECT_ALLUSER, CM_REDIRECT_PERUSER, CM_REDIRECT_LASTINDEX } LUA_CM_INDEX; BOOL LuapDisplayContextMenu( HWND hwndList, POINT* ppt) { int i; if (g_hContextMenu == NULL) { g_hContextMenu = CreatePopupMenu(); if (g_hContextMenu == NULL) { MessageBox( hwndList, GetString(IDS_LUA_ERROR_CM), g_pEntryLua->strAppName, MB_ICONERROR); return FALSE; } CSTRING strItems[CM_REDIRECT_LASTINDEX]; strItems[CM_SELECT] = GetString(IDS_LUA_CM_SELECT); strItems[CM_DESELECT] = GetString(IDS_LUA_CM_DESELECT); strItems[CM_REDIRECT_ALLUSER] = GetString(IDS_LUA_CM_REDIRECT_ALLUSER); strItems[CM_REDIRECT_PERUSER] = GetString(IDS_LUA_CM_REDIRECT_PERUSER); MENUITEMINFO mi = {0}; mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STRING | MIIM_ID; for (i = 0; i < CM_REDIRECT_LASTINDEX; ++i) { mi.dwTypeData = strItems[i]; mi.cch = wcslen(mi.dwTypeData); mi.wID = i + 1; InsertMenuItem(g_hContextMenu, i, TRUE, &mi); } } // // Disable the corresponding item in the context menu if all the selected items // already have that attribute, eg, if all of them are checked already, "Select" // should be disabled. // BOOL bChecked, bUnchecked, bPerUser, bAllUser; bChecked = bUnchecked = bPerUser = bAllUser = TRUE; int cItems = ListView_GetItemCount(hwndList); WCHAR wszRedirect[32] = L""; for (i = 0 ; i < cItems; ++i) { if (ListView_GetItemState(hwndList, i, LVIS_SELECTED) == LVIS_SELECTED) { if (ListView_GetCheckState(hwndList, i)) { bUnchecked = FALSE; } else { bChecked = FALSE; } ListView_GetItemText(hwndList, i, 1, wszRedirect, 32); if (!wcscmp(wszRedirect, GetString(IDS_LUA_RDIR_ALLUSER))) { bPerUser = FALSE; } else { bAllUser = FALSE; } } } if (bChecked) { EnableMenuItem(g_hContextMenu, CM_SELECT, MF_BYPOSITION | MF_GRAYED); } if (bUnchecked) { EnableMenuItem(g_hContextMenu, CM_DESELECT, MF_BYPOSITION | MF_GRAYED); } if (bAllUser) { EnableMenuItem(g_hContextMenu, CM_REDIRECT_ALLUSER, MF_BYPOSITION | MF_GRAYED); } if (bPerUser) { EnableMenuItem(g_hContextMenu, CM_REDIRECT_PERUSER, MF_BYPOSITION | MF_GRAYED); } UINT nIDSelected = TrackPopupMenuEx(g_hContextMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, ppt->x, ppt->y, hwndList, NULL); int iCheck, iRedirectAllUser; iCheck = iRedirectAllUser = -1; iCheck = (nIDSelected == CM_SELECT + 1 ? 1 : nIDSelected == CM_DESELECT + 1 ? 0 : -1); iRedirectAllUser = (nIDSelected == CM_REDIRECT_ALLUSER + 1 ? 1 : nIDSelected == CM_REDIRECT_PERUSER + 1 ? 0 : -1); for (i = 0 ; i < cItems; ++i) { if (ListView_GetItemState(hwndList, i, LVIS_SELECTED) == LVIS_SELECTED) { if (iCheck != -1) { if (ListView_GetCheckState(hwndList, i) != (BOOL)iCheck) { ListView_SetCheckState(hwndList, i, (BOOL)iCheck); } } if (iRedirectAllUser != -1) { ListView_GetItemText(hwndList, i, 1, wszRedirect, 32); if (!wcscmp(wszRedirect, GetString(IDS_LUA_RDIR_ALLUSER)) != (BOOL)iRedirectAllUser) { ListView_SetItemText( hwndList, i, 1, GetString((BOOL)iRedirectAllUser ? IDS_LUA_RDIR_ALLUSER : IDS_LUA_RDIR_PERUSER)); } } } } // // Restore the state of menu items. // for (i = 0; i < CM_REDIRECT_LASTINDEX; ++i) { EnableMenuItem(g_hContextMenu, i, MF_BYPOSITION | MF_ENABLED); } return TRUE; } // // dwRefData stores the index of the item that this edit control covers. // LRESULT CALLBACK ListViewEditControlSubclass(HWND hwndEdit, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { if (uMsg == WM_SIZE) { DefSubclassProc(hwndEdit, uMsg, wParam, lParam); HWND hwndList = GetParent(hwndEdit); RECT rect; ListView_GetItemRect(hwndList, dwRefData, &rect, LVIR_LABEL); MoveWindow( hwndEdit, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); return TRUE; } return DefSubclassProc(hwndEdit, uMsg, wParam, lParam); } LRESULT CALLBACK ListViewSubclass(HWND hwndList, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { if (uMsg == WM_LBUTTONDOWN) { LVHITTESTINFO lvhti; GetCursorPos(&lvhti.pt); ScreenToClient(hwndList, &lvhti.pt); if (ListView_SubItemHitTest(hwndList, &lvhti) != -1 && lvhti.iSubItem != 0) { ListView_SetItemState(hwndList, lvhti.iItem, 0, LVIS_SELECTED); ListView_SetItemState(hwndList, lvhti.iItem, 0, LVIS_FOCUSED); LuapEditCell(hwndList, lvhti.iItem, lvhti.iSubItem); return TRUE; } } else if (uMsg == WM_VSCROLL) { if (wParam == SB_PAGEUP || wParam == SB_PAGEDOWN || wParam == SB_LINEUP || wParam == SB_LINEDOWN) { DefSubclassProc(hwndList, uMsg, wParam, lParam); InvalidateRect(hwndList, NULL, FALSE); return TRUE; } } return DefSubclassProc(hwndList, uMsg, wParam, lParam); } BOOL LuapIsItemDuplicate( HWND hwndList, LPCWSTR pszText, int iItem ) { int cItems = ListView_GetItemCount(hwndList); WCHAR wszItem[MAX_PATH] = L""; LVITEM lvi; for (int i = 0 ; i < cItems; ++i) { if (i != iItem) { ListView_GetItemText(hwndList, i, 0, wszItem, MAX_PATH); if (!_wcsicmp(wszItem, pszText)) { return TRUE; } } } return FALSE; } /*++ Desc: Rules of moving an item up or down: 1) We don't allow moving multiple items. 2) If there's no items selected, this function simply does nothing. 3) We don't change the static item list so you can't move a dynamic item to inbetween 2 static ones. --*/ void LuapMoveListViewItem( HWND hwndList, int wCode ) { UINT cSelectedItems = ListView_GetSelectedCount(hwndList); if (cSelectedItems > 1) { MessageBox( hwndList, GetString(IDS_LUA_TOO_MANY_SELECTED), g_pEntryLua->strAppName, MB_ICONERROR); return; } int iSelectedIndex = ListView_GetNextItem( hwndList, -1, LVIS_SELECTED); int cItems = ListView_GetItemCount(hwndList); if (iSelectedIndex >= g_nStaticItems) { if ((wCode == IDC_LUA_UP && iSelectedIndex == g_nStaticItems) || (wCode == IDC_LUA_DOWN && iSelectedIndex == (cItems - 1))) { // // Can't move the first item up or the last item down. // return; } int iNewIndex = (wCode == IDC_LUA_UP ? (iSelectedIndex - 1) : (iSelectedIndex + 1)); BOOL bChecked = ListView_GetCheckState(hwndList, iSelectedIndex); WCHAR wszText[MAX_PATH]; WCHAR wszRedirect[32]; ListView_GetItemText(hwndList, iSelectedIndex, 0, wszText, MAX_PATH); ListView_GetItemText(hwndList, iSelectedIndex, 1, wszRedirect, 32); ListView_DeleteItem(hwndList, iSelectedIndex); LVITEM lvi; lvi.mask = LVIF_TEXT; lvi.lParam = 0; lvi.pszText = wszText; lvi.iItem = iNewIndex; lvi.iSubItem = 0; ListView_InsertItem(hwndList, &lvi); ListView_SetItemText(hwndList, iNewIndex, 1, wszRedirect); ListView_SetCheckState(hwndList, iNewIndex, bChecked); SetFocus(hwndList); ListView_SetItemState(hwndList, iNewIndex, LVIS_SELECTED, LVIS_SELECTED); } } INT_PTR CALLBACK LuapEditFileList( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: { ShowWindow(GetDlgItem(hDlg, IDC_LUA_FILE_EDIT), SW_HIDE); HWND hwndCombo = GetDlgItem(hDlg, IDC_LUA_RDIR); SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)GetString(IDS_LUA_RDIR_PERUSER)); SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)GetString(IDS_LUA_RDIR_ALLUSER)); ShowWindow(hwndCombo, SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_LUA_EDIT_BROWSE), SW_HIDE); HWND hwndUpButton = GetDlgItem(hDlg, IDC_LUA_UP); HWND hwndDownButton = GetDlgItem(hDlg, IDC_LUA_DOWN); SendMessage(hwndUpButton, WM_SETFONT, (WPARAM)g_hArrowFont, TRUE); SendMessage(hwndDownButton, WM_SETFONT, (WPARAM)g_hArrowFont, TRUE); SetWindowText(hwndUpButton, TEXT("\xE1")); SetWindowText(hwndDownButton, TEXT("\xE2")); HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); SetWindowSubclass(hwndList, ListViewSubclass, 0, 0); ListView_SetExtendedListViewStyleEx( hwndList, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_GRIDLINES); InsertColumnIntoListView(hwndList, CSTRING(IDS_LUA_FILEDIR_NAME), 0, 80); InsertColumnIntoListView(hwndList, CSTRING(IDS_LUA_REDIRECT), 1, 20); // // Set the column width of the last column of the list view appropriately // to cover the width of the list view // Assumption: The list veiw has two columns // ListView_SetColumnWidth(hwndList, 1, LVSCW_AUTOSIZE_USEHEADER); } break; case WM_NOTIFY: { NMHDR * pHdr = (NMHDR *) lParam; switch (pHdr->code) { case PSN_SETACTIVE: { if (!LuapSetAppEnvVars(hDlg)) { // // Prevent from going to the next page if any error occured. // SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); break; } ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UNTOK), g_bHasAppPathSet); LPARAM buttons = PSWIZB_BACK | PSWIZB_NEXT; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); // // First delete all items // int i; int cItems = ListView_GetItemCount(hwndList); for (i = 0; i < cItems; ++i) { ListView_DeleteItem(hwndList, 0); } // // If the lists are not there, it means we are back from the // Exclusion or the Common Path page, regenerate the lists. // if (!g_bListsInitialized) { LuapInitializeOldLists(hDlg); } // // // Populate the static items. // i = 0; PLIST_ENTRY pHead = (g_bUseNewStaticList ? &g_NewStaticList : &g_OldStaticList); for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { LuapAddItemToListView(hwndList, pEntry, i); ++i; } g_nStaticItems = i; // // Populate the dynamic items. // pHead = &g_DynamicList; for (PLIST_ENTRY pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { LuapAddItemToListView(hwndList, pEntry, i); ++i; } SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); g_TrackState = LUA_TRACK_YES; } break; case PSN_WIZNEXT: case PSN_WIZBACK: { // // Save the static and the dynamic lists. // if (!LuapSaveFileLists(GetDlgItem(hDlg, IDC_LUA_FILE_LIST))) { // // Prevent from going to the next page if any error occured. // SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1); } } break; case PSN_RESET: { LuapCleanup(); } break; case NM_CLICK: { if (g_bDuringUntokenize) { // // When we show the items untokenized, we don't allow the users // to edit anything. // break; } HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); LVHITTESTINFO lvhti; GetCursorPos(&lvhti.pt); ScreenToClient(hwndList, &lvhti.pt); if (ListView_SubItemHitTest(hwndList, &lvhti) != -1) { // // If the user clicked on a subitem, we need to show the combo box. // LuapEditCell(hwndList, lvhti.iItem, lvhti.iSubItem); } else { // // Check if the user clicked on the row right below the last item, // which means he wants to add a new row. // int iLastItem = ListView_GetItemCount(hwndList); RECT rect; g_bNewListViewItem = FALSE; if (iLastItem == 0) { g_bNewListViewItem = TRUE; } else { ListView_GetItemRect( hwndList, iLastItem - 1, &rect, LVIR_LABEL); LONG x = lvhti.pt.x; LONG y = lvhti.pt.y; LONG height = rect.bottom - rect.top; if (x > rect.left && x < rect.right && y > rect.bottom && y < (rect.bottom + height)) { g_bNewListViewItem = TRUE; } } if (g_bNewListViewItem) { LVITEM lvi; int index; lvi.mask = LVIF_TEXT; lvi.lParam = 0; lvi.pszText = L""; lvi.iItem = iLastItem; lvi.iSubItem = 0; index = ListView_InsertItem(hwndList, &lvi); ListView_SetItemText( hwndList, index, 1, GetString(IDS_LUA_RDIR_PERUSER)); SetFocus(hwndList); ListView_EditLabel(hwndList, index); g_iCurrentEditItem = iLastItem; } } } break; case NM_RCLICK: { HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); LVHITTESTINFO lvhti; GetCursorPos(&lvhti.pt); // // Display a context menu for the user to (de)select the items // and change the selection of the redirect dir. // LuapDisplayContextMenu(hwndList, &lvhti.pt); } break; case LVN_ITEMCHANGED: { // // If nothing is selected, the up/down and copy buttons will // be disabled. // int index = -1; BOOL bNoneSelected = TRUE; HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); while ((index = ListView_GetNextItem(hwndList, index, LVIS_SELECTED)) != -1) { bNoneSelected = FALSE; break; } ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UP), !bNoneSelected && !g_bDuringUntokenize); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_DOWN), !bNoneSelected && !g_bDuringUntokenize); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_COPY), !bNoneSelected && !g_bDuringUntokenize); } break; case LVN_BEGINSCROLL: { // // When the scrolling begins, we need to hide the combobox. // ShowWindow(GetDlgItem(hDlg, IDC_LUA_RDIR), SW_HIDE); SetFocus(GetDlgItem(hDlg, IDC_LUA_FILE_LIST)); } break; case LVN_KEYDOWN: { NMLVKEYDOWN* pnkd = (NMLVKEYDOWN*)lParam; if (pnkd->wVKey == VK_DELETE) { // // Delete all the selected items. // LuapDeleteSelectedItems(GetDlgItem(hDlg, IDC_LUA_FILE_LIST)); } } break; case LVN_BEGINLABELEDIT: { NMLVDISPINFO FAR *pdi = (NMLVDISPINFO FAR *) lParam; LVITEM lvi = pdi->item; BOOL bRet = (lvi.iItem < g_nStaticItems || g_bDuringUntokenize); HWND hwndList = pdi->hdr.hwndFrom; HWND hwndListViewEdit = ListView_GetEditControl(hwndList); SendMessage( hwndListViewEdit, EM_LIMITTEXT, (WPARAM)(MAX_PATH - 1), (LPARAM)0); SetWindowSubclass(hwndListViewEdit, ListViewEditControlSubclass, 0, lvi.iItem); SHAutoComplete(hwndListViewEdit, AUTOCOMPLETE); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)bRet); return bRet; } case LVN_ENDLABELEDIT: { NMLVDISPINFO FAR *pdi = (NMLVDISPINFO FAR *) lParam; LVITEM lvi = pdi->item; BOOL bRet = FALSE; if (lvi.iItem >= g_nStaticItems) { int iLastItem = ListView_GetItemCount(pdi->hdr.hwndFrom) - 1; if (g_bNewListViewItem && lvi.iItem == iLastItem && (lvi.pszText == NULL || lvi.pszText[0] == L'\0')) { // // if we are adding a new row, we delete it whether // the user cancelled or typed in something then deleted // it. // ListView_DeleteItem(pdi->hdr.hwndFrom, iLastItem); g_bNewListViewItem = FALSE; return bRet; } if (lvi.pszText && lvi.pszText[0] == L'\0') { ListView_DeleteItem(pdi->hdr.hwndFrom, lvi.iItem); } else { CSTRING strCurrentItem = lvi.pszText; if (lvi.pszText == NULL) { if (!g_bNewListViewItem) { // // If the user cancelled editing, we should still check if it's a duplicated // in case the user was editing a copied item. // WCHAR wszItem[MAX_PATH]; ListView_GetItemText( pdi->hdr.hwndFrom, lvi.iItem, 0, wszItem, MAX_PATH); strCurrentItem = wszItem; } } else { if (g_bHasAppPathSet) { // // Tokenize it. // LPWSTR pwszItem = lvi.pszText; if (!_wcsnicmp(pwszItem, g_wszAppPath, 2)) { if (!LuapSubstituteProgramFilesCommon(pwszItem, strCurrentItem)) { if (!LuapGetRelativeName(pwszItem, strCurrentItem)) { strCurrentItem = L"%APPDRIVE%"; strCurrentItem.Strcat(pwszItem + 2); } } } } } if (strCurrentItem == TEXT("")) { ListView_DeleteItem(pdi->hdr.hwndFrom, lvi.iItem); } else { ListView_SetItemText(pdi->hdr.hwndFrom, lvi.iItem, 0, strCurrentItem); } SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)FALSE); } } g_iCurrentEditItem = -1; g_bNewListViewItem = FALSE; } break; case NM_CUSTOMDRAW: { if (pHdr->hwndFrom == GetDlgItem(hDlg, IDC_LUA_FILE_LIST)) { NMLVCUSTOMDRAW* pcd = (NMLVCUSTOMDRAW*)lParam; switch (pcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)CDRF_NOTIFYITEMDRAW); return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { // // If it's a dynamic item we just let the control draw itself. // if (pcd->nmcd.dwItemSpec >= g_nStaticItems) { return CDRF_DODEFAULT; } // // Use half of the intensity of the default font to draw the static items. // HDC hdc = pcd->nmcd.hdc; COLORREF crFont = GetTextColor(hdc); COLORREF crBk = GetBkColor(hdc); pcd->clrText = LuapGetHalfIntensity(crFont, crBk); return CDRF_NEWFONT; } } return CDRF_DODEFAULT; } break; } } break; } case WM_COMMAND: if ((wNotifyCode == CBN_KILLFOCUS || wNotifyCode == CBN_SELCHANGE) && wCode == IDC_LUA_RDIR) { HWND hwndCombo = GetDlgItem(hDlg, IDC_LUA_RDIR); SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0); ShowWindow(hwndCombo, SW_HIDE); HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); WCHAR wszText[MAX_PATH]; SendMessage(hwndCombo, WM_GETTEXT, MAX_PATH, (LPARAM)wszText); ListView_SetItemText(hwndList, g_iCurrentEditItem, 1, wszText); g_iCurrentEditItem = -1; break; } if (wCode == IDC_LUA_UP || wCode == IDC_LUA_DOWN) { LuapMoveListViewItem(GetDlgItem(hDlg, IDC_LUA_FILE_LIST), wCode); break; } if (wCode == IDC_LUA_COPY) { // // Copy the selected items to the bottom of the list view. // g_bNewListViewItem = FALSE; LuapCopyItems(GetDlgItem(hDlg, IDC_LUA_FILE_LIST)); break; } if (wCode == IDC_LUA_UNTOK) { LPARAM buttons; HWND hwndList = GetDlgItem(hDlg, IDC_LUA_FILE_LIST); // // The "Show Untokenized" is only for convenience purposes so // if the user check this checkbox, we need to disable the NEXT button, // and disble editing, and prevent the user from going backward or forward // in the wizard. // if (IsDlgButtonChecked(hDlg, IDC_LUA_UNTOK) == BST_CHECKED) { buttons = 0; ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_COPY), FALSE); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UP), FALSE); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_DOWN), FALSE); g_bDuringUntokenize = TRUE; LuapTokenizeItems(hwndList, TRUE); } else { buttons = PSWIZB_BACK | PSWIZB_NEXT; ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_COPY), TRUE); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_UP), TRUE); ENABLEWINDOW(GetDlgItem(hDlg, IDC_LUA_DOWN), TRUE); g_bDuringUntokenize = FALSE; LuapTokenizeItems(hwndList, FALSE); } SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); } default: return FALSE; } return TRUE; } LONG GetDefaultExclusionList() { HKEY hKey; LONG lRet; if ((lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, LUA_APPCOMPAT_FLAGS_PATH, 0, KEY_QUERY_VALUE, &hKey)) == ERROR_SUCCESS) { DWORD dwSize = 0; if ((lRet = RegQueryValueEx( hKey, LUA_DEFAULT_EXCLUSION_LIST, NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS) { // // Prefix problem. I mean prefix is a problem :-) // try{ g_pwszDefaultExclusionList = new WCHAR [dwSize]; } catch(...) { g_pwszDefaultExclusionList = NULL; } if (g_pwszDefaultExclusionList) { if ((lRet = RegQueryValueEx( hKey, LUA_DEFAULT_EXCLUSION_LIST, NULL, NULL, (LPBYTE)g_pwszDefaultExclusionList, &dwSize)) != ERROR_SUCCESS) { delete [] g_pwszDefaultExclusionList; g_pwszDefaultExclusionList = NULL; } } else { MEM_ERR; lRet = ERROR_NOT_ENOUGH_MEMORY; } } REGCLOSEKEY(hKey); } return lRet; } INT_PTR CALLBACK LuapExclusion( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: { SendMessage( GetDlgItem(hDlg, IDC_LUA_EXTS), EM_LIMITTEXT, (WPARAM)(MAX_STRING_SIZE - 1), (LPARAM)0); } break; case WM_NOTIFY: { NMHDR * pHdr = (NMHDR *) lParam; switch (pHdr->code) { case PSN_SETACTIVE: { LPARAM buttons = PSWIZB_BACK | PSWIZB_NEXT; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); LPWSTR pwszExcludedExtensions = L""; if (g_LuaData.strExcludedExtensions.isNULL()) { // // We don't have lua data from the SDB, so display the default // exclusion list. // if (!g_pwszDefaultExclusionList) { // // Don't need to check the return value - if we can't get // it, just display an empty string. // GetDefaultExclusionList(); } if (g_pwszDefaultExclusionList) { pwszExcludedExtensions = g_pwszDefaultExclusionList; } } else { pwszExcludedExtensions = g_LuaData.strExcludedExtensions; } SetDlgItemText( hDlg, IDC_LUA_EXTS, pwszExcludedExtensions); } break; case PSN_WIZNEXT: case PSN_WIZBACK: { TCHAR szExcludedExtensions[MAX_STRING_SIZE]; GetDlgItemText( hDlg, IDC_LUA_EXTS, szExcludedExtensions, ARRAYSIZE(szExcludedExtensions)); g_LuaData.strExcludedExtensions = szExcludedExtensions; } break; case PSN_RESET: { LuapCleanup(); } break; } } default: return FALSE; } return TRUE; } void LuapGetRedirectDirs( HWND hDlg ) { WCHAR wszPath[MAX_PATH]; g_LuaData.strPerUserDir.Release(); g_LuaData.strAllUserDir.Release(); GetDlgItemText(hDlg, IDC_LUA_PERUSER_DIR, wszPath, ARRAYSIZE(wszPath)); if (wszPath[0] != L'\0') { g_LuaData.strPerUserDir = wszPath; } GetDlgItemText(hDlg, IDC_LUA_ALLUSER_DIR, wszPath, ARRAYSIZE(wszPath)); if (wszPath[0] != L'\0') { g_LuaData.strAllUserDir = wszPath; } } INT_PTR CALLBACK LuapCommonPaths( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); LPARAM buttons; switch (uMsg) { case WM_NOTIFY: { NMHDR * pHdr = (NMHDR *) lParam; switch (pHdr->code) { case PSN_SETACTIVE: { buttons = PSWIZB_BACK | PSWIZB_FINISH; SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, buttons); SetDlgItemText(hDlg, IDC_LUA_PERUSER_DIR, g_LuaData.strPerUserDir); SetDlgItemText(hDlg, IDC_LUA_ALLUSER_DIR, g_LuaData.strAllUserDir); } break; case PSN_WIZFINISH: { // // Save everything we have changed. // BOOL bChanged = FALSE; //LuapGetRedirectDirs(hDlg); if (!g_bAllUserDirUsed) { // // If the user didn't want to redirect any files to // the all user redirect dir, we need to record this. // g_LuaData.strAllUserDir.Release(); } PLUADATA pOriginalLuaData = g_psflLua->pLuaData; if (pOriginalLuaData == NULL) { if (!g_LuaData.strAllUserDir.isNULL() || !g_LuaData.strPerUserDir.isNULL() || !g_LuaData.strStaticList.isNULL() || !g_LuaData.strDynamicList.isNULL()) { pOriginalLuaData = new LUADATA; if (!pOriginalLuaData) { MEM_ERR; break; } bChanged = TRUE; } } else { if (!pOriginalLuaData->IsEqual(g_LuaData)) { bChanged = TRUE; } } if (bChanged) { pOriginalLuaData->Copy(g_LuaData); g_psflLua->pLuaData = pOriginalLuaData; } if (s_pDatabase != g_pPresentDataBase) { // // g_pPresentDataBase can change because the query and search // windows can be used to select some entry in some other database. // The TVN_SELCHANGE event changes g_pPresentDataBase // These dialogs are modeless // g_pPresentDataBase = s_pDatabase; } if (!g_pPresentDataBase->bChanged) { g_pPresentDataBase->bChanged = bChanged; SetCaption(); } LuapCleanup(); } break; } } break; default: return FALSE; } return TRUE; } /*++ Desc: This functions is called when we select the menu item for configuring the LUA for the selectd entry. Return: TRUE : if changes made are to be preserved. FALSE : if the changes should not be saved. --*/ BOOL LuaBeginWizard( HWND hParent, PDBENTRY pEntry, // Entry for which we are setting the LUA params PDATABASE pDatabase // The present database ) { s_pDatabase = pDatabase; if (pEntry == NULL || pDatabase == NULL) { assert(FALSE); return FALSE; } // // If we haven't gotten the value of %ProgramFiles%\Common Files, get it now. // This is not going to change anyway so we only get it once. // if (g_wszProgramFilesCommon[0] == L'\0') { DWORD cBufferLen = MAX_PATH - COMMON_FILES_LEN; if ((g_czProgramFilesCommon = GetEnvironmentVariableW( L"ProgramFiles", g_wszProgramFilesCommon, cBufferLen)) && g_czProgramFilesCommon < cBufferLen) { wcsncat(g_wszProgramFilesCommon, COMMON_FILES, COMMON_FILES_LEN); g_czProgramFilesCommon += COMMON_FILES_LEN; g_wszProgramFilesCommon[g_czProgramFilesCommon] = L'\0'; } else { MessageBoxA( hParent, "Failed to get the value of %ProgramFiles% or it's too long", "Error", MB_ICONERROR); g_wszProgramFilesCommon[0] = L'\0'; g_czProgramFilesCommon = 0; return FALSE; } } g_bAllUserDirUsed = FALSE; g_bUseNewStaticList = TRUE; g_TrackState = LUA_TRACK_UNKNOWN; g_psflLua = NULL; g_pEntryLua = pEntry; g_psflLua = IsLUARedirectFSPresent(pEntry); if (g_psflLua == NULL) { assert(FALSE); return FALSE; } LuapGetDataFromEntry(g_psflLua->pLuaData); if (g_TrackState == LUA_TRACK_UNKNOWN) { // // We shouldn't get here!!! // MessageBox( hParent, GetString(IDS_LUA_ERROR_FIND), pEntry->strAppName, MB_ICONERROR); return FALSE; } if (g_hArrowFont == NULL) { g_hArrowFont = CreateFont( 14, 0, 0, 0, FW_DONTCARE, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, TEXT("Wingdings")); if (g_hArrowFont == NULL) { MessageBox( NULL, GetString(IDS_LUA_ARROW_FONT), g_pEntryLua->strAppName, MB_ICONERROR); return FALSE; } } PROPSHEETPAGE Pages[NUM_PAGES_LUA] = {0}; ZeroMemory(Pages, sizeof(Pages)); // // Begin the wizard // PROPSHEETHEADER Header = {0}; Header.dwSize = sizeof(PROPSHEETHEADER); Header.dwFlags = PSH_WIZARD97 | PSH_HEADER | PSH_WATERMARK | PSH_PROPSHEETPAGE; Header.hwndParent = hParent; Header.hInstance = g_hInstance; Header.nStartPage = 0; Header.ppsp = Pages; Header.nPages = NUM_PAGES_LUA; Header.pszbmHeader = MAKEINTRESOURCE(IDB_WIZBMP); Header.pszbmWatermark = MAKEINTRESOURCE(IDB_TOOL); Pages[PAGE_LUA_ACTION].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_LUA_ACTION].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; Pages[PAGE_LUA_ACTION].hInstance = g_hInstance; Pages[PAGE_LUA_ACTION].pszTemplate = MAKEINTRESOURCE(IDD_LUA_ACTION); Pages[PAGE_LUA_ACTION].pfnDlgProc = LuapAction; Pages[PAGE_LUA_ACTION].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_TRACK_FILES); Pages[PAGE_LUA_ACTION].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_TRACK_FILES_SUBHEADING); Pages[PAGE_LUA_EXCLUSION].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_LUA_EXCLUSION].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; Pages[PAGE_LUA_EXCLUSION].hInstance = g_hInstance; Pages[PAGE_LUA_EXCLUSION].pszTemplate = MAKEINTRESOURCE(IDD_LUA_EXCLUSION); Pages[PAGE_LUA_EXCLUSION].pfnDlgProc = LuapExclusion; Pages[PAGE_LUA_EXCLUSION].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_EXCLUSION_HEADING); Pages[PAGE_LUA_EXCLUSION].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_EXCLUSION_SUBHEADING); Pages[PAGE_LUA_EDIT_FILE_LIST].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_LUA_EDIT_FILE_LIST].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; Pages[PAGE_LUA_EDIT_FILE_LIST].hInstance = g_hInstance; Pages[PAGE_LUA_EDIT_FILE_LIST].pszTemplate = MAKEINTRESOURCE(IDD_LUA_TRACKED_FILES); Pages[PAGE_LUA_EDIT_FILE_LIST].pfnDlgProc = LuapEditFileList; Pages[PAGE_LUA_EDIT_FILE_LIST].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_EDIT_FILE_LIST); Pages[PAGE_LUA_EDIT_FILE_LIST].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_EDIT_FILE_LIST_SUBHEADING); Pages[PAGE_LUA_COMMON_PATHS].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_LUA_COMMON_PATHS].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; Pages[PAGE_LUA_COMMON_PATHS].hInstance = g_hInstance; Pages[PAGE_LUA_COMMON_PATHS].pszTemplate = MAKEINTRESOURCE(IDD_LUA_COMMON_PATHS); Pages[PAGE_LUA_COMMON_PATHS].pfnDlgProc = LuapCommonPaths; Pages[PAGE_LUA_COMMON_PATHS].pszHeaderTitle = MAKEINTRESOURCE(IDS_LUA_COMMON_PATHS_HEADING); Pages[PAGE_LUA_COMMON_PATHS].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LUA_COMMON_PATHS_SUBHEADING); if (PropertySheet(&Header) < 0) { return FALSE; } return TRUE; } BOOL GetDBStringData( const PDB pdb, const TAGID tiFix, LPCWSTR pwszName, CSTRING& strValue ) { WCHAR wsz[32]; DWORD dwDataType, cSize = 0; if (SdbQueryDataExTagID(pdb, tiFix, pwszName, &dwDataType, NULL, &cSize, NULL) != ERROR_INSUFFICIENT_BUFFER) { Dbg(dlWarning,"Cannot get the size for DATA named %S\n", pwszName); return FALSE; } LPWSTR pwszValue = new WCHAR [cSize / sizeof(WCHAR)]; if (pwszValue == NULL) { MEM_ERR; return FALSE; } if (SdbQueryDataExTagID( pdb, tiFix, pwszName, &dwDataType, pwszValue, &cSize, NULL) != ERROR_SUCCESS) { Dbg(dlWarning,"Cannot read the VALUE of DATA named %S\n", pwszName); return FALSE; } strValue = pwszValue; delete [] pwszValue; return TRUE; } /*++ Desc: This function gets the pdb and the tagid for the layer or the shim and creates a LUADATA* and returns it back. This function is invoked when we are reading in the .SDB file. Return: Valid LUADATA* if there is one NULL: Otherwise. --*/ PLUADATA LuaProcessLUAData( const PDB pdb, const TAGID tiFix ) { PLUADATA pLuaData = new LUADATA; if (pLuaData == NULL) { MEM_ERR; } else { GetDBStringData(pdb, tiFix, LUA_DATA_ALLUSERDIR, pLuaData->strAllUserDir); GetDBStringData(pdb, tiFix, LUA_DATA_PERUSERDIR, pLuaData->strPerUserDir); GetDBStringData(pdb, tiFix, LUA_DATA_STATICLIST, pLuaData->strStaticList); GetDBStringData(pdb, tiFix, LUA_DATA_DYNAMICLIST, pLuaData->strDynamicList); GetDBStringData(pdb, tiFix, LUA_DATA_EXCLUDEDEXTENSIONS, pLuaData->strExcludedExtensions); } return pLuaData; } BOOL LuapAddDataNode( LPCWSTR pwszName, CSTRING& strValue, CSTRINGLIST& strlXML ) { CSTRING strSpecialChar; TCHAR szSpace[64]; INT iszSpaceSize = 0; *szSpace = 0; iszSpaceSize = ARRAYSIZE(szSpace); if (!strValue.isNULL() && strValue.pszString[0] != 0) { CSTRING strTemp; strTemp.Sprintf(TEXT("%s")); if (!strlXML.AddString(strTemp)) { return FALSE; } } return TRUE; } /*++ Desc: This function is called when we are about to write out the data to an XML file. Return: TRUE : If valid added has been added to strlXML FALSE: Otherwise --*/ BOOL LuaGenerateXML( PLUADATA pLuaData, CSTRINGLIST& strlXML ) { return (LuapAddDataNode(LUA_DATA_ALLUSERDIR, pLuaData->strAllUserDir, strlXML) && LuapAddDataNode(LUA_DATA_PERUSERDIR, pLuaData->strPerUserDir, strlXML) && LuapAddDataNode(LUA_DATA_STATICLIST, pLuaData->strStaticList, strlXML) && LuapAddDataNode(LUA_DATA_DYNAMICLIST, pLuaData->strDynamicList, strlXML) && LuapAddDataNode(LUA_DATA_EXCLUDEDEXTENSIONS, pLuaData->strExcludedExtensions, strlXML)); }