//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1998. // // File: packages.cpp // // Contents: Methods on CScopePane related to package deployment // and maintenence of the various index and cross-reference // structures. // // Classes: // // Functions: CopyPackageDetail // FreePackageDetail // GetMsiProperty // // History: 2-03-1998 stevebl Created // 3-25-1998 stevebl Added GetMsiProperty // 5-20-1998 RahulTh - Added DetectUpgrades for automatic upgrade // detection // - Added GetCapitalizedExt // //--------------------------------------------------------------------------- // UNDONE - put in exception handling for low memory conditions #include "precomp.hxx" // uncomment this line to get the old behavior of putting up an upgrade // dialog for auto-detected upgrades //#define SHOWDETECTEDUPGRADEDIALOG //IMalloc * g_pIMalloc = NULL; BOOL IsNullGUID (GUID *pguid) { return ( (pguid->Data1 == 0) && (pguid->Data2 == 0) && (pguid->Data3 == 0) && (pguid->Data4[0] == 0) && (pguid->Data4[1] == 0) && (pguid->Data4[2] == 0) && (pguid->Data4[3] == 0) && (pguid->Data4[4] == 0) && (pguid->Data4[5] == 0) && (pguid->Data4[6] == 0) && (pguid->Data4[7] == 0) ); } void FreePlatformInfo(PLATFORMINFO * &ppiOut) { if (ppiOut) { OLESAFE_DELETE(ppiOut->prgPlatform); OLESAFE_DELETE(ppiOut->prgLocale); OLESAFE_DELETE(ppiOut); } } HRESULT CopyPlatformInfo(PLATFORMINFO * &ppiOut, PLATFORMINFO * & ppiIn) { if (NULL == ppiIn) { ppiOut = NULL; return S_OK; } UINT n; ppiOut = (PLATFORMINFO *)OLEALLOC(sizeof(PLATFORMINFO)); if (!ppiOut) { goto out_of_memory; } memcpy(ppiOut, ppiIn, sizeof(PLATFORMINFO)); ppiOut->prgPlatform = NULL; ppiOut->prgLocale = NULL; n = ppiIn->cPlatforms; if (n) { ppiOut->prgPlatform = (CSPLATFORM*) OLEALLOC(sizeof(CSPLATFORM) * n); if (!ppiOut->prgPlatform) { goto out_of_memory; } memcpy(ppiOut->prgPlatform, ppiIn->prgPlatform, sizeof(CSPLATFORM) * n); } n = ppiIn->cLocales; if (n) { ppiOut->prgLocale = (LCID *) OLEALLOC(sizeof(LCID) * n); if (!ppiOut->prgLocale) { goto out_of_memory; } memcpy(ppiOut->prgLocale, ppiIn->prgLocale, sizeof(LCID) * n); } return S_OK; out_of_memory: FreePlatformInfo(ppiOut); return E_OUTOFMEMORY; } void FreeActInfo(ACTIVATIONINFO * &paiOut) { if (paiOut) { if (paiOut->pClasses) { UINT n = paiOut->cClasses; while (n--) { OLESAFE_DELETE(paiOut->pClasses[n].prgProgId); } OLESAFE_DELETE(paiOut->pClasses); } OLESAFE_DELETE(paiOut->prgInterfaceId); OLESAFE_DELETE(paiOut->prgPriority); if (paiOut->prgShellFileExt) { UINT n = paiOut->cShellFileExt; while (n--) { OLESAFE_DELETE(paiOut->prgShellFileExt[n]) } OLESAFE_DELETE(paiOut->prgShellFileExt); } OLESAFE_DELETE(paiOut->prgTlbId); OLESAFE_DELETE(paiOut); } } HRESULT CopyActInfo(ACTIVATIONINFO * & paiOut, ACTIVATIONINFO * & paiIn) { if (NULL == paiIn) { paiOut = NULL; return S_OK; } UINT n; paiOut = (ACTIVATIONINFO *) OLEALLOC(sizeof(ACTIVATIONINFO)); if (!paiOut) { goto out_of_memory; } memcpy(paiOut, paiIn, sizeof(ACTIVATIONINFO)); paiOut->prgInterfaceId = NULL; paiOut->prgPriority = NULL; paiOut->prgShellFileExt = NULL; paiOut->prgTlbId = NULL; paiOut->pClasses = NULL; n = paiIn->cClasses; paiOut->bHasClasses = paiIn->bHasClasses; if (n) { paiOut->pClasses = (CLASSDETAIL *) OLEALLOC(sizeof(CLASSDETAIL) * n); if (!paiOut->pClasses) { goto out_of_memory; } memcpy(paiOut->pClasses, paiIn->pClasses, sizeof(CLASSDETAIL) * n); while (n--) { UINT n2 = paiIn->pClasses[n].cProgId; if (n2) { paiOut->pClasses[n].prgProgId = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n2); if (!paiOut->pClasses[n].prgProgId) { goto out_of_memory; } while (n2--) { OLESAFE_COPYSTRING(paiOut->pClasses[n].prgProgId[n2], paiIn->pClasses[n].prgProgId[n2]); } } } } n = paiIn->cShellFileExt; if (n) { paiOut->prgPriority = (UINT *) OLEALLOC(sizeof(UINT) * n); if (!paiOut->prgPriority) { goto out_of_memory; } memcpy(paiOut->prgPriority, paiIn->prgPriority, sizeof(UINT) * n); paiOut->prgShellFileExt = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n); if (!paiOut->prgShellFileExt) { goto out_of_memory; } while (n--) { OLESAFE_COPYSTRING(paiOut->prgShellFileExt[n], paiIn->prgShellFileExt[n]); } } n = paiIn->cInterfaces; if (n) { paiOut->prgInterfaceId = (IID *) OLEALLOC(sizeof(IID) * n); if (!paiOut->prgInterfaceId) { goto out_of_memory; } memcpy(paiOut->prgInterfaceId, paiIn->prgInterfaceId, sizeof(IID) * n); } n = paiIn->cTypeLib; if (n) { paiOut->prgTlbId = (GUID *) OLEALLOC(sizeof(GUID) * n); if (!paiOut->prgTlbId) { goto out_of_memory; } memcpy(paiOut->prgTlbId, paiIn->prgTlbId, sizeof(GUID) * n); } return S_OK; out_of_memory: FreeActInfo(paiOut); return E_OUTOFMEMORY; } void FreeInstallInfo(INSTALLINFO * &piiOut) { if (piiOut) { if (piiOut->prgUpgradeInfoList) { UINT n = piiOut->cUpgrades; while (n--) { OLESAFE_DELETE(piiOut->prgUpgradeInfoList[n].szClassStore); } OLESAFE_DELETE(piiOut->prgUpgradeInfoList); } OLESAFE_DELETE(piiOut->pClsid); OLESAFE_DELETE(piiOut->pszScriptPath); OLESAFE_DELETE(piiOut->pszSetupCommand); OLESAFE_DELETE(piiOut->pszUrl); OLESAFE_DELETE(piiOut); } } HRESULT CopyInstallInfo(INSTALLINFO * & piiOut, INSTALLINFO * & piiIn) { ULONG n; if (NULL == piiIn) { piiOut = NULL; return S_OK; } piiOut = (INSTALLINFO *) OLEALLOC(sizeof(INSTALLINFO)); if (!piiOut) { goto out_of_memory; } memcpy(piiOut, piiIn, sizeof(INSTALLINFO)); piiOut->pClsid = NULL; piiOut->prgUpgradeInfoList = NULL; piiOut->pszScriptPath = NULL; piiOut->pszSetupCommand = NULL; piiOut->pszUrl = NULL; OLESAFE_COPYSTRING(piiOut->pszScriptPath, piiIn->pszScriptPath); OLESAFE_COPYSTRING(piiOut->pszSetupCommand, piiIn->pszSetupCommand); OLESAFE_COPYSTRING(piiOut->pszUrl, piiIn->pszUrl); if (piiIn->pClsid) { piiOut->pClsid = (GUID *) OLEALLOC(sizeof(GUID)); if (!piiOut->pClsid) { goto out_of_memory; } memcpy(piiOut->pClsid, piiIn->pClsid, sizeof(GUID)); } n = piiIn->cUpgrades; if (n) { piiOut->prgUpgradeInfoList = (UPGRADEINFO *) OLEALLOC(sizeof(UPGRADEINFO) * n); if (!piiOut->prgUpgradeInfoList) { goto out_of_memory; } memcpy(piiOut->prgUpgradeInfoList, piiIn->prgUpgradeInfoList, sizeof(UPGRADEINFO) * n); while (n--) { OLESAFE_COPYSTRING(piiOut->prgUpgradeInfoList[n].szClassStore, piiIn->prgUpgradeInfoList[n].szClassStore); } } return S_OK; out_of_memory: FreeInstallInfo(piiOut); return E_OUTOFMEMORY; } void InternalFreePackageDetail(PACKAGEDETAIL * &ppdOut) { if (ppdOut) { FreeActInfo(ppdOut->pActInfo); FreePlatformInfo(ppdOut->pPlatformInfo); FreeInstallInfo(ppdOut->pInstallInfo); OLESAFE_DELETE(ppdOut->pszPackageName); OLESAFE_DELETE(ppdOut->pszPublisher); if (ppdOut->pszSourceList) { UINT n = ppdOut->cSources; while (n--) { OLESAFE_DELETE(ppdOut->pszSourceList[n]); } OLESAFE_DELETE(ppdOut->pszSourceList); } OLESAFE_DELETE(ppdOut->rpCategory); } } HRESULT CopyPackageDetail(PACKAGEDETAIL * & ppdOut, PACKAGEDETAIL * & ppdIn) { ULONG n; if (NULL == ppdIn) { ppdOut = NULL; return S_OK; } ppdOut = new PACKAGEDETAIL; if (!ppdOut) { goto out_of_memory; } memcpy(ppdOut, ppdIn, sizeof(PACKAGEDETAIL)); ppdOut->pActInfo = NULL; ppdOut->pInstallInfo = NULL; ppdOut->pPlatformInfo = NULL; ppdOut->pszPackageName = NULL; ppdOut->pszPublisher = NULL; ppdOut->pszSourceList = NULL; ppdOut->rpCategory = NULL; OLESAFE_COPYSTRING(ppdOut->pszPackageName, ppdIn->pszPackageName); n = ppdIn->cSources; if (n) { ppdOut->pszSourceList = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n); if (!ppdOut->pszSourceList) { goto out_of_memory; } while (n--) { OLESAFE_COPYSTRING(ppdOut->pszSourceList[n], ppdIn->pszSourceList[n]); } } n = ppdIn->cCategories; if (n) { ppdOut->rpCategory = (GUID *)OLEALLOC(sizeof(GUID) * n); if (!ppdOut->rpCategory) { goto out_of_memory; } memcpy(ppdOut->rpCategory, ppdIn->rpCategory, sizeof(GUID) * n); } if FAILED(CopyActInfo(ppdOut->pActInfo, ppdIn->pActInfo)) goto out_of_memory; if FAILED(CopyPlatformInfo(ppdOut->pPlatformInfo, ppdIn->pPlatformInfo)) goto out_of_memory; if FAILED(CopyInstallInfo(ppdOut->pInstallInfo, ppdIn->pInstallInfo)) goto out_of_memory; return S_OK; out_of_memory: LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, E_OUTOFMEMORY); InternalFreePackageDetail(ppdOut); if (ppdOut) delete ppdOut; return E_OUTOFMEMORY; } void FreePackageDetail(PACKAGEDETAIL * & ppd) { if (ppd) { ReleasePackageDetail(ppd); delete ppd; ppd = NULL; } } //+-------------------------------------------------------------------------- // // Member: CScopePane::GetUniquePackageName // // Synopsis: Returns a unique package name. // // Arguments: [sz] - [in] the name of the package // [out] the new name, guaranteed unique on this cs // // History: 1-23-1998 stevebl Created // // Notes: First the input name is checked for uniqueness. If it is // already unique it is returned unchanged. If it is not // unique then a new name is formed by adding " (2)" to the end // of the string, then " (3)" and " (4)" and so on until a // unique name is found. // // If you don't want a number appended to the name, nHint must // be 1. // // The value passed back in nHint will be the seed for the // next try. // //--------------------------------------------------------------------------- void CScopePane::GetUniquePackageName(CString szRoot, CString &szOut, int &nHint) { map::iterator i; set sNames; int cch = szRoot.GetLength(); for (i=m_AppData.begin(); i != m_AppData.end(); i++) { // As an optimization, I'm only going to add names that might match // this one to the set. LPOLESTR szName = i->second.m_pDetails->pszPackageName; if ((0 == wcsncmp(szRoot, szName, cch)) && (i->second.m_fVisible)) sNames.insert(szName); } szOut = szRoot; if (nHint++ == 1) // try the first name { if (sNames.end() == sNames.find(szOut)) return; } // now check for a match do { szOut.Format(L"%s (%i)", (LPCTSTR)szRoot, nHint++); if (sNames.end() == sNames.find(szOut)) { // we are unique return; } // try a different name } while (TRUE); } //+-------------------------------------------------------------------------- // // Member: CScopePand::GetDeploymentType // // Synopsis: // // Arguments: [szPackagePath] - // [lpFileTitle] - // // Returns: // // Modifies: // // Derivation: // // History: 6-29-1998 stevebl Created // // Notes: // //--------------------------------------------------------------------------- HRESULT CScopePane::GetDeploymentType(PACKAGEDETAIL * ppd, BOOL & fShowPropertySheet) { INSTALLINFO * pii = ppd->pInstallInfo; if (m_ToolDefaults.fUseWizard) { CDeployApp dlgDeployApp; // Turn on theme'ing for the dialog by activating the theme context CThemeContextActivator themer; dlgDeployApp.m_fMachine = m_fMachine; dlgDeployApp.m_fCrappyZaw = pii->PathType == SetupNamePath; if (IDCANCEL == dlgDeployApp.DoModal()) { return E_FAIL; } switch (dlgDeployApp.m_iDeployment) { default: case 0: //published pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; break; case 1: // assigned pii->dwActFlags = ACTFLG_Assigned | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; break; case 3: // disabled pii->dwActFlags = 0; break; case 2: // custom if (m_fMachine) { pii->dwActFlags = ACTFLG_Assigned | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; } else { pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; } fShowPropertySheet = TRUE; } } else { switch (m_ToolDefaults.NPBehavior) { default: case NP_PUBLISHED: if (!m_fMachine) { pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; break; } case NP_ASSIGNED: if (pii->PathType != SetupNamePath) { pii->dwActFlags = ACTFLG_Assigned | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; } else { // Crappy ZAW app.. force it to be published. pii->dwActFlags = ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall; } break; case NP_DISABLED: pii->dwActFlags = 0; break; } if (m_ToolDefaults.fCustomDeployment) { fShowPropertySheet = TRUE; } } return S_OK; } //+-------------------------------------------------------------------------- // // Member: CScopePane::DeployPackage // // Synopsis: // // Arguments: [hr] - // [hr] - // // Returns: // // Modifies: // // Derivation: // // History: 6-29-1998 stevebl Created // // Notes: // //--------------------------------------------------------------------------- HRESULT CScopePane::DeployPackage(PACKAGEDETAIL * ppd, BOOL fShowPropertySheet) { CHourglass hourglass; INSTALLINFO * pii = ppd->pInstallInfo; HRESULT hrDeploy = S_OK; hrDeploy = PrepareExtensions(*ppd); if (SUCCEEDED(hrDeploy)) { DWORD dwRememberFlags; // put the entry in the class store if (fShowPropertySheet) { dwRememberFlags = pii->dwActFlags; pii->dwActFlags = 0; // disabled state } if (!m_pIClassAdmin) { hrDeploy = GetClassStore(TRUE); if (FAILED(hrDeploy)) { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_NOCLASSSTORE_ERROR, hrDeploy); DebugMsg((DM_WARNING, TEXT("GetClassStore failed with 0x%x"), hrDeploy)); } } if (SUCCEEDED(hrDeploy)) { hrDeploy = m_pIClassAdmin->AddPackage(ppd, &ppd->pInstallInfo->PackageGuid); if (FAILED(hrDeploy)) { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_ADDPACKAGE_ERROR, hrDeploy, ppd->pszPackageName); DebugMsg((DM_WARNING, TEXT("AddPackage failed with 0x%x"), hrDeploy)); } } if (FAILED(hrDeploy)) { return hrDeploy; } if (fShowPropertySheet) { pii->dwActFlags = dwRememberFlags; // restore state } } if (SUCCEEDED(hrDeploy)) { CString szCSPath; hrDeploy = GetClassStoreName(szCSPath, FALSE); if (FAILED(hrDeploy)) { DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hrDeploy)); return hrDeploy; } CAppData data; hrDeploy = CopyPackageDetail(data.m_pDetails, ppd); if (FAILED(hrDeploy)) { DebugMsg((DM_WARNING, TEXT("CopyPackageDetail failed with 0x%x"), hrDeploy)); return hrDeploy; } data.InitializeExtraInfo(); m_lLastAllocated++; // make sure that m_lLastAllocated hasn't already been used while (m_AppData.end() != m_AppData.find(m_lLastAllocated)) { m_lLastAllocated++; } data.m_fVisible = FALSE; m_AppData[m_lLastAllocated] = data; BOOL fAddOk = TRUE; // The admin has said he wants to do a "custom" deployment. if (fShowPropertySheet) { HRESULT hr; // errors that happen while setting up // the property sheets are NOT to be // reported as deployment errors. MMC_COOKIE cookie = m_lLastAllocated; PROPSHEETHEADER psh; memset(&psh, 0, sizeof(psh)); psh.dwSize = sizeof(psh); psh.dwFlags = PSH_NOAPPLYNOW | PSH_PROPTITLE; psh.pszCaption = m_AppData[m_lLastAllocated].m_pDetails->pszPackageName; int nPage = 0; HPROPSHEETPAGE rgPages[6]; psh.phpage = rgPages; // // Create the Product property page // CProduct prpProduct; prpProduct.m_fPreDeploy = TRUE; prpProduct.m_pData = &m_AppData[m_lLastAllocated]; prpProduct.m_cookie = cookie; prpProduct.m_pScopePane = this; prpProduct.m_pAppData = &m_AppData; prpProduct.m_pIGPEInformation = m_pIGPEInformation; prpProduct.m_fMachine = m_fMachine; prpProduct.m_fRSOP = m_fRSOP; // no longer need to marshal this interface, just set it prpProduct.m_pIClassAdmin = m_pIClassAdmin; m_pIClassAdmin->AddRef(); rgPages[nPage++] = CreateThemedPropertySheetPage(&prpProduct.m_psp); // // Create the Depeployment property page // CDeploy prpDeploy; prpDeploy.m_fPreDeploy = TRUE; prpDeploy.m_pData = &m_AppData[m_lLastAllocated]; prpDeploy.m_cookie = cookie; prpDeploy.m_fMachine = m_fMachine; prpDeploy.m_fRSOP = m_fRSOP; prpDeploy.m_pScopePane = this; #if 0 prpDeploy.m_pIGPEInformation = m_pIGPEInformation; #endif // no longer need to marshal this interface, just set it prpDeploy.m_pIClassAdmin = m_pIClassAdmin; m_pIClassAdmin->AddRef(); rgPages[nPage++] = CreateThemedPropertySheetPage(&prpDeploy.m_psp); CUpgradeList prpUpgradeList; if (pii->PathType != SetupNamePath) { // // Create the upgrades property page // prpUpgradeList.m_pData = &m_AppData[m_lLastAllocated]; prpUpgradeList.m_cookie = cookie; prpUpgradeList.m_pScopePane = this; prpUpgradeList.m_fPreDeploy = TRUE; prpUpgradeList.m_fMachine = m_fMachine; prpUpgradeList.m_fRSOP = m_fRSOP; #if 0 prpUpgradeList.m_pIGPEInformation = m_pIGPEInformation; #endif // no longer need to marshal the interface, just set it prpUpgradeList.m_pIClassAdmin = m_pIClassAdmin; m_pIClassAdmin->AddRef(); rgPages[nPage++] = CreateThemedPropertySheetPage(&prpUpgradeList.m_psp); } // // make sure we have an up-to-date categories list // ClearCategories(); hr = CsGetAppCategories(&m_CatList); if (FAILED(hr)) { // report it LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GETCATEGORIES_ERROR, hr, NULL); // Since failure only means the categories list will be // empty, we'll proceed as if nothing happened. hr = S_OK; } // // Create the Category property page // CCategory prpCategory; prpCategory.m_pData = &m_AppData[m_lLastAllocated]; prpCategory.m_cookie = cookie; prpCategory.m_pCatList = &m_CatList; prpCategory.m_fRSOP = m_fRSOP; prpCategory.m_fPreDeploy = TRUE; // no longer need to marshal this interface, just set it prpCategory.m_pIClassAdmin = m_pIClassAdmin; m_pIClassAdmin->AddRef(); rgPages[nPage++] = CreateThemedPropertySheetPage(&prpCategory.m_psp); CXforms prpXforms; if (pii->PathType != SetupNamePath) { // // Create the Xforms property page // prpXforms.m_fPreDeploy = TRUE; prpXforms.m_pData = &m_AppData[m_lLastAllocated]; prpXforms.m_cookie = cookie; prpXforms.m_pScopePane = this; // no longer need to marshal the interface, just set it prpXforms.m_pIClassAdmin = m_pIClassAdmin; m_pIClassAdmin->AddRef(); rgPages[nPage++] = CreateThemedPropertySheetPage(&prpXforms.m_psp); } // // Create the security property page // CString szPath; hr = GetPackageDSPath(szPath, m_AppData[m_lLastAllocated].m_pDetails->pszPackageName); if (SUCCEEDED(hr)) { LPSECURITYINFO pSI; hr = DSCreateISecurityInfoObject(szPath, NULL, 0, &pSI, NULL, NULL, 0); if (SUCCEEDED(hr)) { rgPages[nPage++] = CreateSecurityPage(pSI); pSI->Release(); } else { DebugMsg((DM_WARNING, TEXT("DSCreateISecurityInfoObject failed with 0x%x"), hr)); } } else { DebugMsg((DM_WARNING, TEXT("GetPackageDSPath failed with 0x%x"), hr)); } psh.nPages = nPage; psh.hwndParent = m_hwndMainWindow; if (IDOK != PropertySheet(&psh)) { fAddOk = FALSE; RemovePackage(cookie, FALSE, TRUE); } else { // Make sure that the package is deployed with the proper // deployment type hr = m_pIClassAdmin->ChangePackageProperties(m_AppData[m_lLastAllocated].m_pDetails->pszPackageName, NULL, &m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->dwActFlags, NULL, NULL, NULL, NULL); if (SUCCEEDED(hr)) { if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine, TRUE, &guidExtension, m_fMachine ? &guidMachSnapin : &guidUserSnapin ))) { ReportPolicyChangedError(m_hwndMainWindow); } } } } if (fAddOk) { set ::iterator i; for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++) { RESULTDATAITEM resultItem; memset(&resultItem, 0, sizeof(resultItem)); if ((*i)->_fVisible) { resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM; resultItem.str = MMC_CALLBACK; resultItem.nImage = m_AppData[m_lLastAllocated].GetImageIndex(this); resultItem.lParam = m_lLastAllocated; hrDeploy = (*i)->m_pResult->InsertItem(&resultItem); } // The following code must be excecuted wheather the InsertItem // call succeeds or not. // There are legitimate cases when InsertItem will fail. For // instance, if the scope pane is being shown, but not the // result pane. m_AppData[m_lLastAllocated].m_fVisible = TRUE; m_AppData[m_lLastAllocated].m_itemID = resultItem.itemID; InsertExtensionEntry(m_lLastAllocated, m_AppData[m_lLastAllocated]); if (m_pFileExt) { m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0); } InsertUpgradeEntry(m_lLastAllocated, m_AppData[m_lLastAllocated]); m_UpgradeIndex[GetUpgradeIndex(m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->PackageGuid)] = m_lLastAllocated; // if this is an upgrade, set icons for upgraded apps to // the proper icon and refresh any open property sheets UINT n = m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->cUpgrades; while (n--) { map::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(m_AppData[m_lLastAllocated].m_pDetails->pInstallInfo->prgUpgradeInfoList[n].PackageGuid)); if (i != m_UpgradeIndex.end()) { if (m_AppData[i->second].m_pUpgradeList) { m_AppData[i->second].m_pUpgradeList->SendMessage(WM_USER_REFRESH, 0, 0); } } } if ((*i)->_fVisible) { if (SUCCEEDED(hrDeploy)) { (*i)->m_pResult->SetItem(&resultItem); (*i)->m_pResult->Sort((*i)->m_nSortColumn, (*i)->m_dwSortOptions, -1); } else { DebugMsg((DM_WARNING, TEXT("InsertItem failed with 0x%x"), hrDeploy)); hrDeploy = S_OK; } } } } } return hrDeploy; } //+-------------------------------------------------------------------------- // // Member: CScopePane::AddZAPPackage // // Synopsis: // // Arguments: [szPackagePath] - // [lpFileTitle] - // // Returns: // // Modifies: // // Derivation: // // History: 6-29-1998 stevebl Created // // Notes: // //--------------------------------------------------------------------------- HRESULT CScopePane::AddZAPPackage(LPCOLESTR szPackagePath, LPCOLESTR lpFileTitle) { CHourglass hourglass; HRESULT hr = E_FAIL; OLECHAR szBuffer[1024]; OLECHAR * sz = szBuffer; CString szFriendlyName; CString szUniqueFriendlyName; int nHint = 1; DWORD dw = GetPrivateProfileString( L"Application", L"FriendlyName", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (0 == dw) { // either bogus FriendlyName or no setup command, both of which are fatal goto bad_script; } szFriendlyName = sz; // save this for later dw = GetPrivateProfileString( L"Application", L"SetupCommand", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (0 == dw) { // either bogus file or no setup command, both of which are fatal bad_script: { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADZAP_ERROR, HRESULT_FROM_WIN32(dw), lpFileTitle); TCHAR szBadScriptBuffer[256]; ::LoadString(ghInstance, IDS_ADDFAILED_ZAP, szBadScriptBuffer, 256); m_pConsole->MessageBox(szBadScriptBuffer, lpFileTitle, MB_OK | MB_ICONEXCLAMATION, NULL); } return E_FAIL; } INSTALLINFO * pii = NULL; PLATFORMINFO * ppi = NULL; ACTIVATIONINFO * pai = NULL; PACKAGEDETAIL *ppd = new PACKAGEDETAIL; if (!ppd) { goto out_of_memory; } memset(ppd, 0, sizeof(PACKAGEDETAIL)); pii = (INSTALLINFO *) OLEALLOC(sizeof(INSTALLINFO)); ppd->pInstallInfo = pii; if (!pii) { goto out_of_memory; } memset(pii, 0, sizeof(INSTALLINFO)); ppi = (PLATFORMINFO *) OLEALLOC(sizeof(PLATFORMINFO)); ppd->pPlatformInfo = ppi; if (!ppi) { goto out_of_memory; } memset(ppi, 0, sizeof(PLATFORMINFO)); pai = (ACTIVATIONINFO *) OLEALLOC(sizeof(ACTIVATIONINFO)); ppd->pActInfo = pai; if (!pai) { goto out_of_memory; } else { memset(pai, 0, sizeof(ACTIVATIONINFO)); pai->bHasClasses = ! m_ToolDefaults.fExtensionsOnly; // Munge the setup path. // surround the path in quotes to be sure that spaces are dealt // with properly CString szPath = L'"'; szPath += szPackagePath; // strip off the package name int ich = szPath.ReverseFind(L'\\'); // check for either slash symbol (just in case) int ich2 = szPath.ReverseFind(L'/'); if (ich2 > ich) { ich = ich2; } if (ich >= 0) { szPath = szPath.Left(ich + 1); // keep the path separator } // merge it with the setup command string BOOL fNeedQuote = TRUE; if (sz[0] == L'"') { // remember that we had a leading quote (no need to insert a quote) // and strip it off sz++; fNeedQuote = FALSE; } while (sz[0]) { if (sz[0] == L'.' && sz[1] == L'.' && (sz[2] == L'/' || sz[2] == L'\\')) { // strip off the last path element // First strip off the path separator (the one we kept previously) szPath = szPath.Left(ich); // now find the symbol ich = szPath.ReverseFind(L'\\'); // check for either slash symbol (just in case) ich2 = szPath.ReverseFind(L'/'); if (ich2 > ich) { ich = ich2; } if (ich >= 0) { szPath = szPath.Left(ich + 1); // keep the path separator } // skip the "..\" sz += 3; } else { if ((0 != sz[0] && L':' == sz[1]) || ((L'\\' == sz[0] || L'/' == sz[0]) && (L'\\' == sz[1] || L'/' == sz[1])) || (0 == wcsncmp(L"http:",sz,5))) { // hard path // throw away szPath; szPath = L""; if (!fNeedQuote) { // make sure we don't drop that quote szPath += L'"'; } // and make sure we don't insert quotes where they're not wanted fNeedQuote = FALSE; } // break the loop on anything other than "..\" break; } } if (fNeedQuote) { CString szTemp = sz; // copy everything up to the first space ich = szTemp.Find(L' '); szPath += szTemp.Left(ich); // then add a quote szPath += L'"'; szPath += szTemp.Mid(ich); } else { szPath += sz; } OLESAFE_COPYSTRING(pii->pszScriptPath, szPath); sz = szBuffer; dw = GetPrivateProfileString( L"Application", L"DisplayVersion", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { // parse product version CString szProdVersion = szBuffer; szProdVersion.TrimLeft(); CString szTemp = szProdVersion.SpanIncluding(L"0123456789"); (void) swscanf(szTemp, L"%u", &pii->dwVersionHi); szProdVersion = szProdVersion.Mid(szTemp.GetLength()); szTemp = szProdVersion.SpanExcluding(L"0123456789"); szProdVersion = szProdVersion.Mid(szTemp.GetLength()); (void) swscanf(szProdVersion, L"%u", &pii->dwVersionLo); } dw = GetPrivateProfileString( L"Application", L"Publisher", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { OLESAFE_COPYSTRING(ppd->pszPublisher, sz); } dw = GetPrivateProfileString( L"Application", L"URL", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { OLESAFE_COPYSTRING(pii->pszUrl, sz); } set sPlatforms; dw = GetPrivateProfileString( L"Application", L"Architecture", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); BOOL fValidPlatform; fValidPlatform = FALSE; if (dw) { CString szPlatforms = szBuffer; CString szTemp; while (szPlatforms.GetLength()) { szTemp = szPlatforms.SpanExcluding(L","); if (0 == szTemp.CompareNoCase(L"intel")) { sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL); fValidPlatform = TRUE; } else if (0 == szTemp.CompareNoCase(L"amd64")) { sPlatforms.insert(PROCESSOR_ARCHITECTURE_AMD64); fValidPlatform = TRUE; } else if (0 == szTemp.CompareNoCase(L"intel64")) { sPlatforms.insert(PROCESSOR_ARCHITECTURE_IA64); fValidPlatform = TRUE; } szPlatforms = szPlatforms.Mid(szTemp.GetLength()+1); } } // // Ensure that if we saw any platforms, at least one of them // was a supported platform // if ( dw && ! fValidPlatform ) { ::LoadString(ghInstance, IDS_ILLEGAL_PLATFORM, szBuffer, 256); m_pConsole->MessageBox(szBuffer, lpFileTitle, MB_OK | MB_ICONEXCLAMATION, NULL); delete ppd; return E_FAIL; } if (0 == sPlatforms.size()) { // If the ZAP file doesn't specify an architecture // then we'll treat is as an x86 package sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL); DebugMsg((DL_VERBOSE, TEXT("No platform detected, assuming x86."))); } ppi->cPlatforms = sPlatforms.size(); ppi->prgPlatform = (CSPLATFORM *) OLEALLOC(sizeof(CSPLATFORM) * (ppi->cPlatforms));; if (!ppi->prgPlatform) { ppi->cPlatforms = 0; goto out_of_memory; } INT iIndex=0; set::iterator iPlatform; for (iPlatform = sPlatforms.begin(); iPlatform != sPlatforms.end(); iPlatform++, iIndex++) { ppi->prgPlatform[iIndex].dwPlatformId = VER_PLATFORM_WIN32_NT; ppi->prgPlatform[iIndex].dwVersionHi = 5; ppi->prgPlatform[iIndex].dwVersionLo = 0; ppi->prgPlatform[iIndex].dwProcessorArch = *iPlatform; } ppi->prgLocale = (LCID *) OLEALLOC(sizeof(LCID)); if (!ppi->prgLocale) { goto out_of_memory; } ppi->cLocales = 1; ppi->prgLocale[0] = 0; // if none is supplied we assume language neutral dw = GetPrivateProfileString( L"Application", L"LCID", NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { (void) swscanf(szBuffer, L"%i", &ppi->prgLocale[0]); // we only deploy one LCID (the primary one) } // Get the list of extensions dw = GetPrivateProfileString( L"ext", NULL, NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { vector v; TCHAR szName[256]; while (sz < &szBuffer[dw]) { while ('.' == sz[0]) sz++; CString szExt = "."; szExt += sz; v.push_back(szExt); sz += (wcslen(sz) + 1); } // build the new list UINT n = v.size(); if (n > 0) { pai->prgShellFileExt = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * n); if (!pai->prgShellFileExt) { goto out_of_memory; } pai->prgPriority = (UINT *) OLEALLOC(sizeof(UINT) * n); if (!pai->prgPriority) { goto out_of_memory; } pai->cShellFileExt = n; while (n--) { CString &szLower = v[n]; szLower.MakeLower(); OLESAFE_COPYSTRING(pai->prgShellFileExt[n], szLower); pai->prgPriority[n] = 0; } } } // get the list of CLSIDs vector v; sz = szBuffer; dw = GetPrivateProfileString( L"CLSIDs", NULL, NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { while (sz < &szBuffer[dw]) { OLECHAR szType[256]; DWORD dwSubKey = GetPrivateProfileString( L"CLSIDs", sz, NULL, szType, sizeof(szType) / sizeof(szType[0]), szPackagePath); CLASSDETAIL cd; memset(&cd, 0, sizeof(CLASSDETAIL)); hr = CLSIDFromString(sz, &cd.Clsid); if (SUCCEEDED(hr)) { CString szTypes = szType; szTypes.MakeLower(); if (szTypes.Find(L"inprocserver32") >= 0) { cd.dwComClassContext |= CLSCTX_INPROC_SERVER; } if (szTypes.Find(L"localserver32") >= 0) { cd.dwComClassContext |= CLSCTX_LOCAL_SERVER; } if (szTypes.Find(L"inprochandler32") >= 0) { cd.dwComClassContext |= CLSCTX_INPROC_HANDLER; } v.push_back(cd); } sz += (wcslen(sz) + 1); } } // get the list of ProgIDs sz = szBuffer; dw = GetPrivateProfileString( L"ProgIDs", NULL, NULL, sz, sizeof(szBuffer) / sizeof(szBuffer[0]), szPackagePath); if (dw) { while (sz < &szBuffer[dw]) { OLECHAR szType[256]; DWORD dwSubKey = GetPrivateProfileString( L"ProgIDs", sz, NULL, szType, sizeof(szType) / sizeof(szType[0]), szPackagePath); CLSID cid; hr = CLSIDFromString(sz, &cid); if (SUCCEEDED(hr)) { // Match it to its CLASSDETAIL structure and insert it into the // ProgID list. // (fat and slow method) vector::iterator i; for (i = v.begin(); i != v.end(); i++) { if (0 == memcmp(&i->Clsid, &cid, sizeof(CLSID))) { // found a match // hereiam vector vIds; CString szAppIds = szType; CString szTemp; while (szAppIds.GetLength()) { szTemp = szAppIds.SpanExcluding(L","); szTemp.TrimLeft(); vIds.push_back(szTemp); szAppIds = szAppIds.Mid(szTemp.GetLength()+1); } while (i->cProgId--) { OLESAFE_DELETE(i->prgProgId[i->cProgId]); } OLESAFE_DELETE(i->prgProgId); DWORD cProgId = vIds.size(); LPOLESTR * prgProgId = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR) * (cProgId)); if (!prgProgId) { goto out_of_memory; } i->cProgId = cProgId; while (cProgId--) { OLESAFE_COPYSTRING(prgProgId[cProgId], vIds[cProgId]); } i->prgProgId = prgProgId; } } } sz += (wcslen(sz) + 1); } } // create the list of CLASSDETAIL structures { UINT n = v.size(); if (n > 0) { pai->pClasses = (CLASSDETAIL *) OLEALLOC(sizeof(CLASSDETAIL) * n); if (!pai->pClasses) { goto out_of_memory; } pai->cClasses = n; while (n--) { pai->pClasses[n] = v[n]; } } } ppd->pszSourceList = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR)); if (!ppd->pszSourceList) { goto out_of_memory; } ppd->cSources = 1; OLESAFE_COPYSTRING(ppd->pszSourceList[0], szPackagePath); GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint); OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName); // Popup UI pii->PathType = SetupNamePath; BOOL fShowPropertyPage = FALSE; hr = GetDeploymentType(ppd, fShowPropertyPage); if (SUCCEEDED(hr)) { CHourglass hourglass; if (m_ToolDefaults.fZapOn64) { pii->dwActFlags |= ACTFLG_ExcludeX86OnWin64; // same as ACTFLG_ZAP_IncludeX86OfWin64 } do { hr = DeployPackage(ppd, fShowPropertyPage); if (hr == CS_E_OBJECT_ALREADY_EXISTS) { OLESAFE_DELETE(ppd->pszPackageName); GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint); OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName); } } while (hr == CS_E_OBJECT_ALREADY_EXISTS); } if (FAILED(hr) && hr != E_FAIL) // don't report E_FAIL error // because it's a benign error // (probably a dialog cancellation) { // report the error in the event log LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_DEPLOYMENT_ERROR, hr, lpFileTitle); // now try to come up with a meaningful message for the user if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) { // access permission failure ::LoadString(ghInstance, IDS_ADDFAILED_ACCESS_DENIED, szBuffer, 256); } else { switch (hr) { // For these errors, we'll report the party line: case CS_E_CLASS_NOTFOUND: case CS_E_INVALID_VERSION: case CS_E_NO_CLASSSTORE: case CS_E_OBJECT_NOTFOUND: case CS_E_OBJECT_ALREADY_EXISTS: case CS_E_INVALID_PATH: case CS_E_NETWORK_ERROR: case CS_E_ADMIN_LIMIT_EXCEEDED: case CS_E_SCHEMA_MISMATCH: case CS_E_PACKAGE_NOTFOUND: case CS_E_INTERNAL_ERROR: { dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), NULL); if (0 != dw) { // got a valid message string break; } // otherwise fall through and give the generic message } // Either these CS errors don't apply or an admin // wouldn't know what they mean: case CS_E_NOT_DELETABLE: default: // generic class store problem ::LoadString(ghInstance, IDS_ADDFAILED_CSFAILURE, szBuffer, 256); break; } } #if DBG TCHAR szDebugBuffer[256]; dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szDebugBuffer, sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]), NULL); if (0 == dw) { (void) StringCchPrintf(szDebugBuffer, sizeof(szDebugBuffer)/sizeof(szDebugBuffer[0]), TEXT("(HRESULT: 0x%lX)"), hr); } (void) StringCchCat(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szDebugBuffer); #endif m_pConsole->MessageBox(szBuffer, lpFileTitle, MB_OK | MB_ICONEXCLAMATION, NULL); } FreePackageDetail(ppd); } return hr; out_of_memory: if (ppd) { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, E_OUTOFMEMORY); InternalFreePackageDetail(ppd); delete ppd; } return E_OUTOFMEMORY; } //+-------------------------------------------------------------------------- // // Member: CScopePane::AddMSIPackage // // Synopsis: Add's one or more packages to the class store and adds the // appropriate entries to the result pane. // // Arguments: [szPackagePath] - Full path to the Darwin package. // [lpFileTitle] - file title from the open file dialog (used // for UI) // // Returns: S_OK - succeeded // E_FAIL - benign failure (probably a cancellation or something) // other - significant failure // // History: 2-03-1998 stevebl Created // //--------------------------------------------------------------------------- HRESULT CScopePane::AddMSIPackage(LPCOLESTR szPackagePath, LPCOLESTR lpFileTitle) { CHourglass hourglass; AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = E_FAIL; BOOL fPreparationDone = FALSE; // Used to identify if the routine has // progressed passed the "prep" stage // and is now in the deployment stage. // Errors in the earlier part are most // likely due to Darwin problems. // Errors in teh latter part are most // likely due to Class Store problems. set sLocales; CUpgrades dlgUpgrade; int nLocales; set::iterator iLocale; PACKAGEDETAIL *ppd = NULL; CString szFriendlyName; CString szUniqueFriendlyName; int nHint = 1; ASSERT(m_pConsole); { BOOL fShowPropertySheet = FALSE; GUID guid; INSTALLINFO *pii = NULL; PLATFORMINFO *ppi = NULL; ACTIVATIONINFO *pai = NULL; ppd = new PACKAGEDETAIL; if (!ppd) { goto out_of_memory; } memset(ppd, 0, sizeof(PACKAGEDETAIL)); pii = (INSTALLINFO *) OLEALLOC(sizeof(INSTALLINFO)); if (!pii) { goto out_of_memory; } memset(pii, 0, sizeof(INSTALLINFO)); ppi = (PLATFORMINFO *) OLEALLOC(sizeof(PLATFORMINFO)); ppd->pPlatformInfo = ppi; if (!ppi) { goto out_of_memory; } ppd->pInstallInfo = pii; memset(ppi, 0, sizeof(PLATFORMINFO)); pai = (ACTIVATIONINFO *) OLEALLOC(sizeof(ACTIVATIONINFO)); ppd->pActInfo = pai; if (!pai) { goto out_of_memory; } else { memset(pai, 0, sizeof(ACTIVATIONINFO)); pai->bHasClasses = ! m_ToolDefaults.fExtensionsOnly; pii->PathType = DrwFilePath; hr = GetDeploymentType(ppd, fShowPropertySheet); CHourglass hourglass; if (FAILED(hr)) { goto done; } if (!m_ToolDefaults.f32On64) { pii->dwActFlags |= ACTFLG_ExcludeX86OnWin64; // same as ACTFLG_ZAP_IncludeX86OfWin64 } if (m_ToolDefaults.fUninstallOnPolicyRemoval) { pii->dwActFlags |= ACTFLG_UninstallOnPolicyRemoval; } else { pii->dwActFlags |= ACTFLG_OrphanOnPolicyRemoval; } if (m_fMachine) { pii->dwActFlags |= ACTFLG_ForceUpgrade; } pii->InstallUiLevel = m_ToolDefaults.UILevel; // disable MSI ui MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); // Use MsiSummaryInfoGetProperty to get platform and locale info. { MSIHANDLE hSummaryInfo; UINT msiReturn = MsiGetSummaryInformation(0, szPackagePath, 0, &hSummaryInfo); if (ERROR_SUCCESS == msiReturn) { TCHAR szBuffer[256]; DWORD dwSize = 256; msiReturn = MsiSummaryInfoGetProperty(hSummaryInfo, 7, // PID_TEMPLATE NULL, NULL, NULL, szBuffer, &dwSize); if (ERROR_SUCCESS == msiReturn) { // break out the locale and platform properties CString szLocales = szBuffer; CString szPlatforms = szLocales.SpanExcluding(L";"); szLocales = szLocales.Mid(szPlatforms.GetLength()+1); CString szTemp; set sPlatforms; BOOL fValidPlatform; BOOL fPlatformsSpecified; fValidPlatform = FALSE; fPlatformsSpecified = 0 != szPlatforms.GetLength(); while (szPlatforms.GetLength()) { szTemp = szPlatforms.SpanExcluding(L","); if (0 == szTemp.CompareNoCase(L"intel")) { sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL); fValidPlatform = TRUE; } else if (0 == szTemp.CompareNoCase(L"amd64")) { sPlatforms.insert(PROCESSOR_ARCHITECTURE_AMD64); fValidPlatform = TRUE; } else if (0 == szTemp.CompareNoCase(L"intel64")) { sPlatforms.insert(PROCESSOR_ARCHITECTURE_IA64); fValidPlatform = TRUE; } szPlatforms = szPlatforms.Mid(szTemp.GetLength()+1); } // // If platforms have been specified, at least one of them // must be valid // if ( fPlatformsSpecified && ! fValidPlatform ) { hr = HRESULT_FROM_WIN32( ERROR_INSTALL_PLATFORM_UNSUPPORTED ); ppi->cPlatforms = 0; goto done; } while (szLocales.GetLength()) { szTemp = szLocales.SpanExcluding(L","); LCID lcid; if (swscanf(szTemp, L"%i", &lcid) != EOF) { sLocales.insert(lcid); szLocales = szLocales.Mid(szTemp.GetLength()+1); } } if (0 == sPlatforms.size()) { // If the MSI file doesn't specify an architecture // then we'll mark it X86-allow on Win64. sPlatforms.insert(PROCESSOR_ARCHITECTURE_INTEL); pii->dwActFlags &= ~ACTFLG_ExcludeX86OnWin64; DebugMsg((DL_VERBOSE, TEXT("No platform detected, setting to X86 - allow on Win64."))); } if (0 == sLocales.size()) { // If the MSI file doesn't specify a locale then // we'll just assume it's language neutral. DebugMsg((DL_VERBOSE, TEXT("No locale detected, assuming neutral."))); sLocales.insert(0); } ppi->cPlatforms = sPlatforms.size(); ppi->prgPlatform = (CSPLATFORM *) OLEALLOC(sizeof(CSPLATFORM) * (ppi->cPlatforms));; if (!ppi->prgPlatform) { ppi->cPlatforms = 0; goto out_of_memory; } set::iterator iPlatform; INT n = 0; for (iPlatform = sPlatforms.begin(); iPlatform != sPlatforms.end(); iPlatform++, n++) { ppi->prgPlatform[n].dwPlatformId = VER_PLATFORM_WIN32_NT; ppi->prgPlatform[n].dwVersionHi = 5; ppi->prgPlatform[n].dwVersionLo = 0; ppi->prgPlatform[n].dwProcessorArch = *iPlatform; } } MsiCloseHandle(hSummaryInfo); } if (ERROR_SUCCESS != msiReturn) { hr = HRESULT_FROM_WIN32(msiReturn); LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle); goto done; } } { // Grovel through the database to get additional information // that for some reason MSI won't give us any other way. TCHAR szBuffer[256]; DWORD cch = 256; UINT msiReturn = GetMsiProperty(szPackagePath, L"ProductVersion", szBuffer, &cch); if (ERROR_SUCCESS != msiReturn) { hr = HRESULT_FROM_WIN32(msiReturn); LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle); goto done; } if (ERROR_SUCCESS == msiReturn) { // Parse Product Version CString sz = szBuffer; sz.TrimLeft(); CString szTemp = sz.SpanIncluding(L"0123456789"); if (swscanf(szTemp, L"%u", &pii->dwVersionHi) == EOF) { hr = HRESULT_FROM_WIN32(GetLastError()); LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle); goto done; } sz = sz.Mid(szTemp.GetLength()); szTemp = sz.SpanExcluding(L"0123456789"); sz = sz.Mid(szTemp.GetLength()); if (swscanf(sz, L"%u", &pii->dwVersionLo) == EOF) { hr = HRESULT_FROM_WIN32(GetLastError()); LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle); goto done; } } cch = 256; msiReturn = GetMsiProperty(szPackagePath, L"ProductCode", szBuffer, &cch); if (ERROR_SUCCESS != msiReturn) { hr = HRESULT_FROM_WIN32(msiReturn); LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, lpFileTitle); goto done; } if (ERROR_SUCCESS == msiReturn) { // Parse Product Code CLSIDFromString(szBuffer, &pii->ProductCode); } cch = 256; msiReturn = GetMsiProperty(szPackagePath, L"ARPHELPLINK", szBuffer, &cch); if (ERROR_SUCCESS == msiReturn) { OLESAFE_COPYSTRING(pii->pszUrl, szBuffer); } cch = 256; msiReturn = GetMsiProperty(szPackagePath, L"LIMITUI", szBuffer, &cch); if (ERROR_SUCCESS == msiReturn) { pii->dwActFlags |= ACTFLG_MinimalInstallUI; pii->InstallUiLevel = INSTALLUILEVEL_BASIC; } } ppi->prgLocale = (LCID *) OLEALLOC(sizeof(LCID)); if (!ppi->prgLocale) { goto out_of_memory; } ppi->cLocales = 1; ppd->pszSourceList = (LPOLESTR *) OLEALLOC(sizeof(LPOLESTR)); if (!ppd->pszSourceList) { goto out_of_memory; } ppd->cSources = 1; OLESAFE_COPYSTRING(ppd->pszSourceList[0], szPackagePath); if (S_OK == DetectUpgrades(szPackagePath, ppd, dlgUpgrade)) { UINT n = dlgUpgrade.m_UpgradeList.size(); if (n) { pii->prgUpgradeInfoList = (UPGRADEINFO *) OLEALLOC(sizeof(UPGRADEINFO) * n); if (!pii->prgUpgradeInfoList) { goto out_of_memory; } pii->cUpgrades = n; map::iterator i = dlgUpgrade.m_UpgradeList.begin(); while (n--) { pii->prgUpgradeInfoList[n].Flag = i->second.m_flags; OLESAFE_COPYSTRING(pii->prgUpgradeInfoList[n].szClassStore, i->second.m_szClassStore); memcpy(&pii->prgUpgradeInfoList[n].PackageGuid, &i->second.m_PackageGuid, sizeof(GUID)); i++; } } } // // Only one locale may be specified for this package // nLocales = 1; iLocale = sLocales.begin(); { ppi->prgLocale[0] = *iLocale; // set the script path hr = CoCreateGuid(&guid); if (FAILED(hr)) { goto done; } OLECHAR sz [256]; StringFromGUID2(guid, sz, 256); CString szScriptPath = m_szGPT_Path; szScriptPath += L"\\"; szScriptPath += sz; szScriptPath += L".aas"; OLESAFE_DELETE(pii->pszScriptPath); OLESAFE_COPYSTRING(pii->pszScriptPath, szScriptPath); HWND hwnd; m_pConsole->GetMainWindow(&hwnd); hr = BuildScriptAndGetActInfo(*ppd, m_ToolDefaults.fExtensionsOnly); // make sure the name is unique szFriendlyName = ppd->pszPackageName; GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint); OLESAFE_DELETE(ppd->pszPackageName); OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName); if (SUCCEEDED(hr)) { fPreparationDone = TRUE; do { hr = DeployPackage(ppd, fShowPropertySheet); if (hr == CS_E_OBJECT_ALREADY_EXISTS) { GetUniquePackageName(szFriendlyName, szUniqueFriendlyName, nHint); OLESAFE_DELETE(ppd->pszPackageName); OLESAFE_COPYSTRING(ppd->pszPackageName, szUniqueFriendlyName); } } while (hr == CS_E_OBJECT_ALREADY_EXISTS); } if (FAILED(hr)) { // clean up script file if deployment fails DeleteFile(pii->pszScriptPath); } } done: if (FAILED(hr) && hr != E_FAIL) // don't report E_FAIL error // because it's a benign error // (probably a dialog cancellation) { // report the error in the event log LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_DEPLOYMENT_ERROR, hr, lpFileTitle); TCHAR szBuffer[256]; if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) { // access permission failure ::LoadString(ghInstance, IDS_ADDFAILED_ACCESS_DENIED, szBuffer, 256); } else if ( HRESULT_FROM_WIN32( ERROR_INSTALL_PLATFORM_UNSUPPORTED ) == hr ) { ::LoadString(ghInstance, IDS_ILLEGAL_PLATFORM, szBuffer, 256); } else if ( HRESULT_FROM_WIN32( CS_E_ADMIN_LIMIT_EXCEEDED ) == hr ) { ::LoadString(ghInstance, IDS_ADDFAILED_METADATA_OVERFLOW, szBuffer, 256); } else { if (fPreparationDone) { switch (hr) { // For these errors, we'll report the party line: case CS_E_CLASS_NOTFOUND: case CS_E_INVALID_VERSION: case CS_E_NO_CLASSSTORE: case CS_E_OBJECT_NOTFOUND: case CS_E_OBJECT_ALREADY_EXISTS: case CS_E_INVALID_PATH: case CS_E_NETWORK_ERROR: case CS_E_SCHEMA_MISMATCH: case CS_E_PACKAGE_NOTFOUND: case CS_E_INTERNAL_ERROR: { DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), NULL); if (0 != dw) { // got a valid message string break; } // otherwise fall through and give the generic message } // Either these CS errors don't apply or an admin // wouldn't know what they mean: case CS_E_NOT_DELETABLE: default: // generic class store problem ::LoadString(ghInstance, IDS_ADDFAILED_CSFAILURE, szBuffer, 256); break; } } else { // probably some error with the package itself ::LoadString(ghInstance, IDS_ADDFAILED, szBuffer, 256); } } #if DBG TCHAR szDebugBuffer[256]; DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szDebugBuffer, sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]), NULL); if (0 == dw) { (void) StringCchPrintf(szDebugBuffer, sizeof(szDebugBuffer)/sizeof(szDebugBuffer[0]), TEXT("(HRESULT: 0x%lX)"), hr); } (void) StringCchCat(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szDebugBuffer); #endif m_pConsole->MessageBox(szBuffer, lpFileTitle, MB_OK | MB_ICONEXCLAMATION, NULL); } InternalFreePackageDetail(ppd); delete ppd; } } return hr; out_of_memory: if (ppd) { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, E_OUTOFMEMORY); InternalFreePackageDetail(ppd); delete ppd; } return E_OUTOFMEMORY; } //+-------------------------------------------------------------------------- // // Member: CScopePane::DetectUpgrades // // Synopsis: This functions checks if any of the existing packages in the // class store can be upgraded by a given package. If any such // packages exist, then this function populates the m_UpgradeList // member of the dlgUpgrade parameter passed to it. This function // also adds the upgrade code GUID to the PACKAGEDETAIL structure // passed to it. // // Arguments: // szPackagePath - the path of the given package // ppd - pointer to the PACKAGEDETAIL structure of the // given package // dlgUpgrade - the dialog whose member m_UpgradeList needs to be // populated // // Returns: // S_OK the function succeeded in finding upgradeable packages // S_FALSE the function did not encounter any errors, but no // upgradeable packages were found // other failure codes the function encountered errors // // History: 5/19/1998 RahulTh created // // Notes: // //--------------------------------------------------------------------------- HRESULT CScopePane::DetectUpgrades (LPCOLESTR szPackagePath, const PACKAGEDETAIL* ppd, CUpgrades& dlgUpgrade) { DWORD dwBufSize = 50; TCHAR szUpgradeCode[50]; //the upgrade GUID GUID guidUpgradeCode; TCHAR szData[50]; DWORD dwOperator; HRESULT hr; HRESULT hres; MSIHANDLE hDatabase; UINT msiReturn; map::iterator i; INSTALLINFO* pii; BOOL fUpgradeable; LARGE_INTEGER verNew, verExisting; CString szCSPath; hr = GetClassStoreName(szCSPath, FALSE); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr)); } msiReturn = GetMsiProperty(szPackagePath, TEXT("UpgradeCode"), szUpgradeCode, &dwBufSize); if (ERROR_SUCCESS != msiReturn) return HRESULT_FROM_WIN32(msiReturn); //no upgrade code was found hr = CLSIDFromString(szUpgradeCode, &guidUpgradeCode); if (FAILED(hr)) return hr; //insert the upgrade code GUID into the packagedetail structure. memcpy((LPVOID)&(ppd->pInstallInfo->Mvipc), (LPVOID)&guidUpgradeCode, sizeof(GUID)); verNew.LowPart = ppd->pInstallInfo->dwVersionLo; verNew.HighPart = ppd->pInstallInfo->dwVersionHi; hr = S_FALSE; //this will get set to S_OK only if we find any upgradeable packages msiReturn = MsiOpenDatabase (szPackagePath, MSIDBOPEN_READONLY, &hDatabase); if (ERROR_SUCCESS == msiReturn) { CString szQuery; szQuery.Format (TEXT("SELECT `UpgradeCode`, `Attributes`, `VersionMin`, `VersionMax`, `Language` FROM `Upgrade`")); MSIHANDLE hView; msiReturn = MsiDatabaseOpenView(hDatabase, szQuery, &hView); if (ERROR_SUCCESS == msiReturn) { msiReturn = MsiViewExecute (hView, 0); if (ERROR_SUCCESS == msiReturn) { MSIHANDLE hRecord; //for each operator value returned by the query, if an operator is found that permits //upgrades, iterate through the list of existing packages to see if any of those are //upgradeable by the supplied package. If any such package is found, add it to the //m_UpgradeList member of the upgrade dialog dlgUpgrade. do { msiReturn = MsiViewFetch (hView, &hRecord); if (ERROR_SUCCESS == msiReturn) { //reset dwBufSize since it is modified by MsiRecordString during every iteration //of the loop. dwBufSize = 50; //get the upgrade code for this upgrade table entry msiReturn = MsiRecordGetString (hRecord, 1, szData, &dwBufSize); hres = CLSIDFromString (szData, &guidUpgradeCode); if (FAILED(hres)) { MsiCloseHandle(hRecord); continue; //ignore this package and move on to the next } dwBufSize = 50; //must reset to reflect the correct buffer size //get the operator for this upgrade table entry msiReturn = MsiRecordGetString (hRecord, 2, szData, &dwBufSize); int iRetVal; iRetVal = swscanf(szData, TEXT("%d"), &dwOperator); if ((iRetVal != EOF) && (0 == (dwOperator & 0x002))) { // we have a potential hit LARGE_INTEGER verMin; LARGE_INTEGER verMax; // get min version dwBufSize = 50; //must reset to reflect the correct buffer size BOOL fMin = FALSE; msiReturn = MsiRecordGetString (hRecord, 3, szData, &dwBufSize); if (ERROR_SUCCESS == msiReturn && 0 != szData[0]) { fMin = TRUE; // Parse Product Version CString sz = szData; sz.TrimLeft(); CString szTemp = sz.SpanIncluding(L"0123456789"); if (swscanf(szTemp, L"%u", &verMin.HighPart) != EOF) { sz = sz.Mid(szTemp.GetLength()); szTemp = sz.SpanExcluding(L"0123456789"); sz = sz.Mid(szTemp.GetLength()); if (swscanf(sz, L"%u", &verMin.LowPart) == EOF) { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(GetLastError()), szPackagePath); } } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(GetLastError()), szPackagePath); } } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath); } // get max version dwBufSize = 50; //must reset to reflect the correct buffer size BOOL fMax = FALSE; msiReturn = MsiRecordGetString (hRecord, 4, szData, &dwBufSize); if (ERROR_SUCCESS == msiReturn && 0 != szData[0]) { fMax = TRUE; // Parse Product Version CString sz = szData; sz.TrimLeft(); CString szTemp = sz.SpanIncluding(L"0123456789"); if (swscanf(szTemp, L"%u", &verMax.HighPart) != EOF) { sz = sz.Mid(szTemp.GetLength()); szTemp = sz.SpanExcluding(L"0123456789"); sz = sz.Mid(szTemp.GetLength()); if (swscanf(sz, L"%u", &verMax.LowPart) == EOF) { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(GetLastError()), szPackagePath); } } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(GetLastError()), szPackagePath); } } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath); } // get lcid list dwBufSize = 0; //must reset to reflect the correct buffer size BOOL fLcids = FALSE; set sLCID; msiReturn = MsiRecordGetString (hRecord, 5, szData, &dwBufSize); if (ERROR_MORE_DATA == msiReturn) { dwBufSize++; TCHAR * szLanguages = new TCHAR[dwBufSize]; if (szLanguages) { msiReturn = MsiRecordGetString (hRecord, 5, szLanguages, &dwBufSize); if (ERROR_SUCCESS == msiReturn) { // build set of LCIDs CString sz = szLanguages; sz.TrimLeft(); while (!sz.IsEmpty()) { fLcids = TRUE; LCID lcid; CString szTemp = sz.SpanIncluding(L"0123456789"); if (swscanf(szTemp, L"%u", &lcid) != EOF) { sz = sz.Mid(szTemp.GetLength()); szTemp = sz.SpanExcluding(L"0123456789"); sz = sz.Mid(szTemp.GetLength()); sLCID.insert(lcid); } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(GetLastError()), szPackagePath); } } } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath); } delete [] szLanguages; } } else { LogADEEvent(EVENTLOG_WARNING_TYPE, EVENT_ADE_UNEXPECTEDMSI_ERROR, HRESULT_FROM_WIN32(msiReturn), szPackagePath); } //if an operator is found that that does not block installs and //does not force uninstalling of existing apps, then search //for any packages that can be upgraded for (i = m_AppData.begin(); i != m_AppData.end(); i++) { //get the install info. for the app. pii = (i->second.m_pDetails)->pInstallInfo; //process this only if it has the same upgrade code if ( (guidUpgradeCode == pii->Mvipc) && ! IsNullGUID(&guidUpgradeCode) ) { //check if other conditions for the operator are satisfied. verExisting.LowPart = pii->dwVersionLo; verExisting.HighPart = pii->dwVersionHi; // don't even bother to upgrade unless the // new version is greater or equal to the // old version fUpgradeable = (verNew.QuadPart >= verExisting.QuadPart); if (fMin && fUpgradeable) { // check minimum if (0 != (dwOperator & 0x100)) { // inclusive fUpgradeable = verExisting.QuadPart >= verMin.QuadPart; } else { // exclusive fUpgradeable = verExisting.QuadPart > verMin.QuadPart; } } if (fMax && fUpgradeable) { // check maximum if (0 != (dwOperator & 0x200)) { // inclusive fUpgradeable = verExisting.QuadPart <= verMax.QuadPart; } else { // exclusive fUpgradeable = verExisting.QuadPart < verMax.QuadPart; } } if (fLcids && fUpgradeable) { // check the lcid BOOL fMatch = FALSE; // look for a match PLATFORMINFO * ppi = (i->second.m_pDetails)->pPlatformInfo; UINT n = ppi->cLocales; while ((n--) && !fMatch) { if (sLCID.end() != sLCID.find(ppi->prgLocale[n])) { fMatch = TRUE; } } // set the upgradeable flag if (0 != (dwOperator & 0x400)) { // exclusive fUpgradeable = !fMatch; } else { // inclusive fUpgradeable = fMatch; } } if (fUpgradeable) //the package in question can be upgraded { CUpgradeData data; data.m_szClassStore = szCSPath; memcpy(&data.m_PackageGuid, &pii->PackageGuid, sizeof(GUID)); data.m_flags = UPGFLG_NoUninstall | UPGFLG_Enforced; dlgUpgrade.m_UpgradeList.insert(pair(GetUpgradeIndex(data.m_PackageGuid), data)); hr = S_OK; } } } } MsiCloseHandle(hRecord); } } while (NULL != hRecord && ERROR_SUCCESS == msiReturn); MsiViewClose (hView); //close the view to be on the safe side, though it is not absolutely essential } else hr = HRESULT_FROM_WIN32(msiReturn); MsiCloseHandle(hView); } else hr = HRESULT_FROM_WIN32(msiReturn); MsiCloseHandle (hDatabase); } else hr = HRESULT_FROM_WIN32(msiReturn); if (FAILED(hr)) { if (msiReturn != ERROR_SUCCESS) { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_BADMSI_ERROR, hr, szPackagePath); } else { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_GENERAL_ERROR, hr); } } return hr; } //+-------------------------------------------------------------------------- // // Member: CScopePane::DisplayPropSheet // // Synopsis: a generic routine for showing the property sheet for a package // // Arguments: [szPackeName] - name of the package to show properties for // [iPage] - index of the preferred page to display // // Returns: nothing // // History: 3-11-1998 stevebl Created // // Notes: The property sheet will be started on the preferred page // only if it isn't already being displayed, in which case // whatever page was being displayed will retain the focus. // //--------------------------------------------------------------------------- void CScopePane::DisplayPropSheet(CString szPackageName, int iPage) { map ::iterator i = m_AppData.begin(); while (i != m_AppData.end()) { if (0 == szPackageName.Compare(i->second.m_pDetails->pszPackageName)) { IDataObject * pDataObject; HRESULT hr = QueryDataObject(i->first, CCT_RESULT, &pDataObject); if (SUCCEEDED(hr)) { set ::iterator i2; for (i2 = m_sResultPane.begin(); i2 != m_sResultPane.end(); i2++) { hr = m_pIPropertySheetProvider->FindPropertySheet(i->first, (*i2), pDataObject); if (S_FALSE == hr) { m_pIPropertySheetProvider->CreatePropertySheet(i->second.m_pDetails->pszPackageName, TRUE, i->first, pDataObject, 0); m_pIPropertySheetProvider->AddPrimaryPages((*i2)->GetUnknown(), FALSE, NULL, FALSE); m_pIPropertySheetProvider->AddExtensionPages(); m_pIPropertySheetProvider->Show(NULL, iPage); } } } return; } i++; } } //+-------------------------------------------------------------------------- // // Member: CScopePane::RemovePackage // // Synopsis: Removes a package from the class store and the result pane. // // Arguments: [pDataObject] - data object for this result pane item // [fForceUninstall] - TRUE - force app to be uninstalled on // client machines // FALSE - orphan any installations // // Returns: S_OK - success // // History: 2-03-1998 stevebl Created // 3-30-1998 stevebl adde fForceUninstall // // Notes: bAssigned is used // //--------------------------------------------------------------------------- HRESULT CScopePane::RemovePackage(MMC_COOKIE cookie, BOOL fForceUninstall, BOOL fRemoveNow) { BOOL fAssigned; HRESULT hr = E_FAIL; // put up an hourglass (this could take a while) CHourglass hourglass; CAppData & data = m_AppData[cookie]; CString szPackageName = data.m_pDetails->pszPackageName; // We are now not removing script files here; instead the script // file will be removed by the class store code when the package // is actually removed from the DS. #if 0 // only remove script files for packages that have script files if (data.m_pDetails->pInstallInfo->PathType == DrwFilePath) { // We need to make sure it gets removed from // the GPT before we delete it from the class store. // check to see if it's an old style relative path if (L'\\' != data.m_pDetails->pInstallInfo->pszScriptPath[0]) { // find the last element in the path int iBreak = m_szGPT_Path.ReverseFind(L'{'); CString sz = m_szGPT_Path.Left(iBreak-1); sz += L"\\"; sz += data.m_pDetails->pInstallInfo->pszScriptPath; DeleteFile(sz); } else DeleteFile(data.m_pDetails->pInstallInfo->pszScriptPath); } #endif if (0 != (data.m_pDetails->pInstallInfo->dwActFlags & ACTFLG_Assigned)) { fAssigned = TRUE; } else { fAssigned = FALSE; } hr = m_pIClassAdmin->RemovePackage((LPOLESTR)((LPCOLESTR)(data.m_pDetails->pszPackageName)), fRemoveNow ? 0 : ((fForceUninstall ? ACTFLG_Uninstall : ACTFLG_Orphan) | (data.m_pDetails->pInstallInfo->dwActFlags & (ACTFLG_ExcludeX86OnWin64 | ACTFLG_IgnoreLanguage))) ); if (SUCCEEDED(hr)) { // Notify clients of change if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine, TRUE, &guidExtension, m_fMachine ? &guidMachSnapin : &guidUserSnapin))) { ReportPolicyChangedError(m_hwndMainWindow); } #if 0 if (data.m_fVisible) { set ::iterator i; for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++) { (*i)->m_pResult->DeleteItem(data.m_itemID, 0); } } if (SUCCEEDED(hr)) { CString szCSPath; hr = GetClassStoreName(szCSPath, FALSE); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr)); } // remove its entries in the extension table RemoveExtensionEntry(cookie, data); if (m_pFileExt) { m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0); } RemoveUpgradeEntry(cookie, data); m_UpgradeIndex.erase(GetUpgradeIndex(data.m_pDetails->pInstallInfo->PackageGuid)); // If this thing upgraded other apps or had apps that were // upgrading, make sure that they get the proper icons and any // property sheets get updated. UINT n = data.m_pDetails->pInstallInfo->cUpgrades; while (n--) { map::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(data.m_pDetails->pInstallInfo->prgUpgradeInfoList[n].PackageGuid)); if (i != m_UpgradeIndex.end()) { RESULTDATAITEM rd; memset(&rd, 0, sizeof(rd)); rd.mask = RDI_IMAGE; rd.itemID = m_AppData[i->second].m_itemID; rd.nImage = m_AppData[i->second].GetImageIndex(this); set ::iterator i2; for (i2 = m_sResultPane.begin(); i2 != m_sResultPane.end(); i2++) { (*i2)->m_pResult->SetItem(&rd); } if (m_AppData[i->second].m_pUpgradeList) { m_AppData[i->second].m_pUpgradeList->SendMessage(WM_USER_REFRESH, 0, 0); } } } FreePackageDetail(data.m_pDetails); m_AppData.erase(cookie); set ::iterator i; for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++) { (*i)->m_pResult->Sort((*i)->m_nSortColumn, (*i)->m_dwSortOptions, -1); } } #else // just force a refresh Refresh(); } #endif else { DebugMsg((DM_WARNING, TEXT("RemovePackage failed with 0x%x"), hr)); } if (FAILED(hr) && hr != E_FAIL) // don't report E_FAIL error { LogADEEvent(EVENTLOG_ERROR_TYPE, EVENT_ADE_REMOVE_ERROR, hr, data.m_pDetails->pszPackageName); TCHAR szBuffer[256]; if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) { // access permission failure ::LoadString(ghInstance, IDS_DELFAILED_ACCESS_DENIED, szBuffer, 256); } else { switch (hr) { // For these errors, we'll report the party line: case CS_E_CLASS_NOTFOUND: case CS_E_INVALID_VERSION: case CS_E_NO_CLASSSTORE: case CS_E_OBJECT_NOTFOUND: case CS_E_OBJECT_ALREADY_EXISTS: case CS_E_INVALID_PATH: case CS_E_NETWORK_ERROR: case CS_E_ADMIN_LIMIT_EXCEEDED: case CS_E_SCHEMA_MISMATCH: case CS_E_PACKAGE_NOTFOUND: case CS_E_INTERNAL_ERROR: case CS_E_NOT_DELETABLE: { DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), NULL); if (0 != dw) { // got a valid message string break; } // otherwise fall through and give the generic message } // Either these CS errors don't apply or an admin // wouldn't know what they mean: default: // generic class store problem ::LoadString(ghInstance, IDS_DELFAILED_CSFAILURE, szBuffer, 256); break; } } #if DBG TCHAR szDebugBuffer[256]; DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szDebugBuffer, sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]), NULL); if (0 == dw) { (void) StringCchPrintf(szDebugBuffer, sizeof(szDebugBuffer)/sizeof(szDebugBuffer[0]), TEXT("(HRESULT: 0x%lX)"), hr); } (void) StringCchCat(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szDebugBuffer); #endif m_pConsole->MessageBox(szBuffer, szPackageName, MB_OK | MB_ICONEXCLAMATION, NULL); } return hr; } //+-------------------------------------------------------------------------- // // Member: CScopePane::PopulateUpgradeLists // // Synopsis: Walks the list of apps, making sure that all the upgrade // tables are complete. // // Arguments: none // // Returns: // // History: 2-02-1998 stevebl Created // //--------------------------------------------------------------------------- HRESULT CScopePane::PopulateUpgradeLists() { HRESULT hr = S_OK; // For each app in the list, insert an entry in the upgrade tables of // the apps it upgrades. map ::iterator iAppData; for (iAppData=m_AppData.begin(); iAppData != m_AppData.end(); iAppData++) { hr = InsertUpgradeEntry(iAppData->first, iAppData->second); if (FAILED(hr)) { return hr; } } return hr; } //+-------------------------------------------------------------------------- // // Member: CScopePane::InsertUpgradeEntry // // Synopsis: For every app that this app upgrades, place an entry in its // upgrades set so that it points back to this one. // // Arguments: [cookie] - // [data] - // // Returns: // // History: 2-02-1998 stevebl Created // // Notes: Needs to be able to deal with scripts that might not be in // this OU. // //--------------------------------------------------------------------------- HRESULT CScopePane::InsertUpgradeEntry(MMC_COOKIE cookie, CAppData & data) { CString szCSPath; HRESULT hr = GetClassStoreName(szCSPath, FALSE); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr)); } UINT uUpgrades = data.m_pDetails->pInstallInfo->cUpgrades; while (uUpgrades--) { map::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(data.m_pDetails->pInstallInfo->prgUpgradeInfoList[uUpgrades].PackageGuid)); if (m_UpgradeIndex.end() != i) { // Make sure the entry isn't already added: INSTALLINFO * pii = m_AppData[i->second].m_pDetails->pInstallInfo; BOOL fExists = FALSE; UINT uCount = pii->cUpgrades; while (uCount--) { if (0 == memcmp(&data.m_pDetails->pInstallInfo->PackageGuid, &pii->prgUpgradeInfoList[uCount].PackageGuid, sizeof(GUID))) { // it already exists fExists = TRUE; break; } } if (!fExists) { // Add the entry to this app. // We don't need to update the class store because it should // maintain referential integrity for us. But we do need to // update our own internal structures so we're consistent with // what's in the class store. UINT n = ++(pii->cUpgrades); UPGRADEINFO * prgUpgradeInfoList = (UPGRADEINFO *)OLEALLOC(sizeof(UPGRADEINFO) * n); if (!prgUpgradeInfoList) { // out of memory // back out the change (this would be unfortunate but not fatal) pii->cUpgrades--; } else { if (n > 1) { memcpy(prgUpgradeInfoList, pii->prgUpgradeInfoList, sizeof(UPGRADEINFO) * (n-1)); OLESAFE_DELETE(pii->prgUpgradeInfoList); } OLESAFE_COPYSTRING(prgUpgradeInfoList[n-1].szClassStore, (LPOLESTR)((LPCWSTR)szCSPath)); memcpy(&prgUpgradeInfoList[n-1].PackageGuid, &data.m_pDetails->pInstallInfo->PackageGuid, sizeof(GUID)); prgUpgradeInfoList[n-1].Flag = UPGFLG_UpgradedBy; pii->prgUpgradeInfoList = prgUpgradeInfoList; } } } } return S_OK; } //+-------------------------------------------------------------------------- // // Member: CScopePane::RemoveUpgradeEntry // // Synopsis: For every app that this app upgraded, remove the entry from // its upgrades set. // // Arguments: [cookie] - // [data] - // // Returns: // // History: 2-02-1998 stevebl Created // // Notes: Needs to be able to deal with scripts that might not be in // this OU. // //--------------------------------------------------------------------------- HRESULT CScopePane::RemoveUpgradeEntry(MMC_COOKIE cookie, CAppData & data) { UINT uUpgradeIndex = data.m_pDetails->pInstallInfo->cUpgrades; while (uUpgradeIndex--) { map::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(data.m_pDetails->pInstallInfo->prgUpgradeInfoList[uUpgradeIndex].PackageGuid)); if (m_UpgradeIndex.end() != i) { // Find which entry needs to be erased. INSTALLINFO * pii = m_AppData[i->second].m_pDetails->pInstallInfo; UINT n = pii->cUpgrades; while (n--) { if (0 == memcmp(&data.m_pDetails->pInstallInfo->PackageGuid, &pii->prgUpgradeInfoList[n].PackageGuid, sizeof(GUID))) { // Now free this entry, copy the last entry over this // one and decrement cUpgrades. Don't need to actually // reallocate the array because it will be freed later. OLESAFE_DELETE(pii->prgUpgradeInfoList[n].szClassStore); if (--(pii->cUpgrades)) { memcpy(&pii->prgUpgradeInfoList[n], &pii->prgUpgradeInfoList[pii->cUpgrades], sizeof(UPGRADEINFO)); } else { OLESAFE_DELETE(pii->prgUpgradeInfoList); } // If we ever were to need to update the class store, // this is where we would do it. break; } } } } return S_OK; } //+-------------------------------------------------------------------------- // // Member: CScopePane::PopulateExtensions // // Synopsis: Builds the file extension table from the list of applications. // // Arguments: (none) // // Returns: // // History: 1-29-1998 stevebl Created // //--------------------------------------------------------------------------- HRESULT CScopePane::PopulateExtensions() { HRESULT hr = S_OK; // first erase the old extension list m_Extensions.erase(m_Extensions.begin(), m_Extensions.end()); // now add each app's extensions to the table map ::iterator iAppData; for (iAppData=m_AppData.begin(); iAppData != m_AppData.end(); iAppData++) { hr = InsertExtensionEntry(iAppData->first, iAppData->second); if (FAILED(hr)) { return hr; } } if (m_pFileExt) { m_pFileExt->SendMessage(WM_USER_REFRESH, 0, 0); } return hr; } //+-------------------------------------------------------------------------- // // Member: CScopePane::InsertExtensionEntry // // Synopsis: Adds a single entry to the extension tables. // // Arguments: [cookie] - // [data] - // // Returns: // // History: 1-29-1998 stevebl Created // //--------------------------------------------------------------------------- HRESULT CScopePane::InsertExtensionEntry(MMC_COOKIE cookie, CAppData & data) { UINT n = data.m_pDetails->pActInfo->cShellFileExt; while (n--) { m_Extensions[data.m_pDetails->pActInfo->prgShellFileExt[n]].insert(cookie); } return S_OK; } //+-------------------------------------------------------------------------- // // Member: CScopePane::RemoveExtensionEntry // // Synopsis: Removes ane entry from the extension tables. // // Arguments: [cookie] - // [data] - // // Returns: // // History: 1-29-1998 stevebl Created // //--------------------------------------------------------------------------- HRESULT CScopePane::RemoveExtensionEntry(MMC_COOKIE cookie, CAppData & data) { UINT n = data.m_pDetails->pActInfo->cShellFileExt; while (n--) { m_Extensions[data.m_pDetails->pActInfo->prgShellFileExt[n]].erase(cookie); if (m_Extensions[data.m_pDetails->pActInfo->prgShellFileExt[n]].empty()) { m_Extensions.erase(data.m_pDetails->pActInfo->prgShellFileExt[n]); } } return S_OK; } //+-------------------------------------------------------------------------- // // Member: CScopePane::PrepareExtensions // // Synopsis: Sets extension priorities so that this data can be inserted // into the extension list with the proper priority. // // Arguments: [pd] - // // Returns: // // Modifies: // // Derivation: // // History: 1-29-1998 stevebl Created // //--------------------------------------------------------------------------- HRESULT CScopePane::PrepareExtensions(PACKAGEDETAIL &pd) { UINT n = pd.pActInfo->cShellFileExt; while (n--) { // For each extension that is going to be added, we need to assign // it a priority that is one larger than the largest priority // already added. // NOTE: The odds of this number rolling over to 0 are so // unlikely that it would be pointless to check for it. In any case // the results of such a bug would be easy for the admin to remedy // via the file extension priority dialog. pd.pActInfo->prgPriority[n] = 0; EXTLIST::iterator i; CString sz = pd.pActInfo->prgShellFileExt[n]; for (i= m_Extensions[sz].begin(); i != m_Extensions[sz].end(); i++) { // look for the entry that matches this file extension CAppData & data = m_AppData[*i]; UINT n2 = data.m_pDetails->pActInfo->cShellFileExt; while (n2--) { if (0 == sz.CompareNoCase(data.m_pDetails->pActInfo->prgShellFileExt[n2])) { break; } } if (data.m_pDetails->pActInfo->prgPriority[n2] >= pd.pActInfo->prgPriority[n]) { pd.pActInfo->prgPriority[n] = data.m_pDetails->pActInfo->prgPriority[n2] + 1; } } } return S_OK; } //+-------------------------------------------------------------------------- // // Member: CScopePane::ChangePackageState // // Synopsis: Changes the state of a package and puts up advisory message // boxes informing the admin about the effects of the change. // // Arguments: [data] - entry to change // [dwNewState] - new state // // History: 2-03-1998 stevebl Created // //--------------------------------------------------------------------------- STDMETHODIMP CScopePane::ChangePackageState(CAppData &data, DWORD dwNewState, BOOL fShowUI) { HRESULT hr = S_OK; // first detect what's changed DWORD dwOldState = data.m_pDetails->pInstallInfo->dwActFlags; DWORD dwChange = dwOldState ^ dwNewState; if (dwChange) { // commit changes hr = m_pIClassAdmin->ChangePackageProperties(data.m_pDetails->pszPackageName, NULL, &dwNewState, NULL, NULL, NULL, NULL); if (SUCCEEDED(hr)) { if (data.m_fVisible) { data.m_pDetails->pInstallInfo->dwActFlags = dwNewState; RESULTDATAITEM rd; memset(&rd, 0, sizeof(rd)); rd.mask = RDI_IMAGE; rd.itemID = data.m_itemID; rd.nImage = data.GetImageIndex(this); set ::iterator i; for (i = m_sResultPane.begin(); i != m_sResultPane.end(); i++) { (*i)->m_pResult->SetItem(&rd); (*i)->m_pResult->Sort((*i)->m_nSortColumn, (*i)->m_dwSortOptions, -1); } } data.NotifyChange(); if (FAILED(m_pIGPEInformation->PolicyChanged(m_fMachine, TRUE, &guidExtension, m_fMachine ? &guidMachSnapin : &guidUserSnapin))) { ReportPolicyChangedError(m_hwndMainWindow); } } else { DebugMsg((DM_WARNING, TEXT("ChangePackageProperties failed with 0x%x"), hr)); } } return hr; } HRESULT CScopePane::ClearCategories() { while (m_CatList.cCategory) { m_CatList.cCategory--; OLESAFE_DELETE(m_CatList.pCategoryInfo[m_CatList.cCategory].pszDescription); } OLESAFE_DELETE(m_CatList.pCategoryInfo); return S_OK; } //+-------------------------------------------------------------------------- // // Function: GetUpgradeIndex // // Synopsis: utility function that returns an upgrade index entry for a package. // // Arguments: [PackageID] - the PackageID guid // // Returns: S_OK on success // // History: 8-12-1998 stevebl Created // // Notes: Pretty simple really, the index is just the string form of // the GUID. // //--------------------------------------------------------------------------- CString GetUpgradeIndex(GUID & PackageID) { CString szIndex; WCHAR wsz[256]; StringFromGUID2(PackageID, wsz, 256); return wsz; } //+-------------------------------------------------------------------------- // // Member: CScopePane::GetPackageNameFromUpgradeInfo // // Synopsis: returns the name of a package given its PackageGuid and CSPath // // Arguments: [szPackageName] - [out] name of the package associated with // this script // [szScript] - [in] path to the script // // Returns: S_OK - found a package associated with this script // (other) - failed to find a package (could be for any number // of reasons) // // History: 4-07-1998 stevebl Created // // Notes: In cases where the package does not reside in this // container, the package name will be returned as // "Package Name (container name)" // Note that this does not return the friendly name of the // MSI package, it returns the name of the package entry in the // class store. The two are not always the same. // //--------------------------------------------------------------------------- HRESULT CScopePane::GetPackageNameFromUpgradeInfo(CString & szPackageName, GUID &PackageGuid, LPOLESTR szCSPath) { HRESULT hr; IEnumPackage * pIPE = NULL; CString szMyCSPath; hr = GetClassStoreName(szMyCSPath, FALSE); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GetClassStoreName failed with 0x%x"), hr)); } // see if it's in our container if (0 == _wcsicmp((LPOLESTR)((LPCWSTR)szMyCSPath), szCSPath)) { hr = E_FAIL; map ::iterator i = m_UpgradeIndex.find(GetUpgradeIndex(PackageGuid)); if (m_UpgradeIndex.end() != i) { szPackageName = m_AppData[i->second].m_pDetails->pszPackageName; hr = S_OK; } } else { IClassAdmin * pIClassAdmin; hr = CsGetClassStore((LPOLESTR)((LPCOLESTR)szCSPath), (LPVOID*)&pIClassAdmin); if (SUCCEEDED(hr)) { PACKAGEDETAIL pd; hr = pIClassAdmin->GetPackageDetailsFromGuid(PackageGuid, &pd); if (SUCCEEDED(hr)) { if (0 == (pd.pInstallInfo->dwActFlags & (ACTFLG_Orphan | ACTFLG_Uninstall))) { GUID guid; LPOLESTR pszPolicyName; hr = pIClassAdmin->GetGPOInfo(&guid, &pszPolicyName); if (SUCCEEDED(hr)) { szPackageName = pd.pszPackageName; szPackageName += L" ("; szPackageName += pszPolicyName; szPackageName += L")"; OLESAFE_DELETE(pszPolicyName); } } else { // this app is marked as deleted hr = E_FAIL; } ReleasePackageDetail(&pd); } pIClassAdmin->Release(); } } return hr; } //+-------------------------------------------------------------------------- // // Function: GetMsiProperty // // Synopsis: Retrieves a property from the Property table of an MSI package. // // Arguments: [szPackagePath] - path to the MSI package // [szProperty] - property to fetch // [szValue] - buffer to contain the value // [puiSize] - size of the buffer // // Returns: ERROR_SUCCESS if successful // // History: 3-25-1998 stevebl Created // //--------------------------------------------------------------------------- UINT GetMsiProperty(const TCHAR * szPackagePath, const TCHAR* szProperty, TCHAR* szValue, DWORD* puiSize) { MSIHANDLE hDatabase; UINT msiReturn = MsiOpenDatabase(szPackagePath, MSIDBOPEN_READONLY, &hDatabase); if (ERROR_SUCCESS == msiReturn) { CString szQuery; szQuery.Format(L"SELECT `Value` FROM `Property` WHERE `Property`='%s'", szProperty); MSIHANDLE hView; msiReturn = MsiDatabaseOpenView(hDatabase, szQuery, &hView); if (ERROR_SUCCESS == msiReturn) { msiReturn = MsiViewExecute(hView, 0); if (ERROR_SUCCESS == msiReturn) { MSIHANDLE hRecord; msiReturn = MsiViewFetch(hView, &hRecord); if (ERROR_SUCCESS == msiReturn) { msiReturn = MsiRecordGetString(hRecord, 1, szValue, puiSize); MsiCloseHandle(hRecord); } } MsiCloseHandle(hView); } MsiCloseHandle(hDatabase); } return msiReturn; } //+-------------------------------------------------------------------------- // // Function: GetCapitalizedExt // // Synopsis: Given a file name, this function finds the filename // extension, and returns it capitalized. // // Arguments: // [in] [szName] The file name // [out][szExt] The capitalized extension // // Returns: // TRUE - an extension was found // FALSE - an extension could not be found // // History: 5/20/1998 RahulTh created // // Notes: If an extension cannot be found, then this function makes // szExt an empty string // //--------------------------------------------------------------------------- BOOL GetCapitalizedExt (LPCOLESTR szName, CString& szExt) { int slashpos, dotpos; BOOL fRetVal = FALSE; CString szFileName = szName; szExt.Empty(); //to be on the safe side //get the positions of the last . and last backslash dotpos = szFileName.ReverseFind('.'); slashpos = szFileName.ReverseFind('\\'); //if the last dot occurs after the last slash, this file has an extension if (dotpos > slashpos) { szExt = szFileName.Mid(dotpos + 1); szExt.MakeUpper(); fRetVal = TRUE; } return fRetVal; }