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.
1204 lines
33 KiB
1204 lines
33 KiB
#include "..\pch\headers.hxx"
|
|
#pragma hdrstop
|
|
#include "myheaders.hxx"
|
|
#include <shlobjp.h> // IShellLinkDataList
|
|
#include <shlguidp.h> // IID_IShellLinkDataList
|
|
#include <msi.h> // MsiQueryProductState
|
|
|
|
#include <stdlib.h>
|
|
#include <process.h>
|
|
#include <winver.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <io.h>
|
|
#include "walklib.h"
|
|
#include "..\inc\misc.hxx"
|
|
|
|
|
|
typedef INSTALLSTATE (WINAPI* PFN_MsiQueryProductState) (LPCTSTR tszProduct);
|
|
|
|
BOOL
|
|
IsMsiApp(
|
|
IShellLink * psl
|
|
);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
HWALK GetFirstFileLnkInfo(LPLINKINFO lpLnkInfo, DWORD dwFlags,
|
|
LPTSTR lpszFolder, ERR *pErrRet)
|
|
{
|
|
BOOL bRC=TRUE;
|
|
ERR errVal;
|
|
LPWALKHEADER lpWalk;
|
|
LPTSTR lpszSubStr;
|
|
TCHAR szFullPath[MAX_PATH +1];
|
|
|
|
#ifdef _DEBUG
|
|
lpWalk = (LPWALKHEADER) MyGlobalAlloc(FAILMEMA, sizeof(WALKHEADER));
|
|
#else
|
|
lpWalk = (LPWALKHEADER) GlobalAlloc(GPTR, sizeof(WALKHEADER));
|
|
#endif
|
|
|
|
if (lpWalk == NULL)
|
|
{
|
|
*pErrRet = ERR_NOMEMORY ;//ERR_NOMEMORY -6;
|
|
return NULL; // Global Alloc failed
|
|
}
|
|
|
|
lpWalk->lpSrchDirListHead = NULL;
|
|
lpWalk->lpSrchDirListTail = NULL;
|
|
lpWalk->lpszIniString = NULL;
|
|
lpWalk->lpszNextFile = NULL;
|
|
lpWalk->dwCurrentFlag = RESET_FLAG;
|
|
lpWalk->dwWalkFlags = dwFlags;
|
|
if (lpWalk->dwWalkFlags & INPTYPE_ANYFOLDER)
|
|
{
|
|
if (IsBadStringPtr(lpszFolder, MAX_PATH))
|
|
lpWalk->lpszFolder = NULL;
|
|
else
|
|
lpWalk->lpszFolder = lpszFolder;
|
|
}
|
|
else
|
|
lpWalk->lpszFolder = NULL;
|
|
|
|
|
|
SetLnkInfo(lpLnkInfo);
|
|
errVal = GetFileHandle(lpLnkInfo, lpWalk, szFullPath, MAX_PATH +1);
|
|
if (errVal == 0)
|
|
{
|
|
*pErrRet = ERR_SUCCESS;//ERR_NOMOREFILES 0;
|
|
CloseWalk(lpWalk);
|
|
return NULL; /* No more files: Done */
|
|
}
|
|
else if (errVal < 0)
|
|
{
|
|
*pErrRet = errVal;
|
|
CloseWalk(lpWalk);
|
|
return NULL;
|
|
}
|
|
|
|
lpszSubStr = _tcsrchr(lpLnkInfo->szLnkName, TEXT('.'));
|
|
|
|
if (lpszSubStr)
|
|
{
|
|
if ((_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0) ||
|
|
(_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0))
|
|
{
|
|
if (!(errVal = GetLnkInfo(lpWalk, lpLnkInfo, szFullPath)))
|
|
{
|
|
lpszSubStr = _tcsrchr(lpLnkInfo->szExeName, TEXT('.'));
|
|
if (lpszSubStr)
|
|
{
|
|
if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
|
|
_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
|
|
{
|
|
*pErrRet = ERR_MOREFILESTOCOME;// ERR_SUCCESS but there are more files;
|
|
return lpWalk;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((errVal == ERR_NOTANEXE) || errVal > 0)
|
|
{
|
|
*pErrRet = GetNextFileLnkInfo(lpWalk, lpLnkInfo);
|
|
if ((*pErrRet != ERR_SUCCESS) && (*pErrRet != ERR_MOREFILESTOCOME))
|
|
{
|
|
CloseWalk(lpWalk);
|
|
return NULL;
|
|
}
|
|
else
|
|
return lpWalk;
|
|
}
|
|
else
|
|
{
|
|
*pErrRet = errVal;
|
|
CloseWalk(lpWalk);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
ERR GetNextFileLnkInfo(HWALK hWalk, LPLINKINFO lpLnkInfo)
|
|
{
|
|
BOOL bRC=TRUE;
|
|
INT retVal;
|
|
LPTSTR lpszSubStr;
|
|
TCHAR szFullPath[MAX_PATH +1];
|
|
|
|
LPWALKHEADER lpWalk = (LPWALKHEADER) hWalk;
|
|
|
|
while (1)
|
|
{
|
|
retVal = GetFileHandle(lpLnkInfo, lpWalk, szFullPath, MAX_PATH +1);
|
|
if (retVal < 0)
|
|
return retVal; /* Couldn't find next file */
|
|
else if (retVal == 0 ) /* Done : No more files */
|
|
return ERR_SUCCESS;
|
|
|
|
lpszSubStr = _tcsrchr(lpLnkInfo->szLnkName, TEXT('.'));
|
|
|
|
if (lpszSubStr)
|
|
{
|
|
if ((_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0) ||
|
|
(_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0))
|
|
{
|
|
if (!(retVal = GetLnkInfo(lpWalk, lpLnkInfo, szFullPath)))
|
|
{
|
|
lpszSubStr = _tcsrchr(lpLnkInfo->szExeName, TEXT('.'));
|
|
if (lpszSubStr)
|
|
{
|
|
if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
|
|
_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (retVal != ERR_NOTANEXE)
|
|
return retVal;
|
|
}
|
|
}
|
|
continue; /* Not a Link File */
|
|
}
|
|
return ERR_MOREFILESTOCOME;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
BOOL InSkipList(LPTSTR lpszFileName)
|
|
{
|
|
INT i;
|
|
LPTSTR lplpszToSkipFiles[] =
|
|
{
|
|
TEXT("write.exe"),
|
|
TEXT("winhelp.exe"),
|
|
TEXT("winhlp32.exe"),
|
|
TEXT("notepad.exe"),
|
|
TEXT("wordpad.exe"),
|
|
TEXT("rundll32.exe"),
|
|
TEXT("explorer.exe"),
|
|
TEXT("control.exe")
|
|
};
|
|
|
|
for (i = 0; i < ARRAYLEN(lplpszToSkipFiles); i++)
|
|
{
|
|
if (_tcsicmp(lpszFileName, lplpszToSkipFiles[i]) == 0)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
INT GetFileHandle(LPLINKINFO lpLnkInfo, LPWALKHEADER lpWalk, LPTSTR lpszPath, size_t pathBufSize)
|
|
{
|
|
DWORD dwAttrs;
|
|
BOOL bRC;
|
|
HANDLE hSearch;
|
|
INT retVal;
|
|
TCHAR szFolderPath[MAX_PATH +1];
|
|
WIN32_FIND_DATA wfdFileData;
|
|
|
|
DEBUG_ASSERT(lpWalk != NULL);
|
|
|
|
while (GetInputType(lpWalk) == FOLDER)
|
|
{
|
|
SetLnkInfo(lpLnkInfo);
|
|
if (lpWalk->lpSrchDirListHead == NULL)
|
|
{
|
|
if (retVal = GetFolder(szFolderPath, MAX_PATH +1, lpWalk))
|
|
return retVal;
|
|
|
|
if (!SetCurrentDirectory(szFolderPath))
|
|
{
|
|
lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
|
|
goto LoopBack;
|
|
// return ERR_SETCURRENTDIR;
|
|
}
|
|
|
|
hSearch = FindFirstFile(TEXT("*"), &wfdFileData);
|
|
if (hSearch == INVALID_HANDLE_VALUE)
|
|
{
|
|
lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
|
|
goto LoopBack;
|
|
}
|
|
else
|
|
{
|
|
retVal = AddToList(hSearch, lpWalk);
|
|
if (retVal == ERR_NOMEMORY)
|
|
return ERR_NOMEMORY; // GlobalAlloc failed
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (!(bRC = FindNextFile(lpWalk->lpSrchDirListTail->hDirHandle, &wfdFileData)))
|
|
{
|
|
if (GetLastError() == ERROR_NO_MORE_FILES)
|
|
{
|
|
FindClose(lpWalk->lpSrchDirListTail->hDirHandle);
|
|
RemoveFromList(lpWalk);
|
|
if (lpWalk->lpSrchDirListHead == NULL)
|
|
{
|
|
lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
|
|
goto LoopBack;
|
|
}
|
|
SetCurrentDirectory(TEXT(".."));
|
|
}
|
|
else
|
|
return ERR_UNKNOWN ; // should never come here
|
|
}
|
|
}
|
|
|
|
dwAttrs = GetFileAttributes(wfdFileData.cFileName);
|
|
while (dwAttrs & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
if (_tcsicmp(wfdFileData.cFileName, TEXT(".")) &&
|
|
_tcsicmp(wfdFileData.cFileName, TEXT("..")))
|
|
{
|
|
SetCurrentDirectory(wfdFileData.cFileName);
|
|
hSearch = FindFirstFile(TEXT("*"), &wfdFileData);
|
|
if (hSearch == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (lpWalk->lpSrchDirListHead == NULL)
|
|
{
|
|
lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
|
|
goto LoopBack;
|
|
}
|
|
else
|
|
return ERR_UNKNOWN; // Never comes here for all dirs have . and ..
|
|
}
|
|
retVal = AddToList(hSearch, lpWalk);
|
|
if (retVal == ERR_NOMEMORY)
|
|
return ERR_NOMEMORY; // GlobalAlloc failed
|
|
dwAttrs = GetFileAttributes(wfdFileData.cFileName);
|
|
}
|
|
else
|
|
{
|
|
while (!(bRC = FindNextFile(lpWalk->lpSrchDirListTail->hDirHandle, &wfdFileData)))
|
|
{
|
|
if ((GetLastError() == ERROR_NO_MORE_FILES))
|
|
{
|
|
FindClose(lpWalk->lpSrchDirListTail->hDirHandle);
|
|
RemoveFromList(lpWalk);
|
|
if (lpWalk->lpSrchDirListHead == NULL)
|
|
{
|
|
lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
|
|
goto LoopBack;
|
|
}
|
|
SetCurrentDirectory(TEXT(".."));
|
|
}
|
|
else
|
|
return ERR_UNKNOWN ; //should never come here
|
|
}
|
|
dwAttrs = GetFileAttributes(wfdFileData.cFileName);
|
|
}
|
|
}
|
|
StringCchCopy(lpLnkInfo->szLnkName, MAX_PATH, wfdFileData.cFileName);
|
|
|
|
GetCurrentDirectory(MAX_PATH, lpLnkInfo->szLnkPath); //BUG
|
|
|
|
StringCchCopy(lpLnkInfo->szExeName, MAX_PATH, lpLnkInfo->szLnkName);
|
|
|
|
StringCchCopy(lpLnkInfo->szExePath, MAX_PATH, lpLnkInfo->szLnkPath);
|
|
|
|
StringCchPrintf(lpszPath, pathBufSize, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
|
|
|
|
|
|
return ERR_MOREFILESTOCOME;
|
|
LoopBack:
|
|
lpWalk->dwCurrentFlag = RESET_FLAG;
|
|
continue;
|
|
}
|
|
|
|
DEBUG_ASSERT(GetInputType(lpWalk) != INIFILE);
|
|
DEBUG_ASSERT(GetInputType(lpWalk) != REGISTRY);
|
|
|
|
return ERR_SUCCESS; //This means we are done with all of them.
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
ERR GetNextFileFromString(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
BOOL GetFileLAD(LPLINKINFO lpLnkInfo)
|
|
{
|
|
WIN32_FIND_DATA wfdFileData;
|
|
HANDLE hSearch;
|
|
TCHAR szTempStr[MAX_PATH+1];
|
|
|
|
StringCchCopy(szTempStr, MAX_PATH +1, lpLnkInfo->szExePath);
|
|
StringCchCat(szTempStr, MAX_PATH +1, TEXT("\\"));
|
|
StringCchCat(szTempStr, MAX_PATH +1, lpLnkInfo->szExeName);
|
|
|
|
if (!_tcschr(szTempStr, '.'))
|
|
StringCchCat(szTempStr, MAX_PATH +1, TEXT(".exe"));
|
|
|
|
if ( NULL == szTempStr && _tcsicmp(_tcschr(szTempStr, '.'), TEXT(".exe")) != 0)
|
|
return FALSE;
|
|
//bugbug performance hit
|
|
|
|
hSearch = FindFirstFile( szTempStr, &wfdFileData);
|
|
if (hSearch == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
else
|
|
{
|
|
lpLnkInfo->ftExeLAD = wfdFileData.ftLastAccessTime;
|
|
FindClose(hSearch);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
ERR GetRegistryString(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ERR GetIniString(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
INT GetInputType(LPWALKHEADER lpWalk)
|
|
{
|
|
if (lpWalk->dwWalkFlags & INPTYPE_FOLDER)
|
|
{
|
|
return FOLDER;
|
|
}
|
|
if (lpWalk->dwWalkFlags & INPTYPE_INIFILE)
|
|
{
|
|
return INIFILE;
|
|
}
|
|
if (lpWalk->dwWalkFlags & INPTYPE_REGISTRY)
|
|
{
|
|
return REGISTRY;
|
|
}
|
|
return ERR_UNKNOWN; // should never come here
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ERR GetFolder(LPTSTR lpszFolder, size_t folderBufSize, LPWALKHEADER lpWalk)
|
|
{
|
|
HKEY hKey;
|
|
UINT cchFolder = MAX_PATH;
|
|
TCHAR szRegVal[MAX_PATH];
|
|
DWORD dwType;
|
|
|
|
if (!(lpWalk->dwWalkFlags & INPTYPE_ANYFOLDER))
|
|
{
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_SHELLFOLDERS, 0, KEY_READ, &hKey)
|
|
== ERROR_SUCCESS)
|
|
{
|
|
if (lpWalk->dwWalkFlags & INPTYPE_STARTMENU)
|
|
{
|
|
StringCchCopy(szRegVal, MAX_PATH, TEXT("Start Menu"));
|
|
lpWalk->dwCurrentFlag = INPTYPE_STARTMENU;
|
|
}
|
|
else if (lpWalk->dwWalkFlags & INPTYPE_DESKTOP)
|
|
{
|
|
StringCchCopy(szRegVal, MAX_PATH, TEXT("Desktop"));
|
|
lpWalk->dwCurrentFlag = INPTYPE_DESKTOP;
|
|
}
|
|
|
|
cchFolder = ARRAYLEN(szRegVal);
|
|
LONG lr = RegQueryValueEx(hKey,
|
|
szRegVal,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)lpszFolder,
|
|
(ULONG *)&cchFolder);
|
|
|
|
|
|
if (dwType == REG_EXPAND_SZ)
|
|
{
|
|
TCHAR tszTemp[MAX_PATH] = { 0 };
|
|
|
|
DWORD dwSize = ExpandEnvironmentStrings(lpszFolder, tszTemp, ARRAYLEN(tszTemp));
|
|
if (!dwSize)
|
|
{
|
|
return ERR_UNKNOWN; // should never come here
|
|
}
|
|
if (dwSize > ARRAYLEN(tszTemp))
|
|
{
|
|
return ERR_BUFFERTOOSMALL; // should not come here either; but if it does, we'll return this error
|
|
// we could dynamically allocate a buffer large enough,
|
|
// but since almost all storage for paths in this component
|
|
// seem to be MAX_PATH, it would surely overflow someplace else
|
|
// if everything weren't changed to allow larger sizes
|
|
}
|
|
|
|
StringCchCopy(lpszFolder, folderBufSize, tszTemp);
|
|
}
|
|
|
|
if (lr != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey);
|
|
|
|
if (lpWalk->dwWalkFlags & INPTYPE_STARTMENU)
|
|
{
|
|
return ERR_NOSTARTMENU;
|
|
}
|
|
else
|
|
{
|
|
return ERR_NODESKTOP;
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
else
|
|
return ERR_NOSHELLFOLDERS;
|
|
}
|
|
else
|
|
{
|
|
StringCchCopy(lpszFolder, folderBufSize, (LPTSTR) lpWalk->lpszFolder);
|
|
lpWalk->dwCurrentFlag = INPTYPE_ANYFOLDER;
|
|
}
|
|
return ERR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
ERR GetLnkInfo(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo, LPTSTR lpszPath)
|
|
{
|
|
WIN32_FIND_DATA wfdExeData;
|
|
ERR errVal = ERR_NOTANEXE;
|
|
UINT uiDType;
|
|
TCHAR szExepath[MAX_PATH +1];
|
|
TCHAR szDrivePath[MAX_PATH];
|
|
LPTSTR lpszSubStr;
|
|
INT iLen1, iLen2;
|
|
BOOL bExists;
|
|
|
|
//BUGBUG THe if thens should be such that there is repetition of code
|
|
szExepath[0] = '\0';
|
|
LPTSTR ptszExt = PathFindExtension(lpLnkInfo->szLnkName);
|
|
|
|
if (ptszExt && !_tcsicmp(ptszExt, TEXT(".LNK")))
|
|
{
|
|
if (!(errVal = ResolveLnk(lpszPath, szExepath, &wfdExeData, (LPTSTR)lpLnkInfo->tszArguments)))
|
|
{
|
|
|
|
if (lpszSubStr = _tcsrchr(szExepath, TEXT('.')))
|
|
{
|
|
if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
|
|
_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
|
|
{
|
|
if (lpszSubStr = _tcsrchr(szExepath, '\\'))
|
|
lpszSubStr++;
|
|
else
|
|
lpszSubStr = szExepath;
|
|
StringCchCopy(lpLnkInfo->szExeName, MAX_PATH, lpszSubStr);
|
|
iLen1 = lstrlen(szExepath);
|
|
iLen2 = lstrlen(lpLnkInfo->szExeName);
|
|
*(szExepath + iLen1 - iLen2 - 1) = TEXT('\0');
|
|
StringCchCopy(lpLnkInfo->szExePath, MAX_PATH, szExepath);
|
|
GetFileLAD(lpLnkInfo);
|
|
|
|
StringCchPrintf(szExepath, MAX_PATH +1, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
|
|
|
|
GetDrivePath(szExepath, szDrivePath, MAX_PATH);
|
|
uiDType = GetDriveType(szDrivePath);
|
|
|
|
if ((lpWalk->dwWalkFlags & INPFLAG_SKIPFILES ) && (InSkipList(lpLnkInfo->szExeName)))
|
|
{
|
|
errVal = ERR_NOTANEXE;
|
|
}
|
|
else if (!(lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
|
|
(uiDType != DRIVE_FIXED))
|
|
errVal = ERR_NOTANEXE;
|
|
else if ((lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
|
|
(uiDType != DRIVE_FIXED) && (uiDType != DRIVE_REMOTE) && (uiDType != DRIVE_CDROM))
|
|
errVal = ERR_NOTANEXE;
|
|
else if (!(bExists = CheckFileExists(szExepath, &(lpLnkInfo->ftExeLAD))) && (uiDType == DRIVE_FIXED))
|
|
errVal = ERR_NOTANEXE;
|
|
else if (!(errVal = GetExeVersion(lpLnkInfo)))
|
|
{
|
|
errVal = ERR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
errVal = ERR_NOTANEXE;
|
|
}
|
|
else
|
|
errVal = ERR_NOTANEXE; // link resolved to a non exe
|
|
|
|
if (errVal == ERR_SUCCESS)
|
|
*(_tcsrchr(lpLnkInfo->szLnkName, TEXT('.'))) = '\0';
|
|
}
|
|
else
|
|
errVal = ERR_NOTANEXE;
|
|
}
|
|
else if (ptszExt && !_tcsicmp(ptszExt, TEXT(".EXE")))
|
|
{
|
|
StringCchCopy(lpLnkInfo->szExeName, MAX_PATH, lpLnkInfo->szLnkName);
|
|
StringCchPrintf(szExepath, MAX_PATH +1, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
|
|
|
|
GetDrivePath(szExepath, szDrivePath, MAX_PATH);
|
|
uiDType = GetDriveType(szDrivePath);
|
|
GetFileLAD(lpLnkInfo);
|
|
|
|
if ((lpWalk->dwWalkFlags & INPFLAG_SKIPFILES) && (InSkipList(lpLnkInfo->szExeName)))
|
|
errVal = ERR_NOTANEXE;
|
|
else if (!(lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
|
|
(uiDType != DRIVE_FIXED))
|
|
errVal = ERR_NOTANEXE;
|
|
else if ((lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
|
|
(uiDType != DRIVE_FIXED) && (uiDType != DRIVE_REMOTE) && (uiDType != DRIVE_CDROM))
|
|
errVal = ERR_NOTANEXE;
|
|
else if (!(bExists = CheckFileExists(szExepath, &(lpLnkInfo->ftExeLAD))) && (uiDType == DRIVE_FIXED))
|
|
errVal = ERR_NOTANEXE;
|
|
else if (!(errVal = GetExeVersion(lpLnkInfo)))
|
|
errVal = ERR_SUCCESS;
|
|
}
|
|
return errVal;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
void GetDrivePath(LPTSTR lpszExePath, LPTSTR lpszDrPath, size_t drPathSize)
|
|
{
|
|
LPTSTR lpszSubStr;
|
|
if (s_isDriveLetter(lpszExePath[0]) && lpszExePath[1] == TEXT(':'))
|
|
{
|
|
lstrcpyn(lpszDrPath, lpszExePath, 3);
|
|
StringCchCat(lpszDrPath, drPathSize, TEXT("\\"));
|
|
}
|
|
else if (!_tcsncmp(lpszExePath, TEXT("\\\\"), 2))
|
|
{
|
|
if (lpszSubStr = _tcschr(&lpszExePath[2], TEXT('\\')))
|
|
{
|
|
if (lpszSubStr = _tcschr(lpszSubStr+1, TEXT('\\')))
|
|
{
|
|
lstrcpyn(lpszDrPath, lpszExePath, (size_t)(lpszSubStr - lpszExePath + 1));
|
|
lpszDrPath[lpszSubStr - lpszExePath + 1] = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
else
|
|
lpszDrPath[0] = '\0';
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ERR ResolveLnk(LPCTSTR pszShortcutFile, LPTSTR lpszLnkPath,
|
|
LPWIN32_FIND_DATA lpwfdExeData, LPTSTR tszArgs)
|
|
{
|
|
HRESULT hres;
|
|
IShellLink *psl;
|
|
TCHAR szGotPath[MAX_PATH +1];
|
|
HWND hwnd = NULL;
|
|
ERR errVal = ERR_RESOLVEFAIL;
|
|
|
|
*tszArgs = TEXT('\0');
|
|
// Get a pointer to the IShellLink interface.
|
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink, (void **)&psl);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IPersistFile* ppf;
|
|
|
|
// Get a pointer to the IPersistFile interface.
|
|
hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
WCHAR wsz[MAX_PATH +1];
|
|
|
|
lstrcpyn(wsz, pszShortcutFile, ARRAYLEN(wsz));
|
|
|
|
// Load the shell link.
|
|
hres = ppf->Load(wsz, STGM_READ);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, "Link: %ws\n", wsz));
|
|
//
|
|
// If the link is to an MSI app, don't get the path to the
|
|
// link target - use the path to the link itself instead.
|
|
//
|
|
if (IsMsiApp(psl))
|
|
{
|
|
errVal = ERR_SUCCESS;
|
|
lstrcpyn(lpszLnkPath, pszShortcutFile, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
lstrcpyn(szGotPath, pszShortcutFile, MAX_PATH);
|
|
|
|
// Get the path to the link target.
|
|
hres = psl->GetPath(szGotPath, MAX_PATH, (LPWIN32_FIND_DATA)lpwfdExeData,
|
|
SLGP_SHORTPATH );
|
|
if (!SUCCEEDED(hres))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, " GetPath failed %#x\n", hres));
|
|
errVal = ERR_RESOLVEFAIL; /* get path failed : Link not resolved */
|
|
}
|
|
else
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, " Path: %ws\n", szGotPath));
|
|
if (lstrlen(szGotPath) > 0)
|
|
{
|
|
errVal = ERR_SUCCESS;
|
|
lstrcpyn(lpszLnkPath, szGotPath, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
errVal = ERR_RESOLVEFAIL;
|
|
}
|
|
}
|
|
|
|
hres = psl->GetArguments(tszArgs, MAX_PATH);
|
|
CHECK_HRESULT(hres);
|
|
}
|
|
}
|
|
// Release pointer to IPersistFile interface.
|
|
ppf->Release();
|
|
}
|
|
// Release pointer to IShellLink interface.
|
|
psl->Release();
|
|
}
|
|
return errVal;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ERR AddToList(HANDLE hDir, LPWALKHEADER lpWalk)
|
|
{
|
|
LPHSEARCHDIR lpSrchDirNode;
|
|
|
|
#ifdef _DEBUG
|
|
lpSrchDirNode = (LPHSEARCHDIR) MyGlobalAlloc(FAILMEMA, sizeof(HSEARCHDIR));
|
|
#else
|
|
lpSrchDirNode = (LPHSEARCHDIR) GlobalAlloc(GPTR, sizeof(HSEARCHDIR));
|
|
#endif
|
|
|
|
if (lpSrchDirNode == NULL)
|
|
return ERR_NOMEMORY; /* Global Alloc failed */
|
|
|
|
lpSrchDirNode->hDirHandle = hDir;
|
|
lpSrchDirNode->lpSrchDirNext = NULL;
|
|
|
|
if (lpWalk->lpSrchDirListHead == NULL)
|
|
lpWalk->lpSrchDirListHead = lpSrchDirNode;
|
|
else
|
|
lpWalk->lpSrchDirListTail->lpSrchDirNext = lpSrchDirNode;
|
|
|
|
lpWalk->lpSrchDirListTail = lpSrchDirNode;
|
|
return ERR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ERR RemoveFromList(LPWALKHEADER lpWalk)
|
|
{
|
|
LPHSEARCHDIR lpSrchDirNode;
|
|
|
|
if (lpWalk->lpSrchDirListHead == NULL)
|
|
return ERR_SUCCESS;
|
|
|
|
lpSrchDirNode = lpWalk->lpSrchDirListHead;
|
|
while ( (lpSrchDirNode->lpSrchDirNext != lpWalk->lpSrchDirListTail) &&
|
|
(lpSrchDirNode != lpWalk->lpSrchDirListTail))
|
|
{
|
|
lpSrchDirNode = lpSrchDirNode->lpSrchDirNext;
|
|
}
|
|
|
|
if (lpSrchDirNode != lpWalk->lpSrchDirListTail)
|
|
{
|
|
#ifdef _DEBUG
|
|
MyGlobalFree(lpWalk->lpSrchDirListTail, FAILMEMF);
|
|
#else
|
|
GlobalFree(lpWalk->lpSrchDirListTail);
|
|
#endif
|
|
lpSrchDirNode->lpSrchDirNext = NULL;
|
|
lpWalk->lpSrchDirListTail = lpSrchDirNode;
|
|
}
|
|
else
|
|
{
|
|
#ifdef _DEBUG
|
|
MyGlobalFree(lpWalk->lpSrchDirListTail, FAILMEMF);
|
|
#else
|
|
GlobalFree(lpWalk->lpSrchDirListTail);
|
|
#endif
|
|
lpWalk->lpSrchDirListHead = NULL;
|
|
lpWalk->lpSrchDirListTail = NULL;
|
|
}
|
|
|
|
return ERR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ERR GetExeVersion(LPLINKINFO lpLnkInfo)
|
|
{
|
|
LPTSTR lpVersion;
|
|
DWORD dwVerInfoSize;
|
|
DWORD dwVerHnd;
|
|
WORD wVersionLen;
|
|
WORD wRootLen;
|
|
BOOL bRetCode;
|
|
const size_t GetNameLength = 100;
|
|
TCHAR szGetName[GetNameLength];
|
|
|
|
TCHAR szFullName[MAX_PATH];
|
|
ERR errVal;
|
|
LPTSTR lpstrVffInfo;
|
|
|
|
|
|
// Get the file version info size
|
|
StringCchPrintf(szFullName, MAX_PATH, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
|
|
dwVerInfoSize = GetFileVersionInfoSize(szFullName, &dwVerHnd);
|
|
|
|
if (dwVerInfoSize)
|
|
{
|
|
// allocate memory to hold the verinfo block
|
|
|
|
#ifdef _DEBUG
|
|
lpstrVffInfo = (LPTSTR) MyGlobalAlloc(FAILMEMA, dwVerInfoSize);
|
|
#else
|
|
lpstrVffInfo = (LPTSTR) GlobalAlloc(GPTR, dwVerInfoSize);
|
|
#endif
|
|
if (lpstrVffInfo == NULL)
|
|
{
|
|
errVal = ERR_NOMEMORY; //Global Alloc failed
|
|
goto Exit;
|
|
}
|
|
|
|
bRetCode = GetFileVersionInfo(szFullName, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
|
|
if (!bRetCode)
|
|
{
|
|
errVal = ERR_SUCCESS; //ERR_FILEVERSIONFAIL;
|
|
goto Exit;
|
|
}
|
|
//GetFileVersionInfo failed
|
|
// Do this the American english translation be default.
|
|
// Keep track of the string length for easy updating.
|
|
// 040904E4 represents the language ID and the four
|
|
// least significant digits represent the codepage for
|
|
// which the data is formatted. The language ID is
|
|
// composed of two parts: the low ten bits represent
|
|
// the major language and the high six bits represent
|
|
// the sub language.
|
|
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
TEXT("\\"),
|
|
(void FAR* FAR*) &lpVersion,
|
|
(UINT FAR*)&wVersionLen);
|
|
|
|
if ( bRetCode && wVersionLen && lpVersion)
|
|
{
|
|
lpLnkInfo->dwExeVerMS =
|
|
((VS_FIXEDFILEINFO *)lpVersion)->dwProductVersionMS;
|
|
lpLnkInfo->dwExeVerLS =
|
|
((VS_FIXEDFILEINFO *)lpVersion)->dwProductVersionLS;
|
|
}
|
|
else
|
|
{
|
|
lpLnkInfo->dwExeVerMS = 0;
|
|
lpLnkInfo->dwExeVerLS = 0;
|
|
}
|
|
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
TEXT("\\VarFileInfo\\Translation"),
|
|
(void FAR* FAR*) &lpVersion,
|
|
(UINT FAR*)&wVersionLen);
|
|
|
|
if ( bRetCode && wVersionLen && lpVersion)
|
|
{
|
|
DWORD dwLangCharSet;
|
|
WORD wTemp1, wTemp2;
|
|
CopyMemory(&dwLangCharSet, lpVersion, 4);
|
|
if (!dwLangCharSet)
|
|
dwLangCharSet = 0x04E40409; // the Words have been switched
|
|
|
|
// Need to switch the words back since lpbuffer has them reversed
|
|
wTemp1 = LOWORD(dwLangCharSet);
|
|
wTemp2 = HIWORD(dwLangCharSet);
|
|
StringCchPrintf(szGetName, GetNameLength, TEXT("\\StringFileInfo\\%04lx%04lx\\"), wTemp1, wTemp2);
|
|
}
|
|
else
|
|
{
|
|
errVal = ERR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
wRootLen = (WORD)lstrlen(szGetName);
|
|
|
|
// "Illegal string" "CompanyName" "FileDescription",
|
|
// "FileVersion" "InternalName" "LegalCopyright"
|
|
// "LegalTrademarks" "ProductName" "ProductVersion
|
|
|
|
StringCchCat(szGetName, GetNameLength, TEXT("FileVersion"));
|
|
wVersionLen = 0;
|
|
lpVersion = NULL;
|
|
|
|
// Look for the corresponding string.
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
szGetName,
|
|
(void FAR* FAR*)&lpVersion,
|
|
(UINT FAR *) &wVersionLen);
|
|
|
|
if ( bRetCode && wVersionLen && lpVersion)
|
|
{
|
|
StringCchCopy(lpLnkInfo->szExeVersionInfo, MAX_PATH, lpVersion);
|
|
}
|
|
// Now let's get FileDescription
|
|
|
|
szGetName[wRootLen] = NULL;
|
|
StringCchCat(szGetName, GetNameLength, TEXT("FileDescription"));
|
|
|
|
wVersionLen = 0;
|
|
lpVersion = NULL;
|
|
|
|
// Look for the corresponding string.
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
szGetName,
|
|
(void FAR* FAR*)&lpVersion,
|
|
(UINT FAR *) &wVersionLen);
|
|
|
|
if ( bRetCode && wVersionLen && lpVersion)
|
|
{
|
|
StringCchCopy(lpLnkInfo->szExeDesc, MAX_DESC, lpVersion);
|
|
}
|
|
|
|
szGetName[wRootLen] = NULL;
|
|
StringCchCat(szGetName, GetNameLength, TEXT("CompanyName"));
|
|
|
|
wVersionLen = 0;
|
|
lpVersion = NULL;
|
|
|
|
// Look for the corresponding string.
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
szGetName,
|
|
(void FAR* FAR*)&lpVersion,
|
|
(UINT FAR *) &wVersionLen);
|
|
|
|
if ( bRetCode && wVersionLen && lpVersion)
|
|
{
|
|
StringCchCopy(lpLnkInfo->szExeCompName, MAX_COMPNAME, lpVersion);
|
|
}
|
|
|
|
szGetName[wRootLen] = NULL;
|
|
StringCchCat(szGetName, GetNameLength, TEXT("ProductName"));
|
|
wVersionLen = 0;
|
|
lpVersion = NULL;
|
|
|
|
// Look for the corresponding string.
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
szGetName,
|
|
(void FAR* FAR*)&lpVersion,
|
|
(UINT FAR *) &wVersionLen);
|
|
|
|
if ( bRetCode && wVersionLen && lpVersion)
|
|
{
|
|
StringCchCopy(lpLnkInfo->szExeProdName, MAX_PRODNAME, lpVersion);
|
|
}
|
|
|
|
/* else if (i == 1)
|
|
{
|
|
// This is an attempt to special case the multimedia
|
|
// extensions. I think they paid attention to the
|
|
// original docs which suggested that they use the
|
|
// 0409 language ID and 0 codepage which indicates
|
|
// 7 bit ASCII.
|
|
|
|
StringCchCopy(szGetName, GetNameLength, TEXT("\\StringFileInfo\\04090000\\"));
|
|
i = 0; // be sure to reset the counter
|
|
}*/
|
|
|
|
// Be sure to reset to NULL so that we can concat
|
|
errVal = ERR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
lpLnkInfo->dwExeVerMS = 0;
|
|
lpLnkInfo->dwExeVerLS = 0;
|
|
return ERR_SUCCESS;
|
|
}
|
|
|
|
Exit :
|
|
if (errVal != ERR_NOMEMORY)
|
|
{
|
|
#ifdef _DEBUG
|
|
MyGlobalFree(lpstrVffInfo, FAILMEMF);
|
|
#else
|
|
GlobalFree(lpstrVffInfo);
|
|
#endif
|
|
// Be sure to reset to NULL so that we can concat
|
|
lpstrVffInfo = NULL;
|
|
}
|
|
|
|
return errVal;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void SetLnkInfo(LPLINKINFO lpLinkInfo)
|
|
{
|
|
SecureZeroMemory((void *)lpLinkInfo, sizeof(LINKINFO));
|
|
lpLinkInfo->iAppCompat = APPCOMPATUNKNOWN;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
DWORD ReverseDWord(DWORD dwIn)
|
|
{
|
|
DWORD dwOut= 0;
|
|
while (dwIn != 0)
|
|
{
|
|
dwOut = dwOut << 8;
|
|
dwOut = dwOut | (dwIn & 0x000000FF);
|
|
dwIn = dwIn >> 8;
|
|
}
|
|
return dwOut;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
BOOL CheckFileExists(LPTSTR szFullName, LPVOID ftLAD)
|
|
{
|
|
BOOL bRC;
|
|
HANDLE hFile;
|
|
|
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
hFile = CreateFile(
|
|
szFullName, // pointer to name of the file
|
|
GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode
|
|
NULL, // pointer to security attributes
|
|
OPEN_EXISTING, // how to create
|
|
NULL, // file attributes
|
|
NULL // handle to file with attributes to copy
|
|
);
|
|
int i = GetLastError();
|
|
if ((hFile == INVALID_HANDLE_VALUE) &&
|
|
((i == ERROR_FILE_NOT_FOUND) || (i == ERROR_PATH_NOT_FOUND) ||
|
|
(i == ERROR_BAD_NETPATH)))
|
|
{
|
|
bRC = FALSE;
|
|
}
|
|
else if (hFile == INVALID_HANDLE_VALUE)
|
|
bRC = TRUE;
|
|
else
|
|
{
|
|
if (ftLAD != 0)
|
|
SetFileTime(hFile, NULL, (FILETIME *) ftLAD, NULL);
|
|
|
|
CloseHandle(hFile);
|
|
bRC = TRUE;
|
|
}
|
|
|
|
return bRC;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void CloseWalk(HWALK hWalk)
|
|
{
|
|
LPWALKHEADER lpWalk = (LPWALKHEADER) hWalk;
|
|
|
|
if (lpWalk != NULL)
|
|
{
|
|
while (lpWalk->lpSrchDirListHead != NULL)
|
|
RemoveFromList(lpWalk);
|
|
//BUGBUG : Must free everything in hWalk
|
|
|
|
if (lpWalk != NULL)
|
|
{
|
|
if (lpWalk->lpszIniString != NULL)
|
|
{
|
|
#ifdef _DEBUG
|
|
MyGlobalFree(lpWalk->lpszIniString, FAILMEMF);
|
|
#else
|
|
GlobalFree(lpWalk->lpszIniString);
|
|
#endif
|
|
lpWalk->lpszIniString = NULL;
|
|
}
|
|
#ifdef _DEBUG
|
|
MyGlobalFree(lpWalk, FAILMEMF);
|
|
#else
|
|
GlobalFree(lpWalk);
|
|
#endif
|
|
lpWalk = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _DEBUG
|
|
HGLOBAL MyGlobalFree(HGLOBAL hGlobal, BOOL FAILMEM)
|
|
{
|
|
HGLOBAL hGbl;
|
|
|
|
g_MemAlloced = g_MemAlloced - GlobalSize(hGlobal);
|
|
hGbl = GlobalFree(hGlobal);
|
|
return hGbl;
|
|
};
|
|
|
|
HGLOBAL MyGlobalAlloc(BOOL FAILMEM, DWORD dwBytes)
|
|
{
|
|
HGLOBAL hGbl;
|
|
if (FAILMEM)
|
|
{
|
|
hGbl = GlobalAlloc(GPTR, dwBytes);
|
|
g_MemAlloced = g_MemAlloced + GlobalSize(hGbl);
|
|
return hGbl;
|
|
}
|
|
else
|
|
return NULL;
|
|
};
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
BOOL
|
|
IsMsiApp(
|
|
IShellLink * psl
|
|
)
|
|
{
|
|
//
|
|
// Find out if this link is to an MSI app.
|
|
// The algorithm for finding out is from ProcessDarwinAd in
|
|
// shell\shell32\unicpp\startmnu.cpp.
|
|
//
|
|
|
|
IShellLinkDataList * psldl;
|
|
HRESULT hr = psl->QueryInterface(IID_IShellLinkDataList, (void **)&psldl);
|
|
if (FAILED(hr))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, " QI for IShellLinkDataList failed %#x\n", hr));
|
|
return FALSE;
|
|
}
|
|
|
|
EXP_DARWIN_LINK * pexpDarwin;
|
|
|
|
hr = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
|
|
|
|
psldl->Release();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, " CopyDataBlock failed %#x\n", hr));
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUG_OUT((DEB_ITRACE, " This IS a Darwin app\n"));
|
|
|
|
LocalFree(pexpDarwin);
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
///////////////////////DDDDOOOONNNNEEEE//////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
|