#include "..\pch\headers.hxx" #pragma hdrstop #include "myheaders.hxx" #include // IShellLinkDataList #include // IID_IShellLinkDataList #include // MsiQueryProductState #include #include #include #include #include #include #include #include #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////////////////////////// /////////////////////////////////////////////////////////////////