|
|
//=======================================================================
//
// Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
//
// File: detect.cpp
//
// Purpose: Component Detection
//
// History: 3/9/99 YAsmi Created
//
//=======================================================================
#include "stdafx.h"
#include "detect.h"
#include "debug.h"
#include <wustl.h>
#include "log.h"
LPCSTR ParseField(LPCSTR pszStr, LPSTR pszTokOut, int cTokSize); BOOL UninstallKeyExists(LPCSTR pszUninstallKey); static int CompareLocales(LPCSTR pszLoc1, LPCSTR pszLoc2);
//
// CComponentDetection
//
CComponentDetection::CComponentDetection() : m_dwDetectStatus(ICI_NOTINITIALIZED), m_dwDLLReturnValue(0), m_dwInstalledVer(0), m_dwInstalledBuild(0) { int i;
for (i = 0; i < (int)ccValueCount; i++) { m_ppValue[i] = (char*)malloc(ccMaxSize); }
// custom data has its own size and can be longer than MaxSize
m_dwCustomDataSize = ccMaxSize;
for (i = 0; i < (int)ccDLLCount; i++) { m_pDLLs[i].bUsed = FALSE; }
ClearValues(); }
CComponentDetection::~CComponentDetection() { int i;
//
// free cached libraries
//
for (i = 0; i < (int)ccDLLCount; i++) { if (m_pDLLs[i].bUsed) FreeLibrary(m_pDLLs[i].hLib); }
for (i = 0; i < (int)ccValueCount; i++) { free(m_ppValue[i]); } }
void CComponentDetection::ClearValues() { for (int i = 0; i < (int)ccValueCount; i++) { m_ppValue[i][0] = '\0'; } }
BOOL CComponentDetection::SetValue(enumCCValue cc, LPCSTR pszValue) { if (cc <= ccLastValue) { if (cc == ccCustomData) { // we allow custom data to be as long as possible so we will reallocate if neccessory
DWORD l = strlen(pszValue) + 1;
if (l > m_dwCustomDataSize) { free(m_ppValue[cc]); m_ppValue[cc] = _strdup(pszValue); m_dwCustomDataSize = l; } else { strncpy(m_ppValue[cc], pszValue, m_dwCustomDataSize); } return TRUE;
} else { // we don't copy more than ccMaxSize
strncpy(m_ppValue[cc], pszValue, ccMaxSize - 1); return TRUE; } } return FALSE; }
BOOL CComponentDetection::GetValue(enumCCValue cc, LPSTR pszValue, DWORD dwSize) { if (cc <= ccLastValue) { strncpy(pszValue, m_ppValue[cc], dwSize); if (pszValue[0] != '\0') return TRUE; } return FALSE; }
// detects using the current values specified by SetValue
// clears all the values after detection but we can still retrieve the
// status of last detection using GetLastDetectStatus
//
// Returns the status of detection ICI_INSTALLED etc
DWORD CComponentDetection::Detect() { DWORD dwDetStat; m_dwDLLReturnValue = 0; dwDetStat = IsComponentInstalled();
ClearValues();
return dwDetStat; }
DWORD CComponentDetection::GetLastDetectStatus() { return m_dwDetectStatus; }
DWORD CComponentDetection::GetLastDLLReturnValue() { return m_dwDLLReturnValue; }
void CComponentDetection::GetInstalledVersion(LPDWORD pdwVer, LPDWORD pdwBuild) { *pdwVer = m_dwInstalledVer; *pdwBuild = m_dwInstalledBuild; }
HINSTANCE CComponentDetection::CacheLoadLibrary(LPCSTR pszDLLName, LPCTSTR pszDLLFullPath) { int iAvailable = -1; int iFound = -1;
//
// check the cache to see if we already have loaded it
//
for (int i = 0; i < (int)ccDLLCount; i++) { if (m_pDLLs[i].bUsed) { if (_stricmp(pszDLLName, m_pDLLs[i].szDLLName) == 0) { iFound = i; break; } } else { if (iAvailable == -1) iAvailable = i; } }
if (iFound != -1) { //
// returned the cached libary instance
//
return m_pDLLs[iFound].hLib; } else { //
// load and cache the libary
//
if (iAvailable == -1) { iAvailable = 0;
if (m_pDLLs[iAvailable].bUsed) { FreeLibrary(m_pDLLs[iAvailable].hLib); m_pDLLs[iAvailable].bUsed = FALSE; } } m_pDLLs[iAvailable].hLib = LoadLibrary(pszDLLFullPath); if (m_pDLLs[iAvailable].hLib != NULL) { strcpy(m_pDLLs[iAvailable].szDLLName, pszDLLName); m_pDLLs[iAvailable].bUsed = TRUE; } else { TRACE_HR(HRESULT_FROM_WIN32(GetLastError()), "Could not load %s (%d)", pszDLLFullPath, HRESULT_FROM_WIN32(GetLastError())); } return m_pDLLs[iAvailable].hLib; } }
HRESULT CComponentDetection::CallDetectDLL(LPCSTR pszDll, LPCSTR pszEntry) { USES_CONVERSION;
HRESULT hr = E_FAIL; HINSTANCE hLib; DETECTION_STRUCT Det; DWORD dwCifVer, dwCifBuild; char szLocale[8]; char szGUID[128]; m_dwDetectStatus = ICI_NOTINSTALLED;
GetValue(ccGUID, szGUID, sizeof(szGUID)); GetLocale(szLocale, sizeof(szLocale)); GetVersion(&dwCifVer, &dwCifBuild);
//
// init the Detection structure
//
Det.dwSize = sizeof(DETECTION_STRUCT); Det.pdwInstalledVer = &m_dwInstalledVer; Det.pdwInstalledBuild = &m_dwInstalledBuild; Det.pszLocale = szLocale; Det.pszGUID = szGUID; Det.dwAskVer = dwCifVer; Det.dwAskBuild = dwCifBuild; Det.pCifFile = NULL; Det.pCifComp = (ICifComponent*)this; TCHAR szDllFile[MAX_PATH]; GetWindowsUpdateDirectory(szDllFile); lstrcat(szDllFile, A2T(pszDll));
//
// load the detection dll
//
hLib = CacheLoadLibrary(pszDll, szDllFile); if (hLib) { DETECTVERSION fpDetVer = (DETECTVERSION)GetProcAddress(hLib, pszEntry); if (fpDetVer) { //
// call the entry point
//
m_dwDLLReturnValue = fpDetVer(&Det); switch(m_dwDLLReturnValue) { case DET_NOTINSTALLED: m_dwDetectStatus = ICI_NOTINSTALLED; break; case DET_INSTALLED: m_dwDetectStatus = ICI_INSTALLED; break; case DET_NEWVERSIONINSTALLED: m_dwDetectStatus = ICI_OLDVERSIONAVAILABLE; break; case DET_OLDVERSIONINSTALLED: m_dwDetectStatus = ICI_NEWVERSIONAVAILABLE; break; } hr = NOERROR;
} else { TRACE_HR(HRESULT_FROM_WIN32(GetLastError()), "Detection DLL call failed %s %s", pszDll, pszEntry); } }
return hr; }
STDMETHODIMP_(DWORD) CComponentDetection::IsComponentInstalled() { USES_CONVERSION;
char szDllName[32]; char szDllEntry[32]; DWORD dwUnused; DWORD dwIsInstalled; char szGUID[128]; HKEY hComponentKey = NULL; m_dwDetectStatus = ICI_NOTINSTALLED; //
// if we need to call detection dll, call it
//
if (SUCCEEDED(GetDetVersion(szDllName, sizeof(szDllName), szDllEntry, sizeof(szDllEntry)))) { if (SUCCEEDED(CallDetectDLL(szDllName, szDllEntry))) { if (m_dwDetectStatus == ICI_OLDVERSIONAVAILABLE) m_dwDetectStatus = ICI_INSTALLED; return m_dwDetectStatus; } }
//
// build GUID registry key
//
GetValue(ccGUID, szGUID, sizeof(szGUID));
TCHAR szKeyName[MAX_PATH]; lstrcpy(szKeyName, COMPONENT_KEY); lstrcat(szKeyName, _T("\\")); lstrcat(szKeyName, A2T(szGUID)); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hComponentKey) == ERROR_SUCCESS) { //
// first check for the IsInstalled valuename
// if the valuename is there AND equals zero, we say not installed.
// otherwise continue.
//
// NOTE: We default to ISINSTALLED_YES if valuename not present to be Back-compatible
//
dwUnused = sizeof(dwIsInstalled); if (RegQueryValueEx(hComponentKey, ISINSTALLED_KEY, 0, NULL, (LPBYTE) (&dwIsInstalled), &dwUnused) != ERROR_SUCCESS) dwIsInstalled = ISINSTALLED_YES; if (dwIsInstalled == ISINSTALLED_YES) { //
// next check for a locale match (no locale entry uses default)
//
DWORD dwType; TCHAR szRegLocale[8]; dwUnused = sizeof(szRegLocale); if (RegQueryValueEx(hComponentKey, LOCALE_KEY, 0, NULL, (LPBYTE)szRegLocale, &dwUnused) != ERROR_SUCCESS) lstrcpy(szRegLocale, DEFAULT_LOCALE); char szAskLocale[8]; GetValue(ccLocale, szAskLocale, sizeof(szAskLocale));
if (CompareLocales(T2A(szRegLocale), szAskLocale) == 0) { //
// locales match so go check the QFEversio, version in that order
//
BOOL bVersionFound = FALSE; TCHAR szRegVer[128]; DWORD dwCifVer, dwCifBuild; dwUnused = sizeof(szRegVer); bVersionFound = (RegQueryValueEx(hComponentKey, QFE_VERSION_KEY, 0, &dwType, (LPBYTE)szRegVer, &dwUnused) == ERROR_SUCCESS); if (!bVersionFound) { dwUnused = sizeof(szRegVer); bVersionFound = (RegQueryValueEx(hComponentKey, VERSION_KEY, 0, &dwType, (LPBYTE)szRegVer, &dwUnused) == ERROR_SUCCESS); } if (bVersionFound) { if (dwType == REG_SZ) { ConvertVersionStrToDwords(szRegVer, &m_dwInstalledVer, &m_dwInstalledBuild); GetVersion(&dwCifVer, &dwCifBuild); if ((m_dwInstalledVer > dwCifVer) || ((m_dwInstalledVer == dwCifVer) && (m_dwInstalledBuild >= dwCifBuild))) { m_dwDetectStatus = ICI_INSTALLED; } else { m_dwDetectStatus = ICI_NEWVERSIONAVAILABLE; } } else { // if a string field is not found assume we have a newer version
m_dwDetectStatus = ICI_NEWVERSIONAVAILABLE; }
} //version found
} //locales match
} // installed key
} if (hComponentKey) RegCloseKey(hComponentKey); //
// we think its installed, now try to verify using uninstall key
//
if (m_dwDetectStatus != ICI_NOTINSTALLED) { char szUninstallKey[ccMaxSize]; if (GetValue(ccUninstallKey, szUninstallKey, sizeof(szUninstallKey))) { if (!UninstallKeyExists(szUninstallKey)) { m_dwDetectStatus = ICI_NOTINSTALLED; } } } return m_dwDetectStatus; }
STDMETHODIMP CComponentDetection::GetDetVersion(LPSTR pszDll, DWORD dwdllSize, LPSTR pszEntry, DWORD dwentSize) { char szBuf[ccMaxSize]; if (pszDll && pszEntry) *pszDll = *pszEntry = '\0'; else return E_FAIL; if (GetValue(ccDetectVersion, szBuf, sizeof(szBuf))) { LPCSTR pszParse = szBuf; pszParse = ParseField(pszParse, pszDll, dwdllSize); pszParse = ParseField(pszParse, pszEntry, dwentSize); } if (pszDll[0] == '\0' || pszEntry[0] == '\0') return E_FAIL; else return NOERROR; }
STDMETHODIMP CComponentDetection::GetCustomData(LPSTR pszKey, LPSTR pszData, DWORD dwSize) { USES_CONVERSION;
if (_stricmp(pszKey, "DetectVersion") == 0) { strncpy(pszData, m_ppValue[ccDetectVersion], dwSize); return NOERROR; } char szKeyName[128]; LPCSTR pCus = m_ppValue[ccCustomData]; LPCSTR pBeg = pCus; LPCSTR pEq; strcpy(szKeyName, "_"); strcat(szKeyName, pszKey);
// look for the _ key name
pBeg = stristr(pBeg, szKeyName); while (pBeg != NULL) { // we found a match ensure that its at the begining of a line
if ((pBeg == pCus) || (*(pBeg - 1) == '\n')) { // point to equal sign
pEq = pBeg + strlen(szKeyName); // skip spaces
while (*pEq == ' ') pEq++;
if (*pEq == '=') { // skip the equal sign
pEq++; // copy the value into pszData
LPSTR p = pszData; int i = dwSize - 1; while ((*pEq != '\n') && (i > 0)) { *p++ = *pEq++; i--; } *p = '\0';
TRACE("Detect GetCustomData %s returns %s", A2T(pszKey), A2T(pszData)); return NOERROR; } } // not the begining of the line
}
TRACE("Detect GetCustomData %s not found", A2T(pszKey)); return E_FAIL;
}
STDMETHODIMP CComponentDetection::GetVersion(LPDWORD pdwVersion, LPDWORD pdwBuild) { USES_CONVERSION; char szBuf[ccMaxSize]; if (GetValue(ccVersion, szBuf, sizeof(szBuf))) { ConvertVersionStrToDwords(A2T(szBuf), pdwVersion, pdwBuild); return NOERROR; } else return E_FAIL; }
STDMETHODIMP CComponentDetection::GetGUID(LPSTR pszGUID, DWORD dwSize) { if (GetValue(ccGUID, pszGUID, dwSize)) return NOERROR; else return E_FAIL; }
STDMETHODIMP CComponentDetection::GetLocale(LPSTR pszLocale, DWORD dwSize) { if (GetValue(ccLocale, pszLocale, dwSize)) return NOERROR; else return E_FAIL; }
STDMETHODIMP CComponentDetection::GetUninstallKey(LPSTR pszKey, DWORD dwSize) { if (GetValue(ccUninstallKey, pszKey, dwSize)) return NOERROR; else return E_FAIL; }
STDMETHODIMP CComponentDetection::GetID(LPSTR pszID, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetDescription(LPSTR pszDesc, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetDetails(LPSTR pszDetails, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetUrl(UINT uUrlNum, LPSTR pszUrl, DWORD dwSize, LPDWORD pdwUrlFlags) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetFileExtractList(UINT uUrlNum, LPSTR pszExtract, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetUrlCheckRange(UINT uUrlNum, LPDWORD pdwMin, LPDWORD pdwMax) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetCommand(UINT uCmdNum, LPSTR pszCmd, DWORD dwCmdSize, LPSTR pszSwitches, DWORD dwSwitchSize, LPDWORD pdwType) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetInstalledSize(LPDWORD pdwWin, LPDWORD pdwApp) { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetDownloadSize() { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetExtractSize() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetSuccessKey(LPSTR pszKey, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetProgressKeys(LPSTR pszProgress, DWORD dwProgSize, LPSTR pszCancel, DWORD dwCancelSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::IsActiveSetupAware() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::IsRebootRequired() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::RequiresAdminRights() { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetPriority() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetDependency(UINT uDepNum, LPSTR pszID, DWORD dwBuf, char *pchType, LPDWORD pdwVer, LPDWORD pdwBuild) { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetPlatform() { return E_NOTIMPL; }
STDMETHODIMP_(BOOL) CComponentDetection::DisableComponent() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetMode(UINT uModeNum, LPSTR pszMode, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetGroup(LPSTR pszID, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::IsUIVisible() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetPatchID(LPSTR pszID, DWORD dwSize) { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::GetTreatAsOneComponents(UINT uNum, LPSTR pszID, DWORD dwBuf) { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetCurrentPriority() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::SetCurrentPriority(DWORD dwPriority) { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetActualDownloadSize() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::IsComponentDownloaded() { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::IsThisVersionInstalled(DWORD dwAskVer, DWORD dwAskBld, LPDWORD pdwVersion, LPDWORD pdwBuild) { return E_NOTIMPL; }
STDMETHODIMP_(DWORD) CComponentDetection::GetInstallQueueState() { return E_NOTIMPL; }
STDMETHODIMP CComponentDetection::SetInstallQueueState(DWORD dwState) { return E_NOTIMPL; }
LPCSTR ParseField(LPCSTR pszStr, LPSTR pszTokOut, int cTokSize) { LPCSTR pszRetVal = NULL; LPSTR p; LPSTR p2;
if (pszStr == NULL || *pszStr == '\0') { pszTokOut[0] = '\0'; return NULL; }
// look for a comma separator
p = strstr(pszStr, ","); if (p != NULL) { int l = p - pszStr; if (l >= cTokSize) l = cTokSize - 1;
strncpy(pszTokOut, pszStr, l); pszTokOut[l] = '\0'; pszRetVal = p + 1; } else { strncpy(pszTokOut, pszStr, cTokSize - 1); }
//strip spaces
p = pszTokOut; p2 = pszTokOut; while (*p2) { if (*p2 != ' ') *p++ = *p2++; else p2++; } *p = '\0';
return pszRetVal; }
static int CompareLocales(LPCSTR pszLoc1, LPCSTR pszLoc2) { if (pszLoc1[0] == '*' || pszLoc2[0] == '*') return 0; else return _stricmp(pszLoc1, pszLoc2); }
void ConvertVersionStrToDwords(LPCTSTR pszVer, LPDWORD pdwVer, LPDWORD pdwBuild) { USES_CONVERSION;
DWORD dwTemp1,dwTemp2; LPCSTR pszParse = T2A(pszVer); char szBuf[20];
pszParse = ParseField(pszParse, szBuf, sizeof(szBuf)); dwTemp1 = atoi(szBuf); pszParse = ParseField(pszParse, szBuf, sizeof(szBuf)); dwTemp2 = atoi(szBuf);
*pdwVer = (dwTemp1 << 16) + dwTemp2;
pszParse = ParseField(pszParse, szBuf, sizeof(szBuf)); dwTemp1 = atoi(szBuf); pszParse = ParseField(pszParse, szBuf, sizeof(szBuf)); dwTemp2 = atoi(szBuf);
*pdwBuild = (dwTemp1 << 16) + dwTemp2; }
BOOL UninstallKeyExists(LPCSTR pszUninstallKey) { USES_CONVERSION;
HKEY hUninstallKey = NULL; TCHAR szUninstallKey[MAX_PATH]; if (!pszUninstallKey) //if the pointer is NULL, assume installed
return TRUE; lstrcpy(szUninstallKey, UNINSTALL_BRANCH); lstrcat(szUninstallKey, _T("\\")); lstrcat(szUninstallKey, A2T(pszUninstallKey)); if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szUninstallKey, 0, KEY_READ, &hUninstallKey) == ERROR_SUCCESS) { RegCloseKey(hUninstallKey); return TRUE; } else return FALSE; }
//reterives file version
BOOL GetFileVersionDwords(LPCTSTR pszFilename, LPDWORD pdwMSVer, LPDWORD pdwLSVer) { BOOL bRetVal = FALSE; DWORD dwHandle; DWORD dwVerInfoSize = GetFileVersionInfoSize((LPTSTR)pszFilename, &dwHandle); if (dwVerInfoSize) { LPVOID lpBuffer = LocalAlloc(LPTR, dwVerInfoSize); if (lpBuffer) { // Read version stamping info
if (GetFileVersionInfo((LPTSTR)pszFilename, dwHandle, dwVerInfoSize, lpBuffer)) { // Get the value for Translation
UINT uiSize; VS_FIXEDFILEINFO* lpVSFixedFileInfo;
if (VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize)) { *pdwMSVer = lpVSFixedFileInfo->dwFileVersionMS; *pdwLSVer = lpVSFixedFileInfo->dwFileVersionLS; bRetVal = TRUE; } } LocalFree(lpBuffer); } }
if (!bRetVal) { *pdwMSVer = *pdwLSVer = 0L; } return bRetVal; }
|