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.
 
 
 
 
 
 

6391 lines
168 KiB

/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
dbsupport.cpp
Abstract:
Code for the functions that perform most of the database related tasks
Author:
kinshu created July 2, 2001
Revision History:
--*/
#include "precomp.h"
//////////////////////// Extern variables /////////////////////////////////////
extern BOOL g_bWin2K;
extern HINSTANCE g_hInstance;
extern HWND g_hDlg;
extern HWND g_hwndContentsList;
extern TCHAR g_szData[1024];
extern CSTRINGLIST g_strMRU;
extern PDBENTRY g_pEntrySelApp;
extern HWND g_hwndEntryTree;
extern UINT g_uNextDataBaseIndex;
extern BOOL g_bIsCut;
///////////////////////////////////////////////////////////////////////////////
//////////////////////// Defines //////////////////////////////////////////////
// Size of a temporary buffer that is used to read in strings from the database
#define MAX_DATA_SIZE 1024
// The size of a buffer that holds the names of shims, layers, patches
#define MAX_NAME MAX_PATH
//
// The guid of the system db. Note that on Win2kSP3, it is not this constant, so we should
// NOT rely on this.
#define GUID_SYSMAIN_SDB _T("{11111111-1111-1111-1111-111111111111}")
// Guid of apphelp.sdb. There is no apphelp.sdb in Win2K
#define GUID_APPHELP_SDB _T("{22222222-2222-2222-2222-222222222222}")
// Guid of systest.sdb. This is no longer used
#define GUID_SYSTEST_SDB _T("{33333333-3333-3333-3333-333333333333}")
// Guid of drvmain.sdb
#define GUID_DRVMAIN_SDB _T("{F9AB2228-3312-4A73-B6F9-936D70E112EF}")
// Guid of msimain.sdb
#define GUID_MSI_SDB _T("{d8ff6d16-6a3a-468a-8b44-01714ddc49ea}")
// Used to check if the entry is disabled
#define APPCOMPAT_DISABLED 0x03
// Key of AppCompat data in the registry. This will contain the disable status of
// various entries
#define APPCOMPAT_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags")
///////////////////////////////////////////////////////////////////////////////
//////////////////////// Function Declarations /////////////////////////////////
INT_PTR CALLBACK
DatabaseRenameDlgProc(
HWND hdlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
BOOL
HandleFirstEntryofAppDeletion(
PDATABASE pDataBase,
PDBENTRY pApp,
BOOL bRepaint
);
BOOL
GetEntryXML(
CSTRINGLIST* strlXML,
PDBENTRY pEntry
);
///////////////////////////////////////////////////////////////////////////////
//////////////////////// Global Variables /////////////////////////////////////
// This is the system database
struct DataBase GlobalDataBase(DATABASE_TYPE_GLOBAL);
// The list of custom databases
struct tagDataBaseList DataBaseList;
// The list of installed databases
struct tagDataBaseList InstalledDataBaseList;
// Should we show the entry conflict dialog. Presently this is not used and is always FALSE
BOOL g_bEntryConflictDonotShow = FALSE;
// Temporary buffer for reading strings from the database
WCHAR g_wszData[MAX_DATA_SIZE];
// Used to convert from special chars to valid XML and vice-versa
SpecialCharMap g_rgSpecialCharMap[4][2] = {
TEXT("&"), 1, TEXT("&"), 5, // 5 is the length of the string in the prev. column
TEXT("\""), 1, TEXT("""), 6,
TEXT("<"), 1, TEXT("&lt;"), 4,
TEXT(">"), 1, TEXT("&gt;"), 4
};
//
// The various possible attributes for matching files
//
// Caution:
// If you change g_Attributes or their order,
// you will have to change DEFAULT_MASK in CompatAdmin.h
//
TAG g_Attributes[] = {
TAG_SIZE,
TAG_CHECKSUM,
TAG_BIN_FILE_VERSION,
TAG_BIN_PRODUCT_VERSION,
TAG_PRODUCT_VERSION,
TAG_FILE_DESCRIPTION,
TAG_COMPANY_NAME,
TAG_PRODUCT_NAME,
TAG_FILE_VERSION,
TAG_ORIGINAL_FILENAME,
TAG_INTERNAL_NAME,
TAG_LEGAL_COPYRIGHT,
TAG_VERDATEHI,
TAG_VERDATELO,
TAG_VERFILEOS,
TAG_VERFILETYPE,
TAG_MODULE_TYPE,
TAG_PE_CHECKSUM,
TAG_LINKER_VERSION,
#ifndef KERNEL_MODE
TAG_16BIT_DESCRIPTION,
TAG_16BIT_MODULE_NAME,
#endif
TAG_UPTO_BIN_FILE_VERSION,
TAG_UPTO_BIN_PRODUCT_VERSION,
TAG_LINK_DATE,
TAG_UPTO_LINK_DATE,
TAG_VER_LANGUAGE
};
// Total number of attributes available
DWORD ATTRIBUTE_COUNT = ARRAYSIZE(g_Attributes);
///////////////////////////////////////////////////////////////////////////////
BOOL
CheckRegistry(
IN HKEY hkeyRoot,
IN LPCTSTR pszGUID
)
/*++
CheckRegistry
Desc: Checks if the entry with GUID pszGUID is disabled
Params:
IN HKEY hkeyRoot: The key under which to search
IN LPCTSTR pszGUID: The guid of the entry
Return:
TRUE: The entry is disabled
FALSE: The entry is enabled or there was some error
--*/
{
LONG status;
HKEY hkey = NULL;
BOOL bDisabled = FALSE;
DWORD dwFlags;
DWORD type;
DWORD cbSize = sizeof(DWORD);
status = RegOpenKey(hkeyRoot, APPCOMPAT_KEY, &hkey);
if (status != ERROR_SUCCESS) {
return FALSE;
}
status = RegQueryValueEx(hkey, pszGUID, NULL, &type, (LPBYTE)&dwFlags, &cbSize);
if (status == ERROR_SUCCESS && type == REG_DWORD && (dwFlags & APPCOMPAT_DISABLED)) {
bDisabled = TRUE;
}
REGCLOSEKEY(hkey);
return bDisabled;
}
BOOL
SetDisabledStatus(
IN HKEY hKeyRoot,
IN PCTSTR pszGuid,
IN BOOL bDisabled
)
/*++
SetDisabledStatus
Desc: Sets the disabled status of a entry
Params:
IN HKEY hkeyRoot: The AppCompat Key
IN PCTSTR pszGUID: The guid of the entry
IN BOOL bDisabled: Do we want to make it disabled?
Return:
TRUE: The entry's status has been changed
FALSE: There was some error
--*/
{
DWORD dwFlags = 0;
HKEY hkey = NULL;
DWORD dwValue = 0x03;
DWORD dwDisposition = 0;
LONG status;
if (bDisabled == TRUE) {
dwFlags = 0x1;
}
status = RegOpenKey(hKeyRoot, APPCOMPAT_KEY, &hkey);
if (status != ERROR_SUCCESS) {
status = RegCreateKeyEx(hKeyRoot,
APPCOMPAT_KEY,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hkey,
&dwDisposition);
if (status != ERROR_SUCCESS) {
return FALSE;
}
}
status = RegSetValueEx(hkey,
pszGuid,
0,
REG_DWORD,
(LPBYTE) &dwFlags,
sizeof(DWORD));
REGCLOSEKEY(hkey);
return ((status == ERROR_SUCCESS) ? TRUE : FALSE);
}
BOOL
RemoveEntry(
IN PDATABASE pDataBase,
IN PDBENTRY pEntryToRemove,
IN PDBENTRY pApp,
IN BOOL bRepaint //def = TRUE
)
/*++
RemoveEntry
Desc: Remove an Entry from the database. This will also do any UI updates.
Params:
IN PDATABASE pDataBase: The database in which the entry being removed lives
IN PDBENTRY pEntryToRemove: The entry to remove
IN PDBENTRY pApp: The fist entry for the app to which this entry belongs
IN BOOL bRepaint: <TODO>
Return:
TRUE: The entry has been removed
FALSE: There was some error
--*/
{
if (pEntryToRemove == NULL) {
return FALSE;
}
PDBENTRY pPrev = NULL;
PDBENTRY pEntry = pApp;
HTREEITEM hItemEntryExe = NULL, htemEntrySibling = NULL;
while (pEntry) {
if (pEntry == pEntryToRemove) {
break;
}
pPrev = pEntry;
pEntry = pEntry->pSameAppExe;
}
if (pEntry == pEntryToRemove && pEntry != NULL) {
if (pEntry == pApp) {
//
// First entry for the app. Note that this routine does not actually remove this
// pEntry. Does stuff only on the UI
//
HandleFirstEntryofAppDeletion(pDataBase, pEntry, bRepaint);
} else {
assert(pPrev);
if (pPrev) {
pPrev->pSameAppExe = pEntry->pSameAppExe;
}
}
// [BUGBUG]: We need to keep this in the destructor of PDBENTRY
if (pEntry->appHelp.bPresent) {
DeleteAppHelp(pDataBase, pEntry->appHelp.HTMLHELPID);
pEntry->appHelp.bBlock = pEntry->appHelp.bPresent = FALSE;
pEntry->appHelp.severity = APPTYPE_NONE;
}
//
// Now we have to set the focus to some sibling of the deleted entry and
// Update the g_pSelEntry
//
if (!(pApp == pEntryToRemove && pApp->pSameAppExe == NULL)) {
//
// The previous entry tree will be still there only if the condition is true
// Otherwise the old tree will have gone because HandleFirstEntryofAppDeletion
// will have caused the sibling of the app being deleted to be selected and the
// previous entry tree will no
// longer be there
// We will have a new entry tree of the second app.
//
hItemEntryExe = NULL, htemEntrySibling = NULL;
hItemEntryExe = CTree::FindChild(g_hwndEntryTree, TVI_ROOT, (LPARAM)pEntryToRemove);
if (hItemEntryExe) {
htemEntrySibling = TreeView_GetNextSibling(g_hwndEntryTree, hItemEntryExe);
if (htemEntrySibling == NULL) {
htemEntrySibling = TreeView_GetPrevSibling(g_hwndEntryTree,
hItemEntryExe);
}
SendMessage(g_hwndEntryTree, WM_SETREDRAW, FALSE, 0);
TreeView_DeleteItem(g_hwndEntryTree, hItemEntryExe);
SendMessage(g_hwndEntryTree, WM_SETREDRAW, TRUE, 0);
//
// g_pSelEntry will get changed in the notification handler for the tree
//
if (htemEntrySibling && bRepaint) {
TreeView_SelectItem(g_hwndEntryTree, htemEntrySibling);
}
}
}
ValidateClipBoard(NULL, pEntry);
//
// Has destructor
//
delete pEntry;
} else {
assert(FALSE);
return FALSE;
}
return TRUE;
}
LPVOID
FindFix(
IN PCTSTR pszFixName,
IN TYPE fixType,
IN PDATABASE pDataBase // (NULL)
)
/*++
FindFix
Desc: Searches for a fix of type fixType in pDataBase with name pszFixName
Params:
IN LPCTSTR pszFixName: The fix to search for
IN TYPE fixType: The type of the fix. One of
a) FIX_SHIM
b) FIX_FLAG
c) FIX_LAYER
d) FIX_PATCH
IN PDATABASE pDataBase(NULL): The database in which to search.
If this is NULL we search in the GlobalDatabase
Return:
The pointer to the fix if found
NULL otherwise
--*/
{
if (pszFixName == NULL) {
assert(FALSE);
return NULL;
}
switch (fixType) {
case FIX_SHIM:
{
PSHIM_FIX pFix = GlobalDataBase.pShimFixes;
while (pFix) {
if (pFix->strName.Length() && !lstrcmpi(pszFixName, pFix->strName)) {
return pFix;
}
pFix = pFix->pNext;
}
break;
}
case FIX_FLAG:
{
PFLAG_FIX pFix = GlobalDataBase.pFlagFixes;
while (pFix) {
if (pFix->strName.Length() && !lstrcmpi(pszFixName, pFix->strName)) {
return pFix;
}
pFix = pFix->pNext;
}
break;
}
case FIX_LAYER:
{
//
// Search in the local database.
//
if (pDataBase == NULL || pDataBase == &GlobalDataBase) {
goto SearchGlobal;
}
PLAYER_FIX pFix = pDataBase->pLayerFixes;
while (pFix) {
if (pFix->strName.Length() && !lstrcmpi(pszFixName, pFix->strName)) {
return pFix;
}
pFix = pFix->pNext;
}
//
// Search in the global database.
//
SearchGlobal:
pFix = GlobalDataBase.pLayerFixes;
while (pFix) {
if (pFix->strName.Length() && !lstrcmpi(pszFixName, pFix->strName)) {
return pFix;
}
pFix = pFix->pNext;
}
break;
}
case FIX_PATCH:
{
PPATCH_FIX pFix = GlobalDataBase.pPatchFixes;
while (pFix) {
if (pFix->strName.Length() && !lstrcmpi(pszFixName, pFix->strName)) {
return pFix;
}
pFix = pFix->pNext;
}
break;
}
}
return NULL;
}
CSTRING
ReadDBString(
IN PDB pDB,
IN TAGID tagID
)
/*++
ReadDBString
Desc: Reads a string from the database
Params:
IN PDB pDB: The database
IN TAGID tagID: The tag id for the string type
Return: The string read. Will return a string of zero length if there is some error
--*/
{
CSTRING Str;
K_SIZE k_pszAppName = MAX_STRING_SIZE;
PTSTR pszAppName = new TCHAR[k_pszAppName];
if (pszAppName == NULL) {
MEM_ERR;
goto End;
}
if (pDB == NULL) {
goto End;
}
if (!SdbReadStringTag(pDB, tagID, pszAppName, k_pszAppName)) {
assert(FALSE);
goto End;
}
pszAppName[k_pszAppName - 1] = 0;
Str = pszAppName;
Str.XMLToSpecialChar();
End:
if (pszAppName) {
delete[] pszAppName;
pszAppName = NULL;
}
return Str;
}
BOOL
ReadAppHelp(
IN PDB pdb,
IN TAGID tiAppHelp,
IN PDATABASE pDataBase
)
/*++
ReadAppHelp
Desc: Reads the apphelp from the library section of the database
Params:
IN PDB pdb: The database pdb
IN TAGID tiAppHelp: The TAGID for the apphelp
IN PDATABASE pDataBase: The database in which to add the apphelp
Return:
TRUE: The apphelp was read and added to the database
FALSE: There was some error
Notes: We do not read the apphelp for system database. The apphelp for system database
is kept in apphelp.sdb. For system database, this function will apparently not get
called
--*/
{
TAGID tiInfo;
PAPPHELP pAppHelp = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "ReadAppHelp NULL pDataBase passed");
return FALSE;
}
pAppHelp = new APPHELP;
if (pAppHelp == NULL) {
MEM_ERR;
goto error;
}
//
// Add for the specified database.
//
pAppHelp->pNext = pDataBase->pAppHelp;
pDataBase->pAppHelp = pAppHelp;
tiInfo = SdbGetFirstChild(pdb, tiAppHelp);
while (0 != tiInfo) {
TAG tag;
tag = SdbGetTagFromTagID(pdb, tiInfo);
switch (tag) {
case TAG_HTMLHELPID:
pAppHelp->HTMLHELPID = SdbReadDWORDTag(pdb, tiInfo, 0);
//
// Set the highest html id for the database. The next apphelp message
// should have a value one more than this
//
if (pAppHelp->HTMLHELPID > pDataBase->m_nMAXHELPID) {
pDataBase->m_nMAXHELPID = pAppHelp->HTMLHELPID;
}
break;
case TAG_LINK:
{
TAGID tagLink = SdbFindFirstTag(pdb, tiAppHelp, TAG_LINK);
//
// Get the apphelp URL
//
if (tagLink) {
tagLink = SdbFindFirstTag(pdb, tagLink, TAG_LINK_URL);
pAppHelp->strURL = ReadDBString(pdb, tagLink);
}
}
break;
case TAG_APPHELP_DETAILS:
//
// Get the apphelp text message
//
pAppHelp->strMessage = ReadDBString(pdb, tiInfo);
break;
}
tiInfo = SdbGetNextChild(pdb, tiAppHelp, tiInfo);
}
return TRUE;
error:
if (pAppHelp) {
delete pAppHelp;
pAppHelp = NULL;
}
return FALSE;
}
BOOL
ReadIncludeExlude(
IN PDB pdb,
IN TAGID tiShim,
OUT CSTRINGLIST& strlInExclude
)
/*++
ReadIncludeExlude
Desc: Reads the include-exclude list for a shim
Params:
IN PDB pdb: The database pdb
IN TAGID tiShim: TAGID for TAG_SHIM or TAG_SHIM_REF
OUT CSTRINGLIST& strlInExclude: The include-exclude module names will be stored in
this
Return:
TRUE: The include-exclude list was read properly
FALSE: There was some error
Notes: In the .sdb the include exclude modules are arranged in this way
0x0000012E | 0x7003 | INEXCLUDE | LIST | Size 0x00000006
0x00000134 | 0x6003 | MODULE | STRINGREF | out.dll
-end- INEXCLUDE
0x0000013A | 0x7003 | INEXCLUDE | LIST | Size 0x00000008
0x00000140 | 0x1001 | INCLUDE | NULL |
0x00000142 | 0x6003 | MODULE | STRINGREF | IN.DLL
-end- INEXCLUDE
The above means that first exclude the module out.dll then
include the module in.dll
--*/
{
TAGID tiInExclude;
BOOL bReturn = FALSE;
CSTRING strTemp;
//
// Read the INCLUSION list
//
tiInExclude = SdbFindFirstTag(pdb, tiShim, TAG_INEXCLUDE);
if (tiInExclude == TAGID_NULL) {
return FALSE;
}
while (tiInExclude) {
TAGID tiInfo = SdbFindFirstTag(pdb, tiInExclude, TAG_INCLUDE);
if (tiInfo != TAGID_NULL) {
tiInfo = SdbFindFirstTag(pdb, tiInExclude, TAG_MODULE);
if (tiInfo != 0) {
strTemp = ReadDBString(pdb, tiInfo);
if (strTemp == TEXT("$")) {
//
// Means include the module being fixed
//
strTemp = GetString(IDS_INCLUDEMODULE);
}
strlInExclude.AddStringAtBeg(strTemp, INCLUDE);
bReturn= TRUE;
}
} else {
//
// Look for exclusions
//
tiInfo = SdbFindFirstTag(pdb, tiInExclude, TAG_MODULE);
if (tiInfo != 0) {
strTemp = ReadDBString(pdb, tiInfo);
strlInExclude.AddStringAtBeg(strTemp, EXCLUDE);
bReturn= TRUE;
}
}
tiInExclude = SdbFindNextTag(pdb, tiShim, tiInExclude);
}
return bReturn;
}
BOOL
AddShimFix(
IN PDB pdb,
IN TAGID tiFix,
IN OUT PDBENTRY pEntry,
IN OUT PLAYER_FIX pLayerFix,
IN BOOL bAddToLayer
)
/*++
AddShimFix
Desc: Adds a shim fix list in an entry or a layer
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: TAG_SHIM_REF
IN OUT PDBENTRY pEntry: The pointer to entry if we want to add this shim to an entry
IN OUT PLAYER_FIX pLayerFix: The pointer to a layer if we want to add this shim to a layer
IN BOOL bAddToLayer: Do we want to add this to a layer or an entry?
Return:
TRUE: Shim was added properly
FALSE: There was some error
--*/
{
TAGID tiName;
TCHAR szFixName[MAX_NAME];
PSHIM_FIX pFix;
PSHIM_FIX_LIST pFixList;
BOOL bOk = TRUE;
tiName = SdbFindFirstTag(pdb, tiFix, TAG_NAME);
if (!SdbReadStringTag(pdb, tiName, g_wszData, ARRAYSIZE(g_wszData))) {
Dbg(dlError, "Cannot read the name of the fix\n");
return FALSE;
}
SafeCpyN(szFixName, g_wszData, ARRAYSIZE(szFixName));
pFix = (PSHIM_FIX)FindFix(CSTRING(szFixName).XMLToSpecialChar(), FIX_SHIM);
if (pFix == NULL) {
Dbg(dlError, "Cannot find fix ref for: \"%S\" type %d\n", szFixName, FIX_SHIM);
return FALSE;
}
pFixList = new SHIM_FIX_LIST;
if (pFixList == NULL) {
Dbg(dlError, "Cannot allocate %d bytes\n", sizeof(SHIM_FIX_LIST));
return FALSE;
}
pFixList->pShimFix = pFix;
tiName = SdbFindFirstTag(pdb, tiFix, TAG_COMMAND_LINE);
if (tiName != TAGID_NULL) {
pFixList->strCommandLine = ReadDBString(pdb, tiName);
}
tiName = SdbFindFirstTag(pdb, tiFix, TAG_INEXCLUDE);
if (tiName != TAGID_NULL) {
ReadIncludeExlude(pdb, tiFix, pFixList->strlInExclude);
}
if (pFix->strName.BeginsWith(TEXT("LUARedirectFS"))) {
//
// Get the data for LUARedirectFS shim
//
pFixList->pLuaData = LuaProcessLUAData(pdb, tiFix);
}
if (bAddToLayer == FALSE) {
if (pEntry) {
pFixList->pNext = pEntry->pFirstShim;
pEntry->pFirstShim = pFixList;
} else {
assert(FALSE);
Dbg(dlError, "AddShimFix bAddLayer == FALSE and pEntry == NULL");
bOk = FALSE;
}
} else {
//
// We want to put this in the layer list of the library.
//
if (pLayerFix) {
pFixList->pNext = pLayerFix->pShimFixList;
pLayerFix->pShimFixList = pFixList;
++pLayerFix->uShimCount;
} else {
bOk = FALSE;
assert(FALSE);
Dbg(dlError, "AddShimFix bAddLayer == TRUE and pLayerFix == NULL");
}
}
if (bOk == FALSE && pFixList) {
assert(FALSE);
delete pFixList;
pFixList = NULL;
}
return bOk;
}
BOOL
AddFlagFix(
IN PDB pdb,
IN TAGID tiFix,
IN OUT PDBENTRY pEntry,
IN OUT PLAYER_FIX pLayerFix,
IN BOOL bAddToLayer
)
/*++
AddFlagFix
Desc: Adds a flag fix list in an entry or a layer
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: TAG_FLAG_REF
IN OUT PDBENTRY pEntry: The pointer to entry if we want to add this flag to an entry
IN OUT PLAYER_FIX pLayerFix: The pointer to a layer if we want to add this flag to a layer
IN BOOL bAddToLayer: Do we want to add this to a layer or an entry?
Return:
TRUE: Flag was added properly
FALSE: There was some error
--*/
{
TAGID tiName;
TCHAR szFixName[MAX_NAME];
PFLAG_FIX pFix = NULL;
PFLAG_FIX_LIST pFixList = NULL;
BOOL bOk = TRUE;
tiName = SdbFindFirstTag(pdb, tiFix, TAG_NAME);
if (!SdbReadStringTag(pdb, tiName, g_wszData, ARRAYSIZE(g_wszData))) {
Dbg(dlError, "Cannot read the name of the fix\n");
bOk = FALSE;
goto End;
}
SafeCpyN(szFixName, g_wszData, ARRAYSIZE(szFixName));
szFixName[ARRAYSIZE(szFixName) - 1] = 0;
pFix = (PFLAG_FIX)FindFix(CSTRING(szFixName).XMLToSpecialChar(), FIX_FLAG);
if (pFix == NULL) {
Dbg(dlError, "Cannot find fix ref for: \"%S\" type %d\n", szFixName, FIX_FLAG);
bOk = FALSE;
goto End;
}
pFixList = new FLAG_FIX_LIST;
if (pFixList == NULL) {
Dbg(dlError, "Cannot allocate %d bytes\n", sizeof(FLAG_FIX_LIST));
bOk = FALSE;
goto End;
}
pFixList->pFlagFix = pFix;
//
// Add the commandline for flags
//
tiName = SdbFindFirstTag(pdb, tiFix, TAG_COMMAND_LINE);
if (tiName != TAGID_NULL) {
pFixList->strCommandLine = ReadDBString(pdb, tiName);
}
if (bAddToLayer == FALSE) {
if (pEntry == NULL) {
//
// We wanted this flag to be added to an entry but did not give a pointer to the entry
//
assert(FALSE);
bOk = FALSE;
goto End;
}
pFixList->pNext = pEntry->pFirstFlag;
pEntry->pFirstFlag = pFixList;
} else {
//
// We want to put this in the layer list of the library.
//
if (pLayerFix == NULL) {
assert(FALSE);
bOk = FALSE;
goto End;
}
pFixList->pNext = pLayerFix->pFlagFixList;
pLayerFix->pFlagFixList = pFixList;
++pLayerFix->uShimCount;
}
End:
if (bOk == FALSE) {
//
// There was some error, free any memory that we might have allocated in this routine
//
assert(FALSE);
if (pFixList) {
delete pFixList;
pFixList = NULL;
}
}
return bOk;
}
BOOL
AddPatchFix(
IN PDB pdb,
IN TAGID tiFix,
IN OUT PDBENTRY pEntry
)
/*++
AddPatchFix
Desc: Adds a patch fix list in an entry
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: TAG_PATCH_REF
IN OUT PDBENTRY pEntry: The pointer to entry that we want the patch to be added
Return:
TRUE: Patch was added properly
FALSE: There was some error
--*/
{
TAGID tiName;
TCHAR szFixName[MAX_NAME];
PPATCH_FIX pFix;
PPATCH_FIX_LIST* ppHead;
PPATCH_FIX_LIST pFixList;
if (pEntry == NULL) {
assert(FALSE);
return FALSE;
}
tiName = SdbFindFirstTag(pdb, tiFix, TAG_NAME);
if (!SdbReadStringTag(pdb, tiName, g_wszData, ARRAYSIZE(g_wszData))) {
Dbg(dlError, "Cannot read the name of the fix\n");
return FALSE;
}
SafeCpyN(szFixName, g_wszData, ARRAYSIZE(szFixName));
CSTRING strTemp = szFixName;
strTemp.XMLToSpecialChar();
pFix = (PPATCH_FIX)FindFix(strTemp, FIX_PATCH);
if (pFix == NULL) {
Dbg(dlError, "Cannot find fix ref for: \"%S\" type %d\n", szFixName, FIX_PATCH);
return FALSE;
}
ppHead = &pEntry->pFirstPatch;
pFixList = new PATCH_FIX_LIST;
if (pFixList == NULL) {
Dbg(dlError, "Cannot allocate %d bytes\n", sizeof(PATCH_FIX_LIST));
return FALSE;
}
pFixList->pPatchFix = pFix;
pFixList->pNext = *ppHead;
*ppHead = pFixList;
return TRUE;
}
BOOL
AddLayerFix(
IN PDB pdb,
IN TAGID tiFix,
IN OUT PDBENTRY pEntry,
IN PDATABASE pDataBase
)
/*++
AddLayerFix
Desc: Adds a layer fix list in an entry
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: TAG_LAYER_REF
IN OUT PDBENTRY pEntry: The pointer to entry that we want the layer to be added
IN PDATABASE pDataBase: The database where this entry lives in.
We need this because we need to pass the database to FindFix in case of layers.
Layers can be present in the custom database as well as system database
and we have to search in the custom database also to make sure that
the layer name in the TAG_LAYER_REF is a valid layer.
Return:
TRUE: Layer was added properly
FALSE: There was some error
--*/
{
TAGID tiName;
TCHAR szFixName[MAX_NAME];
PLAYER_FIX pFix;
PLAYER_FIX_LIST* ppHead;
PLAYER_FIX_LIST pFixList;
if (pEntry == NULL) {
assert(FALSE);
return FALSE;
}
tiName = SdbFindFirstTag(pdb, tiFix, TAG_NAME);
if (!SdbReadStringTag(pdb, tiName, g_wszData, ARRAYSIZE(g_wszData))) {
Dbg(dlError, "Cannot read the name of the fix\n");
return FALSE;
}
SafeCpyN(szFixName, g_wszData, ARRAYSIZE(szFixName));
CSTRING strTemp = szFixName;
strTemp.XMLToSpecialChar();
pFix = (PLAYER_FIX)FindFix(strTemp, FIX_LAYER, pDataBase);
if (pFix == NULL) {
assert(FALSE);
Dbg(dlError, "Cannot find fix ref for: \"%S\" type %d\n", szFixName, FIX_LAYER);
return FALSE;
}
ppHead = &pEntry->pFirstLayer;
pFixList = new LAYER_FIX_LIST;
if (pFixList == NULL) {
Dbg(dlError, "Cannot allocate %d bytes\n", sizeof(LAYER_FIX_LIST));
return FALSE;
}
pFixList->pLayerFix = pFix;
pFixList->pNext = *ppHead;
*ppHead = pFixList;
return TRUE;
}
void
ReadShimFix(
IN PDB pdb,
IN TAGID tiFix,
IN PDATABASE pDataBase
)
/*++
ReadShimFix
Desc: Adds the shim to the database
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: The TAGID for the shim
IN PDATABASE pDataBase: The database in which to add the shim fix
Return:
void
--*/
{
TAGID tiInfo;
TAG tWhich;
BOOL bInExcludeProcessed = FALSE;
PSHIM_FIX pFix = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "ReadShimFix NULL pDataBase passed");
return;
}
pFix = new SHIM_FIX;
if (pFix == NULL) {
MEM_ERR;
return;
}
pFix->pNext = NULL;
tiInfo = SdbGetFirstChild(pdb, tiFix);
while (tiInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiInfo);
switch (tWhich) {
case TAG_NAME:
pFix->strName = ReadDBString(pdb, tiInfo);
break;
case TAG_DESCRIPTION:
pFix->strDescription = ReadDBString(pdb, tiInfo);
break;
case TAG_COMMAND_LINE:
pFix->strCommandLine = ReadDBString(pdb, tiInfo);
break;
case TAG_GENERAL:
pFix->bGeneral = TRUE;
break;
case TAG_INEXCLUDE:
if (bInExcludeProcessed == FALSE) {
ReadIncludeExlude(pdb, tiFix, pFix->strlInExclude);
bInExcludeProcessed = TRUE;
}
break;
}
tiInfo = SdbGetNextChild(pdb, tiFix, tiInfo);
}
//
// Add for the specified database.
//
pFix->pNext = pDataBase->pShimFixes;
pDataBase->pShimFixes = pFix;
if (pFix->bGeneral || g_bExpert) {
++pDataBase->uShimCount;
}
}
void
ReadLayerFix(
IN PDB pdb,
IN TAGID tiFix,
IN PDATABASE pDataBase
)
/*++
ReadLayerFix
Desc: Adds the layer to the database
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: The TAGID for the layer
IN PDATABASE pDataBase: The database in which to add the layer
Return:
void
--*/
{
TAGID tiInfo;
TAG tWhich;
PLAYER_FIX pFix = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "ReadLayerFix NULL pDataBase passed");
return;
}
pFix = new LAYER_FIX(pDataBase != &GlobalDataBase);
if (!pFix) {
MEM_ERR;
return;
}
tiInfo = SdbGetFirstChild(pdb, tiFix);
while (tiInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiInfo);
switch (tWhich) {
case TAG_NAME:
pFix->strName = ReadDBString(pdb, tiInfo);
break;
case TAG_SHIM_REF:
AddShimFix(pdb, tiInfo, NULL, pFix, TRUE);
break;
case TAG_FLAG_REF:
AddFlagFix(pdb, tiInfo, NULL, pFix, TRUE);
break;
}
tiInfo = SdbGetNextChild(pdb, tiFix, tiInfo);
}
//
// Add for the specified database.
//
pFix->pNext = pDataBase->pLayerFixes;
pDataBase->pLayerFixes = pFix;
++pDataBase->uLayerCount;
}
void
ReadPatchFix(
IN PDB pdb,
IN TAGID tiFix,
IN PDATABASE pDataBase
)
/*++
ReadPatchFix
Desc: Adds the patch to the database
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: The TAGID for the patch
IN PDATABASE pDataBase: The database in which to add the apphelp
Return:
void
--*/
{
TAGID tiInfo;
TAG tWhich;
PPATCH_FIX pFix = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "ReadPatchFix NULL pDataBase passed");
return;
}
pFix = new PATCH_FIX;
if (pFix == NULL) {
MEM_ERR;
return;
}
tiInfo = SdbGetFirstChild(pdb, tiFix);
while (tiInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiInfo);
switch (tWhich) {
case TAG_NAME:
pFix->strName = ReadDBString(pdb, tiInfo);
break;
case TAG_DESCRIPTION:
pFix->strDescription = ReadDBString(pdb, tiInfo);
break;
}
tiInfo = SdbGetNextChild(pdb, tiFix, tiInfo);
}
//
// Add for the specified database.
//
pFix->pNext = pDataBase->pPatchFixes;
pDataBase->pPatchFixes = pFix;
}
void
ReadFlagFix(
IN PDB pdb,
IN TAGID tiFix,
IN PDATABASE pDataBase
)
/*++
ReadFlagFix
Desc: Adds the flag to the database
Params:
IN PDB pdb: The database pdb
IN TAGID tiFix: The TAGID for the flag
IN PDATABASE pDataBase: The database in which to add the FlagFix
Return:
void
--*/
{
TAGID tiInfo;
TAG tWhich;
ULONGLONG ullUser = 0;
ULONGLONG ullKernel = 0;
PFLAG_FIX pFix = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "ReadFlagFix NULL pDataBase passed");
return;
}
pFix = new FLAG_FIX;
if (pFix == NULL) {
MEM_ERR;
return;
}
tiInfo = SdbGetFirstChild(pdb, tiFix);
while (tiInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiInfo);
switch (tWhich) {
case TAG_NAME:
pFix->strName = ReadDBString(pdb, tiInfo);
break;
case TAG_DESCRIPTION:
pFix->strDescription = ReadDBString(pdb, tiInfo);
break;
case TAG_COMMAND_LINE:
pFix->strCommandLine = ReadDBString(pdb, tiInfo);
break;
case TAG_GENERAL:
pFix->bGeneral = TRUE;
break;
case TAG_FLAG_MASK_USER:
ullUser = SdbReadQWORDTag(pdb, tiInfo, 0);
break;
case TAG_FLAG_MASK_KERNEL:
ullKernel = SdbReadQWORDTag(pdb, tiInfo, 0);
break;
}
tiInfo = SdbGetNextChild(pdb, tiFix, tiInfo);
}
if (ullKernel == 0) {
pFix->flagType = FLAG_USER;
pFix->ullMask = ullUser;
} else {
pFix->flagType = FLAG_KERNEL;
pFix->ullMask = ullKernel;
}
//
// Add for the specified database.
//
pFix->pNext = pDataBase->pFlagFixes;
pDataBase->pFlagFixes = pFix;
if (pFix->bGeneral || g_bExpert) {
++pDataBase->uShimCount;
}
}
void
ReadFixes(
IN PDB pdb,
IN TAGID tiDatabase,
IN TAGID tiLibrary,
IN PDATABASE pDataBase
)
/*++
ReadFixes
Desc: Reads the apphelps, shims, patch, flag, layers for the main database
Params:
IN PDB pdb: The pdb for the database
IN TAGID tiDatabase: The tagid for the database
IN TAGID tiLibrary: The tagid for the library
IN PDATABASE pDataBase: The database in which to add all the fixes
Return:
void
--*/
{
TAGID tiFix;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "ReadFixes NULL pDataBase passed");
return;
}
tiFix = SdbFindFirstTag(pdb, tiDatabase, TAG_APPHELP);
//
// Read all apphelp messages for this database
//
while (tiFix) {
ReadAppHelp(pdb, tiFix, pDataBase);
tiFix = SdbFindNextTag(pdb, tiDatabase, tiFix);
}
tiFix = SdbFindFirstTag(pdb, tiLibrary, TAG_SHIM);
//
// Read all shims for this database
//
while (tiFix != 0) {
ReadShimFix(pdb, tiFix, pDataBase);
tiFix = SdbFindNextTag(pdb, tiLibrary, tiFix);
}
tiFix = SdbFindFirstTag(pdb, tiLibrary, TAG_PATCH);
//
// Read all patches for this database
//
while (tiFix != 0) {
ReadPatchFix(pdb, tiFix, pDataBase);
tiFix = SdbFindNextTag(pdb, tiLibrary, tiFix);
}
tiFix = SdbFindFirstTag(pdb, tiLibrary, TAG_FLAG);
//
// Read all flags for this database
//
while (tiFix != 0) {
ReadFlagFix(pdb, tiFix, pDataBase);
tiFix = SdbFindNextTag(pdb, tiLibrary, tiFix);
}
//
// Note: The LAYERs are under the DATABASE tag instead of LIBRARY
//
tiFix = SdbFindFirstTag(pdb, tiDatabase, TAG_LAYER);
//
// Read all layers for this database
//
while (tiFix != 0) {
ReadLayerFix(pdb, tiFix, pDataBase);
tiFix = SdbFindNextTag(pdb, tiDatabase, tiFix);
}
}
BOOL
AddMatchingFile(
IN PDB pdb,
IN TAGID tiMatch,
IN PDBENTRY pEntry
)
/*++
AddMatchingFile
Desc: Reads the matching file entry from the database and adds it to the entry
Params:
IN PDB pdb: The database pdb
IN TAGID tiMatch: The tag id for the matching file
IN PDBENTRY pEntry: The entry in which we want to add the matching file
Return:
FALSE: There was some error
TRUE: Successful
--*/
{
TAGID tiMatchInfo;
TAG tWhich;
PMATCHINGFILE pMatch;
DWORD dwValue;
DWORD dwPos; //Position of the tag in the g_rgAttributeTags array.
LARGE_INTEGER ullValue;
if (pEntry == NULL) {
assert(FALSE);
return FALSE;
}
pMatch = (PMATCHINGFILE) new MATCHINGFILE;
if (pMatch == NULL) {
MEM_ERR;
return FALSE;
}
pMatch->dwMask = 0;
PATTRINFO_NEW pAttr = pMatch->attributeList.pAttribute;
tiMatchInfo = SdbGetFirstChild(pdb, tiMatch);
while (tiMatchInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiMatchInfo);
dwPos = TagToIndex(tWhich);
UINT tagType = GETTAGTYPE(tWhich);
switch (tagType) {
case TAG_TYPE_DWORD:
dwValue = SdbReadDWORDTag(pdb, tiMatchInfo, -1);
if (dwValue != -1 && dwPos != -1) {
pMatch->dwMask |= (1 << (dwPos + 1));
pAttr[dwPos].tAttrID = tWhich;
pAttr[dwPos].dwFlags |= ATTRIBUTE_AVAILABLE;
pAttr[dwPos].dwAttr = dwValue;
}
break;
case TAG_TYPE_QWORD:
ullValue.QuadPart = SdbReadQWORDTag(pdb, tiMatchInfo, 0);
if ((ullValue.HighPart != 0 || ullValue.LowPart != 0) && dwPos != -1) {
pMatch->dwMask |= (1 << (dwPos + 1));
pAttr[dwPos].tAttrID = tWhich;
pAttr[dwPos].dwFlags |= ATTRIBUTE_AVAILABLE;
pAttr[dwPos].ullAttr = ullValue.QuadPart;
}
break;
case TAG_TYPE_STRINGREF:
{
CSTRING str = ReadDBString(pdb, tiMatchInfo);
//
// NOTE: The TAG_NAME is not present in the g_rgAttributeTags array !!!
//
if (str.Length() > 0 && (tWhich == TAG_NAME || dwPos != -1)) {
if (tWhich == TAG_NAME) {
pMatch->strMatchName = str;
} else {
pMatch->dwMask |= (1 << (dwPos + 1));
pAttr[dwPos].tAttrID = tWhich;
pAttr[dwPos].dwFlags |= ATTRIBUTE_AVAILABLE;
pAttr[dwPos].strValue = str;
pAttr[dwPos].lpAttr = pAttr[dwPos].strValue.pszString;
}
}
}
break;
}
tiMatchInfo = SdbGetNextChild(pdb, tiMatch, tiMatchInfo);
}
pMatch->pNext = pEntry->pFirstMatchingFile;
pEntry->pFirstMatchingFile = pMatch;
(pEntry->nMatchingFiles)++;
return TRUE;
}
PAPPHELP
FindAppHelp(
IN DWORD HTMLHELPID,
IN PDATABASE pDataBase
)
/*++
FindAppHelp
Desc: Finds the apphelp with id HTMLHELPID in the database pDataBaseIn
Params:
IN DWORD HTMLHELPID: The htmlhelp id to look for
IN PDATABASE pDataBase: The database to look in.
Return: If found the corresponding PAPPHELP or NULL if not found
--*/
{
PAPPHELP pAppHelp = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "FindAppHelp NULL pDataBase passed");
return NULL;
}
pAppHelp = pDataBase->pAppHelp;
while (pAppHelp) {
if (pAppHelp->HTMLHELPID == HTMLHELPID) {
return pAppHelp;
} else {
pAppHelp = pAppHelp->pNext;
}
}
return NULL;
}
PDBENTRY
AddExeInApp(
IN PDBENTRY pEntry,
OUT BOOL* pbNew,
IN PDATABASE pDataBase
)
/*++
AddExeInApp
Desc: Adds the entry pEntry in the database pDataBaseIn
Params:
IN PDBENTRY pEntry: The entry to add
OUT BOOL* pbNew: Will be true if this is a new app
IN PDATABASE pDataBase: The database to add into
Return: Returns the PDBENTRY for the parent App.
--*/
{
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "AddExeInApp NULL pDataBase passed");
return NULL;
}
//
// Now add this entry in its correct position for the app.
//
for (PDBENTRY pApps = pDataBase->pEntries, pAppsPrev = NULL;
pApps;
pAppsPrev = pApps, pApps = pApps->pNext) {
if (pApps->strAppName == pEntry->strAppName) {
//
// We insert the new entry at the head of the app
//
if (pAppsPrev == NULL) {
pDataBase->pEntries = pEntry;
} else {
pAppsPrev->pNext = pEntry;
}
pEntry->pNext = pApps->pNext;
pApps->pNext = NULL;
pEntry->pSameAppExe = pApps;
if (pbNew != NULL) {
*pbNew = FALSE;
}
return pApps;
}
}
//
// This an entry for a new app.
//
pEntry->pNext = pDataBase->pEntries;
pDataBase->pEntries = pEntry;
++pDataBase->uAppCount;
if (pbNew != NULL) {
*pbNew = TRUE;
}
return pEntry;
}
PDBENTRY
AddEntry(
IN PDB pdb,
IN TAGID tiExe,
IN PDATABASE pDataBase
)
/*++
AddEntry
Desc: Reads a new entry from the database
Params:
IN PDB pdb: The database pdb
IN TAGID tiExe: The tagid of the exe
IN PDATABASE pDataBase: The database in which to perform this operation
Return: Pointer to the entry read. PDBENTRY
--*/
{
TAGID tiExeInfo;
TAGID tiSeverity, tiHelpId;
TAG tWhich;
PDBENTRY pEntry = NULL;
if (pDataBase == NULL) {
assert(FALSE);
Dbg(dlError, "AddEntry NULL pDataBase passed");
return NULL;
}
tiExeInfo = SdbGetFirstChild(pdb, tiExe);
pEntry = new DBENTRY;
if (pEntry == NULL) {
Dbg(dlError, "Cannot allocate %d bytes\n", sizeof(DBENTRY));
MEM_ERR;
return NULL;
}
pEntry->tiExe = tiExe;
while (tiExeInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiExeInfo);
switch (tWhich) {
case TAG_NAME:
pEntry->strExeName = ReadDBString(pdb, tiExeInfo);
break;
case TAG_APP_NAME:
pEntry->strAppName = ReadDBString(pdb, tiExeInfo);
break;
case TAG_VENDOR:
pEntry->strVendor = ReadDBString(pdb, tiExeInfo);
break;
case TAG_MATCHING_FILE:
AddMatchingFile(pdb, tiExeInfo, pEntry);
break;
case TAG_APPHELP:
pEntry->appHelp.bPresent = TRUE;
tiSeverity = SdbFindFirstTag(pdb, tiExeInfo, TAG_PROBLEMSEVERITY);
pEntry->appHelp.severity = (SEVERITY)SdbReadDWORDTag(pdb, tiSeverity, 0);
if (pEntry->appHelp.severity == APPTYPE_INC_HARDBLOCK) {
pEntry->appHelp.bBlock = TRUE;
} else {
pEntry->appHelp.bBlock = FALSE;
}
tiHelpId = SdbFindFirstTag(pdb, tiExeInfo, TAG_HTMLHELPID);
pEntry->appHelp.HTMLHELPID = SdbReadDWORDTag(pdb, tiHelpId, 0);
if (pDataBase == &GlobalDataBase) {
//
// We do not wish to keep the apphelp data for main database in memory
// Too big.. So we will load it from apphelp.sdb whenever we will need it
// But still we will have to do the following so that the type of the lParam of
// the tree-item in the entry tree is TYPE_APPHELP, so that when we select that
// we know that it is for apphelp
//
pEntry->appHelp.pAppHelpinLib = (PAPPHELP)TYPE_APPHELP_ENTRY;
} else {
pEntry->appHelp.pAppHelpinLib = FindAppHelp(pEntry->appHelp.HTMLHELPID, pDataBase);
}
break;
case TAG_SHIM_REF:
AddShimFix(pdb, tiExeInfo, pEntry, NULL, FALSE);
break;
case TAG_FLAG_REF:
AddFlagFix(pdb, tiExeInfo, pEntry, NULL, FALSE);
break;
case TAG_PATCH_REF:
AddPatchFix(pdb, tiExeInfo, pEntry);
break;
case TAG_LAYER:
AddLayerFix(pdb, tiExeInfo, pEntry, pDataBase);
break;
case TAG_EXE_ID:
{
GUID* pGuid = NULL;
pGuid = (GUID*)SdbGetBinaryTagData(pdb, tiExeInfo);
if (pGuid != NULL) {
StringCchPrintf(pEntry->szGUID,
ARRAYSIZE(pEntry->szGUID),
TEXT ("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0],
pGuid->Data4[1],
pGuid->Data4[2],
pGuid->Data4[3],
pGuid->Data4[4],
pGuid->Data4[5],
pGuid->Data4[6],
pGuid->Data4[7]);
}
break;
}
default:
break;
}
tiExeInfo = SdbGetNextChild(pdb, tiExe, tiExeInfo);
}
pEntry->bDisablePerMachine = CheckRegistry(HKEY_LOCAL_MACHINE, pEntry->szGUID);
pEntry->bDisablePerUser = CheckRegistry(HKEY_CURRENT_USER, pEntry->szGUID);
//
// Search the application where this entry should go and add it
//
AddExeInApp(pEntry, (BOOL*)NULL, pDataBase);
return pEntry;
}
BOOL
LookUpEntryProperties(
IN PDB pdb,
IN TAGID tiExe,
OUT BOOL* pbLayers,
OUT BOOL* pbShims,
OUT BOOL* pbPatches,
OUT BOOL* pbFlags,
OUT BOOL* pbAppHelp,
OUT CSTRING& strAppName
)
/*++
LookUpEntryProperties
Desc: Checks if the entry has shims, layers, flags, patches, or apphelp. NULL values
for the various BOOL* is allowed
Params:
IN PDB pdb: The database pdb
IN TAGID tiExe: The TAGID of the entry whose properties we want to check
OUT BOOL* pbLayers: Does the entry have layers?
OUT BOOL* pbShims: Does the entry have shims?
OUT BOOL* pbPatches: Does the entry have patches?
OUT BOOL* pbFlags: Does the entry have flags?
OUT BOOL* pbAppHelp: Does the entry have apphelp?
OUT CSTRING& strAppName: The name of the application of this entry
Return: TRUE: The routine was able to obtain the info for the entry,
FALSE: otherwise
--*/
{
TAGID tiExeInfo;
TAG tWhich;
BOOL bOk = TRUE;
tiExeInfo = SdbGetFirstChild(pdb, tiExe);
while (tiExeInfo != 0) {
tWhich = SdbGetTagFromTagID(pdb, tiExeInfo);
switch (tWhich) {
case TAG_APP_NAME:
strAppName = ReadDBString(pdb, tiExeInfo);
break;
case TAG_APPHELP:
if (pbAppHelp) {
*pbAppHelp = TRUE;
}
break;
case TAG_SHIM_REF:
if (pbShims) {
*pbShims = TRUE;
}
break;
case TAG_FLAG_REF:
if (pbFlags) {
*pbFlags = TRUE;
}
break;
case TAG_PATCH_REF:
if (pbPatches) {
*pbPatches = TRUE;
}
break;
case TAG_LAYER:
if (pbLayers) {
*pbLayers = TRUE;
}
break;
}
tiExeInfo = SdbGetNextChild(pdb, tiExe, tiExeInfo);
}
return bOk;
}
void
DeleteShimFixList(
IN PSHIM_FIX_LIST psl
)
/*++
DeleteShimFixList
Desc: Deletes this PSHIM_FIX_LIST and all PSHIM_FIX_LIST in this chain
Params:
IN PSHIM_FIX_LIST psl: The PSHIM_FIX_LIST to delete.
Note: Caller must NULLify this argument
Return:
void
--*/
{
PSHIM_FIX_LIST pslNext;
while (psl) {
pslNext = psl->pNext;
if (psl->pLuaData) {
delete psl->pLuaData;
psl->pLuaData = NULL;
}
delete psl;
psl = pslNext;
}
}
void
DeletePatchFixList(
IN PPATCH_FIX_LIST pPat
)
/*++
DeletePatchFixList
Desc: Deletes this PPATCH_FIX_LIST and all PPATCH_FIX_LIST in this chain
Params:
IN PPATCH_FIX_LIST pPat: The PPATCH_FIX_LIST to delete.
Note: Caller must NULLify this argument
Return:
void
--*/
{
PPATCH_FIX_LIST pPatNext;
while (pPat) {
pPatNext = pPat->pNext;
delete (pPat);
pPat = pPatNext;
}
}
void
DeleteLayerFixList(
IN PLAYER_FIX_LIST pll
)
/*++
DeleteLayerFixList
Desc: Deletes this PLAYER_FIX_LIST and all PLAYER_FIX_LIST in this chain
Note: Caller must NULLify this argument
Params:
IN PLAYER_FIX_LIST pll: The PLAYER_FIX_LIST to delete.
Return:
void
--*/
{
PLAYER_FIX_LIST pllNext;
while (pll) {
pllNext = pll->pNext;
delete (pll);
pll = pllNext;
}
}
void
DeleteFlagFixList(
IN PFLAG_FIX_LIST pfl
)
/*++
DeleteFlagFixList
Desc: Deletes this PFLAG_FIX_LIST and all PFLAG_FIX_LIST in this chain
Note: Caller must NULLify this argument
Params:
IN PFLAG_FIX_LIST pfl: The PFLAG_FIX_LIST to delete.
Return:
void
--*/
{
PFLAG_FIX_LIST pflNext;
while (pfl) {
pflNext = pfl->pNext;
delete (pfl);
pfl = pflNext;
}
}
void
DeleteMatchingFiles(
IN PMATCHINGFILE pMatch
)
/*++
DeleteMatchingFiles
Desc: Deletes this PMATCHINGFILE and all PMATCHINGFILE in this chain
Note: Caller must NULLify this argument
Params:
IN PMATCHINGFILE pMatch: The PMATCHINGFILE to delete.
Return:
void
--*/
{
PMATCHINGFILE pMatchNext;
while (pMatch) {
pMatchNext = pMatch->pNext;
delete (pMatch);
pMatch = pMatchNext;
}
}
BOOL
WriteXML(
IN CSTRING& szFilename,
IN CSTRINGLIST* pString
)
/*++
WriteXML
Desc: Writes the XML contained in pString to file szFilename. CSTRINGLIST is a linked
list of CSTRING, and a node contains one line of XML to be written to the file
Params:
IN CSTRING& szFilename: The name of the file
IN CSTRINGLIST* pString: Linked list of CSTRING containing the XML.
Each node contains one line of XML to be written to the file
Return:
TRUE: Success
FALSE: There was some error
--*/
{
BOOL bOk = TRUE;
HANDLE hFile = NULL;
PSTRLIST pTemp = NULL;
TCHAR chUnicodeID = 0xFEFF; // Ensure that the file is saved as unicode
TCHAR szCR[] = {TEXT('\r'), TEXT('\n')};
DWORD dwBytesWritten;
CSTRING szTemp;
if (NULL == pString) {
bOk = FALSE;
goto End;
}
pTemp = pString->m_pHead;
hFile = CreateFile((LPCTSTR)szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
bOk = FALSE;
goto End;
}
if (!WriteFile(hFile, &chUnicodeID, sizeof(chUnicodeID) , &dwBytesWritten, NULL)) {
assert(FALSE);
bOk = FALSE;
goto End;
}
while (NULL != pTemp) {
if (!WriteFile(hFile,
pTemp->szStr.pszString,
pTemp->szStr.Length() * sizeof(TCHAR) ,
&dwBytesWritten,
NULL)) {
bOk = FALSE;
goto End;
}
if (!WriteFile(hFile, szCR, sizeof(szCR) , &dwBytesWritten, NULL)) {
bOk = FALSE;
goto End;
}
pTemp = pTemp->pNext;
}
End:
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
return bOk;
}
void
CleanupDbSupport(
IN PDATABASE pDataBase
)
/*++
CleanupDbSupport
Desc: Deletes the data structures associated with a PDATABASE. This should be called
when we are going to close a database or we are going to delete a database.
We should call this function before we do a delete PDATABASE
Params:
IN PDATABASE pDataBase: The pointer to the database
Return:
void
--*/
{
if (pDataBase == NULL) {
assert(FALSE);
return;
}
//
// Free the Library section for the local database
//
//
// Free the shims
//
PSHIM_FIX pShimFixNext;
while (pDataBase->pShimFixes) {
pShimFixNext = pDataBase->pShimFixes->pNext;
delete (pDataBase->pShimFixes);
pDataBase->pShimFixes = pShimFixNext;
}
//
// Free the patches
//
PPATCH_FIX pPatchFixNext;
while (pDataBase->pPatchFixes) {
pPatchFixNext = pDataBase->pPatchFixes->pNext;
delete (pDataBase->pPatchFixes);
pDataBase->pPatchFixes = pPatchFixNext;
}
//
// Free the flags
//
PFLAG_FIX pFlagFixNext;
while (pDataBase->pFlagFixes) {
pFlagFixNext = pDataBase->pFlagFixes->pNext;
delete(pDataBase->pFlagFixes);
pDataBase->pFlagFixes = pFlagFixNext;
}
//
// Free the layers.
//
PLAYER_FIX pLayerFixNext;
while (pDataBase->pLayerFixes) {
pLayerFixNext = pDataBase->pLayerFixes->pNext;
//
// Delete the shim list for this layer
//
DeleteShimFixList(pDataBase->pLayerFixes->pShimFixList);
//
// Delete the flags for this layer
//
DeleteFlagFixList(pDataBase->pLayerFixes->pFlagFixList);
delete (pDataBase->pLayerFixes);
pDataBase->pLayerFixes = pLayerFixNext;
}
//
// Free the AppHelp
//
PAPPHELP pAppHelpNext;
while (pDataBase->pAppHelp) {
pAppHelpNext = pDataBase->pAppHelp->pNext;
delete pDataBase->pAppHelp;
pDataBase->pAppHelp = pAppHelpNext;
}
//
// Free the exes of the local database.
//
PDBENTRY pEntryNext = NULL;
PDBENTRY pApp = pDataBase->pEntries, pEntry = pDataBase->pEntries;
while (pApp) {
pEntry = pApp;
pApp = pApp->pNext;
while (pEntry) {
pEntryNext = pEntry->pSameAppExe;
delete pEntry;
pEntry = pEntryNext;
}
}
pDataBase->pEntries = NULL;
}
BOOL
GetDatabaseEntries(
IN PCTSTR szFullPath,
IN PDATABASE pDataBase
)
/*++
GetDatabaseEntries
Desc: Reads in database contents.
If this is the system database, then we only read in the
fix entries as the library section has been already read when we started up.
For other databases reads in both the library section and the entries
Params:
IN PCTSTR szFullPath: Full path of the database. If NULL we load the system database
IN PDATABASE pDataBase: Pointer to the database that we are going to populate
Return:
TRUE: Success
FALSE: Failure
--*/
{
CSTRING strMessage;
TAGID tiDatabase, tiLibrary, tiExe;
BOOL bOk = TRUE;
WCHAR wszShimDB[MAX_PATH * 2] = L"";
PDB pdb = NULL;
UINT uResult = 0;
if (pDataBase == NULL) {
assert(FALSE);
return FALSE;
}
SetCursor(LoadCursor(NULL, IDC_WAIT));
if (pDataBase == &GlobalDataBase) {
uResult = GetSystemWindowsDirectoryW(wszShimDB, MAX_PATH);
if (uResult == 0 || uResult >= MAX_PATH) {
bOk = FALSE;
goto Cleanup;
}
ADD_PATH_SEPARATOR(wszShimDB, ARRAYSIZE(wszShimDB));
StringCchCat(wszShimDB, ARRAYSIZE(wszShimDB), TEXT("AppPatch\\sysmain.sdb"));
} else {
if (StringCchPrintf(wszShimDB, ARRAYSIZE(wszShimDB), TEXT("%s"), szFullPath) != S_OK) {
bOk = FALSE;
goto Cleanup_Msg;
}
pDataBase->strPath = wszShimDB;
}
//
// Open the database.
//
pdb = SdbOpenDatabase(wszShimDB, DOS_PATH);
if (pdb == NULL) {
Dbg(dlError, "Cannot open shim DB \"%ws\"\n", wszShimDB);
bOk = FALSE;
goto Cleanup_Msg;
}
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
if (tiDatabase == 0) {
Dbg(dlError, "Cannot find TAG_DATABASE\n");
bOk = FALSE;
goto Cleanup_Msg;
}
TAGID tiGuid = SdbFindFirstTag(pdb, tiDatabase, TAG_DATABASE_ID);
TAGID tName = NULL;
//
// Get the guid for the database
//
if (0 != tiGuid) {
GUID* pGuid;
pGuid = (GUID*)SdbGetBinaryTagData(pdb, tiGuid);
TCHAR szGuid[128];
*szGuid = 0;
if (pGuid != NULL) {
StringCchPrintf(szGuid,
ARRAYSIZE(szGuid),
TEXT ("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0],
pGuid->Data4[1],
pGuid->Data4[2],
pGuid->Data4[3],
pGuid->Data4[4],
pGuid->Data4[5],
pGuid->Data4[6],
pGuid->Data4[7]);
if (pDataBase != &GlobalDataBase &&
(!lstrcmpi(szGuid, GlobalDataBase.szGUID)
|| !lstrcmpi(szGuid, GUID_APPHELP_SDB)
|| !lstrcmpi(szGuid, GUID_SYSTEST_SDB)
|| !lstrcmpi(szGuid, GUID_MSI_SDB)
|| !lstrcmpi(szGuid, GUID_DRVMAIN_SDB))) {
MessageBox(g_hDlg,
CSTRING(IDS_ERROR_SYSDB),
g_szAppName,
MB_ICONERROR);
bOk = FALSE;
goto Cleanup;
}
SafeCpyN(pDataBase->szGUID, szGuid, ARRAYSIZE(pDataBase->szGUID));
//
// Get the name of the database
//
tName = SdbFindFirstTag(pdb, tiDatabase, TAG_NAME);
if (0 != tName) {
pDataBase->strName = ReadDBString(pdb, tName);
}
} else {
bOk = FALSE;
goto Cleanup_Msg;
}
} else {
bOk = FALSE;
goto Cleanup_Msg;
}
if ((pDataBase->type == DATABASE_TYPE_WORKING) && CheckInstalled(pDataBase->strPath,
pDataBase->szGUID)) {
MessageBox(g_hDlg,
GetString(IDS_TRYOPENINSTALLED),
g_szAppName,
MB_ICONWARNING);
bOk = FALSE;
goto Cleanup;
}
tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
if (tiLibrary == 0) {
Dbg(dlError, "Cannot find TAG_LIBRARY\n");
bOk = FALSE;
goto Cleanup_Msg;
}
if (pDataBase != &GlobalDataBase) {
//
// Fixes for the main database have been read when the program started.
//
ReadFixes(pdb, tiDatabase, tiLibrary, pDataBase);
}
//
// Loop through the EXEs.
//
tiExe = SdbFindFirstTag(pdb, tiDatabase, TAG_EXE);
while (tiExe != TAGID_NULL) {
AddEntry(pdb, tiExe, pDataBase);
tiExe = SdbFindNextTag(pdb, tiDatabase, tiExe);
}
//
// Add the pDataBase to the DATABASELIST
//
if (pDataBase->type == DATABASE_TYPE_WORKING) {
DataBaseList.Add(pDataBase);
}
goto Cleanup;
Cleanup_Msg:
strMessage.Sprintf(GetString(IDS_ERROROPEN), wszShimDB);
MessageBox(g_hDlg,
strMessage,
g_szAppName,
MB_ICONERROR);
Cleanup:
if (pdb != NULL) {
SdbCloseDatabase(pdb);
}
if (bOk == FALSE) {
CleanupDbSupport(pDataBase);
}
SetCursor(LoadCursor(NULL, IDC_ARROW));
return bOk;
}
BOOL
ReadMainDataBase(
void
)
/*++
ReadMainDataBase
Desc: Read the library section of the main database
Return:
TRUE: The library section of the main database was read successfully
FALSE: Otherwise
--*/
{
PDB pdb;
TAGID tiDatabase, tiLibrary;
BOOL bOk = TRUE;
TCHAR szShimDB[MAX_PATH * 2] = TEXT("");
TAGID tName, tiGuid;
UINT uResult = 0;
tiDatabase = tiLibrary = tName = tiGuid = NULL;
uResult = GetSystemWindowsDirectory(szShimDB, MAX_PATH);
if (uResult == 0 || uResult >= MAX_PATH) {
assert(FALSE);
return FALSE;
}
ADD_PATH_SEPARATOR(szShimDB, ARRAYSIZE(szShimDB));
StringCchCat(szShimDB, ARRAYSIZE(szShimDB), TEXT("apppatch\\sysmain.sdb"));
//
// Open the database.
//
pdb = SdbOpenDatabase(szShimDB, DOS_PATH);
if (pdb == NULL) {
Dbg(dlError, "Cannot open shim DB \"%ws\"\n", szShimDB);
bOk = FALSE;
goto Cleanup;
}
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
if (tiDatabase == 0) {
Dbg(dlError, "Cannot find TAG_DATABASE\n");
bOk = FALSE;
goto Cleanup;
}
tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
if (tiLibrary == 0) {
Dbg(dlError, "Cannot find TAG_LIBRARY\n");
bOk = FALSE;
goto Cleanup;
}
//
// Read in the guid and the name of the system database.
//
tiGuid = SdbFindFirstTag(pdb, tiDatabase, TAG_DATABASE_ID);
if (0 != tiGuid) {
GUID* pGuid;
TCHAR szGuid[128];
pGuid = (GUID*)SdbGetBinaryTagData(pdb, tiGuid);
if (pGuid != NULL) {
*szGuid = 0;
StringCchPrintf(szGuid,
ARRAYSIZE(szGuid),
TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0],
pGuid->Data4[1],
pGuid->Data4[2],
pGuid->Data4[3],
pGuid->Data4[4],
pGuid->Data4[5],
pGuid->Data4[6],
pGuid->Data4[7]);
SafeCpyN(GlobalDataBase.szGUID, szGuid, ARRAYSIZE(GlobalDataBase.szGUID));
tName = SdbFindFirstTag(pdb, tiDatabase, TAG_NAME);
if (0 != tName) {
GlobalDataBase.strName = ReadDBString(pdb, tName);
}
} else {
assert(FALSE);
bOk = FALSE;
goto Cleanup;
}
} else {
assert(FALSE);
bOk = FALSE;
goto Cleanup;
}
ReadFixes(pdb, tiDatabase, tiLibrary, &GlobalDataBase);
Cleanup:
if (pdb != NULL) {
SdbCloseDatabase(pdb);
}
return bOk;
}
BOOL
AttributesToXML(
IN OUT CSTRING& strStr,
IN PMATCHINGFILE pMatch
)
/*++
AttributesToXML
Desc: Appends the XML for the attributes of pMatch to strStr
Params:
IN OUT CSTRING& strStr: Appends the XML for the attributes of pMatch to this
IN PMATCHINGFILE pMatch: The PMATCHINGFILE, whose attributes have to converted
to XML
Return:
TRUE: Success
FALSE: Otherwise
--*/
{
TCHAR szText[1024];
CSTRING strTemp;
PATTRINFO_NEW pAttr = NULL;
*szText = 0;
if (pMatch == NULL) {
Dbg(dlError, "pMatch == NULL in AttributesToXML function");
return FALSE;
}
pAttr = pMatch->attributeList.pAttribute;
if (pAttr == NULL) {
assert(FALSE);
return FALSE;
}
//
// For all the attributes see if it available (ATTRIBUTE_AVAILABLE)
// and if the user has selected this attribute (use the mask), if yes then
// we get the formatted string for this attribute value that we can write to XML
//
for (DWORD dwIndex = 0; dwIndex < ATTRIBUTE_COUNT; ++dwIndex) {
DWORD dwPos = TagToIndex(pAttr[dwIndex].tAttrID);
if ((pAttr[dwIndex].dwFlags & ATTRIBUTE_AVAILABLE)
&& dwPos != -1
&& (pMatch->dwMask & (1 << (dwPos + 1)))) {
*szText = 0;
SdbFormatAttribute(&pAttr[dwIndex], szText, ARRAYSIZE(szText));
strStr.Strcat(TEXT(" "));
strStr.Strcat(szText);
}
}
return TRUE;
}
BOOL
CreateXMLForLUAAction(
IN PLUADATA pLuaData,
IN OUT CSTRINGLIST* strlXML
)
/*++
CreateXMLForLUAAction
Desc: Appends the action string for PLUADATA to strlXML
Params:
IN PLUADATA pLuaData
IN OUT CSTRINGLIST* strlXML
Return:
FALSE: If there is some error
TRUE: Otherwise
Notes: Currently only one type of ACTION is supported for the LUA shims.
--*/
{
TCHAR szSpace[64];
INT iszSpaceSize = 0;
iszSpaceSize = ARRAYSIZE(szSpace);
CSTRING strTemp;
strTemp.Sprintf(TEXT("%s<ACTION NAME = \"REDIRECT\" TYPE=\"ChangeACLs\">"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize));
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
if (pLuaData == NULL) {
strTemp.Sprintf(
TEXT("%s<DATA NAME = \"AllUserDir\" VALUETYPE=\"STRING\" VALUE=\"%%ALLUSERSPROFILE%%\\Application Data\\Redirected\"/>"),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize));
} else {
strTemp.Sprintf(
TEXT("%s<DATA NAME = \"AllUserDir\" VALUETYPE=\"STRING\" VALUE=\"%s\"/>"),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
pLuaData->strAllUserDir.SpecialCharToXML().pszString);
}
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
strTemp.Sprintf(TEXT("%s</ACTION>"), GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize));
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
return TRUE;
}
BOOL
CreateXMLForShimFixList(
IN PSHIM_FIX_LIST pShimFixList,
IN OUT CSTRINGLIST* strlXML
)
/*++
CreateXMLForShimFixList
Desc: Creates XML for a pShimFixList chain
Params:
IN PSHIM_FIX_LIST pShimFixList: The head of the shim fix list
IN OUT CSTRINGLIST* strlXML: We should append the XML to this
Return:
TRUE: If success
FALSE: If error
--*/
{
CSTRING strTemp;
TCHAR szSpace[64];
INT iszSpaceSize = 0;
iszSpaceSize = ARRAYSIZE(szSpace);
while (pShimFixList) {
if (pShimFixList->pShimFix == NULL) {
assert(FALSE);
goto Next_ShimList;
}
//
// Check if we have a specific commandline for this shim. For shims with lua data handled differently
//
if (pShimFixList->pLuaData) {
strTemp.Sprintf(TEXT("%s<SHIM NAME=\"%s\" COMMAND_LINE=\"%%DbInfo%%\">"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pShimFixList->pShimFix->strName.SpecialCharToXML().pszString);
} else if (pShimFixList->strCommandLine.Length()) {
strTemp.Sprintf(TEXT("%s<SHIM NAME=\"%s\" COMMAND_LINE= \"%s\">"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pShimFixList->pShimFix->strName.SpecialCharToXML().pszString,
pShimFixList->strCommandLine.SpecialCharToXML().pszString);
} else {
strTemp.Sprintf(TEXT("%s<SHIM NAME=\"%s\">"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pShimFixList->pShimFix->strName.SpecialCharToXML().pszString);
}
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
//
// Look for INCLUSIONS & EXCLUSIONS
//
if (!pShimFixList->strlInExclude.IsEmpty()) {
PSTRLIST pList = pShimFixList->strlInExclude.m_pHead;
while (pList) {
if (pList->data == INCLUDE) {
if (pList->szStr == GetString(IDS_INCLUDEMODULE)) {
strTemp.Sprintf(TEXT("%s<INCLUDE MODULE = \"%s\" />"),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
TEXT("$"));
} else {
strTemp.Sprintf(TEXT("%s<INCLUDE MODULE = \"%s\" />"),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
pList->szStr.SpecialCharToXML().pszString);
}
} else {
strTemp.Sprintf(TEXT("%s<EXCLUDE MODULE = \"%s\" />"),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
pList->szStr.SpecialCharToXML().pszString);
}
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
pList = pList->pNext;
}
}
//
// Get the LUA data.
//
if (pShimFixList->pLuaData) {
LuaGenerateXML(pShimFixList->pLuaData, *strlXML);
}
strTemp.Sprintf(TEXT("%s</SHIM>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pShimFixList->pShimFix->strName.SpecialCharToXML().pszString);
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
if (pShimFixList->pShimFix->strName == TEXT("LUARedirectFS")) {
if (pShimFixList->pLuaData){
//
// If this entry has been customized we need to check if we should create
// an ACTION node for it.
//
if (!(pShimFixList->pLuaData->strAllUserDir.isNULL())) {
CreateXMLForLUAAction(pShimFixList->pLuaData, strlXML);
}
} else {
//
// If we don't have any LUA data it means this hasn't been customized.
// We always create the default Redirected dir.
//
CreateXMLForLUAAction(NULL, strlXML);
}
}
Next_ShimList:
pShimFixList = pShimFixList->pNext;
}
return TRUE;
}
BOOL
GetXML(
IN PDBENTRY pEntry,
IN BOOL bComplete,
OUT CSTRINGLIST* strlXML,
IN PDATABASE pDataBase
)
/*++
GetXML
Desc: Gets the XML for a fix entry
Params:
IN PDBENTRY pEntry: The app or entry whose XML we want
IN BOOL bComplete: Save all entries for this app.
pEntry is the head of the list, i.e an app. Otherwise just get the XML for this
entry
OUT CSTRINGLIST* strlXML: The XML has to be written into this
IN PDATABASE pDataBase: The database for which we want to perform the operation
Return:
TRUE: Success
FALSE: Otherwise
Notes: Also gets the XML for the entire library section. Will create a guid for the database
If there is none and we are trying to do a save.
During test run we do not care and allow the compiler to create a guid, but for
save since the guid member of the PDATABASE has to be updated if there is no guid,
we create it ourselves
--*/
{
PSHIM_FIX_LIST pShimFixList;
CSTRING strTemp;
TCHAR szSpace[64];
INT iszSpaceSize = 0;
iszSpaceSize = ARRAYSIZE(szSpace);
if (pDataBase == NULL) {
assert(FALSE);
return FALSE;
}
if (!strlXML->AddString(TEXT("<?xml version=\"1.0\" encoding=\"UTF-16\"?>"))) {
return FALSE;
}
if (bComplete == FALSE) {
//
// This is a test-run, guid should be generated automatically
//
strTemp.Sprintf(TEXT("<DATABASE NAME=\"%s\">"),
pDataBase->strName.SpecialCharToXML().pszString);
} else {
//
// We are trying to save the database, create a guid if it is not there
//
if (*(pDataBase->szGUID) == 0) {
GUID Guid;
CoCreateGuid(&Guid);
StringCchPrintf(pDataBase->szGUID,
ARRAYSIZE(pDataBase->szGUID),
TEXT ("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
Guid.Data1,
Guid.Data2,
Guid.Data3,
Guid.Data4[0],
Guid.Data4[1],
Guid.Data4[2],
Guid.Data4[3],
Guid.Data4[4],
Guid.Data4[5],
Guid.Data4[6],
Guid.Data4[7]);
}
strTemp.Sprintf(TEXT("<DATABASE NAME=\"%s\" ID = \"%s\">"),
pDataBase->strName.SpecialCharToXML().pszString,
pDataBase->szGUID);
}
strlXML->AddString(strTemp);
strTemp.Sprintf(TEXT("%s<LIBRARY>"),
GetSpace(szSpace, TAB_SIZE * 1, iszSpaceSize));
strlXML->AddString(strTemp);
//
// Put the AppHelp messages.
//
PAPPHELP pAppHelp = pDataBase->pAppHelp;
while (pAppHelp) {
CSTRING strName;
strName.Sprintf(TEXT("%u"), pAppHelp->HTMLHELPID);
strTemp.Sprintf(TEXT("%s<MESSAGE NAME = \"%s\" >"),
GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize),
strName.SpecialCharToXML().pszString);
strlXML->AddString(strTemp);
strTemp.Sprintf(TEXT("%s<SUMMARY>"), GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize));
strlXML->AddString(strTemp);
//
// We must use SpecialCharToXML() and pass TRUE for the apphelp message as html
// tags are allowed. When we pass TRUE to SpecialCharToXML(), it understands that this is a AppHelp
// message and ignores the <, > but handles &, " correctly
//
strTemp.Sprintf(TEXT("%s%s"),
GetSpace(szSpace, TAB_SIZE * 4, iszSpaceSize),
pAppHelp->strMessage.SpecialCharToXML(TRUE).pszString);
strlXML->AddString(strTemp);
strTemp.Sprintf(TEXT("%s</SUMMARY>"), GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize));
strlXML->AddString(strTemp);
strTemp.Sprintf(TEXT("%s</MESSAGE>"), GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize));
strlXML->AddString(strTemp);
pAppHelp = pAppHelp->pNext;
}
//
// AppHelp Added to Library
//
PLAYER_FIX plf = pDataBase->pLayerFixes;
while (plf) {
strTemp.Sprintf(TEXT("%s<LAYER NAME=\"%s\">"),
GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize),
plf->strName.SpecialCharToXML().pszString);
strlXML->AddString(strTemp);
pShimFixList = plf->pShimFixList;
CreateXMLForShimFixList(pShimFixList, strlXML);
//
// Now the same story for the flags for this layer.
//
PFLAG_FIX_LIST pFlagFixList = plf->pFlagFixList;
while (pFlagFixList) {
PFLAG_FIX pff = pFlagFixList->pFlagFix;
if (pFlagFixList->strCommandLine.Length() == 0) {
strTemp.Sprintf(TEXT("%s<FLAG NAME = \"%s\"/>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pff->strName.SpecialCharToXML().pszString);
} else {
strTemp.Sprintf(TEXT("%s<FLAG NAME = \"%s\" COMMAND_LINE = \"%s\" />"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pff->strName.SpecialCharToXML().pszString,
pFlagFixList->strCommandLine.SpecialCharToXML().pszString);
}
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
pFlagFixList = pFlagFixList->pNext;
}
strTemp.Sprintf(TEXT("%s</LAYER>"), GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize));
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
plf = plf->pNext;
}
strTemp.Sprintf(TEXT("%s</LIBRARY>"), GetSpace(szSpace, TAB_SIZE * 1, iszSpaceSize));
if (!strlXML->AddString(strTemp)) {
return FALSE;
}
//
// Now for the EXE entries
//
if (!bComplete) {
if (!GetEntryXML(strlXML, pEntry)) {
return FALSE;
}
} else {
//
// Get the XML for all the entries
//
for (PDBENTRY pApps = pEntry; pApps != NULL; pApps = pApps->pNext) {
for (PDBENTRY pEntryinApp = pApps;
pEntryinApp;
pEntryinApp = pEntryinApp->pSameAppExe) {
if (!GetEntryXML(strlXML, pEntryinApp)) {
return FALSE;
}
}
}
}
if (!strlXML->AddString(TEXT("</DATABASE>"))) {
return FALSE;
}
return TRUE;
}
BOOL
GetEntryXML(
IN OUT CSTRINGLIST* pstrlXML,
IN PDBENTRY pEntry
)
/*++
GetEntryXML
Desc: Gets the XML for an entry
Params:
IN OUT CSTRINGLIST* pstrlXML: Append the XML to this
IN PDBENTRY pEntry: Entry whose XML we want to get
Return:
TRUE: Success
FALSE: Otherwise
--*/
{
PSHIM_FIX_LIST pShimFixList;
PFLAG_FIX_LIST pFlagFixList;
PLAYER_FIX_LIST pLayerFixList;
PPATCH_FIX_LIST pPatchFixList;
TCHAR szSpace[64];
INT iszSpaceSize = 0;
iszSpaceSize = ARRAYSIZE(szSpace);
//
// The App Info
//
if (pEntry == NULL || pstrlXML == NULL) {
assert(FALSE);
return FALSE;
}
CSTRING strTemp;
strTemp.Sprintf(TEXT("%s<APP NAME=\"%s\" VENDOR=\"%s\">"),
GetSpace(szSpace, TAB_SIZE * 1, iszSpaceSize),
pEntry->strAppName.SpecialCharToXML().pszString,
pEntry->strVendor.SpecialCharToXML().pszString);
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
if (pEntry->szGUID[0] == 0) {
strTemp.Sprintf(TEXT("%s<EXE NAME=\"%s\""),
GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize),
pEntry->strExeName.SpecialCharToXML().pszString);
} else {
strTemp.Sprintf(TEXT("%s<EXE NAME=\"%s\" ID=\"%s\""),
GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize),
pEntry->strExeName.SpecialCharToXML().pszString,
pEntry->szGUID);
}
PMATCHINGFILE pMatch = pEntry->pFirstMatchingFile;
//
// Resolve for the "*". We need to get the attributes for the program being fixed
//
while (pMatch) {
if (pMatch->strMatchName == TEXT("*")) {
AttributesToXML(strTemp, pMatch);
break;
} else {
pMatch = pMatch->pNext;
}
}
strTemp.Strcat(TEXT(">"));
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
//
// Add the matching info
//
pMatch = pEntry->pFirstMatchingFile;
while (pMatch) {
//
// We will ignore the program file being fixed(represented by *), because
// we have already added its xml above
//
if (pMatch->strMatchName != TEXT("*")) {
strTemp.Sprintf(TEXT("%s<MATCHING_FILE NAME=\"%s\""),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pMatch->strMatchName.SpecialCharToXML().pszString);
AttributesToXML(strTemp, pMatch);
strTemp.Strcat(TEXT("/>"));
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
}
pMatch = pMatch->pNext;
}
//
// Add the layers
//
pLayerFixList = pEntry->pFirstLayer;
pShimFixList = pEntry->pFirstShim;
BOOL bCustomLayerFound = FALSE; // Does there exist a layer for this exe entry?
while (pLayerFixList) {
if (pLayerFixList->pLayerFix == NULL) {
assert(FALSE);
goto Next_Layer;
}
if (pLayerFixList->pLayerFix->bCustom) {
bCustomLayerFound = TRUE;
}
strTemp.Sprintf(TEXT("%s<LAYER NAME = \"%s\"/>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pLayerFixList->pLayerFix->strName.SpecialCharToXML().pszString);
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
Next_Layer:
pLayerFixList = pLayerFixList->pNext;
}
if (g_bWin2K
&& (bCustomLayerFound == TRUE || pShimFixList)
&& !IsShimInEntry(TEXT("Win2kPropagateLayer"), pEntry)) {
//
// On Win2K we need to add Win2kPropagateLayer shim to entries that have a shim
// or a custom layer.
//
strTemp.Sprintf(TEXT("%s<SHIM NAME= \"Win2kPropagateLayer\"/>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize));
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
}
//
// Add the Shims for this exe
//
if (pShimFixList) {
if (!CreateXMLForShimFixList(pShimFixList, pstrlXML)) {
return FALSE;
}
}
//
// Add the Patches
//
pPatchFixList = pEntry->pFirstPatch;
while (pPatchFixList) {
if (pPatchFixList->pPatchFix == NULL) {
assert(FALSE);
goto Next_Patch;
}
strTemp.Sprintf(TEXT("%s<PATCH NAME = \"%s\"/>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pPatchFixList->pPatchFix->strName.SpecialCharToXML().pszString);
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
Next_Patch:
pPatchFixList = pPatchFixList->pNext;
}
//
// Add the flags
//
pFlagFixList = pEntry->pFirstFlag;
while (pFlagFixList) {
if (pFlagFixList->pFlagFix == NULL) {
assert(FALSE);
goto Next_Flag;
}
if (pFlagFixList->strCommandLine.Length() == 0) {
strTemp.Sprintf(TEXT("%s<FLAG NAME = \"%s\"/>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pFlagFixList->pFlagFix->strName.SpecialCharToXML().pszString);
} else {
strTemp.Sprintf(TEXT("%s<FLAG NAME = \"%s\" COMMAND_LINE = \"%s\"/>"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
pFlagFixList->pFlagFix->strName.SpecialCharToXML().pszString,
pFlagFixList->strCommandLine.SpecialCharToXML().pszString);
}
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
Next_Flag:
pFlagFixList = pFlagFixList->pNext;
}
//
// Add the AppHelp
//
PAPPHELP pAppHelp = &(pEntry->appHelp);
assert(pAppHelp);
if (pAppHelp->bPresent) {
CSTRING strBlock;
if (pAppHelp->bBlock) {
strBlock = TEXT("YES");
} else {
strBlock = TEXT("NO");
}
CSTRING strName;
strName.Sprintf(TEXT("%u"), pAppHelp->HTMLHELPID);
CSTRING strHelpID;
strHelpID.Sprintf(TEXT("%u"), pAppHelp->HTMLHELPID);
//
// The URL is kept with the apphelp in the Library. Just as in the .SDB
//
pAppHelp = pEntry->appHelp.pAppHelpinLib;
assert(pAppHelp);
assert(pEntry->appHelp.HTMLHELPID == pAppHelp->HTMLHELPID);
if (pAppHelp->strURL.Length()) {
strTemp.Sprintf(TEXT("%s<APPHELP MESSAGE = \"%s\" BLOCK = \"%s\" HTMLHELPID = \"%s\" DETAILS_URL = \"%s\" />"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
strName.pszString,
strBlock.pszString,
strHelpID.pszString,
pAppHelp->strURL.SpecialCharToXML().pszString);
} else {
strTemp.Sprintf(TEXT("%s<APPHELP MESSAGE = \"%s\" BLOCK = \"%s\" HTMLHELPID = \"%s\" />"),
GetSpace(szSpace, TAB_SIZE * 3, iszSpaceSize),
strName.pszString,
strBlock.pszString,
strHelpID.pszString);
}
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
}
// End of AppHelp
strTemp.Sprintf(TEXT("%s</EXE>"), GetSpace(szSpace, TAB_SIZE * 2, iszSpaceSize));
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
strTemp.Sprintf(TEXT("%s</APP>"), GetSpace(szSpace, TAB_SIZE * 1, iszSpaceSize));
if (!pstrlXML->AddString(strTemp)) {
return FALSE;
}
return TRUE;
}
BOOL
CheckForDBName(
IN PDATABASE pDatabase
)
/*++
CheckForDBName
Description: Prompts the user if the database name is still the default name
Params:
IN PDATABASE pDatabase: The pointer to the database, for which we need to make
the check.
Return:
TRUE: The database name is now not the default name
FALSE: The databae name is still the default name
--*/
{
BOOL bOkayPressed = TRUE;
CSTRING strNewDBName;
//
// Check if the database name is the default name that we provided. We should not
// allow that because the database name appears in the "Add and Remove" Programs list
//
while (pDatabase->strName.BeginsWith(GetString(IDS_DEF_DBNAME))) {
//
// Yes, it does
//
bOkayPressed = DialogBoxParam(g_hInstance,
MAKEINTRESOURCE(IDD_DBRENAME),
g_hDlg,
DatabaseRenameDlgProc,
(LPARAM)&strNewDBName);
if (bOkayPressed == FALSE) {
//
// User pressed cancel, we must not save this database
//
goto End;
} else {
pDatabase->strName = strNewDBName;
}
}
End:
return bOkayPressed;
}
BOOL
SaveDataBase(
IN PDATABASE pDataBase,
IN CSTRING& strFileName
)
/*++
SaveDataBase
Desc: Saves the database pDataBase in file strFileName
Params:
IN PDATABASE pDataBase: The database that we want to save
IN CSTRING &strFileName: The file in which to save
Return:
TRUE: Success
FALSE: Otherwise
--*/
{
BOOL bOk = TRUE;
CSTRINGLIST strlXML;
CSTRING strTemp;
CSTRING strCommandLine;
TCHAR szPath[MAX_PATH * 2];
TCHAR szXMLFileName[MAX_PATH];
GUID Guid;
DWORD dwCount = 0;
*szPath = 0;
if (!pDataBase || !strFileName.Length()) {
assert(FALSE);
bOk = FALSE;
goto End;
}
//
// Check if the database name has the default name. This routine will prompt
// the user and lets the user change the name
//
if (!CheckForDBName(pDataBase)) {
//
// The user did not change the default database name, we must not save
// the database
//
bOk = FALSE;
goto End;
}
SetCursor(LoadCursor(NULL, IDC_WAIT));
dwCount = GetTempPath(MAX_PATH, szPath);
if (dwCount == 0 || dwCount > MAX_PATH) {
bOk = FALSE;
goto End;
}
ADD_PATH_SEPARATOR(szPath, ARRAYSIZE(szPath));
if (*(pDataBase->szGUID) == NULL) {
//
// We do not have a guid. Get that..
//
CoCreateGuid(&Guid);
StringCchPrintf(pDataBase->szGUID,
ARRAYSIZE(pDataBase->szGUID),
TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
Guid.Data1,
Guid.Data2,
Guid.Data3,
Guid.Data4[0],
Guid.Data4[1],
Guid.Data4[2],
Guid.Data4[3],
Guid.Data4[4],
Guid.Data4[5],
Guid.Data4[6],
Guid.Data4[7]);
}
StringCchPrintf(szXMLFileName, ARRAYSIZE(szXMLFileName), TEXT("%s.XML"), pDataBase->szGUID);
szXMLFileName[ARRAYSIZE(szXMLFileName) - 1] = 0;
StringCchCat(szPath, ARRAYSIZE(szPath), szXMLFileName);
if (!GetXML(pDataBase->pEntries, TRUE, &strlXML, pDataBase)) {
bOk = FALSE;
goto End;
}
strTemp = szPath;
if (!WriteXML(strTemp , &strlXML)) {
bOk = FALSE;
goto End;
}
strCommandLine.Sprintf(TEXT("custom \"%s\" \"%s\""),
(LPCTSTR)strTemp,
(LPCTSTR)strFileName);
if (!InvokeCompiler(strCommandLine)) {
MSGF(g_hDlg,
g_szAppName,
MB_ICONERROR,
GetString(IDS_CANNOTSAVE),
(LPCTSTR)pDataBase->strName);
bOk = FALSE;
goto End;
}
pDataBase->strPath = strFileName;
pDataBase->bChanged = FALSE;
//
// Add this name to the MRU list and refresh this MRU menu
//
AddToMRU(pDataBase->strPath);
RefreshMRUMenu();
End:
SetCaption();
SetCursor(LoadCursor(NULL, IDC_ARROW));
return bOk;
}
BOOL
SaveDataBaseAs(
IN PDATABASE pDataBase
)
/*++
SaveDataBaseAs
Desc: Saves the database pDataBase after prompting for a file name
Params:
IN PDATABASE pDataBase: The database that we want to save
Return:
TRUE: Success
FALSE: Otherwise
--*/
{
TCHAR szBuffer1[MAX_PATH] = TEXT(""), szBuffer2[MAX_PATH] = TEXT("");
CSTRING strCaption;
CSTRING strFileName;
BOOL bOk = FALSE;
if (pDataBase == NULL) {
assert(FALSE);
return FALSE;
}
//
// Check if the database name has the default name. This routine will prompt
// the user and lets the user change the name
//
if (!CheckForDBName(pDataBase)) {
//
// The user did not change the default database name, we must not save
// the database
//
bOk = FALSE;
goto End;
}
strCaption.Sprintf(TEXT("%s: \"%s\""), GetString(IDS_SAVE), pDataBase->strName);
BOOL bResult = GetFileName(g_hDlg,
strCaption,
GetString(IDS_FILTER, szBuffer1, ARRAYSIZE(szBuffer1)),
TEXT(""),
GetString(IDS_SDB_EXT, szBuffer2, ARRAYSIZE(szBuffer2)),
OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
FALSE,
strFileName);
//
// Redraw the controls
//
UpdateControls();
if (bResult) {
bOk = SaveDataBase(pDataBase, strFileName);
} else {
bOk = FALSE;
}
End:
SetCaption();
return bOk;
}
BOOL
CheckIfConflictingEntry(
IN PDATABASE pDataBase,
IN PDBENTRY pEntry,
IN PDBENTRY pEntryBeingEdited,
IN PDBENTRY* ppEntryFound, // (NULL)
IN PDBENTRY* ppAppFound // (NULL)
)
/*++
CheckIfConflictingEntry
Desc: Checks if some entry that will conflict with pEntry already exists in the database
Algo: For all the entries in the database that have the same name as this
entry (we do not care for the application name), let us say an
existing entry with the same name as pEntry is X, we see if all
the matching files for the entry being checked (pEntry) are also similar to
some matching files in X
If yes then we say that pEntry conflicts with X
Two matching files are said to be similar if there does not any exist any attribute
that has different values in these two matching files
Params:
IN PDATABASE pDataBase : The database in which to make the check
IN PDBENTRY pEntry, : The entry to check
IN PDBENTRY pEntryBeingEdited : This is required because when we check for existing
entries and we are editing an entry, then the entry being edited
Will always match (well, not if we modify the matching file)
IN PDBENTRY* ppEntryFound (NULL) : If not NULL this will hold the conflicting entry
IN PDBENTRY* ppAppFound (NULL) : If not NULL this will hold the app of the conflicting entry
Return:
TRUE: There is a conflict
FALSE: Otherwise
--*/
{
PDBENTRY pApps = NULL, pEntryExists = NULL;
if (pDataBase == NULL || pEntry == NULL) {
assert(FALSE);
return FALSE;
}
for (pApps = pDataBase->pEntries;
pApps != NULL;
pApps = pApps->pNext) {
for (pEntryExists = pApps;
pEntryExists;
pEntryExists = pEntryExists->pSameAppExe) {
if (pEntryExists == pEntryBeingEdited) {
//
// Do not compare with self. Also pEntryExists will never be NULL here(see the for loop)
// So we will not enter here when we are creating a new entry as we pass
// NULL for pEntryBeingEdited.
//
continue;
}
if (pEntryExists->strExeName == pEntry->strExeName) {
for (PMATCHINGFILE pMatchNewEntry = pEntry->pFirstMatchingFile;
pMatchNewEntry != NULL;
pMatchNewEntry = pMatchNewEntry->pNext) {
BOOL bFound = FALSE;
for (PMATCHINGFILE pMatchOldEntry = pEntryExists->pFirstMatchingFile;
pMatchOldEntry != NULL;
pMatchOldEntry = pMatchOldEntry->pNext) {
if (*pMatchNewEntry == *pMatchOldEntry) {
bFound = TRUE;
break;
}
}
if (bFound == FALSE) {
goto next_entry;
}
}
if (ppAppFound) {
*ppAppFound = pApps;
}
if (ppEntryFound) {
*ppEntryFound = pEntryExists;
}
return TRUE;
}
next_entry: ;
}
}
return FALSE;
}
BOOL
CloseDataBase(
IN PDATABASE pDataBase
)
/*++
CloseDataBase
Desc: Closes the pDataBase database, prompts for save if not saved already.
This routine will also remove the item for the database from the db tree.
Only working databases can be closed.
This routine first checks if the database is saved, if not prompts the user to save it.
If the user, says CANCEL then we return FALSE.
Otherwise we first remove the entry from the tree, then close the database
and return.
Params:
IN PDATABASE pDataBase: Database to close
Return:
TRUE: The database entry was removed from the tree and the database was
removed from the list of working databases.
FALSE: Otherwise
Notes: In some bizarre condition if DataBaseList.Remove(pDataBase) fails then we will end up
removing the item from the tree but not from the database list. This is certainly a
big error but there is no need to worry as by then we are already totally messed up,
so as to come to this situation
Please note that we must remove the entry before removing/deleting the database pointer,
because in case we get the focus on the db tree item whose database has been deleted
then the lParam of the database tree item will point to a freed memory location
--*/
{
if (pDataBase == NULL) {
assert(FALSE);
return FALSE;
}
if (!CheckAndSave(pDataBase)) {
return FALSE;
}
//
// NOTE: This routine will remove the entry and in the process set the focus
// on some other entry. This will change the g_pPresentDatabase
//
if (!DBTree.RemoveDataBase(pDataBase->hItemDB , DATABASE_TYPE_WORKING)) {
assert(FALSE);
return FALSE;
}
//
// Clear the entry tree so that we do not get any selection message there. We have to do this
// because in the next step we are removing the database and if the tree view stays around and it
// gets a sel change message somehow we may AV as:
// 1. CompatAdminDlgProc handles WM_NOTIFY for the entry tree
// 2. HandleNotifyExeTree
// 3. OnEntrySelChange
// 4. GetItemType.
// In GetItemType the pEntry for the entry tree is now no longer valid
//
// We do not get this behavior if the focus is in the contents list
//
TreeDeleteAll(g_hwndEntryTree);
g_pSelEntry = g_pEntrySelApp = NULL;
//
// Remove this database from the list of databases
//
PDATABASELIST pDataBaseList;
if (pDataBase->type != DATABASE_TYPE_WORKING) {
assert(FALSE);
return FALSE;
}
return (DataBaseList.Remove(pDataBase));
}
void
GetNextSDBFileName(
OUT CSTRING& strFileName,
OUT CSTRING& strDBName
)
/*++
GetNextSDBFileName
Desc: Gets the next filename and then database name for a working database
The file name is not the complete path but just the file name like
Untitled_X
The database name will be something like New Database(X)
Params:
OUT CSTRING &strFileName: Will contain the filename
OUT CSTRING &strDBName: Will contain the database name
Return:
void
--*/
{
BOOL bRepeat = TRUE;
//
// When we close the databases, we decrement g_uNextDataBaseIndex, so that it can become
// 0, but we want to start from 1
//
if (g_uNextDataBaseIndex == 0) {
g_uNextDataBaseIndex = 1;
}
strFileName.Sprintf(TEXT("%s_%u"), GetString(IDS_DEF_FILENAME), g_uNextDataBaseIndex);
while (bRepeat) {
PDATABASE pDatabase = DataBaseList.pDataBaseHead;
strDBName.Sprintf(TEXT("%s(%u)"), GetString(IDS_DEF_DBNAME), g_uNextDataBaseIndex);
//
// Try to make sure that we do not have a database with the same name.
// This is not a strict rule and users can rename it to some existing open database
//
while (pDatabase) {
if (pDatabase->strName == strDBName) {
++g_uNextDataBaseIndex;
break;
}
pDatabase = pDatabase->pNext;
}
bRepeat = (pDatabase == NULL) ? FALSE : TRUE;
}
}
BOOL
CompareLayers(
IN PLAYER_FIX pLayerOne,
IN PLAYER_FIX pLayerTwo
)
/*++
CompareLayers
Desc: Checks if two layers have the same stuff
Algo: Two layers will be said to be same if they have the same shims and fixes and for each
similar shim and fix, the parameters also tally.
For shims two include-exclude lists will be said to be similar if they have the same modules
and module types and the order of occurrence is also same
Params:
IN PLAYER_FIX pLayerOne: Layer 1
IN PLAYER_FIX pLayerTwo: layer 2
Return:
TRUE: Both layers have same stuff
FALSE: Otherwise
--*/
{
BOOL bFound = FALSE;
if (pLayerOne == NULL || pLayerTwo == NULL) {
assert(FALSE);
return FALSE;
}
//
// First compare the flag Lists
//
int countOne = 0, countTwo = 0; // Number of elements in pFlag/ShimListOne/Two
for (PFLAG_FIX_LIST pFlagListOne = pLayerOne->pFlagFixList;
pFlagListOne;
pFlagListOne = pFlagListOne->pNext) {
countOne++;
bFound = FALSE;
for (PFLAG_FIX_LIST pFlagListTwo = pLayerTwo->pFlagFixList;
pFlagListTwo;
pFlagListTwo = pFlagListTwo->pNext) {
if (pFlagListOne->pFlagFix == pFlagListTwo->pFlagFix) {
if (pFlagListOne->strCommandLine != pFlagListTwo->strCommandLine) {
return FALSE;
}
bFound = TRUE;
break;
}
}
if (bFound == FALSE) {
return FALSE;
}
}
// TODO: Can optimize
// Count the number of items in the second list.
//
countTwo = 0;
for (PFLAG_FIX_LIST pFlagListTwo = pLayerTwo->pFlagFixList;
pFlagListTwo;
pFlagListTwo = pFlagListTwo->pNext) {
countTwo++;
}
if (countOne != countTwo) {
return FALSE;
}
bFound = FALSE;
countOne = 0;
for (PSHIM_FIX_LIST pShimListOne = pLayerOne->pShimFixList;
pShimListOne;
pShimListOne = pShimListOne->pNext) {
bFound = FALSE;
countOne++;
for (PSHIM_FIX_LIST pShimListTwo = pLayerTwo->pShimFixList;
pShimListTwo;
pShimListTwo = pShimListTwo->pNext) {
if (pShimListOne->pShimFix == pShimListTwo->pShimFix) {
//
// Now check if the command lines are same
//
if (pShimListOne->strCommandLine != pShimListTwo->strCommandLine) {
return FALSE;
}
//
// Now check if the include exclude lists are same. Operator is overloaded
//
if (pShimListOne->strlInExclude != pShimListTwo->strlInExclude) {
return FALSE;
}
bFound = TRUE;
break;
}
}
if (bFound == FALSE) {
return FALSE;
}
}
countTwo = 0;
for (PSHIM_FIX_LIST pShimListTwo = pLayerTwo->pShimFixList;
pShimListTwo;
pShimListTwo = pShimListTwo->pNext) {
countTwo++;
}
return (countOne == countTwo);
}
BOOL
PasteSystemAppHelp(
IN PDBENTRY pEntry,
IN PAPPHELP_DATA pData,
IN PDATABASE pDataBaseTo,
OUT PAPPHELP* ppAppHelpInLib
)
/*++
PasteSystemAppHelp
Desc: This routine, copies the apphelp for the help-id present in apphelp.sdb,
to the custom database specified by pDataBaseTo
Params:
IN PDBENTRY pEntry: The entry to which this apphelp message has been applied
IN PAPPHELP_DATA pData: Address of a APPHELP_DATA to pass to SdbReadApphelpDetailsData
This contains among other things the HTMLHELPID of the message to be copied
IN PDATABASE pDataBaseTo: The database in which we want to copy this message to
OUT PAPPHELP* ppAppHelpInLib: If not null Will contain a pointer to copied PAPPHELP
in the library section of pDataBaseTo
Return:
TRUE: Successful
FALSE: Otherwise
--*/
{
PDB pdbAppHelp = NULL;
BOOL bOk = TRUE;
if (!pEntry || !pData || !pDataBaseTo) {
assert (FALSE);
return FALSE;
}
pdbAppHelp = SdbOpenApphelpDetailsDatabase(NULL);
if (pdbAppHelp == NULL) {
bOk = FALSE;
goto end;
}
if (!SdbReadApphelpDetailsData(pdbAppHelp, pData)) {
bOk = FALSE;
goto end;
}
PAPPHELP pAppHelpNew = new APPHELP;
if (NULL == pAppHelpNew) {
MEM_ERR;
bOk = FALSE;
goto end;
}
pAppHelpNew->strURL = pData->szURL;
pAppHelpNew->strMessage = pData->szDetails;
pAppHelpNew->HTMLHELPID = ++(pDataBaseTo->m_nMAXHELPID);
pAppHelpNew->severity = pEntry->appHelp.severity;
pAppHelpNew->bBlock = pEntry->appHelp.bBlock;
pAppHelpNew->pNext = pDataBaseTo->pAppHelp;
pDataBaseTo->pAppHelp = pAppHelpNew;
if (ppAppHelpInLib) {
*ppAppHelpInLib = pAppHelpNew;
}
end:
if (pdbAppHelp) {
SdbCloseDatabase(pdbAppHelp);
pdbAppHelp = NULL;
}
return bOk;
}
BOOL
PasteAppHelpMessage(
IN PAPPHELP pAppHelp,
IN PDATABASE pDataBaseTo,
OUT PAPPHELP* ppAppHelpInLib
)
/*++
PasteAppHelpMessage
Desc: This routine is used to copy a single apphelp from a custom database
to some another database. This will be employed when we are copy pasting the
DBENTRY ies from one database to another. The APPHELP pointed to by the
DBENTRY, in the library, has to be copied to the library of the second database.
Notes: This routine is to be used only when we are copying from a custom (working or installed)
database, because for them we keep the app help data in the library.
For system aka main or global database the apphelp that is kept in the lib section for
custom databases is kept in apphelp.sdb so we employ PasteSystemAppHelp() for pasting
system database apphelp messages
Important: Win2K SP3 does not have apphelp.sdb and SdbOpenApphelpDetailsDatabase(NULL)
will fail there, so we cannot copy-paste app help from the system
database to a custom database in win2k
--*/
{
PAPPHELP pAppHelpNew = NULL;
if (pAppHelp == NULL || pDataBaseTo == NULL) {
assert(FALSE);
return FALSE;
}
pAppHelpNew = new APPHELP;
if (pAppHelpNew == NULL) {
MEM_ERR;
return FALSE;
}
//
// Copy all members of pAppHelp to pAppHelpNew
//
*pAppHelpNew = *pAppHelp;
//
// Now change the members that should change.
//
pAppHelpNew->HTMLHELPID = ++(pDataBaseTo->m_nMAXHELPID);
pAppHelpNew->pNext = pDataBaseTo->pAppHelp;
pDataBaseTo->pAppHelp = pAppHelpNew;
if (ppAppHelpInLib) {
*ppAppHelpInLib = pAppHelpNew;
}
return TRUE;
}
INT
PasteLayer(
IN PLAYER_FIX plf,
IN PDATABASE pDataBaseTo,
IN BOOL bForcePaste, // (FALSE)
OUT PLAYER_FIX* pplfNewInserted, // (NULL)
IN BOOL bShow // (FALSE)
)
/*++
PasteLayer
Desc: Pastes single layer plf to pDataBaseTo
Params:
IN PLAYER_FIX plf: The layer to paste
IN PDATABASE pDataBaseTo: The database to paste into
IN BOOL bForcePaste (FALSE): This means that we do want to
copy the layer, even if there exists a layer with the same name and shims
in database
OUT PLAYER_FIX* pplfNewInserted (NULL): Will contain the pointer to the
newly pasted layer or existing exactly similar layer
IN BOOL bShow (FALSE): Should we set the focus to the
newly created layer in the DBTree
Return:
0: Copied, Note that we will return 0, if a layer already exists in this database
with the same name and same set of fixes and bForce == FALSE
-1: There was some error
Algo:
We proceed this way, for the modes to be pasted, we check if there exists some layer
in the target database with the same name. If there does not exist then we just paste it.
If there exists a layer with the same name then we check if the two layers are exactly
similar.
If they are exactly similar and bForcePaste is false then we quit. If they are exactly similar
and bForcePaste is true then we will paste the layer. It will have a derived name though. e.g
suppose we want to copy layer foo, then the name of the new layer that will be pasted will
be foo(1). Both of them will have the same fixes. We will also do this if the names are similar
but the contents of the two layers are different.
Under no circumstance will we allow two layers to have the same name in a database
If there already exists a layer with the same name then we always make a new layer with a derived
name. e.g suppose we want to copy layer foo, then the name of the new layer that
will be pasted will be foo(1)
Notes: This function is used when we copy-paste a layer from one db to another and also when we
copy an entry from one database that is fixed with a custom layer. bForcePaste will be true
if we are copying a layer from one database to another, but false if the routine is
getting called because we are trying to copy-paste an entry.
--*/
{
PLAYER_FIX pLayerFound = NULL;
INT iReturn = -1;
CSTRING strName = plf->strName;
CSTRING strEvent;
TCHAR szNewLayerName[MAX_PATH];
//
// Check if we have a layer with the same name in the target database or in
// the system database
//
pLayerFound = (PLAYER_FIX)FindFix(LPCTSTR(strName), FIX_LAYER, pDataBaseTo);
if (pLayerFound) {
//
// Now we check if *plf is exactly same as *pLayerFound
//
if (pplfNewInserted) {
*pplfNewInserted = pLayerFound;
}
if (!bForcePaste && CompareLayers(plf, pLayerFound)) {
//
// The layer already exists, do nothing
//
return 0;
} else {
//
// Dissimilar or we want to force a paste, Get the unique name
//
*szNewLayerName = 0;
strName = GetUniqueName(pDataBaseTo,
plf->strName,
szNewLayerName,
ARRAYSIZE(szNewLayerName),
FIX_LAYER);
}
}
//
// Add this new layer for the second database.
//
PLAYER_FIX pLayerNew = new LAYER_FIX(TRUE);
if (pLayerNew == NULL) {
MEM_ERR;
return -1;
}
//
// Overloaded operator. Copy all the fields from plf to pLayerNew. Then we will
// change the fields that need to be changed
//
*pLayerNew = *plf;
//
// Set the name of the layer. This might need to be changed, if we already had a layer
// by the same name in the target database
//
pLayerNew->strName = strName;
pLayerNew->pNext = pDataBaseTo->pLayerFixes;
pDataBaseTo->pLayerFixes = pLayerNew;
if (pplfNewInserted) {
*pplfNewInserted = pLayerNew;
}
if (plf->bCustom == FALSE) {
//
// System layer. We will have to add the event that a system layer had to be
// renamed
//
strEvent.Sprintf(GetString(IDS_EVENT_SYSTEM_RENAME),
plf->strName.pszString,
szNewLayerName,
pDataBaseTo->strName.pszString);
AppendEvent(EVENT_SYSTEM_RENAME, NULL, strEvent.pszString);
} else {
//
// We will show the name of the layer as it is shown in the target database.
// It might have got changed in case there was a conflict
//
strEvent.Sprintf(GetString(IDS_EVENT_LAYER_COPYOK),
plf->strName.pszString,
pDataBaseTo->strName.pszString,
pLayerNew->strName.pszString,
pDataBaseTo->strName.pszString);
AppendEvent(EVENT_LAYER_COPYOK, NULL, strEvent.pszString);
}
DBTree.AddNewLayer(pDataBaseTo, pLayerNew, bShow);
return 0;
}
BOOL
PasteMultipleLayers(
IN PDATABASE pDataBaseTo
)
/*++
PasteMultipleLayers
Desc: Pastes the layers that are copied to the clipboard to another database
Params:
IN PDATABASE pDataBaseTo: The database to copy the layers to
Return:
TRUE: Success
FALSE: Error
Notes: The difference between PasteMultipleLayers and PasteAllLayers is that
PasteMultipleLayers will only paste layers which are in the clipboard.
But PasteAllLayers will copy all layers of the "From" database. So
PasteAllLayers only checks which database is the "From" database.
PasteMultipleLayers is used when we select multiple items from the contents list
(RHS). PasteAllLayers is used when we have selected the "Compatibility Modes" node
in the db tree (LHS) while copying
--*/
{
CopyStruct* pCopyTemp = gClipBoard.pClipBoardHead;
//
// Copy all the layers in the clipboard
//
while (pCopyTemp) {
INT iRet = PasteLayer((PLAYER_FIX)pCopyTemp->lpData,
pDataBaseTo,
TRUE,
NULL,
FALSE);
if (iRet == -1) {
return FALSE;
}
pCopyTemp = pCopyTemp->pNext;
}
if (pDataBaseTo->hItemAllLayers) {
TreeView_Expand(DBTree.m_hLibraryTree, pDataBaseTo->hItemAllLayers, TVE_EXPAND);
TreeView_SelectItem(DBTree.m_hLibraryTree, pDataBaseTo->hItemAllLayers);
}
return TRUE;
}
BOOL
ShimFlagExistsInLayer(
IN LPVOID lpData,
IN PLAYER_FIX plf,
IN TYPE type
)
/*++
ShimFlagExistsInLayer
Desc: Checks if the specified shim / flag pData is present in the layer plf.
We just check if the layer contains this shim or flag, i.e. there is a
pointer in the PSHIM_FIX_LIST or PFLAG_FIX_LIST of the layer to the
shim or flag
Params:
IN LPVOID lpData: The pointer to shim or flag that we want to look for
IN PLAYER_FIX plf: The layer in which we should be looking
IN TYPE type: One of a) FIX_SHIM b) FIX_FLAG
Return:
TRUE: The fix exists in the layer
FALSE: Otherwise
--*/
{
if (lpData == NULL || plf == NULL) {
assert(FALSE);
return FALSE;
}
//
// First test for shims
//
if (type == FIX_SHIM) {
PSHIM_FIX_LIST psflInLayer = plf->pShimFixList;
while (psflInLayer) {
if (psflInLayer->pShimFix == (PSHIM_FIX)lpData) {
return TRUE;
}
psflInLayer = psflInLayer->pNext;
}
} else if (type == FIX_FLAG) {
//
// Test for flags
//
PFLAG_FIX_LIST pfflInLayer = plf->pFlagFixList;
while (pfflInLayer) {
if (pfflInLayer->pFlagFix == (PFLAG_FIX)lpData) {
return TRUE;
}
pfflInLayer = pfflInLayer->pNext;
}
} else {
//
// Invalid type
//
assert(FALSE);
return FALSE;
}
return FALSE;
}
BOOL
PasteShimsFlags(
IN PDATABASE pDataBaseTo
)
/*++
PasteShimsFlags
Desc: Copies the shims selected from the global database into the presently selected working
database's presently selected layer
If this shim is already present in the layer we do not
copy the shims, otherwise we copy this shim
The layer in which we want to copy the shims/flags is the layer associated with the
presently selected hItem in the db tree
Params:
IN PDATABASE pDataBaseTo: The database containing the layer in which we want to paste
the copied shims to.
--*/
{
CopyStruct* pCopyTemp = gClipBoard.pClipBoardHead;
HTREEITEM hItemSelected = TreeView_GetSelection(DBTree.m_hLibraryTree);
LPARAM lParam = NULL;
PLAYER_FIX plf = NULL;
TYPE type = TYPE_UNKNOWN;
LVITEM lvitem = {0};
//
// hItemSelected should be a layer, so that we can paste the shims into it
//
if (hItemSelected == NULL) {
assert(FALSE);
return FALSE;
}
if (!DBTree.GetLParam(hItemSelected, &lParam)) {
assert(FALSE);
return FALSE;
}
type = GetItemType(DBTree.m_hLibraryTree, hItemSelected);
if (type != FIX_LAYER) {
//
// A layer should have been selected if we want to copy-paste shims
//
if (type == TYPE_GUI_LAYERS && GetFocus() == g_hwndContentsList) {
//
// We had the focus on the contents list view. Now lets us get the
// item that has the selection mark in the list view pretend that the user
// wants to paste the fixes in that tree item for the corresponding list view
// item in the db tree
//
lvitem.mask = LVIF_PARAM;
lvitem.iItem = ListView_GetSelectionMark(g_hwndContentsList);
lvitem.iSubItem = 0;
if (ListView_GetItem(g_hwndContentsList, &lvitem)) {
//
// Since the focus is at the contents list and type == TYPE_GUI_LAYERS and
// we are going to paste fixes we must be having the "Compatibility Modes"
// tree item selected in the db tree
//
hItemSelected = DBTree.FindChild(hItemSelected,
lvitem.lParam);
if (hItemSelected == NULL) {
assert(FALSE);
return FALSE;
}
//
// Must set the lParam local variable to that of the list view item's lParam. The
// list view item for a layer and the corresponding tree view item
// in the db tree have the same lParam
//
lParam = lvitem.lParam;
} else {
//
// could not get the lparam for the list item
//
assert(FALSE);
return FALSE;
}
} else {
//
// We cannot paste fixes here
//
assert(FALSE);
return FALSE;
}
}
plf = (PLAYER_FIX)lParam;
while (pCopyTemp) {
//
// First we check if this shim is already present in the layer, if yes then we do not
// copy this, otherwise we copy this shim
//
TYPE typeFix = ConvertLpVoid2Type(pCopyTemp->lpData);
if (ShimFlagExistsInLayer(pCopyTemp->lpData, plf, typeFix)) {
goto next_shim;
}
//
// Now copy this shim or flag
//
if (typeFix == FIX_SHIM) {
PSHIM_FIX_LIST psfl = new SHIM_FIX_LIST;
PSHIM_FIX psfToCopy = (PSHIM_FIX)pCopyTemp->lpData;
if (psfl == NULL) {
MEM_ERR;
return FALSE;
}
psfl->pShimFix = psfToCopy;
psfl->pNext = plf->pShimFixList;
plf->pShimFixList = psfl;
//
// [Note:] We are not copying the parameters for the shim or flag because the shim or flag can be
// only selected from the system database. We need to change this if we allow copying of
// shims and layers from anywhere else except the system database.
//
} else if (typeFix == FIX_FLAG) {
PFLAG_FIX_LIST pffl = new FLAG_FIX_LIST;
if (pffl == NULL) {
MEM_ERR;
return FALSE;
}
pffl->pFlagFix = (PFLAG_FIX)pCopyTemp->lpData;
pffl->pNext = plf->pFlagFixList;
plf->pFlagFixList = pffl;
}
next_shim:
pCopyTemp = pCopyTemp->pNext;
}
//
// Now update this layer
//
DBTree.RefreshLayer(pDataBaseTo, plf);
return TRUE;
}
BOOL
PasteAllLayers(
IN PDATABASE pDataBaseTo
)
/*++
PasteAllLayers
Desc: Copies the layers that are in the clipboard to some other database
Params:
IN PDATABASE pDataBaseTo: The database in which we want to paste the modes
Return:
TRUE: Success
FALSE: Error
Notes: The difference between PasteMultipleLayers and PasteAllLayers is that
PasteMultipleLayers will only paste layers which are in the clipboard. But
PasteAllLayers will copy all layers of the "From" database. So
PasteAllLayers only checks which database is the "From" database.
PasteMultipleLayers is used when we select multiple items from the contents list
(RHS). PasteAllLayers is used when we have selected the "Compatibility Modes" node
in the db tree (LHS) while copying
--*/
{
PLAYER_FIX plf = gClipBoard.pDataBase->pLayerFixes;
while (plf) {
if (PasteLayer(plf, pDataBaseTo, TRUE, NULL, FALSE) == -1) {
return FALSE;
}
plf = plf->pNext;
}
if (pDataBaseTo->hItemAllLayers) {
TreeView_Expand(DBTree.m_hLibraryTree, pDataBaseTo->hItemAllLayers, TVE_EXPAND);
TreeView_SelectItem(DBTree.m_hLibraryTree, pDataBaseTo->hItemAllLayers);
}
return TRUE;
}
void
FreeAppHelp(
PAPPHELP_DATA pData
)
{
// bugbug: Do we need to free the strings with PAPPHELP_DATA <TODO>
}
INT
PasteSingleApp(
IN PDBENTRY pApptoPaste,
IN PDATABASE pDataBaseTo,
IN PDATABASE pDataBaseFrom,
IN BOOL bAllExes,
IN PCTSTR szNewAppNameIn //def = NULL
)
/*++
Desc: Pastes a single app into the database
Params:
IN PDBENTRY pApptoPaste: App to paste
IN PDATABASE pDataBaseTo: Database in which to paste
IN PDATABASE pDataBaseFrom: Database from where we obtained the pApptoPaste
IN BOOL bAllExes: Should we paste all exes for this app or only the entry
for pApptoPaste
IN PCTSTR szNewAppNameIn (NULL): If non null then the app name for the entries should be
changed to this name
Note: We save the Previous value of the m_nMAXHELPID of the TO database.
The function PasteAppHelpMessage will modify that while pasting the
entries, we will again make use of this so that the entries point
to the correct apphelp messages in the database and also they contain
the correct HTMLHELPids.
Return:
-1: There was some problem
1: Successful
--*/
{
HCURSOR hCursor = GetCursor();
UINT uPrevMaxHtmldIdTo = pDataBaseTo->m_nMAXHELPID;
CSTRING strAppName = pApptoPaste->strAppName;
CSTRING strNewname = pApptoPaste->strAppName;
PDBENTRY pEntryToPaste = pApptoPaste;
PDBENTRY pApp = NULL;
PDBENTRY pEntryNew = NULL;
INT iRet = 0;
BOOL bConflictFound = FALSE;
CSTRING strEvent;
INT iReturn = 1;
SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Copy the layers
//
while (pEntryToPaste) {
PDBENTRY pEntryMatching = NULL, pAppOfEntry = NULL;
BOOL bRepaint = FALSE; //ReDraw the entry tree only if the entry to be deleted is in that!
// The entry that we want to ignore while looking for conflicts. This variable
// is used when we are doing a cut-paste on the same database, at that time we will like to ignore
// the entry that has been cut, during checking for conflicts
//
PDBENTRY pEntryIgnoreMatching = NULL;
if (!bAllExes && g_bIsCut && pDataBaseFrom == pDataBaseTo && gClipBoard.SourceType == ENTRY_TREE) {
pEntryIgnoreMatching = pApptoPaste;
}
if (CheckIfConflictingEntry(pDataBaseTo,
pEntryToPaste,
pEntryIgnoreMatching,
&pEntryMatching,
&pAppOfEntry)) {
if (g_bEntryConflictDonotShow == FALSE) {
*g_szData = 0;
StringCchPrintf(g_szData,
ARRAYSIZE(g_szData),
GetString(IDS_ENTRYCONFLICT),
pEntryMatching->strExeName.pszString,
pEntryMatching->strAppName.pszString);
iRet = DialogBoxParam(g_hInstance,
MAKEINTRESOURCE(IDD_CONFLICTENTRY),
g_hDlg,
HandleConflictEntry,
(LPARAM)g_szData);
if (iRet == IDNO) {
goto NextEntry;
}
strEvent.Sprintf(GetString(IDS_EVENT_CONFLICT_ENTRY),
pEntryMatching->strExeName.pszString,
pEntryMatching->strAppName.pszString,
pDataBaseTo->strName.pszString);
AppendEvent(EVENT_CONFLICT_ENTRY, NULL, strEvent.pszString);
bConflictFound = TRUE;
}
//
// Now copy the entry
//
HTREEITEM hItemSelected = DBTree.GetSelection();
if (GetItemType(DBTree.m_hLibraryTree, hItemSelected) == TYPE_ENTRY) {
LPARAM lParam;
if (DBTree.GetLParam(hItemSelected, &lParam) && (PDBENTRY)lParam == pAppOfEntry) {
//
// The entry tree for the correct app is already visible. So we can paste directly there
//
bRepaint = TRUE;
}
}
}
pEntryNew = new DBENTRY;
if (pEntryNew == NULL) {
iRet = -1;
goto End;
}
*pEntryNew = *pEntryToPaste;
GUID Guid;
CoCreateGuid(&Guid);
StringCchPrintf(pEntryNew->szGUID,
ARRAYSIZE(pEntryNew->szGUID),
TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
Guid.Data1,
Guid.Data2,
Guid.Data3,
Guid.Data4[0],
Guid.Data4[1],
Guid.Data4[2],
Guid.Data4[3],
Guid.Data4[4],
Guid.Data4[5],
Guid.Data4[6],
Guid.Data4[7]);
//
// Now set the flags as per the entry being copied.
//
SetDisabledStatus(HKEY_LOCAL_MACHINE,
pEntryNew->szGUID,
pEntryToPaste->bDisablePerMachine);
//
// Unfortunately, now the custom layers in the custom layer list for the entry
// point to the custom layers in the From database, so correct that !
//
DeleteLayerFixList(pEntryNew->pFirstLayer);
pEntryNew->pFirstLayer = NULL;
PLAYER_FIX plfNewInserted = NULL; // The layer inserted by PasteLayer
PLAYER_FIX_LIST plflExisting = pEntryToPaste->pFirstLayer;
while (plflExisting) {
assert(plflExisting->pLayerFix);
PLAYER_FIX_LIST plflNew = new LAYER_FIX_LIST;
if (plflExisting->pLayerFix->bCustom) {
INT iRetLayerPaste = PasteLayer(plflExisting->pLayerFix,
pDataBaseTo,
FALSE,
&plfNewInserted,
FALSE);
if (iRetLayerPaste == -1) {
if (plflNew) {
delete plflNew;
}
if (pEntryNew) {
delete pEntryNew;
}
iRet = -1;
goto End;
}
plflNew->pLayerFix = plfNewInserted;
} else {
plflNew->pLayerFix = plflExisting->pLayerFix;
}
//
// Add this layer list for the entry.
//
plflNew->pNext = pEntryNew->pFirstLayer;
pEntryNew->pFirstLayer = plflNew;
plflExisting = plflExisting->pNext;
}
//
// Now get the apphelp message as well.
//
PAPPHELP pAppHelpInLib = NULL;
if (pDataBaseFrom->type != DATABASE_TYPE_GLOBAL && pEntryToPaste->appHelp.bPresent) {
if (!PasteAppHelpMessage(pEntryToPaste->appHelp.pAppHelpinLib,
pDataBaseTo,
&pAppHelpInLib)) {
iRet = -1;
goto End;
}
pEntryNew->appHelp.HTMLHELPID = ++uPrevMaxHtmldIdTo;
assert(pAppHelpInLib);
pEntryNew->appHelp.pAppHelpinLib = pAppHelpInLib;
} else if (pDataBaseFrom->type == DATABASE_TYPE_GLOBAL && pEntryToPaste->appHelp.bPresent) {
APPHELP_DATA AppHelpData;
ZeroMemory(&AppHelpData, sizeof(AppHelpData));
AppHelpData.dwHTMLHelpID = pEntryToPaste->appHelp.HTMLHELPID;
if (!PasteSystemAppHelp(pEntryToPaste, &AppHelpData, pDataBaseTo, &pAppHelpInLib)) {
//
// We cannot copy apphelp in win2k
//
pEntryNew->appHelp.bPresent = FALSE;
FreeAppHelp(&AppHelpData);
} else {
pEntryNew->appHelp.HTMLHELPID = ++uPrevMaxHtmldIdTo;
assert(pAppHelpInLib);
pEntryNew->appHelp.pAppHelpinLib = pAppHelpInLib;
FreeAppHelp(&AppHelpData);
}
}
//
// If We were passed the app name use that.
//
if (szNewAppNameIn != NULL) {
pEntryNew->strAppName = szNewAppNameIn;
}
BOOL bNew;
pApp = AddExeInApp(pEntryNew, &bNew, pDataBaseTo);
if (bNew == TRUE) {
pApp = NULL;
}
if (bConflictFound == FALSE) {
//
// We have been able to copy entry without any conflicts
//
strEvent.Sprintf(GetString(IDS_EVENT_ENTRY_COPYOK),
pEntryNew->strExeName.pszString,
pEntryNew->strAppName.pszString,
pDataBaseFrom->strName.pszString,
pDataBaseTo->strName.pszString);
AppendEvent(EVENT_ENTRY_COPYOK, NULL, strEvent.pszString);
}
NextEntry:
//
// Copy all other entries only if asked.
//
pEntryToPaste = (bAllExes) ? pEntryToPaste->pSameAppExe: NULL;
}
if (pEntryNew) {
DBTree.AddApp(pDataBaseTo, pEntryNew, TRUE);
}
End:
SetCursor(hCursor);
return iRet;
}
BOOL
PasteMultipleApps(
IN PDATABASE pDataBaseTo
)
/*++
PasteMultipleApps
Desc: Copies multiple apps that have been copied to the clipboard
Params:
IN PDATABASE pDataBaseTo: The database to copy to
Return:
TRUE: Success
FALSE: Error
--*/
{
CopyStruct* pCopyTemp = gClipBoard.pClipBoardHead;
int iRet = 0;
while (pCopyTemp ) {
iRet = PasteSingleApp((PDBENTRY) pCopyTemp->lpData,
pDataBaseTo,
gClipBoard.pDataBase,
TRUE);
if (iRet == IDCANCEL || iRet == -1) {
break;
}
pCopyTemp = pCopyTemp->pNext;
}
SendMessage(g_hwndEntryTree, WM_SETREDRAW, TRUE, 0);
return iRet != -1 ? TRUE : FALSE;
}
BOOL
PasteAllApps(
IN PDATABASE pDataBaseTo
)
/*++
PasteAllApps
Desc: Copies all apps from one database to another. This routine is called when the user
had pressed copy when the focus was on the "Applications" tree item for a database
Params:
IN PDATABASE pDataBaseTo: The database to copy to
Return:
TRUE: Success
FALSE: Error
--*/
{
if (gClipBoard.pDataBase == NULL) {
assert(FALSE);
return FALSE;
}
PDBENTRY pApp = gClipBoard.pDataBase->pEntries;
int iRet = 0;
while (pApp) {
iRet = PasteSingleApp(pApp, pDataBaseTo, gClipBoard.pDataBase, TRUE);
if (iRet == IDCANCEL || iRet == -1) {
break;
}
pApp = pApp->pNext;
}
SendMessage(g_hwndEntryTree,
WM_SETREDRAW,
TRUE,
0);
return (iRet != -1) ? TRUE : FALSE;
}
void
ValidateClipBoard(
IN PDATABASE pDataBase,
IN LPVOID lpData
)
/*++
ValidateClipBoard
Desc: If the database is being closed and we have something from that database in the
clipboard Then the clipboard should be emptied.
If we have some other data in the clipboard such as an entry or some layer in
the clipboard and that is removed we have to remove it from the clipboard as
well.
Params:
IN PDATABASE pDataBase: Database being closed
IN LPVOID lpData: The entry or layer being removed
--*/
{
if (pDataBase && pDataBase == gClipBoard.pDataBase) {
gClipBoard.RemoveAll();
} else if (lpData) {
gClipBoard.CheckAndRemove(lpData);
}
}
BOOL
RemoveApp(
IN PDATABASE pDataBase,
IN PDBENTRY pApp
)
/*++
RemoveApp
Desc: Removes the application pApp and all the entries of this app from pDataBase
Params:
IN PDATABASE pDataBase: The database in which pApp resides
IN PDBENTRY pApp: The app to remove
Return:
void
--*/
{
if (!pDataBase || !pApp) {
assert(FALSE);
return FALSE;
}
PDBENTRY pAppInDataBase = pDataBase->pEntries;
PDBENTRY pAppPrev = NULL;
//
// Find the previous pointer of the app, so that we can remove this app
//
while (pAppInDataBase) {
if (pAppInDataBase == pApp) {
break;
}
pAppPrev = pAppInDataBase;
pAppInDataBase = pAppInDataBase->pNext;
}
if (pAppInDataBase) {
//
// We found the app
//
if (pAppPrev) {
pAppPrev->pNext = pAppInDataBase->pNext;
} else {
//
// The first app of the database matched
//
pDataBase->pEntries = pAppInDataBase->pNext;
}
}
PDBENTRY pEntryTemp = pAppInDataBase;
PDBENTRY pTempNext = NULL;
//
// Delete all the entries of this app.
//
while (pEntryTemp) {
pTempNext = pEntryTemp->pSameAppExe;
ValidateClipBoard(NULL, pEntryTemp);
delete pEntryTemp;
pEntryTemp = pTempNext;
}
--pDataBase->uAppCount;
return TRUE;
}
void
RemoveAllApps(
IN PDATABASE pDataBase
)
/*++
RemoveAllApps
Desc: Removes all the applications and all the entries from pDataBase. This will be invoked
when the user presses delete after when the focus was on the "Applications"
tree item for a database. Or when we want to cut all the applications
Params:
IN PDATABASE pDataBase: The database from which to remove all the entries
Return:
void
--*/
{
while (pDataBase->pEntries) {
//
// pDataBase->pEntries will get modified in the following function, as it is the first element
//
RemoveApp(pDataBase, pDataBase->pEntries);
}
}
BOOL
CheckForSDB(
void
)
/*++
CheckForSDB
Desc: Attempts to locate sysmain.sdb in the apppatch directory.
--*/
{
HANDLE hFile;
TCHAR szSDBPath[MAX_PATH * 2];
BOOL fResult = FALSE;
UINT uResult = 0;
uResult = GetSystemWindowsDirectory(szSDBPath, MAX_PATH);
if (uResult == 0 || uResult >= MAX_PATH) {
assert(FALSE);
return FALSE;
}
ADD_PATH_SEPARATOR(szSDBPath, ARRAYSIZE(szSDBPath));
StringCchCat(szSDBPath, ARRAYSIZE(szSDBPath), TEXT("apppatch\\sysmain.sdb"));
hFile = CreateFile(szSDBPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hFile) {
CloseHandle(hFile);
fResult = TRUE;
} else {
fResult = FALSE;
}
return (fResult);
}
BOOL
CheckIfInstalledDB(
IN PCTSTR szGuid
)
/*++
CheckIfInstalledDB
Desc: Tests whether the szGuid matches with one of an installed database.
This function assumes that all the installed databases are currently in
InstalledDataBaseList
Params:
IN PCTSTR szGuid: The guid of the database that we want to check
Return:
TRUE: If installed
FALSE: Otherwise
Warn: Do not do EnterCriticalSection(g_csInstalledList) in CheckIfInstalledDB()
because CheckIfInstalledDB() is called by Qyery db as well when it tries
to evaluate expressions and it might already have done a
EnterCriticalSection(g_csInstalledList)
and then we will get a deadlock
--*/
{
PDATABASE pDatabase = NULL;
//
// Was this a system database ?
//
if (!lstrcmpi(szGuid, GlobalDataBase.szGUID)
|| !lstrcmpi(szGuid, GUID_APPHELP_SDB)
|| !lstrcmpi(szGuid, GUID_SYSTEST_SDB)
|| !lstrcmpi(szGuid, GUID_MSI_SDB)
|| !lstrcmpi(szGuid, GUID_DRVMAIN_SDB)) {
return TRUE;
}
pDatabase = InstalledDataBaseList.pDataBaseHead;
while (pDatabase) {
if (!lstrcmpi(pDatabase->szGUID, szGuid)) {
return TRUE;
}
pDatabase = pDatabase->pNext;
}
return FALSE;
}
INT
GetLayerCount(
IN LPARAM lp,
IN TYPE type
)
/*++
GetLayerCount
Desc: Gets the number of layers applied to a entry or present in a database
Params:
IN LPARAM lp: The pointer to an entry or a database
IN TYPE type: The type, either an entry (TYPE_ENTRY) or one of the DATABASE_TYPE_*
Return:
-1: Error
#Layers: Otherwise
--*/
{
PLAYER_FIX_LIST plfl;
PLAYER_FIX plf;
INT iCount = 0;
PDATABASE pDatabase = NULL;
PDBENTRY pEntry = NULL;
if (lp == NULL) {
assert(FALSE);
return -1;
}
if (type == TYPE_ENTRY) {
pEntry = (PDBENTRY)lp;
plfl = pEntry->pFirstLayer;
while (plfl) {
++iCount;
plfl = plfl->pNext;
}
return iCount;
}
if (type == DATABASE_TYPE_GLOBAL
|| type == DATABASE_TYPE_INSTALLED
|| type == DATABASE_TYPE_WORKING) {
pDatabase = (PDATABASE)lp;
plf = pDatabase->pLayerFixes;
while (plf) {
++iCount;
plf = plf->pNext;
}
}
return iCount;
}
INT
GetPatchCount(
IN LPARAM lp,
IN TYPE type
)
/*++
GetPatchCount
Desc: Gets the number of patches applied to a entry or present in a database
Params:
IN LPARAM lp: The pointer to an entry or a database
IN TYPE type: The type, either an entry (TYPE_ENTRY) or one of the DATABASE_TYPE_*
Return:
-1: Error
#Patches: Otherwise
--*/
{
PPATCH_FIX_LIST ppfl;
PPATCH_FIX ppf;
INT iCount = 0;
if (lp == NULL) {
return -1;
}
if (type == TYPE_ENTRY) {
PDBENTRY pEntry = (PDBENTRY)lp;
ppfl = pEntry->pFirstPatch;
while (ppfl) {
++iCount;
ppfl = ppfl->pNext;
}
return iCount;
}
if (type == DATABASE_TYPE_GLOBAL || type == DATABASE_TYPE_INSTALLED || type == DATABASE_TYPE_WORKING) {
PDATABASE pDatabase = (PDATABASE)lp;
ppf = pDatabase->pPatchFixes;
while (ppf) {
++iCount;
ppf = ppf->pNext;
}
}
return iCount;
}
INT
GetShimFlagCount(
IN LPARAM lp,
IN TYPE type
)
/*++
GetShimFlagCount
Desc: Gets the number of shims and flags applied to a entry or present in a database
Params:
IN LPARAM lp: The pointer to an entry or a database
IN TYPE type: The type, either an entry (TYPE_ENTRY) or one of the DATABASE_TYPE_*,
Or FIX_LAYER
Return:
-1: Error
#shims and flags: Otherwise
--*/
{
PSHIM_FIX_LIST psfl = NULL;
PSHIM_FIX psf = NULL;
PFLAG_FIX_LIST pffl = NULL;
PFLAG_FIX pff = NULL;
INT iCount = 0;
if (lp == NULL) {
assert(FALSE);
return -1;
}
if (type == TYPE_ENTRY) {
PDBENTRY pEntry = (PDBENTRY)lp;
psfl = pEntry->pFirstShim;
while (psfl) {
++iCount;
psfl = psfl->pNext;
}
pffl = pEntry->pFirstFlag;
while (pffl) {
++iCount;
pffl = pffl->pNext;
}
return iCount;
} else if (type == DATABASE_TYPE_GLOBAL || type == DATABASE_TYPE_INSTALLED || type == DATABASE_TYPE_WORKING) {
PDATABASE pDatabase = (PDATABASE)lp;
psf = pDatabase->pShimFixes;
while (psf) {
++iCount;
psf = psf->pNext;
}
pff = pDatabase->pFlagFixes;
while (pff) {
++iCount;
pff = pff->pNext;
}
return iCount;
} else if (type == FIX_LAYER) {
PLAYER_FIX plf = (PLAYER_FIX)lp;
psfl = plf->pShimFixList;
while (psfl) {
++iCount;
psfl = psfl->pNext;
}
pffl = plf->pFlagFixList;
while (pffl) {
++iCount;
pffl = pffl->pNext;
}
} else {
assert(FALSE);
}
return iCount;
}
INT
GetMatchCount(
IN PDBENTRY pEntry
)
/*++
GetMatchCount
Desc: Returns the number of matching files used by an entry
Params:
IN PDBENTRY pEntry: The entry whose number of matching files we want to get
Return:
-1: If error
number of matching files: if success
--*/
{
if (pEntry == NULL) {
assert(FALSE);
return -1;
}
PMATCHINGFILE pMatch = pEntry->pFirstMatchingFile;
INT iCount = 0;
while (pMatch) {
iCount++;
pMatch = pMatch->pNext;
}
return iCount;
}
BOOL
IsUnique(
IN PDATABASE pDatabase,
IN PCTSTR szName,
IN UINT uType
)
/*++
IsUnique
Desc: Tests whether the passed string already exists as an appname
or a layer name in the database pDatabase
Params:
IN PDATABASE pDatabase: The database in which to search
IN PCTSTR szName: The string to search for
IN UINT uType: One of:
a) FIX_LAYER: If it is FIX_LAYER, we should check if a
layer with the name szName already exists in the database.
b) TYPE_ENTRY: If it is TYPE_ENTRY we should check if an app with the strAppName of szName
already exists in the database
--*/
{
PLAYER_FIX plf = NULL;
PDBENTRY pEntry = NULL;
if (pDatabase == NULL || szName == NULL) {
assert(FALSE);
return FALSE;
}
if (uType == FIX_LAYER) {
plf = pDatabase->pLayerFixes;
while (plf) {
if (plf->strName == szName) {
return FALSE;
}
plf = plf->pNext;
}
return TRUE;
} else if (uType == TYPE_ENTRY) {
pEntry = pDatabase->pEntries;
while (pEntry) {
if (pEntry->strAppName == szName) {
return FALSE;
}
pEntry = pEntry->pNext;
}
return TRUE;
} else {
//
// Invalid TYPE
//
assert(FALSE);
}
return FALSE;
}
PTSTR
GetUniqueName(
IN PDATABASE pDatabase,
IN PCTSTR szExistingName,
OUT PTSTR szBuffer,
IN INT cchBufferCount,
IN TYPE type
)
/*++
GetUniqueName
Desc: Gets a unique name for a layer or an app
Params:
IN PDATABASE pDatabase: The database in which to search
IN PCTSTR szExistingName: The existing layer or app name
OUT PTSTR szBuffer: The buffer where we put in the name
IN INT cchBufferCount: The size of the buffer szBuffer in TCHARs
IN TYPE type: One of: a) FIX_LAYER b) TYPE_ENTRY:
Return: Pointer to szBuffer. This will contain the new name
--*/
{
CSTRING strNewname;
TCHAR szName[MAX_PATH];
BOOL bValid = FALSE;
UINT uIndex = 0;
if (szBuffer == NULL) {
assert(FALSE);
return TEXT("X");
}
*szBuffer = 0;
*szName = 0;
SafeCpyN(szName, szExistingName, ARRAYSIZE(szName));
//
// Extract any number that occurs between () in the string, and increment that
//
TCHAR *pch = szName + lstrlen(szName);
while (pch > szName) {
if (*pch == TEXT(')')) {
*pch = TEXT('\0');
} else if (*pch == TEXT('(')) {
*pch = TEXT('\0');
uIndex = Atoi(pch + 1, &bValid);
if (bValid) {
++uIndex;
} else {
SafeCpyN(szName, szExistingName, ARRAYSIZE(szName));
}
break;
}
--pch;
}
if (uIndex == 0) {
uIndex = 1;
}
while (TRUE) {
strNewname.Sprintf(TEXT("%s(%u)"), szName, uIndex);
if (IsUnique(pDatabase, strNewname, type) == TRUE) {
break;
}
uIndex++;
}
SafeCpyN(szBuffer, strNewname, cchBufferCount);
return szBuffer;
}
PDBENTRY
GetAppForEntry(
IN PDATABASE pDatabase,
IN PDBENTRY pEntryToCheck
)
/*++
GetAppForEntry
Desc: Gets the app for the entry.
Params:
IN PDATABASE pDatabase: The database in which to look
IN PDBENTRY pEntryToCheck: The entry whose app we need to find
Return: The First PDBENTRY in the link list where this entry occurs, if it
occurs in the database
NULL otherwise
--*/
{
PDBENTRY pApp = pDatabase->pEntries;
PDBENTRY pEntry = pApp;
while (pApp) {
pEntry = pApp;
while (pEntry) {
if (pEntry == pEntryToCheck) {
goto End;
}
pEntry = pEntry->pSameAppExe;
}
pApp = pApp->pNext;
}
End:
return pApp;
}
BOOL
GetDbGuid(
OUT PTSTR pszGuid,
IN INT cchpszGuid,
IN PDB pdb
)
/*++
GetDbGuid
Desc: Gets the guid of the database specified by pdb in pszGuid
OUT TCHAR* pszGuid: The guid will be stored in this
IN PDB pdb: The pdb of the database whose guid we want
Return:
TRUE: Success
FALSE: Error
--*/
{
BOOL bOk = FALSE;
TAGID tiDatabase = NULL;
TAGID tName = NULL;
if (pszGuid == NULL || cchpszGuid == 0) {
assert(FALSE);
return FALSE;
}
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
if (tiDatabase == 0) {
Dbg(dlError, "Cannot find TAG_DATABASE\n");
bOk = FALSE;
goto End;
}
tName = SdbFindFirstTag(pdb, tiDatabase, TAG_DATABASE_ID);
if (0 != tName) {
GUID* pGuid;
TAGID tiGuid = SdbFindFirstTag(pdb, tiDatabase, TAG_DATABASE_ID);
pGuid = (GUID*)SdbGetBinaryTagData(pdb, tiGuid);
//BUGBUG: What about freeing this ?
*pszGuid = 0;
if (pszGuid != NULL) {
StringCchPrintf(pszGuid,
cchpszGuid,
TEXT ("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0],
pGuid->Data4[1],
pGuid->Data4[2],
pGuid->Data4[3],
pGuid->Data4[4],
pGuid->Data4[5],
pGuid->Data4[6],
pGuid->Data4[7]);
bOk = TRUE;
}
}
End:
return bOk;
}
BOOL
IsShimInEntry(
IN PCTSTR szShimName,
IN PDBENTRY pEntry
)
/*++
IsShimInEntry
Desc: Checks if the entry has the specified shim.
We only check if the shim name matches, we do not check for parameters
Params:
IN PCTSTR szShimName: Name of the shim that we want to check for
IN PDBENTRY pEntry: Entry that we want to check in
--*/
{
PSHIM_FIX_LIST psfl = NULL;
if (pEntry == NULL) {
assert(FALSE);
return FALSE;
}
psfl = pEntry->pFirstShim;
while (psfl) {
if (psfl->pShimFix->strName == szShimName) {
return TRUE;
}
psfl = psfl->pNext;
}
return FALSE;
}
BOOL
IsShimInlayer(
IN PLAYER_FIX plf,
IN PSHIM_FIX psf,
IN CSTRING* pstrCommandLine,
IN CSTRINGLIST* pstrlInEx
)
/*++
IsShimInlayer
Desc: Checks if the shim psf is present in the layer plf
Params:
IN PLAYER_FIX plf: The layer to check in
IN PSHIM_FIX psf: The shim to check for
IN CSTRING* pstrCommandLine: Any command line for the shim
IN CSTRINGLIST* pstrlInEx: The pointer to the include-exclude list for the shim
Return: TRUE if present
: FALSE if not present
--*/
{
PSHIM_FIX_LIST psflInLayer = plf->pShimFixList;
while (psflInLayer) {
if (psflInLayer->pShimFix == psf) {
if (pstrCommandLine && psflInLayer->strCommandLine != *pstrCommandLine) {
goto Next_Loop;
}
if (pstrlInEx && *pstrlInEx != psflInLayer->strlInExclude) {
goto Next_Loop;
}
return TRUE;
}
Next_Loop:
psflInLayer = psflInLayer->pNext;
}
return FALSE;
}
BOOL
IsFlagInlayer(
PLAYER_FIX plf,
PFLAG_FIX pff,
CSTRING* pstrCommandLine
)
/*++
IsFlagInlayer
Desc: Checks if the flag psf is present in the layer plf
Params:
IN PLAYER_FIX plf: The layer to check in
IN PFLAG_FIX pff: The flag to check for
IN CSTRING* pstrCommandLine: Any command line for the flag
Return: TRUE if present
: FALSE if not present
--*/
{
PFLAG_FIX_LIST pfflInLayer = plf->pFlagFixList;
while (pfflInLayer) {
if (pfflInLayer->pFlagFix == pff) {
if (pstrCommandLine && *pstrCommandLine != pff->strCommandLine) {
goto Next_Loop;
} else {
return TRUE;
}
}
Next_Loop:
pfflInLayer = pfflInLayer->pNext;
}
return FALSE;
}
void
PreprocessForSaveAs(
IN PDATABASE pDatabase
)
/*++
PreprocessForSaveAs
Desc: This routine replaces the db guid and the entry guids with fresh guids.
This routine is called just before we do a save as. This routine,
also makes sure that if there is a entry that is disabled then the
new guid for the entry also is set to disabled in the registry.
Params:
IN PDATABASE pDatabase: The database that we are going to save
--*/
{
GUID Guid;
PDBENTRY pEntry = NULL, pApp = NULL;
if (pDatabase == NULL) {
assert(FALSE);
return;
}
CoCreateGuid(&Guid);
StringCchPrintf(pDatabase->szGUID,
ARRAYSIZE(pDatabase->szGUID),
TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
Guid.Data1,
Guid.Data2,
Guid.Data3,
Guid.Data4[0],
Guid.Data4[1],
Guid.Data4[2],
Guid.Data4[3],
Guid.Data4[4],
Guid.Data4[5],
Guid.Data4[6],
Guid.Data4[7]);
pEntry = pDatabase->pEntries, pApp = pDatabase->pEntries;
while (pEntry) {
CoCreateGuid(&Guid);
StringCchPrintf(pEntry->szGUID,
ARRAYSIZE(pEntry->szGUID),
TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
Guid.Data1,
Guid.Data2,
Guid.Data3,
Guid.Data4[0],
Guid.Data4[1],
Guid.Data4[2],
Guid.Data4[3],
Guid.Data4[4],
Guid.Data4[5],
Guid.Data4[6],
Guid.Data4[7]);
//
// Now set the flags as per the entry being copied.
//
SetDisabledStatus(HKEY_LOCAL_MACHINE,
pEntry->szGUID,
pEntry->bDisablePerMachine);
if (pEntry->pSameAppExe) {
pEntry = pEntry->pSameAppExe;
} else {
pApp = pApp->pNext;
pEntry = pApp;
}
}
}
void
ShowShimLog(
void
)
/*++
ShowShimLog
Desc: Show the shim log file in notepad.
--*/
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
TCHAR szLogPath[MAX_PATH * 2];
CSTRING strCmd;
CSTRING strNotePadpath;
UINT uResult = 0;
*szLogPath = 0;
uResult = GetSystemWindowsDirectory(szLogPath, MAX_PATH);
if (uResult == 0 || uResult >= MAX_PATH) {
assert(FALSE);
return;
}
ADD_PATH_SEPARATOR(szLogPath, ARRAYSIZE(szLogPath));
StringCchCat(szLogPath, ARRAYSIZE(szLogPath), TEXT("AppPatch\\") SHIM_FILE_LOG_NAME);
if (GetFileAttributes(szLogPath) == -1) {
//
// The log file does not exist
//
MessageBox(g_hDlg,
GetString(IDS_NO_LOGFILE),
g_szAppName,
MB_ICONEXCLAMATION | MB_OK);
return;
}
strNotePadpath.GetSystemDirectory();
strNotePadpath += TEXT("notepad.exe");
//
// Note the space at the end
//
strCmd.Sprintf(TEXT("\"%s\" "), (LPCTSTR)strNotePadpath, szLogPath);
strCmd.Strcat(szLogPath);
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL,
(LPTSTR)strCmd,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi)) {
MessageBox(g_hDlg, GetString(IDS_NO_NOTEPAD), g_szAppName, MB_ICONEXCLAMATION);
return;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
INT
CopyShimFixList(
IN OUT PSHIM_FIX_LIST* ppsflDest,
IN PSHIM_FIX_LIST* ppsflSrc
)
/*++
Copy
Desc: Copies the *ppsflSrc to *ppsflDest. Removes any existing
shims first
Params:
IN OUT PSHIM_FIX_LIST* ppsflDest: The pointer to shim fix list in which we want to copy
IN PSHIM_FIX_LIST* ppsflSrc: The pointer to shim fix list from which we want to copy
Return: Number of shims copied
--*/
{
PSHIM_FIX_LIST psflDestination = NULL;
PSHIM_FIX_LIST psflSrc = NULL;
PSHIM_FIX_LIST psflTemp = NULL;
INT iCount = 0;
if (ppsflDest == NULL || ppsflSrc == NULL) {
assert(FALSE);
goto End;
}
psflDestination = *ppsflDest;
psflSrc = *ppsflSrc;
//
// Remove all the shims for this
//
DeleteShimFixList(psflDestination);
psflDestination = NULL;
//
// Now do the copy
//
//
// Loop over the shims for psflSrc and add them to the destination shim fix list
//
while (psflSrc) {
psflTemp = new SHIM_FIX_LIST;
if (psflTemp == NULL) {
MEM_ERR;
goto End;
}
//
// copy all the members for psflSrc
//
if (psflSrc->pLuaData) {
//
// Source has lua data so we need to get that
//
psflTemp->pLuaData = new LUADATA;
if (psflTemp == NULL) {
MEM_ERR;
break;
}
psflTemp->pLuaData->Copy(psflSrc->pLuaData);
}
psflTemp->pShimFix = psflSrc->pShimFix;
psflTemp->strCommandLine = psflSrc->strCommandLine;
psflTemp->strlInExclude = psflSrc->strlInExclude;
if (psflDestination == NULL) {
//
// First item
//
psflDestination = psflTemp;
} else {
//
// Insert at the beginning
//
psflTemp->pNext = psflDestination;
psflDestination = psflTemp;
}
++iCount;
psflSrc = psflSrc->pNext;
}
End:
if (ppsflDest) {
*ppsflDest = psflDestination;
}
return iCount;
}
BOOL
IsValidAppName(
IN PCTSTR pszAppName
)
/*++
ValidAppName
Desc: Checks if the name can be used for an app. Since LUA wizard uses the app name
to create directories, we should not allow the chars that are not allowed in file
names
Params:
IN PCTSTR pszAppName: The name that we want to check
Return:
TRUE: The app name is valid
FDALSE: Otherwise
--*/
{
PCTSTR pszIndex = pszAppName;
if (pszIndex == NULL) {
assert(FALSE);
return FALSE;
}
while (*pszIndex) {
if (_tcschr(TEXT("\\/?:*<>|\""), *pszIndex)) {
return FALSE;
}
++pszIndex;
}
return TRUE;
}