///////////////////////////////////////////////////////////////////////////// // WUDetect.cpp // // Copyright (C) Microsoft Corp. 1998 // All rights reserved // ///////////////////////////////////////////////////////////////////////////// // // Description: // DLL loaded by the install engine that exposes entry points // that can determines the installation status of legacy or complex // components. The dll name and entry points are specified for a // component in the CIF file. ///////////////////////////////////////////////////////////////////////////// #include "wudetect.h" //#include //#include //#include //#include //#include //#include //#include //#include //#include //#include ///////////////////////////////////////////////////////////////////////////// // dwKeyType // Determines the registry root (HKLM, HKCU, etc) that the key lies under. // // Parameters: // // Comments : ///////////////////////////////////////////////////////////////////////////// inline DWORD dwKeyType(TCHAR *szBuf, HKEY *phKey, TCHAR * szKeyName, DWORD dwSize) { DWORD dwStatus = ERROR_SUCCESS; TCHAR szRootType[MAX_PATH]; if ( (GetStringField2(szBuf, 0, szRootType, sizeof(szRootType)/sizeof(TCHAR)) == 0) || (GetStringField2(szBuf, 1, szKeyName, dwSize) == 0) ) { dwStatus = ERROR_BADKEY; } else if ( lstrcmpi(HKEY_LOCAL_MACHINE_ROOT, szRootType) == 0 ) { *phKey = HKEY_LOCAL_MACHINE; } else if ( lstrcmpi(HKEY_CURRENT_USER_ROOT, szRootType) == 0 ) { *phKey = HKEY_CURRENT_USER; } else if ( lstrcmpi(HKEY_CLASSES_ROOT_ROOT, szRootType) == 0 ) { *phKey = HKEY_CLASSES_ROOT; } else if ( lstrcmpi(HKEY_CURRENT_CONFIG_ROOT, szRootType) == 0 ) { *phKey = HKEY_CURRENT_CONFIG; } else if ( lstrcmpi(HKEY_USERS_ROOT, szRootType) == 0 ) { *phKey = HKEY_USERS; } else if ( lstrcmpi(HKEY_PERFORMANCE_DATA_ROOT, szRootType) == 0 ) { *phKey = HKEY_PERFORMANCE_DATA; } else if ( lstrcmpi(HKEY_DYN_DATA_ROOT, szRootType) == 0 ) { *phKey = HKEY_DYN_DATA; } else { dwStatus = ERROR_BADKEY; } return dwStatus; } ///////////////////////////////////////////////////////////////////////////// // dwParseValue // // Parses out the registry key name, value, and type that needs to // be opened to determine the installation status of the component. ///////////////////////////////////////////////////////////////////////////// inline DWORD dwParseValue(TCHAR * szBuf, TargetRegValue & targetValue) { DWORD dwStatus = ERROR_BADKEY; TCHAR szType[MAX_PATH]; // BUGBUG - get real value TCHAR szValue[MAX_PATH]; // BUGBUG - get real value // get the data type if ( (GetStringField2(szBuf, 0, targetValue.szName, sizeof(targetValue.szName)/sizeof(TCHAR)) != 0) && (GetStringField2(szBuf, 1, szType, sizeof(szType)/sizeof(TCHAR)) != 0) ) { if ( lstrcmpi(REG_NONE_TYPE, szType) == 0 ) { targetValue.type = REG_NONE; dwStatus = ERROR_SUCCESS; } else { if ( GetStringField2(szBuf, 2, szValue, sizeof(szValue)/sizeof(TCHAR)) != 0 ) { if ( lstrcmpi(REG_DWORD_TYPE, szType) == 0 ) { targetValue.type = REG_DWORD; targetValue.dw = _ttol(szValue); dwStatus = ERROR_SUCCESS; } else if ( lstrcmpi(REG_SZ_TYPE, szType) == 0 ) { targetValue.type = REG_SZ; lstrcpy(targetValue.sz, szValue); dwStatus = ERROR_SUCCESS; } } } } return dwStatus; } ///////////////////////////////////////////////////////////////////////////// // fCompareVersion // // Returns: 1,0,-1 depending on whether dwVersion1 is greater than, equal, or // less than dwVersion2. ///////////////////////////////////////////////////////////////////////////// inline int nCompareVersion(IN DWORD dwVer1, IN DWORD dwBuild1, IN DWORD dwVer2, IN DWORD dwBuild2) { int nResult = 0; if ( dwVer1 > dwVer2 ) { nResult = 1; } else if ( dwVer1 < dwVer2 ) { nResult = -1; } else if ( dwBuild1 > dwBuild2 ) // dwVer1 == dwVer2 { nResult = 1; } else if ( dwBuild1 < dwBuild2 ) // dwVer1 == dwVer2 { nResult = -1; } return nResult; } ///////////////////////////////////////////////////////////////////////////// // GetCifEntry // Get an entry from the CIF file. // // Comments : // We get the value differently depending on whether we are being // called by IE 4 or IE 5 Active Setup. ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // // Function FGetCifEntry //--------------------------------------------------------------------------- // // Return Value --- TRUE if Successfully retrieved CIF file value // FALSE if failed // Parameter // TCHAR* pszParamName --- [IN] Name of the CIF file // TCHAR* pszParamValue --- [OUT] Value of the CIF file // DWORD cbParamValue --- size of the pszParamValue in TCHAR // NOTE: This function calls GetCustomData to retrieve the value of CIF file // GetCustomData is defined in inseng.h which takes only ANSI strings. // Thus, UNICODE version of this function needed to convert parameters // to and from ANSI compatibles. // NOTE: This is a global function. Don't mixed with member function of // CExpressionParser::fGetCifEntry // ///////////////////////////////////////////////////////////////////////////// // // Modified by RogerJ, 03/09/00 // Original Creator Unknown (YanL?) // Modification --- UNICODE and Win64 enabled // ///////////////////////////////////////////////////////////////////////////// inline bool FGetCifEntry(DETECTION_STRUCT* pDetection, TCHAR *pszParamName, TCHAR *pszParamValue, DWORD cbParamValue) // pszParamName is [IN], pszParamValue is [OUT], the function GetCustomData requires // LPSTR for both parameters, string conversion is necessary in the UNICODE case { #ifdef UNICODE bool fSucceed; char pszParamNameANSI[MAX_PATH]; char pszParamValueANSI[MAX_PATH]; // do UNICODE to ANSI string conversion // only pszParamName [IN] parameter need to be converted // wcstombs and mbstowcs do not ensure the last character is NULL // ensure manually wcstombs(pszParamNameANSI,pszParamName,MAX_PATH-1); pszParamNameANSI[MAX_PATH-1]=NULL; // make actual function call fSucceed= (ERROR_SUCCESS == pDetection->pCifComp->GetCustomData(pszParamNameANSI, pszParamValueANSI, cbParamValue)); // do ANSI to UNICODE string conversion // only pszParamValue [OUT] parameter need to be converted mbstowcs(pszParamValue,pszParamValueANSI,cbParamValue-1); pszParamValue[cbParamValue-1]=(TCHAR)NULL; return fSucceed; #else return (ERROR_SUCCESS == pDetection->pCifComp->GetCustomData(pszParamName, pszParamValue, cbParamValue)); #endif } ///////////////////////////////////////////////////////////////////////////// // RegKeyExists (EXPORT) // This API will determine if an application exists based on the // existence of a registry key and perhaps a value. // // Parameters: // // Comments : ///////////////////////////////////////////////////////////////////////////// DWORD WINAPI RegKeyExists(DETECTION_STRUCT *pDetection) { DWORD dwInstallStatus = DET_NOTINSTALLED; HKEY hKeyRoot; HKEY hKey; DWORD type; TCHAR szTargetKeyName[MAX_PATH]; TCHAR szTargetKeyValue[MAX_PATH]; TCHAR szBuf[MAX_PATH]; DWORD dwStatus; //DWORD dwLen; // make sure the struct is of the expected size if ( (pDetection->dwSize >= sizeof(DETECTION_STRUCT)) ) { // get the registry key name from the components section of the // CIF file. if ( FGetCifEntry(pDetection, DETREG_KEY, szBuf, sizeof(szBuf)/sizeof(TCHAR)) ) { if ( (dwStatus = dwKeyType(szBuf, &hKeyRoot, szTargetKeyName, sizeof(szTargetKeyName)/sizeof(TCHAR))) == ERROR_SUCCESS ) { // determine if we should log transmissions if ( RegOpenKeyEx( hKeyRoot, szTargetKeyName, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { if ( FGetCifEntry(pDetection, DETREG_VALUE, szTargetKeyValue, sizeof(szTargetKeyValue)/sizeof(TCHAR)) ) { TargetRegValue targetValue; dwStatus = dwParseValue(szTargetKeyValue, targetValue); if ( dwStatus == ERROR_SUCCESS ) { ActualKeyValue keyvalue; DWORD size = sizeof(keyvalue); if ( RegQueryValueEx(hKey, targetValue.szName, 0, &type, (BYTE *)&keyvalue, &size) == ERROR_SUCCESS ) { switch ( targetValue.type ) { case REG_NONE: { dwInstallStatus = DET_INSTALLED; break; } case REG_DWORD: { if ( (type == REG_DWORD) || ((type == REG_BINARY) && (size >= sizeof(DWORD))) ) { // see if we have a match if ( targetValue.dw == keyvalue.dw ) { *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; dwInstallStatus = DET_INSTALLED; } } break; } case REG_SZ: { if ( type == REG_SZ ) { if ( lstrcmpi(targetValue.sz, keyvalue.sz) == 0 ) { *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; dwInstallStatus = DET_INSTALLED; } } break; } } // switch } } } else { // no REG value so, REGPATH is sufficient to determine // installation. *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; dwInstallStatus = DET_INSTALLED; } RegCloseKey(hKey); } } } } return dwInstallStatus; } ///////////////////////////////////////////////////////////////////////////// // RegKeyVersion (EXPORT) // // This API will determine if an application exists based on the // existence of a version number in the registry. ///////////////////////////////////////////////////////////////////////////// DWORD WINAPI RegKeyVersion(DETECTION_STRUCT *pDetection) { DWORD dwInstallStatus = DET_NOTINSTALLED; HKEY hKeyRoot; HKEY hKey; DWORD type; TCHAR szTargetKeyName[MAX_PATH]; TCHAR szTargetKeyValue[MAX_PATH]; TCHAR szAskVersion[MAX_PATH]; //TCHAR szVersion[MAX_VERSION_STRING_LEN]; TCHAR szBuf[MAX_PATH]; //DWORD dwStatus; //DWORD dwLen; DWORD dwVer; DWORD dwBuild; DWORD dwAskVer; DWORD dwAskBuild; // make sure the struct is of the expected size if ( pDetection->dwSize < sizeof(DETECTION_STRUCT) ) { goto cleanup; } // get the registry key name from the components section of the // CIF file. if ( FGetCifEntry(pDetection, DETREG_KEY, szBuf, sizeof(szBuf)/sizeof(TCHAR)) && (dwKeyType(szBuf, &hKeyRoot, szTargetKeyName, sizeof(szTargetKeyName)/sizeof(TCHAR)) == ERROR_SUCCESS) ) { if ( RegOpenKeyEx( hKeyRoot, szTargetKeyName, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { if ( FGetCifEntry(pDetection, DETREG_VERSION, szBuf, sizeof(szBuf)/sizeof(TCHAR)) && (GetStringField2(szBuf, 0, szTargetKeyValue, sizeof(szTargetKeyValue)/sizeof(TCHAR)) != 0) ) { DWORD size = sizeof(szBuf); if (GetStringField2(szBuf, 1, szAskVersion, sizeof(szAskVersion)/sizeof(TCHAR)) != 0) { fConvertDotVersionStrToDwords(szAskVersion, &dwAskVer, &dwAskBuild); } else { dwAskVer = pDetection->dwAskVer; dwAskBuild = pDetection->dwAskBuild; } if ( RegQueryValueEx(hKey, szTargetKeyValue, 0, &type, (BYTE *)szBuf, &size) == ERROR_SUCCESS ) { if ( type == REG_SZ ) { fConvertDotVersionStrToDwords(szBuf, &dwVer, &dwBuild); if ( nCompareVersion(dwVer, dwBuild, dwAskVer, dwAskBuild) >= 0 ) { *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; dwInstallStatus = DET_INSTALLED; } } } } RegCloseKey(hKey); } } cleanup: return dwInstallStatus; } ///////////////////////////////////////////////////////////////////////////// // RegKeySubStr (EXPORT) // // This API will determine if an application exists based on the // existence of one of a number of sub strings in the data. ///////////////////////////////////////////////////////////////////////////// DWORD WINAPI RegKeySubStr(DETECTION_STRUCT *pDetection) { DWORD dwInstallStatus = DET_NOTINSTALLED; HKEY hKeyRoot; HKEY hKey; DWORD type; TCHAR szTargetKeyName[MAX_PATH]; TCHAR szTargetKeyValue[MAX_PATH]; TCHAR szKeyMissingStatus[MAX_PATH]; TCHAR szData[MAX_PATH]; TCHAR szSubStr[MAX_PATH]; //TCHAR szTmp[MAX_PATH]; TCHAR szBuf[MAX_PATH]; //DWORD dwStatus; //DWORD dwLen; //DWORD dwVer; //DWORD dwBuild; // make sure the struct is of the expected size if ( pDetection->dwSize < sizeof(DETECTION_STRUCT) ) { goto cleanup; } // get the registry key name from the components section of the // CIF file. if ( FGetCifEntry(pDetection, DETREG_KEY, szBuf, sizeof(szBuf)/sizeof(TCHAR)) && (dwKeyType(szBuf, &hKeyRoot, szTargetKeyName, sizeof(szTargetKeyName)/sizeof(TCHAR)) == ERROR_SUCCESS) ) { if ( RegOpenKeyEx( hKeyRoot, szTargetKeyName, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { if ( FGetCifEntry(pDetection, DETREG_SUBSTR, szBuf, sizeof(szBuf)/sizeof(TCHAR)) && (GetStringField2(szBuf, 0, szTargetKeyValue, sizeof(szTargetKeyValue)/sizeof(TCHAR)) != 0) && (GetStringField2(szBuf, 1, szKeyMissingStatus, sizeof(szKeyMissingStatus)/sizeof(TCHAR)) != 0) ) { DWORD size = sizeof(szData); if ( RegQueryValueEx(hKey, szTargetKeyValue, 0, &type, (BYTE *)szData, &size) == ERROR_SUCCESS ) { if ( type == REG_SZ ) { _tcslwr(szData); // iterate thru the substrings looking for a match. int index = 2; while ( GetStringField2(szBuf, index, szSubStr, sizeof(szSubStr)/sizeof(TCHAR)) != 0 ) { _tcslwr(szSubStr); if ( _tcsstr(szData, szSubStr) != NULL ) { *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; dwInstallStatus = DET_INSTALLED; goto quit_while; } index++; } quit_while:; } } else { // if we get an error, assume the key does not exist. Note that if // the status is DETFIELD_NOT_INSTALLED then we don't have to do // anything since that is the default status. if ( lstrcmpi(DETFIELD_INSTALLED, szKeyMissingStatus) == 0 ) { dwInstallStatus = DET_INSTALLED; } } } RegCloseKey(hKey); } } cleanup: return dwInstallStatus; } ///////////////////////////////////////////////////////////////////////////// // MinFileVersion (EXPORT) // This API will determine if an application exists based on the // minimum version of a file. // // Parameters: // // Comments : ///////////////////////////////////////////////////////////////////////////// DWORD WINAPI MinFileVersion(DETECTION_STRUCT *pDetection) { DWORD dwInstallStatus = DET_INSTALLED; TCHAR szDllName[MAX_PATH]; TCHAR szVersion[MAX_PATH]; DWORD dwSize; DWORD dwHandle; TCHAR *pszVerInfo[MAX_PATH]; VS_FIXEDFILEINFO *vsVerInfo; UINT uLen; // make sure the struct is of the expected size if ( pDetection->dwSize >= sizeof(DETECTION_STRUCT) ) { // get the dll name and version from the components section of the // CIF file. if ( FGetCifEntry(pDetection, DETREG_KEY, szDllName, sizeof(szDllName)/sizeof(TCHAR)) ) { if ( FGetCifEntry(pDetection, DETREG_VALUE, szVersion, sizeof(szVersion)/sizeof(TCHAR)) ) { PTSTR pszPoint = szDllName; PTSTR pszPoint2 = szDllName; TCHAR szNewDllName[MAX_PATH]; while (*pszPoint != '\0') { if (*pszPoint == '%') { *pszPoint = '\0'; pszPoint += 1; pszPoint2 = pszPoint; while (pszPoint2 != '\0') { if (*pszPoint2 == '%') { *pszPoint2 = '\0'; pszPoint2 += 1; break; } pszPoint2 += 1; } break; } pszPoint += 1; } if (lstrcmpi(pszPoint, TEXT("11")) == 0) { TCHAR szSystemDir[MAX_PATH]; GetSystemDirectory(szSystemDir, sizeof(szSystemDir)/sizeof(TCHAR)); lstrcpy(szNewDllName, szSystemDir); if ((lstrlen(szSystemDir) + lstrlen(pszPoint2)) < sizeof(szNewDllName)/sizeof(TCHAR)) { lstrcat(szNewDllName, pszPoint2); } } dwSize = GetFileVersionInfoSize(szNewDllName, &dwHandle); if (dwSize > 0) { if(dwSize > MAX_PATH) dwSize = MAX_PATH; GetFileVersionInfo(szNewDllName, dwHandle, dwSize, &pszVerInfo); VerQueryValue(&pszVerInfo, TEXT("\\"), (void **) &vsVerInfo, &uLen); DWORD dwDllVersion[4]; DWORD dwCheckVersion[4]; dwDllVersion[0] = HIWORD(vsVerInfo->dwProductVersionMS); dwDllVersion[1] = LOWORD(vsVerInfo->dwProductVersionMS); dwDllVersion[2] = HIWORD(vsVerInfo->dwProductVersionLS); dwDllVersion[3] = LOWORD(vsVerInfo->dwProductVersionLS); pszPoint = szVersion; pszPoint2 = szVersion; INT i = 0; while (*pszPoint != '\0') { if (*pszPoint == ',') { *pszPoint = '\0'; dwCheckVersion[i] = _ttol(pszPoint2); i += 1; pszPoint2 = pszPoint + 1; } pszPoint += 1; } dwCheckVersion[i] = _ttol(pszPoint2); for (i = 0; i < 4; i += 1) { if (dwDllVersion[i] < dwCheckVersion[i]) { dwInstallStatus = DET_NOTINSTALLED; } } } else { dwInstallStatus = DET_NOTINSTALLED; } *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; } } } return dwInstallStatus; } ///////////////////////////////////////////////////////////////////////////// // Expression (EXPORT) // // This API will evaluate a boolean expression where every operand is a // detection operation. ///////////////////////////////////////////////////////////////////////////// const DWORD MAX_EXPRESSION_LEN = 1024; DWORD WINAPI Expression(DETECTION_STRUCT *pDetection) { DWORD dwInstallStatus = DET_NOTINSTALLED; //HKEY hKeyRoot; //HKEY hKey; //DWORD type; //TCHAR szTargetKeyName[MAX_PATH]; //TCHAR szTargetKeyValue[MAX_PATH]; //TCHAR szKeyMissingStatus[MAX_PATH]; //TCHAR szData[MAX_PATH]; //TCHAR szSubStr[MAX_PATH]; //TCHAR szTmp[MAX_PATH]; TCHAR szExpression[MAX_EXPRESSION_LEN]; //DWORD dwStatus; //DWORD dwLen; //DWORD dwVer; //DWORD dwBuild; // make sure the struct is of the expected size if ( pDetection->dwSize < sizeof(DETECTION_STRUCT) ) { goto cleanup; } // get the expression. if ( FGetCifEntry(pDetection, DET_EXPRESSION, szExpression, sizeof(szExpression)/sizeof(TCHAR)) ) { CExpressionParser expression(pDetection); bool fResult = TRUE; HRESULT hr = expression.fEvalExpression(szExpression, &fResult); if ( SUCCEEDED(hr) && fResult) { *pDetection->pdwInstalledVer = 1; *pDetection->pdwInstalledBuild = 1; dwInstallStatus = DET_INSTALLED; } } cleanup: return dwInstallStatus; }