Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1058 lines
26 KiB

// ClientCaps.cpp : Implementation of CClientCaps
#include "headers.h"
#pragma MARK_DATA(__FILE__)
#pragma MARK_CODE(__FILE__)
#pragma MARK_CONST(__FILE__)
#include "iextag.h"
#include "ccaps.h"
typedef HRESULT STDAPICALLTYPE SHOWHTMLDIALOGFN (HWND hwndParent, IMoniker *pmk,
VARIANT *pvarArgIn, WCHAR* pchOptions,
VARIANT *pvArgOut);
#define REGKEY_ACTIVESETUP "Software\\Microsoft\\Active Setup"
/////////////////////////////////////////////////////////////////////////////
// CClientCaps
STDMETHODIMP CClientCaps::get_javaEnabled(VARIANT_BOOL * pVal)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->javaEnabled(pVal);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_cookieEnabled(VARIANT_BOOL * pVal)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_cookieEnabled(pVal);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_cpuClass(BSTR * p)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_cpuClass(p);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_systemLanguage(BSTR * p)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_systemLanguage(p);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_userLanguage(BSTR * p)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_userLanguage(p);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_platform(BSTR * p)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_platform(p);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_connectionSpeed(long * p)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_connectionSpeed(p);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_onLine(VARIANT_BOOL *p)
{
IOmNavigator *pClientInformation;
HRESULT hr = GetClientInformation(&pClientInformation);
if (SUCCEEDED(hr))
{
hr = pClientInformation->get_onLine(p);
pClientInformation->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_colorDepth(long * p)
{
IHTMLScreen *pScreen;
HRESULT hr = GetScreen(&pScreen);
if (SUCCEEDED(hr))
{
hr = pScreen->get_colorDepth(p);
pScreen->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_bufferDepth(long * p)
{
IHTMLScreen *pScreen;
HRESULT hr = GetScreen(&pScreen);
if (SUCCEEDED(hr))
{
hr = pScreen->get_bufferDepth(p);
pScreen->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_width(long * p)
{
IHTMLScreen *pScreen;
HRESULT hr = GetScreen(&pScreen);
if (SUCCEEDED(hr))
{
hr = pScreen->get_width(p);
pScreen->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_height(long * p)
{
IHTMLScreen *pScreen;
HRESULT hr = GetScreen(&pScreen);
if (SUCCEEDED(hr))
{
hr = pScreen->get_height(p);
pScreen->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_availHeight(long * p)
{
IHTMLScreen *pScreen;
HRESULT hr = GetScreen(&pScreen);
if (SUCCEEDED(hr))
{
hr = pScreen->get_availHeight(p);
pScreen->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_availWidth(long * p)
{
IHTMLScreen *pScreen;
HRESULT hr = GetScreen(&pScreen);
if (SUCCEEDED(hr))
{
hr = pScreen->get_availWidth(p);
pScreen->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::get_connectionType(BSTR *pbstr)
{
DWORD dwFlags = 0;
BOOL bConnected;
HRESULT hr = S_OK;
DWORD dwState = 0;
DWORD dwSize = sizeof(dwState);
BOOL bGlobalOffline = FALSE ; // Has the user gone into offline mode, inspite of having a connection.
if (InternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
{
if (dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
bGlobalOffline = TRUE;
}
bConnected = InternetGetConnectedStateEx(&dwFlags, NULL, 0, 0);
// NOTE: We use literal strings in code and resources so these don't get localized.
if (bConnected && !bGlobalOffline)
{
// If we are connected figure out how.
if (dwFlags & INTERNET_CONNECTION_MODEM )
{
*pbstr = SysAllocString(L"modem");
}
else if (dwFlags & INTERNET_CONNECTION_LAN )
{
*pbstr = SysAllocString(L"lan");
}
else
{
// Don't know what to do here.
*pbstr = SysAllocString(L"");
hr = S_FALSE;
}
}
else
{
*pbstr = SysAllocString(L"offline");
}
if (!*pbstr)
hr = E_OUTOFMEMORY;
return hr;
}
STDMETHODIMP CClientCaps::isComponentInstalled(BSTR bstrName, BSTR bstrType, BSTR bstrVersion, VARIANT_BOOL *pVal)
{
if (pVal == NULL)
{
return E_POINTER;
}
DWORD dwVersionMS;
DWORD dwVersionLS;
HRESULT hr = GetVersion(bstrName, bstrType, &dwVersionMS, &dwVersionLS);
HRESULT hrRet;
if (hr == S_OK)
{
if (bstrVersion && bstrVersion[0] != L'\0')
{
// User wants us to check for minimum version number.
DWORD dwVersionReqdMS;
DWORD dwVersionReqdLS;
hr = GetVersionFromString(bstrVersion, &dwVersionReqdMS, &dwVersionReqdLS);
if (SUCCEEDED(hr))
{
if ( (dwVersionMS > dwVersionReqdMS) ||
(dwVersionMS == dwVersionReqdMS && dwVersionLS >= dwVersionReqdLS)
)
{
*pVal = TRUE;
}
else
{
*pVal = FALSE;
}
hrRet = S_OK;
}
else
{
*pVal = FALSE;
hrRet = S_FALSE;
}
}
else
{
*pVal = TRUE;
hrRet = S_OK;
}
}
else if (hr == S_FALSE)
{
*pVal = FALSE;
hrRet = S_OK;
}
else
{
// This is really an error, but to avoid script error dialogs we still return a success
// code, but indicate that the component is not installed.
*pVal = FALSE;
hrRet = S_FALSE;
}
return hrRet;
}
STDMETHODIMP CClientCaps::getComponentVersion(BSTR bstrName, BSTR bstrType, BSTR* pbstrVersion)
{
if (pbstrVersion == NULL)
return E_POINTER;
DWORD dwVersionMS;
DWORD dwVersionLS;
HRESULT hr = GetVersion(bstrName, bstrType, &dwVersionMS, &dwVersionLS);
if (hr == S_OK)
{
hr = GetStringFromVersion(dwVersionMS, dwVersionLS, pbstrVersion);
}
else
{
*pbstrVersion = SysAllocString(L"");
hr = S_OK;
}
return hr;
}
STDMETHODIMP CClientCaps::compareVersions(BSTR bstrVer1, BSTR bstrVer2, long *p)
{
if ( p == NULL)
return E_POINTER;
HRESULT hr = S_OK;
if (bstrVer1 == NULL || bstrVer2 == NULL)
{
hr = E_INVALIDARG;
}
else
{
DWORD dwMS1 = 0 , dwLS1 = 0, dwMS2 = 0, dwLS2 = 0;
HRESULT hr1 = GetVersionFromString(bstrVer1, &dwMS1, &dwLS1);
HRESULT hr2 = GetVersionFromString(bstrVer2, &dwMS2, &dwLS2);
if (SUCCEEDED(hr1) && SUCCEEDED(hr2))
{
if (dwMS1 > dwMS2)
*p = 1;
else if (dwMS1 < dwMS2)
*p = -1;
else /* dwMS1 == dwMS2 */
{
if (dwLS1 > dwLS2)
*p = 1;
else if (dwLS1 < dwLS2)
*p = -1;
else
*p = 0;
}
hr = S_OK;
}
else
{
*p = 1; // ISSUE: what is the right thing to do here.
hr = S_FALSE;
}
}
return hr;
}
STDMETHODIMP CClientCaps::addComponentRequest(BSTR bstrName, BSTR bstrType, BSTR bstrVer)
// Checks if the passed component is installed (optionally at or above the passed version)
// and if not, adds it to a list of components to be added at a call to DoComponentRequest
{
HRESULT hr = 0;
VARIANT_BOOL bInstalled;
uCLSSPEC classspec;
int iLength;
int iRes;
LPWSTR pwszComponentID = NULL;
LPSTR pszComponentID = NULL;
hr = isComponentInstalled(bstrName, bstrType, bstrVer, &bInstalled);
// Unknown Error
if(! SUCCEEDED(hr))
{
goto Exit;
}
// Component is already installed
if(bInstalled)
{
hr = S_OK;
goto Exit;
}
// otherwise, add the comnponent to the list of components to be installed
// First figure out the type of the component and populate the CLSSPEC appropriately.
if (0 == StrCmpICW(bstrType, L"mimetype"))
{
classspec.tyspec = TYSPEC_MIMETYPE;
classspec.tagged_union.pMimeType = bstrName;
}
else if (0 == StrCmpICW(bstrType, L"progid"))
{
classspec.tyspec = TYSPEC_PROGID;
classspec.tagged_union.pProgId = bstrName;
}
else if (0 == StrCmpICW(bstrType, L"clsid"))
{
classspec.tyspec = TYSPEC_CLSID;
// Convert class-id string to GUID.
hr = CLSIDFromString(bstrName, &classspec.tagged_union.clsid);
if (FAILED(hr))
goto Exit;
}
else if (0 == StrCmpICW(bstrType, L"componentid")) //internally called a FeatureID
{
classspec.tyspec = TYSPEC_FILENAME;
classspec.tagged_union.pFileName = bstrName;
}
else
{
hr = E_INVALIDARG;
goto Exit;
}
// Get a ComponentID from the uCLSSPEC
hr = GetComponentIDFromCLSSPEC(&classspec, &pszComponentID);
if(FAILED(hr))
{
goto Exit;
}
// Convert the ComponentID to a wide character string (wide expected by ShowHTMLDialog)
iLength = lstrlenA(pszComponentID) + 1;
pwszComponentID = new WCHAR[iLength];
if(pwszComponentID == NULL)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
iRes = MultiByteToWideChar(CP_ACP,0,pszComponentID, iLength,
pwszComponentID, iLength);
if(iRes == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
if(pwszComponentID)
{
delete [] pwszComponentID;
pwszComponentID = NULL;
}
goto Exit;
}
// initialize array for first time
if(ppwszComponents == NULL)
{
// Hard coded initial size of 10; It's in the right order of magnitude
// Maybe this should be in a constant, but that seems a lot of overhead
// for such a small feature
ppwszComponents = new LPWSTR[10];
iComponentNum = 0;
iComponentCap = 10;
}
// Resizing the array of Components
if(iComponentNum >= iComponentCap)
{
iComponentCap *= 2;
LPWSTR * ppwszOldComponents = ppwszComponents;
ppwszComponents = NULL;
ppwszComponents = new LPWSTR[iComponentCap];
if(ppwszComponents == NULL)
{
hr = E_OUTOFMEMORY;
ppwszComponents = ppwszOldComponents;
if(pwszComponentID)
{
delete [] pwszComponentID;
pwszComponentID = NULL;
}
goto Exit;
}
for(int i = 0; i < iComponentNum; i++)
{
ppwszComponents[i] = ppwszOldComponents[i];
}
delete [] ppwszOldComponents;
}
ppwszComponents[iComponentNum++] = pwszComponentID;
hr = S_OK;
Exit:
if(pszComponentID)
{
CoTaskMemFree(pszComponentID);
}
return hr;
}
STDMETHODIMP CClientCaps::doComponentRequest(VARIANT_BOOL * pVal)
// Uses the url in HKLM\Software\Microsoft\Active Setup\JITSetupPage
// to add the list of components logged using AddComponentRequest
{
SHOWHTMLDIALOGFN *pfnShowHTMLDialog = NULL;
HINSTANCE hInst = 0;
HRESULT hr = 0;
LPWSTR pwszFeatures = NULL;
IMoniker *pMk = NULL;
VARIANT vtDialogArg;
VariantInit(&vtDialogArg);
VARIANT vtRetVal;
VariantInit(&vtRetVal);
int i,j,k,iFeatureArgLength;
TCHAR *pszSETUPPAGE = _T("JITSetupPage");
WCHAR wszDownLoadPage[MAX_PATH];
WCHAR wszDownLoadPageReg[MAX_PATH];
// LPWSTR pwszDownLoadPage = NULL;
HKEY hkeyActiveSetup = 0;
LONG lResult = 0;
DWORD dwType;
DWORD dwSize = INTERNET_MAX_URL_LENGTH;
int iLength = 0;
int iRes = 0;
OSVERSIONINFO osvi;
// NT5 should never show JIT dialog.
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
osvi.dwMajorVersion >= 5) {
hr = E_ACCESSDENIED;
goto Exit;
}
// No Component Requests to process. Return success and exit
if(iComponentNum <= 0)
{
if(pVal)
*pVal = TRUE;
hr = S_OK;
goto Exit;
}
// calculate space needed
iFeatureArgLength = 0;
// Length for the characters in the ComponentIDs
for(k = 0; k < iComponentNum; k++)
{
iFeatureArgLength += lstrlenW(ppwszComponents[k]);
}
iFeatureArgLength += 9*iComponentNum - 1; // "Feature="s and &'s
iFeatureArgLength += 10; // breathing room
pwszFeatures = new WCHAR[iFeatureArgLength];
if(!pwszFeatures)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
// copy the individual strings to one big string, seperated by "&feature="
// i.e. "feature=JavaVM&feature=MOBILEPKx86"
// i is the position in the full string
// k is the current substring
for(i = k = 0; k < iComponentNum; k++)
{
// "feature="
StrCpyW(pwszFeatures + i, L"feature=");
i += 8;
iLength = lstrlenW(ppwszComponents[k]);
// componentID
StrCpyW(pwszFeatures + i, ppwszComponents[k]);
i += iLength;
// "&" || '\0'
if(k + 1 < iComponentNum)
{
pwszFeatures[i] = L'&';
i++;
}
else
{
pwszFeatures[i] = L'\0';
i++;
}
}
// Change string to variant
vtDialogArg.vt = VT_BSTR;
vtDialogArg.bstrVal = SysAllocString(pwszFeatures);
if(! vtDialogArg.bstrVal)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
// get the download dialog page from the registry
if ((lResult = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
REGKEY_ACTIVESETUP, 0, KEY_READ,
&hkeyActiveSetup)) != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(lResult);
goto Exit;
}
if (lResult = SHQueryValueEx(hkeyActiveSetup, pszSETUPPAGE, NULL,
&dwType, wszDownLoadPageReg, &dwSize) != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(lResult);
goto Exit;
}
if (wszDownLoadPageReg) {
WCHAR *wszDownLoadPageFile = NULL;
wszDownLoadPageFile = PathFindFileNameW(wszDownLoadPageReg);
hr = SHGetWebFolderFilePathW(wszDownLoadPageFile, wszDownLoadPage, MAX_PATH);
if (FAILED(hr)) {
goto Exit;
}
}
/* iLength = lstrlenA(szDownLoadPage) + 1;
pwszDownLoadPage = new WCHAR[iLength];
iRes = MultiByteToWideChar(CP_ACP,0,szDownLoadPage, iLength,
pwszDownLoadPage, iLength);
if(iRes == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
*/
// Get Moniker to The JIT Dialog page
hr = CreateURLMoniker(NULL, wszDownLoadPage, &pMk);
if (FAILED(hr))
goto Exit;
// Get the ShowHTMLDialog function from the mshtml dll
hInst = LoadLibraryEx(TEXT("MSHTML.DLL"), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!hInst)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
pfnShowHTMLDialog = (SHOWHTMLDIALOGFN *)GetProcAddress(hInst, "ShowHTMLDialog");
if (!pfnShowHTMLDialog)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Show the JIT download page; the rest of the work is accomplished there
hr = (*pfnShowHTMLDialog)(NULL, pMk, &vtDialogArg, NULL, &vtRetVal);
if(FAILED(hr))
{
goto Exit;
}
// Process the return value
if ((vtRetVal.vt == VT_I4) && vtRetVal.lVal != S_OK )
{
hr = S_FALSE;
if(pVal)
*pVal = FALSE;
}
else if(vtRetVal.vt != VT_I4)
{
hr = S_FALSE;
if(pVal)
*pVal = FALSE;
}
else
{
hr = S_OK;
if(pVal)
*pVal = TRUE;
}
// Since everything was successful, clear the component list
clearComponentRequest();
Exit: // Goto needed because these resources must be cleaned up on all errors and successes
// clear string
if(pwszFeatures)
delete [] pwszFeatures;
if(pMk)
{
pMk->Release();
}
// if(pwszDownLoadPage)
// {
// delete [] pwszDownLoadPage;
// pwszDownLoadPage = NULL;
// }
VariantClear(&vtRetVal);
VariantClear(&vtDialogArg);
if(hInst)
{
FreeLibrary(hInst);
}
return hr;
}
STDMETHODIMP CClientCaps::clearComponentRequest()
// Clears the list of components logged using AddComponentRequest
{
int i;
for(i = 0; i < iComponentNum; i++)
{
if(ppwszComponents[i] != NULL)
{
// delete the wide string
delete [] ppwszComponents[i];
ppwszComponents[i] = NULL;
}
}
iComponentNum = 0;
return S_OK;
}
// IElementBehavior methods
STDMETHODIMP CClientCaps::Init(IElementBehaviorSite *pSite)
{
HRESULT hr = E_INVALIDARG;
if (pSite != NULL)
{
m_pSite = pSite;
m_pSite->AddRef();
hr = S_OK;
}
return hr;
}
STDMETHODIMP CClientCaps::Notify(LONG lNotify, VARIANT * pVarNotify)
{
return S_OK;
}
// Helper functions for internal use only
STDMETHODIMP CClientCaps::GetHTMLDocument(IHTMLDocument2 **ppDoc)
{
HRESULT hr = E_FAIL;
if (m_pSite != NULL)
{
IHTMLElement *pElement = NULL;
hr = m_pSite->GetElement(&pElement);
if (SUCCEEDED(hr))
{
IDispatch * pDispDoc = NULL;
hr = pElement->get_document(&pDispDoc);
if (SUCCEEDED(hr))
{
hr = pDispDoc->QueryInterface(IID_IHTMLDocument2, (void **)ppDoc);
pDispDoc->Release();
}
pElement->Release();
}
}
return hr;
}
STDMETHODIMP CClientCaps::GetHTMLWindow(IHTMLWindow2 **ppWindow)
{
HRESULT hr = E_FAIL;
IHTMLDocument2 *pDoc = NULL;
hr = GetHTMLDocument(&pDoc);
if (SUCCEEDED(hr))
{
hr = pDoc->get_parentWindow(ppWindow);
pDoc->Release();
}
return hr;
}
STDMETHODIMP CClientCaps::GetClientInformation(IOmNavigator **ppNav)
{
HRESULT hr = E_FAIL;
IHTMLWindow2 *pWindow = NULL;
hr = GetHTMLWindow(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_clientInformation(ppNav);
pWindow->Release();
}
return hr ;
}
STDMETHODIMP CClientCaps::GetScreen(IHTMLScreen **ppScreen)
{
HRESULT hr = E_FAIL;
IHTMLWindow2 *pWindow = NULL;
hr = GetHTMLWindow(&pWindow);
if (SUCCEEDED(hr))
{
hr = pWindow->get_screen(ppScreen);
pWindow->Release();
}
return hr ;
}
// Returns S_OK if component is installed and the version # in pbstrVersion.
// Returns S_FALSE if component is not installed.
// E_INVALIDARG if the input args are ill-formed or not an IE component.
// E_* if it encounters an error.
STDMETHODIMP CClientCaps::GetVersion(BSTR bstrName, BSTR bstrType, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS)
{
if (bstrName == NULL || bstrType == NULL)
return E_INVALIDARG;
uCLSSPEC classspec;
HRESULT hr = E_FAIL;
QUERYCONTEXT qc = {0};
// First figure out the type of the component and populate the CLSSPEC appropriately.
if (0 == StrCmpICW(bstrType, L"mimetype"))
{
classspec.tyspec = TYSPEC_MIMETYPE;
classspec.tagged_union.pMimeType = bstrName;
}
else if (0 == StrCmpICW(bstrType, L"progid"))
{
classspec.tyspec = TYSPEC_PROGID;
classspec.tagged_union.pProgId = bstrName;
}
else if (0 == StrCmpICW(bstrType, L"clsid"))
{
classspec.tyspec = TYSPEC_CLSID;
// Convert class-id string to GUID.
hr = CLSIDFromString(bstrName, &classspec.tagged_union.clsid);
if (FAILED(hr))
goto Exit;
}
else if (0 == StrCmpICW(bstrType, L"componentid"))
{
classspec.tyspec = TYSPEC_FILENAME;
classspec.tagged_union.pFileName = bstrName;
}
else
{
hr = E_INVALIDARG;
goto Exit;
}
hr = FaultInIEFeature(NULL, &classspec, &qc, FIEF_FLAG_PEEK);
if (hr == S_OK || (qc.dwVersionHi != 0 || qc.dwVersionLo != 0))
{
// Put the version #'s that we found in the out args.
if (pdwFileVersionMS != NULL)
*pdwFileVersionMS = qc.dwVersionHi;
if (pdwFileVersionLS != NULL)
*pdwFileVersionLS = qc.dwVersionLo;
hr = S_OK;
}
else if ( hr == S_FALSE)
{
// this implies the component is not recognized as an IE component.
// The input argument must be incorrect in this case.
hr = E_INVALIDARG;
}
else if ( hr == HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED))
{
hr = S_FALSE;
}
Exit:
return hr;
}
// ---------------------------------------------------------------------------
// %%Function: GetVersionFromString
//
// converts version in text format (a,b,c,d) into two dwords (a,b), (c,d)
// The printed version number is of format a.b.d (but, we don't care)
// ---------------------------------------------------------------------------
HRESULT
CClientCaps::GetVersionFromString(LPCOLESTR szBuf, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS)
{
LPCOLESTR pch = szBuf;
OLECHAR ch;
*pdwFileVersionMS = 0;
*pdwFileVersionLS = 0;
if (!pch) // default to zero if none provided
return S_OK;
if (StrCmpCW(pch, L"-1,-1,-1,-1") == 0) {
*pdwFileVersionMS = 0xffffffff;
*pdwFileVersionLS = 0xffffffff;
return S_OK;
}
USHORT n = 0;
USHORT a = 0;
USHORT b = 0;
USHORT c = 0;
USHORT d = 0;
enum HAVE { HAVE_NONE, HAVE_A, HAVE_B, HAVE_C, HAVE_D } have = HAVE_NONE;
for (ch = *pch++;;ch = *pch++) {
if ((ch == L',') || (ch == L'\0')) {
switch (have) {
case HAVE_NONE:
a = n;
have = HAVE_A;
break;
case HAVE_A:
b = n;
have = HAVE_B;
break;
case HAVE_B:
c = n;
have = HAVE_C;
break;
case HAVE_C:
d = n;
have = HAVE_D;
break;
case HAVE_D:
return E_INVALIDARG; // invalid arg
}
if (ch == L'\0') {
// all done convert a,b,c,d into two dwords of version
*pdwFileVersionMS = ((a << 16)|b);
*pdwFileVersionLS = ((c << 16)|d);
return S_OK;
}
n = 0; // reset
} else if ( (ch < L'0') || (ch > L'9'))
return E_INVALIDARG; // invalid arg
else
n = n*10 + (ch - L'0');
} /* end forever */
// NEVERREACHED
}
// ---------------------------------------------------------------------------
// %%Function: GetStringFromVersion
//
// converts version from two DWORD's to the string format a,b,c,d
// ---------------------------------------------------------------------------
HRESULT CClientCaps::GetStringFromVersion(DWORD dwVersionMS, DWORD dwVersionLS, BSTR *pbstrVersion)
{
if (pbstrVersion == NULL)
return E_POINTER;
// 16-bits is a max of 5 decimal digits * 4 + 3 ','s + null terminator
const int maxStringSize = 5 * 4 + 3 * 1 + 1;
OLECHAR rgch[maxStringSize];
USHORT a = (USHORT)(dwVersionMS >> 16);
USHORT b = (USHORT)(dwVersionMS & 0xffff);
USHORT c = (USHORT)(dwVersionLS >> 16);
USHORT d = (USHORT)(dwVersionLS & 0xffff);
OLECHAR rgchFormat[] = L"%hu,%hu,%hu,%hu";
int nRet = wnsprintfW(rgch, maxStringSize, rgchFormat, a, b, c, d);
HRESULT hr;
if (nRet < 7 ) // 0,0,0,0
{
hr = E_FAIL;
}
else
{
*pbstrVersion = SysAllocString(rgch);
if (*pbstrVersion == NULL)
hr = E_OUTOFMEMORY;
else
hr = S_OK;
}
return hr;
}