|
|
#define STRICT
#define LEAN_AND_MEAN
#include <windows.h>
#include <setupapi.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <mbstring.h>
#include "miginf.h"
#define DIRECTORYKEY "SOFTWARE\\Microsoft\\DevStudio\\5.0\\Products\\Microsoft Visual C++"
#define DIRECTORYVALUE "ProductDir"
#define DIR_95SPECIFIC "\\bin\\win95"
#define FILE_PVIEW "pview.exe"
#define MESSAGE \
"PVIEW.EXE has been found in one or more directories outside of your Visual C++ 5.0" \ " installation directory. These copies will not be updated with the NT version." \
#define MESSAGE_SECTION "Microsoft\\Visual C++ 5.0\\Process Viewer"
#define SIZENEEDED 100000L
#define CP_USASCII 1252
//
// 9x side globals.
//
const CHAR g_ProductId[] = {"Microsoft Visual C++ 5.0"}; UINT g_DllVersion = 1; INT g_CodePageArray[] = {CP_USASCII,-1}; CHAR g_ExeNamesBuffer[] = {"pview95.exe\0""\0"};
//
// Nt side globals.
//
//
// Uncomment next line to get popups.
//
//#define MYDEBUG
#ifdef MYDEBUG
# define INFO(x) (MessageBoxA(NULL,(x),"PVIEW Sample Migration Dll",MB_OK | MB_ICONINFORMATION))
#else
# define INFO(x)
#endif
static BOOL PathIsInPath( IN PCSTR SubPath, IN PCSTR ParentPath ) { DWORD parentLength; BOOL rInPath;
//
// This function assumes both parameters are non-NULL.
//
assert(SubPath); assert(ParentPath); parentLength = _mbslen(ParentPath);
//
// A path is considered "in" another path if the path is in the ParentPath
// or a subdirectory of it.
//
rInPath = !_mbsnicmp(SubPath,ParentPath,parentLength);
if (rInPath) { rInPath = SubPath[parentLength] == 0 || SubPath[parentLength] == '\\'; }
return rInPath;
}
static PSTR GetPviewDirectoryNt ( VOID ) { HKEY softwareKey; LONG rc; LONG valueType; LONG sizeNeeded; PSTR rString = NULL;
//
// First, open the key.
//
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, DIRECTORYKEY, 0, KEY_READ, &softwareKey );
if (rc == ERROR_SUCCESS) { //
// Determine how large of a buffer to allocate.
//
rc = RegQueryValueEx( softwareKey, DIRECTORYVALUE, 0, &valueType, NULL, &sizeNeeded );
//
// Allocate enough space for the registry path, with the additional
// subpath to Visual C++ 5.0's win 95 specific binaries.
//
rString = LocalAlloc(0,sizeNeeded + lstrlen(DIR_95SPECIFIC) + 1); } if (rc == ERROR_SUCCESS && rString != NULL) { //
// Read in the buffer.
//
rc = RegQueryValueEx( softwareKey, DIRECTORYVALUE, 0, &valueType, (PBYTE) rString, &sizeNeeded );
if (rc == ERROR_SUCCESS) { if (valueType != REG_SZ) { rc = ERROR_INVALID_DATATYPE; } } }
//
// If we didn't complete successfully, set the last error, and free the
// return string if it was allocated.
//
if (rc != ERROR_SUCCESS) { SetLastError(rc);
if (rString) { LocalFree(rString); rString = NULL; } }
return rString; }
static PSTR GetPviewDirectory9x ( VOID ) { HKEY softwareKey; LONG rc; LONG valueType; LONG sizeNeeded; PSTR rString = NULL;
//
// First, open the key.
//
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, DIRECTORYKEY, 0, KEY_READ, &softwareKey );
if (rc == ERROR_SUCCESS) { //
// Determine how large of a buffer to allocate.
//
rc = RegQueryValueEx( softwareKey, DIRECTORYVALUE, 0, &valueType, NULL, &sizeNeeded );
//
// Allocate enough space for the registry path, with the additional
// subpath to Visual C++ 5.0's win 95 specific binaries.
//
rString = LocalAlloc(0,sizeNeeded + lstrlen(DIR_95SPECIFIC) + 1); } if (rc == ERROR_SUCCESS && rString != NULL) { //
// Read in the buffer.
//
rc = RegQueryValueEx( softwareKey, DIRECTORYVALUE, 0, &valueType, (PBYTE) rString, &sizeNeeded );
if (rc == ERROR_SUCCESS) { if (valueType == REG_SZ) {
//
// We have successfully read in the value of the installation
// directory into rString. Now, all we need to do is tack on
// the win 95 specific portion that we care about.
//
lstrcat(rString,DIR_95SPECIFIC);
} else { rc = ERROR_INVALID_DATATYPE; } } }
//
// If we didn't complete successfully, set the last error, and free the
// return string if it was allocated.
//
if (rc != ERROR_SUCCESS) { SetLastError(rc);
if (rString) { LocalFree(rString); rString = NULL; } }
return rString; }
static LONG CheckForInstalledComponents ( VOID ) { BOOL rc; HKEY softwareKey;
//
// Attempt to open the key.
//
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, DIRECTORYKEY, 0, KEY_READ, &softwareKey );
//
// If the key exists, then assume that Microsoft Visual C++ 5.0 is installed.
//
RegCloseKey(softwareKey);
return rc; }
BOOL WINAPI DllMain ( IN HANDLE Instance, IN ULONG Reason, IN LPVOID Reserved ) {
switch (Reason) {
case DLL_PROCESS_ATTACH: break;
case DLL_PROCESS_DETACH: //
// Ensure that the MigInf structure is cleaned up before unloading this DLL.
//
MigInf_CleanUp(); break; }
return TRUE; }
LONG CALLBACK QueryVersion ( OUT LPCSTR * ProductId, OUT LPUINT DllVersion, OUT LPINT * CodePageArray, OPTIONAL OUT LPCSTR * ExeNamesBuf, OPTIONAL LPVOID Reserved ) {
LONG rc;
INFO("Entering QueryVersion.");
assert(ProductId); assert(DllVersion); assert(CodePageArray); assert(ExeNamesBuf);
//
// Setup is calling us to query our version information and to identify if
// we need processing. We always need to provide the product ID and the
// DLL version.
//
*ProductId = g_ProductId; *DllVersion = g_DllVersion; //
// Check to see if there is anything to do.
//
if (CheckForInstalledComponents() == ERROR_SUCCESS) { //
// There are installed components. Return the information Setup is
// asking for.
//
*CodePageArray = g_CodePageArray; // Use the CP_ACP code page for conversion to unicode,
*ExeNamesBuf = g_ExeNamesBuffer; //
// Since there is work to do, return EXIT_SUCCESS. This informs Setup
// that this dll does require processing during migration.
//
rc = ERROR_SUCCESS; } else { rc = ERROR_NOT_INSTALLED; }
return rc;
}
LONG CALLBACK Initialize9x ( IN LPCSTR WorkingDirectory, IN LPCSTR SourceDirectories, LPVOID Reserved ) { LONG rc;
//
// Setup guarantees that the source directories parameter is valid.
//
assert(SourceDirectories);
INFO("Entering Initialize9x.");
//
// Initialize the MigInf structure.
//
if (!MigInf_Initialize()) { rc = GetLastError(); } else { rc = ERROR_SUCCESS; }
return rc; }
LONG CALLBACK MigrateUser9x ( IN HWND ParentWnd, IN LPCSTR UnattendFile, IN HKEY UserRegKey, IN LPCSTR UserName, LPVOID Reserved ) { //
// Setup guarantees that UnattendFile,UserRegKey will be non-NULL
//
assert(UnattendFile); assert(UserRegKey); INFO("Entering MigrateUser9x.");
//
// Nothing to do per user, so, return ERROR_NO_MORE_FILES
//
return ERROR_NOT_INSTALLED; }
LONG CALLBACK MigrateSystem9x ( IN HWND ParentWnd, IN LPCSTR UnattendFile, LPVOID Reserved ) { LONG rc = EXIT_SUCCESS; PSTR visualCppDirectory = NULL; MIGINFSECTIONENUM sectionEnum; BOOL firstMessage = TRUE; PCSTR messageSection = NULL;
//
// Setup guarantees that UnattendFile will be non-NULL.
//
assert(UnattendFile);
INFO("Entering MigrateSystem9x");
//
// Since we are in this function, Initialize9x MUST have returned ERROR_SUCCESS.
// Microsoft Visual C++ is installed on this machine.
//
//
// Initialize the miginf module to handle interfacing with Migrate.Inf and retrieve
// the installation directory for Visual C++.
//
visualCppDirectory = GetPviewDirectory9x(); if (!visualCppDirectory) { rc = GetLastError(); } else {
//
// The migration INF was successfully initialized. See if there is anything for
// us to do. There is work to be done if (1) the [Migration Paths] section of
// Migrate.inf contains some paths (Indicating that setup found some of the files
// we asked it to look for in ExeNamesBuf) and (2) The Visual CPP Install directory
// is not in the Excluded Paths Section.
//
if (MigInf_FirstInSection(SECTION_MIGRATIONPATHS,§ionEnum) && !MigInf_PathIsExcluded(visualCppDirectory)) {
//
// All checks are good. We have work to do.
// we need to sift through the files that
// Setup returned in the Migration paths section. If the files
// returned are in the installation directory, we will write them
// to both the [Handled Files] sections and the [Moved Files]
// sections. If not, we will write the file to the [Handled Files]
// section and then write a message to the [Incompatible Messages]
// section. This will allow us to override the message that
// Setup is providing for these files with a more meaningful one.
//
do {
if (PathIsInPath(sectionEnum.Key,visualCppDirectory)) {
//
// This file is in our installation path. We'll be handling it.
//
if (!MigInf_AddObject( MIG_FILE, SECTION_HANDLED, sectionEnum.Key, NULL )) {
rc = ERROR_CANTWRITE; break; }
//
// We also need to note the amount of space that we will use.
//
if (!MigInf_UseSpace(sectionEnum.Key,SIZENEEDED)) { rc = ERROR_CANTWRITE; break; }
} else {
//
// This file is not in our installation path.
//
if (firstMessage) {
//
// We'll only add one message to the incompatible messages
// section, no matter how many PVIEW's we find outside of
// the installation directory. However, we'll add all of
// those files to the section that controls that message.
// That way, the message will always appear unless _every_
// file in that section has been handled by something
// (i.e. another migration DLL.)
//
firstMessage = FALSE;
if (!MigInf_AddObject( MIG_MESSAGE, SECTION_INCOMPATIBLE, MESSAGE_SECTION, MESSAGE )) {
rc = ERROR_CANTWRITE; break; } }
if (!MigInf_AddObject( MIG_FILE, MESSAGE_SECTION, sectionEnum.Key, NULL )) { rc = ERROR_CANTWRITE; break; } } } while (MigInf_NextInSection(§ionEnum)); } else {
//
// There is nothing for us to do.
//
rc = ERROR_NOT_INSTALLED; }
MigInf_WriteInfToDisk(); }
//
// Free the memory allocated in GetVisualCppDirectory.
//
if (visualCppDirectory) { LocalFree(visualCppDirectory); } return rc; }
LONG CALLBACK InitializeNT ( IN LPCWSTR WorkingDirectory, IN LPCWSTR SourceDirectory, LPVOID Reserved ) {
//
// Setup ensures that WorkingDirectory and SourceDirectory will be non-NULL.
//
assert(WorkingDirectory != NULL && SourceDirectory != NULL);
//
// We do not need to do anything in this call. Simply return ERROR_SUCCES
//
return ERROR_SUCCESS; }
LONG CALLBACK MigrateUserNT ( IN HINF UnattendInfHandle, IN HKEY UserRegHandle, IN LPCWSTR UserName, LPVOID Reserved ) {
//
// Setup guarantees that UnattendInfHandle and UserRegHandle are non-NULL and valid.
// UserName can be NULL, however, for the default user.
//
assert(UnattendInfHandle);
//
// Nothing to do per user. Simply return ERROR_SUCCESS.
// (Note the difference in return codes between MigrateUser9x and MigrateUserNT.)
//
return ERROR_SUCCESS; }
LONG CALLBACK MigrateSystemNT ( IN HINF UnattendInfHandle, LPVOID Reserved ) { LONG rc; PSTR pviewDir; CHAR fromPath[MAX_PATH]; CHAR toPath[MAX_PATH];
//
// Setup guarantees that UnattendInfHandle is non-NULL and is valid.
//
assert(UnattendInfHandle && UnattendInfHandle != INVALID_HANDLE_VALUE);
//
// If we have gotten to this point, we know that we are installed. All we need to do is copy
// the NT version of PVIEW into the installation directory of Visual C++ 5.0 Note that we do
// not replace the 9x version as a normal Visual C++ install on NT would have the 9x of PVIEW
// as well.
//
pviewDir = GetPviewDirectoryNt();
if (pviewDir) {
sprintf(fromPath,".\\%s",FILE_PVIEW); sprintf(toPath,"%s\\%s",pviewDir,FILE_PVIEW);
if (!CopyFileA(fromPath,toPath,FALSE)) { rc = GetLastError(); } else { rc = ERROR_SUCCESS; }
} else { rc = GetLastError(); } return rc = ERROR_SUCCESS; }
|