windows-nt/Source/XPSP1/NT/com/ole32/stg/props/iprop/dllmain.cxx
2020-09-26 16:20:57 +08:00

533 lines
18 KiB
C++

//+============================================================================
//
// File: dllmain.cxx
//
// Purpose: This file provides the registration and deregistration
// functions for the IProp DLL: DllRegisterServer and
// DllUnregisterServer. These two functions register/
// deregister the property set marshaling code:
// IPropertySetStorage, IPropertyStorage, IEnumSTATPROPSETSTG,
// and IEnumSTATPROPSTG. Note that this registration is
// different from the typical server registration in that
// it only registers the marshaling code, it does not
// register an instantiable COM server. Also, no registration
// takes place if OLE32 is already registered to perform
// this marshaling.
//
// The actual DllRegisterServer and DllUnregisterServer
// implementations are at the end of this file. First,
// several helper functions are defined.
//
//+============================================================================
// --------
// Includes
// --------
#include <pch.cxx>
#include <tchar.h>
// The following is from "olectl.h". That file couldn't simply
// be included, however, because it isn't compatible with the
// special objidl.h and wtypes.h used by IProp DLL.
#define SELFREG_E_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x0200)
#define SELFREG_E_LAST MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x020F)
#define SELFREG_S_FIRST MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_ITF, 0x0200)
#define SELFREG_S_LAST MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_ITF, 0x020F)
#define SELFREG_E_TYPELIB (SELFREG_E_FIRST+0)
#define SELFREG_E_CLASS (SELFREG_E_FIRST+1)
// -------
// Globals
// -------
// Important DLL names.
const LPTSTR tszNameDll = TEXT( "IProp.dll" );
// Registry entry descriptions
const LPTSTR tszOle32PSFactoryClsid = TEXT( "{00000320-0000-0000-C000-000000000046}" );
const LPTSTR tszNamePropertySetStorage = TEXT( "IPropertySetStorage" );
const LPTSTR tszNamePropertyStorage = TEXT( "IPropertyStorage" );
const LPTSTR tszNameIEnumSTATPROPSETSTG = TEXT( "IEnumSTATPROPSETSTG" );
const LPTSTR tszNameIEnumSTATPROPSTG = TEXT( "IEnumSTATPROPSTG" );
// GUIDs in Registry format
const LPTSTR tszGuidPropertySetStorage = TEXT( "{0000013A-0000-0000-C000-000000000046}" );
const LPTSTR tszGuidPropertyStorage = TEXT( "{00000138-0000-0000-C000-000000000046}" );
const LPTSTR tszGuidIEnumSTATPROPSETSTG = TEXT( "{0000013B-0000-0000-C000-000000000046}" );
const LPTSTR tszGuidIEnumSTATPROPSTG = TEXT( "{00000139-0000-0000-C000-000000000046}" );
//+----------------------------------------------------------------------------
//
// Function: UpdateKeyAndSubKey
//
// Synopsis: This function either creates or deletes first
// a key and un-named value under HKEY_CLASSES_ROOT,
// then a sub-key and associated un-named value. The
// caller indicates whether a create or delete should occur.
//
// However, the caller may specify that nothing be done
// if the sub-key exists and already has a specific
// un-named REG_SZ value.
//
// Inputs: [const LPTSTR] tszMainKey (in)
// The name of the key under HKEY_CLASSES_ROOT.
// [const LPTSTR] tszMainKeyDescription (in)
// The un-named REG_SZ value under this key (not necessary
// if fDelete is true).
// [const LPTSTR] tszSubKey (in)
// The name of the key under the first key.
// [const LPTSTR] tszSubKeyDescription (in)
// The un-named REG_SZ value to write under this sub-key
// (not necessary if fDelete is true).
// [const LPTSTR] tszSubKeyCheck (in)
// If non-NULL, and the subkey already exists, see if
// this string matches an un-named REG_SZ value in
// the sub-key. If so, abort the operation and return
// ERROR_ALREADY_EXISTS.
// [BOOL] fDelete
// If TRUE, delete the keys, if FALSE, create them.
// But this is ignored if tszSubKeyCheck matches
// (in which case nothing happens).
//
// Returns: [long] A GetLastError value.
//
//+----------------------------------------------------------------------------
long
UpdateKeyAndSubKey( const LPTSTR tszMainKey,
const LPTSTR tszMainKeyDescription,
const LPTSTR tszSubKey,
const LPTSTR tszSubKeyDescription,
const LPTSTR tszSubKeyCheck,
BOOL fDelete )
{
// ------
// Locals
// ------
long lResult = ERROR_SUCCESS;
DWORD dwDisposition;
HKEY hkeyMain = NULL; // E.g. "HKEY_CLASSES_ROOT\\CLSID\\{.....}"
HKEY hkeySub = NULL; // E.g. ..."InProcServer32"
// -------------
// Open the keys
// -------------
// Are we opening for delete?
if( fDelete )
{
// Yes - we're deleting. We'll just attempt to do an Open.
dwDisposition = REG_OPENED_EXISTING_KEY;
lResult = RegOpenKeyEx( HKEY_CLASSES_ROOT,
tszMainKey,
0L,
KEY_ALL_ACCESS,
&hkeyMain );
if( ERROR_SUCCESS == lResult )
{
lResult = RegOpenKeyEx( hkeyMain,
tszSubKey,
0L,
KEY_ALL_ACCESS,
&hkeySub );
}
if( ERROR_FILE_NOT_FOUND == lResult )
lResult = ERROR_SUCCESS;
else if( ERROR_SUCCESS != lResult )
goto Exit;
} // if( fDelete )
else
{
// We're not opening for delete. So we'll use RegCreateKey,
// which does an Open if the key exists, and a Create otherwise.
lResult = RegCreateKeyEx( HKEY_CLASSES_ROOT,
tszMainKey,
0L,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hkeyMain,
&dwDisposition );
if( lResult != ERROR_SUCCESS ) goto Exit;
// Open the sub-key.
lResult = RegCreateKeyEx( hkeyMain,
tszSubKey,
0L,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hkeySub,
&dwDisposition );
if( ERROR_SUCCESS != lResult ) goto Exit;
} // if( fDelete ) ... else
// --------------------------
// Do we need to do anything?
// --------------------------
// Does it look like we might not need to do anything?
if( NULL != tszSubKeyCheck // The caller said to check first
&&
NULL != hkeySub // We Created or Opened a sub-key
&& // Specifically, it was an Open.
REG_OPENED_EXISTING_KEY == dwDisposition )
{
// Yes - we need to see if the key already contains
// tszSubKeyCheck. If so, then we're done.
DWORD dwType = 0;
TCHAR tszData[ MAX_PATH ];
DWORD dwDataSize = sizeof( tszData );
// Is there an un-named value in this key?
lResult = RegQueryValueEx( hkeySub,
NULL, // Name
NULL, // Reserved
&dwType, // E.g. REG_SZ
(LPBYTE) tszData,// Return value
&dwDataSize ); // In: size of buf. Out: size of value
// We should have gotten a success-code or a not-extant code
if( ERROR_SUCCESS != lResult
&&
ERROR_FILE_NOT_FOUND != lResult )
{
goto Exit;
}
// If we got an extant SZ value that matches tszSubKeyCheck,
// then there's nothing we need do.
if( ERROR_SUCCESS == lResult
&&
REG_SZ == dwType
&&
!_tcsicmp( tszData, tszSubKeyCheck )
)
{
lResult = ERROR_ALREADY_EXISTS;
goto Exit;
}
} // if( REG_OPENED_EXISTING_KEY == dwDisposition ...
// --------------------------
// Delete keys, or set values
// --------------------------
if( fDelete )
{
// Reset the result code, since the code below may not set it.
lResult = ERROR_SUCCESS;
// We're doing a delete. First, delete the sub-key, which
// will delete any values. If there was no subkey, hkeySub will
// be NULL.
if( NULL != hkeySub )
{
CloseHandle( hkeySub );
hkeySub = NULL;
lResult = RegDeleteKey( hkeyMain,
tszSubKey );
if( ERROR_SUCCESS != lResult ) goto Exit;
}
// Second, delete the main key
if( NULL != hkeyMain )
{
CloseHandle( hkeyMain );
hkeyMain = NULL;
lResult = RegDeleteKey( HKEY_CLASSES_ROOT,
tszMainKey );
if( ERROR_SUCCESS != lResult ) goto Exit;
}
} // if( fDelete )
else
{
// We're adding to the Registry. The two keys are now
// created & opened, so we can add the REG_SZ values.
// The REG_SZ value for the main key.
lResult = RegSetValueEx(hkeyMain,
NULL,
0L,
REG_SZ,
(const BYTE *) tszMainKeyDescription,
sizeof(TCHAR) * (1 + _tcslen(tszMainKeyDescription) ));
if( ERROR_SUCCESS != lResult ) goto Exit;
// The REG_SZ value for the sub-key.
lResult = RegSetValueEx(hkeySub,
NULL, 0L,
REG_SZ,
(const BYTE *) tszSubKeyDescription,
sizeof(TCHAR) * (1 + _tcslen(tszSubKeyDescription) ));
if( ERROR_SUCCESS != lResult ) goto Exit;
} // if( fDelete ) ... else
// ----
// Exit
// ----
Exit:
if( NULL != hkeySub )
CloseHandle( hkeySub );
if( NULL != hkeyMain )
CloseHandle( hkeyMain );
return( lResult );
} // WriteKeyAndSubKey()
//+----------------------------------------------------------------------------
//
// Function: RegisterForMarshaling
//
// Synopsis: This function takes the GUID ane name of an interface
// for which MIDL-generated marshaling code exists in the
// caller-specified DLL. First we try to update the
// CLSID entries, but we'll fail this if the entries already
// exist and reference OLE32 (OLE32 has better marshaling
// code). If this doesn't fail, then we'll update the
// Interface entries.
//
// The caller specifies if this "update" of the registry
// is a write or a delete. This this routine can be used
// in either a registration or a de-registration.
//
// Inputs: [const LPTSTR] tszGuid (in)
// The GUID in registery format ("{...-...-...}")
// [const LPTSTR] tszName (in)
// The name of the interface
// [const LPTSTR] tszDllPath (in)
// The complete path and filename of the DLL which contains
// the marshaling code.
// [BOOL] fDelete (in)
// Determines if we add to the Registry or delete from it.
//
// Returns: [long] a GetLastError() value
//
//+----------------------------------------------------------------------------
long
RegisterForMarshaling( const LPTSTR tszGuid,
const LPTSTR tszName,
const LPTSTR tszDllPath,
BOOL fDelete )
{
// ------
// Locals
// ------
long lResult;
TCHAR tszMainKey[ MAX_PATH ];
// -----------------------------------
// Update HKEY_CLASSES_ROOT\Interfaces
// -----------------------------------
// Calculate the key name name
_tcscpy( tszMainKey, TEXT( "Interface\\" ));
_tcscat( tszMainKey, tszGuid );
// Update the registry, but only if there isn't a current
// entry pointing to OLE32's proxy/stub factory.
lResult = UpdateKeyAndSubKey( tszMainKey,
tszName,
TEXT( "ProxyStubClsid32" ),
tszGuid,
tszOle32PSFactoryClsid,
fDelete );
if( ERROR_SUCCESS != lResult ) goto Exit;
// ------------------------------
// Update HKEY_CLASSES_ROOT\CLSID
// ------------------------------
// Calculate the name.
_tcscpy( tszMainKey, TEXT( "CLSID\\" ));
_tcscat( tszMainKey, tszGuid );
// Update the entries. This will add the path (if !fDelete) or remove
// the registry entry (if fDelete) regardless of the current state
// of the key; if we weren't supposed to remove it, the previous
// call to UpdateKeyAndSubKey would have returned an error.
lResult = UpdateKeyAndSubKey( tszMainKey,
tszName,
TEXT( "InprocServer32" ),
tszDllPath,
NULL, // Add/delete, regardless of what exists
fDelete );
if( ERROR_SUCCESS != lResult ) goto Exit;
// ----
// Exit
// ----
Exit:
if( ERROR_ALREADY_EXISTS == lResult )
{
propDbg(( DEB_WARN, "IProp DLL UpdateKeyAndSubKey: Entry already exists\n" ));
lResult = ERROR_SUCCESS;
}
return( lResult );
} // RegisterForMarshaling()
//+----------------------------------------------------------------------------
//
// Function: RegisterServer
//
// Synopsis: This routine can be used with both DllRegisterServer and
// DllUnregisterServer. It adds/deletes IPropertySetStorage
// IPropertyStorage, IEnumSTATPROPSETSTG, and IEnumSTATPROPSTG.
//
// Inputs: [BOOL] fDelete (in)
// Indicates whether the registry entries should be added
// or removed.
//
// Returns: [HRESULT]
//
//+----------------------------------------------------------------------------
STDAPI RegisterServer( BOOL fDelete )
{
// ------
// Locals
// ------
LONG lResult;
// -----
// Begin
// -----
// Register IPropertySetStorage
lResult = RegisterForMarshaling( tszGuidPropertySetStorage,
tszNamePropertySetStorage,
tszNameDll,
fDelete );
if( ERROR_SUCCESS != lResult ) goto Exit;
// Register IPropertyStorage
lResult = RegisterForMarshaling( tszGuidPropertyStorage,
tszNamePropertyStorage,
tszNameDll,
fDelete );
if( ERROR_SUCCESS != lResult ) goto Exit;
// Register IEnumSTATPROPSETSTG
lResult = RegisterForMarshaling( tszGuidIEnumSTATPROPSETSTG,
tszNameIEnumSTATPROPSETSTG,
tszNameDll,
fDelete );
if( ERROR_SUCCESS != lResult ) goto Exit;
// Register IEnumSTATPROPSTG
lResult = RegisterForMarshaling( tszGuidIEnumSTATPROPSTG,
tszNameIEnumSTATPROPSTG,
tszNameDll,
fDelete );
if( ERROR_SUCCESS != lResult ) goto Exit;
// ----
// Exit
// ----
Exit:
if( ERROR_SUCCESS != lResult )
{
propDbg(( DEB_ERROR, "IProp DLL RegisterServer failed (%lu)\n", lResult ));
return( SELFREG_E_CLASS );
}
else
{
return( S_OK );
}
} // RegisterServer()
//+----------------------------------------------------------------------------
//
// Function: DllRegisterServer & DllUnregisterServer
//
// Synopsis: These routines are the standard DLL registration entry
// points for a self-registering in-proc COM server. They
// are used to register the property set marshaling code.
// These routines are called, for example,
// by a setup program during installation and de-installation,
// respectively.
//
//+----------------------------------------------------------------------------
STDAPI DllRegisterServer()
{
return( RegisterServer( FALSE ));
}
STDAPI DllUnregisterServer()
{
return( RegisterServer( TRUE ));
}
void InitializeDebugging();
void UnInitializeDebugging();
BOOL WINAPI
DllMain( HANDLE hinst, DWORD dwReason, LPVOID lpv )
{
#if DBG == 1
{
if( DLL_PROCESS_ATTACH == dwReason )
InitializeDebugging();
else if( DLL_PROCESS_DETACH == dwReason )
UnInitializeDebugging();
}
#endif // #if DBG == 1
return( TRUE );
}