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
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));
|
|
}
|