|
|
///////////////////////////////////////////////////////////////////////////////
// Implementation of class CParseInf
//
// CParseInf is created to deal with parsing of an INF file.
#include <ole2.h>
#include "ParseInf.h"
#include "resource.h"
#include "init.h"
#include "global.h"
#include <shlwapi.h>
#include <initguid.h>
#include <pkgguid.h>
#include <cleanoc.h> // for STATUS_CTRL values
#include <mluisupp.h>
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
static BOOL FGetCLSIDFile( LPTSTR szFile, LPCTSTR szCLSID ) { BOOL fGotIt = FALSE; HKEY hkeyClsid; TCHAR szT[MAX_PATH]; TCHAR *szPath = CatPathStrN( szT, HKCR_CLSID, szCLSID, MAX_PATH );
if ( RegOpenKeyEx( HKEY_CLASSES_ROOT, szPath, 0, KEY_READ, &hkeyClsid ) == ERROR_SUCCESS ) { DWORD dw; LRESULT lResult;
// Look for InprocServer[32] or LocalServer[32] key
dw = MAX_PATH; lResult = RegQueryValue(hkeyClsid, INPROCSERVER32, szT, (PLONG)&dw); if (lResult != ERROR_SUCCESS) { dw = MAX_PATH; lResult = RegQueryValue(hkeyClsid, LOCALSERVER32, szT, (PLONG)&dw); }
if (lResult != ERROR_SUCCESS) { dw = MAX_PATH; lResult = RegQueryValue(hkeyClsid, INPROCSERVERX86, szT, (PLONG)&dw); }
if (lResult != ERROR_SUCCESS) { dw = MAX_PATH; lResult = RegQueryValue(hkeyClsid, LOCALSERVERX86, szT, (PLONG)&dw); }
if ( lResult == ERROR_SUCCESS ) { if ( OCCGetLongPathName( szFile, szT, MAX_PATH ) == 0 ) lstrcpy( szFile, szT ); fGotIt = TRUE; } RegCloseKey( hkeyClsid ); }
return fGotIt; }
// constructor
CParseInf::CParseInf() { m_pHeadFileList = NULL; m_pCurFileNode = NULL; m_pFileRetrievalPtr = NULL; m_pHeadPackageList = NULL; m_pCurPackageNode = NULL; m_pPackageRetrievalPtr = NULL; m_bIsDistUnit = FALSE; m_bHasActiveX = FALSE; m_bHasJava = FALSE; m_pijpm = NULL; m_bCoInit = FALSE; m_dwStatus = STATUS_CTRL_UNKNOWN; GetDaysBeforeExpireGeneral( &m_cExpireDays ); }
// destructor
CParseInf::~CParseInf() { DestroyFileList(); DestroyPackageList();
if ( m_pijpm != NULL ) m_pijpm->Release();
if ( m_bCoInit ) CoUninitialize(); }
// initialization
void CParseInf::Init() { m_dwFileSizeSaved = 0; m_dwTotalFileSize = 0; m_nTotalFiles = 0; m_pHeadFileList = m_pCurFileNode = NULL; m_pHeadPackageList = m_pCurPackageNode = NULL;
lstrcpyn(m_szInf, m_szFileName, ARRAYSIZE(m_szInf)); TCHAR *pCh = ReverseStrchr(m_szInf, '.'); if (pCh != NULL) *pCh = '\0'; if ( lstrlen(m_szInf) + lstrlen(INF_EXTENSION) < ARRAYSIZE(m_szInf)) lstrcat(m_szInf, INF_EXTENSION); else m_szInf[0] = 0; // if can't hold it, we can't hold it.
}
// release memory used by a linked list of files
void CParseInf::DestroyFileList() { if (m_pHeadFileList != NULL) delete m_pHeadFileList; m_pHeadFileList = m_pCurFileNode = NULL; }
void CParseInf::DestroyPackageList() { if (m_pHeadPackageList != NULL) delete m_pHeadPackageList; m_pHeadPackageList = m_pCurPackageNode = NULL; }
// find inf from cache directory if one with the
// same name as the OCX is not found
HRESULT CParseInf::FindInf(LPTSTR szInf) { HRESULT hr = S_OK; WIN32_FIND_DATA dataFile; HANDLE h = INVALID_HANDLE_VALUE; DWORD dwLen = 0; TCHAR szValueBuf[MAX_PATH]; TCHAR *szOcxFileName = ReverseStrchr(m_szFileName, '\\'); int nCachePathLength = 0, i = 0;
Assert(szOcxFileName != NULL); szOcxFileName += 1; Assert (szInf != NULL); if (szInf == NULL) goto ExitFindInf;
// search for inf file in two directories. First the dir where the
// OCX is, then the OC cache dir.
for (i = 0; dwLen == 0 && i < 2; i++) { if (i == 0) hr = GetDirectory(GD_EXTRACTDIR, szInf, ARRAYSIZE(szInf), m_szFileName); else { TCHAR szTemp[MAX_PATH]; hr = GetDirectory(GD_CACHEDIR, szTemp, ARRAYSIZE(szTemp)); if (lstrcmpi(szTemp, szInf) == 0) continue; lstrcpy(szInf, szTemp); }
if (FAILED(hr)) goto ExitFindInf;
lstrcat(szInf, TEXT("\\")); nCachePathLength = lstrlen(szInf); lstrcat(szInf, TEXT("*")); lstrcat(szInf, INF_EXTENSION); h = FindFirstFile(szInf, &dataFile); if (h == INVALID_HANDLE_VALUE) { goto ExitFindInf; }
// find an inf file with a section in [Add.Code] dedicated
// to the OCX file in question
do { szInf[nCachePathLength] = '\0'; lstrcat(szInf, (LPCTSTR)dataFile.cFileName); dwLen = GetPrivateProfileString( KEY_ADDCODE, szOcxFileName, DEFAULT_VALUE, szValueBuf, MAX_PATH, szInf); } while(dwLen == 0 && FindNextFile(h, &dataFile)); } hr = (dwLen != 0 ? hr : S_FALSE);
ExitFindInf:
if (h != INVALID_HANDLE_VALUE) FindClose(h);
if (hr != S_OK) szInf[0] = '\0';
return hr; }
// initiate parsing of INF file
// szCLSID -- address to a buffer storing CLSID of control
// szOCXFileName -- full path and name (ie. long file name) of OCX file
HRESULT CParseInf::DoParse( LPCTSTR szOCXFileName, LPCTSTR szCLSID) { Assert(szOCXFileName != NULL); Assert(szCLSID != NULL);
HRESULT hr = S_OK; const TCHAR *pszPath = NULL; TCHAR szFileName[MAX_PATH]; DWORD dwFileSize = 0;
if ( FGetCLSIDFile( szFileName, szCLSID ) && lstrcmpi( szFileName, szOCXFileName ) != 0 ) m_dwStatus = STATUS_CTRL_UNPLUGGED;
// If DoParse was called, we are assumed to be a legacy control and not
// a distribution unit (subsequent call to DoParseDU will change the
// status). This information is required for control removal purposes.
m_bIsDistUnit = FALSE; m_bHasActiveX = TRUE; // all legacy controls are ActiveX
// initialization
if ( OCCGetLongPathName(m_szFileName, szOCXFileName, MAX_PATH) == 0 ) lstrcpyn( m_szFileName, szOCXFileName, MAX_PATH );
lstrcpyn(m_szCLSID, szCLSID, MAX_CLSID_LEN); DestroyFileList(); Init();
BOOL bOCXRemovable = IsModuleRemovable(m_szFileName);
// test INF file existance, if not, try to find one in OC cache dir.
if (!FileExist(m_szInf)) { if (!ReadInfFileNameFromRegistry(m_szCLSID, m_szInf, MAX_PATH)) { FindInf(m_szInf);
// record inf file name into the registry
WriteInfFileNameToRegistry( m_szCLSID, (m_szInf[0] == '\0' ? NULL : m_szInf)); } }
// enumerate files assocated with a particular OCX
if (FAILED(hr = EnumSections())) goto ExitDoParse;
// S_FALSE is returned when an ocx has no inf file
if (hr == S_FALSE) { m_nTotalFiles = 1; if (FAILED(GetSizeOfFile(m_szFileName, &m_dwFileSizeSaved))) { m_dwFileSizeSaved = 0; m_dwTotalFileSize = 0; } else { m_dwTotalFileSize = m_dwFileSizeSaved; } hr = S_OK; if ( !PathFileExists( m_szFileName ) ) m_dwStatus = STATUS_CTRL_DAMAGED; else m_dwStatus = STATUS_CTRL_INSTALLED; goto ExitDoParse; }
// OCX has an corresponding INF file.
// Loop through the list of assocated files to dig out info for each
// from their corresponding section in the INF file
for (m_pCurFileNode = m_pHeadFileList; m_pCurFileNode != NULL; m_pCurFileNode = m_pCurFileNode->GetNextFileNode(), hr = S_OK) { // if m_pCurFileNode->GetNextFileNode() == NULL => it's the inf file itself,
// which does not need to be processed.
if (m_pCurFileNode->GetNextFileNode() != NULL) { pszPath = m_pCurFileNode->GetPath(); Assert(pszPath != NULL); if (pszPath == NULL) { hr = E_UNEXPECTED; goto ExitDoParse; } CatPathStrN( szFileName, pszPath, m_pCurFileNode->GetName(), ARRAYSIZE(szFileName)); } else { lstrcpyn(szFileName, m_szInf, ARRAYSIZE(szFileName)); pszPath = NULL; }
// hr might either be S_OK or S_FALSE
// S_OK means file can be removed as it has a SharedDlls count of 1
// S_FALSE if the count is greater than 1
// calculate total num of files and their sizes
if (SUCCEEDED(hr = GetSizeOfFile(szFileName, &dwFileSize))) { if (pszPath == NULL || IsModuleRemovable(szFileName) || lstrcmpi(szFileName, m_szFileName) == 0) { m_dwFileSizeSaved += dwFileSize; }
m_dwTotalFileSize += dwFileSize; } else m_dwStatus = STATUS_CTRL_DAMAGED; // failure to get size indicative of missing file.
m_nTotalFiles += 1; }
// if we didn't detect a problem, flag the control as installed.
if ( m_dwStatus == STATUS_CTRL_UNKNOWN ) m_dwStatus = STATUS_CTRL_INSTALLED;
ExitDoParse: return hr; }
HRESULT CParseInf::BuildDUFileList( HKEY hKeyDU ) { HRESULT hr = S_OK; LRESULT lResult; HKEY hkeyFiles; TCHAR szDUFileName[MAX_PATH + 1]; DWORD dwStrSize = MAX_PATH; int cFilesEnum = 0;
lResult = RegOpenKeyEx(hKeyDU, REGSTR_DU_CONTAINS_FILES, 0, KEY_READ, &hkeyFiles);
if ( lResult != ERROR_SUCCESS ) // if no files, maybe there's Java
return hr;
while ((lResult = RegEnumValue(hkeyFiles, cFilesEnum++, szDUFileName, &dwStrSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) { TCHAR szPath[MAX_PATH + 1]; CFileNode *pFileNode;
lstrcpyn(szPath, szDUFileName, MAX_PATH); TCHAR *szFName = ReverseStrchr(szPath, '\\');
Assert(szFName != NULL); // long ago and far away, in the IE4, PP1-2 timeframe, there was a horrible
// bug that corrupted these entries on Memphis and NT5. We suspect that GetLongPathName
// was doing something wrong for code download, but repro scenarios were not
// to be found. Anywho, the damaged registries are out there, so we need to
// cope with them more gracefully than faulting at the *szFName = NULL;
if ( szFName == NULL ) continue;
*szFName = NULL; szFName++;
pFileNode = new CFileNode(szFName, "", szPath); if (pFileNode == NULL) { hr = E_OUTOFMEMORY; break; }
// create and add node to list
if (m_pHeadFileList == NULL) { m_pHeadFileList = pFileNode; m_pCurFileNode = m_pHeadFileList; } else { hr = m_pCurFileNode->Insert(pFileNode); m_pCurFileNode = m_pCurFileNode->GetNextFileNode(); } dwStrSize = MAX_PATH; }
RegCloseKey( hkeyFiles );
return hr; }
HRESULT CParseInf::BuildDUPackageList( HKEY hKeyDU ) { HRESULT hr = S_OK; LRESULT lResult; HKEY hkeyJava; ICreateJavaPackageMgr *picjpm;
DestroyPackageList();
lResult = RegOpenKeyEx(hKeyDU, REGSTR_DU_CONTAINS_JAVA, 0, KEY_READ, &hkeyJava);
if ( lResult != ERROR_SUCCESS ) // it's OK if there's no Java
return hr;
if ( !m_bCoInit ) m_bCoInit = SUCCEEDED(hr = CoInitialize(NULL));
if ( m_bCoInit ) { hr=CoCreateInstance(CLSID_JavaPackageManager,NULL,CLSCTX_INPROC_SERVER, IID_ICreateJavaPackageMgr,(LPVOID *) &picjpm); if (SUCCEEDED(hr)) { hr = picjpm->GetPackageManager(&m_pijpm); picjpm->Release(); } }
if (FAILED(hr)) return S_OK; // hr; // quietly fail until we're sure the JavaVM with package manager support is in the build.
// list the packages under Contains/Java - these are in the gobal namespace
hr = BuildNamespacePackageList(hkeyJava, "");
// add packages for each namespace key under Contains\Java
if ( SUCCEEDED(hr) ) { DWORD dwIndex; TCHAR szNamespace[MAX_PATH + 1]; //
DWORD dwStrSize;
for ( dwIndex = 0, dwStrSize = MAX_PATH; RegEnumKey( hkeyJava, dwIndex, szNamespace, dwStrSize ) == ERROR_SUCCESS && SUCCEEDED(hr); dwIndex++, dwStrSize = MAX_PATH ) { HKEY hkeyNamespace;
lResult = RegOpenKeyEx(hkeyJava, szNamespace, 0, KEY_READ, &hkeyNamespace); if ( lResult == ERROR_SUCCESS ) { hr = BuildNamespacePackageList(hkeyNamespace, szNamespace ); RegCloseKey( hkeyNamespace ); } else { hr = HRESULT_FROM_WIN32(lResult); break; } } }
RegCloseKey( hkeyJava );
m_bHasJava = m_pHeadPackageList != NULL;
return hr; }
HRESULT CParseInf::BuildNamespacePackageList( HKEY hKeyNS, LPCTSTR szNamespace ) { HRESULT hr = S_OK; LRESULT lResult; int cPackagesEnum = 0; TCHAR szDUPackageName[MAX_PATH + 1]; DWORD dwStrSize = MAX_PATH; BOOL fIsSystemClass = FALSE;
while ((lResult = RegEnumValue(hKeyNS, cPackagesEnum++, szDUPackageName, &dwStrSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) { IJavaPackage *pijp;
#ifndef UNICODE
MAKE_WIDEPTR_FROMANSI(swzPackage, szDUPackageName ); MAKE_WIDEPTR_FROMANSI(swzNamespace, szNamespace ); #else
OLESTR swzPackage = szDUPackageName; OLESTR swzNamespace = szNamespace; #endif
hr = m_pijpm->GetPackage( swzPackage, ((*szNamespace == '\0')? NULL : swzNamespace), &pijp ); if ( SUCCEEDED(hr) ) { BSTR bstrPath;
hr = pijp->GetFilePath( &bstrPath ); if ( SUCCEEDED(hr) ) { CPackageNode *pPackageNode;
pPackageNode = new CPackageNode(szDUPackageName, szNamespace); if (pPackageNode == NULL) { hr = E_OUTOFMEMORY; pijp->Release(); break; } #ifndef UNICODE
MAKE_ANSIPTR_FROMWIDE(szPath, bstrPath ); #else
TCHAR *szPath = bstrPath; #endif
pPackageNode->SetPath( szPath );
pijp->IsSystemClass(&fIsSystemClass); pPackageNode->SetIsSystemClass(fIsSystemClass);
if (m_pHeadPackageList == NULL) { m_pHeadPackageList = pPackageNode; m_pCurPackageNode = m_pHeadPackageList; } else { hr = m_pCurPackageNode->Insert(pPackageNode); m_pCurPackageNode = m_pCurPackageNode->GetNextPackageNode(); }
SysFreeString( bstrPath ); pijp->Release(); // we're done with the package
} } else { m_dwStatus = STATUS_CTRL_DAMAGED; hr = S_OK; // don't barf if this doesn't work, some villain might have uninstalled it
}
dwStrSize = MAX_PATH; }
return hr; }
HRESULT CParseInf::DoParseDU(LPCTSTR szOCXFileName, LPCTSTR szCLSID) { HRESULT hr = S_OK; TCHAR szFileName[MAX_PATH]; TCHAR szDUSvrName[MAX_PATH]; const TCHAR *pszSvrFile = NULL; DWORD dwFileSize = 0; HKEY hKeyFiles = 0; HKEY hKeyDU = 0; HKEY hKeyDLInfo = 0; TCHAR szDistUnit[MAX_REGPATH_LEN]; HRESULT lResult; CFileNode *pFileNode = NULL; DWORD dwExpire; DWORD dw;
Assert(szCLSID != NULL);
// Since this function was called, we must be a distribution unit.
// Set a member flag so that all other member functions realize that
// we are really part of a DU now.
m_bIsDistUnit = TRUE;
// initialization
if ( szOCXFileName != NULL ) lstrcpyn(m_szFileName, szOCXFileName, ARRAYSIZE(m_szFileName)); lstrcpyn(m_szCLSID, szCLSID, ARRAYSIZE(m_szCLSID)); Init();
// Add files from ...\Distribution Units\{Name}\Contains\Files
CatPathStrN( szDistUnit, REGSTR_PATH_DIST_UNITS, szCLSID, ARRAYSIZE(szDistUnit));
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szDistUnit, 0, KEY_READ, &hKeyDU); if (lResult != ERROR_SUCCESS) { hr = E_FAIL; goto ExitDoParseDU; }
hr = BuildDUFileList( hKeyDU ); if (FAILED(hr)) { goto ExitDoParseDU; }
hr = BuildDUPackageList( hKeyDU ); if (FAILED(hr)) { goto ExitDoParseDU; }
// Now add the OSD and INF files
lResult = RegOpenKeyEx(hKeyDU, REGSTR_DOWNLOAD_INFORMATION, 0, KEY_READ, &hKeyDLInfo); if (lResult == ERROR_SUCCESS) { TCHAR *pFileName = NULL; TCHAR szBuffer[MAX_PATH + 1];
dw = MAX_PATH; lResult = RegQueryValueEx(hKeyDLInfo, REGSTR_VALUE_INF, NULL, NULL, (unsigned char*)szBuffer, &dw); if (lResult == ERROR_SUCCESS) { pFileName = ReverseStrchr(szBuffer, '\\'); if (pFileName != NULL) { pFileName++;
// set INF member variable
lstrcpyn(m_szInf, szBuffer, ARRAYSIZE(m_szInf));
pFileNode = new CFileNode(szBuffer, "", NULL); if (pFileNode == NULL) { hr = E_OUTOFMEMORY; goto ExitDoParseDU; } // create and add node to list
if (m_pHeadFileList == NULL) { m_pHeadFileList = pFileNode; m_pCurFileNode = m_pHeadFileList; } else { hr = m_pCurFileNode->Insert(pFileNode); m_pCurFileNode = m_pCurFileNode->GetNextFileNode(); } } }
pFileName = NULL; dw = MAX_PATH; lResult = RegQueryValueEx(hKeyDLInfo, REGSTR_VALUE_OSD, NULL, NULL, (unsigned char*)szBuffer, &dw); if (lResult == ERROR_SUCCESS) { pFileName = ReverseStrchr(szBuffer, '\\'); if (pFileName != NULL) { pFileName++; pFileNode = new CFileNode(szBuffer, "", NULL); // create and add node to list
if (m_pHeadFileList == NULL) { m_pHeadFileList = pFileNode; m_pCurFileNode = m_pHeadFileList; } else { hr = m_pCurFileNode->Insert(pFileNode); m_pCurFileNode = m_pCurFileNode->GetNextFileNode(); } } } }
// See if there's an Expire value, and if so, override the default/general expire.
dw = sizeof(DWORD); dwExpire = 0; if ( RegQueryValueEx(hKeyDU, REGSTR_VALUE_EXPIRE, NULL, NULL, (LPBYTE)&dwExpire, &dw) == ERROR_SUCCESS ) { if ( dwExpire ) m_cExpireDays = dwExpire; else GetDaysBeforeExpireAuto(&m_cExpireDays); }
// Find out where COM thinks our CLSID is, and what the server name is.
if ( FGetCLSIDFile( szDUSvrName, szCLSID ) ) { m_bHasActiveX = TRUE; pszSvrFile = PathFindFileName(szDUSvrName); } else szDUSvrName[0] = '\0';
for (m_pCurFileNode = m_pHeadFileList; m_pCurFileNode != NULL; m_pCurFileNode = m_pCurFileNode->GetNextFileNode(), hr = S_OK) { const TCHAR *pszPath = m_pCurFileNode->GetPath();
if (pszPath != NULL) { CatPathStrN( szFileName, m_pCurFileNode->GetPath(), m_pCurFileNode->GetName(), ARRAYSIZE(szFileName)); } else { lstrcpyn(szFileName, m_pCurFileNode->GetName(),ARRAYSIZE(szFileName)); }
if (SUCCEEDED(hr = GetSizeOfFile(szFileName, &dwFileSize))) { if (pszPath == NULL || IsModuleRemovable(szFileName) || lstrcmpi(szFileName, m_szFileName) == 0) { m_dwFileSizeSaved += dwFileSize; }
// only play with the status if we haven't already flagged the installation
// as damaged and we're looking at the the file that should be the host for
// our control, if any.
if ( m_dwStatus != STATUS_CTRL_DAMAGED && pszSvrFile != NULL && lstrcmpi( pszSvrFile, m_pCurFileNode->GetName() ) == 0 ) { TCHAR szDUSvrNameSPN[MAX_PATH]; TCHAR szFileNameSPN[MAX_PATH];
GetShortPathName(szDUSvrName, szDUSvrNameSPN, MAX_PATH); GetShortPathName(szFileName, szFileNameSPN, MAX_PATH); if ( lstrcmpi( szDUSvrNameSPN, szFileNameSPN ) == 0 ) m_dwStatus = STATUS_CTRL_INSTALLED; // no, we're not unplugged
else // server and our file are in different directories - unplugged scenario
m_dwStatus = STATUS_CTRL_UNPLUGGED; }
m_dwTotalFileSize += dwFileSize; } else if ( !PathFileExists( szFileName ) ) // if a DU file is missing, then the installation is damaged.
m_dwStatus = STATUS_CTRL_DAMAGED;
m_nTotalFiles += 1; }
// If we're still unsure, and there are packages, then this is a pure Java
// DU and will say we're installed unless a check of the package files indicates otherwise.
if ( m_pHeadPackageList != NULL && m_dwStatus == STATUS_CTRL_UNKNOWN ) m_dwStatus = STATUS_CTRL_INSTALLED;
// Accumulate package sizes and such into our running total
for (m_pCurPackageNode = m_pHeadPackageList; m_pCurPackageNode != NULL; m_pCurPackageNode = m_pCurPackageNode->GetNextPackageNode(), hr = S_OK) { // the files can hold more than one of our packages, so only add a package
// path file to the totals if we haven't already counted it.
// N^2 to be sure, but the numbers will be small.
CPackageNode *ppn; LPCTSTR szPackagePath = m_pCurPackageNode->GetPath(); BOOL bAlreadySeen = FALSE;
for ( ppn = m_pHeadPackageList; ppn != m_pCurPackageNode && !bAlreadySeen; ppn = ppn->GetNextPackageNode() ) bAlreadySeen = lstrcmp( szPackagePath, ppn->GetPath() ) == 0; if ( bAlreadySeen ) continue;
// Must be a new file,
if ( SUCCEEDED(GetSizeOfFile(szPackagePath, &dwFileSize)) ) { m_dwFileSizeSaved += dwFileSize; m_dwTotalFileSize += dwFileSize; } else m_dwStatus = STATUS_CTRL_DAMAGED;
// m_nTotalFiles += 1; don't count these files, or the dependency file list will have a bunch of blank entries
}
// Some DUs, like SportsZone or Shockwave, have no Contains subkeys.
// If status is still unknown here, but the server is in place, consider it
// installed.
if ( m_dwStatus == STATUS_CTRL_UNKNOWN && PathFileExists( szDUSvrName ) ) m_dwStatus = STATUS_CTRL_INSTALLED;
ExitDoParseDU:
if (hKeyDU) { RegCloseKey(hKeyDU); }
if (hKeyDLInfo) { RegCloseKey(hKeyDLInfo); }
return hr; }
// ---------------------------------------------------------------------------
// CParseInf::IsSectionInINF
// Checks if a section is in the INF
// returns:
// S_OK: lpCurCode has the satellite binary name
// S_FALSE: ignore this code and use default resources in main dll
// E_XXX: any other error
BOOL CParseInf::IsSectionInINF( LPCSTR lpCurCode) { const char *szDefault = ""; DWORD len; #define FAKE_BUF_SIZE 3
char szBuf[FAKE_BUF_SIZE];
len = GetPrivateProfileString(lpCurCode, NULL, szDefault, szBuf, FAKE_BUF_SIZE, m_szInf);
if (len == (FAKE_BUF_SIZE - 2)) { // returns Out Of Buffer Space?
// yes, section found
return TRUE; } else { return FALSE; } } // loop through the keys in [Add.Code} section and enumerate the
// files and their corresponding sections.
HRESULT CParseInf::HandleSatellites(LPCTSTR pszFileName) {
HRESULT hr = S_OK;
// BEGIN NOTE: add vars and values in matching order
// add a var by adding a new define VAR_NEW_VAR = NUM_VARS++
const char *szVars[] = {
#define VAR_LANG 0 // expands to 3 letter lang code based on lcid
"%LANG%",
#define NUM_VARS 1
"" };
const char *szValues[NUM_VARS + 1]; szValues[VAR_LANG] = "***"; // unint magic
szValues[NUM_VARS] = NULL; // END NOTE: add vars and values in matching order
// look for and substitute variables like %EXTRACT_DIR%
// and expand out the command line
TCHAR szSectionName[MAX_PATH]; TCHAR szSectionNameCopy[MAX_PATH]; hr = ExpandCommandLine(pszFileName, szSectionName, MAX_PATH, szVars, szValues);
if (hr != S_OK) return hr; // no vars to expand ignore section
lstrcpy(szSectionNameCopy, szSectionName); // preserve
// OK, this is a satellite DLL. Now we need to find the section(s) that
// got installed.
// we first enum the registry's Module Usage looking for DLLs that were
// installed by (or used by) this CLSID. For each of those we need to
// check if the base filename matches the pattern of the section,
// if it does then we process those sections
DWORD iSubKey = 0; TCHAR szModName[MAX_PATH];
while ( SUCCEEDED(hr = FindDLLInModuleUsage( szModName, m_szCLSID, iSubKey)) ) {
if (PatternMatch(szModName, szSectionName) && IsSectionInINF(szSectionName) ) {
// create new node
CFileNode *pFileNode = new CFileNode(szSectionName, szSectionName); if (pFileNode == NULL) { hr = E_OUTOFMEMORY; goto Exit; }
// don't insert file into list if it's path cannot be found
if (FAILED(GetFilePath(pFileNode))) { delete pFileNode; continue; }
// create and add node to list
if (m_pHeadFileList == NULL) { m_pHeadFileList = pFileNode; m_pCurFileNode = m_pHeadFileList; } else if (SUCCEEDED(hr = m_pCurFileNode->Insert(pFileNode))) { m_pCurFileNode = m_pCurFileNode->GetNextFileNode(); } else { goto Exit; }
lstrcpy(szSectionName, szSectionNameCopy); // restore
} }
if ( hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) { hr = S_OK; }
Exit:
return hr;
}
// loop through the keys in [Add.Code} section and enumerate the
// files and their corresponding sections.
HRESULT CParseInf::EnumSections() { HRESULT hr = S_OK; TCHAR szSectionBuffer[MAX_INF_SECTION_SIZE]; TCHAR szValueBuffer[MAX_PATH]; TCHAR *pszFileName = NULL; CFileNode *pFileNode = NULL; DWORD dwLen = GetPrivateProfileString( KEY_ADDCODE, NULL, DEFAULT_VALUE, szSectionBuffer, MAX_INF_SECTION_SIZE, m_szInf); if (dwLen == 0) { // if inf file or [Add.Code] section
// does not exist, just delete the OCX
Assert (m_pHeadFileList == NULL);
// separate file name from its directory
Assert( lstrlen(m_szFileName) < ARRAYSIZE(szValueBuffer) ); lstrcpy(szValueBuffer, m_szFileName); TCHAR *szName = ReverseStrchr(szValueBuffer, '\\'); Assert (szName != NULL); if (szName == NULL) { hr = E_UNEXPECTED; goto ExitEnumSections; }
// create a node of the OCX and put it in a linked list
m_pHeadFileList = new CFileNode(szName + 1, DEFAULT_VALUE); if (m_pHeadFileList == NULL) { hr = E_OUTOFMEMORY; goto ExitEnumSections; } m_pCurFileNode = m_pHeadFileList;
*szName = '\0'; if (FAILED(hr = m_pHeadFileList->SetPath(szValueBuffer))) { goto ExitEnumSections; } hr = S_FALSE; goto ExitEnumSections; }
// For OCX's that have an INF file and [Add.Code] section, loop
// through the section to get filenames and section names. Store
// each file and its section in a node and add the node to a
// linked list
for (pszFileName = szSectionBuffer; pszFileName[0] != '\0'; pszFileName += lstrlen(pszFileName) + 1) { dwLen = GetPrivateProfileString( KEY_ADDCODE, pszFileName, DEFAULT_VALUE, szValueBuffer, MAX_PATH, m_szInf);
// skip the file if no section is specified for it
if (dwLen == 0) { continue; }
if (StrChr(pszFileName, '%')) { // if section not found and it contains a %
// could be a variable like %LANG% that gets
// substituted to install satellite DLLs
// check if it has any vars that we know about
// and expand them and add filenodes if reqd.
if (HandleSatellites(pszFileName) == S_OK) {
// if this expanded to a satellite dll name then
// we would have already added that
// as a node in HandleSatellites
continue;
} }
// create new node
pFileNode = new CFileNode(pszFileName, szValueBuffer); if (pFileNode == NULL) { hr = E_OUTOFMEMORY; goto ExitEnumSections; }
// don't insert file into list if it's path cannot be found
if (FAILED(GetFilePath(pFileNode))) { delete pFileNode; continue; }
// create and add node to list
if (m_pHeadFileList == NULL) { m_pHeadFileList = pFileNode; m_pCurFileNode = m_pHeadFileList; } else if (SUCCEEDED(hr = m_pCurFileNode->Insert(pFileNode))) { m_pCurFileNode = m_pCurFileNode->GetNextFileNode(); } else { goto ExitEnumSections; } }
// include inf file into file list
if (m_pHeadFileList && m_pCurFileNode) { hr = m_pCurFileNode->Insert(new CFileNode(m_szInf, DEFAULT_VALUE)); if (SUCCEEDED(hr)) m_pCurFileNode = m_pCurFileNode->GetNextFileNode(); }
ExitEnumSections:
return hr; }
// Loop through all the sections in [Setup Hooks]. For each
// section, call ParseUninstallSection to find its UNINSTALL section
// and execute it.
HRESULT CParseInf::ParseSetupHook() { HRESULT hr = S_FALSE; // Return S_FALSE if we don't run into any errors, but also don't do any work.
TCHAR szSectionBuffer[MAX_INF_SECTION_SIZE]; TCHAR szSection[MAX_PATH]; TCHAR *pszKey = NULL;
DWORD dwLen = GetPrivateProfileString( KEY_SETUPHOOK, NULL, DEFAULT_VALUE, szSectionBuffer, MAX_INF_SECTION_SIZE, m_szInf);
// no Setup Hook section found
if (dwLen == 0) goto EXITPARSESETUPHOOK;
for (pszKey = szSectionBuffer; pszKey[0] != '\0'; pszKey += lstrlen(pszKey) + 1) { // For each key, get the section and run the section with RunSetupCommand
dwLen = GetPrivateProfileString( KEY_SETUPHOOK, pszKey, DEFAULT_VALUE, szSection, MAX_PATH, m_szInf);
if (dwLen == 0) continue;
hr = ParseUninstallSection(szSection); if (FAILED(hr)) goto EXITPARSESETUPHOOK; }
EXITPARSESETUPHOOK: return hr; }
// Go to each file's section, find its conditional hook section, then
// call ParseUninstallSection to execute the conditional hook section.
HRESULT CParseInf::ParseConditionalHook() { HRESULT hr = S_FALSE; // Return S_FALSE if we don't run into any errors, but also don't do any work.
TCHAR szHookSection[MAX_PATH]; const TCHAR *pszSection = NULL; CFileNode *pNode = NULL;
if (m_pHeadFileList == NULL) { hr = S_FALSE; goto EXITPARSECONDITIONALHOOK; }
pNode = m_pHeadFileList; for (pNode = m_pHeadFileList; pNode != NULL; pNode = pNode->GetNextFileNode()) { pszSection = pNode->GetSection(); if (pszSection == NULL) continue;
if (GetPrivateProfileString( pszSection, KEY_HOOK, DEFAULT_VALUE, szHookSection, MAX_PATH, m_szInf) == 0) continue;
hr = ParseUninstallSection(szHookSection); if (FAILED(hr)) goto EXITPARSECONDITIONALHOOK; }
EXITPARSECONDITIONALHOOK: return hr; }
// Given a file section, find its UNINSTALL section, go to the
// section and executes the commands there
HRESULT CParseInf::ParseUninstallSection(LPCTSTR lpszSection) { HRESULT hr = S_OK; TCHAR szUninstallSection[MAX_PATH]; TCHAR szBuf[MAX_PATH]; TCHAR szInfSection[MAX_PATH]; TCHAR szCacheDir[MAX_PATH]; HANDLE hExe = INVALID_HANDLE_VALUE; HINSTANCE hInst = NULL;
// check for "UNINSTALL" key
DWORD dwLen = GetPrivateProfileString( lpszSection, KEY_UNINSTALL, DEFAULT_VALUE, szUninstallSection, ARRAYSIZE(szUninstallSection), m_szInf);
// UNINSTALL key not found, quit.
if (dwLen == 0) { return S_FALSE; }
// There are 4 possible combinations inside the uninstall section
// 1) Both inffile and infsection are specified -> simply to go those
// 2) Only inffile is given -> go to inffile and do DefaultInstall
// 3) Only infsection is given -> do infsection in this inf file
// 4) Nothing is specified -> simply do this section
GetDirectory(GD_EXTRACTDIR, szCacheDir, ARRAYSIZE(szCacheDir), m_szFileName);
lstrcpyn(szBuf, szCacheDir, MAX_PATH - 1); lstrcat(szBuf, TEXT("\\"));
int cch = lstrlen(szBuf);
dwLen = GetPrivateProfileString( szUninstallSection, KEY_INFFILE, DEFAULT_VALUE, szBuf + cch, MAX_PATH - cch, m_szInf);
if (dwLen == 0) { szBuf[0] = '\0'; }
// get inf section
dwLen = GetPrivateProfileString( szUninstallSection, KEY_INFSECTION, DEFAULT_VALUE, szInfSection, ARRAYSIZE(szInfSection), m_szInf);
if (dwLen == 0) { if (szBuf[0] != '\0') lstrcpyn(szInfSection, KEY_DEFAULTUNINSTALL,ARRAYSIZE(szInfSection)); else { lstrcpyn(szBuf, m_szInf,ARRAYSIZE(szBuf)); lstrcpyn(szInfSection, szUninstallSection,ARRAYSIZE(szInfSection)); } }
// load advpack.dll and call RunSetupCommand() to process
// any special uninstall commands
hr = STG_E_FILENOTFOUND;
HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL")); if (hinstAdvPack) { RUNSETUPCOMMAND pfnRunSetup = (RUNSETUPCOMMAND)GetProcAddress( hinstAdvPack, achRUNSETUPCOMMANDFUNCTION); if (pfnRunSetup) { hr = pfnRunSetup(NULL, szBuf, szInfSection, szCacheDir, NULL, &hExe, 1, NULL); } }
return hr; }
// For each file specified in the INF file, find its
// path in this order
// 1) OCX path
// 2) System dir
// 3) Windows dir
// 4) PATH directories
HRESULT CParseInf::GetFilePath(CFileNode *pFileNode) { Assert (pFileNode != NULL); HRESULT hr = S_OK; TCHAR szValueBuf[MAX_PATH]; TCHAR *pszPathPtr = NULL; TCHAR *pszPathEnv = NULL; TCHAR *pchPathEnd = NULL; DWORD dwLenPATH = 0;
// ocx directory
hr = GetDirectory(GD_EXTRACTDIR, szValueBuf, ARRAYSIZE(szValueBuf), m_szFileName); CatPathStrN( szValueBuf, szValueBuf, pFileNode->GetName(), ARRAYSIZE(szValueBuf));
// if file being searched for now is the OCX itself, just leave
if (lstrcmpi(szValueBuf, m_szFileName) == 0) { goto EXITGETFILEPATH; }
if (SUCCEEDED(hr) && SUCCEEDED(LookUpModuleUsage(szValueBuf, m_szCLSID))) { goto EXITGETFILEPATH; }
// system directory
hr = GetDirectory(GD_SYSTEMDIR, szValueBuf, ARRAYSIZE(szValueBuf)); if (SUCCEEDED(hr) && CatPathStrN( szValueBuf, szValueBuf, pFileNode->GetName(), ARRAYSIZE(szValueBuf)) && SUCCEEDED(LookUpModuleUsage(szValueBuf, m_szCLSID))) { goto EXITGETFILEPATH; }
// windows directory
hr = GetDirectory(GD_WINDOWSDIR, szValueBuf, ARRAYSIZE(szValueBuf)); if (SUCCEEDED(hr) && CatPathStrN( szValueBuf, szValueBuf, pFileNode->GetName(), ARRAYSIZE(szValueBuf)) && SUCCEEDED(LookUpModuleUsage(szValueBuf, m_szCLSID))) { goto EXITGETFILEPATH; }
// get PATH envirnment variable
dwLenPATH = GetEnvironmentVariable(ENV_PATH, szValueBuf, 0); if (dwLenPATH == 0) { hr = E_FAIL; goto EXITGETFILEPATH; }
pszPathEnv = new TCHAR[dwLenPATH]; if (pszPathEnv == NULL) { hr = E_OUTOFMEMORY; goto EXITGETFILEPATH; } GetEnvironmentVariable(ENV_PATH, pszPathEnv, dwLenPATH); pchPathEnd = pszPathPtr = pszPathEnv;
// walk all directories in PATH and see if file is found
// in any of them
while (pchPathEnd != NULL) { pchPathEnd = StrChr(pszPathPtr, ';'); if (pchPathEnd != NULL) *pchPathEnd = '\0';
CatPathStrN( szValueBuf, pszPathPtr, pFileNode->GetName(), ARRAYSIZE(szValueBuf));
if (SUCCEEDED(LookUpModuleUsage(szValueBuf, m_szCLSID))) goto EXITGETFILEPATH;
if (pchPathEnd != NULL) *(pchPathEnd++) = ';';
pszPathPtr = pchPathEnd; }
// file not found anywhere
hr = E_FAIL;
EXITGETFILEPATH:
if (pszPathEnv != NULL) delete [] pszPathEnv;
if (SUCCEEDED(hr)) { hr = NullLastSlash(szValueBuf, 0); if (SUCCEEDED(hr)) { hr = pFileNode->SetPath(szValueBuf); } }
return hr; }
HRESULT CParseInf::CheckFilesRemovability(void) { HRESULT hr = S_OK; TCHAR szFullName[MAX_PATH]; const TCHAR *pszPath = NULL; BOOL bFileExist;
// Walk through every file and see if it is deletable. If so,
// then check if for sharing violations on that file.
for (m_pCurFileNode = m_pHeadFileList; m_pCurFileNode != NULL && SUCCEEDED(hr); m_pCurFileNode = m_pCurFileNode->GetNextFileNode()) { pszPath = m_pCurFileNode->GetPath(); if (pszPath == NULL || pszPath[0] == '\0') continue;
CatPathStrN( szFullName, pszPath, m_pCurFileNode->GetName(), ARRAYSIZE(szFullName) );
if (IsModuleRemovable(szFullName)) { HANDLE h = CreateFile( szFullName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, NULL); if (h == INVALID_HANDLE_VALUE) { bFileExist = (GetLastError() != ERROR_FILE_NOT_FOUND); if (bFileExist) { hr = STG_E_SHAREVIOLATION; break; } } else { CloseHandle(h); m_pCurFileNode->SetRemovable( TRUE ); } } }
return hr; }
HRESULT CParseInf::CheckLegacyRemovability(LONG *cOldSharedCount ) { HRESULT hr = S_OK; BOOL bFileExist;
HANDLE h = CreateFile( m_szFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, NULL); if (h == INVALID_HANDLE_VALUE) { bFileExist = (GetLastError() != ERROR_FILE_NOT_FOUND); if (bFileExist) { hr = STG_E_SHAREVIOLATION; } else hr = S_FALSE; } else { CloseHandle(h); }
if ( SUCCEEDED(hr) ) hr = CheckFilesRemovability();
return hr; }
HRESULT CParseInf::CheckDURemovability(HKEY hkeyDUDB, BOOL bSilent) { HRESULT hr = S_OK; BOOL bAskSystemClass = TRUE;
hr = CheckFilesRemovability(); if (FAILED(hr)) { goto CheckDURemovabilityExit; }
hr = CheckDUDependencies(hkeyDUDB, bSilent); if (FAILED(hr)) { goto CheckDURemovabilityExit; } // Check for package removability.
// We shouldn't remove a package if another DU also uses it.
// TODO: Some sort of package-currently-in-use test. Either test the path file, as above,
// or use some groovy new IJavaPackage(Manager) method.
for (m_pCurPackageNode = m_pHeadPackageList; m_pCurPackageNode != NULL; m_pCurPackageNode = m_pCurPackageNode->GetNextPackageNode()) { TCHAR szT[MAX_PATH]; LRESULT lResult; BOOL bFoundInOtherDU = FALSE; int cDistUnitEnum = 0;
if (!bAskSystemClass && m_pCurPackageNode->GetIsSystemClass()) { char lpszBuf[MAX_MSGBOX_STRING_LEN]; char lpszBufTitle[MAX_MSGBOX_TITLE_LEN];
MLLoadString(IDS_OCCACHE_WARNING_JAVA_SYSTEM_CLASS, lpszBuf, MAX_MSGBOX_STRING_LEN); MLLoadString(IDS_REMOVAL_WARNING, lpszBufTitle, MAX_MSGBOX_TITLE_LEN);
// Attempting to remove system class. Warn user.
if ( bSilent || MessageBox(NULL, lpszBuf, lpszBufTitle, MB_YESNO | MB_ICONWARNING) != IDYES) {
hr = E_FAIL; goto CheckDURemovabilityExit; } bAskSystemClass = FALSE; }
// Enumerate distribution units
while ( (lResult = RegEnumKey(hkeyDUDB, cDistUnitEnum++, szT, MAX_PATH)) == ERROR_SUCCESS && !bFoundInOtherDU ) { if ( lstrcmp(szT, m_szCLSID) != 0 ) // skip the current DU
{ HKEY hkeyDUCJ; DWORD dw = MAX_PATH; lstrcat(szT, REGSTR_DU_CONTAINS_JAVA ); lResult = RegOpenKeyEx( hkeyDUDB, szT, 0, KEY_READ, &hkeyDUCJ ); if ( lResult == ERROR_SUCCESS ) { lResult = RegQueryValueEx(hkeyDUCJ, REGSTR_VALUE_INF, NULL, NULL, (unsigned char*)szT, &dw); // To be safe, assume that anything other than value not found means
// that the other DU also uses the package.
bFoundInOtherDU = lResult != ERROR_FILE_NOT_FOUND; RegCloseKey( hkeyDUCJ ); } // if we could open other key's Contains\Java subkey
} // if it's a different DU
} // while enumerating DUs
// if we found it in another DU, then we shouldn't remove this package with this DU
m_pCurPackageNode->SetRemovable( !bFoundInOtherDU ); } // for each package
CheckDURemovabilityExit:
return hr; }
HRESULT CParseInf::RemoveLegacyControl( LPCTSTR lpszTypeLibID, BOOL bSilent ) { HRESULT hr = S_FALSE; const TCHAR *pszPath; BOOL bUnplug = m_dwStatus != STATUS_CTRL_UNPLUGGED; BOOL bFileMissing = !PathFileExists( m_szFileName ); BOOL bDidRemove = FALSE; TCHAR szFullName[MAX_PATH];
// loop through the list of assocated files, remove them as
// well as their registry entries.
for (m_pCurFileNode = m_pHeadFileList; m_pCurFileNode != NULL; m_pCurFileNode = m_pCurFileNode->GetNextFileNode()) { int cOwners;
pszPath = m_pCurFileNode->GetPath();
// Process INF file, which as no path since it's not described in INF
if (pszPath == NULL || pszPath[0] == '\0') { if ( DeleteFile(m_pCurFileNode->GetName()) ) hr = S_OK; // hey, we did _something_ - averts the "not enough info" message
continue; } // If we're where, we had some other file besides the INF.
// Even if we don't remove it, we still knock down its module
// usage, which has gotta count for having done something.
hr = S_OK;
CatPathStrN( szFullName, pszPath, m_pCurFileNode->GetName(), MAX_PATH);
cOwners = SubtractModuleOwner( szFullName, m_szCLSID ); if (m_pCurFileNode->GetRemovable() && cOwners == 0) { if ( bUnplug ) UnregisterOCX(szFullName); DeleteFile(szFullName); bDidRemove = bDidRemove || StrCmpI(szFullName,m_szFileName) == 0; } }
if (hr == S_OK && bDidRemove && lpszTypeLibID != NULL) CleanInterfaceEntries(lpszTypeLibID); if ( bUnplug && bFileMissing ) { if ( m_szFileName[0] != '\0' ) // only do this if there is an ocx to clean up after
CleanOrphanedRegistry(m_szFileName, m_szCLSID, lpszTypeLibID); }
return hr; }
HRESULT CParseInf::RemoveDU( LPTSTR szFullName, LPCTSTR lpszTypeLibID, HKEY hkeyDUDB, BOOL bSilent ) { HRESULT hr = S_FALSE; // only say S_OK if we actually do something beyond yanking the INF
const TCHAR *pszPath = NULL;
hr = RemoveLegacyControl( lpszTypeLibID, bSilent ); if (SUCCEEDED(hr)) {
// Remove the packages that we have determined are safe to remove.
for (m_pCurPackageNode = m_pHeadPackageList; m_pCurPackageNode != NULL; m_pCurPackageNode = m_pCurPackageNode->GetNextPackageNode()) { if ( m_pCurPackageNode->GetRemovable() ) { Assert(m_pijpm != NULL); #ifdef UNICODE
OLECHAR *swzPkg = m_pCurPackageNode->GetName(); OLECHAR *swzNamespace = m_pCurPackageNode->GetNamespace(); #else
MAKE_WIDEPTR_FROMANSI(swzPkg, m_pCurPackageNode->GetName()); MAKE_WIDEPTR_FROMANSI(swzNamespace, m_pCurPackageNode->GetNamespace()); #endif
hr = m_pijpm->UninstallPackage( swzPkg, ((*swzNamespace == 0)? NULL : swzNamespace), 0 ); } } }
DeleteKeyAndSubKeys(hkeyDUDB, m_szCLSID);
return hr; }
HRESULT CParseInf::CheckDUDependencies(HKEY hKeyDUDB, BOOL bSilent ) { long lrDist = 0; long lResult = 0; long lr = 0; int iSubKey = 0; HKEY hkeyCurrent = 0; HKEY hkeyCurDU = 0; char szName[MAX_REGPATH_LEN]; int iValue = 0; unsigned long ulSize; char szDependency[MAX_REGPATH_LEN]; HKEY hkeyCOM = 0; DWORD dwType = 0; char szDepName[MAX_CONTROL_NAME_LEN]; char szDepWarnBuf[MAX_MSGBOX_STRING_LEN]; char szCOMControl[MAX_REGPATH_LEN]; DWORD dwSize = 0; HRESULT hr = S_OK;
// Iterate through DUs that have a ...\contains\Distribution Units
// key in the registry and compare the entries inside with the DU
// being removed.
while ((lResult = RegEnumKey(hKeyDUDB, iSubKey++, szName, MAX_REGPATH_LEN)) == ERROR_SUCCESS) {
if (!lstrcmpi(szName, m_szCLSID)) { // Skip ourselves
continue; }
if (RegOpenKeyEx(hKeyDUDB, szName, 0, KEY_READ, &hkeyCurrent) == ERROR_SUCCESS) { lr = RegOpenKeyEx(hkeyCurrent, REGSTR_DU_CONTAINS_DIST_UNITS, 0, KEY_READ, &hkeyCurDU); if (lr != ERROR_SUCCESS) { RegCloseKey(hkeyCurrent); continue; }
ulSize = MAX_REGPATH_LEN; while ((lResult = RegEnumValue(hkeyCurDU, iValue++, szDependency, &ulSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) { if (!lstrcmpi(szDependency, m_szCLSID)) { // dependency found
// Try to get a friendly name for the dependency control
dwSize = MAX_CONTROL_NAME_LEN; lResult = RegQueryValueEx(hkeyCurrent, NULL, NULL, &dwType, (unsigned char *)szDepName, &dwSize);
if (lResult != ERROR_SUCCESS || szDepName[0] == '\0') { // Couldn't get a friendly name. Try the COM branch.
// Technically, this could overflow because
// szName and szCOMControl are the same size, but
// this is already at our defined maximum size for reg
// entries.
wsprintf(szCOMControl, "%s\\%s", REGSTR_COM_BRANCH, szName); lResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szCOMControl, 0, KEY_READ, &hkeyCOM);
if (lResult != ERROR_SUCCESS) { MLLoadString(IDS_OCCACHE_WARNING_DEP_REMOVAL_NAME_UNKNOWN, szDepWarnBuf, MAX_MSGBOX_STRING_LEN); } else { dwSize = MAX_CONTROL_NAME_LEN; lResult = RegQueryValueEx(hkeyCOM, NULL, NULL, &dwType, (unsigned char *)szDepName, &dwSize);
if (lResult != ERROR_SUCCESS || szDepName[0] == '\0') { MLLoadString(IDS_OCCACHE_WARNING_DEP_REMOVAL_NAME_UNKNOWN, szDepWarnBuf, MAX_MSGBOX_STRING_LEN); } else { char lpszBuf[MAX_MSGBOX_STRING_LEN];
MLLoadString(IDS_OCCACHE_WARNING_DEPENDENCY_REMOVAL, lpszBuf, MAX_MSGBOX_STRING_LEN); wsprintf(szDepWarnBuf, lpszBuf, szDepName); }
if (hkeyCOM) { RegCloseKey(hkeyCOM); } } } else { char lpszBuf[MAX_MSGBOX_STRING_LEN];
MLLoadString(IDS_OCCACHE_WARNING_DEPENDENCY_REMOVAL, lpszBuf, MAX_MSGBOX_STRING_LEN);
wsprintf(szDepWarnBuf, lpszBuf, szDepName); }
// TODO: Consider using better HWND than desktop
char lpszBufTitle[MAX_MSGBOX_TITLE_LEN]; MLLoadString(IDS_REMOVAL_WARNING, lpszBufTitle, MAX_MSGBOX_TITLE_LEN); if (bSilent || MessageBox(NULL, szDepWarnBuf, lpszBufTitle, MB_YESNO | MB_ICONWARNING) != IDYES) { hr = E_FAIL; RegCloseKey(hkeyCurDU); RegCloseKey(hkeyCurrent); RegCloseKey(hKeyDUDB); goto ReturnCheckDUDependencies; } } ulSize = MAX_REGPATH_LEN; } RegCloseKey(hkeyCurDU); RegCloseKey(hkeyCurrent); } }
ReturnCheckDUDependencies: return hr; }
// uninstall OCX and its associated files
HRESULT CParseInf::RemoveFiles( LPCTSTR lpszTypeLibID /* = NULL */, BOOL bForceRemove, /* = FALSE */ DWORD dwIsDistUnit, BOOL bSilent) { HRESULT hr = S_OK; HRESULT hrInf1; HRESULT hrInf2; TCHAR szFullName[MAX_PATH]; const TCHAR *pszPath = NULL; BOOL bRemovable = (dwIsDistUnit) ? (TRUE) : (IsModuleRemovable(m_szFileName)); BOOL bIsOCX = FALSE; LONG cRefOld = 0; HKEY hKeyDUDB = 0; BOOL bUnplug = m_dwStatus == STATUS_CTRL_DAMAGED || m_dwStatus == STATUS_CTRL_INSTALLED;
if ( !g_fAllAccess || (!bForceRemove && !bRemovable)) { hr = E_ACCESSDENIED; goto ExitRemoveFiles; }
// Check sharing violation (if it is a legacy control)
if (!dwIsDistUnit) { hr = CheckLegacyRemovability( &cRefOld ); // set SharedDlls count to 1 and save up the old
// count in case the removal fails
if (hr == S_OK && !bRemovable && FAILED(hr = SetSharedDllsCount(m_szFileName, 1, &cRefOld))) { hr = (!PathFileExists( m_szFileName ) ? S_OK : hr); goto ExitRemoveFiles; }
if ( FAILED(hr) ) goto ExitRemoveFiles; } else { long lResultDist;
lResultDist = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DIST_UNITS, 0, KEY_READ, &hKeyDUDB); if (lResultDist == ERROR_SUCCESS) hr = CheckDURemovability( hKeyDUDB, bSilent ); else hr = E_FAIL;
if ( FAILED(hr) ) goto ReturnRemoveFiles; }
// ** keyword UNINSTALL -- new feature that hasn't been implemented yet **
// parse [Setup Hook], look for "UNINSTALL" key
if (FAILED(hrInf1 = ParseSetupHook())) { goto ExitRemoveFiles; }
// parse conditional hooks in each of the file sections
if (FAILED(hrInf2 = ParseConditionalHook())) { goto ExitRemoveFiles; }
// Okay, if the both didn't do anything, we'll try the DefaultUninstall
if ( hrInf1 == S_FALSE && hrInf2 == S_FALSE && PathFileExists( m_szInf ) ) { // see if there's anybody home in the default uninstall section
DWORD dwSize = GetPrivateProfileString( KEY_DEFAULTUNINSTALL, NULL, DEFAULT_VALUE, szFullName, MAX_PATH, m_szInf );
if ( dwSize > 0 ) { HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL")); HANDLE hExe = INVALID_HANDLE_VALUE;
GetDirectory(GD_EXTRACTDIR, szFullName, ARRAYSIZE(szFullName), m_szInf);
if (hinstAdvPack) { RUNSETUPCOMMAND pfnRunSetup = (RUNSETUPCOMMAND)GetProcAddress( hinstAdvPack, achRUNSETUPCOMMANDFUNCTION); if (pfnRunSetup) { // reset hrINf2 to reflect the success of running the default
// uninstall section. This will prevent us from pointing to the
// Add/Remove control panel in some cases, like Shockwave.
hrInf2 = pfnRunSetup(NULL, m_szInf, KEY_DEFAULTUNINSTALL, szFullName, NULL, &hExe, RSC_FLAG_INF, NULL); }
FreeLibrary( hinstAdvPack ); } } }
if ( !dwIsDistUnit ) hr = RemoveLegacyControl( lpszTypeLibID, bSilent ); else hr = RemoveDU( szFullName, lpszTypeLibID, hKeyDUDB, bSilent ); if ( FAILED(hr) ) goto ExitRemoveFiles;
// Return S_FALSE iff none of our uninstall efforts succeeded
if ( hr == S_FALSE && (hrInf1 == S_OK || hrInf2 == S_OK) ) hr = S_OK; // remove conflict directory
if (SUCCEEDED(GetDirectory(GD_CONFLICTDIR, szFullName, ARRAYSIZE(szFullName))) && LStrNICmp(m_szFileName, szFullName, lstrlen(szFullName)) == 0) { TCHAR *pCh = ReverseStrchr(m_szFileName, '\\'); Assert (pCh != NULL); TCHAR chTemp = *pCh; *pCh = '\0'; RemoveDirectory(m_szFileName); *pCh = chTemp; }
DestroyFileList();
ExitRemoveFiles:
// set shared dlls count back to where it was if OCX cannot be removed
if (cRefOld > 0 && FileExist(m_szFileName)) { if (SUCCEEDED(hr)) hr = SetSharedDllsCount(m_szFileName, cRefOld); else SetSharedDllsCount(m_szFileName, cRefOld); }
if ( hKeyDUDB ) RegCloseKey( hKeyDUDB );
ReturnRemoveFiles:
return hr; }
void CParseInf::SetIsDistUnit(BOOL bDist) { m_bIsDistUnit = bDist; }
BOOL CParseInf::GetIsDistUnit() const { return m_bIsDistUnit; }
// return total size of OCX and its associated files
DWORD CParseInf::GetTotalFileSize() const { return m_dwTotalFileSize; }
DWORD CParseInf::GetTotalSizeSaved() const { return m_dwFileSizeSaved; }
DWORD CParseInf::GetStatus() const { return m_dwStatus; }
// return total number of files which will be removed
// together with the OCX
int CParseInf::GetTotalFiles() const { return m_nTotalFiles; }
// return first file in the list of associated files
CFileNode* CParseInf::GetFirstFile() { m_pFileRetrievalPtr = m_pHeadFileList; return m_pFileRetrievalPtr; }
// get the next file in the list of associated files
CFileNode* CParseInf::GetNextFile() { m_pFileRetrievalPtr = m_pFileRetrievalPtr->GetNextFileNode(); return m_pFileRetrievalPtr; }
// return first file in the list of associated files
CPackageNode* CParseInf::GetFirstPackage() { m_pPackageRetrievalPtr = m_pHeadPackageList; return m_pPackageRetrievalPtr; }
// get the next file in the list of associated files
CPackageNode* CParseInf::GetNextPackage() { m_pPackageRetrievalPtr = (m_pPackageRetrievalPtr != NULL)? m_pPackageRetrievalPtr->GetNextPackageNode() : NULL; return m_pPackageRetrievalPtr; }
|