/**************************************************************************\ * Module Name: Winmain.cpp * * Copyright (C) 2000, Microsoft Corporation * * Korean IME 6.1 install utility * * History: * 11-Dec-2000 CSLim Ported from Satori 8.1 code \**************************************************************************/ #include "private.h" #include #include "imkrinst.h" #include "regtip.h" #include "insert.h" #include "..\tip\resource.h" #include "..\version\verres.h" // Safe String #define STRSAFE_NO_DEPRECATE #include "strsafe.h" #define MEMALLOC(x) LocalAlloc(LMEM_FIXED, x) #define MEMFREE(x) LocalFree(x) // Profile reg key #define SZTIPREG_LANGPROFILE_TEMPLATE TEXT("SOFTWARE\\Microsoft\\CTF\\TIP\\%s\\LanguageProfile\\0x00000412") #if defined(_WIN64) #define SZTIPREG_LANGPROFILE_TEMPLATE_WOW64 TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\CTF\\TIP\\%s\\LanguageProfile\\0x00000412") #endif #ifdef DEBUG CCicCriticalSectionStatic g_cs; #endif // IA64 IME does not support IME Pad. So we just need to take care Wow64 IME in IA64. #if !defined(_WIN64) // Pad Applet Registry location #define SZPADSHARE TEXT("SOFTWARE\\Microsoft\\TIP Shared\\1.1\\IMEPad\\1042") #define SZAPPLETCLSID TEXT("SOFTWARE\\Microsoft\\TIP Shared\\1.1\\IMEPad\\1042\\AppletCLSIDList") #define SZAPPLETIID TEXT("SOFTWARE\\Microsoft\\TIP Shared\\1.1\\IMEPad\\1042\\AppletIIDList") #else #define SZPADSHARE TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\TIP Shared\\1.1\\IMEPad\\1042") #define SZAPPLETCLSID TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\TIP Shared\\1.1\\IMEPad\\1042\\AppletCLSIDList") #define SZAPPLETIID TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\TIP Shared\\1.1\\IMEPad\\1042\\AppletIIDList") #endif ///////////////////////////////////////////////////////////////////////////// // Script run routines BOOL CmdSetupDefaultParameters(); BOOL CmdSetVersion(LPCTSTR szParam); BOOL CmdFileList(LPCTSTR szFormat); BOOL CmdPreSetupCheck(LPCTSTR szParam); BOOL CmdRenamePEFile(LPCTSTR szParam); BOOL CmdRenameFile(LPCTSTR szParam); BOOL CmdRegisterInterface(LPCTSTR szParam); BOOL CmdRegisterInterfaceWow64(LPCTSTR szParam); BOOL CmdRegisterIMEandTIP(LPCTSTR szParam); BOOL CmdRegisterPackageVersion(void); BOOL CmdRegisterPadOrder(void); BOOL CmdAddToPreload(LPCTSTR szParam); BOOL CmdPrepareMigration(LPCTSTR szParam); BOOL CmdCreateDirectory(LPCTSTR szParam); BOOL CmdRegisterHelpDirs(); ///////////////////////////////////////////////////////////////////////////// // Private Functions // Utility functions static DWORD WINAPI ProcessScriptFile(); static void RegisterIMEWithFixedHKL(LPCTSTR szHKL, LPCTSTR szIMEFileName, LPCTSTR szIMEName); static void cdecl LogOutDCPrintf(LPCTSTR lpFmt, va_list va); static void DebugLog(LPCTSTR szFormat, ...); static void ErrorLog(LPCTSTR szFormat, ...); static INT ParseEnvVar(LPTSTR szBuffer, const UINT arg_nLength); static void TrimString(LPTSTR szString); static BOOL fExistFile(LPCTSTR szFilePath); static BOOL fOldIMEsExist(); static BOOL WINAPI ReplaceFileOnReboot (LPCTSTR pszExisting, LPCTSTR pszNew); static void GetPEFileVersion(LPTSTR szFilePath, DWORD *pdwMajorVersion, DWORD *pdwMiddleVersion, DWORD *pdwMinorVersion, DWORD *pdwBuildNumber); static BOOL ActRenameFile(LPCTSTR szSrcPath, LPCTSTR tszDstPath, DWORD dwFileAttributes); static void RegisterTIP(LPCTSTR szTIPName); static void RegisterTIPWow64(LPCTSTR szTIPName); static BOOL RegisterRUNKey(LPCTSTR szParam); static BOOL MakeSIDList(); static PSECURITY_DESCRIPTOR CreateSD(); static PSID MyCreateSid(DWORD dwSubAuthority); // HKL Helpers static void HKLHelpSetDefaultKeyboardLayout(HKEY hKeyHKCU, HKL hKL, BOOL fSetToDefault); static BOOL HKLHelp412ExistInPreload(HKEY hKeyCU); static HKL GetHKLfromHKLM(LPTSTR argszIMEFile); static void RestoreMajorVersionRegistry(); ///////////////////////////////////////////////////////////////////////////// // Global variables ///////////////////////////////////////////////////////////////////////////// static TCHAR g_szCurrentDirectory[MAX_PATH] = {0}; // Directory in where this EXE resides. static TCHAR g_szScriptFile[MAX_PATH] = {0}; // File name (not full path) of script file. static TCHAR g_szSetupProgram[MAX_PATH] = {0}; // File name (not full path) of setup program. static TCHAR g_szSystemDirectory[MAX_PATH] = {0}; // System directory. static TCHAR g_szErrorMessage[200] = {0}; // Global buffer for last error message. static BOOL g_fDebugLog = FALSE; // Dump debug message when true. static BOOL g_fErrorLog = FALSE; // Dump error message when true. static DWORD g_dwMajorVersion = 0; // Package version of this installation. static DWORD g_dwMiddleVersion = 0; static DWORD g_dwMinorVersion = 0; static DWORD g_dwBuildNumber = 0; static std::set g_FileList; // FileListSet. Used to store set of file paths given by "CmdFileList" // script command. TCHAR g_szVersionKeyCur[MAX_PATH] = {0}; BOOL g_fExistNewerVersion = FALSE; /*--------------------------------------------------------------------------- WinMain ---------------------------------------------------------------------------*/ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { LPTSTR szHitPtr; LPTSTR szCommandLine; size_t cchCommandLine; if (FAILED(StringCchLength(GetCommandLine(), MAX_PATH, &cchCommandLine))) return (0); szCommandLine = new TCHAR[cchCommandLine + 1]; if (szCommandLine == NULL) return (0); // szCommandLine contains all command line. // Will be modified by _tcstok. StringCchCopy(szCommandLine, cchCommandLine+1, GetCommandLine()); // TEMP Code // LogOutDCPrintf(TEXT("WinMain CommandLine arg: %s"), szCommandLine); CoInitialize(NULL); szHitPtr = _tcstok(szCommandLine, TEXT("\"")); // g_szCurrentDirectory has path for the process. (IMKRINST.EXE) StringCchCopy(g_szCurrentDirectory, ARRAYSIZE(g_szCurrentDirectory), szHitPtr); szHitPtr = _tcsrchr(g_szCurrentDirectory, TEXT('\\')); // if g_szCurrentDirectory contains full path, if (szHitPtr != NULL) { *szHitPtr = 0; // terminate with the last '\' character to obtain current directory, StringCchCopy(g_szSetupProgram, ARRAYSIZE(g_szSetupProgram), szHitPtr + 1); // then copy the rest (after last '\') to g_szScriptFile. } else { StringCchCopy(g_szSetupProgram, ARRAYSIZE(g_szSetupProgram), g_szCurrentDirectory); // Otherwise (g_szCurrentDirectory is not full path), copy entire GetCurrentDirectory(MAX_PATH, g_szCurrentDirectory); // to g_szScriptFile and obtain current directory by GetCurrentDirectory. } StringCchCopy(g_szScriptFile, ARRAYSIZE(g_szScriptFile), g_szSetupProgram); szHitPtr = _tcsrchr(g_szScriptFile, TEXT('.')); if (szHitPtr != NULL) // If g_szScriptFile contains '.' character, find the last one *szHitPtr = 0; // and terminate string with it, then concatenate ".inf" to it. // Usually it results ".exe" -> ".inf" replacement. If g_szScriptFile // doesn't have '.' character, just concatenate ".ini". lstrcat(g_szScriptFile, TEXT(".ini")); // Get system32 dir GetSystemDirectory(g_szSystemDirectory, ARRAYSIZE(g_szSystemDirectory)); // g_szCurrentDirectory, g_szSetupProgram, g_szSystemDirectory and g_szScriptFile are prepared. // szCommandLine will be no longer used. // We can use these environment variable in the process. SetEnvironmentVariable(TEXT("SETUPSOURCE"), g_szCurrentDirectory); SetEnvironmentVariable(TEXT("SETUPEXE"), g_szSetupProgram); SetEnvironmentVariable(TEXT("SETUPINF"), g_szScriptFile); SetEnvironmentVariable(TEXT("SYSTEMDIR"), g_szSystemDirectory); delete[] szCommandLine; szCommandLine = NULL; ////////////////////////////////////////////////////////////////////////// // Read and run Script file switch (ProcessScriptFile()) { case errNoError: break; case errPreSetupCheck: { #ifdef NEVER for(set::iterator itFLE = g_FileList.begin(); itFLE != g_FileList.end(); itFLE++){ DebugLog(TEXT("Cleanup: Deleting Source file: %s"), itFLE->szFileName); DeleteFile(itFLE->szFileName); } #endif // NEVER } break; default: DebugLog(g_szErrorMessage); } #ifdef NEVER for (set::iterator itFLE = g_FileList.begin(); itFLE != g_FileList.end(); itFLE++) { ErrorLog(TEXT("Warning: File %s in CmdFileList will be removed without any processing"), itFLE->szFileName); DeleteFile(itFLE->szFileName); } #endif // NEVER CoUninitialize(); return(0); } ///////////////////////////////////////////////////////////////////////////// // Main Script Processing functions ///////////////////////////////////////////////////////////////////////////// inline LPCTSTR GetParameter(LPTSTR szLineBuffer) { return(szLineBuffer + lstrlen(szLineBuffer) + 1); } /*--------------------------------------------------------------------------- ProcessScriptFile Read script file. Dispatch commands for each line. ---------------------------------------------------------------------------*/ DWORD WINAPI ProcessScriptFile() { TCHAR szScriptFilePath[MAX_PATH]; FILE *fileScript; wsprintf(szScriptFilePath, TEXT("%s\\%s"), g_szCurrentDirectory, g_szScriptFile); fileScript = _tfopen(szScriptFilePath, TEXT("rt")); if (fileScript != NULL) { TCHAR szLineBuffer[_cchBuffer]; LPTSTR szCommand; // Parse command // Command form : while (_fgetts(szLineBuffer, _cchBuffer, fileScript) != NULL) { // Chop CR code. szLineBuffer[lstrlen(szLineBuffer) - 1] = 0; // Empty or Comment line if (lstrlen(szLineBuffer) == 0 || (_tcsncmp(TEXT("//"), szLineBuffer, 2) == 0)) continue; DebugLog(TEXT("Line: %s"), szLineBuffer); szCommand = _tcstok(szLineBuffer, TEXT(":")); if (szCommand == NULL) { // Dispatch each commands. DebugLog(TEXT("Ignore line")); } else if (lstrcmpi(szCommand, TEXT("DebugLogOn")) == 0) { g_fDebugLog = TRUE; g_fErrorLog = TRUE; DebugLog(TEXT("Turn on DebugLog")); } else if (lstrcmpi(szCommand, TEXT("DebugLogOff")) == 0) { DebugLog(TEXT("Turn off DebugLog")); g_fDebugLog = FALSE; } else if (lstrcmpi(szCommand, TEXT("ErrorLogOn")) == 0) { g_fErrorLog = TRUE; DebugLog(TEXT("Turn on DebugLog")); } else if (lstrcmpi(szCommand, TEXT("ErrorLogOff")) == 0) { DebugLog(TEXT("Turn off DebugLog")); g_fErrorLog = FALSE; } else if (lstrcmpi(szCommand, TEXT("FileList")) == 0) { if (!CmdFileList(GetParameter(szCommand))) return(errFileList); } else if (lstrcmpi(szCommand, TEXT("SetupDefaultParameters")) == 0) { if (!CmdSetupDefaultParameters()) return(errSetDefaultParameters); } else if (lstrcmpi(szCommand, TEXT("SetVersion")) == 0) { if (!CmdSetVersion(GetParameter(szCommand))) return(errSetVersion); } else if (lstrcmpi(szCommand, TEXT("PreSetupCheck")) == 0) { if (!CmdPreSetupCheck(GetParameter(szCommand))) return(errPreSetupCheck); } else if (lstrcmpi(szCommand, TEXT("RenamePEFile")) == 0) { if (!CmdRenamePEFile(GetParameter(szCommand))) return(errRenameFile); } else if (lstrcmpi(szCommand, TEXT("RenameFile")) == 0) { if (!CmdRenameFile(GetParameter(szCommand))) return(errRenameFile); } else if (lstrcmpi(szCommand, TEXT("RegisterIMEandTIP")) == 0) { if (!CmdRegisterIMEandTIP(GetParameter(szCommand))) return(errRegisterIMEandTIP); } else if (lstrcmpi(szCommand, TEXT("RegisterPackageVersion")) == 0) { if (!CmdRegisterPackageVersion()) return(errRegisterPackageVersion); } else if (lstrcmpi(szCommand, TEXT("RegisterInterface")) == 0) { if (!CmdRegisterInterface(GetParameter(szCommand))) return(errRegisterInterface); } else if (lstrcmpi(szCommand, TEXT("RegisterInterfaceWow64")) == 0) { if (!CmdRegisterInterfaceWow64(GetParameter(szCommand))) return(errRegisterInterfaceWow64); } else if (lstrcmpi(szCommand, TEXT("RegisterPadOrder")) == 0) { if (!CmdRegisterPadOrder()) return(errRegisterPadOrder); } else if (lstrcmpi(szCommand, TEXT("AddToPreload")) == 0) { if (!CmdAddToPreload(GetParameter(szCommand))) return(errAddToPreload); } else if (lstrcmpi(szCommand, TEXT("PrepareMigration")) == 0) { if (!CmdPrepareMigration(GetParameter(szCommand))) return(errPrepareMigration); } else if (lstrcmpi(szCommand, TEXT("CreateDirectory")) == 0) { if (!CmdCreateDirectory(GetParameter(szCommand))) return(errCmdCreateDirectory); } else if (lstrcmpi(szCommand, TEXT("RegisterHelpDirs")) == 0) { if (!CmdRegisterHelpDirs()) return(errCmdRegisterHelpDirs); } else DebugLog(TEXT("Ignore line")); } fclose(fileScript); } else { wsprintf(g_szErrorMessage, TEXT("Cannot open %s"), g_szScriptFile); return(errNoFile); } return(errNoError); } ///////////////////////////////////////////////////////////////////////////// // Command handlers. Which are invoked from ProcessScriptFile ///////////////////////////////////////////////////////////////////////////// /*--------------------------------------------------------------------------- CmdSetupDefaultParameters Setup default parameters. For now, it only sets default ProductVersion value. ---------------------------------------------------------------------------*/ #define MAKE_STR(a) #a #define MAKE_VERSTR(a, b, c, d) MAKE_STR(a.b.c.d) #define VERRES_VERSIONSTR MAKE_VERSTR(VERRES_VERSION_MAJOR, VERRES_VERSION_MINOR, VERRES_VERSION_BUILD, VERRES_VERSION_REVISION) BOOL CmdSetupDefaultParameters() { _stscanf(TEXT(VERRES_VERSIONSTR), TEXT("%d.%d.%d.%d"), &g_dwMajorVersion, &g_dwMiddleVersion, &g_dwMinorVersion, &g_dwBuildNumber); wsprintf(g_szVersionKeyCur, "%s\\%d.%d\\%s", g_szVersionKey, g_dwMajorVersion, g_dwMiddleVersion, g_szVersion); DebugLog(TEXT("CmdSetupDefaultParameters: Version Info : %d.%d.%d.%d"), g_dwMajorVersion, g_dwMiddleVersion, g_dwMinorVersion, g_dwBuildNumber); return(TRUE); } /*--------------------------------------------------------------------------- CmdSetVersion Overwrites default ProductVersion value with value provided in script file. ---------------------------------------------------------------------------*/ BOOL CmdSetVersion(LPCTSTR szParam) { int iNum = _stscanf(szParam, TEXT("%d.%d.%d.%d"), &g_dwMajorVersion, &g_dwMiddleVersion, &g_dwMinorVersion, &g_dwBuildNumber); wsprintf(g_szVersionKeyCur, "%s\\%d.%d\\%s", g_szVersionKey, g_dwMajorVersion, g_dwMiddleVersion, g_szVersion); if (iNum == 4) { DebugLog(TEXT("CmdSetVersion: Version Info : %d.%d.%d.%d"), g_dwMajorVersion, g_dwMiddleVersion, g_dwMinorVersion, g_dwBuildNumber); return(TRUE); } else { ErrorLog(TEXT("CmdSetVersion: Failed to retrieve version number from string [%s]"), szParam); wsprintf(g_szErrorMessage, TEXT("CmdSetVersion: Failed to retrieve version number from string [%s]"), szParam); return(FALSE); } } /*--------------------------------------------------------------------------- CmdFileList Add file to the file list. Files in the file list will be deleted when they become no longer needed. ---------------------------------------------------------------------------*/ BOOL CmdFileList(LPCTSTR szFormat) { FLE flElem; TCHAR szExpandedFileName[MAX_PATH]; flElem.fRemoved = FALSE; StringCchCopy(flElem.szFileName, MAX_PATH, szFormat); if (ExpandEnvironmentStrings(flElem.szFileName, szExpandedFileName, sizeof(szExpandedFileName)/sizeof(TCHAR))) StringCchCopy(flElem.szFileName, MAX_PATH, szExpandedFileName); // Add the element to file list set. if (g_FileList.insert(flElem).second) DebugLog(TEXT("Add to CmdFileList \"%s\" -> Added."), szFormat); else ErrorLog(TEXT("Add to CmdFileList \"%s\" -> Not added. Duplicate?"), szFormat); return(TRUE); } /*--------------------------------------------------------------------------- CmdPreSetupCheck Check whether the newer IME has been installed. Return TRUE when we can proceed. !!! FALSE will terminates setup. !!! ---------------------------------------------------------------------------*/ BOOL CmdPreSetupCheck(LPCTSTR szParam) { HKEY hKey; TCHAR szInstalledVersionString[30]; DWORD cbInstalledVersionString = sizeof(szInstalledVersionString); DWORD dwInstalledMajorVersion, dwInstalledMiddleVersion, dwInstalledMinorVersion, dwInstalledBuildNumber; BOOL fResult = TRUE; RestoreMajorVersionRegistry(); // // root // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szVersionKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS ) { cbInstalledVersionString = sizeof(szInstalledVersionString); RegQueryValueEx(hKey, g_szVersion, NULL, NULL, (LPBYTE)szInstalledVersionString, &cbInstalledVersionString); if (_stscanf(szInstalledVersionString, TEXT("%d.%d"), &dwInstalledMajorVersion, &dwInstalledMiddleVersion) == 2) { if (VersionComparison2(g_dwMajorVersion, g_dwMiddleVersion) < VersionComparison2(dwInstalledMajorVersion, dwInstalledMiddleVersion)) { DebugLog(TEXT("Newer version of IME has been already installed.")); wsprintf(g_szErrorMessage, TEXT("Newer version of IME has been already installed. but, continue to setup")); g_fExistNewerVersion = TRUE; } } RegCloseKey(hKey); } // // current // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szVersionKeyCur, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { cbInstalledVersionString = sizeof(szInstalledVersionString); RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szInstalledVersionString, &cbInstalledVersionString); if (_stscanf(szInstalledVersionString, TEXT("%d.%d.%d.%04d"), &dwInstalledMajorVersion, &dwInstalledMiddleVersion, &dwInstalledMinorVersion, &dwInstalledBuildNumber) == 4) { if ( VersionComparison4(g_dwMajorVersion, g_dwMiddleVersion, g_dwMinorVersion, g_dwBuildNumber) < VersionComparison4(dwInstalledMajorVersion, dwInstalledMiddleVersion, dwInstalledMinorVersion, dwInstalledBuildNumber)) { DebugLog(TEXT("Newer version of IME has been already installed.")); wsprintf(g_szErrorMessage, TEXT("Newer version of IME has been already installed.")); fResult = FALSE; } } RegCloseKey(hKey); } return(fResult); } /*--------------------------------------------------------------------------- CmdRenamePEFile Rename file with PE format version comparison. ---------------------------------------------------------------------------*/ BOOL CmdRenamePEFile(LPCTSTR szParam) { TCHAR szSrc[MAX_PATH], szDst[MAX_PATH]; TCHAR szExpandedSrc[MAX_PATH], szExpandedDst[MAX_PATH]; LPTSTR szHitPtr; DWORD dwFileAttributes = FILE_ATTRIBUTE_NORMAL; DWORD dwSrcMajorVersion, dwSrcMiddleVersion, dwSrcMinorVersion, dwSrcBuildNumber; DWORD dwDstMajorVersion, dwDstMiddleVersion, dwDstMinorVersion, dwDstBuildNumber; szHitPtr = _tcschr(szParam, TEXT(',')); if (szHitPtr == NULL) { ErrorLog(TEXT("CmdRenamePEFile: Invalid parameters (%s)"), szParam); wsprintf(g_szErrorMessage, TEXT("CmdRenamePEFile: Invalid parameters (%s)"), szParam); return(FALSE); } *szHitPtr = 0; StringCchCopy(szSrc, ARRAYSIZE(szSrc), szParam); StringCchCopy(szDst, ARRAYSIZE(szDst), szHitPtr + 1); // Here, szDst may contain optional parameter. szHitPtr = _tcschr(szDst, TEXT(',')); if (NULL != szHitPtr) { *szHitPtr = 0; _stscanf(szHitPtr + 1, TEXT("%d"), &dwFileAttributes); } TrimString(szSrc); TrimString(szDst); ExpandEnvironmentStrings(szSrc, szExpandedSrc, sizeof(szExpandedSrc)); ExpandEnvironmentStrings(szDst, szExpandedDst, sizeof(szExpandedDst)); DebugLog(TEXT("CmdRenamePEFile: szExpandedSrc = %s, szExpandedDst = %s"), szExpandedSrc, szExpandedDst); GetPEFileVersion(szExpandedSrc, &dwSrcMajorVersion, &dwSrcMiddleVersion, &dwSrcMinorVersion, &dwSrcBuildNumber); GetPEFileVersion(szExpandedDst, &dwDstMajorVersion, &dwDstMiddleVersion, &dwDstMinorVersion, &dwDstBuildNumber); DebugLog(TEXT("SrcVersion: (%d.%d.%d.%d), DstVersion: (%d.%d.%d.%d)"), dwSrcMajorVersion, dwSrcMiddleVersion, dwSrcMinorVersion, dwSrcBuildNumber, dwDstMajorVersion, dwDstMiddleVersion, dwDstMinorVersion, dwDstBuildNumber); if (VersionComparison4(0, 0, 0, 0) == VersionComparison4(dwSrcMajorVersion, dwSrcMinorVersion, dwSrcMiddleVersion, dwSrcBuildNumber)) ErrorLog(TEXT("Version of source file (%s) is 0.0.0.0. May be file not found."), szSrc); if(VersionComparison4(dwSrcMajorVersion, dwSrcMiddleVersion, dwSrcMinorVersion, dwSrcBuildNumber) < VersionComparison4(dwDstMajorVersion, dwDstMiddleVersion, dwDstMinorVersion, dwDstBuildNumber)) { DebugLog(TEXT("CmdRenamePEFile: Source version is less than Destination. Copy skipped and Source will be deleted.")); if(DeleteFile(szSrc)) { FLE fleKey; StringCchCopy(fleKey.szFileName, MAX_PATH, szSrc); g_FileList.erase(fleKey); } else DebugLog(TEXT("CmdRenamePEFile: Failed to delete Source file (%s)"), szSrc); } else { DebugLog(TEXT("CmdRenamePEFile: Invoke ActRenameFile")); ActRenameFile(szSrc, szDst, dwFileAttributes); } return(TRUE); } /*--------------------------------------------------------------------------- CmdRenameFile Rename file without version comparison ---------------------------------------------------------------------------*/ BOOL CmdRenameFile(LPCTSTR szParam) { TCHAR szSrc[MAX_PATH], szDst[MAX_PATH]; TCHAR szExpandedSrc[MAX_PATH], szExpandedDst[MAX_PATH]; LPTSTR szHitPtr; DWORD dwFileAttributes = FILE_ATTRIBUTE_NORMAL; szHitPtr = _tcschr(szParam, TEXT(',')); if (szHitPtr == NULL) { ErrorLog(TEXT("CmdRenameFile: Invalid parameters (%s)"), szParam); wsprintf(g_szErrorMessage, TEXT("CmdRenameFile: Invalid parameters (%s)"), szParam); return(FALSE); } *szHitPtr = 0; StringCchCopy(szSrc, ARRAYSIZE(szSrc), szParam); StringCchCopy(szDst, ARRAYSIZE(szDst), szHitPtr + 1); // Here, szDst may contain optional parameter. szHitPtr = _tcschr(szDst, TEXT(',')); if (szHitPtr != NULL) { *szHitPtr = 0; _stscanf(szHitPtr + 1, TEXT("%d"), &dwFileAttributes); } TrimString(szSrc); TrimString(szDst); ExpandEnvironmentStrings(szSrc, szExpandedSrc, sizeof(szExpandedSrc)); ExpandEnvironmentStrings(szDst, szExpandedDst, sizeof(szExpandedDst)); DebugLog(TEXT("RanemeFile: szExpandedSrc = %s, szExpandedDst = %s"), szExpandedSrc, szExpandedDst); ActRenameFile(szExpandedSrc, szExpandedDst, dwFileAttributes); return(TRUE); } /*--------------------------------------------------------------------------- RegisterIMEWithFixedHKL ---------------------------------------------------------------------------*/ void RegisterIMEWithFixedHKL(LPCTSTR szHKL, LPCTSTR szIMEFileName, LPCTSTR szIMEName) { HKEY hKeyKbdLayout; HKEY hKeyOneIME; if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts"), &hKeyKbdLayout) != ERROR_SUCCESS) return; if (RegCreateKey(hKeyKbdLayout, szHKL, &hKeyOneIME) != ERROR_SUCCESS) { RegCloseKey(hKeyKbdLayout); return; } if (RegSetValueEx(hKeyOneIME, TEXT("Ime File"), 0, REG_SZ, (CONST BYTE*)szIMEFileName, (lstrlen(szIMEFileName) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) goto WriteImeLayoutFail; if (RegSetValueEx(hKeyOneIME, TEXT("Layout Text"), 0, REG_SZ, (CONST BYTE*)szIMEName, (lstrlen(szIMEName) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) goto WriteImeLayoutFail; WriteImeLayoutFail: RegCloseKey(hKeyOneIME); RegCloseKey(hKeyKbdLayout); } /*--------------------------------------------------------------------------- CmdRegisterInterface Invoke SelfReg. If given file is DLL, call DllRegisterServer export function. If given file is EXE, run it with "/RegServer" command line option. ---------------------------------------------------------------------------*/ typedef HRESULT (STDAPICALLTYPE *pfnDllRegisterServerType)(void); BOOL CmdRegisterInterface(LPCTSTR szParam) { TCHAR szExpandedModulePath[MAX_PATH]; HRESULT hr = S_FALSE; ExpandEnvironmentStrings(szParam, szExpandedModulePath, sizeof(szExpandedModulePath)); TrimString(szExpandedModulePath); INT iLen = 0; iLen = lstrlen(szExpandedModulePath); if (iLen < 4) { ErrorLog(TEXT("CmdRegisterInterface: Too short szExpandedModulePath (%s)"), szExpandedModulePath); wsprintf(g_szErrorMessage, TEXT("CmdRegisterInterface: Invalid Parameters.")); return(FALSE); } if (lstrcmpi(TEXT(".dll"), &szExpandedModulePath[iLen - 4]) == 0) { DebugLog(TEXT("CmdRegisterInterface: DLL mode for %s"), szExpandedModulePath); HINSTANCE hLib = LoadLibrary(szExpandedModulePath); if (hLib != NULL) { pfnDllRegisterServerType pfnDllRegisterServer = (pfnDllRegisterServerType)GetProcAddress(hLib, "DllRegisterServer"); if (pfnDllRegisterServer != NULL) { hr = pfnDllRegisterServer(); ErrorLog(TEXT("CmdRegisterInterface: hResult=%x"), hr); } FreeLibrary(hLib); } } else { if (lstrcmpi(TEXT(".exe"), &szExpandedModulePath[iLen - 4]) == 0) { DebugLog(TEXT("CmdRegisterInterface: EXE mode for %s"), szExpandedModulePath); TCHAR szCommandBuffer[MAX_PATH * 2]; wsprintf(szCommandBuffer, TEXT("%s /RegServer"), szExpandedModulePath); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); if (CreateProcess(NULL, szCommandBuffer, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi)) { DebugLog(TEXT("CmdRegisterInterface: Running \"%s\". Waiting for the process termination."), szCommandBuffer); WaitForSingleObject(pi.hProcess, INFINITE); DebugLog(TEXT("CmdRegisterInterface: \"%s\" terminates."), szCommandBuffer); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); hr = S_OK; } else { DWORD dwError = GetLastError(); ErrorLog(TEXT("CmdRegisterInterface: CreateProcess(\"%s\") failed with error code = %d(%x)"), szCommandBuffer, dwError, dwError); } } else ErrorLog(TEXT("Cannot detect module type for %s. Skipped."), szExpandedModulePath); } return(SUCCEEDED(hr)); } /*--------------------------------------------------------------------------- CmdRegisterInterfaceWow64 Invoke SelfReg. If given file is DLL, call DllRegisterServer export function. If given file is EXE, run it with "/RegServer" command line option. ---------------------------------------------------------------------------*/ BOOL CmdRegisterInterfaceWow64(LPCTSTR szParam) { #if defined(_WIN64) TCHAR szExpandedModulePath[MAX_PATH]; TCHAR szCommandBuffer[MAX_PATH * 2]; STARTUPINFO si; PROCESS_INFORMATION pi; ExpandEnvironmentStrings(szParam, szExpandedModulePath, sizeof(szExpandedModulePath)); TrimString(szExpandedModulePath); INT iLen = 0; iLen = lstrlen(szExpandedModulePath); if (iLen < 4) { ErrorLog(TEXT("CmdRegisterInterfaceWow64: Too short szExpandedModulePath (%s)"), szExpandedModulePath); wsprintf(g_szErrorMessage, TEXT("CmdRegisterInterface: Invalid Parameters.")); return(FALSE); } if (lstrcmpi(TEXT(".dll"), &szExpandedModulePath[iLen - 4]) == 0) { // First get systemWow64Directory TCHAR szSysWow64Dir[MAX_PATH] = TEXT(""); HMODULE hmod = GetModuleHandle(TEXT("kernel32.dll")); DebugLog(TEXT("CmdRegisterInterfaceWow64: DLL mode for %s"), szExpandedModulePath); if (hmod == NULL) { DebugLog(TEXT("CmdRegisterInterfaceWow64: Faile to load kernel32.dll")); return (TRUE); } UINT (WINAPI* pfnGetSystemWow64Directory)(LPTSTR, UINT); (FARPROC&)pfnGetSystemWow64Directory = GetProcAddress (hmod, "GetSystemWow64DirectoryA"); if (pfnGetSystemWow64Directory == NULL) { DebugLog(TEXT("CmdRegisterInterfaceWow64: Faile to load GetSystemWow64DirectoryA API")); return (TRUE); } /* * if GetSystemWow64Directory fails and sets the last error to * ERROR_CALL_NOT_IMPLEMENTED, we're on a 32-bit OS */ if (((pfnGetSystemWow64Directory)(szSysWow64Dir, ARRAYSIZE(szSysWow64Dir)) == 0) && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { DebugLog(TEXT("CmdRegisterInterfaceWow64: Failed to load GetSystemWow64DirectoryA API")); return (TRUE); } wsprintf(szCommandBuffer, TEXT("%s\\regsvr32.exe \"%s\" /s"), szSysWow64Dir, szExpandedModulePath); } else if (lstrcmpi(TEXT(".exe"), &szExpandedModulePath[iLen - 4]) == 0) { DebugLog(TEXT("CmdRegisterInterfaceWow64: EXE mode for %s"), szExpandedModulePath); wsprintf(szCommandBuffer, TEXT("\"%s\" /RegServer"), szExpandedModulePath); } else { ErrorLog(TEXT("Cannot detect module type for %s. Skipped."), szExpandedModulePath); // Return true not to stop further processing. return (TRUE); } ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; ZeroMemory(&pi, sizeof(pi)); if (CreateProcess(NULL, szCommandBuffer, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi)) { DebugLog(TEXT("CmdRegisterInterfaceWow64: Running \"%s\". Waiting for the process termination."), szCommandBuffer); WaitForSingleObject(pi.hProcess, INFINITE); DebugLog(TEXT("CmdRegisterInterfaceWow64: \"%s\" terminates."), szCommandBuffer); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else { DWORD dwError = GetLastError(); ErrorLog(TEXT("CmdRegisterInterfaceWow64: CreateProcess(\"%s\") failed with error code = %d(%x)"), szCommandBuffer, dwError, dwError); } #endif return(TRUE); } /*--------------------------------------------------------------------------- CmdRegisterIMEandTIP Register IME using IMM API and TIP ---------------------------------------------------------------------------*/ BOOL CmdRegisterIMEandTIP(LPCTSTR szParam) { TCHAR szIMEFileName[MAX_PATH], szTIPName[MAX_PATH], szTIPNameWow64[MAX_PATH]; TCHAR *szHitPtr; TCHAR *szHitPtr2; HKL hIME61KL = 0; TCHAR szHKL[10]; TCHAR szNonFullPath[MAX_PATH]; HKEY hKey; szHitPtr = _tcschr(szParam, TEXT(',')); szHitPtr2 = _tcschr(szHitPtr + 1, TEXT(',')); // because there are three parameters if (szHitPtr2 == NULL) { ErrorLog(TEXT("CmdRegisterIMEandTIP: Invalid parameters (%s)"), szParam); wsprintf(g_szErrorMessage, TEXT("CmdRegisterIMEandTIP: Invalid parameters (%s)"), szParam); return(FALSE); } *szHitPtr = 0; *szHitPtr2 = 0; StringCchCopy(szIMEFileName, ARRAYSIZE(szIMEFileName), szParam); StringCchCopy(szTIPName, ARRAYSIZE(szTIPName), szHitPtr + 1); StringCchCopy(szTIPNameWow64, ARRAYSIZE(szTIPNameWow64), szHitPtr2 + 1); TrimString(szIMEFileName); TrimString(szTIPName); TrimString(szTIPNameWow64); ParseEnvVar(szIMEFileName, MAX_PATH); ParseEnvVar(szTIPName, MAX_PATH); ParseEnvVar(szTIPNameWow64, MAX_PATH); DebugLog(TEXT("CmdRegisterIMEandTIP: IMEFileName = %s, TIPFileName = %s szTIPNameWow64 = %s"), szIMEFileName, szTIPName, szTIPNameWow64); ///////////////////////////////////////////////////////////////////////////// // IME registration if ((szHitPtr = _tcsrchr(szIMEFileName, TEXT('\\'))) != NULL) szHitPtr++; else szHitPtr = szIMEFileName; StringCchCopy(szNonFullPath, ARRAYSIZE(szNonFullPath), szHitPtr); hIME61KL = GetHKLfromHKLM(szNonFullPath); if (hIME61KL == (HKL)0) DebugLog(TEXT("CmdRegisterIMEandTIP: hIME61KL is zero %x -- error"), hIME61KL); //if (hKL && HKLHelp412ExistInPreload(HKEY_CURRENT_USER)) // { // HKLHelpSetDefaultKeyboardLayout(HKEY_CURRENT_USER, hKL, FALSE); //hKL = ImmInstallIME(szIMEFileName, szLayoutText); // } ///////////////////////////////////////////////////////////////////////////// // TIP registration // Regster wow64 TIP first to avoid regstry overwrite problem. RegisterTIPWow64(szTIPNameWow64); RegisterTIP(szTIPName); ///////////////////////////////////////////////////////////////////////////// // IME and TIP - make substitution TCHAR szTIPGuid[MAX_PATH]; TCHAR szLangProfile[MAX_PATH]; CLSIDToStringA(CLSID_KorIMX, szTIPGuid); DebugLog(TEXT("CmdRegisterIMEandTIP: CLSID_KorIMX guid=%s"), szTIPGuid); // make a reg key wsprintf(szLangProfile, SZTIPREG_LANGPROFILE_TEMPLATE, szTIPGuid); ///////////////////////////////////////////////////////////////////////////// // Add Substitute HKL value to the TIP registry if (hIME61KL != 0 && RegOpenKeyEx(HKEY_LOCAL_MACHINE, szLangProfile, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { TCHAR szSubKeyName[MAX_PATH], szHKL[MAX_PATH]; DWORD dwIndex; HKEY hSubKey; wsprintf(szHKL, TEXT("0x%x"), hIME61KL); dwIndex = 0; while (RegEnumKey(hKey, dwIndex, szSubKeyName, MAX_PATH) != ERROR_NO_MORE_ITEMS) { if (RegOpenKeyEx(hKey,szSubKeyName,0,KEY_ALL_ACCESS, &hSubKey) == ERROR_SUCCESS) { RegSetValueEx(hSubKey, TEXT("SubstituteLayout"), 0,REG_SZ,(BYTE *)szHKL, sizeof(TCHAR)*(lstrlen(szHKL)+1)); RegCloseKey(hSubKey); } dwIndex++; } RegCloseKey(hKey); } #if defined(_WIN64) // make a reg key wsprintf(szLangProfile, SZTIPREG_LANGPROFILE_TEMPLATE_WOW64, szTIPGuid); ///////////////////////////////////////////////////////////////////////////// // Add Substitute HKL value to the TIP registry if (hIME61KL != 0 && RegOpenKeyEx(HKEY_LOCAL_MACHINE, szLangProfile, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { TCHAR szSubKeyName[MAX_PATH], szHKL[MAX_PATH]; DWORD dwIndex; HKEY hSubKey; wsprintf(szHKL, TEXT("0x%x"), hIME61KL); dwIndex = 0; while (RegEnumKey(hKey, dwIndex, szSubKeyName, MAX_PATH) != ERROR_NO_MORE_ITEMS) { if (RegOpenKeyEx(hKey, szSubKeyName, 0, KEY_ALL_ACCESS, &hSubKey) == ERROR_SUCCESS) { RegSetValueEx(hSubKey, TEXT("SubstituteLayout"), 0, REG_SZ, (BYTE*)szHKL, sizeof(TCHAR)*(lstrlen(szHKL)+1)); RegCloseKey(hSubKey); } dwIndex++; } RegCloseKey(hKey); } #endif return(TRUE); } /*--------------------------------------------------------------------------- CmdRegisterRUNKey Register package version ---------------------------------------------------------------------------*/ BOOL CmdRegisterPackageVersion(void) { HKEY hKey; TCHAR szVersionString[30]; // Write RootVersion reg only if this is latest IME. if (g_fExistNewerVersion == FALSE) { if(ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, g_szVersionKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) { wsprintf(szVersionString, TEXT("%d.%d"), g_dwMajorVersion, g_dwMiddleVersion); RegSetValueEx(hKey, g_szVersion, 0, REG_SZ, (CONST BYTE *)szVersionString, (lstrlen(szVersionString) + 1) * sizeof(TCHAR)); RegCloseKey(hKey); } } // Current if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, g_szVersionKeyCur, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { wsprintf(szVersionString, TEXT("%d.%d.%d.%d"), g_dwMajorVersion, g_dwMiddleVersion, g_dwMinorVersion, g_dwBuildNumber); RegSetValueEx(hKey, NULL, 0, REG_SZ, (CONST BYTE *)szVersionString, (lstrlen(szVersionString) + 1) * sizeof(TCHAR)); RegCloseKey(hKey); } return(TRUE); } // // Register Applet order // #define FE_KOREAN // need Korean stuff #include "../fecommon/imembx/guids.h" typedef struct tagAPPLETCLSID { const GUID *pguidClsid; BOOL fNoUIM; } APPLETCLSID; typedef struct tagAPPLETIID { const GUID *pguidIID; } APPLETIID; /*--------------------------------------------------------------------------- CmdRegisterPadOrder Not support WOW64. ---------------------------------------------------------------------------*/ BOOL CmdRegisterPadOrder(void) { HKEY hKey; TCHAR szClsid[MAX_PATH]; TCHAR szKey[MAX_PATH]; static const APPLETCLSID appletClsid[] = { { &CLSID_ImePadApplet_MultiBox, FALSE }, {0}, }; static const APPLETIID appletIID[] = { { &IID_MultiBox }, {0}, }; // // Applet clsid // for (INT i = 0; appletClsid[i].pguidClsid; i++) { CLSIDToStringA(*appletClsid[i].pguidClsid, szClsid); wsprintf(szKey, TEXT("%s\\%s"), SZAPPLETCLSID, szClsid); if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { if(appletClsid[i].fNoUIM) { DWORD dw = 1; RegSetValueEx(hKey, TEXT("nouim"), 0, NULL, (BYTE*)&dw, sizeof(DWORD)); } RegCloseKey(hKey); } } // // Applet iid // TCHAR szSubKey[MAX_PATH]; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, SZAPPLETIID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { for (INT i = 0; appletIID[i].pguidIID; i++) { CLSIDToStringA(*appletIID[i].pguidIID, szKey); wsprintf(szSubKey, TEXT("%d"), i); RegSetValueEx(hKey, szSubKey, 0, REG_SZ, (BYTE*)szKey, (lstrlen(szKey)+1)*sizeof(TCHAR)); } RegCloseKey(hKey); } return(TRUE); } /*--------------------------------------------------------------------------- CmdCreateDirectory ---------------------------------------------------------------------------*/ BOOL CmdCreateDirectory(LPCTSTR szParam) { TCHAR szDirectory[MAX_PATH], szExpandedDirectory[MAX_PATH]; StringCchCopy(szDirectory, ARRAYSIZE(szDirectory), szParam); TrimString(szDirectory); ExpandEnvironmentStrings(szDirectory, szExpandedDirectory, sizeof(szExpandedDirectory)/sizeof(TCHAR)); CreateDirectory(szExpandedDirectory, NULL); return(TRUE); } /*--------------------------------------------------------------------------- CmdAddToPreload Add HKL for given IMEFile to current user's preload. The HKL won't become default IME. ---------------------------------------------------------------------------*/ BOOL CmdAddToPreload(LPCTSTR szParam) { TCHAR tszIMEFileName[MAX_PATH]; HKL hKL; // If there is no Kor IME exist in preload, we shouldn't add Kor IME. if (!HKLHelp412ExistInPreload(HKEY_CURRENT_USER)) { DebugLog(TEXT("CmdAddToPreload: No 0412 HKL exist in HKCU\\Preload")); return TRUE; } StringCchCopy(tszIMEFileName, ARRAYSIZE(tszIMEFileName), szParam); TrimString(tszIMEFileName); hKL = GetHKLfromHKLM(tszIMEFileName); DebugLog(TEXT("CmdAddToPreload: Calling SetDefaultKeyboardLayout(HKEY_CURRENT_USER, %x, FALSE)"), hKL); HKLHelpSetDefaultKeyboardLayout(HKEY_CURRENT_USER, hKL, FALSE); return(TRUE); } /*--------------------------------------------------------------------------- fOldIMEsExist Register Run regi onl if old IME exist in system. ---------------------------------------------------------------------------*/ static BOOL fOldIMEsExist() { HKL hKL; static LPCSTR m_szOldIMEs[] = { "msime95.ime", // Win 95 IME "msime95k.ime", // NT 4 IME "imekr98u.ime", // IME98 "imekr.ime", // Office 10 IME "" }; CHAR** ppch = (CHAR**)&m_szOldIMEs[0]; while (ppch && **ppch) { hKL = GetHKLfromHKLM(*ppch); if (hKL) return TRUE; // existing ppch++; } return FALSE; } /*--------------------------------------------------------------------------- DisableTIP60ByDefault ---------------------------------------------------------------------------*/ VOID DisableTIP60ByDefault() { // KorIMX CLSID // {766A2C14-B226-4fd6-B52A-867B3EBF38D2} const static CLSID CLSID_KorTIP60 = { 0x766A2C14, 0xB226, 0x4FD6, {0xb5, 0x2a, 0x86, 0x7b, 0x3e, 0xbf, 0x38, 0xd2} }; const static GUID guidProfile60 = // {E47ABB1E-46AC-45f3-8A89-34F9D706DA83} { 0xe47abb1e, 0x46ac, 0x45f3, {0x8a, 0x89, 0x34, 0xf9, 0xd7, 0x6, 0xda, 0x83} }; // Set default Tip as for Cicero. CoInitialize(NULL); ITfInputProcessorProfiles *pProfile; HRESULT hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfiles, (void **) &pProfile); if (SUCCEEDED(hr)) { pProfile->EnableLanguageProfileByDefault(CLSID_KorTIP60, MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), guidProfile60, FALSE); pProfile->Release(); } else { OurEnableLanguageProfileByDefault(CLSID_KorTIP60, MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), guidProfile60, FALSE); } CoUninitialize(); } /*--------------------------------------------------------------------------- CmdPrepareMigration ---------------------------------------------------------------------------*/ BOOL CmdPrepareMigration(LPCTSTR szParam) { // Disable TIP 6.0 from HKLM by default // This will handle Office 10 install after Whistler mig exe removed from run reg. DisableTIP60ByDefault(); // First user SID list if (MakeSIDList() == FALSE) return FALSE; //Register IMEKRMIG.EXE to run reg Key on "Software\Microsoft\Windows\CurrentVersion\Run" return RegisterRUNKey(szParam); } /*--------------------------------------------------------------------------- CmdRegisterHelpDirs ---------------------------------------------------------------------------*/ BOOL CmdRegisterHelpDirs() { TCHAR szFileNameFullPath[MAX_PATH], szFileName[MAX_PATH]; LPTSTR szExtension, szFileNamePtr; HKEY hKey; for (std::set::iterator itFLE = g_FileList.begin(); itFLE != g_FileList.end(); itFLE++) { StringCchCopy(szFileNameFullPath, ARRAYSIZE(szFileNameFullPath), itFLE->szFileName); szExtension = _tcsrchr(szFileNameFullPath, TEXT('.')); if (szExtension == NULL) continue; if (lstrcmpi(szExtension, TEXT(".CHM")) == 0) { if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\HTML Help"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { szFileNamePtr = _tcsrchr(szFileNameFullPath, TEXT('\\')); // Get file name StringCchCopy(szFileName, ARRAYSIZE(szFileName), szFileNamePtr+1); // Get rid of file name we only need path. *(szFileNamePtr+1) = 0; RegSetValueEx(hKey, szFileName, 0, REG_SZ, (LPBYTE)szFileNameFullPath, (lstrlen(szFileNameFullPath)+1)*sizeof(TCHAR)); } } else if (lstrcmpi(szExtension, TEXT(".HLP")) == 0) { if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\Help"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { szFileNamePtr = _tcsrchr(szFileNameFullPath, TEXT('\\')); // Get file name StringCchCopy(szFileName, ARRAYSIZE(szFileName), szFileNamePtr+1); // Get rid of file name we only need path. *(szFileNamePtr+1) = 0; RegSetValueEx(hKey, szFileName, 0, REG_SZ, (LPBYTE)szFileNameFullPath, (lstrlen(szFileNameFullPath)+1)*sizeof(TCHAR)); } } } return(TRUE); } ///////////////////////////////////////////////////////////////////////////// // Private functions ///////////////////////////////////////////////////////////////////////////// // // Debug output routine. // void cdecl LogOutDCPrintf(LPCTSTR lpFmt, va_list va) { static INT DCLine = 0; HDC hDC = GetDC((HWND)0); TCHAR sz[512]; HANDLE hFile; DWORD dwWrite; wvsprintf(sz, lpFmt, va ); lstrcat(sz, TEXT("| ")); TextOut(hDC, 0, DCLine*16, sz, lstrlen(sz)); if (DCLine++ > 50) DCLine = 0; hFile = CreateFile(TEXT("\\IMKRINST.LOG"), GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (hFile != INVALID_HANDLE_VALUE) { SetFilePointer(hFile, 0, NULL, FILE_END); WriteFile(hFile, sz, lstrlen(sz), &dwWrite, NULL); WriteFile(hFile, TEXT("\r\n"), 2, &dwWrite, NULL); CloseHandle(hFile); } ReleaseDC((HWND)0, hDC); } void DebugLog(LPCTSTR szFormat, ...) { va_list va; va_start(va, szFormat); if (g_fDebugLog) LogOutDCPrintf(szFormat, va); va_end(va); } void ErrorLog(LPCTSTR szFormat, ...) { va_list va; va_start(va, szFormat); if (g_fErrorLog) LogOutDCPrintf(szFormat, va); va_end(va); } /*--------------------------------------------------------------------------- ParseEnvVar Evaluate environment variable. Modiry given string. ---------------------------------------------------------------------------*/ INT ParseEnvVar(LPTSTR szBuffer, const UINT arg_nLength) { INT iTranslated=0, i, j; TCHAR *pLParen, *pRParen, *pStart = szBuffer; INT nLength = min(arg_nLength, MAX_PATH); static TCHAR szInternalBuffer[MAX_PATH*2], szValue[MAX_PATH]; szInternalBuffer[0] = 0; for (i=0; idwFileVersionMS); *pdwMiddleVersion = LOWORD(pffiVersion->dwFileVersionMS); *pdwMinorVersion = HIWORD(pffiVersion->dwFileVersionLS); *pdwBuildNumber = LOWORD(pffiVersion->dwFileVersionLS); } } } if (NULL != pbData) { delete[] pbData; pbData = NULL; } } } /*--------------------------------------------------------------------------- ActRenameFile MoveFile. If destination file exists, it will be overwritten. If existing destination file cannot be overwritten in this session, file replacement is reserved to be held after rebooting. ---------------------------------------------------------------------------*/ BOOL ActRenameFile(LPCTSTR szSrcPath, LPCTSTR tszDstPath, DWORD dwFileAttributes) { BOOL fReplaceAfterReboot = FALSE; BOOL fResult = TRUE; FLE fleKey; StringCchCopy(fleKey.szFileName, MAX_PATH, szSrcPath); if (g_FileList.end() == g_FileList.find(fleKey)) ErrorLog(TEXT("ActRenameFile: WARNING: Cannot find source file [%s] in CmdFileList"), szSrcPath); if (!fExistFile(szSrcPath)) { ErrorLog(TEXT("ActRenameFile: Source file [%s] doesn't exist."), szSrcPath); wsprintf(g_szErrorMessage, TEXT("ActRenameFile: Source file [%s] doesn't exist."), szSrcPath); return(FALSE); } if (fExistFile(tszDstPath)) { SetFileAttributes(tszDstPath, FILE_ATTRIBUTE_NORMAL); if(!DeleteFile(tszDstPath)) { DWORD dwError = GetLastError(); fReplaceAfterReboot = TRUE; DebugLog(TEXT("ActRenameFile: Cannot delete destination file [%s] with error code = %d(%x)"), tszDstPath, dwError, dwError); } } if (!fReplaceAfterReboot) { if(MoveFile(szSrcPath, tszDstPath)) { SetFileAttributes(szSrcPath, dwFileAttributes); DebugLog(TEXT("ActRenameFile: MoveFile(%s, %s) succeeded."), szSrcPath, tszDstPath); } else { DWORD dwError = GetLastError(); DebugLog(TEXT("ActRenameFile: MoveFile(%s, %s) failed with error code = %d(%x)."), szSrcPath, tszDstPath, dwError, dwError); DebugLog(TEXT("ActRenameFile: Try again with fReplaceAfterReboot.")); fReplaceAfterReboot = TRUE; } } if (fReplaceAfterReboot) { SetFileAttributes(szSrcPath, dwFileAttributes); // In this case, change file attributes for Src path. ReplaceFileOnReboot(szSrcPath, tszDstPath); // Since this function writes lines in reverse order, deletion of DebugLog(TEXT("ActRenameFile: ReplaceFileOnReboot(%s, %s)."), szSrcPath, tszDstPath); ReplaceFileOnReboot(tszDstPath, NULL); // tszDstPath will come first. DebugLog(TEXT("ActRenameFile: ReplaceFileOnReboot(%s, NULL)."), tszDstPath); } if (fResult) g_FileList.erase(fleKey); return(fResult); } /////////////////////////////////////////////////////////////////////////////// // This should sync with SERVER.CPP in TIP folder // TIP Categories to be added const REGISTERCAT c_rgRegCat[] = { {&GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_KorIMX}, {&GUID_TFCAT_TIP_KEYBOARD, &CLSID_KorIMX}, {&GUID_TFCAT_PROPSTYLE_CUSTOM, &GUID_PROP_OVERTYPE}, {NULL, NULL} }; // TIP Profile name const REGTIPLANGPROFILE c_rgProf[] = { { MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), &GUID_Profile, SZ_TIPDISPNAME, SZ_TIPMODULENAME, (IDI_UNIKOR-IDI_ICONBASE), IDS_PROFILEDESC }, {0, &GUID_NULL, L"", L"", 0, 0} }; // /////////////////////////////////////////////////////////////////////////////// /*--------------------------------------------------------------------------- RegisterTIP Write neccessary registry key and values for TIP ---------------------------------------------------------------------------*/ void RegisterTIP(LPCTSTR szTIPName) { HKEY hKey; TCHAR szTIPGuid[MAX_PATH]; TCHAR szTIPProfileGuid[MAX_PATH]; TCHAR szSubKey[MAX_PATH]; DWORD dwValue; DebugLog(TEXT("RegisterTIP: (%s)."), szTIPName); // Run self reg // If self reg fails, run custom TIP registration if (!CmdRegisterInterface(szTIPName)) { TCHAR szExpandedTIPPath[MAX_PATH]; DebugLog(TEXT("RegisterTIP: TIP self reg failed, Run custom reg")); // Expand Env var ExpandEnvironmentStrings(szTIPName, szExpandedTIPPath, sizeof(szExpandedTIPPath)); // Register TIP CLSID if (!RegisterServer(CLSID_KorIMX, SZ_TIPSERVERNAME, szExpandedTIPPath, TEXT("Apartment"), NULL)) { DebugLog(TEXT("RegisterTIP: RegisterServer failed")); return; } if (!OurRegisterTIP(szExpandedTIPPath, CLSID_KorIMX, SZ_TIPNAME, c_rgProf)) { DebugLog(TEXT("RegisterTIP: szExpandedTIPPath failed")); return; } if (FAILED(OurRegisterCategories(CLSID_KorIMX, c_rgRegCat))) { DebugLog(TEXT("RegisterTIP: OurRegisterCategories failed")); return; } } // Get String format GUIDs CLSIDToStringA(CLSID_KorIMX, szTIPGuid); CLSIDToStringA(GUID_Profile, szTIPProfileGuid); ///////////////////////////////////////////////////////////////////////////// // If no Kor IME is in .default user. // Set HKLM [HKLM\Software\Microsoft\CTF\TIP\TIP classid\LanguageProfile\Language ID\Guid Profile] // "Enable" = "0" (DWORD) if (RegOpenKeyEx(HKEY_USERS, TEXT(".DEFAULT"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { if (!HKLHelp412ExistInPreload(hKey)) { HKEY hKProfRegKey; // Create "Software\Microsoft\CTF\TIP\{CLSID_KorIMX}\LanguageProfile\0x00000412\{CLSID_INPUTPROFILE}" wsprintf(szSubKey, TEXT("%s%s\\LanguageProfile\\0x00000412\\%s"), TEXT("SOFTWARE\\Microsoft\\CTF\\TIP\\"), szTIPGuid, szTIPProfileGuid); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_ALL_ACCESS, &hKProfRegKey) == ERROR_SUCCESS) { // Enabled DebugLog(TEXT("RegisterTIP: IME HKL not exist in HKU\\.Default disable TIP")); dwValue= 0; RegSetValueEx(hKProfRegKey, TEXT("Enable"), 0, REG_DWORD, (BYTE*)&dwValue, sizeof(dwValue)); RegCloseKey(hKProfRegKey); } } RegCloseKey(hKey); } } /*--------------------------------------------------------------------------- RegisterTIPWow64 Write neccessary registry key and values for TIP ---------------------------------------------------------------------------*/ void RegisterTIPWow64(LPCTSTR szTIPName) { #if defined(_WIN64) // Run just selfreg. Cicero doesn't use "HKLM\Software\Wow6432Node\Microsoft\CTF\TIP\" CmdRegisterInterfaceWow64(szTIPName); #endif } //////////////////////////////////////////////////////////////////////////// // HKL Helper functions //////////////////////////////////////////////////////////////////////////// /*--------------------------------------------------------------------------- GetHKLfromHKLM ---------------------------------------------------------------------------*/ HKL GetHKLfromHKLM(LPTSTR argszIMEFile) { HKL hklAnswer = 0; HKEY hKey, hSubKey; DWORD i, cbSubKey, cbIMEFile; TCHAR szSubKey[MAX_PATH], szIMEFile[MAX_PATH]; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\Keyboard Layouts"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) { for (i=0; ;i++) { cbSubKey = MAX_PATH; if (RegEnumKeyEx(hKey, i, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS) break; RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey); cbIMEFile=MAX_PATH; if (RegQueryValueEx(hSubKey, TEXT("IME File"), NULL, NULL, (LPBYTE)szIMEFile, &cbIMEFile) == ERROR_SUCCESS) { if (lstrcmpi(argszIMEFile, szIMEFile) == 0) { RegCloseKey(hSubKey); _stscanf(szSubKey, TEXT("%08x"), &hklAnswer); break; } } RegCloseKey(hSubKey); } RegCloseKey(hKey); } return(hklAnswer); } /*--------------------------------------------------------------------------- HKLHelpSetDefaultKeyboardLayout ---------------------------------------------------------------------------*/ void HKLHelpSetDefaultKeyboardLayout(HKEY hKeyHKCU, HKL hKL, BOOL fSetToDefault) { TCHAR szKL[20]; BYTE Data[MAX_PATH]; DWORD cbData; TCHAR szSubKey[MAX_PATH]; HKEY hKey,hSubKey; DWORD NumKL; wsprintf(szKL, TEXT("%08x"), hKL); RegOpenKeyEx(hKeyHKCU, TEXT("Keyboard Layout\\Preload"), 0, KEY_ALL_ACCESS, &hKey); RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &NumKL, NULL, NULL, NULL, NULL); for (DWORD i=0; i0; j--) { wsprintf(szSubKey, TEXT("%d"),j); cbData = MAX_PATH; RegQueryValueEx(hKey, szSubKey, NULL, NULL, Data, &cbData); wsprintf(szSubKey, TEXT("%d"),j+1); RegSetValueEx(hKey, szSubKey, 0, REG_SZ, Data, cbData); } RegSetValueEx(hKey, TEXT("1"), 0, REG_SZ, (const LPBYTE)szKL, (lstrlen(szKL)+1)*sizeof(TCHAR)); } RegCloseKey(hKey); (void)LoadKeyboardLayout(szKL, KLF_ACTIVATE); // To activate IME2002 right now without reboot. if(fSetToDefault) (void)SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, &hKL, SPIF_SENDCHANGE); } #define MAX_NAME 100 /*--------------------------------------------------------------------------- HKLHelp412ExistInPreload ---------------------------------------------------------------------------*/ BOOL HKLHelp412ExistInPreload(HKEY hKeyCU) { HKEY hKey, hSubKey; int i ,j; DWORD cbName, cbData; CHAR szName[MAX_NAME]; CHAR szData[MAX_NAME]; HKL hkl; FILETIME ftLastWriteTime; BOOL fResult = FALSE; if (RegOpenKeyEx(hKeyCU, "Keyboard Layout\\Preload", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { for (j=0; cbName=MAX_NAME, cbData=MAX_NAME, RegEnumValue(hKey, j, szName, &cbName, NULL, NULL, (LPBYTE)szData, &cbData) != ERROR_NO_MORE_ITEMS; j++) { // See If Korean KL exist. Just compare last LCID part if it's 0x412. // IME hkl set 0xE000 on hiword. sscanf(szData, "%08x", &hkl); if ((HIWORD(hkl) & 0xe000) && LOWORD(hkl) == 0x0412) { fResult = TRUE; break; } } RegCloseKey(hKey); } return(fResult); } /*--------------------------------------------------------------------------- RegisterRUNKey Register IME using IMM API and TIP ---------------------------------------------------------------------------*/ BOOL RegisterRUNKey(LPCTSTR szParam) { TCHAR szKey[MAX_PATH]; TCHAR szFilename[MAX_PATH]; TCHAR *szHitPtr; HKEY hRunKey; szHitPtr = _tcschr(szParam, TEXT(',')); if (szHitPtr == NULL) { ErrorLog(TEXT("RegisterRUNKey: Invalid parameters (%s)"), szParam); wsprintf(g_szErrorMessage, TEXT("RegisterRUNKey: Invalid parameters (%s)"), szParam); return(FALSE); } *szHitPtr = 0; StringCchCopy(szKey, ARRAYSIZE(szKey), szParam); StringCchCopy(szFilename, ARRAYSIZE(szFilename), szHitPtr + 1); TrimString(szKey); TrimString(szFilename); ParseEnvVar(szKey, MAX_PATH); ParseEnvVar(szFilename, MAX_PATH); if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hRunKey, NULL) == ERROR_SUCCESS) { RegSetValueEx(hRunKey, szKey, 0, REG_SZ, (CONST BYTE *)szFilename, (lstrlen(szFilename)+1)*sizeof(TCHAR)); RegCloseKey(hRunKey); } return(TRUE); } /*--------------------------------------------------------------------------- MakeSIDList Gets all users' SID and list that in the reg for migration ---------------------------------------------------------------------------*/ BOOL MakeSIDList() { HKEY hKey, hUserList; DWORD i, cbName; BOOL fNoMoreSID = FALSE; TCHAR szMigRegKey[MAX_PATH], szName[500]; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), 0, KEY_READ, &hKey) ==ERROR_SUCCESS) { StringCchCopy(szMigRegKey, ARRAYSIZE(g_szIMERootKey), g_szIMERootKey); lstrcat(szMigRegKey, TEXT("\\MigrateUser")); if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szMigRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hUserList, NULL) == ERROR_SUCCESS) { for (i=0; !fNoMoreSID; i++) { cbName = 500; if (RegEnumKeyEx(hKey, i, szName, &cbName, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS) fNoMoreSID = TRUE; else { // Do not add Local Service and Network Service pid if (lstrlen(szName) > 8) RegSetValueEx(hUserList, szName, 0, REG_SZ, (BYTE *)TEXT(""), sizeof(TCHAR)*2); } } //Change MigrateUser List security settings PSECURITY_DESCRIPTOR pSD = CreateSD(); if (pSD) { RegSetKeySecurity(hUserList, DACL_SECURITY_INFORMATION, pSD); MEMFREE(pSD); } RegCloseKey(hUserList); } RegCloseKey(hKey); } return (TRUE); } /*--------------------------------------------------------------------------- RestoreMajorVersionRegistry Restore IME major version reg value. It could be overwritten during Win9x to NT upgrade. ---------------------------------------------------------------------------*/ void RestoreMajorVersionRegistry() { HKEY hKey; /////////////////////////////////////////////////////////////////////////// // Restore IME major version reg value. // It could be overwritten during Win9x to NT upgrading. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szVersionKey, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { CHAR szVersion[MAX_PATH]; DWORD cbVersion = MAX_PATH; CHAR szMaxVersion[MAX_PATH]; FILETIME time; float flVersion, flMaxVersion; StringCchCopy(szMaxVersion, ARRAYSIZE(szMaxVersion), "0"); for (int i=0; cbVersion = MAX_PATH, RegEnumKeyEx(hKey, i, szVersion, &cbVersion, NULL, NULL, NULL, &time) != ERROR_NO_MORE_ITEMS; i++) { if (lstrcmp(szVersion, szMaxVersion) > 0) StringCchCopy(szMaxVersion, ARRAYSIZE(szMaxVersion), szVersion); } StringCchCopy(szVersion, ARRAYSIZE(szVersion), "0"); RegQueryValueEx(hKey, g_szVersion, NULL, NULL, (BYTE *)szVersion, &cbVersion); flVersion = (float)atof(szVersion); flMaxVersion = (float)atof(szMaxVersion); if (flVersion < flMaxVersion) RegSetValueEx(hKey, g_szVersion, 0, REG_SZ, (BYTE *)szMaxVersion, (sizeof(CHAR)*lstrlen(szMaxVersion))); RegCloseKey(hKey); } /////////////////////////////////////////////////////////////////////////// } /*--------------------------------------------------------------------------- CreateSecurityAttributes ---------------------------------------------------------------------------*/ PSECURITY_DESCRIPTOR CreateSD() { PSECURITY_DESCRIPTOR psd; PACL pacl; ULONG AclSize; PSID psid1, psid2, psid3, psid4; BOOL fResult; psid1 = MyCreateSid(SECURITY_INTERACTIVE_RID); if (psid1 == NULL) return NULL; psid2 = MyCreateSid(SECURITY_LOCAL_SYSTEM_RID); if (psid2 == NULL) goto Fail4; psid3 = MyCreateSid(SECURITY_SERVICE_RID); if (psid3 == NULL) goto Fail3; psid4 = MyCreateSid(SECURITY_NETWORK_RID); if (psid4 == NULL) goto Fail2; // // allocate and initialize an access control list (ACL) that will // contain the SIDs we've just created. // AclSize = sizeof(ACL) + (4 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + GetLengthSid(psid1) + GetLengthSid(psid2) + GetLengthSid(psid3) + GetLengthSid(psid4); // // allocate and initialize a new security descriptor plus ACL // psd = MEMALLOC(SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize); if (psd == NULL) { return NULL; } pacl = (PACL)((LPBYTE)psd + SECURITY_DESCRIPTOR_MIN_LENGTH); fResult = InitializeAcl(pacl, AclSize, ACL_REVISION); if (!fResult) { goto Fail; } // // adds an access-allowed ACE for interactive users to the ACL // fResult = AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid1); if (!fResult) { goto Fail; } // // adds an access-allowed ACE for operating system to the ACL // fResult = AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid2); if (!fResult) { goto Fail; } // // adds an access-allowed ACE for operating system to the ACL // fResult = AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid3); if (!fResult) { goto Fail; } // // adds an access-allowed ACE for operating system to the ACL // fResult = AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid4); if (!fResult) { goto Fail; } // // Let's make sure that our ACL is valid. // if (!IsValidAcl(pacl)) { goto Fail; } if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) { goto Fail; } fResult = SetSecurityDescriptorDacl(psd, fTrue, pacl, fFalse ); // The discretionary ACL is referenced by, not copied // into, the security descriptor. We shouldn't free up ACL // after the SetSecurityDescriptorDacl call. if (!fResult) { goto Fail; } if (!IsValidSecurityDescriptor(psd)) { goto Fail; } // // Those SIDs have been copied into the ACL. We don't need'em any more. // FreeSid(psid1); FreeSid(psid2); FreeSid(psid3); FreeSid(psid4); return psd; Fail: MEMFREE(psd); FreeSid(psid4); Fail2: FreeSid(psid3); Fail3: FreeSid(psid2); Fail4: FreeSid(psid1); return NULL; } PSID MyCreateSid(DWORD dwSubAuthority) { PSID psid; BOOL fResult; SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY; // // allocate and initialize an SID // fResult = AllocateAndInitializeSid(&SidAuthority, 1, dwSubAuthority, 0,0,0,0,0,0,0, &psid ); if (!fResult) { return NULL; } if (!IsValidSid(psid)) { FreeSid(psid); return NULL; } return psid; }