2025-04-27 07:49:33 -04:00

516 lines
16 KiB
C++

/****************************************************************************
WINMAIN.CPP : Per-user migration and reg install
History:
22-SEP-2000 CSLim Created
****************************************************************************/
#include "private.h"
#include <shlobj.h>
#include "hklhelp.h"
#include "msctf.h"
#include "shlwapi.h"
// IME 2002 main module
#define SZMODULENAME_MAIN "imekr.ime"
// IME Main HKLM Reg
#define SZIMEREG_MAIN_ROOT "Software\\Microsoft\\IMEKR\\6.0"
#define SZIMEREG_MAIN_ROOT_MIG SZIMEREG_MAIN_ROOT"\\MigrateUser"
#define MAJORVER "6.0"
#define IME_REGISTRY_LATEST_VERSION "Software\\Microsoft\\IMEKR" //The latest version of IME installed in the system
//will always be stored at HKLM\Software\Microsoft\IMEKR
//even if it's system IME.
extern BOOL WINAPI IsNT();
// Private functions
static void CheckForOtherUsers();
static void MigrateUserData();
static void WriteHKCUData();
static void DisableTip();
static void GetSIDString(LPSTR tszBuffer, SIZE_T cbBuffLen);
static BOOL GetTextualSid(PSID pSid, LPSTR TextualSid, LPDWORD dwBufferLen);
static PSID KYGetCurrentSID();
static POSVERSIONINFO GetVersionInfo();
/*---------------------------------------------------------------------------
WinMain
---------------------------------------------------------------------------*/
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
HKEY hKey;
BOOL fMigrated = fFalse;
BOOL fRunAlreadyForThisUser = fFalse;
CHAR szBuffer[500];
BOOL fSetDefault = fFalse;
// Check if this user already migrated
if (RegOpenKeyEx(HKEY_CURRENT_USER, SZIMEREG_MAIN_ROOT, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hKey, "Migrated", NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
fMigrated = fTrue; // Already migrated
RegCloseKey(hKey);
}
// In case no HKCU IME main root key or "Migrated" is not exist
if (fMigrated == fFalse)
{
DWORD dwMigrated = 1;
// It could possibe there is no HKCU\SZIMEREG_MAIN_ROOT, so we create it here.
if (RegCreateKey(HKEY_CURRENT_USER, SZIMEREG_MAIN_ROOT, &hKey) == ERROR_SUCCESS)
{
// Set migrated reg.
RegSetValueEx(hKey, "Migrated", 0, REG_DWORD, (BYTE *)&dwMigrated, sizeof(DWORD));
RegCloseKey(hKey);
}
}
if (IsNT())
GetSIDString(szBuffer, sizeof(szBuffer)); // get the sid of the current user
else
{
DWORD cbBuffer = sizeof(szBuffer);
GetUserName(szBuffer, &cbBuffer);
}
// if sid exists under HKLM\Software\Microsoft\IMEKR\6.0\MigrateUser migrate and delete sid from reg
// if sid does not exist == this user didn't exist when ime was installed?
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZIMEREG_MAIN_ROOT_MIG, 0, KEY_ALL_ACCESS, &hKey))
{
if (ERROR_SUCCESS == RegQueryValueEx(hKey, szBuffer, NULL, NULL, NULL, NULL))
{
RegDeleteValue(hKey, szBuffer);
fRunAlreadyForThisUser = fFalse;
}
else
fRunAlreadyForThisUser = fTrue;
RegCloseKey(hKey);
}
CheckForOtherUsers();
// O10 #316759
// For per-user install. If this is per-user install(non-admin), SID list won't be created.
// Darwin custom action set parameter "/Force" to we force to set preload.
if (lpCmdLine && StrStrI(lpCmdLine, "/Force"))
fRunAlreadyForThisUser = fFalse;
// 1. Do migrate
if (fMigrated == fFalse)
MigrateUserData();
if (fRunAlreadyForThisUser == fFalse)
{
HKEY hKey;
CHAR szVersion[MAX_PATH];
DWORD cbVersion = MAX_PATH;
// 2. Reset Show Status
if (RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Input Method", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
{
LPSTR szStatus = "1";
RegSetValueEx(hKey, "Show Status", 0, REG_SZ, (BYTE *)szStatus, (sizeof(CHAR)*lstrlen(szStatus)));
RegCloseKey(hKey);
}
// Add IME to preload only when it is the latest IME existing in the system
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, IME_REGISTRY_LATEST_VERSION, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hKey, "version", NULL, NULL, (BYTE *)szVersion, &cbVersion) == ERROR_SUCCESS)
{
if (lstrcmpi(szVersion, MAJORVER) == 0)
fSetDefault = fTrue;
}
RegCloseKey(hKey);
}
// 3. Write any HKCU data (Set IME2002 as default TIP and Set preload)
if (fSetDefault)
WriteHKCUData();
else
DisableTip();
}
return(0);
}
//////////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////////
/*---------------------------------------------------------------------------
MigrateUserData
This function migrate BeolSik and K1 Hanja setting
Search IME98, Win95 IME, NT4 IME and AIME reg.
---------------------------------------------------------------------------*/
void MigrateUserData()
{
const INT iMaxIMERegKeys = 4;
static LPSTR rgszIME98RegKeys[iMaxIMERegKeys] =
{
// IME98
"Software\\Microsoft\\Windows\\CurrentVersion\\IME\\Korea\\IMEKR98U",
// Win95 IME
"Software\\Microsoft\\Windows\\CurrentVersion\\MSIME95",
// Kor NT4 IME
"Software\\Microsoft\\Windows\\CurrentVersion\\MSIME95K",
// Korean AIME
"Software\\Microsoft\\Windows\\CurrentVersion\\Wansung"
};
// Beolsik value
static CHAR szBeolsik[] = "InputMethod";
// K1 Hanja enable(IME98 only)
static CHAR szEnableK1Hanja[] = "KSC5657";
HKEY hKey;
DWORD dwCb, dwIMEKL, dwKSC5657;
// Set default values
dwIMEKL = dwKSC5657 = 0;
for (INT i=0; i<iMaxIMERegKeys; i++)
{
if (RegOpenKeyEx(HKEY_CURRENT_USER, rgszIME98RegKeys[i], 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
{
///////////////////////////////////////////////////////////////////
// Get Beolsik
dwCb = sizeof(dwIMEKL);
if (RegQueryValueEx(hKey, szBeolsik, NULL, NULL, (LPBYTE)&dwIMEKL, &dwCb) != ERROR_SUCCESS)
{
dwIMEKL = 0;
}
///////////////////////////////////////////////////////////////////
// Get K1 Hanja Setting
dwCb = sizeof(dwKSC5657);
if (RegQueryValueEx(hKey, szEnableK1Hanja, NULL, NULL, (LPBYTE)&dwKSC5657, &dwCb) != ERROR_SUCCESS)
{
dwKSC5657 = 0;
}
RegCloseKey(hKey);
// Break for loop
break;
}
}
// Set values to IME2002 reg
if (RegCreateKey(HKEY_CURRENT_USER, SZIMEREG_MAIN_ROOT, &hKey) == ERROR_SUCCESS)
{
// 1. BeolSik
dwCb = sizeof(dwIMEKL);
if (dwIMEKL >= 100 && dwIMEKL <= 102)
dwIMEKL -= 100;
else
if (dwIMEKL > 2) // Only accept 0, 1, 2
dwIMEKL = 0;
RegSetValueEx(hKey, szBeolsik, 0, REG_DWORD, (LPBYTE)&dwIMEKL, dwCb);
// K1 Hanja flag
if (dwKSC5657 != 0 && dwKSC5657 != 1) // Only accept 0 or 1
dwKSC5657 = 0;
RegSetValueEx(hKey, szEnableK1Hanja, 0, REG_DWORD, (LPBYTE)&dwKSC5657, dwCb);
RegCloseKey(hKey);
}
}
// KorIMX CLSID
// {766A2C14-B226-4fd6-B52A-867B3EBF38D2}
extern const CLSID CLSID_KoreanKbdTip = {
0x766A2C14,
0xB226,
0x4FD6,
{0xb5, 0x2a, 0x86, 0x7b, 0x3e, 0xbf, 0x38, 0xd2}
};
const GUID g_guidKorProfile =
// {E47ABB1E-46AC-45f3-8A89-34F9D706DA83}
{ 0xe47abb1e,
0x46ac,
0x45f3,
{0x8a, 0x89, 0x34, 0xf9, 0xd7, 0x6, 0xda, 0x83}
};
/*---------------------------------------------------------------------------
WriteHKCUData
---------------------------------------------------------------------------*/
void WriteHKCUData()
{
// 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->SetDefaultLanguageProfile(MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT),
CLSID_KoreanKbdTip, g_guidKorProfile);
pProfile->Release();
}
CoUninitialize();
// Clean up HKCU preload reg. (Remove old IME)
AddPreload(HKEY_CURRENT_USER, GetHKLfromHKLM("imekr.ime"));
}
/*---------------------------------------------------------------------------
DisableTip
Hide IME 2002 tip from Toolbar
---------------------------------------------------------------------------*/
void DisableTip()
{
// 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->EnableLanguageProfile(CLSID_KoreanKbdTip,
MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), g_guidKorProfile, fFalse);
pProfile->Release();
}
CoUninitialize();
}
/*---------------------------------------------------------------------------
CheckForOtherUsers
---------------------------------------------------------------------------*/
void CheckForOtherUsers(void)
{
HKEY hKey, hRunKey;
CHAR szValueName[MAX_PATH];
DWORD cbValueName = MAX_PATH;
BOOL fRemoveRunKey = fFalse;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZIMEREG_MAIN_ROOT_MIG, 0, KEY_READ, &hKey))
{
// if no more users left for migration, remove HKLM "run" reg
if (ERROR_NO_MORE_ITEMS == RegEnumValue(hKey, 0, szValueName, &cbValueName, NULL, NULL, NULL, NULL))
fRemoveRunKey = fTrue;
RegCloseKey(hKey);
}
else
fRemoveRunKey = fTrue;
if (fRemoveRunKey && (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hRunKey)))
{
RegDeleteValue(hRunKey, "imekrmig");
RegCloseKey(hRunKey);
}
}
/*---------------------------------------------------------------------------
GetTextualSid
---------------------------------------------------------------------------*/
BOOL GetTextualSid(PSID pSid, LPSTR TextualSid, LPDWORD dwBufferLen)
{
PSID_IDENTIFIER_AUTHORITY psia;
DWORD dwSubAuthorities;
DWORD dwSidRev=SID_REVISION;
DWORD dwCounter;
DWORD dwSidSize;
if (!IsValidSid(pSid))
return FALSE;
// SidIdentifierAuthority ???
psia=GetSidIdentifierAuthority(pSid);
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
// S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
if (*dwBufferLen < dwSidSize)
{
*dwBufferLen = dwSidSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// S-SID_REVISION
dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
// SidIdentifierAuthority
if ((psia->Value[0] != 0) || (psia->Value[1] != 0))
{
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
(USHORT)psia->Value[0],
(USHORT)psia->Value[1],
(USHORT)psia->Value[2],
(USHORT)psia->Value[3],
(USHORT)psia->Value[4],
(USHORT)psia->Value[5]);
}
else
{
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
TEXT("%lu"),
(ULONG)(psia->Value[5] ) +
(ULONG)(psia->Value[4] << 8) +
(ULONG)(psia->Value[3] << 16) +
(ULONG)(psia->Value[2] << 24) );
}
// SidSubAuthorities
for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
{
dwSidSize += wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
*GetSidSubAuthority(pSid, dwCounter) );
}
return fTrue;
}
/*---------------------------------------------------------------------------
KYGetCurrentSID
---------------------------------------------------------------------------*/
PSID KYGetCurrentSID()
{
HANDLE hToken = NULL;
BOOL bSuccess;
#define MY_BUFSIZE 512 // highly unlikely to exceed 512 bytes
static UCHAR InfoBuffer[MY_BUFSIZE];
DWORD cbInfoBuffer = MY_BUFSIZE;
/*
if(!OpenThreadToken( // Don't try to get thread owner. Just get process owner.
GetCurrentThread(), // This is to fix Satori:#1265.
//
TOKEN_QUERY, // Winlogon.exe has something special characteristics that
TRUE, // it has many threads and some of them is owned by different
&hToken // user from owner of the process.
)) {
// More concrete, winlogon's process owner is SYSTEM, but
// some certain thread of the process is owned by logon user.
// If KYGetCurrentSID runs on such special thread, this
// function will return SID for logon user. But actually this
// process runs on SYSTEM user context, this results .Default
// user's Registry data loaded on shared memory for logon user.
// Even on such thread, HKCU is mapped to HKU\.Default, so we
// have to abondon to let the thread loads logon user's registry
// on logon user's shared memory. Instead, we just refer proces
// owner (not thread owner) which doesn't conflict with HKCU.
// As a result, winlogon always get SID for SYSTEM, regardless
// on which thread we're running, resulting winlogon loads
// SYSTEM's registry to SYSTEM's shared memory.
// This change may affect on other process that has multiple
// threads owned by different user from process's owner. But
// practically we can assume there're almost no chance for IME
// to run on such threads. 4/27/2000 [KotaroY]
if(GetLastError() == ERROR_NO_TOKEN) {
//
// attempt to open the process token, since no thread token
// exists
//
*/
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return(NULL);
/*
} else {
//
// error trying to get thread token
//
return(NULL);
}
}
*/
bSuccess = GetTokenInformation(
hToken,
TokenUser,
InfoBuffer,
cbInfoBuffer,
&cbInfoBuffer
);
if (!bSuccess)
{
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
//
// alloc buffer and try GetTokenInformation() again
//
CloseHandle(hToken);
return(NULL);
}
else
{
//
// error getting token info
//
CloseHandle(hToken);
return(NULL);
}
}
CloseHandle(hToken);
return(((PTOKEN_USER)InfoBuffer)->User.Sid);
}
/*---------------------------------------------------------------------------
GetSIDString
---------------------------------------------------------------------------*/
void GetSIDString(LPSTR tszBuffer, SIZE_T cbBuffLen)
{
DWORD cbBuffer = cbBuffLen;
if (!GetTextualSid(KYGetCurrentSID(), tszBuffer, &cbBuffer))
tszBuffer[0] = 0;
}
/*---------------------------------------------------------------------------
GetVersionInfo
---------------------------------------------------------------------------*/
POSVERSIONINFO GetVersionInfo()
{
static BOOL fFirstCall = fTrue;
static OSVERSIONINFO os;
if (fFirstCall)
{
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&os))
fFirstCall = fFalse;
}
return &os;
}
/*---------------------------------------------------------------------------
IsNT
---------------------------------------------------------------------------*/
BOOL WINAPI IsNT()
{
BOOL fResult;
fResult = (GetVersionInfo()->dwPlatformId == VER_PLATFORM_WIN32_NT);
return fResult;
}