/*++ 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 // 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; } }