//+============================================================================ // // 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 #include // 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 ); }