//+============================================================================ // // File: PrpSetup.cxx // // Purpose: This file builds to an executable which installs the // IProp DLL in the System(32) directory. This is provided // for the use of applications which re-distribute that DLL. // // Usage: PrpSetup [/u] [/c] // // The /u option indicates that an un-install should be performed. // The /c option indicates that console output is desired. // // History: 10/30/96 MikeHill Get "iprop.dl_" from the exe's resources. // //+============================================================================ // -------- // Includes // -------- #include #include #include #include // ------------- // Global values // ------------- // Name-related information for the DLL const LPTSTR tszResourceType = TEXT( "FILE" ); // Resource type const LPTSTR tszCompressedFilename = TEXT( "IPROP.DL_" ); // Temp file name const LPTSTR tszTargetFilename = TEXT( "IPROP.DLL" ); // Final file name // The reg key where we keep the DLL's install ref-count. const LPTSTR tszRegSharedDLLs = TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs" ); // Registration functions in IProp DLL. const LPTSTR tszRegistrationFunction = TEXT( "DllRegisterServer" ); const LPTSTR tszUnregistrationFunction = TEXT( "DllUnregisterServer" ); // ------------ // Return Codes // ------------ #define RETURN_SUCCESS 0 #define RETURN_ARGUMENT_ERROR 1 #define RETURN_COULDNT_CREATE_TEMP_FILE 2 #define RETURN_COULDNT_INSTALL_DLL 3 #define RETURN_COULDNT_DELETE_DLL 4 #define RETURN_COULDNT_REGISTER_DLL 5 #define RETURN_COULDNT_ACCESS_REGISTRY 6 #define RETURN_OUT_OF_MEMORY 7 #define RETURN_INTERNAL_ERROR 8 //+---------------------------------------------------------------------------- // // Function: Register // // Synopsis: This function registers or de-registers the IProp DLL. // // Inputs: [BOOL] fUninstall (in) // If true, call DllUnregisterServer, otherwise call // DllRegisterServer // // Returns: [HRESULT] // //+---------------------------------------------------------------------------- HRESULT Register( BOOL fUninstall ) { HRESULT hr; HINSTANCE hinst = NULL; // A function pointer for the registration function typedef HRESULT (STDAPICALLTYPE FNREGISTRATION)(); FNREGISTRATION *pfnRegistration = NULL; // Load the DLL hinst = LoadLibrary( tszTargetFilename ); if( NULL == hinst ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Exit; } // Get the registration function pfnRegistration = (FNREGISTRATION*) GetProcAddress( hinst, fUninstall ? tszUnregistrationFunction : tszRegistrationFunction ); if( NULL == pfnRegistration ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Exit; } // Register or De-register IProp. hr = (*pfnRegistration)(); if( FAILED(hr) ) goto Exit; // ---- // Exit // ---- Exit: if( NULL != hinst ) FreeLibrary( hinst ); return( hr ); } //+---------------------------------------------------------------------------- // // Function: main() // // Synopsis: This program loads/removes IProp.DLL into/from the // System directory. A ref-count of the number of installs // of this DLL is kept in the Registry. The DLL is // also registered/deregistered. // //+---------------------------------------------------------------------------- HRESULT __cdecl main(int argc, char **argv) { // File names and paths TCHAR tszSystemPath[_MAX_PATH+1]; // Path to System(32) directory TCHAR tszTempFilename[_MAX_PATH+1]; // Used by VerInstallFile() UINT cbTempFilename = sizeof( tszTempFilename ) - sizeof(TCHAR); TCHAR tszTargetPathAndFile[_MAX_PATH+1]; // E.g. "C:\Win\System32\IProp.dll" TCHAR tszTempPath[_MAX_PATH+1]; // E.g. "C:\Temp\" // E.g. "C:\Temp\iprop.dl_" TCHAR tszTempPathAndFile[_MAX_PATH+1] = {""}; // Index into argv int nArgIndex; // User-settable flags. BOOL fConsole = FALSE; BOOL fInstall = FALSE; BOOL fUninstall = FALSE; // Registry data HKEY hkey; DWORD dwRegValueType; DWORD dwRefCount; DWORD cbRefCountSize = sizeof( dwRefCount ); DWORD dwDisposition; // Handles for reading "iprop.dl_" out of the resources HRSRC hrsrcIProp = NULL; // Handle to the "iprop.dl_" resource. HGLOBAL hglobIProp = NULL; // Handle to the "iprop.dl_" data. LPVOID lpvIProp = NULL; // Pointer to the "iprop.dl_" data. HMODULE hmodCurrent = NULL; // Our module handle HANDLE hfileIProp = NULL; // Handle to "%TEMP%\iprop.dl_" file // Misc. HRESULT hr = S_OK; INT nReturnCode = RETURN_INTERNAL_ERROR; // ----------------- // Process the Input // ----------------- for( nArgIndex = 1; nArgIndex < argc; nArgIndex++ ) { if( // Is this argument an option? ( argv[nArgIndex][0] == '/' || argv[nArgIndex][0] == '-' ) && // and is it more than one character? argv[nArgIndex][1] != '\0' && // and is it exactly two characters? argv[nArgIndex][2] == '\0' ) { // See if it's an argument we recognize. switch( argv[nArgIndex][1] ) { // Installation case 'i': case 'I': fInstall = TRUE; break; // Uninstall case 'u': case 'U': fUninstall = TRUE; break; // Console output case 'c': case 'C': fConsole = TRUE; break; } } // if( ( argv[nArgIndex][0] == '/' ... } // for( nArgIndex = 1; nArgIndex < argc; nArgIndex++ ) // Did we get an illegal command-line combination? if( fInstall && fUninstall ) { nReturnCode = RETURN_ARGUMENT_ERROR; goto Exit; } // Did the user fail to tell us what to do? If so, // display usage information. if( !fInstall && !fUninstall ) { _tprintf( TEXT("\n") ); _tprintf( TEXT(" Installation program for the Microsoft OLE Property Set Implementation\n") ); _tprintf( TEXT(" Usage: IProp [/i | /u] [/c]\n") ); _tprintf( TEXT(" Options: /i => Install\n") TEXT(" /u => Uninstall\n") TEXT(" /c => Console output\n") ); _tprintf( TEXT(" Examples: IProp /i\n") TEXT(" IProp /u /c\n") ); nReturnCode = RETURN_SUCCESS; goto Exit; } // ---------- // Initialize // ---------- // Find the target installation directory. if( GetSystemDirectory( tszSystemPath, sizeof(tszSystemPath) - sizeof(TCHAR)) == 0 ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_COULDNT_INSTALL_DLL; goto Exit; } // Determine the target's total path & filename. _tcscpy( tszTargetPathAndFile, tszSystemPath ); _tcscat( tszTargetPathAndFile, TEXT("\\") ); _tcscat( tszTargetPathAndFile, tszTargetFilename ); // Generate the filename we'll use for the compressed // IProp DLL file ("iprop.dl_"); get the temp directory // and post-pend a filename to it. if( !GetTempPath( sizeof(tszTempPath), tszTempPath )) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_COULDNT_CREATE_TEMP_FILE; goto Exit; } _tcscpy( tszTempPathAndFile, tszTempPath ); _tcscat( tszTempPathAndFile, tszCompressedFilename ); // Open the registry key that holds this DLL's ref-count. hr = RegCreateKeyEx( HKEY_LOCAL_MACHINE, // Open key tszRegSharedDLLs, // Name of subkey 0L, // Reserved NULL, // Class 0, // Options KEY_ALL_ACCESS, // SAM desired NULL, // Security attributes &hkey, // Result &dwDisposition ); // "Created" or "Opened" if( ERROR_SUCCESS != hr ) { hr = HRESULT_FROM_WIN32( hr ); nReturnCode = RETURN_COULDNT_ACCESS_REGISTRY; goto Exit; } // Attempt to read our ref-count hr = RegQueryValueEx( hkey, // Open key tszTargetPathAndFile, // Value name NULL, // Reserved &dwRegValueType, // Out: value type (LPBYTE) &dwRefCount, // Out: value &cbRefCountSize ); // In: buf size, out: data size if( ERROR_FILE_NOT_FOUND == hr ) // This entry didn't already exist. dwRefCount = 0; else if( ERROR_SUCCESS != hr ) { // There was a real error during the Query attempt. hr = HRESULT_FROM_WIN32(hr); nReturnCode = RETURN_COULDNT_ACCESS_REGISTRY; goto Exit; } else if ( REG_DWORD != dwRegValueType ) { // This is an invalid entry. We won't abort, we'll just // re-initialize it to zero, and at the end we'll overwrite // whatever was already there. dwRefCount = 0; } if( fConsole ) { if( fUninstall ) _tprintf ( TEXT("Uninstalling \"%s\"\n"), tszTargetPathAndFile ); else _tprintf( TEXT("Installing \"%s\"\n"), tszTargetPathAndFile ); } // ------------------------------ // Installation or Uninstallation // ------------------------------ if( fUninstall ) { // We're doing an Un-Install // Should we actually delete it? We haven't done a dec-ref yet, // so in the normal case, on the last delete, the RefCount will // currently be 1. if( dwRefCount <= 1 ) { // Yes - we need to do a delete. First unregister the IProp // DLL. If there's an error we'll abort. So we might leave // an unused file on the machine, but that's better than // possibly deleting a file that is still in use by another // app. hr = Register( fUninstall ); if( FAILED(hr) ) { nReturnCode = RETURN_COULDNT_REGISTER_DLL; goto Exit; } // And delete the file if( !DeleteFile( tszTargetPathAndFile ) && ERROR_FILE_NOT_FOUND != GetLastError() ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_COULDNT_DELETE_DLL; goto Exit; } if( fConsole ) _tprintf( TEXT("Removed IProp.DLL\n") ); // Zero-out the ref count. We'll delete it from the // registry later dwRefCount = 0; } else { // We don't need to delete it, just dec-ref it. dwRefCount--; if( fConsole ) _tprintf( TEXT("IProp.DLL not removed (reference count is now %d)\n"), dwRefCount ); } } // if( fUninstall ) else { // We're doing an Install DWORD dwSize; // Size of "iprop.dl_". DWORD cbWritten = 0; if( fConsole ) _tprintf( TEXT("Extracting \"%s\"\n"), tszTempPathAndFile ); // Get our module handle; hmodCurrent = GetModuleHandle( NULL ); if( NULL == hmodCurrent ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_OUT_OF_MEMORY; goto Exit; } // Get the resource which is actually the compressed IProp DLL hrsrcIProp = FindResource( hmodCurrent, tszCompressedFilename, tszResourceType ); if( NULL == hrsrcIProp ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_OUT_OF_MEMORY; goto Exit; } // Get the size of "iprop.dl_" dwSize = SizeofResource( hmodCurrent, hrsrcIProp ); if( 0 == dwSize ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_OUT_OF_MEMORY; goto Exit; } // Get "iprop.dl_" into a memory buffer. hglobIProp = LoadResource( hmodCurrent, hrsrcIProp ); if( NULL == hglobIProp ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_OUT_OF_MEMORY; goto Exit; } // Get a pointer to the "iprop.dl_" data. lpvIProp = LockResource( hglobIProp ); if( NULL == lpvIProp ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_OUT_OF_MEMORY; goto Exit; } // Create a temporary file, which will be "iprop.dl_" hfileIProp = CreateFile( tszTempPathAndFile, // E.g. "C:\Temp\iprop.dl_" GENERIC_READ | GENERIC_WRITE, // Requested access FILE_SHARE_READ, // Sharing mode NULL, // No security attributes CREATE_ALWAYS, // Overwrite existing FILE_ATTRIBUTE_NORMAL, // Default attributes NULL ); // No template file if( INVALID_HANDLE_VALUE == hfileIProp ) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_COULDNT_CREATE_TEMP_FILE; goto Exit; } // Write the contents of "iprop.dl_" if( !WriteFile( hfileIProp, lpvIProp, dwSize, &cbWritten, NULL )) { hr = HRESULT_FROM_WIN32( GetLastError() ); nReturnCode = RETURN_COULDNT_CREATE_TEMP_FILE; goto Exit; } // We must close the file, or VerInstallFile won't open it. CloseHandle( hfileIProp ); hfileIProp = NULL; // Install the file. hr = VerInstallFile( 0, // Flags tszCompressedFilename, // Source filename tszTargetFilename, // Dest filename tszTempPath, // Source location tszSystemPath, // Target location tszSystemPath, // Location of old version tszTempFilename, // Out: name of temp file &cbTempFilename); // In: size of buf, Out: name // If VerInstallFile left a temporary file, delete it now. if( hr & VIF_TEMPFILE ) { TCHAR tszDeleteTempFile[_MAX_PATH+1]; _tcscpy( tszDeleteTempFile, tszSystemPath ); _tcscat( tszDeleteTempFile, TEXT("\\") ); _tcscat( tszDeleteTempFile, tszTempFilename ); DeleteFile( tszDeleteTempFile ); } // If the file was installed successfully, register it. if( 0 == hr ) { hr = Register( fUninstall ); if( FAILED(hr) ) { nReturnCode = RETURN_COULDNT_REGISTER_DLL; goto Exit; } } // If the error wasn't "newer version exists", then we // have a fatal error. else if( 0 == (hr & VIF_SRCOLD) ) { nReturnCode = RETURN_COULDNT_INSTALL_DLL; goto Exit; } else if( fConsole ) { _tprintf( TEXT("A newer version of the file is already installed\n") ); } // Do an add-ref. dwRefCount++; } // if( fUninstall ) ... else // ------------------ // Save the Ref-Count // ------------------ // Did we actually delete the DLL? if( 0 == dwRefCount ) { // Delete our entry from the SharedDlls entry hr = RegDeleteValue( hkey, tszTargetPathAndFile ); if( ERROR_FILE_NOT_FOUND == hr ) hr = ERROR_SUCCESS; else if( ERROR_SUCCESS != hr ) { hr = HRESULT_FROM_WIN32(hr); nReturnCode = RETURN_COULDNT_ACCESS_REGISTRY; goto Exit; } } else { // Otherwise, put the new ref-count in the registry. hr = RegSetValueEx( hkey, // Open key tszTargetPathAndFile, // Value name 0, // Reserved REG_DWORD, // Value type (LPBYTE) &dwRefCount, // Value buffer sizeof( dwRefCount )); // Size of value if( ERROR_SUCCESS != hr ) { hr = HRESULT_FROM_WIN32(hr); nReturnCode = RETURN_COULDNT_ACCESS_REGISTRY; goto Exit; } } // if( 0 == dwRefCount ) ... else // ---- // Exit // ---- Exit: if( fConsole ) { // We only succeeded if hr is 0; VerInstallFile might return // a bitmapped error that doesn't look like an HRESULT error // code. if( 0 == hr ) _tprintf( TEXT("%s successful\n"), fUninstall ? TEXT("Uninstall") : TEXT("Install") ); else _tprintf( TEXT("%s failed. Return code = %d (%08X)\n"), nReturnCode, fUninstall ? TEXT("Uninstall") : TEXT("Install"), hr ); } // Remove the temporary file (we initialized this to "", so this // call should always return success or file-not-found). DeleteFile( tszTempPathAndFile ); // Free all the handles we've used. if( hfileIProp ) CloseHandle( hfileIProp ); if( lpvIProp ) GlobalUnlock( lpvIProp ); return( nReturnCode ); }