#include #include #include #include #include #include // fwd declaration HRESULT CheckPlatform(LPMANIFEST_DATA pPlatformData); // return: 0 for all satisfied HRESULT CheckPlatformRequirementsEx(LPASSEMBLY_MANIFEST_IMPORT pManifestImport, CDebugLog* pDbgLog, LPDWORD pdwNumMissingPlatforms, LPTPLATFORM_INFO* pptPlatform) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); DWORD dwCount = 0; DWORD dwMissingCount = 0; LPMANIFEST_DATA pPlatformList = NULL; LPMANIFEST_DATA pPlatformData = NULL; DWORD cbProperty = 0, dwType = 0; LPASSEMBLY_IDENTITY pAsmId = NULL; LPTPLATFORM_INFO ptPlatform = NULL; LPWSTR pwzId = NULL; DWORD dwCC = 0; IF_NULL_EXIT(pManifestImport, E_INVALIDARG); IF_NULL_EXIT(pdwNumMissingPlatforms, E_INVALIDARG); IF_NULL_EXIT(pptPlatform, E_INVALIDARG); *pdwNumMissingPlatforms = 0; *pptPlatform = NULL; IF_FAILED_EXIT(CreateManifestData(L"platform list", &pPlatformList)); IF_FAILED_EXIT(pManifestImport->GetNextPlatform(dwCount, &pPlatformData)); while (hr == S_OK) { if (pDbgLog) { SAFEDELETEARRAY(pwzId); IF_FAILED_EXIT(pPlatformData->GetType(&pwzId)); IF_NULL_EXIT(pwzId, E_FAIL); IF_FAILED_EXIT(FusionCompareString(pwzId, WZ_DATA_PLATFORM_MANAGED, 0)); if (hr == S_OK) { SAFEDELETEARRAY(pwzId); IF_FAILED_EXIT(pPlatformData->Get(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyIdTag].pwz, (LPVOID*) &pAsmId, &cbProperty, &dwType)); IF_NULL_EXIT(pAsmId, E_FAIL); IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_IUNKNOWN_PTR, E_FAIL); IF_FAILED_EXIT(pAsmId->GetDisplayName(0, &pwzId, &dwCC)); SAFERELEASE(pAsmId); } } IF_FAILED_EXIT(CheckPlatform(pPlatformData)); if (hr == S_FALSE) { IF_FALSE_EXIT(dwMissingCount < dwMissingCount+1, HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)); dwMissingCount++; // ISSUE-06/07/02-felixybc use linked-list instead? IF_FAILED_EXIT((static_cast(pPlatformList))->Set(dwMissingCount, (LPVOID) pPlatformData, sizeof(LPVOID), MAN_DATA_TYPE_IUNKNOWN_PTR)); if (pDbgLog) { DEBUGOUT1(pDbgLog, 1, L" LOG: Missing dependent platform, id: %s", pwzId); } } else if (pDbgLog) { DEBUGOUT1(pDbgLog, 1, L" LOG: Found dependent platform, id: %s", pwzId); } SAFERELEASE(pPlatformData); IF_FALSE_EXIT(dwCount < dwCount+1, HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)); dwCount++; // platform data is returned in order IF_FAILED_EXIT(pManifestImport->GetNextPlatform(dwCount, &pPlatformData)); } // assemble platform struct if (dwMissingCount > 0) { IF_ALLOC_FAILED_EXIT(ptPlatform = new TPLATFORM_INFO[dwMissingCount]); // ISSUE - zero out memory pointed by ptPlatform for (DWORD dw = 0; dw < dwMissingCount; dw++) { IF_FAILED_EXIT((static_cast(pPlatformList))->Get(dw+1, (LPVOID *)&pPlatformData, &cbProperty, &dwType)); IF_NULL_EXIT(pPlatformData, E_FAIL); IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_IUNKNOWN_PTR, E_FAIL); // allow missing friendly name?? IF_FAILED_EXIT(pPlatformData->Get(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::FriendlyName].pwz, (LPVOID *)&((ptPlatform[dw]).pwzName), &cbProperty, &dwType)); IF_NULL_EXIT(((ptPlatform[dw]).pwzName), E_FAIL); IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_LPWSTR, E_FAIL); IF_FAILED_EXIT(pPlatformData->Get(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Href].pwz, (LPVOID *)&((ptPlatform[dw]).pwzURL), &cbProperty, &dwType)); // allow missing URL if ((ptPlatform[dw]).pwzURL != NULL) { IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_LPWSTR, E_FAIL); } // ISSUE-06/07/02-felixybc for internal use, need a different way to return Codebase SAFERELEASE(pPlatformData); if (pDbgLog) { DEBUGOUT2(pDbgLog, 1, L" LOG: Missing dependent platform data, friendlyName: %s; codebase/URL: %s", (ptPlatform[dw]).pwzName, (ptPlatform[dw]).pwzURL); } } } *pdwNumMissingPlatforms = dwMissingCount; *pptPlatform = ptPlatform; ptPlatform = NULL; exit: if (FAILED(hr) && ptPlatform) { for (DWORD dw = 0; dw < dwMissingCount; dw++) { SAFEDELETEARRAY((ptPlatform[dw]).pwzName); SAFEDELETEARRAY((ptPlatform[dw]).pwzURL); } SAFEDELETEARRAY(ptPlatform); } SAFEDELETEARRAY(pwzId); SAFERELEASE(pAsmId); SAFERELEASE(pPlatformData); SAFERELEASE(pPlatformList); return hr; } // return: 0 for all satisfied HRESULT CheckPlatformRequirements(LPASSEMBLY_MANIFEST_IMPORT pManifestImport, LPDWORD pdwNumMissingPlatforms, LPTPLATFORM_INFO* pptPlatform) { return CheckPlatformRequirementsEx(pManifestImport, NULL, pdwNumMissingPlatforms, pptPlatform); } #define WZ_PLATFORM_OS_TYPE_WORKSTATION L"workstation" #define WZ_PLATFORM_OS_TYPE_DOMAIN_CONTROLLER L"domainController" #define WZ_PLATFORM_OS_TYPE_SERVER L"server" #define WZ_PLATFORM_OS_SUITE_BACKOFFICE L"backoffice" #define WZ_PLATFORM_OS_SUITE_BLADE L"blade" #define WZ_PLATFORM_OS_SUITE_DATACENTER L"datacenter" #define WZ_PLATFORM_OS_SUITE_ENTERPRISE L"enterprise" #define WZ_PLATFORM_OS_SUITE_PERSONAL L"home" // note: different text #define WZ_PLATFORM_OS_SUITE_SMALLBUSINESS L"smallbusiness" #define WZ_PLATFORM_OS_SUITE_SMALLBUSINESS_RESTRICTED L"smallbusinessRestricted" #define WZ_PLATFORM_OS_SUITE_TERMINAL L"terminal" // our addition/definition: #define WZ_PLATFORM_OS_SUITE_PROFESSIONAL L"professional" // return: S_OK // S_FALSE // E_* HRESULT CheckOSHelper(LPMANIFEST_DATA pOSData) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LPWSTR pwzBuf = NULL; LPDWORD pdwVal = NULL; DWORD cbProperty = 0; DWORD dwType = 0; OSVERSIONINFOEX osvi; DWORDLONG dwlConditionMask = 0; DWORD dwTypeMask = 0; BOOL bCheckProfessionalSuite = FALSE; #define WORD_MAX 0xffff // verify type IF_FAILED_EXIT(pOSData->GetType(&pwzBuf)); IF_FAILED_EXIT(FusionCompareString(WZ_DATA_OSVERSIONINFO, pwzBuf, 0)); IF_FALSE_EXIT(hr == S_OK, E_INVALIDARG); SAFEDELETEARRAY(pwzBuf); // Initialize the OSVERSIONINFOEX structure. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); for (CAssemblyManifestImport::eStringTableId i = CAssemblyManifestImport::MajorVersion; i <= CAssemblyManifestImport::ProductType; i++) { if (i >= CAssemblyManifestImport::MajorVersion && i <= CAssemblyManifestImport::ServicePackMinor) { IF_FAILED_EXIT(pOSData->Get(CAssemblyManifestImport::g_StringTable[i].pwz, (LPVOID*) &pdwVal, &cbProperty, &dwType)); if (pdwVal != NULL) { IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_DWORD, E_FAIL); switch (i) { case CAssemblyManifestImport::MajorVersion: osvi.dwMajorVersion = *pdwVal; // Initialize the condition mask. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL ); dwTypeMask |= VER_MAJORVERSION; break; case CAssemblyManifestImport::MinorVersion: osvi.dwMinorVersion = *pdwVal; VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL ); dwTypeMask |= VER_MINORVERSION; break; case CAssemblyManifestImport::BuildNumber: osvi.dwBuildNumber = *pdwVal; VER_SET_CONDITION( dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL ); dwTypeMask |= VER_BUILDNUMBER; break; case CAssemblyManifestImport::ServicePackMajor: // WORD osvi.wServicePackMajor = (WORD) ((*pdwVal) & WORD_MAX); VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL ); dwTypeMask |= VER_SERVICEPACKMAJOR; break; case CAssemblyManifestImport::ServicePackMinor: // WORD osvi.wServicePackMinor = (WORD) ((*pdwVal) & WORD_MAX); VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL ); dwTypeMask |= VER_SERVICEPACKMINOR; break; //default: should not happen } SAFEDELETEARRAY(pdwVal); } } else { IF_FAILED_EXIT(pOSData->Get(CAssemblyManifestImport::g_StringTable[i].pwz, (LPVOID*) &pwzBuf, &cbProperty, &dwType)); if (pwzBuf != NULL) { IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_LPWSTR, E_FAIL); if (i == CAssemblyManifestImport::ProductType) { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_TYPE_WORKSTATION, pwzBuf, 0)); if (hr == S_OK) //VER_NT_WORKSTATION The system is running Windows NT 4.0 Workstation, // Windows 2000 Professional, Windows XP Home Edition, or Windows XP Professional. osvi.wProductType = VER_NT_WORKSTATION; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_TYPE_DOMAIN_CONTROLLER, pwzBuf, 0)); if (hr == S_OK) //VER_NT_DOMAIN_CONTROLLER The system is a domain controller. osvi.wProductType = VER_NT_DOMAIN_CONTROLLER; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_TYPE_SERVER, pwzBuf, 0)); if (hr == S_OK) //VER_NT_SERVER The system is a server. osvi.wProductType = VER_NT_SERVER; else { IF_FAILED_EXIT(E_FAIL); } } } VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL ); dwTypeMask |= VER_PRODUCT_TYPE; } else if (i == CAssemblyManifestImport::Suite) { // ISSUE-06/07/02-felixybc suite mask should allow specifying multiple with AND OR conditions // use goto done to avoid indenting. IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_BACKOFFICE, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_BACKOFFICE Microsoft BackOffice components are installed. osvi.wSuiteMask |= VER_SUITE_BACKOFFICE; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_BLADE, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_BLADE Windows Web Server is installed. osvi.wSuiteMask |= VER_SUITE_BLADE; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_DATACENTER, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_DATACENTER Windows 2000 or Windows Datacenter Server is installed. osvi.wSuiteMask |= VER_SUITE_DATACENTER; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_ENTERPRISE, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_ENTERPRISE Windows 2000 Advanced Server or Windows Enterprise Server is installed. osvi.wSuiteMask |= VER_SUITE_ENTERPRISE; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_PERSONAL, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_PERSONAL Windows XP Home Edition is installed. osvi.wSuiteMask |= VER_SUITE_PERSONAL; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_SMALLBUSINESS, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_SMALLBUSINESS Microsoft Small Business Server is installed. osvi.wSuiteMask |= VER_SUITE_SMALLBUSINESS; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_SMALLBUSINESS_RESTRICTED, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_SMALLBUSINESS_RESTRICTED Microsoft Small Business Server is installed with the restrictive client license in force. osvi.wSuiteMask |= VER_SUITE_SMALLBUSINESS_RESTRICTED; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_TERMINAL, pwzBuf, 0)); if (hr == S_OK) //VER_SUITE_TERMINAL Terminal Services is installed. osvi.wSuiteMask |= VER_SUITE_TERMINAL; else { IF_FAILED_EXIT(FusionCompareString(WZ_PLATFORM_OS_SUITE_PROFESSIONAL, pwzBuf, 0)); if (hr == S_OK) bCheckProfessionalSuite = TRUE; else { IF_FAILED_EXIT(E_FAIL); } } // more from winnt.h.. //#define VER_SUITE_COMMUNICATIONS //#define VER_SUITE_EMBEDDEDNT //#define VER_SUITE_SINGLEUSERTS //#define VER_SUITE_EMBEDDED_RESTRICTED } } } } } } } // ISSUE-06/07/02-felixybc assume AND condition VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND ); dwTypeMask |= VER_SUITENAME; } //else should not happen //hr = E_FAIL; SAFEDELETEARRAY(pwzBuf); } } } // ISSUE-06/07/02-felixybc assume nt only osvi.dwPlatformId = VER_PLATFORM_WIN32_NT; VER_SET_CONDITION( dwlConditionMask, VER_PLATFORMID, VER_EQUAL ); dwTypeMask |= VER_PLATFORMID; // Perform the test BOOL bResult = VerifyVersionInfo( &osvi, dwTypeMask, dwlConditionMask); if (!bResult) { DWORD dw = GetLastError(); if (dw != ERROR_OLD_WIN_VERSION) hr = HRESULT_FROM_WIN32(dw); else hr = S_FALSE; } else { hr = S_OK; if (bCheckProfessionalSuite) { // do "professional" - do a GetVersionEx after to check suite // ISSUE-06/14/02-felixybc check 'professional'. API has no notion of professional // assume "not home" == "professional" // note: type==workstation for Home/Pro but suite==Home for Home OSVERSIONINFOEX osvx; ZeroMemory(&osvx, sizeof(OSVERSIONINFOEX)); osvx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); IF_WIN32_FALSE_EXIT(GetVersionEx((OSVERSIONINFO*) &osvx)); if ((osvx.wSuiteMask & VER_SUITE_PERSONAL) || (osvx.wProductType != VER_NT_WORKSTATION)) { hr = S_FALSE; } } } exit: SAFEDELETEARRAY(pwzBuf); SAFEDELETEARRAY(pdwVal); return hr; } HRESULT CheckOS(LPMANIFEST_DATA pPlatformData) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); DWORD dwCount = 0; LPMANIFEST_DATA pOSData = NULL; DWORD cbProperty = 0; DWORD dwType = 0; BOOL bFound = FALSE; while (TRUE) { // test a list of versions - as soon as 1 is satisfied, this check succeeds IF_FAILED_EXIT((static_cast(pPlatformData))->Get(dwCount, (LPVOID*) &pOSData, &cbProperty, &dwType)); if (pOSData == NULL) break; IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_IUNKNOWN_PTR, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_FAILED_EXIT(CheckOSHelper(pOSData)); if (hr == S_OK) { bFound = TRUE; break; } SAFERELEASE(pOSData); dwCount++; } if (bFound) hr = S_OK; else hr = S_FALSE; exit: SAFERELEASE(pOSData); return hr; } HRESULT CheckDotNet(LPMANIFEST_DATA pPlatformData) { #define WZ_DOTNETREGPATH L"Software\\Microsoft\\.NetFramework\\Policy\\" HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); DWORD dwCount = 0; LPWSTR pwzVersion = NULL; DWORD cbProperty = 0; DWORD dwType = 0; CString sRegPath; CString sVersion; CString sBuildNum; CRegImport *pRegImport = NULL; BOOL bFound = FALSE; while (TRUE) { // test a list of versions - as soon as 1 is found, this check succeeds IF_FAILED_EXIT((static_cast(pPlatformData))->Get(dwCount, (LPVOID*) &pwzVersion, &cbProperty, &dwType)); if (pwzVersion == NULL) break; IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_LPWSTR, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_FAILED_EXIT(sVersion.TakeOwnership(pwzVersion, cbProperty/sizeof(WCHAR))); pwzVersion = NULL; // xml format: // registry layout: HKLM\software\microsoft\.netframework\policy\v1.0, value name=4122 IF_FAILED_EXIT(sVersion.SplitLastElement(L'.', sBuildNum)); IF_FAILED_EXIT(sRegPath.Assign(WZ_DOTNETREGPATH)); IF_FAILED_EXIT(sRegPath.Append(sVersion)); // note: require access to HKLM IF_FAILED_EXIT(CRegImport::Create(&pRegImport, sRegPath._pwz, HKEY_LOCAL_MACHINE)); if (hr == S_OK) { IF_FAILED_EXIT(pRegImport->Check(sBuildNum._pwz, bFound)); if (bFound) break; SAFEDELETE(pRegImport); } dwCount++; } if (bFound) hr = S_OK; else hr = S_FALSE; exit: SAFEDELETEARRAY(pwzVersion); SAFEDELETE(pRegImport); return hr; } HRESULT CheckManagedPlatform(LPMANIFEST_DATA pPlatformData) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LPASSEMBLY_IDENTITY pAsmId = NULL; DWORD cbProperty = 0; DWORD dwType = 0; CString sAsmPath; // ISSUE-06/07/02-felixybc apply policy also; use Fusion's PreBind IF_FAILED_EXIT(pPlatformData->Get(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyIdTag].pwz, (LPVOID*) &pAsmId, &cbProperty, &dwType)); IF_NULL_EXIT(pAsmId, E_FAIL); IF_FALSE_EXIT(dwType == MAN_DATA_TYPE_IUNKNOWN_PTR, E_FAIL); IF_FAILED_EXIT(CAssemblyCache::GlobalCacheLookup(pAsmId, sAsmPath)); exit: SAFERELEASE(pAsmId); return hr; } HRESULT CheckPlatform(LPMANIFEST_DATA pPlatformData) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); CString sPlatformType; LPWSTR pwzBuf = NULL; // get the platform type IF_FAILED_EXIT(pPlatformData->GetType(&pwzBuf)); IF_NULL_EXIT(pwzBuf, E_FAIL); // use accessor. IF_FAILED_EXIT(sPlatformType.TakeOwnership(pwzBuf)); pwzBuf = NULL; IF_FAILED_EXIT(sPlatformType.CompareString(WZ_DATA_PLATFORM_OS)); if (hr == S_OK) { IF_FAILED_EXIT(CheckOS(pPlatformData)); } else { IF_FAILED_EXIT(sPlatformType.CompareString(WZ_DATA_PLATFORM_DOTNET)); if (hr == S_OK) { IF_FAILED_EXIT(CheckDotNet(pPlatformData)); } else { /*IF_FAILED_EXIT(sName.CompareString(DX)); if (hr == S_OK) { IF_FAILED_EXIT(CheckDirectX(pPlatformData)); } else {*/ IF_FAILED_EXIT(sPlatformType.CompareString(WZ_DATA_PLATFORM_MANAGED)); if (hr == S_OK) { IF_FAILED_EXIT(CheckManagedPlatform(pPlatformData)); } else hr = E_FAIL; //} } } exit: SAFEDELETEARRAY(pwzBuf); return hr; }