windows-nt/Source/XPSP1/NT/com/ole32/cs/csadmin/pcs/pcs.cxx
2020-09-26 16:20:57 +08:00

890 lines
24 KiB
C++

/******************************************************************************
* 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;
}