Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1563 lines
49 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
links.c
Abstract:
This source file implements the Win95 side of LNK and PIF processing
Author:
Calin Negreanu (calinn) 09-Feb-1998
Revision History:
calinn 23-Sep-1998 Redesigned several pieces
--*/
#include "pch.h"
#include "migdbp.h"
#include "migappp.h"
POOLHANDLE g_LinksPool = NULL;
INT g_LinkStubSequencer = 0;
typedef struct _LINK_STRUCT {
PCTSTR ReportEntry;
PCTSTR Category;
PCTSTR Context;
PCTSTR Object;
PCTSTR LinkName;
PCTSTR LinkNameNoPath;
PMIGDB_CONTEXT MigDbContext;
} LINK_STRUCT, *PLINK_STRUCT;
BOOL
InitLinkAnnounce (
VOID
)
{
//
// Create PoolMem for keeping all structures during this phase
//
g_LinksPool = PoolMemInitNamedPool ("Links Pool");
return TRUE;
}
BOOL
DoneLinkAnnounce (
VOID
)
{
// Write LinkStub max sequencer data
MemDbSetValue (MEMDB_CATEGORY_LINKSTUB_MAXSEQUENCE, g_LinkStubSequencer);
//
// Free Links Pool.
//
if (g_LinksPool != NULL) {
PoolMemDestroyPool (g_LinksPool);
g_LinksPool = NULL;
}
return TRUE;
}
BOOL
SaveLinkFiles (
IN PFILE_HELPER_PARAMS Params
)
{
PCTSTR Ext;
if (Params->Handled) {
return TRUE;
}
Ext = GetFileExtensionFromPath (Params->FullFileSpec);
// Save LNK and PIF filenames to memdb to enumerate later
if (Ext && (StringIMatch (Ext, TEXT("LNK")) || StringIMatch (Ext, TEXT("PIF")))) {
MemDbSetValueEx (
MEMDB_CATEGORY_SHORTCUTS,
Params->FullFileSpec,
NULL,
NULL,
0,
NULL
);
}
return TRUE;
}
VOID
RemoveLinkFromSystem (
IN LPCTSTR LinkPath
)
{
//
// Remove any move or copy operation specified for the link, then
// mark it for deletion.
//
RemoveOperationsFromPath (LinkPath, ALL_DEST_CHANGE_OPERATIONS);
MarkFileForDelete (LinkPath);
}
//
// Function to send instruction to MemDb to edit a shell link or pif file.
// It checks to see whether the link involved has been touched yet by any
// MemDb operation. It modifies the target path, if in a relocating directory,
// to one of the relocated copies.
//
VOID
pAddLinkEditToMemDb (
IN PCTSTR LinkPath,
IN PCTSTR NewTarget,
IN PCTSTR NewArgs,
IN PCTSTR NewWorkDir,
IN PCTSTR NewIconPath,
IN INT NewIconNr,
IN PLNK_EXTRA_DATA ExtraData, OPTIONAL
IN BOOL ForceToShowNormal
)
{
UINT sequencer;
TCHAR tmpStr [20];
sequencer = AddOperationToPath (LinkPath, OPERATION_LINK_EDIT);
if (sequencer == INVALID_OFFSET) {
DEBUGMSG ((DBG_ERROR, "Cannot set OPERATION_LINK_EDIT on %s", LinkPath));
return;
}
if (NewTarget) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewTarget, MEMDB_CATEGORY_LINKEDIT_TARGET);
}
if (NewArgs) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewArgs, MEMDB_CATEGORY_LINKEDIT_ARGS);
}
if (NewWorkDir) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewWorkDir, MEMDB_CATEGORY_LINKEDIT_WORKDIR);
}
if (NewIconPath) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewIconPath, MEMDB_CATEGORY_LINKEDIT_ICONPATH);
}
if (NewIconPath) {
_itoa (NewIconNr, tmpStr, 16);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_ICONNUMBER);
}
if (ForceToShowNormal) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, TEXT("1"), MEMDB_CATEGORY_LINKEDIT_SHOWNORMAL);
}
if (ExtraData) {
_itoa (ExtraData->FullScreen, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_FULLSCREEN);
_itoa (ExtraData->xSize, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_XSIZE);
_itoa (ExtraData->ySize, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_YSIZE);
_itoa (ExtraData->QuickEdit, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_QUICKEDIT);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, ExtraData->FontName, MEMDB_CATEGORY_LINKEDIT_FONTNAME);
_itoa (ExtraData->xFontSize, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_XFONTSIZE);
_itoa (ExtraData->yFontSize, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_YFONTSIZE);
_itoa (ExtraData->FontWeight, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_FONTWEIGHT);
_itoa (ExtraData->FontFamily, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_FONTFAMILY);
_itoa (ExtraData->CurrentCodePage, tmpStr, 10);
AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_CODEPAGE);
}
MYASSERT (IsFileMarkedForOperation (LinkPath, OPERATION_LINK_EDIT));
}
//
// Function to send instruction to MemDb to save some data about a link that's going to be edited.
// We do that to be able to restore this link later using lnkstub.exe
//
UINT
pAddLinkStubToMemDb (
IN PCTSTR LinkPath,
IN PCTSTR OldTarget,
IN PCTSTR OldArgs,
IN PCTSTR OldWorkDir,
IN PCTSTR OldIconPath,
IN INT OldIconNr,
IN DWORD OldShowMode,
IN DWORD Announcement,
IN DWORD Availability
)
{
UINT sequencer;
TCHAR tmpStr [20];
MEMDB_ENUM e, e1;
TCHAR key [MEMDB_MAX];
MYASSERT (OldTarget || OldWorkDir || OldIconPath || OldIconNr);
sequencer = AddOperationToPath (LinkPath, OPERATION_LINK_STUB);
if (sequencer == INVALID_OFFSET) {
DEBUGMSG ((DBG_ERROR, "Cannot set OPERATION_LINK_STUB on %s", LinkPath));
return 0;
}
g_LinkStubSequencer++;
if (OldTarget) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldTarget, MEMDB_CATEGORY_LINKSTUB_TARGET);
}
if (OldArgs) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldArgs, MEMDB_CATEGORY_LINKSTUB_ARGS);
}
if (OldWorkDir) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldWorkDir, MEMDB_CATEGORY_LINKSTUB_WORKDIR);
}
if (OldIconPath) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldIconPath, MEMDB_CATEGORY_LINKSTUB_ICONPATH);
}
if (OldIconPath) {
_itoa (OldIconNr, tmpStr, 16);
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_ICONNUMBER);
}
_itoa (OldShowMode, tmpStr, 16);
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_SHOWMODE);
_itoa (g_LinkStubSequencer, tmpStr, 16);
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_SEQUENCER);
_itoa (Announcement, tmpStr, 16);
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_ANNOUNCEMENT);
_itoa (Availability, tmpStr, 16);
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_REPORTAVAIL);
MemDbBuildKey (key, MEMDB_CATEGORY_REQFILES_MAIN, OldTarget, TEXT("*"), NULL);
if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
do {
MemDbBuildKey (key, MEMDB_CATEGORY_REQFILES_ADDNL, e.szName, TEXT("*"), NULL);
if (MemDbEnumFirstValue (&e1, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, e1.szName, MEMDB_CATEGORY_LINKSTUB_REQFILE);
}
} while (MemDbEnumNextValue (&e));
}
MYASSERT (IsFileMarkedForOperation (LinkPath, OPERATION_LINK_STUB));
return g_LinkStubSequencer;
}
BOOL
pReportEntry (
IN PCTSTR ReportEntry,
IN PCTSTR Category,
IN PCTSTR Message,
IN PCTSTR Context,
IN PCTSTR Object
)
{
PCTSTR component;
component = JoinPaths (ReportEntry, Category);
MsgMgr_ContextMsg_Add (Context, component, Message);
MsgMgr_LinkObjectWithContext (Context, Object);
FreePathString (component);
return TRUE;
}
PTSTR
GetLastDirFromPath (
IN PCTSTR FileName
)
{
PTSTR result = NULL;
PTSTR temp = NULL;
PTSTR ptr;
temp = DuplicatePathString (FileName, 0);
__try {
ptr = (PTSTR)GetFileNameFromPath (temp);
if (ptr == temp) {
__leave;
}
ptr = _tcsdec (temp, ptr);
if (!ptr) {
__leave;
}
*ptr = 0;
ptr = (PTSTR)GetFileNameFromPath (temp);
if (ptr == temp) {
__leave;
}
result = DuplicatePathString (ptr, 0);
}
__finally {
FreePathString (temp);
}
return result;
}
PTSTR
GetDriveFromPath (
IN PCTSTR FileName
)
{
PTSTR result;
PTSTR ptr;
result = DuplicatePathString (FileName, 0);
ptr = _tcschr (result, TEXT(':'));
if (!ptr) {
FreePathString (result);
result = NULL;
}
else {
*ptr = 0;
}
return result;
}
#define MAX_PRIORITY 0xFFFF
BOOL
HandleDeferredAnnounce (
IN PCTSTR LinkName,
IN PCTSTR ModuleName,
IN BOOL DosApp
)
{
TCHAR key [MEMDB_MAX];
PMIGDB_CONTEXT migDbContext;
DWORD actType;
PLINK_STRUCT linkStruct;
PCTSTR reportEntry = NULL;
DWORD priority;
PCTSTR newLinkName = NULL;
PCTSTR linkName = NULL;
PCTSTR extPtr;
MEMDB_ENUM eNicePaths;
DWORD messageId = 0;
PTSTR pattern = NULL;
PTSTR category = NULL;
PTSTR tempParse = NULL;
PTSTR lastDir;
PTSTR drive;
DWORD oldValue;
DWORD oldPrior;
PTSTR argArray[3];
PCTSTR p;
PTSTR q;
BOOL reportEntryIsResource = TRUE;
PCTSTR temp1, temp2;
MYASSERT(ModuleName);
MemDbBuildKey (key, MEMDB_CATEGORY_DEFERREDANNOUNCE, ModuleName, NULL, NULL);
if (!MemDbGetValueAndFlags (key, (PDWORD)(&migDbContext), &actType)) {
actType = ACT_UNKNOWN;
migDbContext = NULL;
}
//
// we need to set the following variables:
// - ReportEntry - is going to be either "Software Incompatible with NT",
// "Software with minor problems" or
// "Software that require reinstallation"
// - Category - is one of the following: - Localized section name
// - link name (with friendly addition)
// - Unlocalized section name
// - Message - this is in migdb context
//
// - Object - this is module name
//
linkStruct = (PLINK_STRUCT) PoolMemGetMemory (g_LinksPool, sizeof (LINK_STRUCT));
ZeroMemory (linkStruct, sizeof (LINK_STRUCT));
linkStruct->MigDbContext = migDbContext;
linkStruct->Object = PoolMemDuplicateString (g_LinksPool, ModuleName);
switch (actType) {
case ACT_REINSTALL:
#if 0
if ((linkStruct->MigDbContext) &&
(linkStruct->MigDbContext->Message)
) {
reportEntry = GetStringResource (MSG_MINOR_PROBLEM_ROOT);
} else {
reportEntry = GetStringResource (MSG_REINSTALL_ROOT);
}
#endif
temp1 = GetStringResource (MSG_REINSTALL_ROOT);
if (!temp1) {
break;
}
temp2 = GetStringResource (
linkStruct->MigDbContext && linkStruct->MigDbContext->Message ?
MSG_REINSTALL_DETAIL_SUBGROUP :
MSG_REINSTALL_LIST_SUBGROUP
);
if (!temp2) {
break;
}
reportEntry = JoinPaths (temp1, temp2);
reportEntryIsResource = FALSE;
FreeStringResource (temp1);
FreeStringResource (temp2);
break;
case ACT_REINSTALL_BLOCK:
temp1 = GetStringResource (MSG_BLOCKING_ITEMS_ROOT);
if (!temp1) {
break;
}
temp2 = GetStringResource (MSG_REINSTALL_BLOCK_ROOT);
if (!temp2) {
break;
}
reportEntry = JoinPaths (temp1, temp2);
reportEntryIsResource = FALSE;
FreeStringResource (temp1);
FreeStringResource (temp2);
break;
case ACT_MINORPROBLEMS:
reportEntry = GetStringResource (MSG_MINOR_PROBLEM_ROOT);
break;
case ACT_INCOMPATIBLE:
case ACT_INC_NOBADAPPS:
case ACT_INC_IHVUTIL:
case ACT_INC_PREINSTUTIL:
case ACT_INC_SIMILAROSFUNC:
if (DosApp && (*g_Boot16 != BOOT16_NO)) {
reportEntry = GetStringResource (MSG_DOS_DESIGNED_ROOT);
}
else {
temp1 = GetStringResource (MSG_INCOMPATIBLE_ROOT);
switch (actType) {
case ACT_INC_SIMILAROSFUNC:
temp2 = GetStringResource (MSG_INCOMPATIBLE_UTIL_SIMILAR_FEATURE_SUBGROUP);
break;
case ACT_INC_PREINSTUTIL:
temp2 = GetStringResource (MSG_INCOMPATIBLE_PREINSTALLED_UTIL_SUBGROUP);
break;
case ACT_INC_IHVUTIL:
temp2 = GetStringResource (MSG_INCOMPATIBLE_HW_UTIL_SUBGROUP);
break;
default:
temp2 = GetStringResource (
linkStruct->MigDbContext && linkStruct->MigDbContext->Message ?
MSG_INCOMPATIBLE_DETAIL_SUBGROUP:
MSG_TOTALLY_INCOMPATIBLE_SUBGROUP
);
break;
}
MYASSERT (temp1 && temp2);
reportEntry = JoinPaths (temp1, temp2);
reportEntryIsResource = FALSE;
FreeStringResource (temp1);
FreeStringResource (temp2);
}
break;
case ACT_INC_SAFETY:
MYASSERT (LinkName);
temp1 = GetStringResource (MSG_INCOMPATIBLE_ROOT);
temp2 = GetStringResource (MSG_REMOVED_FOR_SAFETY_SUBGROUP);
MYASSERT (temp1 && temp2);
reportEntry = JoinPaths (temp1, temp2);
reportEntryIsResource = FALSE;
FreeStringResource (temp1);
FreeStringResource (temp2);
newLinkName = JoinPaths (S_RUNKEYFOLDER, GetFileNameFromPath (LinkName));
break;
case ACT_UNKNOWN:
reportEntry = GetStringResource (MSG_UNKNOWN_ROOT);
break;
default:
LOG((LOG_ERROR, "Unknown action for deferred announcement."));
return FALSE;
}
if (!newLinkName) {
newLinkName = LinkName;
}
if (reportEntry != NULL) {
linkStruct->ReportEntry = PoolMemDuplicateString (g_LinksPool, reportEntry);
if (reportEntryIsResource) {
FreeStringResource (reportEntry);
} else {
FreePathString (reportEntry);
}
}
linkStruct->LinkName = newLinkName?PoolMemDuplicateString (g_LinksPool, newLinkName):NULL;
//
// all we need to set now is the category
//
// if we have a migdb context with a Localized name section
//
if ((migDbContext != NULL) &&
(migDbContext->SectLocalizedName != NULL)
) {
linkStruct->Context = PoolMemDuplicateString (g_LinksPool, migDbContext->SectLocalizedName);
linkStruct->Category = PoolMemDuplicateString (g_LinksPool, migDbContext->SectLocalizedName);
priority = 0;
}
else {
linkStruct->Context = PoolMemDuplicateString (g_LinksPool, newLinkName?newLinkName:ModuleName);
if (newLinkName == NULL) {
MYASSERT (migDbContext);
if (migDbContext->SectName) {
linkStruct->Category = PoolMemDuplicateString (g_LinksPool, migDbContext->SectName);
}
else {
linkStruct->Category = NULL;
}
priority = 0;
}
else {
linkName = GetFileNameFromPath (newLinkName);
extPtr = GetFileExtensionFromPath (linkName);
if (extPtr != NULL) {
extPtr = _tcsdec (linkName, extPtr);
}
if (extPtr == NULL) {
extPtr = GetEndOfString (linkName);
}
messageId = 0;
priority = MAX_PRIORITY;
if (MemDbEnumFirstValue (&eNicePaths, MEMDB_CATEGORY_NICE_PATHS"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
do {
pattern = JoinPaths (eNicePaths.szName, "\\*");
if (IsPatternMatch (pattern, newLinkName)) {
if (priority > eNicePaths.UserFlags) {
messageId = eNicePaths.dwValue;
priority = eNicePaths.UserFlags;
}
}
FreePathString (pattern);
}
while (MemDbEnumNextValue (&eNicePaths));
}
category = AllocText ((PBYTE) extPtr - (PBYTE) linkName + sizeof (TCHAR));
p = linkName;
q = category;
while (p < extPtr) {
if (_tcsnextc (p) == TEXT(' ')) {
do {
p++;
} while (_tcsnextc (p) == TEXT(' '));
if (q > category && *p) {
*q++ = TEXT(' ');
}
} else if (IsLeadByte (*p)) {
*q++ = *p++;
*q++ = *p++;
} else {
*q++ = *p++;
}
}
*q = 0;
if (messageId == 0) {
lastDir = GetLastDirFromPath (newLinkName);
drive = GetDriveFromPath (newLinkName);
if (drive != NULL) {
drive[0] = (TCHAR)toupper (drive[0]);
if (lastDir != NULL) {
argArray [0] = category;
argArray [1] = lastDir;
argArray [2] = drive;
tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_DRIVE_AND_FOLDER, argArray);
}
else {
argArray [0] = category;
argArray [1] = drive;
tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_DRIVE, argArray);
}
}
else {
if (lastDir != NULL) {
argArray [0] = category;
argArray [1] = lastDir;
tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_FOLDER, argArray);
}
else {
argArray [0] = category;
tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_LINK, argArray);
}
}
linkStruct->Category = PoolMemDuplicateString (g_LinksPool, tempParse);
FreeStringResourcePtrA (&tempParse);
priority = MAX_PRIORITY;
} else {
tempParse = (PTSTR)ParseMessageID (messageId, &category);
StringCopy (category, tempParse);
linkStruct->Category = PoolMemDuplicateString (g_LinksPool, tempParse);
FreeStringResourcePtrA (&tempParse);
}
FreeText (category);
}
}
linkStruct->LinkNameNoPath = linkName?PoolMemDuplicateString (g_LinksPool, linkName):linkStruct->Context;
MemDbBuildKey (
key,
MEMDB_CATEGORY_REPORT_LINKS,
linkStruct->ReportEntry,
linkName?linkName:linkStruct->Context,
ModuleName);
if ((!MemDbGetValueAndFlags (key, &oldValue, &oldPrior)) ||
(oldPrior > priority)
) {
MemDbSetValueAndFlags (key, (DWORD)linkStruct, priority, 0);
}
if (newLinkName != LinkName) {
FreePathString (newLinkName);
}
return TRUE;
}
BOOL
pIsGUIDLauncherApproved (
IN PCTSTR FileName
)
{
INFCONTEXT context;
MYASSERT (g_Win95UpgInf != INVALID_HANDLE_VALUE);
return (SetupFindFirstLine (g_Win95UpgInf, S_APPROVED_GUID_LAUNCHER, FileName, &context));
}
#define GUID_LEN (sizeof ("{00000000-0000-0000-0000-000000000000}") - 1)
#define GUID_DASH_1 (sizeof ("{00000000") - 1)
#define GUID_DASH_2 (sizeof ("{00000000-0000") - 1)
#define GUID_DASH_3 (sizeof ("{00000000-0000-0000") - 1)
#define GUID_DASH_4 (sizeof ("{00000000-0000-0000-0000") - 1)
BOOL
pSendCmdLineGuidsToMemdb (
IN PCTSTR File,
IN PCTSTR Target,
IN PCTSTR Arguments
)
/*++
Routine Description:
pSendCmdLineGuidsToMemdb saves any GUIDs contained in a command line to
memdb, along with the file name. Later, OLEREG resolves the GUIDs and
deletes the file if a GUID is incompatible.
Arguments:
File - Specifies the file to delete if the command line arguments contain
an invalid GUID.
Target - Specifies the Target (needs to be one of the approved targets for the
LNK file to go away in an incompatible case).
Arguments - Specifies a command line that may contain one or more GUIDs in
the {a-b-c-d-e} format.
Return value:
TRUE - the operation was successful
FALSE - the operation failed
--*/
{
LPCTSTR p, q;
DWORD Offset;
BOOL b;
static DWORD Seq = 0;
TCHAR TextSeq[16];
TCHAR Guid[GUID_LEN + 1];
PCTSTR namePtr;
namePtr = GetFileNameFromPath (Target);
if (namePtr && pIsGUIDLauncherApproved (namePtr)) {
p = _tcschr (Arguments, TEXT('{'));
while (p) {
q = _tcschr (p, TEXT('}'));
if (q && ((q - p) == (GUID_LEN - 1))) {
if (p[GUID_DASH_1] == TEXT('-') &&
p[GUID_DASH_2] == TEXT('-') &&
p[GUID_DASH_3] == TEXT('-') &&
p[GUID_DASH_4] == TEXT('-')
) {
//
// Extract the GUID
//
q = _tcsinc (q);
StringCopyAB (Guid, p, q);
//
// Add the file name
//
b = MemDbSetValueEx (
MEMDB_CATEGORY_LINK_STRINGS,
File,
NULL,
NULL,
0,
&Offset
);
if (b) {
//
// Now add an entry for the GUID
//
Seq++;
wsprintf (TextSeq, TEXT("%u"), Seq);
b = MemDbSetValueEx (
MEMDB_CATEGORY_LINK_GUIDS,
Guid,
TextSeq,
NULL,
Offset,
NULL
);
}
if (!b) {
LOG ((LOG_ERROR, "Failed to store command line guids."));
}
}
}
p = _tcschr (p + 1, TEXT('{'));
}
}
return TRUE;
}
BOOL
pIsFileInStartup (
IN PCTSTR FileName
)
{
TCHAR key [MEMDB_MAX];
MemDbBuildKey (key, MEMDB_CATEGORY_SF_STARTUP, FileName, NULL, NULL);
return (MemDbGetPatternValue (key, NULL));
}
BOOL
pProcessShortcut (
IN PCTSTR FileName,
IN IShellLink *ShellLink,
IN IPersistFile *PersistFile
)
{
TCHAR shortcutTarget [MEMDB_MAX];
TCHAR shortcutArgs [MEMDB_MAX];
TCHAR shortcutWorkDir [MEMDB_MAX];
TCHAR shortcutIconPath [MEMDB_MAX];
PTSTR shortcutNewTarget = NULL;
PTSTR shortcutNewArgs = NULL;
PTSTR shortcutNewIconPath = NULL;
PTSTR shortcutNewWorkDir = NULL;
PTSTR commandPath = NULL;
PTSTR fullPath = NULL;
PCTSTR extPtr;
INT shortcutIcon;
INT newShortcutIcon;
DWORD shortcutShowMode;
WORD shortcutHotKey;
DWORD fileStatus;
BOOL msDosMode;
BOOL dosApp;
DWORD attrib;
LNK_EXTRA_DATA ExtraData;
INT lnkIdx;
TCHAR lnkIdxStr [10];
BOOL toBeModified = FALSE;
BOOL ConvertedLnk = FALSE;
DWORD announcement;
DWORD availability;
__try {
fileStatus = GetFileStatusOnNt (FileName);
if (((fileStatus & FILESTATUS_DELETED ) == FILESTATUS_DELETED ) ||
((fileStatus & FILESTATUS_REPLACED) == FILESTATUS_REPLACED)
) {
__leave;
}
if (!ExtractShortcutInfo (
shortcutTarget,
shortcutArgs,
shortcutWorkDir,
shortcutIconPath,
&shortcutIcon,
&shortcutHotKey,
&dosApp,
&msDosMode,
&shortcutShowMode,
&ExtraData,
FileName,
ShellLink,
PersistFile
)) {
__leave;
}
if (msDosMode) {
//
// we want to modify this PIF file so it doesn't have MSDOS mode set
// we will only add it to the modify list. The NT side will know what
// to do when a PIF is marked for beeing modify
//
toBeModified = TRUE;
}
if (IsFileMarkedForAnnounce (shortcutTarget)) {
announcement = GetFileAnnouncement (shortcutTarget);
if (g_ConfigOptions.ShowAllReport ||
((announcement != ACT_INC_IHVUTIL) &&
(announcement != ACT_INC_PREINSTUTIL) &&
(announcement != ACT_INC_SIMILAROSFUNC)
)
) {
HandleDeferredAnnounce (FileName, shortcutTarget, dosApp);
}
}
fileStatus = GetFileStatusOnNt (shortcutTarget);
if ((fileStatus & FILESTATUS_DELETED) == FILESTATUS_DELETED) {
if (IsFileMarkedForAnnounce (shortcutTarget)) {
if (!pIsFileInStartup (FileName)) {
if (!g_ConfigOptions.KeepBadLinks) {
RemoveLinkFromSystem (FileName);
} else {
// we only care about LNK files
if (StringIMatch (GetFileExtensionFromPath (FileName), TEXT("LNK"))) {
// let's see what kind of announcement we have here.
// We want to leave the LNK as is if the app was announced
// using MigDb. However, if the app was announced using
// dynamic checking (module checking) then we want to point
// this shortcut to our stub EXE
announcement = GetFileAnnouncement (shortcutTarget);
if ((announcement == ACT_INC_NOBADAPPS) ||
(announcement == ACT_REINSTALL) ||
(announcement == ACT_REINSTALL_BLOCK) ||
(announcement == ACT_INC_IHVUTIL) ||
(announcement == ACT_INC_PREINSTUTIL) ||
(announcement == ACT_INC_SIMILAROSFUNC)
) {
//
// This is the case when we want to redirect this LNK to point
// to our lnk stub. Extract will fail if the icon is known-good.
// In that case, keep using the target icon.
//
if (ExtractIconIntoDatFile (
(*shortcutIconPath)?shortcutIconPath:shortcutTarget,
shortcutIcon,
&g_IconContext,
&newShortcutIcon
)) {
shortcutNewIconPath = JoinPaths (g_System32Dir, TEXT("migicons.exe"));
shortcutIcon = newShortcutIcon;
} else {
shortcutNewIconPath = GetPathStringOnNt (
(*shortcutIconPath) ?
shortcutIconPath : shortcutTarget
);
}
availability = g_ConfigOptions.ShowAllReport ||
((announcement != ACT_INC_IHVUTIL) &&
(announcement != ACT_INC_PREINSTUTIL) &&
(announcement != ACT_INC_SIMILAROSFUNC)
);
lnkIdx = pAddLinkStubToMemDb (
FileName,
shortcutTarget,
shortcutArgs,
shortcutWorkDir,
shortcutNewIconPath,
shortcutIcon + 1, // Add 1 because lnkstub.exe is one-based, but we are zero based
shortcutShowMode,
announcement,
availability
);
wsprintf (lnkIdxStr, TEXT("%d"), lnkIdx);
shortcutNewTarget = JoinPaths (g_System32Dir, S_LNKSTUB_EXE);
shortcutNewArgs = DuplicatePathString (lnkIdxStr, 0);
pAddLinkEditToMemDb (
FileName,
shortcutNewTarget,
shortcutNewArgs,
shortcutNewWorkDir,
shortcutNewIconPath,
shortcutIcon, // don't add one -- shortcuts are zero based
NULL,
TRUE
);
}
} else {
RemoveLinkFromSystem (FileName);
}
}
} else {
//
// This is a startup item
//
RemoveLinkFromSystem (FileName);
}
} else {
RemoveLinkFromSystem (FileName);
}
__leave;
}
if ((fileStatus & FILESTATUS_REPLACED) != FILESTATUS_REPLACED) {
//
// this target is not replaced by a migration DLL or by NT. We need
// to know if this is a "known good" target. If not, we will announce
// this link as beeing "unknown"
//
if (!IsFileMarkedAsKnownGood (shortcutTarget)) {
fullPath = JoinPaths (shortcutWorkDir, shortcutTarget);
if (!IsFileMarkedAsKnownGood (fullPath)) {
extPtr = GetFileExtensionFromPath (shortcutTarget);
if (extPtr) {
if (StringIMatch (extPtr, TEXT("EXE"))) {
//
// This one statement controls our
// "unknown" category. We have the
// ability to list the things we don't
// recognize.
//
// It is currently "off".
//
//HandleDeferredAnnounce (FileName, shortcutTarget, dosApp);
}
}
}
FreePathString (fullPath);
}
}
//
// If this LNK points to a target that will change, back up the
// original LNK, because we might change it.
//
if (fileStatus & ALL_CHANGE_OPERATIONS) {
MarkFileForBackup (FileName);
}
//
// If target points to an OLE object, remove any links to incompatible OLE objects
//
pSendCmdLineGuidsToMemdb (FileName, shortcutTarget, shortcutArgs);
//all we try to do now is to see if this lnk or pif file is going to be edited
//on NT side. That is if target or icon should change.
shortcutNewTarget = GetPathStringOnNt (shortcutTarget);
if (!StringIMatch (shortcutNewTarget, shortcutTarget)) {
toBeModified = TRUE;
//
// special case for COMMAND.COM
//
if (shortcutArgs [0] == 0) {
commandPath = JoinPaths (g_System32Dir, S_COMMAND_COM);
if (StringIMatch (commandPath, shortcutNewTarget)) {
if (msDosMode) {
//
// remove MS-DOS mode PIF files that point to command.com
//
RemoveLinkFromSystem (FileName);
//
// If msdosmode was on, we need to determine how we are going to handle
// boot16. We will turn on boot16 mode if:
// (a) The .pif points to something besides command.com
// (b) The .pif is in a shell folder.
//
// Note that the check for b simply entails seeing if the PIF file has
// OPERATION_FILE_MOVE_SHELL_FOLDER associated with it.
//
//
if (msDosMode && *g_Boot16 == BOOT16_AUTOMATIC) {
if (!StringIMatch(GetFileNameFromPath (shortcutNewTarget?shortcutNewTarget:shortcutTarget), S_COMMAND_COM) ||
IsFileMarkedForOperation (FileName, OPERATION_FILE_MOVE_SHELL_FOLDER)) {
*g_Boot16 = BOOT16_YES;
}
}
__leave;
} else {
ConvertedLnk = TRUE;
FreePathString (shortcutNewTarget);
shortcutNewTarget = JoinPaths (g_System32Dir, S_CMD_EXE);
}
}
FreePathString (commandPath);
shortcutNewArgs = NULL;
}
else {
shortcutNewArgs = DuplicatePathString (shortcutArgs, 0);
}
}
else {
FreePathString (shortcutNewTarget);
shortcutNewTarget = NULL;
}
//
// If msdosmode was on, we need to determine how we are going to handle
// boot16. We will turn on boot16 mode if:
// (a) The .pif points to something besides command.com
// (b) The .pif is in a shell folder.
//
// Note that the check for b simply entails seeing if the PIF file has
// OPERATION_FILE_MOVE_SHELL_FOLDER associated with it.
//
//
if (msDosMode && *g_Boot16 == BOOT16_AUTOMATIC) {
if (!StringIMatch(GetFileNameFromPath (shortcutNewTarget?shortcutNewTarget:shortcutTarget), S_COMMAND_COM) ||
IsFileMarkedForOperation (FileName, OPERATION_FILE_MOVE_SHELL_FOLDER)) {
*g_Boot16 = BOOT16_YES;
}
}
//
// If the link points to a directory, see that the directory survives on NT.
// Potentially this directory can be cleaned up if it's in a shell folder and
// becomes empty after our ObsoleteLinks check
//
attrib = QuietGetFileAttributes (shortcutTarget);
if ((attrib != INVALID_ATTRIBUTES) &&
(attrib & FILE_ATTRIBUTE_DIRECTORY)
){
MarkDirectoryAsPreserved (shortcutNewTarget?shortcutNewTarget:shortcutTarget);
}
//OK, so much with target, let's see what's with the work dir
shortcutNewWorkDir = GetPathStringOnNt (shortcutWorkDir);
if (!StringIMatch (shortcutNewWorkDir, shortcutWorkDir)) {
toBeModified = TRUE;
}
else {
FreePathString (shortcutNewWorkDir);
shortcutNewWorkDir = NULL;
}
//
// If the working dir for this link is a directory, see that the directory survives on NT.
// Potentially this directory can be cleaned up if it's in a shell folder and
// becomes empty after our ObsoleteLinks check
//
attrib = QuietGetFileAttributes (shortcutWorkDir);
if ((attrib != INVALID_ATTRIBUTES) &&
(attrib & FILE_ATTRIBUTE_DIRECTORY)
){
MarkDirectoryAsPreserved (shortcutNewWorkDir?shortcutNewWorkDir:shortcutWorkDir);
}
//OK, so much with workdir, let's see what's with icon
fileStatus = GetFileStatusOnNt (shortcutIconPath);
if ((fileStatus & FILESTATUS_DELETED) ||
((fileStatus & FILESTATUS_REPLACED) && (fileStatus & FILESTATUS_NTINSTALLED)) ||
(IsFileMarkedForOperation (shortcutIconPath, OPERATION_FILE_MOVE_SHELL_FOLDER))
) {
//
// Our icon will go away, because our file is getting deleted or
// replaced. Let's try to preserve it. Extract will fail only if
// the icon is known-good.
//
if (ExtractIconIntoDatFile (
shortcutIconPath,
shortcutIcon,
&g_IconContext,
&newShortcutIcon
)) {
shortcutNewIconPath = JoinPaths (g_System32Dir, TEXT("migicons.exe"));
shortcutIcon = newShortcutIcon;
toBeModified = TRUE;
}
}
if (!shortcutNewIconPath) {
shortcutNewIconPath = GetPathStringOnNt (shortcutIconPath);
if (!StringIMatch (shortcutNewIconPath, shortcutIconPath)) {
toBeModified = TRUE;
}
else {
FreePathString (shortcutNewIconPath);
shortcutNewIconPath = NULL;
}
}
if (toBeModified) {
if (ConvertedLnk) {
//
// Set this for modifying PIF to LNK
//
pAddLinkEditToMemDb (
FileName,
shortcutNewTarget?shortcutNewTarget:shortcutTarget,
shortcutNewArgs?shortcutNewArgs:shortcutArgs,
shortcutNewWorkDir?shortcutNewWorkDir:shortcutWorkDir,
shortcutNewIconPath?shortcutNewIconPath:shortcutIconPath,
shortcutIcon,
&ExtraData,
FALSE
);
} else {
pAddLinkEditToMemDb (
FileName,
shortcutNewTarget,
shortcutNewArgs,
shortcutNewWorkDir,
shortcutNewIconPath,
shortcutIcon,
NULL,
FALSE
);
}
}
}
__finally {
if (shortcutNewWorkDir != NULL) {
FreePathString (shortcutNewWorkDir);
}
if (shortcutNewIconPath != NULL) {
FreePathString (shortcutNewIconPath);
}
if (shortcutNewArgs != NULL) {
FreePathString (shortcutNewArgs);
}
if (shortcutNewTarget != NULL) {
FreePathString (shortcutNewTarget);
}
}
return TRUE;
}
PCTSTR
pBuildNewCategory (
IN PCTSTR LinkName,
IN PCTSTR Category,
IN UINT Levels
)
{
PCTSTR *levPtrs = NULL;
PCTSTR wackPtr = NULL;
PCTSTR result = NULL;
PCTSTR resultTmp = NULL;
UINT index = 0;
UINT indexLnk = 0;
MYASSERT (Levels);
levPtrs = (PCTSTR *) PoolMemGetMemory (g_LinksPool, (Levels + 1) * sizeof (PCTSTR));
wackPtr = LinkName;
while (wackPtr) {
levPtrs[index] = wackPtr;
wackPtr = _tcschr (wackPtr, TEXT('\\'));
if (wackPtr) {
wackPtr = _tcsinc (wackPtr);
index ++;
if (index > Levels) {
index = 0;
}
}
}
indexLnk = index;
if (index == Levels) {
index = 0;
} else {
index ++;
}
resultTmp = StringSearchAndReplace (levPtrs [index], levPtrs [indexLnk], Category);
if (resultTmp) {
result = StringSearchAndReplace (resultTmp, TEXT("\\"), TEXT("->"));
} else {
result = NULL;
}
FreePathString (resultTmp);
PoolMemReleaseMemory (g_LinksPool, (PVOID) levPtrs);
return result;
}
VOID
pGatherInfoFromDefaultPif (
VOID
)
{
PCTSTR defaultPifPath = NULL;
TCHAR tmpStr [20];
TCHAR pifTarget [MEMDB_MAX];
TCHAR pifArgs [MEMDB_MAX];
TCHAR pifWorkDir [MEMDB_MAX];
TCHAR pifIconPath [MEMDB_MAX];
INT pifIcon;
BOOL pifMsDosMode;
LNK_EXTRA_DATA pifExtraData;
defaultPifPath = JoinPaths (g_WinDir, S_COMMAND_PIF);
if (ExtractPifInfo (
pifTarget,
pifArgs,
pifWorkDir,
pifIconPath,
&pifIcon,
&pifMsDosMode,
&pifExtraData,
defaultPifPath
)) {
_itoa (pifExtraData.FullScreen, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FULLSCREEN, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.xSize, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_XSIZE, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.ySize, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_YSIZE, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.QuickEdit, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_QUICKEDIT, tmpStr, NULL, 0, NULL);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTNAME, pifExtraData.FontName, NULL, 0, NULL);
_itoa (pifExtraData.xFontSize, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_XFONTSIZE, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.yFontSize, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_YFONTSIZE, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.FontWeight, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTWEIGHT, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.FontFamily, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTFAMILY, tmpStr, NULL, 0, NULL);
_itoa (pifExtraData.CurrentCodePage, tmpStr, 10);
MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_CODEPAGE, tmpStr, NULL, 0, NULL);
}
FreePathString (defaultPifPath);
}
BOOL
pProcessLinks (
VOID
)
{
MEMDB_ENUM enumItems;
MEMDB_ENUM enumDups;
TCHAR pattern[MEMDB_MAX];
IShellLink *shellLink;
IPersistFile *persistFile;
PLINK_STRUCT linkStruct, linkDup;
BOOL resolved;
PCTSTR newCategory = NULL;
PCTSTR dupCategory = NULL;
UINT levels = 0;
DWORD count = 0;
MYASSERT (g_LinksPool);
if (InitCOMLink (&shellLink, &persistFile)) {
wsprintf (pattern, TEXT("%s\\*"), MEMDB_CATEGORY_SHORTCUTS);
if (MemDbEnumFirstValue (
&enumItems,
pattern,
MEMDB_ALL_SUBLEVELS,
MEMDB_ENDPOINTS_ONLY
)) {
do {
if (!SafeModeActionCrashed (SAFEMODEID_LNK9X, enumItems.szName)) {
SafeModeRegisterAction(SAFEMODEID_LNK9X, enumItems.szName);
if (!pProcessShortcut (enumItems.szName, shellLink, persistFile)) {
LOG((LOG_ERROR, "Error processing shortcut %s", enumItems.szName));
}
count++;
if (!(count % 4)) {
TickProgressBar ();
}
SafeModeUnregisterAction();
}
}
while (MemDbEnumNextValue (&enumItems));
}
FreeCOMLink (&shellLink, &persistFile);
}
if (MemDbEnumFirstValue (&enumItems, MEMDB_CATEGORY_REPORT_LINKS"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
do {
newCategory = NULL;
levels = 0;
linkStruct = (PLINK_STRUCT)enumItems.dwValue;
if (linkStruct->LinkName) {
resolved = !(StringIMatch (linkStruct->LinkNameNoPath, GetFileNameFromPath (linkStruct->LinkName)));
}
else {
resolved = TRUE;
}
while (!resolved) {
resolved = TRUE;
MemDbBuildKey (
pattern,
MEMDB_CATEGORY_REPORT_LINKS,
TEXT("*"),
linkStruct->LinkNameNoPath,
TEXT("*")
);
if (MemDbEnumFirstValue (&enumDups, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
do {
linkDup = (PLINK_STRUCT)enumDups.dwValue;
if ((enumItems.Offset != enumDups.Offset) &&
(enumItems.UserFlags == enumDups.UserFlags) &&
(StringIMatch (linkStruct->Category, linkDup->Category))
) {
if (newCategory) {
dupCategory = pBuildNewCategory (linkDup->LinkName, linkDup->Category, levels);
if (!dupCategory) {
MYASSERT (FALSE);
continue;
}
if (!StringIMatch (dupCategory, newCategory)) {
FreePathString (dupCategory);
continue;
}
FreePathString (newCategory);
}
levels++;
newCategory = pBuildNewCategory (linkStruct->LinkName, linkStruct->Category, levels);
resolved = FALSE;
break;
}
} while (MemDbEnumNextValue (&enumDups));
}
}
pReportEntry (
linkStruct->ReportEntry,
newCategory?newCategory:linkStruct->Category,
linkStruct->MigDbContext?linkStruct->MigDbContext->Message:NULL,
linkStruct->Context,
linkStruct->Object
);
if (newCategory) {
newCategory = NULL;
}
} while (MemDbEnumNextValue (&enumItems));
}
TickProgressBar ();
// gather default command prompt attributes
pGatherInfoFromDefaultPif ();
DoneLinkAnnounce ();
//
// Delete MemDb tree used for this phase
//
MemDbDeleteTree (MEMDB_CATEGORY_REPORT_LINKS);
return TRUE;
}
DWORD
ProcessLinks (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_PROCESS_LINKS;
case REQUEST_RUN:
if (!pProcessLinks ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessLinks"));
}
return 0;
}
BOOL
pProcessCPLs (
VOID
)
{
CHAR pattern[MEMDB_MAX];
MEMDB_ENUM enumItems;
DWORD announcement;
PMIGDB_CONTEXT context;
MemDbBuildKey (pattern, MEMDB_CATEGORY_CPLS, TEXT("*"), NULL, NULL);
if (MemDbEnumFirstValue (&enumItems, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
do {
if ((IsFileMarkedForAnnounce (enumItems.szName)) &&
(IsDisplayableCPL (enumItems.szName))
) {
announcement = GetFileAnnouncement (enumItems.szName);
context = (PMIGDB_CONTEXT) GetFileAnnouncementContext (enumItems.szName);
ReportControlPanelApplet (
enumItems.szName,
context,
announcement
);
}
}
while (MemDbEnumNextValue (&enumItems));
}
return TRUE;
}
DWORD
ProcessCPLs (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_PROCESS_CPLS;
case REQUEST_RUN:
if (!pProcessCPLs ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessCPLs"));
}
return 0;
}