1564 lines
49 KiB
C
1564 lines
49 KiB
C
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|