/**************************************************************************\ * Module Name: layout.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * IMM User Mode Routines * * History: * 03-Jan-1996 wkwok Created \**************************************************************************/ #include "precomp.h" #pragma hdrstop #define VERSION_DLL TEXT("version.dll") #define VER_FILE_VERSION TEXT("FileVersion") #define SZ_BACKSLASH TEXT("\\") #define WCHAR_BACKSLASH L'\\' #define WCHAR_NULL L'\0' #define VERSION_GetFileVersionInfoW "GetFileVersionInfoW" #define VERSION_GetFileVersionInfoSizeW "GetFileVersionInfoSizeW" #define VERSION_VerQueryValueW "VerQueryValueW" typedef BOOL (WINAPI *LPFNGETFILEVERSIONINFOW)(PWSTR, DWORD, DWORD, LPVOID); typedef DWORD (WINAPI *LPFNGETFILEVERSIONINFOSIZEW)(PWSTR, LPDWORD); typedef BOOL (WINAPI *LPFNVERQUERYVALUEW)(const LPVOID, PWSTR, LPVOID*, LPDWORD); typedef VS_FIXEDFILEINFO *PFIXEDFILEINFO; static LPFNGETFILEVERSIONINFOW pfnGetFileVersionInfoW; static LPFNGETFILEVERSIONINFOSIZEW pfnGetFileVersionInfoSizeW; static LPFNVERQUERYVALUEW pfnVerQueryValueW; BOOL ImmLoadLayout( HKL hKL, PIMEINFOEX piiex) { UNICODE_STRING strIme; WCHAR wszIme[MAX_PATH]; HKEY hKeyKbdLayout = NULL; HKEY hKeyIme; NTSTATUS Status; DWORD dwTmp; LONG lRet; hKeyKbdLayout = NULL; hKeyIme = NULL; #ifdef CUAS_ENABLE if (! IS_IME_KBDLAYOUT(hKL) && IS_CICERO_ENABLED_AND_NOT16BIT()) { lRet = RegOpenKey(HKEY_LOCAL_MACHINE, gszRegCiceroIME, &hKeyIme); if ( lRet != ERROR_SUCCESS ) { return FALSE; } } else #endif // CUAS_ENABLE { strIme.Buffer = wszIme; strIme.MaximumLength = sizeof(wszIme); Status = RtlIntegerToUnicodeString(HandleToUlong(hKL), 16, &strIme); if (!NT_SUCCESS(Status)) { return(FALSE); } lRet = RegOpenKey(HKEY_LOCAL_MACHINE, gszRegKbdLayout, &hKeyKbdLayout); if ( lRet != ERROR_SUCCESS ) { return(FALSE); } lRet = RegOpenKey(hKeyKbdLayout, strIme.Buffer, &hKeyIme); if ( lRet != ERROR_SUCCESS ) { RegCloseKey(hKeyKbdLayout); return(FALSE); } } dwTmp = IM_FILE_SIZE; lRet = RegQueryValueEx(hKeyIme, gszValImeFile, NULL, NULL, (LPBYTE)piiex->wszImeFile, &dwTmp); if ( lRet != ERROR_SUCCESS ) { RegCloseKey(hKeyIme); if (hKeyKbdLayout) RegCloseKey(hKeyKbdLayout); return(FALSE); } piiex->wszImeFile[IM_FILE_SIZE - 1] = L'\0'; RegCloseKey(hKeyIme); if (hKeyKbdLayout) RegCloseKey(hKeyKbdLayout); piiex->hkl = hKL; piiex->fLoadFlag = IMEF_NONLOAD; return LoadVersionInfo(piiex); } // GetSystemPathName() // create "%windir%\system32\%filename" VOID GetSystemPathName(PWSTR /*OUT*/ pwszPath, PWSTR pwszFileName, UINT maxChar) { UINT uRet; if (! pwszPath || ! pwszFileName || maxChar == 0) { pwszPath[0] = L'\0'; return; } if (! pwszFileName[0]) { pwszPath[0] = L'\0'; return; } uRet = GetSystemDirectoryW(pwszPath, maxChar); if (uRet >= maxChar) { uRet = 0; pwszPath[0] = L'\0'; } else if (uRet) { UINT uLen; if (pwszPath[uRet - 1] != L'\\') { pwszPath[uRet] = L'\\'; uRet++; } if (uRet >= maxChar) { uRet = 0; pwszPath[0] = L'\0'; } else { uLen = wcslen(pwszFileName); if (maxChar - uRet > uLen) { wcsncpy(&pwszPath[uRet], pwszFileName, maxChar - uRet); uRet += uLen; } else { uRet = 0; pwszPath[0] = L'\0'; } } } } INT ExtractColumn( LPWSTR lpSrc, WCHAR cSeparator, UINT uiColumn ) /*++ Routine Description: Arguments: lpSrc - "YYYY.MM.DD" or "HH:MM:SS" or "MM.NN" pointer Return Value: packed int --*/ { UNICODE_STRING uStr; WCHAR *pSep, *pStr; INT i; if (!lpSrc) { return 0; } pStr = pSep = NULL; while (uiColumn--) { pStr = lpSrc; while (*lpSrc && *lpSrc != cSeparator) { lpSrc++; } if (*lpSrc == cSeparator) { pSep = lpSrc; lpSrc++; } } if (pStr) { if (pSep) { *pSep = TEXT('\0'); uStr.Length = (USHORT)((pSep - pStr) * sizeof(WCHAR)); } else { uStr.Length = (USHORT)(((lpSrc - pStr) + 1) * sizeof(WCHAR)); } uStr.Buffer = pStr; uStr.MaximumLength = (USHORT)(uStr.Length + sizeof(WCHAR)); RtlUnicodeStringToInteger(&uStr, 0, &i); if (pSep) { *pSep = cSeparator; } } else { i = 0; } return i; } PWSTR GetVersionDatum( PWSTR pszVersionBuffer, PWSTR pszVersionKey, PWSTR pszName) { ULONG ulSize; DWORD cbValue = 0; PWSTR pValue; ulSize = wcslen(pszVersionKey); wcscat(pszVersionKey, pszName); (*pfnVerQueryValueW)(pszVersionBuffer, pszVersionKey, (LPVOID*)&pValue, &cbValue); pszVersionKey[ulSize] = L'\0'; return (cbValue != 0) ? pValue : (PWSTR)NULL; } BOOL LoadFixVersionInfo( PIMEINFOEX piiex, PWSTR pszVersionBuffer) { PFIXEDFILEINFO pFixedVersionInfo; BOOL fResult; DWORD cbValue; fResult = (*pfnVerQueryValueW)(pszVersionBuffer, SZ_BACKSLASH, &pFixedVersionInfo, &cbValue); if (!fResult || cbValue == 0) return FALSE; /* * Check for IME file type. */ if (pFixedVersionInfo->dwFileType != VFT_DRV || pFixedVersionInfo->dwFileSubtype != VFT2_DRV_INPUTMETHOD) { return FALSE; } piiex->dwProdVersion = pFixedVersionInfo->dwProductVersionMS; /* * Currently, we only support 4.0 DLL based IME. */ piiex->dwImeWinVersion = IMEVER_0400; return TRUE; } BOOL LoadVarVersionInfo( PIMEINFOEX piiex, PWSTR pszVersionBuffer) { PWSTR pDescription; WORD wLangId; BOOL fResult; PUSHORT puXlate; DWORD cbValue; WCHAR szVersionKey[80]; fResult = (*pfnVerQueryValueW)(pszVersionBuffer, L"\\VarFileInfo\\Translation", (LPVOID *)&puXlate, &cbValue); if (!fResult || cbValue == 0) return FALSE; wLangId = *puXlate; if (piiex->hkl == 0) { /* * A newly installed IME, its HKL is not assigned yet. */ piiex->hkl = (HKL)LongToHandle( MAKELONG(wLangId, 0) ); } #if 0 // let unlocalized IME to work. else if (LOWORD(HandleToUlong(piiex->hkl)) != wLangId){ /* * Mismatch in Lang ID, blow out */ return FALSE; } #endif /* * First try the language we are currently in. */ wsprintf(szVersionKey, L"\\StringFileInfo\\%04X04B0\\", LANGIDFROMLCID(GetThreadLocale())); pDescription = GetVersionDatum(pszVersionBuffer, szVersionKey, L"FileDescription"); if (pDescription == NULL) { /* * Now try the first translation specified in IME */ wsprintf(szVersionKey, L"\\StringFileInfo\\%04X%04X\\", *puXlate, *(puXlate+1)); pDescription = GetVersionDatum(pszVersionBuffer, szVersionKey, L"FileDescription"); } if (pDescription != NULL) { wcsncpy(piiex->wszImeDescription, pDescription, ARRAY_SIZE(piiex->wszImeDescription) - 1); piiex->wszImeDescription[ARRAY_SIZE(piiex->wszImeDescription) - 1] = L'\0'; } else { piiex->wszImeDescription[0] = L'\0'; } return TRUE; } BOOL LoadVersionInfo( PIMEINFOEX piiex) { WCHAR szPath[MAX_PATH]; PWSTR pszVersionBuffer; HANDLE hVersion; DWORD dwVersionSize; DWORD dwHandle = 0; BOOL fUnload, fReturn = FALSE; hVersion = GetModuleHandle(VERSION_DLL); if (hVersion != NULL) { fUnload = FALSE; } else { hVersion = LoadLibrary(VERSION_DLL); if (hVersion == NULL) { return FALSE; } fUnload = TRUE; } #define GET_PROC(x) \ if (!(pfn##x = (PVOID) GetProcAddress(hVersion, VERSION_##x))) { \ goto LoadVerInfoUnload; } GET_PROC(GetFileVersionInfoW); GET_PROC(GetFileVersionInfoSizeW); GET_PROC(VerQueryValueW); #undef GET_PROC // szPath = fully qualified IME file name GetSystemPathName(szPath, piiex->wszImeFile, ARRAY_SIZE(szPath)); dwVersionSize = (*pfnGetFileVersionInfoSizeW)(szPath, &dwHandle); if (dwVersionSize == 0L) goto LoadVerInfoUnload; pszVersionBuffer = (PWSTR)ImmLocalAlloc(0, dwVersionSize); if (pszVersionBuffer == NULL) // can't get memory for version info, blow out goto LoadVerInfoUnload; if (!(*pfnGetFileVersionInfoW)(szPath, dwHandle, dwVersionSize, pszVersionBuffer)) goto LoadVerInfoFree; /* * Get the fixed block version information. */ if (LoadFixVersionInfo(piiex, pszVersionBuffer)) { /* * Get the variable block version information. */ fReturn = LoadVarVersionInfo(piiex, pszVersionBuffer); } LoadVerInfoFree: ImmLocalFree((HLOCAL)pszVersionBuffer); LoadVerInfoUnload: if (fUnload) FreeLibrary(hVersion); return fReturn; }