|
|
/*++
migrate.c
Copyright (c) 1997 Microsoft Corporation
This module performs Windows 95 to Windows XP fax migration. Specifically, this file contains the Windows XP side of migration...
Author:
Brian Dewey (t-briand) 1997-7-14 Mooly Beery (moolyb) 2000-12-20
--*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <setupapi.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <wchar.h>
#include <tchar.h>
#include "migrate.h" // Contains prototypes & version information.
#include "resource.h" // Resources.
#include <faxutil.h>
#include <faxreg.h>
// ------------------------------------------------------------
// Global data
// Wide names of the working & source directories.
static WCHAR lpWorkingDir[MAX_PATH]; HINSTANCE hinstMigDll;
static LPCTSTR REG_KEY_AWF = TEXT("SOFTWARE\\Microsoft\\At Work Fax"); // ------------------------------------------------------------
// Prototypes
static DWORD MigrateDevicesNT(IN HINF UnattendFile); static DWORD CopyCoverPageFilesNT();
#define prv_DEBUG_FILE_NAME _T("%windir%\\FaxSetup.log")
extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved) { SET_DEBUG_PROPERTIES(DEBUG_ALL_MSG,DBG_PRNT_ALL_TO_FILE,DEBUG_CONTEXT_ALL); OPEN_DEBUG_FILE(prv_DEBUG_FILE_NAME); { DEBUG_FUNCTION_NAME(_T("DllMain")); if (dwReason == DLL_PROCESS_ATTACH) { DebugPrintEx(DEBUG_MSG,"Migration DLL attached."); if (!DisableThreadLibraryCalls(hinstDll)) { DebugPrintEx(DEBUG_ERR,"DisableThreadLibraryCalls failed (ec=%d)",GetLastError()); } 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.
) { int iErr = 0;
DEBUG_FUNCTION_NAME(_T("InitializeNT"));
DebugPrintEx(DEBUG_MSG,"Working directory is %s",WorkingDirectory); DebugPrintEx(DEBUG_MSG,"Source directory is %s",SourceDirectory);
wcscpy(lpWorkingDir, WorkingDirectory); 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") }; INT iErr = 0; 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 szWorkingDirectory[MAX_PATH]; TCHAR szUser[MAX_PATH]; // TCHAR representation of the user name.
LONG lError; // Holds a returned error code.
DEBUG_FUNCTION_NAME(_T("MigrateUserNT"));
if(UserName == NULL) { // NULL means the logon user.
_tcscpy(szUser, lpLogonUser);// Get the logon user name for faxuser.ini
} 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.
); }
DebugPrintEx(DEBUG_MSG,"Migrating user '%s'.",szUser);
if (RegCreateKeyEx( UserRegHandle, lpNTOptions, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hReg, NULL)!=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.
DebugPrintEx(DEBUG_ERR,"RegCreateKeyEx %s failed (ec=%d)",lpNTOptions,GetLastError()); return ERROR_SUCCESS; }
iMax = sizeof(alpKeys) / sizeof(LPCTSTR);
iErr = WideCharToMultiByte( CP_ACP, // Convert to ANSI.
0, // No flags.
lpWorkingDir, // The wide char set.
-1, // Null-terminated string.
szWorkingDirectory, // Holds the converted string.
sizeof(szWorkingDirectory), // Size of this buffer...
NULL, // Use default unmappable character.
NULL); // I don't need to know if I used the default.
if (iErr==0) { DebugPrintEx(DEBUG_ERR,"WideCharToMultiByte failed (ec=%d)",iErr); } _stprintf(szInfFileNameRes, TEXT("%s\\migrate.inf"), szWorkingDirectory); ExpandEnvironmentStrings(szInfFileNameRes, szInfFileName, ARR_SIZE(szInfFileName));
DebugPrintEx(DEBUG_MSG,"Reading from file %s.",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'; DebugPrintEx(DEBUG_MSG,"Doing newline translation."); } i++; } lError = RegSetValueEx(hReg, alpKeys[iCount], 0, REG_SZ, LPBYTE(szValue), _tcslen(szValue)+1); if (lError!=ERROR_SUCCESS) { DebugPrintEx(DEBUG_ERR,"RegSetValueEx %s failed (ec=%d)",alpKeys[iCount],GetLastError()); return lError; } DebugPrintEx(DEBUG_MSG,"%s = %s", 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 ) { DWORD dwErr = ERROR_SUCCESS; WCHAR szExeFileName[MAX_PATH]; WCHAR szWindowsDir[MAX_PATH]; WCHAR szDestFile[MAX_PATH];
DEBUG_FUNCTION_NAME(_T("MigrateSystemNT"));
// first, copy 'awdvstub.exe' to %SystemRoot%\system32.
if (!GetWindowsDirectoryW(szWindowsDir, MAX_PATH)) { DebugPrintEx(DEBUG_ERR, "GetWindowsDirectoryW failed (ec=%d)", GetLastError()); return GetLastError (); } swprintf(szExeFileName, L"%s\\%s", lpWorkingDir, L"awdvstub.exe"); swprintf(szDestFile, L"%s\\system32\\%s", szWindowsDir, L"awdvstub.exe"); if (!CopyFileW( szExeFileName, szDestFile, FALSE)) { DebugPrintEx(DEBUG_ERR,"CopyFileW failed (ec=%d)",GetLastError()); } else { DebugPrintEx(DEBUG_MSG,"CopyFileW success"); }
if (MigrateDevicesNT(UnattendInfHandle)!=ERROR_SUCCESS) { DebugPrintEx(DEBUG_ERR,"MigrateDevicesNT failed (ec=%d)",GetLastError()); }
if (CopyCoverPageFilesNT()!=ERROR_SUCCESS) { DebugPrintEx(DEBUG_ERR,"CopyCoverPageFilesNT failed (ec=%d)",GetLastError()); }
return ERROR_SUCCESS; // A very confused return value.
}
///////////////////////////////////////////////////////////////////////////////////////
// Function:
// MigrateDevicesNT
//
// Purpose: Get the active device's settings from the INF
// Set the device info into the FAX key under HKLM
// verify there's only one device, otherwise do not migrate settings
//
// Params:
// IN HINF UnattendFile - handle to the answer file
//
// Return Value:
// Win32 Error code
//
// Author:
// Mooly Beery (MoolyB) 13-dec-2000
///////////////////////////////////////////////////////////////////////////////////////
typedef WINFAXAPI BOOL (WINAPI *FUNC_FAXCONNECTFAXSERVERW) (LPCWSTR MachineName,LPHANDLE FaxHandle); typedef WINFAXAPI BOOL (WINAPI *FUNC_FAXENUMPORTSEXW) (HANDLE hFaxHandle,PFAX_PORT_INFO_EXW* ppPorts,PDWORD lpdwNumPorts); typedef WINFAXAPI BOOL (WINAPI *FUNC_FAXSETPORTEXW) (HANDLE hFaxHandle,DWORD dwDeviceId,PFAX_PORT_INFO_EXW pPortInfo); typedef WINFAXAPI BOOL (WINAPI *FUNC_FAXCLOSE) (HANDLE FaxHandle); typedef WINFAXAPI VOID (WINAPI *FUNC_FAXFREEBUFFER) (LPVOID Buffer); typedef WINFAXAPI BOOL (WINAPI *FUNC_FAXGETOUTBOXCONFIGURATION) (HANDLE hFaxHandle,PFAX_OUTBOX_CONFIG *ppOutboxCfg); typedef WINFAXAPI BOOL (WINAPI *FUNC_FAXSETOUTBOXCONFIGURATION) (HANDLE hFaxHandle,CONST PFAX_OUTBOX_CONFIG pOutboxCfg);
static DWORD MigrateDevicesNT(IN HINF UnattendFile) { DWORD dwErr = ERROR_SUCCESS; HMODULE hModule = 0; HANDLE hFaxHandle = NULL; CHAR szLocalID[MAX_PATH] = {0}; WCHAR wszLocalID[MAX_PATH] = {0}; CHAR szAnswerMode[32] = {0}; CHAR szRetries[32] = {0}; CHAR szRetriesDelay[32] = {0}; CHAR szNumRings[32] = {0}; FUNC_FAXCONNECTFAXSERVERW pfFaxConnectFaxServerW = NULL; FUNC_FAXENUMPORTSEXW pfFaxEnumPortsExW = NULL; FUNC_FAXSETPORTEXW pfFaxSetPortExW = NULL; FUNC_FAXCLOSE pfFaxClose = NULL; FUNC_FAXFREEBUFFER pfFaxFreeBuffer = NULL; FUNC_FAXGETOUTBOXCONFIGURATION pfFaxGetOutboxConfiguration = NULL; FUNC_FAXSETOUTBOXCONFIGURATION pfFaxSetOutboxConfiguration = NULL; PFAX_PORT_INFO_EXW pFaxPortInfoExW = NULL; PFAX_OUTBOX_CONFIG pFaxOutboxConfig = NULL; DWORD dwNumPorts = 0; INT iNumRings = 0; INT iAnswerMode = 0;
DEBUG_FUNCTION_NAME(_T("MigrateDevicesNT"));
// load the FXSAPI.DLL
hModule = LoadLibrary(FAX_API_MODULE_NAME); if (hModule==NULL) { DebugPrintEx(DEBUG_ERR,"LoadLibrary failed (ec=%d)",GetLastError()); goto exit; } // get the following functions:
// 1. FaxConnectFaxServer
// 2. FaxEnumPortsEx
// 3. FaxSetPortEx
// 4. FaxClose
// 5. FaxFreeBuffer
// 6. FaxGetOutboxConfiguration
// 7. FaxSetOutboxConfiguration
pfFaxConnectFaxServerW = (FUNC_FAXCONNECTFAXSERVERW)GetProcAddress(hModule,"FaxConnectFaxServerW"); if (pfFaxConnectFaxServerW==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxConnectFaxServerW failed (ec=%d)",GetLastError()); goto exit; } pfFaxEnumPortsExW = (FUNC_FAXENUMPORTSEXW)GetProcAddress(hModule,"FaxEnumPortsExW"); if (pfFaxEnumPortsExW==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxEnumPortsExW failed (ec=%d)",GetLastError()); goto exit; } pfFaxSetPortExW = (FUNC_FAXSETPORTEXW)GetProcAddress(hModule,"FaxSetPortExW"); if (pfFaxSetPortExW==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxSetPortExW failed (ec=%d)",GetLastError()); goto exit; } pfFaxClose = (FUNC_FAXCLOSE)GetProcAddress(hModule,"FaxClose"); if (pfFaxClose==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxClose failed (ec=%d)",GetLastError()); goto exit; } pfFaxFreeBuffer = (FUNC_FAXFREEBUFFER)GetProcAddress(hModule,"FaxFreeBuffer"); if (pfFaxFreeBuffer==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxFreeBuffer failed (ec=%d)",GetLastError()); goto exit; } pfFaxGetOutboxConfiguration = (FUNC_FAXGETOUTBOXCONFIGURATION)GetProcAddress(hModule,"FaxGetOutboxConfiguration"); if (pfFaxGetOutboxConfiguration==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxGetOutboxConfiguration failed (ec=%d)",GetLastError()); goto exit; } pfFaxSetOutboxConfiguration = (FUNC_FAXSETOUTBOXCONFIGURATION)GetProcAddress(hModule,"FaxSetOutboxConfiguration"); if (pfFaxSetOutboxConfiguration==NULL) { DebugPrintEx(DEBUG_ERR,"GetProcAddress FaxSetOutboxConfiguration failed (ec=%d)",GetLastError()); goto exit; }
// try to connect to the fax server
if (!(*pfFaxConnectFaxServerW)(NULL,&hFaxHandle)) { DebugPrintEx(DEBUG_ERR,"pfFaxConnectFaxServerW failed (ec=%d)",GetLastError()); goto exit; }
// call EnumPortsEx
if (!(*pfFaxEnumPortsExW)(hFaxHandle,&pFaxPortInfoExW,&dwNumPorts)) { DebugPrintEx(DEBUG_ERR,"pfFaxConnectFaxServerW failed (ec=%d)",GetLastError()); goto exit; }
if (dwNumPorts==0) { DebugPrintEx(DEBUG_MSG,"No devices are installed, no migration"); goto next; } else if (dwNumPorts>1) { DebugPrintEx(DEBUG_MSG,"%d devices are installed, no migration",dwNumPorts); goto next; }
// we have one device, get its FAX_PORT_INFOW, modify it and call FaxSetPortW
// TSID
if (SetupGetLineText( NULL, UnattendFile, "FAX", INF_RULE_LOCAL_ID, szLocalID, sizeof(szLocalID), NULL)) { if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szLocalID, -1, wszLocalID, sizeof(wszLocalID)/sizeof(WCHAR) )) { pFaxPortInfoExW[0].lptstrTsid = wszLocalID; pFaxPortInfoExW[0].lptstrCsid = wszLocalID; DebugPrintEx(DEBUG_MSG,"new TSID & CSID is %s",szLocalID); } } else { DebugPrintEx(DEBUG_ERR,"SetupGetLineText TSID failed (ec=%d)",GetLastError()); } // Rings
if (SetupGetLineText( NULL, UnattendFile, "FAX", INF_RULE_NUM_RINGS, szNumRings, sizeof(szNumRings), NULL)) { iNumRings = atoi(szNumRings); if (iNumRings) { pFaxPortInfoExW[0].dwRings = iNumRings; DebugPrintEx(DEBUG_MSG,"new Rings is %d",iNumRings); } } else { DebugPrintEx(DEBUG_ERR,"GetPrivateProfileString NumRings failed (ec=%d)",GetLastError()); }
// Answer mode
pFaxPortInfoExW[0].bSend = TRUE; if (SetupGetLineText( NULL, UnattendFile, "FAX", INF_RULE_ANSWER_MODE, szAnswerMode, sizeof(szAnswerMode), NULL)) { iAnswerMode = atoi(szAnswerMode); switch (iAnswerMode) { case 0: break; case 1: pFaxPortInfoExW[0].ReceiveMode = FAX_DEVICE_RECEIVE_MODE_MANUAL; DebugPrintEx(DEBUG_MSG,"setting flags to manual Receive"); break; case 2: pFaxPortInfoExW[0].ReceiveMode = FAX_DEVICE_RECEIVE_MODE_AUTO; DebugPrintEx(DEBUG_MSG,"setting flags to auto Receive"); break; default: pFaxPortInfoExW[0].ReceiveMode = FAX_DEVICE_RECEIVE_MODE_OFF; DebugPrintEx(DEBUG_MSG,"strange AnswerMode, just send enabled"); break; } } else { DebugPrintEx(DEBUG_ERR,"GetPrivateProfileString AnswerMode failed (ec=%d)",GetLastError()); }
// call FaxSetPort
if (!(*pfFaxSetPortExW)(hFaxHandle,pFaxPortInfoExW[0].dwDeviceID,&(pFaxPortInfoExW[0]))) { DebugPrintEx(DEBUG_ERR,"pfFaxSetPortExW failed (ec=%d)",GetLastError()); goto exit; }
next: // get the Outbox configuration
if (!(*pfFaxGetOutboxConfiguration)(hFaxHandle,&pFaxOutboxConfig)) { DebugPrintEx(DEBUG_ERR,"pfFaxGetOutboxConfiguration failed (ec=%d)",GetLastError()); goto exit; }
// get the retries and retry delay from INF
if (SetupGetLineText( NULL, UnattendFile, "FAX", "NumberOfRetries", szRetries, sizeof(szRetries), NULL)) { pFaxOutboxConfig->dwRetries = atoi(szRetries); }
if (SetupGetLineText( NULL, UnattendFile, "FAX", "TimeBetweenRetries", szRetriesDelay, sizeof(szRetriesDelay), NULL)) { pFaxOutboxConfig->dwRetryDelay = atoi(szRetriesDelay); }
// now set the outbox configuration
if (!(*pfFaxSetOutboxConfiguration)(hFaxHandle,pFaxOutboxConfig)) { DebugPrintEx(DEBUG_ERR,"pfFaxSetOutboxConfiguration failed (ec=%d)",GetLastError()); goto exit; }
exit: if (hFaxHandle) { if (pfFaxClose) { (*pfFaxClose)(hFaxHandle); } if (pFaxPortInfoExW) { if(pfFaxFreeBuffer) { (*pfFaxFreeBuffer)(pFaxPortInfoExW); } } if (pFaxOutboxConfig) { if(pfFaxFreeBuffer) { (*pfFaxFreeBuffer)(pFaxOutboxConfig); } } } if (hModule) { FreeLibrary(hModule); }
return dwErr; }
///////////////////////////////////////////////////////////////////////////////////////
// Function:
// CopyCoverPageFilesNT
//
// Purpose: Copy all of the *.CPE files from the temporary
// directory to the server cover pages dir
//
// Params:
// None
//
// Return Value:
// Win32 Error code
//
// Author:
// Mooly Beery (MoolyB) 13-dec-2000
///////////////////////////////////////////////////////////////////////////////////////
DWORD CopyCoverPageFilesNT() { DWORD dwErr = ERROR_SUCCESS; INT iErr = 0; CHAR szServerCpDir[MAX_PATH] = {0}; CHAR szWorkingDirectory[MAX_PATH] = {0}; SHFILEOPSTRUCT fileOpStruct;
DEBUG_FUNCTION_NAME(_T("CopyCoverPageFiles9X"));
ZeroMemory(&fileOpStruct, sizeof(SHFILEOPSTRUCT));
// Get the server cover pages directory
if (!GetServerCpDir(NULL,szServerCpDir,sizeof(szServerCpDir))) { dwErr = GetLastError(); DebugPrintEx(DEBUG_ERR,"GetServerCpDir failed (ec=%d)",dwErr); goto exit; }
iErr = WideCharToMultiByte( CP_ACP, // Convert to ANSI.
0, // No flags.
lpWorkingDir, // The wide char set.
-1, // Null-terminated string.
szWorkingDirectory, // Holds the converted string.
sizeof(szWorkingDirectory), // Size of this buffer...
NULL, // Use default unmappable character.
NULL); // I don't need to know if I used the default.
if (iErr==0) { DebugPrintEx(DEBUG_ERR,"WideCharToMultiByte failed (ec=%d)",iErr); goto exit; }
strcat(szWorkingDirectory,"\\*.cpe");
fileOpStruct.hwnd = NULL; fileOpStruct.wFunc = FO_MOVE; fileOpStruct.pFrom = szWorkingDirectory; fileOpStruct.pTo = szServerCpDir; fileOpStruct.fFlags =
FOF_FILESONLY | // Perform the operation on files only if a wildcard file name (*.*) is specified.
FOF_NOCONFIRMMKDIR | // Do not confirm the creation of a new directory if the operation requires one to be created.
FOF_NOCONFIRMATION | // Respond with "Yes to All" for any dialog box that is displayed.
FOF_NORECURSION | // Only operate in the local directory. Don't operate recursively into subdirectories.
FOF_SILENT | // Do not display a progress dialog box.
FOF_NOERRORUI; // Do not display a user interface if an error occurs.
fileOpStruct.fAnyOperationsAborted = FALSE; fileOpStruct.hNameMappings = NULL; fileOpStruct.lpszProgressTitle = NULL;
DebugPrintEx(DEBUG_MSG, TEXT("Calling to SHFileOperation from %s to %s."), fileOpStruct.pFrom, fileOpStruct.pTo); if (SHFileOperation(&fileOpStruct)) { dwErr = GetLastError(); DebugPrintEx(DEBUG_ERR,"SHFileOperation failed (ec: %ld)",dwErr); goto exit; }
exit: return dwErr; }
|