windows-nt/Source/XPSP1/NT/windows/feime/fe/chimemig/imemig.c
2020-09-26 16:20:57 +08:00

666 lines
17 KiB
C

//
// stub migration dll for IME Dlls.
//
#include "pch.h"
#include "chs.h"
#include "cht.h"
#include "common.h"
#include "resource.h"
typedef struct {
CHAR CompanyName[256];
CHAR SupportNumber[256];
CHAR SupportUrl[256];
CHAR InstructionsToUser[1024];
} VENDORINFO, *PVENDORINFO;
//IME data
#define MAX_IME_DATA_FILE_NAME 20
TCHAR ChsDataFile[][MAX_IME_DATA_FILE_NAME]={
"winpy.emb",
"winsp.emb",
"winzm.emb",
"winbx.emb",
"winxpy.emb",
"winxsp.emb",
"winxzm.emb",
"winxbx.emb",
"user.rem",
"tmmr.rem",
0
};
TCHAR ChtDataFile[][MAX_IME_DATA_FILE_NAME]={
"lcptr.tbl",
"lcphrase.tbl",
0
};
CHAR ImeDataDirectory[MAX_PATH];
//
// Constants
//
#define CP_USASCII 1252
#define CP_CHINESE_BIG5 950
#define CP_CHINESE_GB 936
#define END_OF_CODEPAGES -1
//
// Code page array, add relevant code pages that you support to this list..
//
INT g_CodePageArray[] = {
CP_USASCII,
END_OF_CODEPAGES
};
// PCSTR g_MyProductId = "This Must be LOCALIZED";
//
// load it from resource
//
TCHAR g_MyProductId[MAX_PATH];
VENDORINFO g_MyVendorInfo = {"Localized Company Name","Localized Support Number","Localized Support URL","Localized Instructions"};
//
// Handle to the process heap for allocations. Initialized in DllMain.
//
HANDLE g_hHeap;
HINSTANCE g_hInstance;
BOOL g_bCHSWin98 = FALSE;
#ifdef MYDBG
void Print(LPCTSTR pszFormat,...)
{
TCHAR szBuf[500];
TCHAR szBuf2[500];
va_list arglist;
va_start(arglist,pszFormat);
wvsprintf(szBuf,pszFormat,arglist);
wsprintf(szBuf2,"%s : %s",DBGTITLE,szBuf);
#ifdef SETUP
OutputDebugString(szBuf2);
#else
SetupLogError(szBuf2,LogSevInformation);
#endif
va_end(arglist);
}
#endif
BOOL
WINAPI
DllMain (
IN HANDLE DllInstance,
IN ULONG ReasonForCall,
IN LPVOID Reserved
)
{
switch (ReasonForCall) {
case DLL_PROCESS_ATTACH:
g_hInstance = DllInstance;
//
// We don't need DLL_THREAD_ATTACH or DLL_THREAD_DETACH messages
//
DisableThreadLibraryCalls (DllInstance);
//
// Global init
//
g_hHeap = GetProcessHeap();
if (!MigInf_Initialize()) {
return FALSE;
}
// Open log; FALSE means do not delete existing log
SetupOpenLog (FALSE);
break;
case DLL_PROCESS_DETACH:
g_hInstance = NULL;
MigInf_CleanUp();
SetupCloseLog();
break;
}
return TRUE;
}
LPTSTR CheckSlash (LPTSTR lpDir)
{
DWORD dwStrLen;
LPTSTR lpEnd;
lpEnd = lpDir + lstrlen(lpDir);
if (*(lpEnd - 1) != TEXT('\\')) {
*lpEnd = TEXT('\\');
lpEnd++;
*lpEnd = TEXT('\0');
}
return lpEnd;
}
BOOL
CheckIfFileExisting(LPCTSTR pszFileName)
{
TCHAR szFullPathName[MAX_PATH];
LONG lResult;
//
// these files are in system directory
//
GetSystemDirectory(szFullPathName,MAX_PATH);
CheckSlash(szFullPathName);
lstrcat(szFullPathName,pszFileName);
lResult = GetFileAttributes(szFullPathName);
if (lResult == 0xFFFFFFFF) { // file does not exist
return FALSE;
} else {
return TRUE;
}
}
BOOL
pMyImeInstalled (
VOID
)
{
//
// Add code in this function that determines if your IME is installed on the system.
//
int i;
UINT uACP;
uACP = GetACP();
switch(uACP) {
case CP_CHINESE_GB: // Simplied Chinese
case CP_CHINESE_BIG5: // Traditional Chinese
g_CodePageArray[0] = uACP;
DebugMsg(("pMyImeInstalled OK, CodePage %d is valid\r\n",g_CodePageArray[0]));
return TRUE;
}
DebugMsg(("pMyImeInstalled Failed, CodePage %d is invalid\r\n",g_CodePageArray[0]));
return FALSE;
}
LONG
CALLBACK
QueryVersion (
OUT LPCSTR * ProductID,
OUT LPUINT DllVersion,
OUT LPINT * CodePageArray, OPTIONAL
OUT LPCSTR * ExeNamesBuf, OPTIONAL
OUT PVENDORINFO * VendorInfo
)
{
LONG returnCode = ERROR_SUCCESS;
//
// Add code to pMyImeInstalled() to determine wether your IME is installed. If this function
// returns TRUE, Setup will call this migration dll.
//
if (pMyImeInstalled()) {
//
// We are installed, so tell Setup who we are. ProductID is used
// for display, so it must be localized. The ProductID string is
// converted to UNICODE for use on Windows NT via the MultiByteToWideChar
// Win32 API. The first element of CodePageArray is used to specify
// the code page of ProductID, and if no elements are returned in
// CodePageArray, Setup assumes CP_ACP.
//
LoadString(g_hInstance,IDS_PRODUCTID,g_MyProductId,MAX_PATH);
*ProductID = g_MyProductId;
//
// Report our version. Zero is reserved for use by DLLs that
// ship with Windows NT.
//
*DllVersion = 1;
//
// Because we have English messages, we return an array that has
// the English language ID. The sublanguage is neutral because
// we do not have currency, time, or other geographic-specific
// information in our messages.
//
// Tip: If it makes more sense for your DLL to use locales,
// return ERROR_NOT_INSTALLED if the DLL detects that an appropriate
// locale is not installed on the machine.
//
//
// The CODE PAGE INFO is determined in 'pMyImeInstalled'
//
*CodePageArray = g_CodePageArray;
DebugMsg(("CodePageArray = %d\r\n",g_CodePageArray[0]));
//
// Use system default code page
//
//
// ExeNamesBuf - we pass a list of file names (the long versions)
// and let Setup find them for us. Keep this list short because
// every instance of the file on every hard drive will be reported
// in migrate.inf.
//
// Most applications don't need this behavior, because the registry
// usually contains full paths to installed components.
//
*ExeNamesBuf = NULL;
//
// VendorInfo is designed to contain support information for a Migration DLL. Since it
// may be used for UI, it's fields should also be localized.
//
LoadString(g_hInstance,MSG_VI_COMPANY_NAME ,g_MyVendorInfo.CompanyName ,256);
LoadString(g_hInstance,MSG_VI_SUPPORT_NUMBER ,g_MyVendorInfo.SupportNumber ,256);
LoadString(g_hInstance,MSG_VI_SUPPORT_URL ,g_MyVendorInfo.SupportUrl ,256);
LoadString(g_hInstance,MSG_VI_INSTRUCTIONS ,g_MyVendorInfo.InstructionsToUser,1024);
*VendorInfo = &g_MyVendorInfo;
DebugMsg(("CompanyName = %s\r\n",g_MyVendorInfo.CompanyName));
DebugMsg(("SupportNumber = %s\r\n",g_MyVendorInfo.SupportNumber));
DebugMsg(("SupportUrl = %s\r\n",g_MyVendorInfo.SupportUrl));
DebugMsg(("InstructionsToUser = %s\r\n",g_MyVendorInfo.InstructionsToUser));
}
else {
//
// If pMyImeInstalled returns false, we have nothing to do. By returning ERROR_NOT_INSTALLED,
// we ensure that we will not be called again.
//
returnCode = ERROR_NOT_INSTALLED;
}
DebugMsg(("QueryVersion, return value = %d\r\n",returnCode));
return returnCode;
}
//Save IME data file to working directory.
BOOL SaveImeDataFile(LPSTR SourceDirectory, LPSTR TargetDirectory, TCHAR * FileBuf, BOOL CheckAll)
{
int lenSource = lstrlen(SourceDirectory);
int lenTarget = lstrlen(TargetDirectory);
HANDLE hfile;
while (*FileBuf)
{
lstrcat(SourceDirectory, FileBuf);
lstrcat(TargetDirectory, FileBuf);
if ((GetFileAttributes(SourceDirectory) != 0xFFFFFFFF) &&
(GetFileAttributes(SourceDirectory) != FILE_ATTRIBUTE_DIRECTORY)){
if (!CopyFile(SourceDirectory, TargetDirectory, FALSE)) {
DebugMsg(("Copy file %s to %s failed \r\n",SourceDirectory,TargetDirectory));
} else {
DebugMsg(("Copy file %s to %s OK \r\n",SourceDirectory,TargetDirectory));
}
} else {
DebugMsg(("File %s doesn't exist, skip it ! \r\n",SourceDirectory));
}
FileBuf+=MAX_IME_DATA_FILE_NAME;
SourceDirectory[lenSource]=0;
TargetDirectory[lenTarget]=0;
}
return TRUE;
}
LONG
CALLBACK
Initialize9x (
IN LPCSTR WorkingDirectory,
IN LPCSTR SourceDirectories,
LPVOID Reserved
)
{
LONG returnCode = ERROR_SUCCESS;
UINT len;
TCHAR FilePath[MAX_PATH];
TCHAR TargetPath[MAX_PATH];
BOOL bInstall;
UINT uACP;
//
// Because we returned ERROR_SUCCESS in QueryVersion, we are being
// called for initialization. Therefore, we know screen savers are
// enabled on the machine at this point.
//
//
// Do any Windows9x side initialization that is necessary here.
//
DebugMsg(("Start ..., Initialize9x\r\n"));
lstrcpy(TargetPath, WorkingDirectory);
len=lstrlen(TargetPath);
if (TargetPath[len-1] != '\\') {
TargetPath[len] ='\\';
TargetPath[++len] = 0;
}
DebugMsg(("Initialize9x, TargetPath = %s\r\n",TargetPath));
len = GetSystemDirectory((LPSTR)FilePath, sizeof(FilePath));
// Consider root directory
if (FilePath[len - 1] != '\\') {
FilePath[len] = '\\';
FilePath[++len] = 0;
}
DebugMsg(("Initialize9x, SystemPath = %s\r\n",FilePath));
uACP = GetACP();
switch (uACP) {
case CP_CHINESE_GB:
{
//
// The Ime tables in CHS Win98 are already unicode format
//
// we don't need to do convert tables , just back up them
//
UINT CreateNestedDirectory(LPCTSTR, LPSECURITY_ATTRIBUTES);
TCHAR szWin98Dir[MAX_PATH];
OSVERSIONINFO OsVersion;
OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&OsVersion);
lstrcpy(szWin98Dir,TargetPath);
if ((OsVersion.dwMajorVersion == 4) &&
(OsVersion.dwMinorVersion == 10)) {
//
// this is Windows 98, create a "Win98" subdirectory
//
DebugMsg(("Initialize9x, SaveImeDataFile, GB, Win98 identified !\r\n"));
lstrcat(szWin98Dir,"Win98");
DebugMsg(("Initialize9x, SaveImeDataFile, Create %s !\r\n",szWin98Dir));
CreateNestedDirectory(szWin98Dir,NULL);
DebugMsg(("Initialize9x, SaveImeDataFile, The target path become %s !\r\n",TargetPath));
}
if (! SaveImeDataFile(FilePath, TargetPath, &ChsDataFile[0][0], FALSE)) {
DebugMsg(("Initialize9x, SaveImeDataFile, GB, failed !\r\n"));
returnCode = ERROR_NOT_INSTALLED;
}
}
break;
case CP_CHINESE_BIG5:
if (! SaveImeDataFile(FilePath, TargetPath, &ChtDataFile[0][0], TRUE)) {
DebugMsg(("Initialize9x, SaveImeDataFile, BIG5, failed !\r\n"));
returnCode = ERROR_NOT_INSTALLED;
}
break;
default:
DebugMsg(("Initialize9x, Invalid codepage !\r\n"));
returnCode = ERROR_NOT_INSTALLED;
}
DebugMsg(("Initialize9x, SaveImeDataFile OK [%d]!\r\n",returnCode));
return returnCode;
}
LONG
CALLBACK
MigrateUser9x (
IN HWND ParentWnd,
IN LPCSTR UnattendFile,
IN HKEY UserRegKey,
IN LPCSTR UserName,
LPVOID Reserved
)
{
DWORD returnCode = ERROR_SUCCESS;
//
// Avoid displaying any user interface when possible.
//
// We don't need to use UnattendFile settings because we are not
// a service (such as a network redirector). Therefore, we do not
// use the UnattendFile parameter.
//
//
// Note: NO changes allowed on Win9x side, we can only read our
// settings and save them in a file.
//
//
// UserRegKey should be used instead of HKCU. You will be called once for
// each user on the system (including logon user and administrator). Each time,
// the correct user root will have been mapped into HKCU.
//
return returnCode;
}
LONG
CALLBACK
MigrateSystem9x (
IN HWND ParentWnd,
IN LPCSTR UnattendFile,
LPVOID Reserved
)
{
LONG returnCode = ERROR_SUCCESS;
//
// Gather all necessary system wide data in this function.
//
return returnCode;
}
LONG
CALLBACK
InitializeNT (
IN LPCWSTR WorkingDirectory,
IN LPCWSTR SourceDirectories,
LPVOID Reserved
)
{
LONG returnCode = ERROR_SUCCESS;
int len;
UINT uACP;
//
// Do any intialization for NT side processing in this function.
//
//Save working directory path
WideCharToMultiByte(CP_ACP,
0,
WorkingDirectory,
-1,
ImeDataDirectory,
sizeof(ImeDataDirectory),
NULL,
NULL);
DebugMsg(("InitializeNT, Save working directory path, ImeDataDirectory = %s\r\n",ImeDataDirectory));
//Patch path with '\'
len = lstrlen(ImeDataDirectory);
if (ImeDataDirectory[len - 1] != '\\') {
ImeDataDirectory[len] = '\\';
ImeDataDirectory[++len] = 0;
}
DebugMsg(("InitializeNT, Patch path with '\', ImeDataDirectory = %s\r\n",ImeDataDirectory));
DebugMsg(("InitializeNT, OK !\r\n"));
uACP = GetACP();
if (uACP == 936) {
TCHAR szWin98Dir[MAX_PATH];
//
// check if this is CHS Win98
//
lstrcpy(szWin98Dir,ImeDataDirectory);
//
// Check if ...\Win98 directory is existing or not
//
// If it is, then it means we're migrating Win98
//
ConcatenatePaths(szWin98Dir,"Win98",sizeof(szWin98Dir));
DebugMsg(("ImeEudcConvert::MigrateImeEUDCTables2 ,Test IME98 directory %s !\r\n",szWin98Dir));
if (GetFileAttributes(szWin98Dir) == 0xFFFFFFFF || ! (GetFileAttributes(szWin98Dir) & FILE_ATTRIBUTE_DIRECTORY)) {
g_bCHSWin98 = FALSE;
} else {
g_bCHSWin98 = TRUE;
}
}
return returnCode;
}
LONG
CALLBACK
MigrateUserNT (
IN HINF UnattendInfHandle,
IN HKEY UserRegKey,
IN LPCWSTR UserName,
LPVOID Reserved
)
{
LONG returnCode = ERROR_SUCCESS;
//
// Migrate all necessary user settings for your IME in this function call. Once again, remember
// to use UserRegKey in place of HKCU.
//
DebugMsg(("MigrateUserNT,Starting ... !\r\n"));
DebugMsg(("MigrateUserNT,The user is %ws !\r\n",UserName));
if (!MigrateImeEUDCTables(UserRegKey)) {
returnCode = ERROR_NOT_INSTALLED;
DebugMsg(("MigrateUserNT,MigrateImeEUDCTables failed !\r\n"));
} else {
DebugMsg(("MigrateUserNT,MigrateImeEUDCTables OK !\r\n"));
}
if (!MigrateImeEUDCTables2(UserRegKey)) {
returnCode = ERROR_NOT_INSTALLED;
DebugMsg(("MigrateUserNT,MigrateImeEUDCTables2 failed !\r\n"));
} else {
DebugMsg(("MigrateUserNT,MigrateImeEUDCTables2 OK !\r\n"));
}
DebugMsg(("MigrateUserNT,Finished !\r\n"));
return returnCode;
}
LONG
CALLBACK
MigrateSystemNT (
IN HINF UnattendInfHandle,
LPVOID Reserved
)
{
LONG returnCode = ERROR_SUCCESS;
//
// Migrate all necessary system settings for your IME in this function call. Anything relative to
// a user should have been handled during MigrateUserNT.
//
UINT uACP;
uACP = GetACP();
switch(uACP) {
case CP_CHINESE_GB: // Simplied Chinese
if (ConvertChsImeData()) {
DebugMsg(("MigrateSystemNT,GB, ConvertChsImeData OK !\r\n"));
} else {
DebugMsg(("MigrateSystemNT,GB, ConvertChsImeData OK !\r\n"));
}
MovePerUserIMEData();
if (CHSBackupWinABCUserDict(ImeDataDirectory)) {
DebugMsg(("MigrateSystemNT,GB, CHSBackupWinABCUserDict OK !\r\n"));
} else {
DebugMsg(("MigrateSystemNT,GB, CHSBackupWinABCUserDict OK !\r\n"));
}
if (CHSDeleteGBKKbdLayout()) {
DebugMsg(("MigrateSystemNT,GB, CHSDeleteGBKKbdLayout OK !\r\n"));
} else {
DebugMsg(("MigrateSystemNT,GB, CHSDeleteGBKKbdLayout OK !\r\n"));
}
break;
case CP_CHINESE_BIG5: // Traditional Chinese
if (ConvertChtImeData()) {
DebugMsg(("MigrateSystemNT,BIG5, ConvertChtImeData OK !\r\n"));
} else {
DebugMsg(("MigrateSystemNT,BIG5, ConvertChtImeData OK !\r\n"));
}
MovePerUserIMEData();
break;
default:
returnCode = ERROR_NOT_INSTALLED;
}
return returnCode;
}