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

/*++
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:
<APP NAME="Some app" VENDOR="Some company">
<EXE NAME="Some executable">
<SHIM NAME="LUARedirectFS">
<DATA NAME="AllUserDir" VALUETYPE="STRING"
VALUE="%ALLUSERSPROFILE%\AllUserRedirect"/>
<DATA NAME="PerUserDir" VALUETYPE="STRING"
VALUE="%USERSPROFILE%\Redirect"/>
<DATA NAME="StaticList" VALUETYPE="STRING"
VALUE="AC-%APPDRIVE%\a\;PU-%APPPATH%\b.txt"/>
<DATA NAME="DynamicList" VALUETYPE="STRING"
VALUE="AC-%APPPATH%\b\;PU-c:\b\b.txt;AU-c:\c\"/>
<DATA NAME="ExcludedExtensions" VALUETYPE="STRING"
VALUE="doc txt gif"/>
</SHIM>
</EXE>
</APP>
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 <DATA> 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("<?xml version=\"1.0\" encoding=\"UTF-16\"?>")) ||
!strlXML->AddString(TEXT("<DATABASE NAME=\"Test database\">"))) {
return FALSE;
}
strTemp.Sprintf(TEXT("\t<APP NAME=\"%s\" VENDOR=\"%s\">"),
(LPCTSTR)(pEntry->strAppName.SpecialCharToXML()),
(LPCTSTR)(pEntry->strVendor.SpecialCharToXML()));
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
strTemp.Sprintf(TEXT("\t\t<EXE NAME=\"%s\">"),
(LPCTSTR)pEntry->strExeName.SpecialCharToXML());
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
if (!strlXML->AddString(TEXT("\t\t\t<SHIM NAME= \"LUATrackFS\"/>")) ||
!strlXML->AddString(TEXT("\t\t</EXE>")) ||
!strlXML->AddString(TEXT("\t</APP>")) ||
!strlXML->AddString(TEXT("</DATABASE>"))) {
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 <DATA> section and the COMMAND_LINE of LUARedirectFS.
For each item in command line, look it up in <DATA> so we know how to display
those items in <DATA> in the UI.
--*/
BOOL
LuapMergeLists(
BOOL bMergeOld, // Merge the old data from the <DATA> 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<DATA NAME=\"%s\" VALUETYPE=\"STRING\""),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
pwszName);
if (!strlXML.AddString(strTemp)) {
return FALSE;
}
strSpecialChar = strValue.SpecialCharToXML();
strTemp.Sprintf(TEXT("%sVALUE=\""), GetSpace(szSpace, TAB_SIZE * 5, iszSpaceSize));
strTemp.Strcat(strValue.SpecialCharToXML().pszString);
strTemp.Strcat(TEXT("\"/>"));
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));
}