/****************************************************************************** * Temp conversion utility to take registry entries and populate the class store with those entries. *****************************************************************************/ /****************************************************************************** includes ******************************************************************************/ #include "precomp.hxx" #include "..\appmgr\resource.h" extern HINSTANCE ghInstance; #define WTOA(sz, wsz, cch) WideCharToMultiByte(CP_ACP, 0, wsz, -1, sz, cch, NULL, NULL) #define HOME 1 /****************************************************************************** defines and prototypes ******************************************************************************/ extern CLSID CLSID_ClassStore; extern const IID IID_IClassAdmin; CLSID CLSID_ClassStore = { /* 62392950-1AF8-11d0-B267-00A0C90F56FC */ 0x62392950, 0x1af8, 0x11d0, {0xb2, 0x67, 0x00, 0xa0, 0xc9, 0x0f, 0x56, 0xfc} }; const IID IID_IClassStore = { 0x00000190, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; const IID IID_IClassAdmin = { 0x00000191, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; int CompareClassDetails( CLASSDETAIL * p1, CLASSDETAIL * p2 ); HRESULT UpdateDatabaseFromRegistry( MESSAGE * pMessage ); HRESULT UpdateClassStoreFromDatabase( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); HRESULT UpdateClassStoreFromMessage( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); HRESULT UpdateClassAssociations( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); void RemoveClassAssociations( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); HRESULT UpdatePackageDetails( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); void RemoveOneClassAssociation( MESSAGE * pMessage, CLASS_ENTRY * pClsEntry, IClassAdmin * pClassAdmin ); HRESULT UpdateOneClassAssociation( MESSAGE * pMessage, CLASS_ENTRY * pClsEntry, IClassAdmin * pClassAdmin ); HRESULT UpdateOnePackageDetail( MESSAGE * pMessage, PACKAGE_ENTRY * pClsEntry, IClassAdmin * pClassAdmin ); LONG UpdateDatabaseFromTypelib( MESSAGE * pMessage ); void DumpTypelibEntries( MESSAGE * pMessage ); LONG UpdateDatabaseFromFileExt( MESSAGE * pMessage ); LONG UpdateDatabaseFromProgID( MESSAGE * pMessage ); LONG UpdateDatabaseFromIID( MESSAGE * pMessage ); HRESULT AddToClassStore( MESSAGE *pMessage, IClassAdmin * pClassAdmin ); void AppEntryToAppDetail( APP_ENTRY * pAppEntry, APPDETAIL * pAppDetail ); HRESULT UpdatePackageDetails( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); void AppEntryToAppDetail( APP_ENTRY * pAppEntry, APPDETAIL * pAppDetail ); HRESULT UpdateInterfaceEntries( MESSAGE * pMessage, IClassAdmin * pClassAdmin ); HRESULT UpdateOneInterfaceEntry( MESSAGE * pMessage, ITF_ENTRY * pITFEntry, IClassAdmin * pClassAdmin ); /****************************************************************************** Da Code ******************************************************************************/ HRESULT VerifyArguments( MESSAGE * pMessage ) { // if( !pMessage->pRegistryKeyName ) // return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_PARAMETER ); return S_OK; } HRESULT UpdateDatabaseFromRegistry( MESSAGE * pMessage ) { HRESULT hr = S_OK; hr = HRESULT_FROM_WIN32( UpdateDatabaseFromCLSID( pMessage )); if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) return UpdateDatabaseFromFileExt(pMessage); if ( !SUCCEEDED(hr ) ) return hr; hr = HRESULT_FROM_WIN32( UpdateDatabaseFromFileExt( pMessage )); if ( !SUCCEEDED(hr ) ) return hr; hr = HRESULT_FROM_WIN32( UpdateDatabaseFromProgID( pMessage )); if ( !SUCCEEDED(hr ) ) return hr; hr = HRESULT_FROM_WIN32( UpdateDatabaseFromIID( pMessage )); if ( !SUCCEEDED(hr ) ) return hr; hr = HRESULT_FROM_WIN32( UpdateDatabaseFromTypelib( pMessage )); if ( !SUCCEEDED(hr ) ) return hr; return hr; } HRESULT UpdateClassStoreFromDatabase( MESSAGE * pMessage, IClassAdmin * pClassAdmin ) { HRESULT hr; hr = UpdateClassAssociations( pMessage, pClassAdmin ); if ( SUCCEEDED(hr)) { hr = UpdateInterfaceEntries( pMessage, pClassAdmin ); if ( SUCCEEDED(hr) ) { hr = UpdatePackageDetails( pMessage, pClassAdmin ); } } if (FAILED(hr)) { // We blew it somewhere so we need to remove all the CLSIDs that we // might have added. RemoveClassAssociations( pMessage, pClassAdmin); } return hr; } HRESULT UpdateClassStoreFromMessage( MESSAGE * pMessage, IClassAdmin * pClassAdmin ) { HRESULT hr; if ( (hr = VerifyArguments( pMessage )) == S_OK ) { hr = UpdateDatabaseFromRegistry( pMessage ); if (SUCCEEDED(hr) || MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,ERROR_NO_MORE_ITEMS) == hr) { if (pMessage->hRoot != HKEY_CLASSES_ROOT) { // We mapped it into a temporary key so we need to do a pass // on HKEY_CLASSES_ROOT as well in order to catch anything // that might have been copied there instead of into our // remapped key. // This is a problem because we can't remap HKCR across // process boundaries, our remapping function only works in // this process. pMessage->hRoot = HKEY_CLASSES_ROOT; hr = UpdateDatabaseFromRegistry( pMessage ); } if (SUCCEEDED(hr) || MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,ERROR_NO_MORE_ITEMS) == hr) { hr = UpdateClassStoreFromDatabase( pMessage, pClassAdmin ); } } } return hr; } HRESULT UpdateInterfaceEntries( MESSAGE * pMessage, IClassAdmin * pClassAdmin ) { ITF_ENTRY * pITFEntry = (ITF_ENTRY *)pMessage->pIIDict->GetFirst(); HRESULT hr; if ( pITFEntry ) { do { hr = UpdateOneInterfaceEntry(pMessage,pITFEntry,pClassAdmin); if ( !SUCCEEDED(hr) ) return hr; pITFEntry = pMessage->pIIDict->GetNext( pITFEntry ); } while ( pITFEntry != 0 ); } else hr = MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); // no interfaces. return hr; } HRESULT UpdateOneInterfaceEntry( MESSAGE * pMessage, ITF_ENTRY * pITFEntry, IClassAdmin * pClassAdmin ) { CLSID IID; CLSID PSClsid; CLSID TypelibID; StringToCLSID( &pITFEntry->IID[1], &IID ); StringToCLSID( &pITFEntry->Clsid[1], &PSClsid ); StringToCLSID( &pITFEntry->TypelibID[1], &PSClsid ); HRESULT hr = S_OK; if ( !pMessage->fDumpOnly ) hr = pClassAdmin->NewInterface( IID, L"", PSClsid, TypelibID ); if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) hr = S_OK; return hr; } HRESULT UpdatePackageDetails( MESSAGE * pMessage, IClassAdmin * pClassAdmin ) { PACKAGE_ENTRY * pPackageEntry = (PACKAGE_ENTRY *)pMessage->pPackageDict->GetFirst(); HRESULT hr = S_OK; hr = E_FAIL; if ( pPackageEntry ) { do { hr = UpdateOnePackageDetail(pMessage,pPackageEntry,pClassAdmin); if (!SUCCEEDED(hr)) return hr; pPackageEntry = pMessage->pPackageDict->GetNext(pPackageEntry); } while ( pPackageEntry != 0 ); } else hr = MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); // no packages. return hr; } HRESULT UpdateOnePackageDetail( MESSAGE * pMessage, PACKAGE_ENTRY * pPackageEntry, IClassAdmin * pClassAdmin ) { PACKAGEDETAIL PackageDetail; APP_ENTRY *pAppEntry; int len; int count; HRESULT hr = S_OK; int Index = 0; int max; // copy the bare package details memcpy( &PackageDetail, &pPackageEntry->PackageDetails, sizeof( PACKAGEDETAIL ) ); count = PackageDetail.cApps = pPackageEntry->Count; // if the null appid contains at least one clsid entry or typelib entry // assume one more app id in the package. There can be either a clsid entry or // a typelib entry in the null appid. if ( (pPackageEntry->GetCountOfClsidsInNullAppid() > 0 ) || (pPackageEntry->GetCountOfTypelibsInNullAppid() > 0 ) ) { PackageDetail.cApps += 1; count++; } // Allocate an APPDETAIL structure if there is at least one appid in the // package. if ( count ) { PackageDetail.pAppDetail = new APPDETAIL[ count ]; memset( PackageDetail.pAppDetail, '\0', count * sizeof(APPDETAIL) ); } // update the rest of entries that have an appid. for ( Index = 0, pAppEntry = pPackageEntry->pAppDict->GetFirst(); pAppEntry && (Index < pPackageEntry->Count); ++Index, pAppEntry = pPackageEntry->pAppDict->GetNext( pAppEntry) ) { AppEntryToAppDetail(pAppEntry, &PackageDetail.pAppDetail[ Index ] ); } // // If there is at least one clsid in the null appid, then assign the appid // the same guid as the first clsid in the list. Else, if there is at least // one typelib in the list, assign the appid the same guid as the typelib id // if ( (max = pPackageEntry->GetCountOfClsidsInNullAppid()) > 0 ) { APP_ENTRY A; char * p = pPackageEntry->GetFirstClsidInNullAppidList(); A.SetAppIDString( p ); // Add the Class ids from the NUll app entry list to the app entry.. for ( count = 0, p = pPackageEntry->ClsidsInNullAppid->GetFirst(); p && (count < max); ++count, p = pPackageEntry->ClsidsInNullAppid->GetNext( p ) ) { A.AddClsid( p ); } // update the entries with the null clsid. AppEntryToAppDetail( &A, &PackageDetail.pAppDetail [ Index ] ); // Add remote server names to app entry ( not implemented yet ). } else if ( (max = pPackageEntry->GetCountOfTypelibsInNullAppid()) > 0 ) { APP_ENTRY A; char * p = pPackageEntry->GetFirstTypelibInNullAppidList(); A.SetAppIDString( p ); // Add the Class ids from the NUll app entry list to the app entry.. for ( count = 0, p = pPackageEntry->TypelibsInNullAppid->GetFirst(); p && (count < max); ++count, p = pPackageEntry->TypelibsInNullAppid->GetNext( p ) ) { A.AddTypelib( p ); } // update the entries with the null clsid. AppEntryToAppDetail( &A, &PackageDetail.pAppDetail [ Index ] ); } // update package name. len = strlen( &pPackageEntry->PackageName[0] ); PackageDetail.pszPackageName = new OLECHAR[ (len +1 )*2 ]; mbstowcs(PackageDetail.pszPackageName,&pPackageEntry->PackageName[0],len+1); // write the class store. if ( pMessage->fDumpOnly) { (*pMessage->pDumpOnePackage)( pMessage, &PackageDetail ); hr = S_OK; } else hr = pClassAdmin->NewPackage( &PackageDetail ); return hr; } void RemoveClassAssociations( MESSAGE * pMessage, IClassAdmin * pClassAdmin ) { CLASS_ENTRY * pClsEntry = pMessage->pClsDict->GetFirst(); if ( pClsEntry ) { do { RemoveOneClassAssociation( pMessage, pClsEntry, pClassAdmin ); pClsEntry = pMessage->pClsDict->GetNext( pClsEntry ); } while ( pClsEntry != 0 ); } } void RemoveOneClassAssociation( MESSAGE * pMessage, CLASS_ENTRY * pClsEntry, IClassAdmin * pClassAdmin ) { CLSID clsid; StringToCLSID(&(pClsEntry->GetClsidString())[1], &clsid ); pClassAdmin->DeleteClass( clsid ); } HRESULT UpdateClassAssociations( MESSAGE * pMessage, IClassAdmin * pClassAdmin ) { CLASS_ENTRY * pClsEntry = pMessage->pClsDict->GetFirst(); HRESULT hr = S_OK; if ( pClsEntry ) { do { hr = UpdateOneClassAssociation( pMessage, pClsEntry, pClassAdmin ); if (hr != S_OK ) return hr; pClsEntry = pMessage->pClsDict->GetNext( pClsEntry ); } while ( pClsEntry != 0 ); } return hr; } HRESULT UpdateOneClassAssociation( MESSAGE * pMessage, CLASS_ENTRY * pClsEntry, IClassAdmin * pClassAdmin ) { CLASSASSOCIATION CA; LPOLESTR * prgFileExt; LPOLESTR * prgProgID; char * p; int len; ListEntry * pListEntry; HRESULT hr = S_OK; memcpy( &CA, &pClsEntry->ClassAssociation, sizeof( CLASSASSOCIATION ) ); CA.cFileExt = pClsEntry->FileExtList.GetCount(); CA.cOtherProgId = pClsEntry->OtherProgIDs.GetCount(); // convert the classid into a guid StringToCLSID(&(pClsEntry->GetClsidString())[1], &CA.Clsid ); // create the file extension array. if ( CA.cFileExt ) { int count; // allocate array for the file extensions. CA.prgFileExt = prgFileExt = new LPOLESTR[ CA.cFileExt ]; // copy the file extensions one by one. for ( count = 0, pListEntry = pClsEntry->FileExtList.GetFirst(); pListEntry; ++count, pListEntry = pClsEntry->FileExtList.GetNext( pListEntry ) ) { char * p = (char *) pListEntry->pElement; int len = strlen(p); prgFileExt[ count ] = new OLECHAR[ (len+1)*2 ]; mbstowcs( prgFileExt[ count ], p, len+1 ); } } // create the progid array if ( CA.cOtherProgId ) { int count; ListEntry * pListEntry; // allocate array for the file extensions. CA.prgOtherProgId = prgProgID = new LPOLESTR[ CA.cOtherProgId ]; // copy the file extensions one by one. for ( count = 0, pListEntry = pClsEntry->OtherProgIDs.GetFirst(); pListEntry; ++count, pListEntry = pClsEntry->OtherProgIDs.GetNext( pListEntry ) ) { p = (char *) pListEntry->pElement; len = strlen(p); prgProgID[ count ] = new OLECHAR[ (len +1) *2 ]; mbstowcs( prgProgID[ count ], p, len+1 ); } } // create the default progid - the first in the progidlist. if ( pClsEntry->OtherProgIDs.GetCount() ) { pListEntry = pClsEntry->OtherProgIDs.GetFirst(); p = (char *)pListEntry->pElement; len = strlen(p); CA.pDefaultProgId = new OLECHAR[ (len+1) * 2 ]; mbstowcs( CA.pDefaultProgId, p, len+1 ); } else CA.pDefaultProgId = 0; if (CA.pszDesc == NULL) { CA.pszDesc = L""; } if ( !pMessage->fDumpOnly ) { // First try and delete the class entry to make sure this class ID // isn't orphaned from some earlier partial installation. If the // classid is in the class store but isn't listed as being // implemented by an application then this will cause it to be // deleted. If it _IS_ implemented by another application then this // wil be a NOP. pClassAdmin->DeleteClass(CA.Clsid); hr = pClassAdmin->NewClass( &CA ); } if ( hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) ) // duplicate { // Get details of the pre-existing class. CLASSDETAIL cdOld; hr = pClassAdmin->GetClassDetails(CA.Clsid, &cdOld); if (SUCCEEDED(hr)) { // Check to see if they are equivalent (CompareClassDetails). int i = CompareClassDetails(&CA, &cdOld); if (0 != i) { // Inform the user of a conflict and abort TCHAR szCaption[256]; TCHAR szBuffer[1024]; ::LoadString(ghInstance, IDS_CLSIDCONFLICT1, szBuffer, 1024); // UNDONE - we need to get the other application's name here. strcpy(szCaption, "some other application"); IEnumPackage * pIEP; CSPLATFORM cp; memset(&cp, 0, sizeof(cp)); hr = pClassAdmin->GetPackagesEnum(CA.Clsid, NULL, cp, 0, 0, &pIEP); if (SUCCEEDED(hr)) { ULONG ul; PACKAGEDETAIL pd; hr = pIEP->Next(1, &pd, &ul); if (SUCCEEDED(hr) && 1 == ul) { WTOA(szCaption, pd.pszPackageName, 256); } pIEP->Release(); } strcat(szBuffer, szCaption); ::LoadString(ghInstance, IDS_CLSIDCONFLICT2, szCaption, 256); strcat (szBuffer, szCaption); strncpy(szCaption, pMessage->pPackagePath, 256); int iReturn = ::MessageBox(pMessage->hwnd, szBuffer, szCaption, MB_OK); hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); } else { // they aren't different so it's OK to continue hr = S_OK; } } } // // before return, update the class association data structure back to the class // entry structure, so that the dumper can use it. memcpy( &pClsEntry->ClassAssociation, &CA, sizeof( CLASSASSOCIATION ) ); return hr; } // compares two class details // // // Input: p1: Pointer to a CLASSDETAIL structure // p2: Pointer to the other CLASSDETAIL structure // Returns: // 0 if all is well, -1 otherwise. // Notes: DOES NOT CHECK FOR NULL INPUT POINTERS. // int CompareClassDetails( CLASSDETAIL * p1, CLASSDETAIL * p2 ) { // compare the class id. if( _memicmp( (const void * )&p1->Clsid, (const void *)&p2->Clsid, sizeof( CLSID ) ) ) return -1; // We do not compare pszdesc, since it is just an info field. // We DO compare the icon paths, since if icon paths are different, they are // likely to be different packages supporting the same classid. (I am not // sure, this is a good argument) if( p1->pszIconPath && p2->pszIconPath ) { if( _wcsicmp( (const wchar_t *)p1->pszIconPath, (const wchar_t *)p2->pszIconPath ) != 0 ) return -1; } // test the Treatas and AutoConvert CLSIDs if( _memicmp( (const unsigned char *)&p1->TreatAsClsid, (const unsigned char *)&p2->TreatAsClsid, sizeof( CLSID ) ) ) return -1; if( _memicmp( (const unsigned char *)&p1->AutoConvertClsid, (const unsigned char *)&p2->AutoConvertClsid, sizeof( CLSID ) ) ) return -1; // If the count of file extensions do not match, they are likely different // packages. if( p1->cFileExt != p2->cFileExt ) return -1; else { int i, cFileExt; // All the file extensions should match for the guaranteeing that the // package is the same. for( i = 0, cFileExt = p1->cFileExt; i < cFileExt; ++i ) { if(_wcsicmp( (const wchar_t *)p1->prgFileExt[ i ], (const wchar_t *)p2->prgFileExt[ i ] ) != 0 ) return -1; } if( i < cFileExt ) return -1; } // compare mime type. if( p1->pMimeType && p2->pMimeType ) { if( _wcsicmp( (const wchar_t *)p1->pMimeType, (const wchar_t *)p2->pMimeType ) != 0 ) return -1; } // compare default progid. if( p1->pDefaultProgId && p2->pDefaultProgId ) { if( _wcsicmp( (const wchar_t *)p1->pDefaultProgId, (const wchar_t *)p2->pDefaultProgId ) != 0 ) return -1; } // if the count of Other prog ids do not match , they are likely different // packages if( p1->cOtherProgId != p2->cOtherProgId ) return -1; else { int i, cOtherProgId; // All the OtherProgIds should match for the guaranteeing that the // package is the same. for( i = 0, cOtherProgId = p1->cOtherProgId; i < cOtherProgId; ++i ) { if(_wcsicmp((const wchar_t *)p1->prgOtherProgId[ i ], (const wchar_t *)p2->prgOtherProgId[ i ]) != 0 ) return -1; } if( i < cOtherProgId ) return -1; } return 0; } void AppEntryToAppDetail( APP_ENTRY * pAppEntry, APPDETAIL * pAppDetail ) { int count; ListEntry * pListEntry; char * p; StringToCLSID( &pAppEntry->AppIDString[1], &pAppDetail->AppID ); // pick up the clsid list. if ( count = pAppEntry->ClsidList.GetCount() ) { // Allocate space for requisite # of CLSIDs pAppDetail->cClasses = count; pAppDetail->prgClsIdList = new CLSID[ count ]; for ( count = 0, pListEntry = pAppEntry->ClsidList.GetFirst(); pListEntry; pListEntry = pAppEntry->ClsidList.GetNext( pListEntry ), ++count ) { p = (char*)pListEntry->pElement; StringToCLSID( p+1, &pAppDetail->prgClsIdList[count] ); } } // pick up typelib list. if ( count = pAppEntry->TypelibList.GetCount() ) { // Allocate space for requisite # of Typelibs pAppDetail->cTypeLibIds = count; pAppDetail->prgTypeLibIdList = new CLSID[ count ]; for ( count = 0, pListEntry = pAppEntry->TypelibList.GetFirst(); pListEntry; pListEntry = pAppEntry->TypelibList.GetNext( pListEntry ), ++count ) { p = (char*)pListEntry->pElement; StringToCLSID( p+1, &pAppDetail->prgTypeLibIdList[count] ); } } // pick up remote server name list. if ( count = pAppEntry->RemoteServerNameList.GetCount() ) { pAppDetail->prgServerNames = new LPOLESTR[ count ]; pAppDetail->cServers = count; for ( count = 0, pListEntry = pAppEntry->RemoteServerNameList.GetFirst(); pListEntry; pListEntry = pAppEntry->RemoteServerNameList.GetNext( pListEntry ), ++count ) { p = (char *) pListEntry->pElement; int len = strlen(p); pAppDetail->prgServerNames[ count ] = new OLECHAR[ (len +1) * 2 ]; mbstowcs( pAppDetail->prgServerNames[count], p, len+1 ); } } } HRESULT AddToClassStore( MESSAGE *pMessage, IClassAdmin * pClassAdmin ) { return S_OK; }