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.

665 lines
17 KiB

  1. //
  2. // stub migration dll for IME Dlls.
  3. //
  4. #include "pch.h"
  5. #include "chs.h"
  6. #include "cht.h"
  7. #include "common.h"
  8. #include "resource.h"
  9. typedef struct {
  10. CHAR CompanyName[256];
  11. CHAR SupportNumber[256];
  12. CHAR SupportUrl[256];
  13. CHAR InstructionsToUser[1024];
  14. } VENDORINFO, *PVENDORINFO;
  15. //IME data
  16. #define MAX_IME_DATA_FILE_NAME 20
  17. TCHAR ChsDataFile[][MAX_IME_DATA_FILE_NAME]={
  18. "winpy.emb",
  19. "winsp.emb",
  20. "winzm.emb",
  21. "winbx.emb",
  22. "winxpy.emb",
  23. "winxsp.emb",
  24. "winxzm.emb",
  25. "winxbx.emb",
  26. "user.rem",
  27. "tmmr.rem",
  28. 0
  29. };
  30. TCHAR ChtDataFile[][MAX_IME_DATA_FILE_NAME]={
  31. "lcptr.tbl",
  32. "lcphrase.tbl",
  33. 0
  34. };
  35. CHAR ImeDataDirectory[MAX_PATH];
  36. //
  37. // Constants
  38. //
  39. #define CP_USASCII 1252
  40. #define CP_CHINESE_BIG5 950
  41. #define CP_CHINESE_GB 936
  42. #define END_OF_CODEPAGES -1
  43. //
  44. // Code page array, add relevant code pages that you support to this list..
  45. //
  46. INT g_CodePageArray[] = {
  47. CP_USASCII,
  48. END_OF_CODEPAGES
  49. };
  50. // PCSTR g_MyProductId = "This Must be LOCALIZED";
  51. //
  52. // load it from resource
  53. //
  54. TCHAR g_MyProductId[MAX_PATH];
  55. VENDORINFO g_MyVendorInfo = {"Localized Company Name","Localized Support Number","Localized Support URL","Localized Instructions"};
  56. //
  57. // Handle to the process heap for allocations. Initialized in DllMain.
  58. //
  59. HANDLE g_hHeap;
  60. HINSTANCE g_hInstance;
  61. BOOL g_bCHSWin98 = FALSE;
  62. #ifdef MYDBG
  63. void Print(LPCTSTR pszFormat,...)
  64. {
  65. TCHAR szBuf[500];
  66. TCHAR szBuf2[500];
  67. va_list arglist;
  68. va_start(arglist,pszFormat);
  69. wvsprintf(szBuf,pszFormat,arglist);
  70. wsprintf(szBuf2,"%s : %s",DBGTITLE,szBuf);
  71. #ifdef SETUP
  72. OutputDebugString(szBuf2);
  73. #else
  74. SetupLogError(szBuf2,LogSevInformation);
  75. #endif
  76. va_end(arglist);
  77. }
  78. #endif
  79. BOOL
  80. WINAPI
  81. DllMain (
  82. IN HANDLE DllInstance,
  83. IN ULONG ReasonForCall,
  84. IN LPVOID Reserved
  85. )
  86. {
  87. switch (ReasonForCall) {
  88. case DLL_PROCESS_ATTACH:
  89. g_hInstance = DllInstance;
  90. //
  91. // We don't need DLL_THREAD_ATTACH or DLL_THREAD_DETACH messages
  92. //
  93. DisableThreadLibraryCalls (DllInstance);
  94. //
  95. // Global init
  96. //
  97. g_hHeap = GetProcessHeap();
  98. if (!MigInf_Initialize()) {
  99. return FALSE;
  100. }
  101. // Open log; FALSE means do not delete existing log
  102. SetupOpenLog (FALSE);
  103. break;
  104. case DLL_PROCESS_DETACH:
  105. g_hInstance = NULL;
  106. MigInf_CleanUp();
  107. SetupCloseLog();
  108. break;
  109. }
  110. return TRUE;
  111. }
  112. LPTSTR CheckSlash (LPTSTR lpDir)
  113. {
  114. DWORD dwStrLen;
  115. LPTSTR lpEnd;
  116. lpEnd = lpDir + lstrlen(lpDir);
  117. if (*(lpEnd - 1) != TEXT('\\')) {
  118. *lpEnd = TEXT('\\');
  119. lpEnd++;
  120. *lpEnd = TEXT('\0');
  121. }
  122. return lpEnd;
  123. }
  124. BOOL
  125. CheckIfFileExisting(LPCTSTR pszFileName)
  126. {
  127. TCHAR szFullPathName[MAX_PATH];
  128. LONG lResult;
  129. //
  130. // these files are in system directory
  131. //
  132. GetSystemDirectory(szFullPathName,MAX_PATH);
  133. CheckSlash(szFullPathName);
  134. lstrcat(szFullPathName,pszFileName);
  135. lResult = GetFileAttributes(szFullPathName);
  136. if (lResult == 0xFFFFFFFF) { // file does not exist
  137. return FALSE;
  138. } else {
  139. return TRUE;
  140. }
  141. }
  142. BOOL
  143. pMyImeInstalled (
  144. VOID
  145. )
  146. {
  147. //
  148. // Add code in this function that determines if your IME is installed on the system.
  149. //
  150. int i;
  151. UINT uACP;
  152. uACP = GetACP();
  153. switch(uACP) {
  154. case CP_CHINESE_GB: // Simplied Chinese
  155. case CP_CHINESE_BIG5: // Traditional Chinese
  156. g_CodePageArray[0] = uACP;
  157. DebugMsg(("pMyImeInstalled OK, CodePage %d is valid\r\n",g_CodePageArray[0]));
  158. return TRUE;
  159. }
  160. DebugMsg(("pMyImeInstalled Failed, CodePage %d is invalid\r\n",g_CodePageArray[0]));
  161. return FALSE;
  162. }
  163. LONG
  164. CALLBACK
  165. QueryVersion (
  166. OUT LPCSTR * ProductID,
  167. OUT LPUINT DllVersion,
  168. OUT LPINT * CodePageArray, OPTIONAL
  169. OUT LPCSTR * ExeNamesBuf, OPTIONAL
  170. OUT PVENDORINFO * VendorInfo
  171. )
  172. {
  173. LONG returnCode = ERROR_SUCCESS;
  174. //
  175. // Add code to pMyImeInstalled() to determine wether your IME is installed. If this function
  176. // returns TRUE, Setup will call this migration dll.
  177. //
  178. if (pMyImeInstalled()) {
  179. //
  180. // We are installed, so tell Setup who we are. ProductID is used
  181. // for display, so it must be localized. The ProductID string is
  182. // converted to UNICODE for use on Windows NT via the MultiByteToWideChar
  183. // Win32 API. The first element of CodePageArray is used to specify
  184. // the code page of ProductID, and if no elements are returned in
  185. // CodePageArray, Setup assumes CP_ACP.
  186. //
  187. LoadString(g_hInstance,IDS_PRODUCTID,g_MyProductId,MAX_PATH);
  188. *ProductID = g_MyProductId;
  189. //
  190. // Report our version. Zero is reserved for use by DLLs that
  191. // ship with Windows NT.
  192. //
  193. *DllVersion = 1;
  194. //
  195. // Because we have English messages, we return an array that has
  196. // the English language ID. The sublanguage is neutral because
  197. // we do not have currency, time, or other geographic-specific
  198. // information in our messages.
  199. //
  200. // Tip: If it makes more sense for your DLL to use locales,
  201. // return ERROR_NOT_INSTALLED if the DLL detects that an appropriate
  202. // locale is not installed on the machine.
  203. //
  204. //
  205. // The CODE PAGE INFO is determined in 'pMyImeInstalled'
  206. //
  207. *CodePageArray = g_CodePageArray;
  208. DebugMsg(("CodePageArray = %d\r\n",g_CodePageArray[0]));
  209. //
  210. // Use system default code page
  211. //
  212. //
  213. // ExeNamesBuf - we pass a list of file names (the long versions)
  214. // and let Setup find them for us. Keep this list short because
  215. // every instance of the file on every hard drive will be reported
  216. // in migrate.inf.
  217. //
  218. // Most applications don't need this behavior, because the registry
  219. // usually contains full paths to installed components.
  220. //
  221. *ExeNamesBuf = NULL;
  222. //
  223. // VendorInfo is designed to contain support information for a Migration DLL. Since it
  224. // may be used for UI, it's fields should also be localized.
  225. //
  226. LoadString(g_hInstance,MSG_VI_COMPANY_NAME ,g_MyVendorInfo.CompanyName ,256);
  227. LoadString(g_hInstance,MSG_VI_SUPPORT_NUMBER ,g_MyVendorInfo.SupportNumber ,256);
  228. LoadString(g_hInstance,MSG_VI_SUPPORT_URL ,g_MyVendorInfo.SupportUrl ,256);
  229. LoadString(g_hInstance,MSG_VI_INSTRUCTIONS ,g_MyVendorInfo.InstructionsToUser,1024);
  230. *VendorInfo = &g_MyVendorInfo;
  231. DebugMsg(("CompanyName = %s\r\n",g_MyVendorInfo.CompanyName));
  232. DebugMsg(("SupportNumber = %s\r\n",g_MyVendorInfo.SupportNumber));
  233. DebugMsg(("SupportUrl = %s\r\n",g_MyVendorInfo.SupportUrl));
  234. DebugMsg(("InstructionsToUser = %s\r\n",g_MyVendorInfo.InstructionsToUser));
  235. }
  236. else {
  237. //
  238. // If pMyImeInstalled returns false, we have nothing to do. By returning ERROR_NOT_INSTALLED,
  239. // we ensure that we will not be called again.
  240. //
  241. returnCode = ERROR_NOT_INSTALLED;
  242. }
  243. DebugMsg(("QueryVersion, return value = %d\r\n",returnCode));
  244. return returnCode;
  245. }
  246. //Save IME data file to working directory.
  247. BOOL SaveImeDataFile(LPSTR SourceDirectory, LPSTR TargetDirectory, TCHAR * FileBuf, BOOL CheckAll)
  248. {
  249. int lenSource = lstrlen(SourceDirectory);
  250. int lenTarget = lstrlen(TargetDirectory);
  251. HANDLE hfile;
  252. while (*FileBuf)
  253. {
  254. lstrcat(SourceDirectory, FileBuf);
  255. lstrcat(TargetDirectory, FileBuf);
  256. if ((GetFileAttributes(SourceDirectory) != 0xFFFFFFFF) &&
  257. (GetFileAttributes(SourceDirectory) != FILE_ATTRIBUTE_DIRECTORY)){
  258. if (!CopyFile(SourceDirectory, TargetDirectory, FALSE)) {
  259. DebugMsg(("Copy file %s to %s failed \r\n",SourceDirectory,TargetDirectory));
  260. } else {
  261. DebugMsg(("Copy file %s to %s OK \r\n",SourceDirectory,TargetDirectory));
  262. }
  263. } else {
  264. DebugMsg(("File %s doesn't exist, skip it ! \r\n",SourceDirectory));
  265. }
  266. FileBuf+=MAX_IME_DATA_FILE_NAME;
  267. SourceDirectory[lenSource]=0;
  268. TargetDirectory[lenTarget]=0;
  269. }
  270. return TRUE;
  271. }
  272. LONG
  273. CALLBACK
  274. Initialize9x (
  275. IN LPCSTR WorkingDirectory,
  276. IN LPCSTR SourceDirectories,
  277. LPVOID Reserved
  278. )
  279. {
  280. LONG returnCode = ERROR_SUCCESS;
  281. UINT len;
  282. TCHAR FilePath[MAX_PATH];
  283. TCHAR TargetPath[MAX_PATH];
  284. BOOL bInstall;
  285. UINT uACP;
  286. //
  287. // Because we returned ERROR_SUCCESS in QueryVersion, we are being
  288. // called for initialization. Therefore, we know screen savers are
  289. // enabled on the machine at this point.
  290. //
  291. //
  292. // Do any Windows9x side initialization that is necessary here.
  293. //
  294. DebugMsg(("Start ..., Initialize9x\r\n"));
  295. lstrcpy(TargetPath, WorkingDirectory);
  296. len=lstrlen(TargetPath);
  297. if (TargetPath[len-1] != '\\') {
  298. TargetPath[len] ='\\';
  299. TargetPath[++len] = 0;
  300. }
  301. DebugMsg(("Initialize9x, TargetPath = %s\r\n",TargetPath));
  302. len = GetSystemDirectory((LPSTR)FilePath, sizeof(FilePath));
  303. // Consider root directory
  304. if (FilePath[len - 1] != '\\') {
  305. FilePath[len] = '\\';
  306. FilePath[++len] = 0;
  307. }
  308. DebugMsg(("Initialize9x, SystemPath = %s\r\n",FilePath));
  309. uACP = GetACP();
  310. switch (uACP) {
  311. case CP_CHINESE_GB:
  312. {
  313. //
  314. // The Ime tables in CHS Win98 are already unicode format
  315. //
  316. // we don't need to do convert tables , just back up them
  317. //
  318. UINT CreateNestedDirectory(LPCTSTR, LPSECURITY_ATTRIBUTES);
  319. TCHAR szWin98Dir[MAX_PATH];
  320. OSVERSIONINFO OsVersion;
  321. OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  322. GetVersionEx(&OsVersion);
  323. lstrcpy(szWin98Dir,TargetPath);
  324. if ((OsVersion.dwMajorVersion == 4) &&
  325. (OsVersion.dwMinorVersion == 10)) {
  326. //
  327. // this is Windows 98, create a "Win98" subdirectory
  328. //
  329. DebugMsg(("Initialize9x, SaveImeDataFile, GB, Win98 identified !\r\n"));
  330. lstrcat(szWin98Dir,"Win98");
  331. DebugMsg(("Initialize9x, SaveImeDataFile, Create %s !\r\n",szWin98Dir));
  332. CreateNestedDirectory(szWin98Dir,NULL);
  333. DebugMsg(("Initialize9x, SaveImeDataFile, The target path become %s !\r\n",TargetPath));
  334. }
  335. if (! SaveImeDataFile(FilePath, TargetPath, &ChsDataFile[0][0], FALSE)) {
  336. DebugMsg(("Initialize9x, SaveImeDataFile, GB, failed !\r\n"));
  337. returnCode = ERROR_NOT_INSTALLED;
  338. }
  339. }
  340. break;
  341. case CP_CHINESE_BIG5:
  342. if (! SaveImeDataFile(FilePath, TargetPath, &ChtDataFile[0][0], TRUE)) {
  343. DebugMsg(("Initialize9x, SaveImeDataFile, BIG5, failed !\r\n"));
  344. returnCode = ERROR_NOT_INSTALLED;
  345. }
  346. break;
  347. default:
  348. DebugMsg(("Initialize9x, Invalid codepage !\r\n"));
  349. returnCode = ERROR_NOT_INSTALLED;
  350. }
  351. DebugMsg(("Initialize9x, SaveImeDataFile OK [%d]!\r\n",returnCode));
  352. return returnCode;
  353. }
  354. LONG
  355. CALLBACK
  356. MigrateUser9x (
  357. IN HWND ParentWnd,
  358. IN LPCSTR UnattendFile,
  359. IN HKEY UserRegKey,
  360. IN LPCSTR UserName,
  361. LPVOID Reserved
  362. )
  363. {
  364. DWORD returnCode = ERROR_SUCCESS;
  365. //
  366. // Avoid displaying any user interface when possible.
  367. //
  368. // We don't need to use UnattendFile settings because we are not
  369. // a service (such as a network redirector). Therefore, we do not
  370. // use the UnattendFile parameter.
  371. //
  372. //
  373. // Note: NO changes allowed on Win9x side, we can only read our
  374. // settings and save them in a file.
  375. //
  376. //
  377. // UserRegKey should be used instead of HKCU. You will be called once for
  378. // each user on the system (including logon user and administrator). Each time,
  379. // the correct user root will have been mapped into HKCU.
  380. //
  381. return returnCode;
  382. }
  383. LONG
  384. CALLBACK
  385. MigrateSystem9x (
  386. IN HWND ParentWnd,
  387. IN LPCSTR UnattendFile,
  388. LPVOID Reserved
  389. )
  390. {
  391. LONG returnCode = ERROR_SUCCESS;
  392. //
  393. // Gather all necessary system wide data in this function.
  394. //
  395. return returnCode;
  396. }
  397. LONG
  398. CALLBACK
  399. InitializeNT (
  400. IN LPCWSTR WorkingDirectory,
  401. IN LPCWSTR SourceDirectories,
  402. LPVOID Reserved
  403. )
  404. {
  405. LONG returnCode = ERROR_SUCCESS;
  406. int len;
  407. UINT uACP;
  408. //
  409. // Do any intialization for NT side processing in this function.
  410. //
  411. //Save working directory path
  412. WideCharToMultiByte(CP_ACP,
  413. 0,
  414. WorkingDirectory,
  415. -1,
  416. ImeDataDirectory,
  417. sizeof(ImeDataDirectory),
  418. NULL,
  419. NULL);
  420. DebugMsg(("InitializeNT, Save working directory path, ImeDataDirectory = %s\r\n",ImeDataDirectory));
  421. //Patch path with '\'
  422. len = lstrlen(ImeDataDirectory);
  423. if (ImeDataDirectory[len - 1] != '\\') {
  424. ImeDataDirectory[len] = '\\';
  425. ImeDataDirectory[++len] = 0;
  426. }
  427. DebugMsg(("InitializeNT, Patch path with '\', ImeDataDirectory = %s\r\n",ImeDataDirectory));
  428. DebugMsg(("InitializeNT, OK !\r\n"));
  429. uACP = GetACP();
  430. if (uACP == 936) {
  431. TCHAR szWin98Dir[MAX_PATH];
  432. //
  433. // check if this is CHS Win98
  434. //
  435. lstrcpy(szWin98Dir,ImeDataDirectory);
  436. //
  437. // Check if ...\Win98 directory is existing or not
  438. //
  439. // If it is, then it means we're migrating Win98
  440. //
  441. ConcatenatePaths(szWin98Dir,"Win98",sizeof(szWin98Dir));
  442. DebugMsg(("ImeEudcConvert::MigrateImeEUDCTables2 ,Test IME98 directory %s !\r\n",szWin98Dir));
  443. if (GetFileAttributes(szWin98Dir) == 0xFFFFFFFF || ! (GetFileAttributes(szWin98Dir) & FILE_ATTRIBUTE_DIRECTORY)) {
  444. g_bCHSWin98 = FALSE;
  445. } else {
  446. g_bCHSWin98 = TRUE;
  447. }
  448. }
  449. return returnCode;
  450. }
  451. LONG
  452. CALLBACK
  453. MigrateUserNT (
  454. IN HINF UnattendInfHandle,
  455. IN HKEY UserRegKey,
  456. IN LPCWSTR UserName,
  457. LPVOID Reserved
  458. )
  459. {
  460. LONG returnCode = ERROR_SUCCESS;
  461. //
  462. // Migrate all necessary user settings for your IME in this function call. Once again, remember
  463. // to use UserRegKey in place of HKCU.
  464. //
  465. DebugMsg(("MigrateUserNT,Starting ... !\r\n"));
  466. DebugMsg(("MigrateUserNT,The user is %ws !\r\n",UserName));
  467. if (!MigrateImeEUDCTables(UserRegKey)) {
  468. returnCode = ERROR_NOT_INSTALLED;
  469. DebugMsg(("MigrateUserNT,MigrateImeEUDCTables failed !\r\n"));
  470. } else {
  471. DebugMsg(("MigrateUserNT,MigrateImeEUDCTables OK !\r\n"));
  472. }
  473. if (!MigrateImeEUDCTables2(UserRegKey)) {
  474. returnCode = ERROR_NOT_INSTALLED;
  475. DebugMsg(("MigrateUserNT,MigrateImeEUDCTables2 failed !\r\n"));
  476. } else {
  477. DebugMsg(("MigrateUserNT,MigrateImeEUDCTables2 OK !\r\n"));
  478. }
  479. DebugMsg(("MigrateUserNT,Finished !\r\n"));
  480. return returnCode;
  481. }
  482. LONG
  483. CALLBACK
  484. MigrateSystemNT (
  485. IN HINF UnattendInfHandle,
  486. LPVOID Reserved
  487. )
  488. {
  489. LONG returnCode = ERROR_SUCCESS;
  490. //
  491. // Migrate all necessary system settings for your IME in this function call. Anything relative to
  492. // a user should have been handled during MigrateUserNT.
  493. //
  494. UINT uACP;
  495. uACP = GetACP();
  496. switch(uACP) {
  497. case CP_CHINESE_GB: // Simplied Chinese
  498. if (ConvertChsImeData()) {
  499. DebugMsg(("MigrateSystemNT,GB, ConvertChsImeData OK !\r\n"));
  500. } else {
  501. DebugMsg(("MigrateSystemNT,GB, ConvertChsImeData OK !\r\n"));
  502. }
  503. MovePerUserIMEData();
  504. if (CHSBackupWinABCUserDict(ImeDataDirectory)) {
  505. DebugMsg(("MigrateSystemNT,GB, CHSBackupWinABCUserDict OK !\r\n"));
  506. } else {
  507. DebugMsg(("MigrateSystemNT,GB, CHSBackupWinABCUserDict OK !\r\n"));
  508. }
  509. if (CHSDeleteGBKKbdLayout()) {
  510. DebugMsg(("MigrateSystemNT,GB, CHSDeleteGBKKbdLayout OK !\r\n"));
  511. } else {
  512. DebugMsg(("MigrateSystemNT,GB, CHSDeleteGBKKbdLayout OK !\r\n"));
  513. }
  514. break;
  515. case CP_CHINESE_BIG5: // Traditional Chinese
  516. if (ConvertChtImeData()) {
  517. DebugMsg(("MigrateSystemNT,BIG5, ConvertChtImeData OK !\r\n"));
  518. } else {
  519. DebugMsg(("MigrateSystemNT,BIG5, ConvertChtImeData OK !\r\n"));
  520. }
  521. MovePerUserIMEData();
  522. break;
  523. default:
  524. returnCode = ERROR_NOT_INSTALLED;
  525. }
  526. return returnCode;
  527. }