mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1230 lines
35 KiB
1230 lines
35 KiB
#include <windows.h>
|
|
#include <setupapi.h>
|
|
#include <tchar.h>
|
|
#include <malloc.h>
|
|
#include "resource.h"
|
|
#include "common.h"
|
|
|
|
TCHAR szMsgBuf[MAX_PATH];
|
|
|
|
#pragma pack(push, USERDIC, 1 )
|
|
//
|
|
// Cht/Chs EUDC IME table Header Format
|
|
//
|
|
typedef struct tagUSRDICIMHDR {
|
|
WORD uHeaderSize; // 0x00
|
|
BYTE idUserCharInfoSign[8]; // 0x02
|
|
BYTE idMajor; // 0x0A
|
|
BYTE idMinor; // 0x0B
|
|
DWORD ulTableCount; // 0x0C
|
|
WORD cMethodKeySize; // 0x10
|
|
BYTE uchBankID; // 0x12
|
|
WORD idInternalBankID; // 0x13
|
|
BYTE achCMEXReserved1[43]; // 0x15
|
|
WORD uInfoSize; // 0x40
|
|
BYTE chCmdKey; // 0x42
|
|
BYTE idStlnUpd; // 0x43
|
|
BYTE cbField; // 0x44
|
|
WORD idCP; // 0x45
|
|
BYTE achMethodName[6]; // 0x47
|
|
BYTE achCSIReserved2[51]; // 0x4D
|
|
BYTE achCopyRightMsg[128]; // 0x80
|
|
} USRDICIMHDR;
|
|
|
|
typedef struct tagWinAR30EUDC95 {
|
|
WORD ID;
|
|
WORD Code;
|
|
BYTE Seq[4];
|
|
} WinAR30EUDC95;
|
|
|
|
typedef struct tagWinAR30EUDCNT {
|
|
WORD ID;
|
|
WORD Code;
|
|
BYTE Seq[5];
|
|
} WinAR30EUDCNT;
|
|
|
|
|
|
#pragma pack(pop, USERDIC)
|
|
|
|
typedef struct tagTABLIST {
|
|
UINT nResID;
|
|
TCHAR szIMEName[MAX_PATH];
|
|
} TABLELIST,*LPTABLELIST;
|
|
|
|
|
|
BYTE WinAR30MapTable[] = {0x00, 0x00 ,
|
|
0x3F, 0x3F ,
|
|
0x1E, 0x01 ,
|
|
0x1B, 0x02 ,
|
|
0x1C, 0x03 ,
|
|
0x1D, 0x04 ,
|
|
0x3E, 0x3E ,
|
|
0x01, 0x05 ,
|
|
0x02, 0x06 ,
|
|
0x03, 0x07 ,
|
|
0x04, 0x08 ,
|
|
0x05, 0x09 ,
|
|
0x06, 0x0a ,
|
|
0x07, 0x0b ,
|
|
0x08, 0x0c ,
|
|
0x09, 0x0d ,
|
|
0x0A, 0x0e ,
|
|
0x0B, 0x0f ,
|
|
0x0C, 0x10 ,
|
|
0x0D, 0x11 ,
|
|
0x0E, 0x12 ,
|
|
0x0F, 0x13 ,
|
|
0x10, 0x14 ,
|
|
0x11, 0x15 ,
|
|
0x12, 0x16 ,
|
|
0x13, 0x17 ,
|
|
0x14, 0x18 ,
|
|
0x15, 0x19 ,
|
|
0x16, 0x1a ,
|
|
0x17, 0x1b ,
|
|
0x18, 0x1c ,
|
|
0x19, 0x1d ,
|
|
0x1A, 0x1e };
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// An EUDC IME table comprises a Header and lots of records, the number of
|
|
// records is ulTableCount, and every record has following format:
|
|
//
|
|
// <WORD1> <WORD2> <SEQCODES>
|
|
//
|
|
// <WORD1>: Identical between Win95 and NT.
|
|
// WORD2 stands for internal code, Win95 is ANSI code, NT is Unicode code.
|
|
// Seqcodes: bytes number is cMethodKeySize. identical between Win95 and NT
|
|
//
|
|
//
|
|
// Following fields in CHTUSRDICIMHDR need to convert from Win95 to NT 5.0
|
|
//
|
|
// idCp: from CHT 950 to 1200. ( stands for Unicode )
|
|
// CHS 936 to 1200.
|
|
// achMethodName[6]: converted from DBCS to Unicode.
|
|
//
|
|
//
|
|
// Every IME EUDC table file names can be got from following registry Key/Value
|
|
//
|
|
// Key:Registry\Current_User\Software\Microsoft\Windows\CurrentVersion\<IMEName>
|
|
// Value: User Dictionary: REG_SZ:
|
|
//
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ImeEudcConvert
|
|
*
|
|
* Convert CHT/CHS Win95 EUDC IME table to NT 5.0
|
|
*
|
|
* Arguments:
|
|
*
|
|
* UCHAR * EudcTblFile - IME Eudc tbl file name.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* BOOL: Success -TRUE. Fail - FALSE;
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL ImeEudcConvert( LPCSTR EudcTblFile)
|
|
{
|
|
|
|
HANDLE hTblFile, hTblMap;
|
|
LPBYTE lpTblFile, lpStart, lpTmp;
|
|
DWORD dwCharNums, i;
|
|
USRDICIMHDR *lpEudcHeader;
|
|
BYTE DBCSChar[2];
|
|
WORD wUnicodeChar, wImeName[3];
|
|
UINT uCodePage;
|
|
|
|
DebugMsg(("ImeEudcConvert,EudcTblFile = %s !\r\n",EudcTblFile));
|
|
|
|
hTblFile = CreateFile(EudcTblFile, // ptr to name of file
|
|
GENERIC_READ | GENERIC_WRITE, // access(read-write)mode
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
|
|
NULL, // ptr to security attr
|
|
OPEN_EXISTING, // how to create
|
|
FILE_ATTRIBUTE_NORMAL, // file attributes
|
|
NULL);
|
|
|
|
if (hTblFile == INVALID_HANDLE_VALUE) {
|
|
DebugMsg(("ImeEudcConvert,hTblFile == INVALID_HANDLE_VALUE !\r\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
hTblMap = CreateFileMapping(hTblFile, // handle to file to map
|
|
NULL, // optional security attributes
|
|
PAGE_READWRITE,// protection for mapping object
|
|
0, // high-order 32 bits of object size
|
|
0, // low-order 32 bits of object size
|
|
NULL); // name of file-mapping object);
|
|
if ( !hTblMap ) {
|
|
DebugMsg(("ImeEudcConvert,CreateFileMapping failed !\r\n"));
|
|
CloseHandle(hTblFile);
|
|
return FALSE;
|
|
}
|
|
|
|
lpTblFile = (LPBYTE) MapViewOfFile(hTblMap, FILE_MAP_WRITE, 0, 0, 0);
|
|
|
|
if ( !lpTblFile ) {
|
|
DebugMsg(("ImeEudcConvert,MapViewOfFile failed !\r\n"));
|
|
CloseHandle(hTblMap);
|
|
CloseHandle(hTblFile);
|
|
return FALSE;
|
|
}
|
|
|
|
lpEudcHeader = (USRDICIMHDR *)lpTblFile;
|
|
|
|
// get the current Code Page.
|
|
uCodePage = lpEudcHeader->idCP;
|
|
|
|
//
|
|
// if CodePage == 1200, it means this table has already been
|
|
// unicode format
|
|
//
|
|
if (uCodePage == 1200) {
|
|
DebugMsg(("ImeEudcConvert,[%s] Codepage is already 1200 !\r\n",EudcTblFile));
|
|
CloseHandle(hTblMap);
|
|
CloseHandle(hTblFile);
|
|
return FALSE;
|
|
}
|
|
|
|
// change the codepage from 950 (CHT) or 936 (CHS) to 1200
|
|
|
|
lpEudcHeader->idCP = 1200; // Unicode Native Code Page.
|
|
|
|
// change the IME name from DBCS to Unicode.
|
|
|
|
MultiByteToWideChar(uCodePage, // code page
|
|
0, // character-type options
|
|
lpEudcHeader->achMethodName, // address of string to map
|
|
6, // number of bytes in string
|
|
wImeName, // addr of wide-char buf
|
|
3); // size of buffer
|
|
|
|
|
|
lpTmp = (LPBYTE)wImeName;
|
|
|
|
for (i=0; i<6; i++)
|
|
lpEudcHeader->achMethodName[i] = lpTmp[i];
|
|
|
|
|
|
|
|
// Now we will convert every record for EUDC char.
|
|
|
|
lpStart = lpTblFile + lpEudcHeader->uHeaderSize;
|
|
|
|
dwCharNums = lpEudcHeader->ulTableCount;
|
|
for (i=0; i<dwCharNums; i++) {
|
|
|
|
lpTmp = lpStart + sizeof(WORD);
|
|
|
|
// swap the leader Byte and tail Byte of the DBCS Code.
|
|
|
|
DBCSChar[0] = *(lpTmp+1);
|
|
DBCSChar[1] = *lpTmp;
|
|
|
|
MultiByteToWideChar(uCodePage, // code page
|
|
0, // character-type options
|
|
DBCSChar, // address of string to map
|
|
2, // number of bytes in string
|
|
&wUnicodeChar, // addr of wide-char buf
|
|
1); // size of buffer
|
|
|
|
*lpTmp = (BYTE)(wUnicodeChar & 0x00ff);
|
|
*(lpTmp+1) = (BYTE)((wUnicodeChar >> 8) & 0x00ff);
|
|
|
|
lpStart += sizeof(WORD) + sizeof(WORD) + lpEudcHeader->cMethodKeySize;
|
|
|
|
}
|
|
|
|
UnmapViewOfFile(lpTblFile);
|
|
|
|
CloseHandle(hTblMap);
|
|
|
|
CloseHandle(hTblFile);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL GetEUDCHeader(
|
|
LPCTSTR EudcFileName,
|
|
USRDICIMHDR *EudcHeader)
|
|
{
|
|
BOOL Result = FALSE;
|
|
|
|
HANDLE EudcFileHandle, EudcMappingHandle;
|
|
LPBYTE EudcPtr;
|
|
|
|
EudcFileHandle = CreateFile(EudcFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (EudcFileHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
DebugMsg(("GetEUDCHeader, EudcFileHandle == INVALID_HANDLE_VALUE !\r\n"));
|
|
|
|
goto Exit1;
|
|
}
|
|
|
|
EudcMappingHandle = CreateFileMapping(EudcFileHandle,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL);
|
|
if ( !EudcMappingHandle ) {
|
|
|
|
DebugMsg(("GetEUDCHeader, EudcMappingHandle == INVALID_HANDLE_VALUE !\r\n"));
|
|
|
|
goto Exit2;
|
|
}
|
|
|
|
EudcPtr = (LPBYTE) MapViewOfFile(EudcMappingHandle, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
if ( ! EudcPtr ) {
|
|
|
|
DebugMsg(("GetEUDCHeader, ! EudcPtr !\r\n"));
|
|
|
|
goto Exit3;
|
|
}
|
|
|
|
CopyMemory(EudcHeader,EudcPtr,sizeof(USRDICIMHDR));
|
|
|
|
Result = TRUE;
|
|
|
|
UnmapViewOfFile(EudcPtr);
|
|
|
|
Exit3:
|
|
CloseHandle(EudcMappingHandle);
|
|
|
|
Exit2:
|
|
CloseHandle(EudcFileHandle);
|
|
|
|
Exit1:
|
|
return Result;
|
|
}
|
|
|
|
BYTE WinAR30SeqMapTable(BYTE SeqCode)
|
|
{
|
|
INT i;
|
|
INT NumOfKey = sizeof(WinAR30MapTable) / (sizeof (BYTE) * 2);
|
|
|
|
for (i = 0; i < NumOfKey; i++) {
|
|
|
|
if (WinAR30MapTable[i * 2] == SeqCode) {
|
|
|
|
return WinAR30MapTable[i * 2+1];
|
|
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL WinAR30ConvertWorker(
|
|
LPBYTE EudcPtr)
|
|
{
|
|
USRDICIMHDR *EudcHeader;
|
|
|
|
WinAR30EUDC95 *EudcDataPtr95;
|
|
WinAR30EUDCNT *EudcDataPtrNT;
|
|
|
|
INT i;
|
|
|
|
DebugMsg(("WinAR30ConvertWorker, ! Start !\r\n"));
|
|
|
|
if (! EudcPtr) {
|
|
|
|
DebugMsg(("WinAR30ConvertWorker, ! EudcPtr !\r\n"));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EudcHeader = (USRDICIMHDR *) EudcPtr;
|
|
|
|
EudcHeader->cMethodKeySize = 5;
|
|
|
|
EudcDataPtr95 = (WinAR30EUDC95 *) (EudcPtr + EudcHeader->uHeaderSize);
|
|
EudcDataPtrNT = (WinAR30EUDCNT *) (EudcPtr + EudcHeader->uHeaderSize);
|
|
|
|
DebugMsg(("Sizeof WinAR30EUDC95 = %d WinAR30EUDCNT = %d ! \r\n",sizeof(WinAR30EUDC95),sizeof(WinAR30EUDCNT)));
|
|
|
|
for (i=(INT)(EudcHeader->ulTableCount -1) ; i >= 0 ; i--) {
|
|
EudcDataPtrNT[i].Seq[4] = 0;
|
|
EudcDataPtrNT[i].Seq[3] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[3]);
|
|
EudcDataPtrNT[i].Seq[2] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[2]);
|
|
EudcDataPtrNT[i].Seq[1] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[1]);
|
|
EudcDataPtrNT[i].Seq[0] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[0]);
|
|
EudcDataPtrNT[i].Code = EudcDataPtr95[i].Code;
|
|
EudcDataPtrNT[i].ID = EudcDataPtr95[i].ID;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WinAR30Convert(
|
|
LPCTSTR EudcFileName,
|
|
USRDICIMHDR *EudcHeader)
|
|
{
|
|
INT NewFileSize;
|
|
|
|
HANDLE EudcFileHandle, EudcMappingHandle;
|
|
LPBYTE EudcPtr;
|
|
|
|
BOOL Result = FALSE;
|
|
|
|
if (! EudcHeader) {
|
|
goto Exit1;
|
|
}
|
|
|
|
NewFileSize = EudcHeader->uHeaderSize + EudcHeader->ulTableCount * sizeof(WinAR30EUDCNT);
|
|
|
|
EudcFileHandle = CreateFile(EudcFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (EudcFileHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
DebugMsg(("WinAR30Convert, EudcFileHandle == INVALID_HANDLE_VALUE !\r\n"));
|
|
|
|
goto Exit1;
|
|
}
|
|
|
|
EudcMappingHandle = CreateFileMapping(EudcFileHandle,
|
|
NULL,
|
|
PAGE_READWRITE,
|
|
0,
|
|
NewFileSize,
|
|
NULL);
|
|
if ( !EudcMappingHandle ) {
|
|
|
|
DebugMsg(("WinAR30Convert, EudcMappingHandle == INVALID_HANDLE_VALUE !\r\n"));
|
|
|
|
goto Exit2;
|
|
}
|
|
|
|
EudcPtr = (LPBYTE) MapViewOfFile(EudcMappingHandle, FILE_MAP_WRITE, 0, 0, 0);
|
|
|
|
if ( !EudcPtr ) {
|
|
|
|
DebugMsg(("GetEUDCHeader, ! EudcPtr !\r\n"));
|
|
|
|
goto Exit3;
|
|
}
|
|
|
|
Result = WinAR30ConvertWorker(EudcPtr);
|
|
|
|
UnmapViewOfFile(EudcPtr);
|
|
|
|
Exit3:
|
|
CloseHandle(EudcMappingHandle);
|
|
|
|
Exit2:
|
|
CloseHandle(EudcFileHandle);
|
|
|
|
Exit1:
|
|
return Result;
|
|
}
|
|
|
|
BOOL FixWinAR30EUDCTable(
|
|
LPCTSTR EudcFileName)
|
|
/*
|
|
Main function to fix WinAR30 EUDC table
|
|
|
|
Input : Eudc File Name (include path)
|
|
*/
|
|
{
|
|
USRDICIMHDR EudcHeader;
|
|
|
|
BOOL Result = FALSE;
|
|
|
|
|
|
if (! GetEUDCHeader(EudcFileName,&EudcHeader)) {
|
|
|
|
DebugMsg(("FixWinAR30EUDCTable,GetEUDCHeader(%s,..) failed!\r\n",EudcFileName));
|
|
|
|
goto Exit1;
|
|
|
|
} else {
|
|
|
|
DebugMsg(("FixWinAR30EUDCTable,GetEUDCHeader(%s,..) OK!\r\n",EudcFileName));
|
|
}
|
|
|
|
DebugMsg(("FixWinAR30EUDCTable,EudcHeader.cMethodKeySize = (%d)!\r\n",EudcHeader.cMethodKeySize));
|
|
|
|
if (EudcHeader.cMethodKeySize != 4) {
|
|
|
|
goto Exit1;
|
|
}
|
|
|
|
DebugMsg(("FixWinAR30EUDCTable,EudcHeader.ulTableCount = (%d) !\r\n",EudcHeader.ulTableCount));
|
|
|
|
if (EudcHeader.ulTableCount == 0) {
|
|
|
|
goto Exit1;
|
|
}
|
|
|
|
Result = WinAR30Convert(EudcFileName, &EudcHeader);
|
|
|
|
Exit1:
|
|
return Result;
|
|
}
|
|
|
|
BOOL GetEUDCPathInRegistry(
|
|
HKEY UserRegKey,
|
|
LPCTSTR EUDCName,
|
|
LPCTSTR EUDCPathValueName,
|
|
LPTSTR EUDCFileName)
|
|
{
|
|
HKEY hKey;
|
|
|
|
TCHAR IMERegPath[MAX_PATH] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\");
|
|
LONG RetVal;
|
|
LONG SizeOfFileName;
|
|
|
|
if (! EUDCName || ! EUDCFileName) {
|
|
return FALSE;
|
|
}
|
|
|
|
ConcatenatePaths(IMERegPath,EUDCName,MAX_PATH);
|
|
|
|
|
|
RetVal = RegOpenKey(UserRegKey,
|
|
IMERegPath,
|
|
&hKey);
|
|
|
|
if (RetVal != ERROR_SUCCESS) {
|
|
//
|
|
// it's ok, not every IME has created eudc table
|
|
//
|
|
DebugMsg(("ImeEudcConvert::GetEUDCPathInRegistry,No table in %s !\r\n",EUDCName));
|
|
return FALSE;
|
|
}
|
|
|
|
SizeOfFileName = MAX_PATH;
|
|
RetVal = RegQueryValueEx(hKey,
|
|
EUDCPathValueName,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) EUDCFileName,
|
|
&SizeOfFileName);
|
|
|
|
if (RetVal == ERROR_SUCCESS) {
|
|
DebugMsg(("ImeEudcConvert::GetEUDCPathInRegistry,IME Table path = %s !\r\n",EUDCFileName));
|
|
} else {
|
|
DebugMsg(("ImeEudcConvert::GetEUDCPathInRegistry,No IME table path %s !\r\n",EUDCName));
|
|
}
|
|
return (RetVal == ERROR_SUCCESS);
|
|
}
|
|
|
|
UINT CreateNestedDirectory(LPCTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
{
|
|
TCHAR szDirectory[2*MAX_PATH];
|
|
LPTSTR lpEnd;
|
|
|
|
//
|
|
// Check for NULL pointer
|
|
//
|
|
|
|
if (!lpDirectory || !(*lpDirectory)) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// First, see if we can create the directory without having
|
|
// to build parent directories.
|
|
//
|
|
|
|
if (CreateDirectory (lpDirectory, lpSecurityAttributes)) {
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// If this directory exists already, this is OK too.
|
|
//
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
return ERROR_ALREADY_EXISTS;
|
|
}
|
|
|
|
|
|
//
|
|
// No luck, copy the string to a buffer we can munge
|
|
//
|
|
|
|
lstrcpy (szDirectory, lpDirectory);
|
|
|
|
|
|
//
|
|
// Find the first subdirectory name
|
|
//
|
|
|
|
lpEnd = szDirectory;
|
|
|
|
if (szDirectory[1] == TEXT(':')) {
|
|
lpEnd += 3;
|
|
} else if (szDirectory[1] == TEXT('\\')) {
|
|
|
|
lpEnd += 2;
|
|
|
|
while (*lpEnd && *lpEnd != TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
if (!(*lpEnd)) {
|
|
return 0;
|
|
}
|
|
|
|
lpEnd++;
|
|
|
|
while (*lpEnd && *lpEnd != TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
if (!(*lpEnd)) {
|
|
return 0;
|
|
}
|
|
|
|
lpEnd++;
|
|
|
|
} else if (szDirectory[0] == TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
while (*lpEnd) {
|
|
|
|
while (*lpEnd && *lpEnd != TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
if (*lpEnd == TEXT('\\')) {
|
|
*lpEnd = TEXT('\0');
|
|
|
|
if (!CreateDirectory (szDirectory, NULL)) {
|
|
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
DebugMsg((TEXT("CreateNestedDirectory: CreateDirectory failed with %d."), GetLastError()));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
*lpEnd = TEXT('\\');
|
|
lpEnd++;
|
|
}
|
|
}
|
|
|
|
|
|
if (CreateDirectory (szDirectory, lpSecurityAttributes)) {
|
|
return 1;
|
|
}
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
return ERROR_ALREADY_EXISTS;
|
|
}
|
|
|
|
|
|
DebugMsg((TEXT("CreateNestedDirectory: Failed to create the directory with error %d."), GetLastError()));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
BOOL
|
|
ConcatenatePaths(
|
|
LPTSTR Target,
|
|
LPCTSTR Path,
|
|
UINT TargetBufferSize
|
|
)
|
|
|
|
{
|
|
UINT TargetLength,PathLength;
|
|
BOOL TrailingBackslash,LeadingBackslash;
|
|
UINT EndingLength;
|
|
|
|
TargetLength = lstrlen(Target);
|
|
PathLength = lstrlen(Path);
|
|
|
|
//
|
|
// See whether the target has a trailing backslash.
|
|
//
|
|
if(TargetLength && (Target[TargetLength-1] == TEXT('\\'))) {
|
|
TrailingBackslash = TRUE;
|
|
TargetLength--;
|
|
} else {
|
|
TrailingBackslash = FALSE;
|
|
}
|
|
|
|
//
|
|
// See whether the path has a leading backshash.
|
|
//
|
|
if(Path[0] == TEXT('\\')) {
|
|
LeadingBackslash = TRUE;
|
|
PathLength--;
|
|
} else {
|
|
LeadingBackslash = FALSE;
|
|
}
|
|
|
|
//
|
|
// Calculate the ending length, which is equal to the sum of
|
|
// the length of the two strings modulo leading/trailing
|
|
// backslashes, plus one path separator, plus a nul.
|
|
//
|
|
EndingLength = TargetLength + PathLength + 2;
|
|
|
|
if(!LeadingBackslash && (TargetLength < TargetBufferSize)) {
|
|
Target[TargetLength++] = TEXT('\\');
|
|
}
|
|
|
|
if(TargetBufferSize > TargetLength) {
|
|
lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength);
|
|
}
|
|
|
|
//
|
|
// Make sure the buffer is nul terminated in all cases.
|
|
//
|
|
if (TargetBufferSize) {
|
|
Target[TargetBufferSize-1] = 0;
|
|
}
|
|
|
|
return(EndingLength <= TargetBufferSize);
|
|
}
|
|
|
|
#define CSIDL_APPDATA 0x001a
|
|
BOOL (* MYSHGetSpecialFolderPathA) (HWND , LPTSTR , int , BOOL );
|
|
|
|
BOOL GetApplicationFolderPath(LPTSTR lpszFolder,UINT nLen)
|
|
{
|
|
HINSTANCE hDll;
|
|
BOOL bGotPath = FALSE;
|
|
|
|
hDll = LoadLibrary(TEXT("shell32.dll"));
|
|
if (hDll) {
|
|
(FARPROC) MYSHGetSpecialFolderPathA = GetProcAddress(hDll,"SHGetSpecialFolderPathA");
|
|
if (MYSHGetSpecialFolderPathA) {
|
|
if (MYSHGetSpecialFolderPathA(NULL, lpszFolder, CSIDL_APPDATA , FALSE)){
|
|
DebugMsg((TEXT("[GetApplicationFolder] SHGetSpecialFolderPath %s !\n"),lpszFolder));
|
|
bGotPath = TRUE;
|
|
} else {
|
|
DebugMsg((TEXT("[GetApplicationFolder] SHGetSpecialFolderPath failed !\n")));
|
|
}
|
|
} else {
|
|
DebugMsg((TEXT("[GetApplicationFolder] GetProc of SHGetSpecialFolderPath failed !\n")));
|
|
}
|
|
FreeLibrary(hDll);
|
|
} else {
|
|
DebugMsg((TEXT("[GetApplicationFolder] Load shell32.dll failed ! %d\n"),GetLastError()));
|
|
}
|
|
|
|
if (! bGotPath) {
|
|
ExpandEnvironmentStrings(TEXT("%userprofile%"),lpszFolder,nLen);
|
|
lstrcat(lpszFolder,TEXT("\\Application data"));
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GetNewPath(
|
|
LPTSTR lpszNewPath,
|
|
LPCTSTR lpszFileName,
|
|
LPCTSTR lpszClass)
|
|
/*
|
|
OUT lpszNewPath : e.q. \winnt\profiles\administrator\application data\Micorsoft\ime\chajei
|
|
IN lpszFileName : e.q. \winnt\chajei.tbl
|
|
IN lpszClass : e.q. Micorsoft\ime\chajei\chajei.tbl
|
|
|
|
lpszFileName (e.q. \winnt\phon.tbl) -> get base name (e.q. phon.tbl) ->
|
|
|
|
get Application folder (e.q. \winnt\profiles\administrator\application data) ->
|
|
|
|
create directory -> concat lpszClass (e.q. Micorsoft\ime\chajei)
|
|
|
|
Then we get lpszNewPath = \winnt\profiles\administrator\application data\Micorsoft\ime\chajei
|
|
*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPTSTR lpszBaseName;
|
|
|
|
DebugMsg((TEXT("[GetNewPath>>>] Param lpszFileName = %s !\n"),lpszFileName));
|
|
DebugMsg((TEXT("[GetNewPath>>>] Param lpszClass = %s !\n"),lpszClass));
|
|
|
|
GetApplicationFolderPath(lpszNewPath,MAX_PATH);
|
|
|
|
ConcatenatePaths(lpszNewPath, lpszClass,MAX_PATH);
|
|
|
|
if (! CreateNestedDirectory(lpszNewPath,NULL)) {
|
|
DebugMsg((TEXT("[GetNewPath] CreateDirectory %s ! %X\n"),lpszNewPath,GetLastError()));
|
|
}
|
|
if ((lpszBaseName = _tcsrchr(lpszFileName,TEXT('\\'))) != NULL) {
|
|
ConcatenatePaths(lpszNewPath,lpszBaseName,MAX_PATH);
|
|
} else {
|
|
ConcatenatePaths(lpszNewPath,lpszFileName,MAX_PATH);
|
|
DebugMsg((TEXT("[GetNewPath] can't find \\ in %s !\n"),lpszFileName));
|
|
}
|
|
|
|
DebugMsg((TEXT("[GetNewPath] return %s !\n"),lpszNewPath));
|
|
|
|
bRet = TRUE;
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
BOOL MigrateImeEUDCTables(HKEY UserRegKey)
|
|
{
|
|
LONG returnCode = ERROR_SUCCESS;
|
|
|
|
UINT uACP;
|
|
UINT uNumOfTables;
|
|
UINT i;
|
|
LPTABLELIST lpTableList;
|
|
TCHAR szIMERegPath[MAX_PATH] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\");
|
|
|
|
LPTSTR lpszEnd;
|
|
TCHAR szPathBuf[MAX_PATH];
|
|
LONG lPathBuf;
|
|
TCHAR szEudcRegValName[MAX_PATH];
|
|
HKEY hKey;
|
|
LONG lRetVal;
|
|
|
|
|
|
TABLELIST IMETableListCHT[] = {
|
|
{IDS_CHT_TABLE1,TEXT("")},
|
|
{IDS_CHT_TABLE2,TEXT("")},
|
|
{IDS_CHT_TABLE3,TEXT("")},
|
|
{IDS_CHT_TABLE4,TEXT("")},
|
|
{IDS_CHT_TABLE5,TEXT("")}
|
|
};
|
|
|
|
TABLELIST IMETableListCHS[] = {
|
|
{IDS_CHS_TABLE1,TEXT("")},
|
|
{IDS_CHS_TABLE2,TEXT("")},
|
|
{IDS_CHS_TABLE3,TEXT("")},
|
|
// {IDS_CHS_TABLE4,TEXT("")},
|
|
{IDS_CHS_TABLE5,TEXT("")},
|
|
{IDS_CHS_TABLE6,TEXT("")},
|
|
{IDS_CHS_TABLE7,TEXT("")}
|
|
// {IDS_CHS_TABLE8,TEXT("")}
|
|
};
|
|
|
|
|
|
if (!UserRegKey) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 1. Decide which language and prepare IME table list
|
|
//
|
|
uACP = GetACP();
|
|
|
|
switch(uACP) {
|
|
case CP_CHINESE_GB: // Simplied Chinese
|
|
|
|
|
|
lpTableList = IMETableListCHS;
|
|
uNumOfTables = sizeof(IMETableListCHS) / sizeof(TABLELIST);
|
|
|
|
lstrcpy(szEudcRegValName,TEXT("EUDCDictName"));
|
|
|
|
break;
|
|
|
|
case CP_CHINESE_BIG5: // Traditional Chinese
|
|
lpTableList = IMETableListCHT;
|
|
uNumOfTables = sizeof(IMETableListCHT) / sizeof(TABLELIST);
|
|
|
|
lstrcpy(szEudcRegValName,TEXT("User Dictionary"));
|
|
|
|
break;
|
|
default:
|
|
DebugMsg(("MigrateImeEUDCTables::MigrateImeEUDCTables failed, wrong system code page !\r\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 2. load IME name from resource
|
|
//
|
|
for (i=0; i<uNumOfTables; i++) {
|
|
if (!LoadString(g_hInstance,lpTableList[i].nResID,lpTableList[i].szIMEName,MAX_PATH)) {
|
|
DebugMsg(("MigrateImeEUDCTables failed, MigrateImeEUDCTables, load string failed !\r\n"));
|
|
return FALSE;
|
|
}
|
|
else {
|
|
DebugMsg(("MigrateImeEUDCTables , MigrateImeEUDCTables, load string [%s] !\r\n",lpTableList[i].szIMEName));
|
|
}
|
|
}
|
|
|
|
//
|
|
// 3. Read eudc table locaion from registry
|
|
//
|
|
lpszEnd = &szIMERegPath[lstrlen(szIMERegPath)];
|
|
|
|
for (i=0; i<uNumOfTables; i++) {
|
|
*lpszEnd = TEXT('\0');
|
|
lstrcat(szIMERegPath,lpTableList[i].szIMEName);
|
|
DebugMsg(("MigrateImeEUDCTables , Open registry, szIMERegPath [%s] !\r\n",szIMERegPath));
|
|
|
|
lRetVal = RegOpenKey(UserRegKey,
|
|
szIMERegPath,
|
|
&hKey);
|
|
|
|
if (lRetVal != ERROR_SUCCESS) {
|
|
//
|
|
// it's ok, not every IME has created eudc table
|
|
//
|
|
DebugMsg(("MigrateImeEUDCTables,No table in %s ! But it's fine\r\n",szIMERegPath));
|
|
continue;
|
|
}
|
|
|
|
lPathBuf = sizeof(szPathBuf);
|
|
lRetVal = RegQueryValueEx(hKey,
|
|
szEudcRegValName,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) szPathBuf,
|
|
&lPathBuf);
|
|
|
|
if (lRetVal == ERROR_SUCCESS) {
|
|
if (! ImeEudcConvert(szPathBuf)) {
|
|
DebugMsg(("MigrateImeEUDCTables,call ImeEudcConvert(%s) failed !\r\n",szPathBuf));
|
|
}
|
|
else {
|
|
DebugMsg(("MigrateImeEUDCTables,call ImeEudcConvert(%s) OK !\r\n",szPathBuf));
|
|
}
|
|
}
|
|
else {
|
|
DebugMsg(("MigrateImeEUDCTables,RegQueryValue for %s failed !\r\n",szEudcRegValName));
|
|
}
|
|
|
|
if (uACP == CP_CHINESE_BIG5) {
|
|
|
|
DebugMsg(("MigrateImeEUDCTables,Test WINAR30 WINAR30 == %s !\r\n",lpTableList[i].szIMEName));
|
|
|
|
if (lstrcmpi(lpTableList[i].szIMEName,TEXT("WINAR30")) == 0) {
|
|
if (FixWinAR30EUDCTable(szPathBuf)) {
|
|
DebugMsg(("MigrateImeEUDCTables,FixWinAR30EUDCTable OK !\r\n"));
|
|
} else {
|
|
DebugMsg(("MigrateImeEUDCTables,FixWinAR30EUDCTable Failed !\r\n"));
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// CHS's memory map file use "\" which cause bug
|
|
//
|
|
// replace "\" with "_"
|
|
//
|
|
if (uACP == CP_CHINESE_GB) {
|
|
lRetVal = RegQueryValueEx(hKey,
|
|
TEXT("EUDCMapFileName"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) szPathBuf,
|
|
&lPathBuf);
|
|
if (lRetVal == ERROR_SUCCESS) {
|
|
DebugMsg(("MigrateImeEUDCTables,Org MemMap = %s !\r\n",szPathBuf));
|
|
|
|
for (i=0; i<(UINT) lPathBuf; i++) {
|
|
if (szPathBuf[i] == '\\') {
|
|
szPathBuf[i] = '-';
|
|
}
|
|
}
|
|
|
|
DebugMsg(("MigrateImeEUDCTables,fixed MemMap = %s !\r\n",szPathBuf));
|
|
|
|
lRetVal = RegSetValueEx(hKey,
|
|
TEXT("EUDCMapFileName"),
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE) szPathBuf,
|
|
(lstrlen(szPathBuf)+1)*sizeof(TCHAR));
|
|
|
|
if (lRetVal != ERROR_SUCCESS) {
|
|
DebugMsg(("MigrateImeEUDCTables,fix CHS MemMap [%s]reg,SetReg failed [%d]!\r\n",szPathBuf,lRetVal));
|
|
} else {
|
|
DebugMsg(("MigrateImeEUDCTables,fix CHS MemMap [%s] reg,SetReg OK !\r\n",szPathBuf));
|
|
}
|
|
|
|
} else {
|
|
DebugMsg(("MigrateImeEUDCTables,MemMap, QuwryValue EUDCMapFileName failed [%d]!\r\n",lRetVal));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
DebugMsg(("MigrateImeEUDCTables , Finished !\r\n"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LPPATHPAIR g_RememberedPath = NULL;
|
|
UINT g_NumofRememberedPath = 0;
|
|
|
|
BOOL RememberPath(LPCTSTR szDstFile,LPCTSTR szSrcFile)
|
|
{
|
|
//
|
|
// only single thread executes this function, skip synchronization protection
|
|
//
|
|
BOOL bRet = FALSE;
|
|
|
|
if (g_NumofRememberedPath == 0) {
|
|
g_RememberedPath = (LPPATHPAIR) malloc(sizeof(PATHPAIR));
|
|
if (! g_RememberedPath) {
|
|
DebugMsg(("RememberPath , alloc memory failed !\r\n"));
|
|
goto Exit1;
|
|
}
|
|
} else {
|
|
g_RememberedPath = (LPPATHPAIR) realloc(g_RememberedPath,(g_NumofRememberedPath + 1) * sizeof(PATHPAIR));
|
|
if (! g_RememberedPath) {
|
|
DebugMsg(("RememberPath , alloc memory failed !\r\n"));
|
|
goto Exit1;
|
|
}
|
|
}
|
|
|
|
lstrcpy(g_RememberedPath[g_NumofRememberedPath].szSrcFile,szSrcFile);
|
|
lstrcpy(g_RememberedPath[g_NumofRememberedPath].szDstFile,szDstFile);
|
|
g_NumofRememberedPath++;
|
|
|
|
bRet = TRUE;
|
|
Exit1:
|
|
return bRet;
|
|
}
|
|
|
|
BOOL MigrateImeEUDCTables2(HKEY UserRegKey)
|
|
/*++
|
|
CHS : if xxx.emb exist, it needs to be duplicated to each user's AP directory
|
|
|
|
CHT : only move emb files that specified in user's "User Dictionary" Reg value
|
|
|
|
--*/
|
|
{
|
|
LONG returnCode = ERROR_SUCCESS;
|
|
|
|
UINT uACP;
|
|
UINT uNumOfTables;
|
|
UINT i;
|
|
LPTABLELIST lpTableList;
|
|
|
|
TCHAR szIMERegPath[MAX_PATH] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\");
|
|
LPTSTR lpszEnd;
|
|
TCHAR szOldDataFile[MAX_PATH];
|
|
LONG lPathBuf;
|
|
TCHAR szEudcRegValName[MAX_PATH];
|
|
HKEY hKey;
|
|
LONG lRetVal;
|
|
|
|
TCHAR szNewDataFile[MAX_PATH];
|
|
TCHAR szClassPath[MAX_PATH];
|
|
|
|
TABLELIST IMETableListCHT[] = {
|
|
{IDS_CHT_TABLE1,TEXT("")},
|
|
{IDS_CHT_TABLE2,TEXT("")},
|
|
{IDS_CHT_TABLE3,TEXT("")},
|
|
{IDS_CHT_TABLE4,TEXT("")},
|
|
{IDS_CHT_TABLE5,TEXT("")}
|
|
};
|
|
|
|
TABLELIST IMETableListCHS[] = {
|
|
{IDS_CHS_TABLE1,TEXT("")},
|
|
{IDS_CHS_TABLE2,TEXT("")},
|
|
{IDS_CHS_TABLE3,TEXT("")}
|
|
};
|
|
|
|
TABLELIST IMETableListCHSENG[] = {
|
|
{IDS_CHS_ENG_TABLE1,TEXT("")},
|
|
{IDS_CHS_ENG_TABLE2,TEXT("")},
|
|
{IDS_CHS_ENG_TABLE3,TEXT("")}
|
|
};
|
|
|
|
|
|
if (!UserRegKey) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 1. Decide which language and prepare IME table list
|
|
//
|
|
uACP = GetACP();
|
|
|
|
switch(uACP) {
|
|
case CP_CHINESE_GB: // Simplied Chinese
|
|
|
|
|
|
lpTableList = IMETableListCHS;
|
|
uNumOfTables = sizeof(IMETableListCHS) / sizeof(TABLELIST);
|
|
|
|
lstrcpy(szEudcRegValName,TEXT("EUDCDictName"));
|
|
|
|
break;
|
|
|
|
case CP_CHINESE_BIG5: // Traditional Chinese
|
|
lpTableList = IMETableListCHT;
|
|
uNumOfTables = sizeof(IMETableListCHT) / sizeof(TABLELIST);
|
|
|
|
lstrcpy(szEudcRegValName,TEXT("User Dictionary"));
|
|
|
|
break;
|
|
default:
|
|
DebugMsg(("MigrateImeEUDCTables2 failed, wrong system code page !\r\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 2. load IME name from resource
|
|
//
|
|
for (i=0; i<uNumOfTables; i++) {
|
|
if (!LoadString(g_hInstance,lpTableList[i].nResID,lpTableList[i].szIMEName,MAX_PATH)) {
|
|
DebugMsg(("MigrateImeEUDCTables2 failed, MigrateImeEUDCTables, load string failed !\r\n"));
|
|
return FALSE;
|
|
}
|
|
else {
|
|
DebugMsg(("MigrateImeEUDCTables2 , MigrateImeEUDCTables, load string [%s] !\r\n",lpTableList[i].szIMEName));
|
|
}
|
|
if (uACP == CP_CHINESE_GB) {
|
|
if (!LoadString(g_hInstance,IMETableListCHSENG[i].nResID,IMETableListCHSENG[i].szIMEName,MAX_PATH)) {
|
|
DebugMsg(("MigrateImeEUDCTables2 failed, MigrateImeEUDCTables, load string failed !\r\n"));
|
|
return FALSE;
|
|
}
|
|
else {
|
|
DebugMsg(("MigrateImeEUDCTables2 , MigrateImeEUDCTables, load string [%s] !\r\n",lpTableList[i].szIMEName));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// 3. Read eudc table locaion from registry
|
|
//
|
|
|
|
|
|
lpszEnd = &szIMERegPath[lstrlen(szIMERegPath)];
|
|
|
|
for (i=0; i<uNumOfTables; i++) {
|
|
|
|
if (uACP == CP_CHINESE_GB) {
|
|
TCHAR szEMBName[MAX_PATH];
|
|
|
|
lstrcpy(szEMBName,IMETableListCHSENG[i].szIMEName);
|
|
lstrcat(szEMBName,TEXT(".emb"));
|
|
|
|
lstrcpy(szOldDataFile,ImeDataDirectory);
|
|
|
|
ConcatenatePaths(szOldDataFile,szEMBName,sizeof(szOldDataFile));
|
|
|
|
if (GetFileAttributes(szOldDataFile) == 0xFFFFFFFF) {
|
|
DebugMsg(("MigrateImeEUDCTables2 , No %s EMB, continue next !\r\n",szOldDataFile));
|
|
continue;
|
|
}
|
|
|
|
lstrcpy(szClassPath,TEXT("Microsoft\\IME\\"));
|
|
lstrcat(szClassPath,IMETableListCHSENG[i].szIMEName);
|
|
|
|
GetSystemDirectory(szOldDataFile, sizeof(szOldDataFile));
|
|
ConcatenatePaths(szOldDataFile,szEMBName,sizeof(szOldDataFile));
|
|
|
|
if (GetNewPath(szNewDataFile,
|
|
szOldDataFile,
|
|
szClassPath)) {
|
|
RememberPath(szNewDataFile,szOldDataFile);
|
|
}
|
|
}
|
|
|
|
|
|
*lpszEnd = TEXT('\0');
|
|
lstrcat(szIMERegPath,lpTableList[i].szIMEName);
|
|
DebugMsg(("MigrateImeEUDCTables2 , Open registry, szIMERegPath [%s] !\r\n",szIMERegPath));
|
|
|
|
lRetVal = RegOpenKey(UserRegKey,
|
|
szIMERegPath,
|
|
&hKey);
|
|
|
|
if (lRetVal != ERROR_SUCCESS) {
|
|
//
|
|
// it's ok, not every IME has created eudc table
|
|
//
|
|
DebugMsg(("MigrateImeEUDCTables2,No table in %s ! But it's fine\r\n",szIMERegPath));
|
|
continue;
|
|
}
|
|
|
|
lPathBuf = sizeof(szOldDataFile);
|
|
lRetVal = RegQueryValueEx(hKey,
|
|
szEudcRegValName,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) szOldDataFile,
|
|
&lPathBuf);
|
|
|
|
if (lRetVal == ERROR_SUCCESS) {
|
|
if (uACP == CP_CHINESE_BIG5) {
|
|
|
|
lstrcpy(szClassPath,TEXT("Microsoft\\IME\\"));
|
|
lstrcat(szClassPath,lpTableList[i].szIMEName);
|
|
|
|
if (GetNewPath(szNewDataFile,
|
|
szOldDataFile,
|
|
szClassPath)) {
|
|
RememberPath(szNewDataFile,szOldDataFile);
|
|
}
|
|
}
|
|
|
|
//
|
|
// at this step, both CHT's and CHS's szNewDataFile is ready
|
|
//
|
|
lRetVal = RegSetValueEx(hKey,
|
|
szEudcRegValName,
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE) szNewDataFile,
|
|
(lstrlen(szNewDataFile)+1) * sizeof (TCHAR));
|
|
|
|
if (lRetVal != ERROR_SUCCESS) {
|
|
DebugMsg(("MigrateImeEUDCTables2,RegSetValueEx %s,%x ! \r\n",szNewDataFile,GetLastError()));
|
|
}
|
|
}
|
|
else {
|
|
DebugMsg(("MigrateImeEUDCTables2,RegQueryValue for %s failed !\r\n",szEudcRegValName));
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
DebugMsg(("MigrateImeEUDCTables2 , Finished !\r\n"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL MovePerUserIMEData()
|
|
{
|
|
UINT i;
|
|
|
|
for (i=0; i< g_NumofRememberedPath; i++) {
|
|
if (CopyFile(g_RememberedPath[i].szSrcFile,g_RememberedPath[i].szDstFile,FALSE)) {
|
|
DebugMsg(("MovePerUserIMEData , Copy %s to %s OK !\r\n",g_RememberedPath[i].szSrcFile,g_RememberedPath[i].szDstFile));
|
|
} else {
|
|
DebugMsg(("MovePerUserIMEData , Copy %s to %s failed !\r\n",g_RememberedPath[i].szSrcFile,g_RememberedPath[i].szDstFile));
|
|
}
|
|
}
|
|
|
|
if (g_RememberedPath) {
|
|
free (g_RememberedPath);
|
|
g_RememberedPath = NULL;
|
|
g_NumofRememberedPath = 0;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|