// // 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; }