/****************************************************************************** * Temp conversion utility to take registry entries and populate the class store with those entries. *****************************************************************************/ /****************************************************************************** includes ******************************************************************************/ #include "precomp.hxx" /****************************************************************************** defines and prototypes ******************************************************************************/ extern CLSID CLSID_ClassStore; extern const IID IID_IClassStore; extern const IID IID_IClassAdmin; LONG UpdateClassEntryFromAutoConvert( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry ); LONG UpdateClassEntryFromTreatAs( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry ); LONG UpdateClassEntryFromServerType( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry ); LONG UpdateClassEntryFromTypelib( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry ); LONG UpdateClassEntryFromAppID( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry, char * pAppidBuffer ); ULONG GeneratePackageDetails( MESSAGE * pMessage, BasicRegistry * pCLSID, PACKAGEDETAIL * pPackageDetails ); ULONG UpdateClassEntryFromServerType( MESSAGE * pMessage, APP_ENTRY * pAppEntry, BasicRegistry * pCLSID ); ULONG PackageFromServerType( MESSAGE * pMessage, DWORD Context, APP_ENTRY * pAppEntry, BasicRegistry * pServerTypeKey, BasicRegistry * pCLSID ); ULONG UpdateClassEntryFromServerType( MESSAGE * pMessage, BasicRegistry * pCLSID, APP_ENTRY * pAppEntry ); LONG UpdatePackageFromClsid( MESSAGE * pMessage, BasicRegistry * pCLSID, char * pClsidString, char * pAppid ); LONG UpdatePackage( MESSAGE * pMessage, BOOL fUsageFlag, DWORD Context, char * pClsidString, char * pAppid, char * ServerName, DWORD * pMajorVersion, DWORD * pMinorVersion, DWORD * pLocale ); CLASSPATHTYPE GetPathType( char * pExtension ); LPOLESTR GetPath( char * pPath ); LPOLESTR GetSetupCommand( char * pName ); LPOLESTR MakePackageName( char * pName ); void SetCSPlatform( CSPLATFORM * pCSPlatform ); /****************************************************************************** Globals ******************************************************************************/ extern char * MapDriveToServerName[ 26 ]; LONG UpdateDatabaseFromCLSID( MESSAGE * pMessage ) /***************************************************************************** Purpose: Update the internal database from clsid entries under the root key specified by the message. In Arguments: Message - A message block that contains the root of the key that has class id etc related information. Out Arguments: None. InOut Arguments: None. Return Arguments: A Win32 error code specifying success or the kind of failure. Remarks: The routine only returns an error code of ERROR_NO_MORE_ITEMS. *****************************************************************************/ { BasicRegistry * pHKCR = new BasicRegistry( pMessage->hRoot ); // HKCR BasicRegistry * pCLSIDUnderHKCR; CLSDICT * pClsDict = pMessage->pClsDict; BOOL fNewEntry = 0; int Index; LONG CLSIDError = ERROR_SUCCESS; CLASS_ENTRY * pClassEntry; // // Get the first clsid key under HKCR // if ( pHKCR->Find( "CLSID", &pCLSIDUnderHKCR ) != ERROR_SUCCESS ) return ERROR_NO_MORE_ITEMS; // // Go thru all the subkeys under CLSID and get the details under the keys. // for ( Index = 0, fNewEntry = 0; CLSIDError != ERROR_NO_MORE_ITEMS; ++Index ) { char CLSIDBuffer[256]; DWORD SizeOfCLSIDBuffer = sizeof(CLSIDBuffer)/sizeof(char); char AppidBuffer[ 256 ]; BasicRegistry * pCLSID; // // Get the name of the key - the next one under HKCRCLSID that // matches our time stamp criteria. // CLSIDError = pCLSIDUnderHKCR->NextKey( CLSIDBuffer, &SizeOfCLSIDBuffer, &pCLSID, pMessage->ftLow, pMessage->ftHigh); if ( (CLSIDError == ERROR_SUCCESS ) && (CLSIDBuffer[0] == '{') ) { // // We got a valid classid entry. See if it is in the database // already, if not make a new entry and update that with the // classid related details. // char * pT = new char [SizeOfCLSIDBuffer+1]; strcpy( pT, CLSIDBuffer ); if ( (pClassEntry = pClsDict->Search( CLSIDBuffer ) ) == 0 ) { pClassEntry = new CLASS_ENTRY; fNewEntry = 1; } memcpy( pClassEntry->ClsidString, &CLSIDBuffer, SIZEOF_STRINGIZED_CLSID ); // // Update class entry from subkeys. // // update frm "autoconvert" value. ignore error, since optional. UpdateClassEntryFromAutoConvert( pMessage, pCLSID, pClassEntry ); // update frm "treatas" value. ignore error, since optional. UpdateClassEntryFromTreatAs( pMessage, pCLSID, pClassEntry ); // // Update from clsid. Although this is optional, the appid setting // is important in that it determines if a classid falls under an // appid that is supported by a package or if it is a clsid that // does not have an appid. A package can have both - clsids // which have appids or those that dont. // BOOL fAdded = FALSE; // Check if this class id has an app id. if ( UpdateClassEntryFromAppID( pMessage, pCLSID, pClassEntry, &AppidBuffer[0] ) ) { // yes this classid has an appid, so enter into the app detail // structure corresponding to the appid. fAdded = UpdatePackageFromClsid( pMessage, pCLSID, pT, &AppidBuffer[0] ); } else { // no, this classid does not have an appid associated, so // enter this into the null appid group. fAdded = UpdatePackageFromClsid( pMessage, pCLSID, pT, 0 ); } if ( fNewEntry && fAdded) pClsDict->Insert( pClassEntry ); } else if ( CLSIDError == ERROR_SUCCESS ) { delete pCLSID; } } // // delete the CLSID key under HKCR // delete pCLSIDUnderHKCR; if ( CLSIDError == ERROR_NO_MORE_ITEMS ) return ERROR_SUCCESS; return ERROR_SUCCESS; } LONG UpdatePackageFromClsid( MESSAGE * pMessage, BasicRegistry * pCLSID, char * pClsidString, char * pAppid ) /***************************************************************************** Purpose: To update package details from package id. In Arguments: pMessage - Message block passing info between modules. pCLSID - An open Key to the registry for the specified clsid. pClsidString- A stringized clsid used for entring into appid database. pAppid - Stringized appid to enter into the package database. Out Arguments: None. InOut Arguments: None. Return Arguments: Status. 1 - need to add CLSID, 0 - don't need to add CLSID Remarks: A package is a collection of individual executables. Under the CLSID key in a registry can be a number of packages: inproc handlers, inproc servers and local and remote servers. Each of these qualify as individual packages unless packaged in say a cab file. That overall packaging is specified by the package path field in the message. Therefore this routine goes thru all individual packages as specified under the CLSID key and attempts to generate packages for them. The Update package routine then decides what the package type is based on whether the message field has a package path specified. It is very possible (and happens for .Cab files) for CLSID entries of local server inproc handler etc to end up in one package *****************************************************************************/ { // class context mapping array. static DWORD ClassContextArray[] = { CLSCTX_INPROC_HANDLER, CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER, CLSCTX_REMOTE_SERVER // BUGBUG - what about the 16-bit cases? // , // CLSCTX_INPROC_SERVER16, // CLSCTX_LOCAL_SERVER, // CLSCTX_INPROC_HANDLER16 }; // Keys that map to a class context. // Must have same number of elements as ClassContextArray. static char * pKeyNamesArray[] = { "InprocHandler32", "InprocServer32", "LocalServer32", "RemoteServer32" // , // "InprocServer", // "LocalServer", // "InprocHandler" }; LONG lReturn = 0; int Index; for ( Index = 0; Index < sizeof(pKeyNamesArray) / sizeof(pKeyNamesArray[0]) ; Index++ ) { // Search for all the server types under the CLSID. If available, create // packages for those server types. BasicRegistry * pServerTypeKey; LONG E; // check if a potential package of the type specified exists in the // registry. In other words, check if one of the above specified keys // exists under the clsid key. // E = pCLSID->Find( pKeyNamesArray[ Index ], &pServerTypeKey ); if ( E == ERROR_SUCCESS ) { // // Yes, a key for the specified server type exists. // Get its named value. Based on this we will attempt to enter // a new package in our database. // char ServerName[_MAX_PATH]; DWORD ServerNameLength; ServerNameLength = sizeof( ServerName) / sizeof( char ); E = pServerTypeKey->QueryValueEx( 0, &ServerName[0], &ServerNameLength ); // // A server name may have a switch specified for execution. That // is not significant for our class store update, but is significant // in that it should not be part of the server name to enter into // the class store. Make sure we ignore it. // if ( E == ERROR_SUCCESS ) { // remove any '/' switch characters, so we dont get confused. char * p = strchr( &ServerName[0], '/' ); if ( p ) { while ( *(--p) == ' ' ); *(p+1) = '\0'; } // // call common routine to update package from clsid and appid // details. // UpdatePackage( pMessage, 0, // clsid update - not a typelib id update ClassContextArray[ Index ], pClsidString, pAppid, &ServerName[0], 0, 0, 0 ); } else { // It is possible that the tag may not have a name, in // which case we need to create a package entry using the // original package path. UpdatePackage( pMessage, 0, // clsid update ClassContextArray[ Index ], pClsidString, pAppid, pMessage->pPackagePath, 0, 0, 0 ); } delete pServerTypeKey; // We've found one entry and that's enough to get everything we // need to know to be able to populate the class store so we're // going to break out of the for loop here. // BUGBUG - For beta 2 we need to simplify this code so that we // don't even bother looking for this. Most of this code // is here to support features that the class store was going to // have once upon a time. Since then, the class store has been // redesigned and we really don't need all of this junk. lReturn = 1; break; } } return lReturn; } LONG UpdatePackage( MESSAGE * pMessage, BOOL fUsage, DWORD Context, char * pClsidString, char * pAppid, char * ServerName, DWORD * pMajor, DWORD * pMinor, LCID * pLocale ) /***************************************************************************** Purpose: Update package details in database based on clsid and appid. In Arguments: pMessage - Message block passing arguments between modules. fUsageFlag - 0 if clsid is being updated in appid list or 1 if a typelib is being updated in appid list. pClsidString- A stringized clsid/typelibid used for entring into appid database. pAppid - Stringized appid to enter into the package database. ServerName - String used to identify the original server name. pMajor - Major version number pMinor - Minor version number pLocale - locale. Out Arguments: InOut Arguments: Return Arguments: Remarks: Version#s and locale info are pointers. This routine is used by typelib update routine also. They usually have version and locale info, but general packages do not. Therefore the routine has pointers to indicate if info is available and if so, update it. If the message has a package path, it indicates that the server supporting the classid is part of that package. So the package path determines the package type etc and overrides any server names specified in the CLSID key We are also making an assumption that there is no appid associated with a typelib, so we can asssume that all typelib entries go to the null appid list only. If this changes, then use the AddTypelib method in APP_ENTRY to update the app entry. THIS ROUTINE NEEDS CLEANUP - IT IS A HACK AFTER HACK AFTER HACK *****************************************************************************/ { PDICT * pPackageDict = pMessage->pPackageDict; PACKAGE_ENTRY * pPackageEntry; char Name[ _MAX_FNAME ]; char Ext[ _MAX_EXT ]; char PackageName[ _MAX_PATH ]; PACKAGEDETAIL PackageDetails; LONG Error = 0; APP_ENTRY * pAppEntry; char * p; CSPLATFORM CSPlatform; SetCSPlatform( &CSPlatform); // clear the package details structure. memset(&PackageDetails, '\0', sizeof( PackageDetails )); // // If package path exists, then the extension etc determine the package // type. If not, the server name (localserver/handler name etc) determines // the package type. // if ( p = pMessage->pPackagePath ) { _splitpath( pMessage->pPackagePath, NULL, NULL, Name, Ext ); } else { p = ServerName; _splitpath( ServerName, NULL, NULL, Name, Ext ); } if (pMessage->pPackageName) { strcpy(PackageName, pMessage->pPackageName); } else { strcpy( PackageName, Name ); strcat( PackageName, Ext ); pMessage->pPackageName = new char[strlen(PackageName)+1]; strcpy(pMessage->pPackageName, PackageName); } // Check if we already have the package name in the dictionary. pPackageEntry = pPackageDict->Search( &PackageName[0], Context ); // if we do not, make a new package entry. if (!pPackageEntry) { pPackageEntry = new PACKAGE_ENTRY; strcpy( &pPackageEntry->PackageName[0], &PackageName[0] ); PackageDetails.dwContext =( pMessage->pPackagePath ) ? CLSCTX_INPROC_SERVER + CLSCTX_LOCAL_SERVER : Context; // Context temp workaround if ( pMessage->fPathTypeKnown ) PackageDetails.PathType = pMessage->PathType; else PackageDetails.PathType = GetPathType( &Ext[0] ); if ( (pMessage->pAuxPath) && (PackageDetails.PathType == DrwFilePath)) PackageDetails.pszPath = GetPath( pMessage->pAuxPath ); else PackageDetails.pszPath = GetPath( p ); PackageDetails.pszIconPath = GetPath( p ); if ( pMessage->pSetupCommand ) PackageDetails.pszSetupCommand = GetPath( pMessage->pSetupCommand ); PackageDetails.dwActFlags = pMessage->ActFlags; PackageDetails.pszPackageName = MakePackageName( &PackageName[0] ); PackageDetails.pszProductName = MakePackageName( &Name[0] ); PackageDetails.Platform = CSPlatform; if (pLocale ) PackageDetails.Locale = *pLocale; else PackageDetails.Locale = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), SORT_DEFAULT ); if ( pMajor ) PackageDetails.dwVersionHi = *pMajor; else PackageDetails.dwVersionHi = 0; if ( pMinor ) PackageDetails.dwVersionLo = *pMinor; else PackageDetails.dwVersionLo = 0; PackageDetails.cApps = 0; PackageDetails.pAppDetail = 0; // set the package details. pPackageEntry->SetPackageDetail( &PackageDetails ); // store the original name so that we can dump it. pPackageEntry->SetOriginalName( ServerName ); // Add this into the package dictionary. pMessage->pPackageDict->Insert( pPackageEntry ); } // search for the app entry. The class entry needs to be entered // there. If there is no app id specified (appentry is null ) // get the app entry whose ID is 0. All classes that do not have // an app id specified, will go into this bucket. Finally we will // assign an appid to it and enter into the class store. if ( !pAppid ) { // There is no appid. Enter the clsid entry in the null appid. if ( fUsage == 0 ) pPackageEntry->AddClsidToNullAppid( pClsidString ); else pPackageEntry->AddTypelibToNullAppid( pClsidString ); } else { pAppEntry = pPackageEntry->SearchAppEntry( pAppid ); if ( !pAppEntry ) { pAppEntry = new APP_ENTRY; pAppEntry->SetAppIDString( pAppid ); pPackageEntry->AddAppEntry( pAppEntry ); } pAppEntry->AddClsid( pClsidString ); } return 0; } CLASSPATHTYPE GetPathType( char * pExt ) /***************************************************************************** Purpose: Map the file extension to CLASSPATHTYPE In: pExt - File Extension to map Out: None. InOut: None. Return: CLASSPATHTYPE of the file extension. Remarks: olb is apparently an extension that implies "old type library"-whatever that is. If no standard mapping is found, a CLASSPATHTYPE of ExeNamePath is returned. *****************************************************************************/ { // extensions to map. static char * ExtArray[] = { ".dll", ".exe", ".cab", ".tlb", ".inf", ".olb" }; // CLASSPATHTYPEs to map the extensions to. static CLASSPATHTYPE PathType[] = { DllNamePath, ExeNamePath, CabFilePath, TlbNamePath, InfFilePath, TlbNamePath }; int index; int fFound = -1; for ( index = 0; index < sizeof( ExtArray ) / sizeof( char * ); ++index ) { if ( _stricmp( pExt, ExtArray[index] ) == 0 ) { fFound = index; break; } } if ( fFound != -1 ) { return PathType[ index ]; } else return ExeNamePath; } LPOLESTR GetPath( char * pPath ) /***************************************************************************** Purpose: Map a char * path to a wide character path In Arguments: pPath - Path to the file to translate to wide char. Out Arguments: None. InOut Arguments: None. Return Arguments: The translated file path. Remarks: *****************************************************************************/ { if ( pPath ) { LPOLESTR p = new OLECHAR[ (MAX_PATH+1) * 2 ]; mbstowcs( p, pPath, strlen(pPath)+1 ); return p; } return 0; } LPOLESTR GetSetupCommand( char * pSetupCommandLine ) /***************************************************************************** Purpose: Translate setup command line to wide char. In Arguments: Setup command line. Out Arguments: None. InOut Arguments: None. Return Arguments: The translated setup command line. Remarks: For now the setup command line is setup.exe *****************************************************************************/ { LPOLESTR p = new OLECHAR[ (MAX_PATH+1) * 2 ]; mbstowcs( p, "setup.exe", strlen("setup.exe")+1 ); return p; } LPOLESTR MakePackageName( char * pName ) /***************************************************************************** Purpose: Translate package name to wide char. In Arguments: package name to translate. Out Arguments: None. InOut Arguments: None. Return Arguments: translated command line Remarks: *****************************************************************************/ { LPOLESTR p = new OLECHAR[ (MAX_PATH+1) * 2 ]; mbstowcs( p, pName, strlen(pName)+1 ); return p; } LONG UpdateClassEntryFromAutoConvert( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry ) /***************************************************************************** Purpose: Update the classid entry in the data base with the autoconvert field. In Arguments: pMessage - Message block passing arguments between modules. pCLSID - pointer to class representing the registry key. pClassEntry - The class entry data structure to update. Out Arguments: None. InOut Arguments: None. Return Arguments: Status. Remarks: *****************************************************************************/ { LONG error; char Data[SIZEOF_STRINGIZED_CLSID]; DWORD SizeOfData = sizeof(Data)/sizeof(char); error = pCLSID->QueryValue( "AutoConvertTo", &Data[0], &SizeOfData ); if ( error == ERROR_SUCCESS ) { StringToCLSID( &Data[1], &pClassEntry->ClassAssociation.AutoConvertClsid ); } return error; } LONG UpdateClassEntryFromTreatAs( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry ) /***************************************************************************** Purpose: Update the class entry in the database with the Treatas key. In Arguments: pMessage - Message block passing arguments between modules. pCLSID - pointer to class representing the registry key. pClassEntry - The class entry data structure to update. Out Arguments: None. InOut Arguments: None. Return Arguments: Status. Remarks: *****************************************************************************/ { LONG error; char Data[SIZEOF_STRINGIZED_CLSID]; DWORD SizeOfData = sizeof(Data)/sizeof(char); error = pCLSID->QueryValue( "TreatAs", &Data[0], &SizeOfData ); if ( error == ERROR_SUCCESS ) { StringToCLSID( &Data[1], &pClassEntry->ClassAssociation.TreatAsClsid ); } return error; } LONG UpdateClassEntryFromAppID( MESSAGE * pMessage, BasicRegistry * pCLSID, CLASS_ENTRY * pClassEntry, char * pAppidBuffer ) /***************************************************************************** Purpose: Update the class entry in the database with the Appid key. In Arguments: pMessage - Message block passing arguments between modules. pCLSID - pointer to class representing the registry key. pClassEntry - The class entry data structure to update. Out Arguments: pAppIdBuffer- Buffer which receives the stringized appid value. InOut Arguments: None. Return Arguments: Status. Remarks: This routine looks for the presence of an appid on a clsid. The appid key will determine the appdetails structure that the clsid will go into. *****************************************************************************/ { LONG error; APP_ENTRY * pAppEntry = 0; DWORD SizeOfAppIDValue = SIZEOF_STRINGIZED_CLSID; char AppIDValue[ SIZEOF_STRINGIZED_CLSID ]; BOOL fNewEntry = 0; error = pCLSID->QueryValueEx( "AppID", &AppIDValue[0], &SizeOfAppIDValue ); if ( error == ERROR_SUCCESS ) { memcpy( pAppidBuffer, &AppIDValue[0], SIZEOF_STRINGIZED_CLSID ); return 1; } else return 0; } void SetCSPlatform( CSPLATFORM * pCSPlatform ) { // OSVERSIONINFO VersionInformation; // VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // GetVersionEx(&VersionInformation); // pCSPlatform->dwPlatformId = VersionInformation.dwPlatformId; // pCSPlatform->dwVersionHi = VersionInformation.dwMajorVersion; // pCSPlatform->dwVersionLo = VersionInformation.dwMinorVersion; #if 0 // this is not supported for Beta 1 pCSPlatform->dwPlatformId = -1; // any OS platform pCSPlatform->dwVersionHi = 0; pCSPlatform->dwVersionLo = 0; #else pCSPlatform->dwPlatformId = VER_PLATFORM_WIN32_NT; pCSPlatform->dwVersionHi = 5; pCSPlatform->dwVersionLo = 0; #endif // pCSPlatform->dwProcessorArch = PROCESSOR_ARCHITECTURE_INTEL; SYSTEM_INFO si; GetSystemInfo(&si); pCSPlatform->dwProcessorArch = si.wProcessorArchitecture; }