616 lines
19 KiB
C++
616 lines
19 KiB
C++
|
|
//+============================================================================
|
|
//
|
|
// 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 <windows.h>
|
|
#include <ole2.h>
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
|
|
// -------------
|
|
// 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 );
|
|
|
|
}
|