298 lines
8.5 KiB
C++
298 lines
8.5 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// HCDetect.cpp
|
|
//
|
|
// Copyright (C) Microsoft Corp. 1999
|
|
// 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 <atlbase.h>
|
|
#include "hcdetect.h"
|
|
#include <initguid.h>
|
|
|
|
//
|
|
// From HelpServiceTypeLib.idl
|
|
//
|
|
#include <HelpServiceTypeLib.h>
|
|
#include <HelpServiceTypeLib_i.c>
|
|
|
|
//
|
|
// Defines
|
|
//
|
|
#define IsDigit(c) ((c) >= '0' && (c) <= '9')
|
|
#define MAX_ID 1024
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT getVersion( BSTR bstrVendorID ,
|
|
BSTR bstrProductID ,
|
|
CComBSTR& bstrValue )
|
|
{
|
|
TCHAR szWinDir[MAX_PATH];
|
|
CComVariant cvVersionPathname;
|
|
CComPtr <IXMLDOMDocument> pXMLDoc;
|
|
CComPtr <IXMLDOMElement> pXMLRootElem;
|
|
CComPtr <IXMLDOMNode> pXMLVersionNode;
|
|
|
|
//
|
|
// get windows directory
|
|
//
|
|
if(::GetWindowsDirectory( szWinDir, MAX_PATH ) == 0)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
_tcscat( szWinDir, "\\pchealth\\helpctr\\config\\pchver.xml" );
|
|
|
|
if(SUCCEEDED(::CoCreateInstance( CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pXMLDoc )))
|
|
{
|
|
CComVariant cvVersionPathname = szWinDir;
|
|
VARIANT_BOOL vBool;
|
|
|
|
if(SUCCEEDED(pXMLDoc->load( cvVersionPathname, &vBool )) && vBool == VARIANT_TRUE)
|
|
{
|
|
if(SUCCEEDED(pXMLDoc->get_documentElement( &pXMLRootElem )) && pXMLRootElem)
|
|
{
|
|
CComBSTR bstrQuery;
|
|
|
|
bstrQuery.Append( "VENDORS/VENDOR[@ID=\"" );
|
|
bstrQuery.Append( bstrVendorID );
|
|
bstrQuery.Append( "\"]/PRODUCT[@ID=\"" );
|
|
bstrQuery.Append( bstrProductID );
|
|
bstrQuery.Append( "\"]/VERSION" );
|
|
|
|
if(SUCCEEDED(pXMLRootElem->selectSingleNode( bstrQuery, &pXMLVersionNode )))
|
|
{
|
|
CComQIPtr<IXMLDOMElement> elem = pXMLVersionNode;
|
|
CComVariant vValue;
|
|
|
|
if(elem && SUCCEEDED(elem->getAttribute( CComBSTR("VALUE"), &vValue )))
|
|
{
|
|
vValue.ChangeType( VT_BSTR );
|
|
bstrValue = vValue.bstrVal;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 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;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ConvertDotVersionStrToDwords
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
bool fConvertDotVersionStrToDwords(LPSTR pszVer, LPDWORD pdwVer, LPDWORD pdwBuild)
|
|
{
|
|
DWORD grVerFields[4] = {0,0,0,0};
|
|
char *pch = pszVer;
|
|
|
|
if (!pszVer || !pdwVer || !pdwBuild)
|
|
return false;
|
|
|
|
grVerFields[0] = atol(pch);
|
|
|
|
for ( int index = 1; index < 4; index++ )
|
|
{
|
|
while ( IsDigit(*pch) && (*pch != '\0') )
|
|
pch++;
|
|
|
|
if ( *pch == '\0' )
|
|
break;
|
|
pch++;
|
|
|
|
grVerFields[index] = atol(pch);
|
|
}
|
|
|
|
*pdwVer = (grVerFields[0] << 16) + grVerFields[1];
|
|
*pdwBuild = (grVerFields[2] << 16) + grVerFields[3];
|
|
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 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.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool FGetCifEntry(DETECTION_STRUCT *pDetection,
|
|
char *pszParamName,
|
|
char *pszParamValue,
|
|
DWORD cbParamValue)
|
|
{
|
|
return (ERROR_SUCCESS == pDetection->pCifComp->GetCustomData(pszParamName,
|
|
pszParamValue,
|
|
cbParamValue));
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 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 HelpPkgVersion(DETECTION_STRUCT *pDetection)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
DWORD dwInstallStatus = DET_INSTALLED;
|
|
TCHAR szVendorID[MAX_ID];
|
|
TCHAR szProductID[MAX_ID];
|
|
TCHAR szVersion[MAX_PATH];
|
|
IPCHUpdate *pPCHUpdate = NULL;
|
|
|
|
//
|
|
// Initialize COM just in case
|
|
//
|
|
::CoInitialize(NULL);
|
|
|
|
//
|
|
// make sure the struct is of the expected size
|
|
//
|
|
if ((pDetection->dwSize >= sizeof(DETECTION_STRUCT)))
|
|
{
|
|
CComBSTR bstrLatestVersion;
|
|
DWORD dwCurrVersion, dwCurrBuild;
|
|
DWORD dwLatestVersion, dwLatestBuild;
|
|
|
|
//
|
|
// get the version number from the components section of the CIF file.
|
|
//
|
|
if (!((FGetCifEntry(pDetection, "VendorID", szVendorID, sizeof(szVendorID))) &&
|
|
(FGetCifEntry(pDetection, "ProductID", szProductID, sizeof(szProductID))) &&
|
|
(FGetCifEntry(pDetection, "Version", szVersion, sizeof(szVersion)))))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Convert it to build and version number
|
|
//
|
|
fConvertDotVersionStrToDwords(szVersion, &dwCurrVersion, &dwCurrBuild);
|
|
|
|
// //
|
|
// // create the IPCHUpdate object
|
|
// //
|
|
// if (FAILED(hr = CoCreateInstance(CLSID_PCHUpdate, NULL, CLSCTX_LOCAL_SERVER, IID_IPCHUpdate, (void**)&pPCHUpdate)))
|
|
// {
|
|
// goto end;
|
|
// }
|
|
//
|
|
// //
|
|
// // call to get the version number
|
|
// //
|
|
// if (FAILED(pPCHUpdate->LatestVersion(CComBSTR(szVendorID), CComBSTR(szProductID), &bstrLatestVersion)))
|
|
// {
|
|
// goto end;
|
|
// }
|
|
if(FAILED(getVersion( CComBSTR( szVendorID ), CComBSTR( szProductID ), bstrLatestVersion )))
|
|
{
|
|
dwInstallStatus = DET_NOTINSTALLED;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// check if there is a version number, if not, return as not installed
|
|
//
|
|
if (bstrLatestVersion.Length() == 0)
|
|
{
|
|
dwInstallStatus = DET_NOTINSTALLED;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Convert it to build and version number
|
|
//
|
|
fConvertDotVersionStrToDwords(OLE2A(bstrLatestVersion), &dwLatestVersion, &dwLatestBuild);
|
|
|
|
//
|
|
// Compare versions, recommend that it is not installed only if current version
|
|
// is greater than latest version installed on the client machine
|
|
//
|
|
if (nCompareVersion(dwCurrVersion, dwCurrBuild, dwLatestVersion, dwLatestBuild) == 1)
|
|
{
|
|
dwInstallStatus = DET_NOTINSTALLED;
|
|
}
|
|
}
|
|
|
|
end:
|
|
//
|
|
// Cleanup
|
|
//
|
|
if (pPCHUpdate)
|
|
pPCHUpdate->Release();
|
|
|
|
::CoUninitialize();
|
|
|
|
return dwInstallStatus;
|
|
}
|
|
|
|
//DWORD WINAPI Test()
|
|
//{
|
|
// CComBSTR bstrVendorID = "CN=Microsoft Corporation,L=Redmond,S=Washington,C=US";
|
|
// CComBSTR bstrProductID = "Microsoft Core Help Center Content";
|
|
// CComBSTR bstrValue;
|
|
// HRESULT hr;
|
|
//
|
|
// ::CoInitialize(NULL);
|
|
//
|
|
// hr = getVersion( bstrVendorID, bstrProductID, bstrValue );
|
|
//
|
|
// ::CoUninitialize();
|
|
//
|
|
// return hr;
|
|
//}
|