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.
 
 
 
 
 
 

939 lines
24 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
linkpif.c
Abstract:
Functions to query and modify LNK and PIF files.
Author:
Calin Negreanu (calinn) 07-Sep-1998
Revision History:
--*/
#include "pch.h"
#include <pif.h> // private\windows\inc
BOOL
InitCOMLinkA (
OUT IShellLinkA **ShellLink,
OUT IPersistFile **PersistFile
)
{
HRESULT hres;
BOOL result;
//
// Initialize COM
//
hres = CoInitialize (NULL);
if (!SUCCEEDED (hres)) {
return FALSE;
}
*ShellLink = NULL;
*PersistFile = NULL;
result = FALSE;
__try {
//
// Get a pointer to the IShellLink interface.
//
hres = CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkA, ShellLink);
if (!SUCCEEDED (hres)) {
__leave;
}
//
// Get a pointer to the IPersistFile interface.
//
hres = (*ShellLink)->lpVtbl->QueryInterface ((*ShellLink), &IID_IPersistFile, PersistFile);
if (!SUCCEEDED (hres)) {
__leave;
}
result = TRUE;
}
__finally {
if (!result) {
if (*PersistFile) {
(*PersistFile)->lpVtbl->Release (*PersistFile);
*PersistFile = NULL;
}
if (*ShellLink) {
(*ShellLink)->lpVtbl->Release (*ShellLink);
*ShellLink = NULL;
}
}
}
if (!result) {
//
// Free COM
//
CoUninitialize ();
}
return result;
}
BOOL
InitCOMLinkW (
OUT IShellLinkW **ShellLink,
OUT IPersistFile **PersistFile
)
{
HRESULT hres;
BOOL result;
//
// Initialize COM
//
hres = CoInitialize (NULL);
if (!SUCCEEDED (hres)) {
return FALSE;
}
*ShellLink = NULL;
*PersistFile = NULL;
result = FALSE;
__try {
//
// Get a pointer to the IShellLink interface.
//
hres = CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, ShellLink);
if (!SUCCEEDED (hres)) {
__leave;
}
//
// Get a pointer to the IPersistFile interface.
//
hres = (*ShellLink)->lpVtbl->QueryInterface ((*ShellLink), &IID_IPersistFile, PersistFile);
if (!SUCCEEDED (hres)) {
__leave;
}
result = TRUE;
}
__finally {
if (!result) {
if (*PersistFile) {
(*PersistFile)->lpVtbl->Release (*PersistFile);
*PersistFile = NULL;
}
if (*ShellLink) {
(*ShellLink)->lpVtbl->Release (*ShellLink);
*ShellLink = NULL;
}
}
}
if (!result) {
//
// Free COM
//
CoUninitialize ();
}
return result;
}
BOOL
FreeCOMLinkA (
IN OUT IShellLinkA **ShellLink,
IN OUT IPersistFile **PersistFile
)
{
if (*PersistFile) {
(*PersistFile)->lpVtbl->Release (*PersistFile);
*PersistFile = NULL;
}
if (*ShellLink) {
(*ShellLink)->lpVtbl->Release (*ShellLink);
*ShellLink = NULL;
}
//
// Free COM
//
CoUninitialize ();
return TRUE;
}
BOOL
FreeCOMLinkW (
IN OUT IShellLinkW **ShellLink,
IN OUT IPersistFile **PersistFile
)
{
if (*PersistFile) {
(*PersistFile)->lpVtbl->Release (*PersistFile);
*PersistFile = NULL;
}
if (*ShellLink) {
(*ShellLink)->lpVtbl->Release (*ShellLink);
*ShellLink = NULL;
}
//
// Free COM
//
CoUninitialize ();
return TRUE;
}
PVOID
FindEnhPifSignature (
IN PVOID FileImage,
IN PCSTR Signature
)
/*++
Routine Description:
FindEnhPifSignature finds a certain PIF structure inside a PIF file (if it exists)
based on a signature.
Arguments:
FileImage - image of the PIF file mapped into memory
Signature - structure signature
Return Value:
address of the PIF structure, or NULL if non existent
--*/
{
PBYTE tempPtr;
PBYTE lastPtr;
PVOID result = NULL;
BOOL finished = FALSE;
PPIFEXTHDR pifExtHdr;
lastPtr = (PBYTE) FileImage;
tempPtr = (PBYTE) FileImage;
tempPtr += sizeof (STDPIF);
pifExtHdr = (PPIFEXTHDR) tempPtr;
__try {
do {
if (tempPtr < lastPtr) {
result = NULL;
break;
} else {
lastPtr = tempPtr;
}
finished = pifExtHdr->extnxthdrfloff == LASTHDRPTR;
if (StringMatchA (pifExtHdr->extsig, Signature)) {
result = tempPtr + sizeof (PIFEXTHDR);
break;
}
else {
tempPtr = (PBYTE)FileImage + pifExtHdr->extnxthdrfloff;
pifExtHdr = (PPIFEXTHDR) tempPtr;
}
} while (!finished);
}
__except (1) {
// something went wrong trying to access PIF file. Let's exit with NULL
return NULL;
}
return result;
}
BOOL
ExtractPifInfoA(
OUT PSTR Target,
OUT PSTR Params,
OUT PSTR WorkDir,
OUT PSTR IconPath,
OUT PINT IconNumber,
OUT BOOL *MsDosMode,
OUT PLNK_EXTRA_DATAA ExtraData, OPTIONAL
IN PCSTR FileName
)
{
PVOID fileImage = NULL;
HANDLE mapHandle = NULL;
HANDLE fileHandle = INVALID_HANDLE_VALUE;
CHAR tempStr [MEMDB_MAX];
PSTR strPtr;
PSTR dontCare;
PSTDPIF stdPif;
PWENHPIF40 wenhPif40;
PW386PIF30 w386ext30;
BOOL result = TRUE;
*Target = *Params = *WorkDir = *IconPath = 0;
*IconNumber = 0;
*MsDosMode = FALSE;
if (ExtraData) {
ZeroMemory (ExtraData, sizeof(LNK_EXTRA_DATA));
}
__try {
fileImage = MapFileIntoMemoryA (FileName, &fileHandle, &mapHandle);
if (fileImage == NULL) {
__leave;
}
__try {
stdPif = (PSTDPIF) fileImage;
//
// getting working directory
//
_mbsncpy (tempStr, stdPif->defpath, PIFDEFPATHSIZE);
// we might have a path terminated with a wack, we don't want that
strPtr = _mbsdec (tempStr, GetEndOfStringA (tempStr));
if (strPtr) {
if (_mbsnextc (strPtr) == '\\') {
*strPtr = 0;
}
}
// now get the long path.
CopyFileSpecToLongA (tempStr, WorkDir);
//
// getting PIFs target
//
_mbsncpy (Target, stdPif->startfile, PIFSTARTLOCSIZE);
// in most cases, the target is without a path. We try to build the path, either
// by using WorkDir or by calling SearchPath to look for this file.
if (*Target) {//non empty target
if (!DoesFileExist (Target)) {
if (*WorkDir) {
StringCopyA (tempStr, WorkDir);
StringCatA (tempStr, "\\");
StringCatA (tempStr, Target);
}
if (!DoesFileExist (tempStr)) {
StringCopyA (tempStr, FileName);
strPtr = _mbsrchr (tempStr, '\\');
if (strPtr) {
strPtr = _mbsinc (strPtr);
if (strPtr) {
StringCopyA (strPtr, Target);
}
}
}
if (!DoesFileExist (tempStr)) {
strPtr = (PSTR)GetFileNameFromPathA (Target);
if (!strPtr) {
strPtr = Target;
}
if (!SearchPathA (NULL, Target, NULL, MEMDB_MAX, tempStr, &dontCare)) {
DEBUGMSG ((DBG_WARNING, "Could not find path for PIF target: %s", FileName));
StringCopyA (tempStr, Target);
}
}
} else {
StringCopyA (tempStr, Target);
}
// now get the long path
CopyFileSpecToLongA (tempStr, Target);
}
//
// getting PIFs arguments
//
_mbsncpy (Params, stdPif->params, PIFPARAMSSIZE);
//
// let's try to read the WENHPIF40 structure
//
wenhPif40 = FindEnhPifSignature (fileImage, WENHHDRSIG40);
if (wenhPif40) {
CopyFileSpecToLongA (wenhPif40->achIconFileProp, IconPath);
*IconNumber = wenhPif40->wIconIndexProp;
if (ExtraData) {
ExtraData->xSize = 80;
ExtraData->ySize = wenhPif40->vidProp.cScreenLines;
if (ExtraData->ySize < 25) {
ExtraData->ySize = 25;
}
ExtraData->QuickEdit = !(wenhPif40->mseProp.flMse & MSE_WINDOWENABLE);
ExtraData->CurrentCodePage = wenhPif40->fntProp.wCurrentCP;
// now let's do some crazy things trying to get the font used
{
LOGFONTA logFont;
HDC dc;
HFONT font;
HGDIOBJ oldObject;
TEXTMETRIC tm;
ZeroMemory (&logFont, sizeof (LOGFONTA));
logFont.lfHeight = wenhPif40->fntProp.cyFontActual;
logFont.lfWidth = wenhPif40->fntProp.cxFontActual;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_DONTCARE;
logFont.lfItalic = FALSE;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = DEFAULT_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
if (wenhPif40->fntProp.flFnt & FNT_TT) {
_mbsncpy (logFont.lfFaceName, wenhPif40->fntProp.achTTFaceName, LF_FACESIZE);
_mbsncpy (ExtraData->FontName, wenhPif40->fntProp.achTTFaceName, LF_FACESIZE);
} else {
_mbsncpy (logFont.lfFaceName, wenhPif40->fntProp.achRasterFaceName, LF_FACESIZE);
_mbsncpy (ExtraData->FontName, wenhPif40->fntProp.achRasterFaceName, LF_FACESIZE);
}
dc = CreateDCA ("DISPLAY", NULL, NULL, NULL);
if (dc) {
font = CreateFontIndirectA (&logFont);
if (font) {
oldObject = SelectObject (dc, font);
if (GetTextMetrics (dc, &tm)) {
ExtraData->xFontSize = tm.tmAveCharWidth;
ExtraData->yFontSize = tm.tmHeight;
ExtraData->FontWeight = tm.tmWeight;
ExtraData->FontFamily = tm.tmPitchAndFamily;
}
SelectObject (dc, oldObject);
DeleteObject (font);
}
DeleteDC (dc);
}
}
}
}
w386ext30 = FindEnhPifSignature (fileImage, W386HDRSIG30);
if (w386ext30) {
if (((w386ext30->PfW386Flags & fRealMode ) == fRealMode ) ||
((w386ext30->PfW386Flags & fRealModeSilent) == fRealModeSilent)
) {
*MsDosMode = TRUE;
}
if (ExtraData) {
ExtraData->FullScreen = (w386ext30->PfW386Flags & fFullScreen) != 0;
}
}
}
__except (1) {
// something went wrong when we tried to read or write PIF file,
result = FALSE;
}
}
__finally {
UnmapFile (fileImage, mapHandle, fileHandle);
}
return result;
}
BOOL
ExtractPifInfoW(
OUT PWSTR Target,
OUT PWSTR Params,
OUT PWSTR WorkDir,
OUT PWSTR IconPath,
OUT PINT IconNumber,
OUT BOOL *MsDosMode,
OUT PLNK_EXTRA_DATAW ExtraData, OPTIONAL
IN PCWSTR FileName
)
{
CHAR aTarget [MEMDB_MAX];
CHAR aParams [MEMDB_MAX];
CHAR aWorkDir [MEMDB_MAX];
CHAR aIconPath [MEMDB_MAX];
PCSTR aFileName;
PCWSTR tempStrW;
BOOL result;
LNK_EXTRA_DATAA extraDataA;
aFileName = ConvertWtoA (FileName);
result = ExtractPifInfoA (
aTarget,
aParams,
aWorkDir,
aIconPath,
IconNumber,
MsDosMode,
ExtraData?&extraDataA:NULL,
aFileName
);
FreeConvertedStr (aFileName);
tempStrW = ConvertAtoW (aTarget);
StringCopyW (Target, tempStrW);
FreeConvertedStr (tempStrW);
tempStrW = ConvertAtoW (aParams);
StringCopyW (Params, tempStrW);
FreeConvertedStr (tempStrW);
tempStrW = ConvertAtoW (aWorkDir);
StringCopyW (WorkDir, tempStrW);
FreeConvertedStr (tempStrW);
tempStrW = ConvertAtoW (aIconPath);
StringCopyW (IconPath, tempStrW);
FreeConvertedStr (tempStrW);
if (ExtraData) {
ExtraData->FullScreen = extraDataA.FullScreen;
ExtraData->xSize = extraDataA.xSize;
ExtraData->ySize = extraDataA.ySize;
ExtraData->QuickEdit = extraDataA.QuickEdit;
tempStrW = ConvertAtoW (extraDataA.FontName);
StringCopyW (ExtraData->FontName, tempStrW);
FreeConvertedStr (tempStrW);
ExtraData->xFontSize = extraDataA.xFontSize;
ExtraData->yFontSize = extraDataA.yFontSize;
ExtraData->FontWeight = extraDataA.FontWeight;
ExtraData->FontFamily = extraDataA.FontFamily;
ExtraData->CurrentCodePage = extraDataA.CurrentCodePage;
}
return result;
}
BOOL
ExtractShellLinkInfoA (
OUT PSTR Target,
OUT PSTR Params,
OUT PSTR WorkDir,
OUT PSTR IconPath,
OUT PINT IconNumber,
OUT PWORD HotKey,
OUT PINT ShowMode, OPTIONAL
IN PCSTR FileName,
IN IShellLinkA *ShellLink,
IN IPersistFile *PersistFile
)
{
CHAR tempStr [MEMDB_MAX];
PCSTR expandedStr;
PCWSTR fileNameW;
PSTR strPtr;
HRESULT hres;
WIN32_FIND_DATAA fd;
fileNameW = ConvertAtoW (FileName);
hres = PersistFile->lpVtbl->Load(PersistFile, fileNameW, STGM_READ);
FreeConvertedStr (fileNameW);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot load link %s", FileName));
return FALSE;
}
//
// Get the link target
//
hres = ShellLink->lpVtbl->GetPath (
ShellLink,
tempStr,
sizeof (tempStr),
&fd,
SLGP_RAWPATH
);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read target for link %s", FileName));
return FALSE;
}
expandedStr = ExpandEnvironmentTextA (tempStr);
CopyFileSpecToLongA (expandedStr, Target);
FreeTextA (expandedStr);
//
// Get the link working directory
//
hres = ShellLink->lpVtbl->GetWorkingDirectory (
ShellLink,
tempStr,
sizeof (tempStr)
);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read target for link %s", FileName));
return FALSE;
}
strPtr = GetEndOfStringA (tempStr);
if (strPtr) {
strPtr = _mbsdec (tempStr, strPtr);
if (strPtr) {
if (_mbsnextc (strPtr) == '\\') {
*strPtr = 0;
}
}
}
CopyFileSpecToLongA (tempStr, WorkDir);
//
// Get the arguments.
//
hres = ShellLink->lpVtbl->GetArguments (
ShellLink,
Params,
MEMDB_MAX
);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read arguments for link %s", FileName));
return FALSE;
}
//
// Get icon path
//
hres = ShellLink->lpVtbl->GetIconLocation (
ShellLink,
tempStr,
sizeof (tempStr),
IconNumber
);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read icon path for link %s", FileName));
return FALSE;
}
CopyFileSpecToLongA (tempStr, IconPath);
//
// Get hot key
//
hres = ShellLink->lpVtbl->GetHotkey (ShellLink, HotKey);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read hot key for link %s", FileName));
return FALSE;
}
//
// Get show command
//
if (ShowMode) {
hres = ShellLink->lpVtbl->GetShowCmd (ShellLink, ShowMode);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read show mode for link %s", FileName));
return FALSE;
}
}
return TRUE;
}
BOOL
ExtractShellLinkInfoW (
OUT PWSTR Target,
OUT PWSTR Params,
OUT PWSTR WorkDir,
OUT PWSTR IconPath,
OUT PINT IconNumber,
OUT PWORD HotKey,
OUT PINT ShowMode,
IN PCWSTR FileName,
IN IShellLinkW *ShellLink,
IN IPersistFile *PersistFile
)
{
WCHAR tempStr [MEMDB_MAX];
PCWSTR expandedStr;
PWSTR strPtr;
HRESULT hres;
WIN32_FIND_DATAW fd;
hres = PersistFile->lpVtbl->Load(PersistFile, FileName, STGM_READ);
if (!SUCCEEDED(hres)) {
DEBUGMSGW((DBG_WARNING, "Cannot load link %s", FileName));
return FALSE;
}
//
// Get the link target
//
hres = ShellLink->lpVtbl->GetPath (
ShellLink,
tempStr,
sizeof (tempStr),
&fd,
SLGP_RAWPATH
);
if (!SUCCEEDED(hres)) {
DEBUGMSGA((DBG_WARNING, "Cannot read target for link %s", FileName));
return FALSE;
}
expandedStr = ExpandEnvironmentTextW (tempStr);
CopyFileSpecToLongW (expandedStr, Target);
FreeTextW (expandedStr);
//
// Get the link working directory
//
hres = ShellLink->lpVtbl->GetWorkingDirectory (
ShellLink,
tempStr,
sizeof (tempStr)
);
if (!SUCCEEDED(hres)) {
DEBUGMSGW((DBG_WARNING, "Cannot read target for link %s", FileName));
return FALSE;
}
strPtr = GetEndOfStringW (tempStr) - 1;
if (strPtr >= tempStr) {
if (*strPtr == '\\') {
*strPtr = 0;
}
}
CopyFileSpecToLongW (tempStr, WorkDir);
//
// Get the arguments.
//
hres = ShellLink->lpVtbl->GetArguments (
ShellLink,
Params,
MEMDB_MAX
);
if (!SUCCEEDED(hres)) {
DEBUGMSGW((DBG_WARNING, "Cannot read arguments for link %s", FileName));
return FALSE;
}
//
// Get icon path
//
hres = ShellLink->lpVtbl->GetIconLocation (
ShellLink,
tempStr,
sizeof (tempStr),
IconNumber
);
if (!SUCCEEDED(hres)) {
DEBUGMSGW((DBG_WARNING, "Cannot read icon path for link %s", FileName));
return FALSE;
}
CopyFileSpecToLongW (tempStr, IconPath);
//
// Get hot key
//
hres = ShellLink->lpVtbl->GetHotkey (ShellLink, HotKey);
if (!SUCCEEDED(hres)) {
DEBUGMSGW((DBG_WARNING, "Cannot read hot key for link %s", FileName));
return FALSE;
}
//
// Get show command
//
if (ShowMode) {
hres = ShellLink->lpVtbl->GetShowCmd (ShellLink, ShowMode);
if (!SUCCEEDED(hres)) {
DEBUGMSGW((DBG_WARNING, "Cannot read show mode for link %s", FileName));
return FALSE;
}
}
return TRUE;
}
BOOL
ExtractShortcutInfoA (
OUT PSTR Target,
OUT PSTR Params,
OUT PSTR WorkDir,
OUT PSTR IconPath,
OUT PINT IconNumber,
OUT PWORD HotKey,
OUT BOOL *DosApp,
OUT BOOL *MsDosMode,
OUT PINT ShowMode, OPTIONAL
OUT PLNK_EXTRA_DATAA ExtraData, OPTIONAL
IN PCSTR FileName,
IN IShellLinkA *ShellLink,
IN IPersistFile *PersistFile
)
{
PCSTR shortcutExt = NULL;
*MsDosMode = FALSE;
*DosApp = FALSE;
*HotKey = 0;
if (ShowMode) {
*ShowMode = SW_NORMAL;
}
shortcutExt = GetFileExtensionFromPathA (FileName);
if (shortcutExt != NULL) {
if (StringIMatchA (shortcutExt, "LNK")) {
return ExtractShellLinkInfoA (
Target,
Params,
WorkDir,
IconPath,
IconNumber,
HotKey,
ShowMode,
FileName,
ShellLink,
PersistFile
);
} else if (StringIMatchA (shortcutExt, "PIF")) {
*DosApp = TRUE;
return ExtractPifInfoA (
Target,
Params,
WorkDir,
IconPath,
IconNumber,
MsDosMode,
ExtraData,
FileName
);
} else {
return FALSE;
}
} else {
return FALSE;
}
}
BOOL
ExtractShortcutInfoW (
OUT PWSTR Target,
OUT PWSTR Params,
OUT PWSTR WorkDir,
OUT PWSTR IconPath,
OUT PINT IconNumber,
OUT PWORD HotKey,
OUT BOOL *DosApp,
OUT BOOL *MsDosMode,
OUT PINT ShowMode, OPTIONAL
OUT PLNK_EXTRA_DATAW ExtraData, OPTIONAL
IN PCWSTR FileName,
IN IShellLinkW *ShellLink,
IN IPersistFile *PersistFile
)
{
PCWSTR shortcutExt = NULL;
*MsDosMode = FALSE;
*DosApp = FALSE;
*HotKey = 0;
if (ShowMode) {
*ShowMode = SW_NORMAL;
}
shortcutExt = GetFileExtensionFromPathW (FileName);
if (shortcutExt != NULL) {
if (StringIMatchW (shortcutExt, L"LNK")) {
return ExtractShellLinkInfoW (
Target,
Params,
WorkDir,
IconPath,
IconNumber,
HotKey,
ShowMode,
FileName,
ShellLink,
PersistFile
);
} else if (StringIMatchW (shortcutExt, L"PIF")) {
*DosApp = TRUE;
return ExtractPifInfoW (
Target,
Params,
WorkDir,
IconPath,
IconNumber,
MsDosMode,
ExtraData,
FileName
);
} else {
return FALSE;
}
} else {
return FALSE;
}
}