#define STRICT #define LEAN_AND_MEAN #include #include #include #include #include #include #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; }