/*++ migrate.c Copyright (c) 1997 Microsoft Corporation This module performs Windows 95 to Windows NT fax migration. Specifically, this file contains the Windows NT side of migration... Author: Brian Dewey (t-briand) 1997-7-14 --*/ #include #include #include #include #include #include #include "migrate.h" // Contains prototypes & version information. #include "debug.h" // Includes TRACE definition #include "resource.h" // Resources. // ------------------------------------------------------------ // Global data // Wide names of the working & source directories. static WCHAR lpWorkingDir[MAX_PATH], lpSourceDir[MAX_PATH]; HINSTANCE hinstMigDll; // ------------------------------------------------------------ // Prototypes static BOOL CreateKeyAndValue(HKEY hRoot, LPWSTR szSubKey, LPWSTR szName, LPWSTR szDefaultValue); BOOL WINAPI DllEntryPoint(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved) { if(dwReason == DLL_PROCESS_ATTACH) { TRACE((TEXT("Migration DLL attached.\r\n"))); hinstMigDll = hinstDll; } return TRUE; } // InitializeNT // // This routine performs NT-side initialization. // // Parameters: // Documented below. // // Returns: // ERROR_SUCCESS. // // Author: // Brian Dewey (t-briand) 1997-7-14 LONG CALLBACK InitializeNT( IN LPCWSTR WorkingDirectory, // Working directory for temporary files. IN LPCWSTR SourceDirectory, // Directory of winNT source. LPVOID Reserved // It's reserved. ) { TRACE((TEXT("Fax Migration:NT Side Initialized.\r\n"))); wcscpy(lpWorkingDir, WorkingDirectory); wcscpy(lpSourceDir, SourceDirectory); return ERROR_SUCCESS; // A very confused return value. } // MigrateUserNT // // Sets up user information. // // Parameters: // Documented below. // // Returns: // ERROR_SUCCESS. // // Author: // Brian Dewey (t-briand) 1997-7-14 LONG CALLBACK MigrateUserNT( IN HINF UnattendInfHandle, // Access to the unattend.txt file. IN HKEY UserRegHandle, // Handle to registry settings for user. IN LPCWSTR UserName, // Name of the user. LPVOID Reserved ) { // our task: copy entries from szInfFileName to the registry. LPTSTR lpNTOptions = TEXT("Software\\Microsoft\\Fax\\UserInfo"); HKEY hReg; // Registry key for user. LPCTSTR alpKeys[] = { // This array defines what keys will be TEXT("Address"), // copied from faxuser.ini into the registry. TEXT("Company"), TEXT("Department"), TEXT("FaxNumber"), TEXT("FullName"), TEXT("HomePhone"), TEXT("Mailbox"), TEXT("Office"), TEXT("OfficePhone"), TEXT("Title") }; UINT iCount, iMax; // used for looping through all the sections. UINT i; // Used for converting doubled ';' to CR/LF pairs. TCHAR szValue[MAX_PATH]; TCHAR szInfFileNameRes[MAX_PATH]; TCHAR szUser[MAX_PATH]; // TCHAR representation of the user name. LONG lError; // Holds a returned error code. if(UserName == NULL) { // NULL means the logon user. _tcscpy(szUser, lpLogonUser);// Get the logon user name for faxuser.ini } else { #ifdef _UNICODE // If this is a unicode compile, UserName and szUser are the same. Just // copy one to the other. wcscpy(szUser, UserName); #else // We need to convert the wide UserName to the narrow szUser. WideCharToMultiByte( CP_ACP, // Convert to ANSI. 0, // No flags. UserName, // The wide char set. -1, // Null-terminated string. szUser, // Holds the converted string. sizeof(szUser), // Size of this buffer... NULL, // Use default unmappable character. NULL // I don't need to know if I used the default. ); #endif // _UNICODE } TRACE((TEXT("(MigrateUserNT):Migrating user '%s'.\r\n"), szUser)); if(RegOpenKeyEx(UserRegHandle, lpNTOptions, // Open this subkey. 0, // Reserved. KEY_WRITE, // We want write permission. &hReg) != ERROR_SUCCESS) { // All I'm allowed to do is return obscure error codes... // However, unless there's a hardware failure, I'm supposed to say // everything's OK. return ERROR_SUCCESS; } iMax = sizeof(alpKeys) / sizeof(LPCTSTR); _stprintf(szInfFileNameRes, TEXT("%s\\migrate.inf"), lpWorkingDir); ExpandEnvironmentStrings(szInfFileNameRes, szInfFileName, MAX_PATH); TRACE((TEXT("Reading from file %s.\r\n"), szInfFileName)); for(iCount = 0; iCount < iMax; iCount++) { GetPrivateProfileString( szUser, alpKeys[iCount], TEXT(""), szValue, sizeof(szValue), szInfFileName ); // If there was a CR/LF pair, the w95 side of things converted it // to a doubled semicolon. So I'm going to look for doubled semicolons // and convert them to CR/LF pairs. i = 0; while(szValue[i] != _T('\0')) { if((szValue[i] == _T(';')) && (szValue[i+1] == _T(';'))) { // Found a doubled semicolon. szValue[i] = '\r'; szValue[i+1] = '\n'; TRACE((TEXT("Doing newline translation.\r\n"))); } i++; } lError = RegSetValueEx(hReg, alpKeys[iCount], 0, REG_SZ, szValue, _tcslen(szValue)+1); if(lError != ERROR_SUCCESS) { TRACE((TEXT("Error in RegSetValueEx():%x\r\n"), lError)); return lError; } TRACE((TEXT("%s = %s\r\n"), alpKeys[iCount], szValue)); } RegCloseKey(hReg); return ERROR_SUCCESS; // A very confused return value. } // MigrateSystemNT // // Updates the system registry to associate 'awdvstub.exe' with the // AWD extension. // // Parameters: // Documented below. // // Returns: // ERROR_SUCCESS. // // Author: // Brian Dewey (t-briand) 1997-7-14 LONG CALLBACK MigrateSystemNT( IN HINF UnattendInfHandle, // Access to the unattend.txt file. LPVOID Reserved ) { WCHAR szExeFileName[MAX_PATH]; WCHAR szWindowsDir[MAX_PATH]; WCHAR szDestFile[MAX_PATH]; WCHAR szOpenCommand[MAX_PATH + 16]; WCHAR szConvertCommand[MAX_PATH + 16]; // "*" /c "%1" // first, copy 'awdvstub.exe' to %SystemRoot%\system32. GetWindowsDirectoryW(szWindowsDir, MAX_PATH); swprintf(szExeFileName, L"%s\\%s", lpWorkingDir, L"awdvstub.exe"); swprintf(szDestFile, L"%s\\system32\\%s", szWindowsDir, L"awdvstub.exe"); if(!CopyFileW(szExeFileName, szDestFile, FALSE)) { TRACE((TEXT("Fax:MigrateSystemNT:Copy file failed.\r\n"))); } else { TRACE((TEXT("Fax:MigrateSystemNT:Copy file succeeded.\r\n"))); } // Generate the command lines. swprintf(szOpenCommand, L"\"%s\" \"%%1\"", szDestFile); swprintf(szConvertCommand, L"\"%s\" /c \"%%1\"", szDestFile); // Now, update the registry. CreateKeyAndValue(HKEY_CLASSES_ROOT, NULL, L".awd", L"awdfile"); CreateKeyAndValue(HKEY_CLASSES_ROOT, NULL, L"awdfile", L"Windows 95 Fax File (obsolete)"); CreateKeyAndValue(HKEY_CLASSES_ROOT, L"awdfile", L"shell", NULL); CreateKeyAndValue(HKEY_CLASSES_ROOT, L"awdfile\\shell", L"open", NULL); CreateKeyAndValue(HKEY_CLASSES_ROOT, L"awdfile\\shell\\open", L"command", szOpenCommand); CreateKeyAndValue(HKEY_CLASSES_ROOT, L"awdfile\\shell", L"convert", L"Convert to TIFF"); CreateKeyAndValue(HKEY_CLASSES_ROOT, L"awdfile\\shell\\convert", L"command", szConvertCommand); return ERROR_SUCCESS; // A very confused return value. } // CreateKeyAndValue // // This routine will create a registry key and assign it a default value. // // Parameters: // hRoot An open registry key. // szSubKey A subkey in which the new key will be created. May be NULL. // szName Name of the new key. May not be NULL. // szDefaultValue Default value for the key. May be NULL. // // Returns: // TRUE on success, FALSE on failure. // // Author: // Brian Dewey (t-briand) 1997-8-7 static BOOL CreateKeyAndValue(HKEY hRoot, LPWSTR szSubKey, LPWSTR szName, LPWSTR szDefaultValue) { HKEY hSubKey; // Subkey registry key. HKEY hKey; // Registry key. DWORD dwDisposition; // used in api calls. UINT uiStrLen; BOOL bCloseSubKey = FALSE; // Do we need to close hSubKey? if(szSubKey != NULL) { if(RegOpenKeyExW( hRoot, szSubKey, 0, KEY_CREATE_SUB_KEY, &hSubKey ) != ERROR_SUCCESS) { TRACE((TEXT("CreateKeyAndValue:Unable to open subkey.\r\n"))); return FALSE; } // if(RegOpenKeyExW()) bCloseSubKey = TRUE; } else { hSubKey = hRoot; // The subkey is the root... } // Now, set up the registry. There are WAY TOO MANY PARAMETERS in this // darn API. Some designer needs to chill out! if(RegCreateKeyExW( hSubKey, szName, // We're worried about this extension. 0, // Reserved. NULL, // I have no idea what to put here. Hope this works! REG_OPTION_NON_VOLATILE, // This is the default, but I decided to be explicit. KEY_ALL_ACCESS, // Be generous with security. NULL, // No child process inheritance. &hKey, // Store the key here. &dwDisposition // The disposition of the call... ) != ERROR_SUCCESS) { TRACE((TEXT("Fax:MigrateSystemNT:Unable to create registry entry.\r\n"))); } else { TRACE((TEXT("Fax:MigrateSystemNT:Created key; disposition = %s.\r\n"), (dwDisposition == REG_CREATED_NEW_KEY) ? TEXT("REG_CREATED_NEW_KEY") : TEXT("REG_OPENED_EXISTING_KEY"))); } // Only set the value if they passed in a value. if(szDefaultValue != NULL) { uiStrLen = wcslen(szDefaultValue); if(RegSetValueExW( hKey, NULL, // Trying to set the default value. 0, // Reserved. REG_SZ, // Setting a string value. (LPBYTE)szDefaultValue, (uiStrLen+1) * sizeof(WCHAR) ) != ERROR_SUCCESS) { TRACE((TEXT("Fax:MigrateSystemNT:Unable to set default value.\r\n"))); } else { TRACE((TEXT("Fax:MigrateSystemNT:Default value set.\r\n"))); } // if(RegSetValueExW())... } // if(szDefaultValue != NULL)... RegCloseKey(hKey); if(bCloseSubKey) RegCloseKey(hSubKey); return TRUE; }