|
|
// 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; }
|