Windows2000/private/inet/urlmon/download/jit.cxx
2020-09-30 17:12:32 +02:00

1264 lines
33 KiB
C++

// ===========================================================================
// File: JIT.CXX
// The Just In Time setup of IE addon components
#include <cdlpch.h>
#include <mshtmhst.h>
#include <shlwapi.h>
#include <shlwapip.h>
#include <inseng.h>
#ifdef UNIX
#include <unixfile.h>
#endif /* UNIX */
HRESULT
GetComponentIDFromIEFeature(LPCSTR pszIEFeature, LPSTR *ppszComponentID)
{
HRESULT hr = S_OK;
HKEY hkeyFeatureComponentID =0;
DWORD lResult;
char szComponentID[MAX_PATH];
DWORD dwSize = MAX_PATH;
DWORD dwType;
*ppszComponentID = NULL;
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
REGKEY_ACTIVESETUP_FEATURECOMPID, 0, KEY_READ,
&hkeyFeatureComponentID)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult);
goto Exit;
}
szComponentID[0] = '\0';
if (SHQueryValueEx(hkeyFeatureComponentID, pszIEFeature, NULL, &dwType,
(unsigned char *)&szComponentID, &dwSize) == ERROR_SUCCESS) {
*ppszComponentID = new char [dwSize+1];
if (*ppszComponentID == NULL) {
hr = E_OUTOFMEMORY;
goto Exit;
}
lstrcpy(*ppszComponentID, szComponentID);
// FALLTHROUGH to exit
} else {
hr = E_UNEXPECTED;
// FALLTHROUGH to exit
}
Exit:
if (hkeyFeatureComponentID)
::RegCloseKey(hkeyFeatureComponentID);
return hr;
}
HRESULT GetComponentIDFromCLSSPEC(uCLSSPEC *pClassspec, LPSTR * ppszComponentID)
{
HRESULT hr = S_OK;
*ppszComponentID = NULL;
LPWSTR pwszIEFeature = NULL;
LPSTR pszIEFeature = NULL;
LPCWSTR pwszMimeType = NULL;
CLSID inclsid = CLSID_NULL;
QUERYCONTEXT qcInternal;
memset(&qcInternal, 0, sizeof(QUERYCONTEXT));
BOOL bUnknown = FALSE;
int iRes = 0;
int length = 0;
switch(pClassspec->tyspec)
{
case TYSPEC_PROGID:
// BUGBUG: we don't have JIT tables for progid to feature id
// so this will only work for PEEK for installed versions
if (FAILED((hr=CLSIDFromProgID(pClassspec->tagged_union.pProgId,
&inclsid))))
goto Exit;
hr = GetIEFeatureFromClass(&pwszIEFeature, inclsid, &qcInternal);
if (hr != S_OK)
goto Exit;
break;
case TYSPEC_CLSID:
inclsid = pClassspec->tagged_union.clsid;
hr = GetIEFeatureFromClass(&pwszIEFeature, inclsid, &qcInternal);
if (hr != S_OK)
goto Exit;
break;
case TYSPEC_MIMETYPE:
pwszMimeType = (LPCWSTR) pClassspec->tagged_union.pMimeType;
hr = GetIEFeatureFromMime(&pwszIEFeature, pwszMimeType, &qcInternal);
if (hr != S_OK)
goto Exit;
break;
case TYSPEC_FILENAME:
// overload filename to be Active Setup feature ID
hr = CDLDupWStr( &pwszIEFeature, pClassspec->tagged_union.pFileName);
if (hr != S_OK)
goto Exit;
break;
default:
hr = E_INVALIDARG;
goto Exit;
}
if(pwszIEFeature == NULL)
{
hr = E_UNEXPECTED;
goto Exit;
}
// Change the wide character IEFeature to a multibyte string
length = lstrlenW(pwszIEFeature) + 1;
pszIEFeature = new CHAR[length];
if(pszIEFeature == NULL)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
bUnknown = FALSE;
iRes = WideCharToMultiByte(CP_ACP, 0, pwszIEFeature,length,
pszIEFeature, length,NULL,&bUnknown);
// unknown multibyte character
if(bUnknown == TRUE)
{
hr = E_INVALIDARG;
goto Exit;
}
// failed for other reason
if(iRes == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Get a ComponentID from the FeatureID
hr = GetComponentIDFromIEFeature(pszIEFeature, ppszComponentID);
if(FAILED(hr))
{
goto Exit;
}
hr = S_OK;
Exit:
SAFEDELETE(pszIEFeature);
SAFEDELETE(pwszIEFeature);
return hr;
}
#define FEATURE_VERSION_SEPARATOR ';'
#define ALT_FEATURE_VERSION_SEPARATOR '!'
// if the IE Feature for this mime/clsid has an IE recommended version
// then modify the querycontext to reflect this as if the caller wanted this
// version. If the caller already has specifies a version that overrides
// the recommnedation.
// format: featurename;a,b,c,d
HRESULT
ParseIEFeature(LPSTR pszIEFeatureWithVersion,
QUERYCONTEXT *pQuery,
LPWSTR *ppwszIEFeature)
{
HRESULT hr = S_OK;
DWORD dwIERecommendedVersionHi = 0;
DWORD dwIERecommendedVersionLo = 0;
LPSTR pchVersion = StrChr(pszIEFeatureWithVersion, FEATURE_VERSION_SEPARATOR);
if (!pchVersion) {
pchVersion = StrChr(pszIEFeatureWithVersion, ALT_FEATURE_VERSION_SEPARATOR);
}
if (pchVersion) {
*pchVersion = '\0'; // stomp version separator so
// pszIEFetaureWithVersion has just the feature name
pchVersion++;
if (*pchVersion && (!(pQuery->dwVersionHi|pQuery->dwVersionLo)) ) {
// now pointing at version string
// of format a,b,c,d
hr = GetVersionFromString(pchVersion,
&dwIERecommendedVersionHi, &dwIERecommendedVersionLo);
if ( SUCCEEDED(hr)) {
pQuery->dwVersionHi = dwIERecommendedVersionHi;
pQuery->dwVersionLo = dwIERecommendedVersionLo;
}
}
}
if ( SUCCEEDED(hr) && ppwszIEFeature)
hr=Ansi2Unicode(pszIEFeatureWithVersion, ppwszIEFeature);
return hr;
}
HRESULT
GetIEFeatureFromMime(LPWSTR *ppwszIEFeature, LPCWSTR pwszMimeType, QUERYCONTEXT *pQuery)
{
HRESULT hr = S_OK;
HKEY hkeyMimeFeature =0;
LPSTR pszMime = NULL;
DWORD lResult;
char szFeature[MAX_PATH];
DWORD dwSize = MAX_PATH;
DWORD dwType;
if (FAILED((hr=::Unicode2Ansi(pwszMimeType, &pszMime))))
{
goto Exit;
}
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
REGKEY_ACTIVESETUP_MIMEFEATURE, 0, KEY_READ,
&hkeyMimeFeature)) != ERROR_SUCCESS) {
#if JIT_IN_BUILD
hr = HRESULT_FROM_WIN32(lResult);
#else
hr = S_FALSE;
#endif
goto Exit;
}
szFeature[0] = '\0';
if (SHQueryValueEx(hkeyMimeFeature, pszMime, NULL, &dwType,
(unsigned char *)szFeature, &dwSize) == ERROR_SUCCESS) {
if (dwSize > MAX_PATH) {
// limit the feature name to MAX_PATH as buffer overrun protection
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
goto Exit;
}
hr = ParseIEFeature(szFeature, pQuery, ppwszIEFeature);
// FALLTHROUGH to exit
} else {
hr = S_FALSE;
// FALLTHROUGH to exit
}
Exit:
if (hkeyMimeFeature)
::RegCloseKey(hkeyMimeFeature);
return hr;
}
HRESULT
GetIEFeatureFromClass(LPWSTR *ppwszIEFeature, REFCLSID clsid, QUERYCONTEXT *pQuery)
{
HRESULT hr = S_OK;
LPOLESTR pwcsClsid = NULL;
LPSTR pszClsid = NULL;
HKEY hkeyClsidFeature =0;
DWORD lResult;
char szFeature[MAX_PATH];
DWORD dwSize = MAX_PATH;
DWORD dwType;
// return if we can't get a valid string representation of the CLSID
if (FAILED((hr=StringFromCLSID(clsid, &pwcsClsid))))
goto Exit;
if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &pszClsid))))
{
goto Exit;
}
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
REGKEY_ACTIVESETUP_CLSIDFEATURE, 0, KEY_READ,
&hkeyClsidFeature)) != ERROR_SUCCESS) {
#if JIT_IN_BUILD
hr = HRESULT_FROM_WIN32(lResult);
#else
hr = S_FALSE;
#endif
goto Exit;
}
szFeature[0] = '\0';
if (SHQueryValueEx(hkeyClsidFeature, pszClsid, NULL, &dwType,
(unsigned char *)szFeature, &dwSize) == ERROR_SUCCESS) {
if (dwSize > MAX_PATH) {
// limit the feature name to MAX_PATH as buffer overrun protection
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
goto Exit;
}
hr = ParseIEFeature(szFeature, pQuery, ppwszIEFeature);
// FALLTHROUGH to exit
} else {
hr = S_FALSE;
// FALLTHROUGH to exit
}
Exit:
if (hkeyClsidFeature)
::RegCloseKey(hkeyClsidFeature);
SAFEDELETE(pwcsClsid);
SAFEDELETE(pszClsid);
return hr;
}
HRESULT
IsActiveSetupFeatureLocallyInstalled(
LPCSTR pszDist,
QUERYCONTEXT *pQuery,
LPSTR *ppszComponentID,
DWORD *pdwVersionHi,
DWORD *pdwVersionLo,
DWORD dwFlags)
{
HRESULT hr = S_FALSE; // Not installed by active setup.
LONG lResult = ERROR_SUCCESS;
char szKey[2*MAX_PATH];
char szVersion[MAX_PATH];
HKEY hKey = NULL;
DWORD dwSize;
DWORD dwValue;
DWORD dwType;
BOOL fIsInstalled = FALSE;
WORD wVersion[4];
DWORD dwCurMS = 0;
DWORD dwCurLS = 0;
const static char * szLocale = "Locale";
const static char * szIsInstalled = "IsInstalled";
const static char * szActVersion = "Version";
const static char * szCOMPONENTID = "ComponentID";
const static char * szKEYFILENAME = "KeyFileName";
if (pdwVersionHi && pdwVersionLo) {
*pdwVersionHi = 0;
*pdwVersionLo = 0;
}
if (ppszComponentID) { // if we need a componentID
GetComponentIDFromIEFeature(pszDist, ppszComponentID);
}
// buffer overrun: assumes that lstrlen(pszDist) < MAX_PATH
lstrcpy(szKey, REGKEY_ACTIVESETUP_COMPONENTS);
lstrcat(szKey, "\\");
lstrcat(szKey, pszDist);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(dwValue);
// Old format of the Installed components did not have the IsInstalled value.
if (RegQueryValueEx( hKey, szIsInstalled, NULL, NULL, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS)
{
dwValue = 0;
}
fIsInstalled = (dwValue != 0);
if (fIsInstalled)
{
hr = S_OK;
} else {
// hr is S_FALSE;
goto Exit;
}
if (pQuery && ((pQuery->dwVersionHi|pQuery->dwVersionLo) ||
(dwFlags & FIEF_FLAG_PEEK)) ) {
dwSize = sizeof(szVersion);
if ( (lResult = RegQueryValueEx(hKey, szActVersion, NULL, &dwType, (LPBYTE)szVersion, &dwSize)) == ERROR_SUCCESS )
{
Assert(dwType == REG_SZ);
if ( SUCCEEDED(GetVersionFromString(szVersion, &dwCurMS, &dwCurLS)))
{
if (dwCurMS > pQuery->dwVersionHi ||
(dwCurMS == pQuery->dwVersionHi && dwCurLS >= pQuery->dwVersionLo)) {
hr = S_OK;
} else {
hr = S_FALSE;
}
if (pdwVersionHi && pdwVersionLo) {
*pdwVersionHi = dwCurMS;
*pdwVersionLo = dwCurLS;
}
} else {
hr = S_FALSE;
}
} else {
hr = S_FALSE;
}
}
if (hr == S_OK) {
// we think it is installed
// robustify with key file presence check
dwSize = sizeof(szVersion);
dwType = REG_SZ;
if ( SHQueryValueEx(hKey, szKEYFILENAME, NULL, &dwType, (LPBYTE)szVersion, &dwSize) == ERROR_SUCCESS ) {
// value present, check if file is present
if (GetFileAttributes(szVersion) == -1)
hr = S_FALSE;
}
}
}
Exit:
SAFEREGCLOSEKEY(hKey);
return hr;
}
typedef HRESULT (*PFNGETICIFFILEFROMFILE)(ICifFile **, LPCSTR pszFile);
HRESULT
IsCIFVersionGoodEnough(
QUERYCONTEXT *pQuery,
LPCSTR pszID)
{
// BUGBUG: not side by side aware!!!
const static char * szCIFPATH = "iesetup.cif";
HRESULT hr = S_OK;
ICifFile *pcif;
ICifComponent *pcomp;
DWORD dwVersionHi = 0;
DWORD dwVersionLo = 0;
PFNGETICIFFILEFROMFILE pfnGetICifFileFromFile = NULL;
HMODULE hMod = LoadLibrary("inseng.dll");
if ( !hMod ||
(!(pfnGetICifFileFromFile = (PFNGETICIFFILEFROMFILE)GetProcAddress(hMod,
"GetICifFileFromFile")))) {
return E_UNEXPECTED;
}
if(SUCCEEDED(pfnGetICifFileFromFile(&pcif, szCIFPATH))) // szCifPath is full path to cif, or 8.3 and it defaults to look in ie dir for it
{
if(SUCCEEDED(pcif->FindComponent(pszID, &pcomp))) // pszID is id of what you are interested in
{
pcomp->GetVersion(&dwVersionHi, &dwVersionLo);
// BUGBUG: ?
// pcomp->Release();
if (pQuery->dwVersionHi > dwVersionHi ||
(dwVersionHi == pQuery->dwVersionHi && pQuery->dwVersionLo > dwVersionLo)) {
hr = HRESULT_FROM_WIN32(ERROR_UNKNOWN_REVISION);
}
}
pcif->Release();
}
if (hMod)
FreeLibrary(hMod);
return hr;
}
/* Returns:
*
* S_OK: Is Installed
* S_FALSE: Is Available, Needs to be faulted in.
* ERROR
*
*/
HRESULT
IsIEFeatureInstalled(
LPCWSTR pwszIEFeature,
QUERYCONTEXT *pQuery,
LPWSTR *ppwszSetupPage,
LPWSTR *ppwszCompID,
DWORD dwFlags
)
{
HRESULT hr = S_FALSE; // assume need to fault in
LPSTR pszIEFeature = NULL;
LPSTR pszComponentID = NULL;
const static char * szSETUPPAGE = "JITSetupPage";
const static char * szQUERYFEATURE = "feature=";
LONG lResult;
HKEY hkeyActiveSetup = 0;
char szJITPage[INTERNET_MAX_URL_LENGTH];
DWORD dwType;
DWORD dwSize = INTERNET_MAX_URL_LENGTH;
DWORD dwInstalledVersionHi =0;
DWORD dwInstalledVersionLo =0;
BOOL bComponentDeclined = FALSE;
#ifdef UNIX
{
/* Unix special handling for features like java VM
* For instance, libmsjava.so will always be installed.
* But, is the Sun VM installed?
*/
hr = CheckIEFeatureOnUnix(pwszIEFeature, &dwInstalledVersionHi, &dwInstalledVersionLo, dwFlags);
if (hr == S_OK || hr == ERROR_PRODUCT_UNINSTALLED)
goto Exit; /* Found on Unix and Handled */
}
#endif /* UNIX */
if (FAILED((hr=::Unicode2Ansi(pwszIEFeature, &pszIEFeature))))
{
goto Exit;
}
hr = IsActiveSetupFeatureLocallyInstalled(pszIEFeature, pQuery, &pszComponentID, &dwInstalledVersionHi, &dwInstalledVersionLo, dwFlags);
if (hr == S_FALSE) {
// not installed, need to JIT
// find out if this is JITDeclined
if (SHRegGetUSValue( REGKEY_DECLINED_IOD, pszIEFeature, NULL, NULL, NULL, 0,NULL,0) == ERROR_SUCCESS)
{
bComponentDeclined = TRUE;
}
}
if (((hr != S_OK) || dwFlags & FIEF_FLAG_SKIP_INSTALLED_VERSION_CHECK)
&& ppwszSetupPage && ppwszCompID) {
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
REGKEY_ACTIVESETUP, 0, KEY_READ,
&hkeyActiveSetup)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult);
goto Exit;
}
szJITPage[0] = '\0';
if (SHQueryValueEx(hkeyActiveSetup, szSETUPPAGE, NULL, &dwType,
(unsigned char *)szJITPage, &dwSize) == ERROR_SUCCESS) {
HRESULT hr1 = ::Ansi2Unicode(szJITPage, ppwszSetupPage);
if(FAILED(hr1))
hr = hr1; // else hr still = S_FALSE;
if (pszComponentID) {
if ((sizeof(szQUERYFEATURE) + lstrlen(pszComponentID) +1)
< INTERNET_MAX_URL_LENGTH){
lstrcpy(szJITPage, szQUERYFEATURE);
lstrcat(szJITPage, pszComponentID);
if ( (dwFlags & FIEF_FLAG_CHECK_CIFVERSION) &&
pQuery &&
(pQuery->dwVersionHi|pQuery->dwVersionLo)) {
hr1=IsCIFVersionGoodEnough(pQuery, pszComponentID);
if (FAILED(hr1)) {
hr = hr1;
goto Exit;
}
}
HRESULT hr1 = ::Ansi2Unicode(szJITPage, ppwszCompID);
if(FAILED(hr1))
hr = hr1; // else hr still = S_FALSE;
} else {
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
}
}
}
}
Exit:
if (pQuery && (dwFlags & FIEF_FLAG_PEEK)) {
pQuery->dwVersionHi = dwInstalledVersionHi;
pQuery->dwVersionLo = dwInstalledVersionLo;
}
SAFEDELETE(pszIEFeature);
SAFEDELETE(pszComponentID);
if (hkeyActiveSetup)
RegCloseKey(hkeyActiveSetup);
if (bComponentDeclined) {
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
return hr;
}
HRESULT
IsJITRestricted()
{
HKEY hkeyRest = 0;
BOOL bJITRest = FALSE;
DWORD dwValue = 0;
DWORD dwLen = sizeof(DWORD);
HRESULT hr = S_OK;
OSVERSIONINFO osvi;
// BUGBUG: NT RAID #216898--when you install IE5 and the shell cabs
// on NT5, the NoJITSetup reg value is blown away, but we can't figure
// out who is doing this. JIT should not occur for NT5. This hack
// is a work-around so JIT does not occur under NT5 and above.
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
osvi.dwMajorVersion >= 5) {
hr = E_ACCESSDENIED;
goto Exit;
}
// per-machine JIT off policy
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_INFODEL_REST, 0, KEY_READ, &hkeyRest) == ERROR_SUCCESS) {
if (RegQueryValueEx( hkeyRest, REGVAL_JIT_REST, NULL, NULL,
(LPBYTE)&dwValue, &dwLen) == ERROR_SUCCESS && dwValue)
hr = E_ACCESSDENIED;
RegCloseKey(hkeyRest);
}
if (SUCCEEDED(hr)) {
// Check to see if the user has turned it off under advanced options
// make this appear in UI similar to the admin restricted case
// hence the return value of access_denied
dwValue = 0;
dwLen = sizeof(DWORD);
if (SHRegGetUSValue( REGSTR_PATH_IE_MAIN, REGVAL_JIT_REST, NULL, (LPBYTE)&dwValue, &dwLen, 0,NULL,0) == ERROR_SUCCESS && dwValue)
hr = E_ACCESSDENIED;
}
Exit:
return hr;
}
HRESULT
SetJITDeclined(
LPCWSTR pwszIEFeature)
{
HRESULT hr = S_FALSE; // assume need to fault in
LPSTR pszIEFeature = NULL;
LONG lResult = ERROR_SUCCESS;
HKEY hKey = NULL;
DWORD dwSize;
DWORD dwValue;
LPSTR szNull = "";
if (FAILED((hr=::Unicode2Ansi(pwszIEFeature, &pszIEFeature))))
{
goto Exit;
}
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_DECLINED_IOD, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
{
if ((lResult = RegCreateKey( HKEY_CURRENT_USER,
REGKEY_DECLINED_IOD, &hKey)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult);
goto Exit;
}
}
if (((lResult = RegSetValueEx (hKey, pszIEFeature, 0, REG_SZ,
(unsigned char *)szNull, 1))) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult);
}
Exit:
if (hKey)
RegCloseKey(hKey);
SAFEDELETE(pszIEFeature);
return hr;
}
HRESULT
HasFeatureAlreadyBeenRejected(
LPCWSTR szDistUnit)
{
HRESULT hr = S_OK;
LISTPOSITION curpos;
LPCWSTR pwszRejectedFeature = NULL;
int iNumRejected;
int i;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr))
goto Exit;
iNumRejected = tls->pRejectedFeaturesList->GetCount();
curpos = tls->pRejectedFeaturesList->GetHeadPosition();
// walk thru all the rejected features in the thread and check for match
for (i=0; i < iNumRejected; i++) {
pwszRejectedFeature = tls->pRejectedFeaturesList->GetNext(curpos);
if (StrCmpIW(szDistUnit, pwszRejectedFeature) == 0) {
hr = S_FALSE;
break;
}
}
Exit:
return hr;
}
HRESULT
RelinquishCodeDownloadCookies()
{
HRESULT hr = S_OK;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr))
goto Exit;
Assert(tls->pTrustCookie);
Assert(tls->pSetupCookie);
if (!tls->pTrustCookie || !tls->pSetupCookie) {
hr = E_UNEXPECTED;
goto Exit;
}
tls->pSetupCookie->JITRelinquish();
tls->pTrustCookie->JITRelinquish();
Exit:
return hr;
}
HRESULT
AcquireCodeDownloadCookies()
{
HRESULT hr = S_OK;
HRESULT hrJITTrustCookie = E_FAIL;
HRESULT hrJITSetupCookie = E_FAIL;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr))
goto Exit;
// are both cookies free?
if (!(tls->pTrustCookie->IsFree() && tls->pSetupCookie->IsFree())) {
hr = E_FAIL;
goto Exit;
}
// if both cookies are free, grab them
// thius will ensure that code downloads are
// frozen or pended to the point JIT completes
hrJITTrustCookie = tls->pTrustCookie->JITAcquire();
if (FAILED(hrJITTrustCookie)) {
Assert(TRUE);
hr = hrJITTrustCookie;
goto Exit;
}
hrJITSetupCookie = tls->pSetupCookie->JITAcquire();
if (FAILED(hrJITSetupCookie)) {
Assert(TRUE);
hr = hrJITSetupCookie;
goto Exit;
}
// taken both the cookies
Exit:
if (FAILED(hr)) {
if (SUCCEEDED(hrJITSetupCookie))
tls->pSetupCookie->JITRelinquish();
if (SUCCEEDED(hrJITTrustCookie))
tls->pTrustCookie->JITRelinquish();
}
return hr;
}
HRESULT
GetDialogArgs(LPCWSTR pwszCompID, DWORD dwFlags, VARIANT& vtDialogArg)
{
HRESULT hr = S_OK;
WCHAR pwszFLAGS[] = L"&flag=forceUI";
WCHAR pwszArgs[INTERNET_MAX_URL_LENGTH];// large buffer
StrCpyNW(pwszArgs, pwszCompID, INTERNET_MAX_URL_LENGTH);
if (dwFlags & FIEF_FLAG_FORCE_JITUI) {
StrCatBuffW(pwszArgs, pwszFLAGS, INTERNET_MAX_URL_LENGTH);
}
vtDialogArg.bstrVal = SysAllocString(pwszArgs);
ASSERT(vtDialogArg.bstrVal);
if(vtDialogArg.bstrVal)
{
vtDialogArg.vt = VT_BSTR;
}
else
{
hr = E_OUTOFMEMORY;
goto Exit;
}
Exit:
return hr;
}
/*
* FaultInIEFeature
*
* Description:
*
* Synchronous API that is to be invoked by client of an IE feature before
* accessing the feature. If the feature is already installed then it
* succeeds and the client should attempt to access the feature. Success
* return by the API does not guarantee that the feature is fully installed
* or will work. The client should still robustify access to the feature
* with proper error checking.
* If the API detects that the feature is missing on the client then it
* maps the feature identified by a clsid or mimetype (in the classspec)
* into a feature name/id and then invokes a HTML dialog with the feature
* name in the form of http://...../setuppage.htm?FeatureName=<featurename>
* The page can communicate back a return value thru
* window.external.returnValue. The following are recognized now:
*
* #define JITPAGE_RETVAL_SUCCESS 0x0 // successfully installed
* #define JITPAGE_RETVAL_CANCELLED 0x1 // was cancelled by user
* #define JITPAGE_RETVAL_DONTASK_THISWINDOW 0x2 // don't ask again in this
*
* Parameters:
*
* hWnd: parent hwnd for htmldialog
* pClassSpec: ptr to union {clsid, mimetype ...}
* querycontext: to specify version, lcid of feature(lcid not impl)
* This is an IN/OUT param. The installed version
* number is returned is FIEF_FLAG_PEEK is passed in
* dwFlags: control behaviour such as UI/no UI, peek versus faultin
* FIEF_FLAG_PEEK
*
* FIEF_FLAG_FORCE_JITUI
* Force JIT even if user has cancelled a previous JIT in
* the same session or even asked to Never JIT this feature.
*
* FIEF_FLAG_PEEK
* Don't fault in just peek. Peek has the side effect of
* returning currently installed version in the querycontext
*
* FIEF_FLAG_SKIP_INSTALLED_VERSION_CHECK
* Ignore local version being satisfactory and force JIT
* download. Typically called by code download or other caller
* after a CoCreateInstance call has failed with
* REGDB_E_CLASSNOTREG or ERROR_MOD_NOT_FOUND (missing
* dependency dll). The registry probably still looks like
* this feature is installed, but really isn't or is damaged.
*
*
* Returns:
*
* S_OK: Is Installed. Caller needs to CoCreate or BindToObject or some
* other system service to invoke the class or mime handler.
* S_FALSE: Class or Mime is not part of an IE feature. Caller needs to
* CoCreate or BindToObject or some other system service to
* invoke the class or mime handler.
* E_ACCESSDENIED
* Admin has turned off JIT feature.
* HRESULT_FROM_WIN32(ERROR_CANCELLED):
* Could have been cancelled by the user or has been requested
* by user not to bother again in this browser window.
* HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED):
* Returned if the feature is not installed, but FIEF_FLAG_PEEK
* was specified
* HRESULT_FROM_WIN32(ERROR_REVISION_UNKNOWN);
* Returned when dwFlag FIEF_FLAG_CHECK_CIFVERSION is passed and
* the local version is not good enough AND the version in the CIF
* that would get JIT installed is also less then the version
* requested by the caller. This flag is typically passed by a
* caller such as code download in URLMON that has the means to
* get the requested version by installing the CODEBASE object.
*
* ERROR:
* Other error.
*
*/
STDAPI
FaultInIEFeature(
HWND hWnd,
uCLSSPEC *pClassSpec,
QUERYCONTEXT *pQuery,
DWORD dwFlags
)
{
HRESULT hr = S_OK;
HRESULT hrCDLCookies=E_FAIL;
WCHAR *pwszMUISetupFile = NULL;
WCHAR pwszMUISetupPage[MAX_PATH];
CLSID inclsid = CLSID_NULL;
LPCWSTR pwszDistUnit=NULL;
LPCWSTR pwszFileExt=NULL;
LPCWSTR pwszMimeType=NULL;
LPWSTR pwszIEFeature=NULL;
LPWSTR pwszSetupPage=NULL;
LPWSTR pwszCompID=NULL;
HINSTANCE hInst = 0;
IMoniker *pMk = NULL;
SHOWHTMLDIALOGFN *pfnShowHTMLDialog = NULL;
VARIANT vtRetVal;
VARIANT vtDialogArg;
VariantInit(&vtRetVal);
VariantInit(&vtDialogArg);
QUERYCONTEXT qcInternal;
// setup the per thread tls list for rejected features, so we
// don't bother the user multiple times for the same feature
// needs review on whether this is per thread or per process
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr))
goto Exit;
hr = SetCodeDownloadTLSVars();
if (FAILED(hr))
goto Exit;
if (pQuery) {
memcpy(&qcInternal, pQuery, sizeof(QUERYCONTEXT));
} else {
memset(&qcInternal, 0, sizeof(QUERYCONTEXT));
}
// Get the class spec.
if(pClassSpec != NULL)
{
switch(pClassSpec->tyspec)
{
case TYSPEC_PROGID:
// BUGBUG: we don't have JIT tables for progid to feature id
// so this will only work for PEEK for installed versions
if (FAILED((hr=CLSIDFromProgID(pClassSpec->tagged_union.pProgId,
&inclsid))))
goto Exit;
hr = GetIEFeatureFromClass(&pwszIEFeature, inclsid, &qcInternal);
if (hr != S_OK)
goto Exit;
break;
case TYSPEC_CLSID:
inclsid = pClassSpec->tagged_union.clsid;
hr = GetIEFeatureFromClass(&pwszIEFeature, inclsid, &qcInternal);
if (hr != S_OK)
goto Exit;
break;
case TYSPEC_MIMETYPE:
pwszMimeType = (LPCWSTR) pClassSpec->tagged_union.pMimeType;
hr = GetIEFeatureFromMime(&pwszIEFeature, pwszMimeType, &qcInternal);
if (hr != S_OK)
goto Exit;
break;
case TYSPEC_FILENAME:
// overload filename to be Active Setup feature ID
hr = CDLDupWStr( &pwszIEFeature, pClassSpec->tagged_union.pFileName);
if (hr != S_OK)
goto Exit;
break;
default:
hr = E_INVALIDARG;
goto Exit;
}
} else {
hr = E_INVALIDARG;
goto Exit;
}
// We have a feature now
ASSERT(pwszIEFeature);
if (!pwszIEFeature) {
hr = E_UNEXPECTED;
goto Exit;
}
hr = IsIEFeatureInstalled(pwszIEFeature, &qcInternal, &pwszSetupPage, &pwszCompID, dwFlags);
if ((dwFlags & FIEF_FLAG_PEEK) && pQuery) {
memcpy(pQuery, &qcInternal, sizeof(QUERYCONTEXT));
}
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
if (!(dwFlags & FIEF_FLAG_FORCE_JITUI))
goto Exit;
else
hr = S_FALSE;
}
if (FAILED(hr) || (hr == S_OK && !(dwFlags & FIEF_FLAG_SKIP_INSTALLED_VERSION_CHECK)))
goto Exit;
if (SUCCEEDED(hr) && pwszSetupPage) {
pwszMUISetupFile = PathFindFileNameW(pwszSetupPage);
hr = SHGetWebFolderFilePathW(pwszMUISetupFile, pwszMUISetupPage, MAX_PATH);
}
hr = IsJITRestricted();
if ( hr == E_ACCESSDENIED ||
((hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) &&
(!(dwFlags & FIEF_FLAG_FORCE_JITUI))
)
) {
goto Exit;
}
if (!(dwFlags & FIEF_FLAG_FORCE_JITUI)) {
hr = HasFeatureAlreadyBeenRejected(pwszIEFeature);
if (hr == S_FALSE) {
// already been rejected
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
goto Exit;
}
}
// We have a setup page for the feature now
// need to faultin feature
if (dwFlags & FIEF_FLAG_PEEK) {
hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED);
goto Exit;
}
if (!pwszMUISetupPage || !pwszCompID) {
hr = E_UNEXPECTED;
goto Exit;
}
// faultin feature
// now we need to acuire some code download cookies
// trust and setup. This is to make sure that we don't
// have a JIT and WVT dialog up at the same time
// we aslo want to avoid having to do a JIT and a code download
// restart machine dialog come up in the middle
hrCDLCookies = AcquireCodeDownloadCookies();
//if (FAILED(hrCDLCookies))
{
// Just try and make the new JIT dialog plaster on top of the
// WVT dialog, but make the WVT dialog disabled while JIT is up
// this can be done by hopefully just parenting the JIT with the
// trust dialog instead of the one passed in.
HWND hWndParent = hWnd;
HWND hWndTop = hWnd;
while ( (hWndParent = GetParent(hWndParent)) != NULL) {
hWndTop = hWndParent;
}
hWnd = GetLastActivePopup(hWndTop);
}
hr = GetDialogArgs(pwszCompID, dwFlags, vtDialogArg);
if (FAILED(hr))
goto Exit;
hr = CreateURLMoniker(NULL, pwszMUISetupPage, &pMk);
if (FAILED(hr))
goto Exit;
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;
}
(*pfnShowHTMLDialog)(hWnd, pMk, &vtDialogArg, NULL, &vtRetVal);
// below to release inseng.dll and asctrls.ocx the setup helper and
// control used in the JIT setup page. This is to help people
// running iesetup for the next build after they have had a JIT
// to not require a reboot
CoFreeUnusedLibraries();
if ((vtRetVal.vt == VT_I4) &&
(vtRetVal.lVal == JITPAGE_RETVAL_CANCELLED)) {
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
} else if ((vtRetVal.vt == VT_I4) &&
vtRetVal.lVal == JITPAGE_RETVAL_NEED_REBOOT) {
hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED);
} else if ((vtRetVal.vt == VT_I4) &&
vtRetVal.lVal == JITPAGE_RETVAL_DONTASK_THISWINDOW) {
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
tls->pRejectedFeaturesList->AddHead(pwszIEFeature);
pwszIEFeature = NULL;
} else if ((vtRetVal.vt == VT_I4) &&
vtRetVal.lVal == JITPAGE_RETVAL_DONTASK_EVER) {
SetJITDeclined(pwszIEFeature);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
} else if ((vtRetVal.vt == VT_I4) && FAILED(vtRetVal.lVal) ) {
hr = vtRetVal.lVal;
}
Exit:
if (SUCCEEDED(hrCDLCookies)) {
HRESULT hr1 = RelinquishCodeDownloadCookies();
if (FAILED(hr1) && SUCCEEDED(hr))
hr = hr1;
}
SAFERELEASE(pMk);
SAFEDELETE(pwszIEFeature);
SAFEDELETE(pwszSetupPage);
SAFEDELETE(pwszCompID);
VariantClear(&vtDialogArg);
if (hInst)
FreeLibrary(hInst);
return hr;
}
BOOL IsJITInProgress()
{
HWND hwnd;
hwnd = FindWindow(JIT_DIALOG_CLASS_NAME, JIT_DIALOG_CAPTION);
return (hwnd != NULL); // not a typo (FindWindow returns NULL for unfound)
}