Source code of Windows XP (NT5)
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

  1. #include <windows.h>
  2. #include <setupapi.h>
  3. #include <tchar.h>
  4. #include <malloc.h>
  5. #include "resource.h"
  6. #include "common.h"
  7. TCHAR szMsgBuf[MAX_PATH];
  8. #pragma pack(push, USERDIC, 1 )
  9. //
  10. // Cht/Chs EUDC IME table Header Format
  11. //
  12. typedef struct tagUSRDICIMHDR {
  13. WORD uHeaderSize; // 0x00
  14. BYTE idUserCharInfoSign[8]; // 0x02
  15. BYTE idMajor; // 0x0A
  16. BYTE idMinor; // 0x0B
  17. DWORD ulTableCount; // 0x0C
  18. WORD cMethodKeySize; // 0x10
  19. BYTE uchBankID; // 0x12
  20. WORD idInternalBankID; // 0x13
  21. BYTE achCMEXReserved1[43]; // 0x15
  22. WORD uInfoSize; // 0x40
  23. BYTE chCmdKey; // 0x42
  24. BYTE idStlnUpd; // 0x43
  25. BYTE cbField; // 0x44
  26. WORD idCP; // 0x45
  27. BYTE achMethodName[6]; // 0x47
  28. BYTE achCSIReserved2[51]; // 0x4D
  29. BYTE achCopyRightMsg[128]; // 0x80
  30. } USRDICIMHDR;
  31. typedef struct tagWinAR30EUDC95 {
  32. WORD ID;
  33. WORD Code;
  34. BYTE Seq[4];
  35. } WinAR30EUDC95;
  36. typedef struct tagWinAR30EUDCNT {
  37. WORD ID;
  38. WORD Code;
  39. BYTE Seq[5];
  40. } WinAR30EUDCNT;
  41. #pragma pack(pop, USERDIC)
  42. typedef struct tagTABLIST {
  43. UINT nResID;
  44. TCHAR szIMEName[MAX_PATH];
  45. } TABLELIST,*LPTABLELIST;
  46. BYTE WinAR30MapTable[] = {0x00, 0x00 ,
  47. 0x3F, 0x3F ,
  48. 0x1E, 0x01 ,
  49. 0x1B, 0x02 ,
  50. 0x1C, 0x03 ,
  51. 0x1D, 0x04 ,
  52. 0x3E, 0x3E ,
  53. 0x01, 0x05 ,
  54. 0x02, 0x06 ,
  55. 0x03, 0x07 ,
  56. 0x04, 0x08 ,
  57. 0x05, 0x09 ,
  58. 0x06, 0x0a ,
  59. 0x07, 0x0b ,
  60. 0x08, 0x0c ,
  61. 0x09, 0x0d ,
  62. 0x0A, 0x0e ,
  63. 0x0B, 0x0f ,
  64. 0x0C, 0x10 ,
  65. 0x0D, 0x11 ,
  66. 0x0E, 0x12 ,
  67. 0x0F, 0x13 ,
  68. 0x10, 0x14 ,
  69. 0x11, 0x15 ,
  70. 0x12, 0x16 ,
  71. 0x13, 0x17 ,
  72. 0x14, 0x18 ,
  73. 0x15, 0x19 ,
  74. 0x16, 0x1a ,
  75. 0x17, 0x1b ,
  76. 0x18, 0x1c ,
  77. 0x19, 0x1d ,
  78. 0x1A, 0x1e };
  79. // ----------------------------------------------------------------------------
  80. // An EUDC IME table comprises a Header and lots of records, the number of
  81. // records is ulTableCount, and every record has following format:
  82. //
  83. // <WORD1> <WORD2> <SEQCODES>
  84. //
  85. // <WORD1>: Identical between Win95 and NT.
  86. // WORD2 stands for internal code, Win95 is ANSI code, NT is Unicode code.
  87. // Seqcodes: bytes number is cMethodKeySize. identical between Win95 and NT
  88. //
  89. //
  90. // Following fields in CHTUSRDICIMHDR need to convert from Win95 to NT 5.0
  91. //
  92. // idCp: from CHT 950 to 1200. ( stands for Unicode )
  93. // CHS 936 to 1200.
  94. // achMethodName[6]: converted from DBCS to Unicode.
  95. //
  96. //
  97. // Every IME EUDC table file names can be got from following registry Key/Value
  98. //
  99. // Key:Registry\Current_User\Software\Microsoft\Windows\CurrentVersion\<IMEName>
  100. // Value: User Dictionary: REG_SZ:
  101. //
  102. // ---------------------------------------------------------------------------
  103. /******************************Public*Routine******************************\
  104. * ImeEudcConvert
  105. *
  106. * Convert CHT/CHS Win95 EUDC IME table to NT 5.0
  107. *
  108. * Arguments:
  109. *
  110. * UCHAR * EudcTblFile - IME Eudc tbl file name.
  111. *
  112. * Return Value:
  113. *
  114. * BOOL: Success -TRUE. Fail - FALSE;
  115. *
  116. \**************************************************************************/
  117. BOOL ImeEudcConvert( LPCSTR EudcTblFile)
  118. {
  119. HANDLE hTblFile, hTblMap;
  120. LPBYTE lpTblFile, lpStart, lpTmp;
  121. DWORD dwCharNums, i;
  122. USRDICIMHDR *lpEudcHeader;
  123. BYTE DBCSChar[2];
  124. WORD wUnicodeChar, wImeName[3];
  125. UINT uCodePage;
  126. DebugMsg(("ImeEudcConvert,EudcTblFile = %s !\r\n",EudcTblFile));
  127. hTblFile = CreateFile(EudcTblFile, // ptr to name of file
  128. GENERIC_READ | GENERIC_WRITE, // access(read-write)mode
  129. FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
  130. NULL, // ptr to security attr
  131. OPEN_EXISTING, // how to create
  132. FILE_ATTRIBUTE_NORMAL, // file attributes
  133. NULL);
  134. if (hTblFile == INVALID_HANDLE_VALUE) {
  135. DebugMsg(("ImeEudcConvert,hTblFile == INVALID_HANDLE_VALUE !\r\n"));
  136. return FALSE;
  137. }
  138. hTblMap = CreateFileMapping(hTblFile, // handle to file to map
  139. NULL, // optional security attributes
  140. PAGE_READWRITE,// protection for mapping object
  141. 0, // high-order 32 bits of object size
  142. 0, // low-order 32 bits of object size
  143. NULL); // name of file-mapping object);
  144. if ( !hTblMap ) {
  145. DebugMsg(("ImeEudcConvert,CreateFileMapping failed !\r\n"));
  146. CloseHandle(hTblFile);
  147. return FALSE;
  148. }
  149. lpTblFile = (LPBYTE) MapViewOfFile(hTblMap, FILE_MAP_WRITE, 0, 0, 0);
  150. if ( !lpTblFile ) {
  151. DebugMsg(("ImeEudcConvert,MapViewOfFile failed !\r\n"));
  152. CloseHandle(hTblMap);
  153. CloseHandle(hTblFile);
  154. return FALSE;
  155. }
  156. lpEudcHeader = (USRDICIMHDR *)lpTblFile;
  157. // get the current Code Page.
  158. uCodePage = lpEudcHeader->idCP;
  159. //
  160. // if CodePage == 1200, it means this table has already been
  161. // unicode format
  162. //
  163. if (uCodePage == 1200) {
  164. DebugMsg(("ImeEudcConvert,[%s] Codepage is already 1200 !\r\n",EudcTblFile));
  165. CloseHandle(hTblMap);
  166. CloseHandle(hTblFile);
  167. return FALSE;
  168. }
  169. // change the codepage from 950 (CHT) or 936 (CHS) to 1200
  170. lpEudcHeader->idCP = 1200; // Unicode Native Code Page.
  171. // change the IME name from DBCS to Unicode.
  172. MultiByteToWideChar(uCodePage, // code page
  173. 0, // character-type options
  174. lpEudcHeader->achMethodName, // address of string to map
  175. 6, // number of bytes in string
  176. wImeName, // addr of wide-char buf
  177. 3); // size of buffer
  178. lpTmp = (LPBYTE)wImeName;
  179. for (i=0; i<6; i++)
  180. lpEudcHeader->achMethodName[i] = lpTmp[i];
  181. // Now we will convert every record for EUDC char.
  182. lpStart = lpTblFile + lpEudcHeader->uHeaderSize;
  183. dwCharNums = lpEudcHeader->ulTableCount;
  184. for (i=0; i<dwCharNums; i++) {
  185. lpTmp = lpStart + sizeof(WORD);
  186. // swap the leader Byte and tail Byte of the DBCS Code.
  187. DBCSChar[0] = *(lpTmp+1);
  188. DBCSChar[1] = *lpTmp;
  189. MultiByteToWideChar(uCodePage, // code page
  190. 0, // character-type options
  191. DBCSChar, // address of string to map
  192. 2, // number of bytes in string
  193. &wUnicodeChar, // addr of wide-char buf
  194. 1); // size of buffer
  195. *lpTmp = (BYTE)(wUnicodeChar & 0x00ff);
  196. *(lpTmp+1) = (BYTE)((wUnicodeChar >> 8) & 0x00ff);
  197. lpStart += sizeof(WORD) + sizeof(WORD) + lpEudcHeader->cMethodKeySize;
  198. }
  199. UnmapViewOfFile(lpTblFile);
  200. CloseHandle(hTblMap);
  201. CloseHandle(hTblFile);
  202. return TRUE;
  203. }
  204. BOOL GetEUDCHeader(
  205. LPCTSTR EudcFileName,
  206. USRDICIMHDR *EudcHeader)
  207. {
  208. BOOL Result = FALSE;
  209. HANDLE EudcFileHandle, EudcMappingHandle;
  210. LPBYTE EudcPtr;
  211. EudcFileHandle = CreateFile(EudcFileName,
  212. GENERIC_READ,
  213. FILE_SHARE_READ,
  214. NULL,
  215. OPEN_EXISTING,
  216. FILE_ATTRIBUTE_NORMAL,
  217. NULL);
  218. if (EudcFileHandle == INVALID_HANDLE_VALUE) {
  219. DebugMsg(("GetEUDCHeader, EudcFileHandle == INVALID_HANDLE_VALUE !\r\n"));
  220. goto Exit1;
  221. }
  222. EudcMappingHandle = CreateFileMapping(EudcFileHandle,
  223. NULL,
  224. PAGE_READONLY,
  225. 0,
  226. 0,
  227. NULL);
  228. if ( !EudcMappingHandle ) {
  229. DebugMsg(("GetEUDCHeader, EudcMappingHandle == INVALID_HANDLE_VALUE !\r\n"));
  230. goto Exit2;
  231. }
  232. EudcPtr = (LPBYTE) MapViewOfFile(EudcMappingHandle, FILE_MAP_READ, 0, 0, 0);
  233. if ( ! EudcPtr ) {
  234. DebugMsg(("GetEUDCHeader, ! EudcPtr !\r\n"));
  235. goto Exit3;
  236. }
  237. CopyMemory(EudcHeader,EudcPtr,sizeof(USRDICIMHDR));
  238. Result = TRUE;
  239. UnmapViewOfFile(EudcPtr);
  240. Exit3:
  241. CloseHandle(EudcMappingHandle);
  242. Exit2:
  243. CloseHandle(EudcFileHandle);
  244. Exit1:
  245. return Result;
  246. }
  247. BYTE WinAR30SeqMapTable(BYTE SeqCode)
  248. {
  249. INT i;
  250. INT NumOfKey = sizeof(WinAR30MapTable) / (sizeof (BYTE) * 2);
  251. for (i = 0; i < NumOfKey; i++) {
  252. if (WinAR30MapTable[i * 2] == SeqCode) {
  253. return WinAR30MapTable[i * 2+1];
  254. }
  255. }
  256. return 0;
  257. }
  258. BOOL WinAR30ConvertWorker(
  259. LPBYTE EudcPtr)
  260. {
  261. USRDICIMHDR *EudcHeader;
  262. WinAR30EUDC95 *EudcDataPtr95;
  263. WinAR30EUDCNT *EudcDataPtrNT;
  264. INT i;
  265. DebugMsg(("WinAR30ConvertWorker, ! Start !\r\n"));
  266. if (! EudcPtr) {
  267. DebugMsg(("WinAR30ConvertWorker, ! EudcPtr !\r\n"));
  268. return FALSE;
  269. }
  270. EudcHeader = (USRDICIMHDR *) EudcPtr;
  271. EudcHeader->cMethodKeySize = 5;
  272. EudcDataPtr95 = (WinAR30EUDC95 *) (EudcPtr + EudcHeader->uHeaderSize);
  273. EudcDataPtrNT = (WinAR30EUDCNT *) (EudcPtr + EudcHeader->uHeaderSize);
  274. DebugMsg(("Sizeof WinAR30EUDC95 = %d WinAR30EUDCNT = %d ! \r\n",sizeof(WinAR30EUDC95),sizeof(WinAR30EUDCNT)));
  275. for (i=(INT)(EudcHeader->ulTableCount -1) ; i >= 0 ; i--) {
  276. EudcDataPtrNT[i].Seq[4] = 0;
  277. EudcDataPtrNT[i].Seq[3] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[3]);
  278. EudcDataPtrNT[i].Seq[2] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[2]);
  279. EudcDataPtrNT[i].Seq[1] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[1]);
  280. EudcDataPtrNT[i].Seq[0] = WinAR30SeqMapTable(EudcDataPtr95[i].Seq[0]);
  281. EudcDataPtrNT[i].Code = EudcDataPtr95[i].Code;
  282. EudcDataPtrNT[i].ID = EudcDataPtr95[i].ID;
  283. }
  284. return TRUE;
  285. }
  286. BOOL
  287. WinAR30Convert(
  288. LPCTSTR EudcFileName,
  289. USRDICIMHDR *EudcHeader)
  290. {
  291. INT NewFileSize;
  292. HANDLE EudcFileHandle, EudcMappingHandle;
  293. LPBYTE EudcPtr;
  294. BOOL Result = FALSE;
  295. if (! EudcHeader) {
  296. goto Exit1;
  297. }
  298. NewFileSize = EudcHeader->uHeaderSize + EudcHeader->ulTableCount * sizeof(WinAR30EUDCNT);
  299. EudcFileHandle = CreateFile(EudcFileName,
  300. GENERIC_READ | GENERIC_WRITE,
  301. FILE_SHARE_READ,
  302. NULL,
  303. OPEN_EXISTING,
  304. FILE_ATTRIBUTE_NORMAL,
  305. NULL);
  306. if (EudcFileHandle == INVALID_HANDLE_VALUE) {
  307. DebugMsg(("WinAR30Convert, EudcFileHandle == INVALID_HANDLE_VALUE !\r\n"));
  308. goto Exit1;
  309. }
  310. EudcMappingHandle = CreateFileMapping(EudcFileHandle,
  311. NULL,
  312. PAGE_READWRITE,
  313. 0,
  314. NewFileSize,
  315. NULL);
  316. if ( !EudcMappingHandle ) {
  317. DebugMsg(("WinAR30Convert, EudcMappingHandle == INVALID_HANDLE_VALUE !\r\n"));
  318. goto Exit2;
  319. }
  320. EudcPtr = (LPBYTE) MapViewOfFile(EudcMappingHandle, FILE_MAP_WRITE, 0, 0, 0);
  321. if ( !EudcPtr ) {
  322. DebugMsg(("GetEUDCHeader, ! EudcPtr !\r\n"));
  323. goto Exit3;
  324. }
  325. Result = WinAR30ConvertWorker(EudcPtr);
  326. UnmapViewOfFile(EudcPtr);
  327. Exit3:
  328. CloseHandle(EudcMappingHandle);
  329. Exit2:
  330. CloseHandle(EudcFileHandle);
  331. Exit1:
  332. return Result;
  333. }
  334. BOOL FixWinAR30EUDCTable(
  335. LPCTSTR EudcFileName)
  336. /*
  337. Main function to fix WinAR30 EUDC table
  338. Input : Eudc File Name (include path)
  339. */
  340. {
  341. USRDICIMHDR EudcHeader;
  342. BOOL Result = FALSE;
  343. if (! GetEUDCHeader(EudcFileName,&EudcHeader)) {
  344. DebugMsg(("FixWinAR30EUDCTable,GetEUDCHeader(%s,..) failed!\r\n",EudcFileName));
  345. goto Exit1;
  346. } else {
  347. DebugMsg(("FixWinAR30EUDCTable,GetEUDCHeader(%s,..) OK!\r\n",EudcFileName));
  348. }
  349. DebugMsg(("FixWinAR30EUDCTable,EudcHeader.cMethodKeySize = (%d)!\r\n",EudcHeader.cMethodKeySize));
  350. if (EudcHeader.cMethodKeySize != 4) {
  351. goto Exit1;
  352. }
  353. DebugMsg(("FixWinAR30EUDCTable,EudcHeader.ulTableCount = (%d) !\r\n",EudcHeader.ulTableCount));
  354. if (EudcHeader.ulTableCount == 0) {
  355. goto Exit1;
  356. }
  357. Result = WinAR30Convert(EudcFileName, &EudcHeader);
  358. Exit1:
  359. return Result;
  360. }
  361. BOOL GetEUDCPathInRegistry(
  362. HKEY UserRegKey,
  363. LPCTSTR EUDCName,
  364. LPCTSTR EUDCPathValueName,
  365. LPTSTR EUDCFileName)
  366. {
  367. HKEY hKey;
  368. TCHAR IMERegPath[MAX_PATH] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\");
  369. LONG RetVal;
  370. LONG SizeOfFileName;
  371. if (! EUDCName || ! EUDCFileName) {
  372. return FALSE;
  373. }
  374. ConcatenatePaths(IMERegPath,EUDCName,MAX_PATH);
  375. RetVal = RegOpenKey(UserRegKey,
  376. IMERegPath,
  377. &hKey);
  378. if (RetVal != ERROR_SUCCESS) {
  379. //
  380. // it's ok, not every IME has created eudc table
  381. //
  382. DebugMsg(("ImeEudcConvert::GetEUDCPathInRegistry,No table in %s !\r\n",EUDCName));
  383. return FALSE;
  384. }
  385. SizeOfFileName = MAX_PATH;
  386. RetVal = RegQueryValueEx(hKey,
  387. EUDCPathValueName,
  388. NULL,
  389. NULL,
  390. (LPBYTE) EUDCFileName,
  391. &SizeOfFileName);
  392. if (RetVal == ERROR_SUCCESS) {
  393. DebugMsg(("ImeEudcConvert::GetEUDCPathInRegistry,IME Table path = %s !\r\n",EUDCFileName));
  394. } else {
  395. DebugMsg(("ImeEudcConvert::GetEUDCPathInRegistry,No IME table path %s !\r\n",EUDCName));
  396. }
  397. return (RetVal == ERROR_SUCCESS);
  398. }
  399. UINT CreateNestedDirectory(LPCTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
  400. {
  401. TCHAR szDirectory[2*MAX_PATH];
  402. LPTSTR lpEnd;
  403. //
  404. // Check for NULL pointer
  405. //
  406. if (!lpDirectory || !(*lpDirectory)) {
  407. return 0;
  408. }
  409. //
  410. // First, see if we can create the directory without having
  411. // to build parent directories.
  412. //
  413. if (CreateDirectory (lpDirectory, lpSecurityAttributes)) {
  414. return 1;
  415. }
  416. //
  417. // If this directory exists already, this is OK too.
  418. //
  419. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  420. return ERROR_ALREADY_EXISTS;
  421. }
  422. //
  423. // No luck, copy the string to a buffer we can munge
  424. //
  425. lstrcpy (szDirectory, lpDirectory);
  426. //
  427. // Find the first subdirectory name
  428. //
  429. lpEnd = szDirectory;
  430. if (szDirectory[1] == TEXT(':')) {
  431. lpEnd += 3;
  432. } else if (szDirectory[1] == TEXT('\\')) {
  433. lpEnd += 2;
  434. while (*lpEnd && *lpEnd != TEXT('\\')) {
  435. lpEnd++;
  436. }
  437. if (!(*lpEnd)) {
  438. return 0;
  439. }
  440. lpEnd++;
  441. while (*lpEnd && *lpEnd != TEXT('\\')) {
  442. lpEnd++;
  443. }
  444. if (!(*lpEnd)) {
  445. return 0;
  446. }
  447. lpEnd++;
  448. } else if (szDirectory[0] == TEXT('\\')) {
  449. lpEnd++;
  450. }
  451. while (*lpEnd) {
  452. while (*lpEnd && *lpEnd != TEXT('\\')) {
  453. lpEnd++;
  454. }
  455. if (*lpEnd == TEXT('\\')) {
  456. *lpEnd = TEXT('\0');
  457. if (!CreateDirectory (szDirectory, NULL)) {
  458. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  459. DebugMsg((TEXT("CreateNestedDirectory: CreateDirectory failed with %d."), GetLastError()));
  460. return 0;
  461. }
  462. }
  463. *lpEnd = TEXT('\\');
  464. lpEnd++;
  465. }
  466. }
  467. if (CreateDirectory (szDirectory, lpSecurityAttributes)) {
  468. return 1;
  469. }
  470. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  471. return ERROR_ALREADY_EXISTS;
  472. }
  473. DebugMsg((TEXT("CreateNestedDirectory: Failed to create the directory with error %d."), GetLastError()));
  474. return 0;
  475. }
  476. BOOL
  477. ConcatenatePaths(
  478. LPTSTR Target,
  479. LPCTSTR Path,
  480. UINT TargetBufferSize
  481. )
  482. {
  483. UINT TargetLength,PathLength;
  484. BOOL TrailingBackslash,LeadingBackslash;
  485. UINT EndingLength;
  486. TargetLength = lstrlen(Target);
  487. PathLength = lstrlen(Path);
  488. //
  489. // See whether the target has a trailing backslash.
  490. //
  491. if(TargetLength && (Target[TargetLength-1] == TEXT('\\'))) {
  492. TrailingBackslash = TRUE;
  493. TargetLength--;
  494. } else {
  495. TrailingBackslash = FALSE;
  496. }
  497. //
  498. // See whether the path has a leading backshash.
  499. //
  500. if(Path[0] == TEXT('\\')) {
  501. LeadingBackslash = TRUE;
  502. PathLength--;
  503. } else {
  504. LeadingBackslash = FALSE;
  505. }
  506. //
  507. // Calculate the ending length, which is equal to the sum of
  508. // the length of the two strings modulo leading/trailing
  509. // backslashes, plus one path separator, plus a nul.
  510. //
  511. EndingLength = TargetLength + PathLength + 2;
  512. if(!LeadingBackslash && (TargetLength < TargetBufferSize)) {
  513. Target[TargetLength++] = TEXT('\\');
  514. }
  515. if(TargetBufferSize > TargetLength) {
  516. lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength);
  517. }
  518. //
  519. // Make sure the buffer is nul terminated in all cases.
  520. //
  521. if (TargetBufferSize) {
  522. Target[TargetBufferSize-1] = 0;
  523. }
  524. return(EndingLength <= TargetBufferSize);
  525. }
  526. #define CSIDL_APPDATA 0x001a
  527. BOOL (* MYSHGetSpecialFolderPathA) (HWND , LPTSTR , int , BOOL );
  528. BOOL GetApplicationFolderPath(LPTSTR lpszFolder,UINT nLen)
  529. {
  530. HINSTANCE hDll;
  531. BOOL bGotPath = FALSE;
  532. hDll = LoadLibrary(TEXT("shell32.dll"));
  533. if (hDll) {
  534. (FARPROC) MYSHGetSpecialFolderPathA = GetProcAddress(hDll,"SHGetSpecialFolderPathA");
  535. if (MYSHGetSpecialFolderPathA) {
  536. if (MYSHGetSpecialFolderPathA(NULL, lpszFolder, CSIDL_APPDATA , FALSE)){
  537. DebugMsg((TEXT("[GetApplicationFolder] SHGetSpecialFolderPath %s !\n"),lpszFolder));
  538. bGotPath = TRUE;
  539. } else {
  540. DebugMsg((TEXT("[GetApplicationFolder] SHGetSpecialFolderPath failed !\n")));
  541. }
  542. } else {
  543. DebugMsg((TEXT("[GetApplicationFolder] GetProc of SHGetSpecialFolderPath failed !\n")));
  544. }
  545. FreeLibrary(hDll);
  546. } else {
  547. DebugMsg((TEXT("[GetApplicationFolder] Load shell32.dll failed ! %d\n"),GetLastError()));
  548. }
  549. if (! bGotPath) {
  550. ExpandEnvironmentStrings(TEXT("%userprofile%"),lpszFolder,nLen);
  551. lstrcat(lpszFolder,TEXT("\\Application data"));
  552. }
  553. return TRUE;
  554. }
  555. BOOL GetNewPath(
  556. LPTSTR lpszNewPath,
  557. LPCTSTR lpszFileName,
  558. LPCTSTR lpszClass)
  559. /*
  560. OUT lpszNewPath : e.q. \winnt\profiles\administrator\application data\Micorsoft\ime\chajei
  561. IN lpszFileName : e.q. \winnt\chajei.tbl
  562. IN lpszClass : e.q. Micorsoft\ime\chajei\chajei.tbl
  563. lpszFileName (e.q. \winnt\phon.tbl) -> get base name (e.q. phon.tbl) ->
  564. get Application folder (e.q. \winnt\profiles\administrator\application data) ->
  565. create directory -> concat lpszClass (e.q. Micorsoft\ime\chajei)
  566. Then we get lpszNewPath = \winnt\profiles\administrator\application data\Micorsoft\ime\chajei
  567. */
  568. {
  569. BOOL bRet = FALSE;
  570. LPTSTR lpszBaseName;
  571. DebugMsg((TEXT("[GetNewPath>>>] Param lpszFileName = %s !\n"),lpszFileName));
  572. DebugMsg((TEXT("[GetNewPath>>>] Param lpszClass = %s !\n"),lpszClass));
  573. GetApplicationFolderPath(lpszNewPath,MAX_PATH);
  574. ConcatenatePaths(lpszNewPath, lpszClass,MAX_PATH);
  575. if (! CreateNestedDirectory(lpszNewPath,NULL)) {
  576. DebugMsg((TEXT("[GetNewPath] CreateDirectory %s ! %X\n"),lpszNewPath,GetLastError()));
  577. }
  578. if ((lpszBaseName = _tcsrchr(lpszFileName,TEXT('\\'))) != NULL) {
  579. ConcatenatePaths(lpszNewPath,lpszBaseName,MAX_PATH);
  580. } else {
  581. ConcatenatePaths(lpszNewPath,lpszFileName,MAX_PATH);
  582. DebugMsg((TEXT("[GetNewPath] can't find \\ in %s !\n"),lpszFileName));
  583. }
  584. DebugMsg((TEXT("[GetNewPath] return %s !\n"),lpszNewPath));
  585. bRet = TRUE;
  586. return bRet;
  587. }
  588. BOOL MigrateImeEUDCTables(HKEY UserRegKey)
  589. {
  590. LONG returnCode = ERROR_SUCCESS;
  591. UINT uACP;
  592. UINT uNumOfTables;
  593. UINT i;
  594. LPTABLELIST lpTableList;
  595. TCHAR szIMERegPath[MAX_PATH] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\");
  596. LPTSTR lpszEnd;
  597. TCHAR szPathBuf[MAX_PATH];
  598. LONG lPathBuf;
  599. TCHAR szEudcRegValName[MAX_PATH];
  600. HKEY hKey;
  601. LONG lRetVal;
  602. TABLELIST IMETableListCHT[] = {
  603. {IDS_CHT_TABLE1,TEXT("")},
  604. {IDS_CHT_TABLE2,TEXT("")},
  605. {IDS_CHT_TABLE3,TEXT("")},
  606. {IDS_CHT_TABLE4,TEXT("")},
  607. {IDS_CHT_TABLE5,TEXT("")}
  608. };
  609. TABLELIST IMETableListCHS[] = {
  610. {IDS_CHS_TABLE1,TEXT("")},
  611. {IDS_CHS_TABLE2,TEXT("")},
  612. {IDS_CHS_TABLE3,TEXT("")},
  613. // {IDS_CHS_TABLE4,TEXT("")},
  614. {IDS_CHS_TABLE5,TEXT("")},
  615. {IDS_CHS_TABLE6,TEXT("")},
  616. {IDS_CHS_TABLE7,TEXT("")}
  617. // {IDS_CHS_TABLE8,TEXT("")}
  618. };
  619. if (!UserRegKey) {
  620. return FALSE;
  621. }
  622. //
  623. // 1. Decide which language and prepare IME table list
  624. //
  625. uACP = GetACP();
  626. switch(uACP) {
  627. case CP_CHINESE_GB: // Simplied Chinese
  628. lpTableList = IMETableListCHS;
  629. uNumOfTables = sizeof(IMETableListCHS) / sizeof(TABLELIST);
  630. lstrcpy(szEudcRegValName,TEXT("EUDCDictName"));
  631. break;
  632. case CP_CHINESE_BIG5: // Traditional Chinese
  633. lpTableList = IMETableListCHT;
  634. uNumOfTables = sizeof(IMETableListCHT) / sizeof(TABLELIST);
  635. lstrcpy(szEudcRegValName,TEXT("User Dictionary"));
  636. break;
  637. default:
  638. DebugMsg(("MigrateImeEUDCTables::MigrateImeEUDCTables failed, wrong system code page !\r\n"));
  639. return FALSE;
  640. }
  641. //
  642. // 2. load IME name from resource
  643. //
  644. for (i=0; i<uNumOfTables; i++) {
  645. if (!LoadString(g_hInstance,lpTableList[i].nResID,lpTableList[i].szIMEName,MAX_PATH)) {
  646. DebugMsg(("MigrateImeEUDCTables failed, MigrateImeEUDCTables, load string failed !\r\n"));
  647. return FALSE;
  648. }
  649. else {
  650. DebugMsg(("MigrateImeEUDCTables , MigrateImeEUDCTables, load string [%s] !\r\n",lpTableList[i].szIMEName));
  651. }
  652. }
  653. //
  654. // 3. Read eudc table locaion from registry
  655. //
  656. lpszEnd = &szIMERegPath[lstrlen(szIMERegPath)];
  657. for (i=0; i<uNumOfTables; i++) {
  658. *lpszEnd = TEXT('\0');
  659. lstrcat(szIMERegPath,lpTableList[i].szIMEName);
  660. DebugMsg(("MigrateImeEUDCTables , Open registry, szIMERegPath [%s] !\r\n",szIMERegPath));
  661. lRetVal = RegOpenKey(UserRegKey,
  662. szIMERegPath,
  663. &hKey);
  664. if (lRetVal != ERROR_SUCCESS) {
  665. //
  666. // it's ok, not every IME has created eudc table
  667. //
  668. DebugMsg(("MigrateImeEUDCTables,No table in %s ! But it's fine\r\n",szIMERegPath));
  669. continue;
  670. }
  671. lPathBuf = sizeof(szPathBuf);
  672. lRetVal = RegQueryValueEx(hKey,
  673. szEudcRegValName,
  674. NULL,
  675. NULL,
  676. (LPBYTE) szPathBuf,
  677. &lPathBuf);
  678. if (lRetVal == ERROR_SUCCESS) {
  679. if (! ImeEudcConvert(szPathBuf)) {
  680. DebugMsg(("MigrateImeEUDCTables,call ImeEudcConvert(%s) failed !\r\n",szPathBuf));
  681. }
  682. else {
  683. DebugMsg(("MigrateImeEUDCTables,call ImeEudcConvert(%s) OK !\r\n",szPathBuf));
  684. }
  685. }
  686. else {
  687. DebugMsg(("MigrateImeEUDCTables,RegQueryValue for %s failed !\r\n",szEudcRegValName));
  688. }
  689. if (uACP == CP_CHINESE_BIG5) {
  690. DebugMsg(("MigrateImeEUDCTables,Test WINAR30 WINAR30 == %s !\r\n",lpTableList[i].szIMEName));
  691. if (lstrcmpi(lpTableList[i].szIMEName,TEXT("WINAR30")) == 0) {
  692. if (FixWinAR30EUDCTable(szPathBuf)) {
  693. DebugMsg(("MigrateImeEUDCTables,FixWinAR30EUDCTable OK !\r\n"));
  694. } else {
  695. DebugMsg(("MigrateImeEUDCTables,FixWinAR30EUDCTable Failed !\r\n"));
  696. }
  697. }
  698. }
  699. //
  700. // CHS's memory map file use "\" which cause bug
  701. //
  702. // replace "\" with "_"
  703. //
  704. if (uACP == CP_CHINESE_GB) {
  705. lRetVal = RegQueryValueEx(hKey,
  706. TEXT("EUDCMapFileName"),
  707. NULL,
  708. NULL,
  709. (LPBYTE) szPathBuf,
  710. &lPathBuf);
  711. if (lRetVal == ERROR_SUCCESS) {
  712. DebugMsg(("MigrateImeEUDCTables,Org MemMap = %s !\r\n",szPathBuf));
  713. for (i=0; i<(UINT) lPathBuf; i++) {
  714. if (szPathBuf[i] == '\\') {
  715. szPathBuf[i] = '-';
  716. }
  717. }
  718. DebugMsg(("MigrateImeEUDCTables,fixed MemMap = %s !\r\n",szPathBuf));
  719. lRetVal = RegSetValueEx(hKey,
  720. TEXT("EUDCMapFileName"),
  721. 0,
  722. REG_SZ,
  723. (LPBYTE) szPathBuf,
  724. (lstrlen(szPathBuf)+1)*sizeof(TCHAR));
  725. if (lRetVal != ERROR_SUCCESS) {
  726. DebugMsg(("MigrateImeEUDCTables,fix CHS MemMap [%s]reg,SetReg failed [%d]!\r\n",szPathBuf,lRetVal));
  727. } else {
  728. DebugMsg(("MigrateImeEUDCTables,fix CHS MemMap [%s] reg,SetReg OK !\r\n",szPathBuf));
  729. }
  730. } else {
  731. DebugMsg(("MigrateImeEUDCTables,MemMap, QuwryValue EUDCMapFileName failed [%d]!\r\n",lRetVal));
  732. }
  733. }
  734. RegCloseKey(hKey);
  735. }
  736. DebugMsg(("MigrateImeEUDCTables , Finished !\r\n"));
  737. return TRUE;
  738. }
  739. LPPATHPAIR g_RememberedPath = NULL;
  740. UINT g_NumofRememberedPath = 0;
  741. BOOL RememberPath(LPCTSTR szDstFile,LPCTSTR szSrcFile)
  742. {
  743. //
  744. // only single thread executes this function, skip synchronization protection
  745. //
  746. BOOL bRet = FALSE;
  747. if (g_NumofRememberedPath == 0) {
  748. g_RememberedPath = (LPPATHPAIR) malloc(sizeof(PATHPAIR));
  749. if (! g_RememberedPath) {
  750. DebugMsg(("RememberPath , alloc memory failed !\r\n"));
  751. goto Exit1;
  752. }
  753. } else {
  754. g_RememberedPath = (LPPATHPAIR) realloc(g_RememberedPath,(g_NumofRememberedPath + 1) * sizeof(PATHPAIR));
  755. if (! g_RememberedPath) {
  756. DebugMsg(("RememberPath , alloc memory failed !\r\n"));
  757. goto Exit1;
  758. }
  759. }
  760. lstrcpy(g_RememberedPath[g_NumofRememberedPath].szSrcFile,szSrcFile);
  761. lstrcpy(g_RememberedPath[g_NumofRememberedPath].szDstFile,szDstFile);
  762. g_NumofRememberedPath++;
  763. bRet = TRUE;
  764. Exit1:
  765. return bRet;
  766. }
  767. BOOL MigrateImeEUDCTables2(HKEY UserRegKey)
  768. /*++
  769. CHS : if xxx.emb exist, it needs to be duplicated to each user's AP directory
  770. CHT : only move emb files that specified in user's "User Dictionary" Reg value
  771. --*/
  772. {
  773. LONG returnCode = ERROR_SUCCESS;
  774. UINT uACP;
  775. UINT uNumOfTables;
  776. UINT i;
  777. LPTABLELIST lpTableList;
  778. TCHAR szIMERegPath[MAX_PATH] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\");
  779. LPTSTR lpszEnd;
  780. TCHAR szOldDataFile[MAX_PATH];
  781. LONG lPathBuf;
  782. TCHAR szEudcRegValName[MAX_PATH];
  783. HKEY hKey;
  784. LONG lRetVal;
  785. TCHAR szNewDataFile[MAX_PATH];
  786. TCHAR szClassPath[MAX_PATH];
  787. TABLELIST IMETableListCHT[] = {
  788. {IDS_CHT_TABLE1,TEXT("")},
  789. {IDS_CHT_TABLE2,TEXT("")},
  790. {IDS_CHT_TABLE3,TEXT("")},
  791. {IDS_CHT_TABLE4,TEXT("")},
  792. {IDS_CHT_TABLE5,TEXT("")}
  793. };
  794. TABLELIST IMETableListCHS[] = {
  795. {IDS_CHS_TABLE1,TEXT("")},
  796. {IDS_CHS_TABLE2,TEXT("")},
  797. {IDS_CHS_TABLE3,TEXT("")}
  798. };
  799. TABLELIST IMETableListCHSENG[] = {
  800. {IDS_CHS_ENG_TABLE1,TEXT("")},
  801. {IDS_CHS_ENG_TABLE2,TEXT("")},
  802. {IDS_CHS_ENG_TABLE3,TEXT("")}
  803. };
  804. if (!UserRegKey) {
  805. return FALSE;
  806. }
  807. //
  808. // 1. Decide which language and prepare IME table list
  809. //
  810. uACP = GetACP();
  811. switch(uACP) {
  812. case CP_CHINESE_GB: // Simplied Chinese
  813. lpTableList = IMETableListCHS;
  814. uNumOfTables = sizeof(IMETableListCHS) / sizeof(TABLELIST);
  815. lstrcpy(szEudcRegValName,TEXT("EUDCDictName"));
  816. break;
  817. case CP_CHINESE_BIG5: // Traditional Chinese
  818. lpTableList = IMETableListCHT;
  819. uNumOfTables = sizeof(IMETableListCHT) / sizeof(TABLELIST);
  820. lstrcpy(szEudcRegValName,TEXT("User Dictionary"));
  821. break;
  822. default:
  823. DebugMsg(("MigrateImeEUDCTables2 failed, wrong system code page !\r\n"));
  824. return FALSE;
  825. }
  826. //
  827. // 2. load IME name from resource
  828. //
  829. for (i=0; i<uNumOfTables; i++) {
  830. if (!LoadString(g_hInstance,lpTableList[i].nResID,lpTableList[i].szIMEName,MAX_PATH)) {
  831. DebugMsg(("MigrateImeEUDCTables2 failed, MigrateImeEUDCTables, load string failed !\r\n"));
  832. return FALSE;
  833. }
  834. else {
  835. DebugMsg(("MigrateImeEUDCTables2 , MigrateImeEUDCTables, load string [%s] !\r\n",lpTableList[i].szIMEName));
  836. }
  837. if (uACP == CP_CHINESE_GB) {
  838. if (!LoadString(g_hInstance,IMETableListCHSENG[i].nResID,IMETableListCHSENG[i].szIMEName,MAX_PATH)) {
  839. DebugMsg(("MigrateImeEUDCTables2 failed, MigrateImeEUDCTables, load string failed !\r\n"));
  840. return FALSE;
  841. }
  842. else {
  843. DebugMsg(("MigrateImeEUDCTables2 , MigrateImeEUDCTables, load string [%s] !\r\n",lpTableList[i].szIMEName));
  844. }
  845. }
  846. }
  847. //
  848. // 3. Read eudc table locaion from registry
  849. //
  850. lpszEnd = &szIMERegPath[lstrlen(szIMERegPath)];
  851. for (i=0; i<uNumOfTables; i++) {
  852. if (uACP == CP_CHINESE_GB) {
  853. TCHAR szEMBName[MAX_PATH];
  854. lstrcpy(szEMBName,IMETableListCHSENG[i].szIMEName);
  855. lstrcat(szEMBName,TEXT(".emb"));
  856. lstrcpy(szOldDataFile,ImeDataDirectory);
  857. ConcatenatePaths(szOldDataFile,szEMBName,sizeof(szOldDataFile));
  858. if (GetFileAttributes(szOldDataFile) == 0xFFFFFFFF) {
  859. DebugMsg(("MigrateImeEUDCTables2 , No %s EMB, continue next !\r\n",szOldDataFile));
  860. continue;
  861. }
  862. lstrcpy(szClassPath,TEXT("Microsoft\\IME\\"));
  863. lstrcat(szClassPath,IMETableListCHSENG[i].szIMEName);
  864. GetSystemDirectory(szOldDataFile, sizeof(szOldDataFile));
  865. ConcatenatePaths(szOldDataFile,szEMBName,sizeof(szOldDataFile));
  866. if (GetNewPath(szNewDataFile,
  867. szOldDataFile,
  868. szClassPath)) {
  869. RememberPath(szNewDataFile,szOldDataFile);
  870. }
  871. }
  872. *lpszEnd = TEXT('\0');
  873. lstrcat(szIMERegPath,lpTableList[i].szIMEName);
  874. DebugMsg(("MigrateImeEUDCTables2 , Open registry, szIMERegPath [%s] !\r\n",szIMERegPath));
  875. lRetVal = RegOpenKey(UserRegKey,
  876. szIMERegPath,
  877. &hKey);
  878. if (lRetVal != ERROR_SUCCESS) {
  879. //
  880. // it's ok, not every IME has created eudc table
  881. //
  882. DebugMsg(("MigrateImeEUDCTables2,No table in %s ! But it's fine\r\n",szIMERegPath));
  883. continue;
  884. }
  885. lPathBuf = sizeof(szOldDataFile);
  886. lRetVal = RegQueryValueEx(hKey,
  887. szEudcRegValName,
  888. NULL,
  889. NULL,
  890. (LPBYTE) szOldDataFile,
  891. &lPathBuf);
  892. if (lRetVal == ERROR_SUCCESS) {
  893. if (uACP == CP_CHINESE_BIG5) {
  894. lstrcpy(szClassPath,TEXT("Microsoft\\IME\\"));
  895. lstrcat(szClassPath,lpTableList[i].szIMEName);
  896. if (GetNewPath(szNewDataFile,
  897. szOldDataFile,
  898. szClassPath)) {
  899. RememberPath(szNewDataFile,szOldDataFile);
  900. }
  901. }
  902. //
  903. // at this step, both CHT's and CHS's szNewDataFile is ready
  904. //
  905. lRetVal = RegSetValueEx(hKey,
  906. szEudcRegValName,
  907. 0,
  908. REG_SZ,
  909. (LPBYTE) szNewDataFile,
  910. (lstrlen(szNewDataFile)+1) * sizeof (TCHAR));
  911. if (lRetVal != ERROR_SUCCESS) {
  912. DebugMsg(("MigrateImeEUDCTables2,RegSetValueEx %s,%x ! \r\n",szNewDataFile,GetLastError()));
  913. }
  914. }
  915. else {
  916. DebugMsg(("MigrateImeEUDCTables2,RegQueryValue for %s failed !\r\n",szEudcRegValName));
  917. }
  918. RegCloseKey(hKey);
  919. }
  920. DebugMsg(("MigrateImeEUDCTables2 , Finished !\r\n"));
  921. return TRUE;
  922. }
  923. BOOL MovePerUserIMEData()
  924. {
  925. UINT i;
  926. for (i=0; i< g_NumofRememberedPath; i++) {
  927. if (CopyFile(g_RememberedPath[i].szSrcFile,g_RememberedPath[i].szDstFile,FALSE)) {
  928. DebugMsg(("MovePerUserIMEData , Copy %s to %s OK !\r\n",g_RememberedPath[i].szSrcFile,g_RememberedPath[i].szDstFile));
  929. } else {
  930. DebugMsg(("MovePerUserIMEData , Copy %s to %s failed !\r\n",g_RememberedPath[i].szSrcFile,g_RememberedPath[i].szDstFile));
  931. }
  932. }
  933. if (g_RememberedPath) {
  934. free (g_RememberedPath);
  935. g_RememberedPath = NULL;
  936. g_NumofRememberedPath = 0;
  937. }
  938. return TRUE;
  939. }