You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1332 lines
36 KiB
1332 lines
36 KiB
|
|
#include "private.h"
|
|
#include "immxutil.h"
|
|
#include "helpers.h"
|
|
#include "regsvr.h"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetTextExtInActiveView
|
|
//
|
|
// Get a range text extent from the active view of a document mgr.
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT GetTextExtInActiveView(TfEditCookie ec, ITfRange *pRange, RECT *prc, BOOL *pfClipped)
|
|
{
|
|
ITfContext *pic;
|
|
ITfContextView *pView;
|
|
HRESULT hr;
|
|
|
|
// do the deref: range->ic->defView->GetTextExt()
|
|
|
|
if (pRange->GetContext(&pic) != S_OK)
|
|
return E_FAIL;
|
|
|
|
hr = pic->GetActiveView(&pView);
|
|
pic->Release();
|
|
|
|
if (hr != S_OK)
|
|
return E_FAIL;
|
|
|
|
hr = pView->GetTextExt(ec, pRange, prc, pfClipped);
|
|
pView->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsActiveView
|
|
//
|
|
// Returns TRUE iff pView is the active view in the specified context.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL IsActiveView(ITfContext *pic, ITfContextView *pView)
|
|
{
|
|
ITfContextView *pActiveView;
|
|
BOOL fRet;
|
|
|
|
if (pic->GetActiveView(&pActiveView) != S_OK)
|
|
return FALSE;
|
|
|
|
fRet = IdentityCompare(pActiveView, pView);
|
|
|
|
pActiveView->Release();
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ShiftToOrClone
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL ShiftToOrClone(IAnchor **ppaDst, IAnchor *paSrc)
|
|
{
|
|
if (*ppaDst == paSrc)
|
|
return TRUE;
|
|
|
|
if (*ppaDst == NULL)
|
|
{
|
|
paSrc->Clone(ppaDst);
|
|
}
|
|
else
|
|
{
|
|
(*ppaDst)->ShiftTo(paSrc);
|
|
}
|
|
|
|
return (*ppaDst != NULL);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AsciiToNum
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD AsciiToNum( char *pszAscii)
|
|
{
|
|
DWORD dwNum = 0;
|
|
|
|
for (; *pszAscii; pszAscii++) {
|
|
if (*pszAscii >= '0' && *pszAscii <= '9') {
|
|
dwNum = (dwNum << 4) | (*pszAscii - '0');
|
|
} else if (*pszAscii >= 'A' && *pszAscii <= 'F') {
|
|
dwNum = (dwNum << 4) | (*pszAscii - 'A' + 0x000A);
|
|
} else if (*pszAscii >= 'a' && *pszAscii <= 'f') {
|
|
dwNum = (dwNum << 4) | (*pszAscii - 'a' + 0x000A);
|
|
} else {
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (dwNum);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AsciiToNumDec
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL AsciiToNumDec(char *pszAscii, DWORD *pdw)
|
|
{
|
|
*pdw = 0;
|
|
|
|
for (; *pszAscii; pszAscii++)
|
|
{
|
|
if (*pszAscii >= '0' && *pszAscii <= '9')
|
|
{
|
|
*pdw *= 10;
|
|
*pdw += (*pszAscii - '0');
|
|
}
|
|
else
|
|
{
|
|
*pdw = 0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// NumToA
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void NumToA(DWORD dw, char *psz)
|
|
{
|
|
int n = 7;
|
|
while (n >= 0)
|
|
{
|
|
BYTE b = (BYTE)(dw >> (n * 4)) & 0x0F;
|
|
if (b < 0x0A)
|
|
*psz = (char)('0' + b);
|
|
else
|
|
*psz = (char)('A' + b - 0x0A);
|
|
psz++;
|
|
n--;
|
|
}
|
|
*psz = L'\0';
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// WToNum
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD WToNum( WCHAR *psz)
|
|
{
|
|
DWORD dwNum = 0;
|
|
|
|
for (; *psz; psz++) {
|
|
if (*psz>= L'0' && *psz<= L'9') {
|
|
dwNum = (dwNum << 4) | (*psz - L'0');
|
|
} else if (*psz>= L'A' && *psz<= L'F') {
|
|
dwNum = (dwNum << 4) | (*psz - L'A' + 0x000A);
|
|
} else if (*psz>= L'a' && *psz<= L'f') {
|
|
dwNum = (dwNum << 4) | (*psz - L'a' + 0x000A);
|
|
} else {
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (dwNum);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// NumToW
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void NumToW(DWORD dw, WCHAR *psz)
|
|
{
|
|
int n = 7;
|
|
while (n >= 0)
|
|
{
|
|
BYTE b = (BYTE)(dw >> (n * 4)) & 0x0F;
|
|
if (b < 0x0A)
|
|
*psz = (WCHAR)(L'0' + b);
|
|
else
|
|
*psz = (WCHAR)(L'A' + b - 0x0A);
|
|
psz++;
|
|
n--;
|
|
}
|
|
*psz = L'\0';
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetTopIC
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL GetTopIC(ITfDocumentMgr *pdim, ITfContext **ppic)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppic = NULL;
|
|
|
|
if (pdim == NULL)
|
|
return FALSE;
|
|
|
|
hr = pdim->GetTop(ppic);
|
|
|
|
return SUCCEEDED(hr) ? TRUE : FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdjustAnchor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LONG AdjustAnchor(LONG ichAdjStart, LONG ichAdjEnd, LONG cchNew, LONG ichAnchor, BOOL fGravityRight)
|
|
{
|
|
int cchAdjust;
|
|
|
|
// if the adjustment is entirely to the right, nothing to do
|
|
if (ichAdjStart > ichAnchor)
|
|
return ichAnchor;
|
|
|
|
// if the adjustment was a simple replacement -- no size change -- nothing to do
|
|
if ((cchAdjust = cchNew - (ichAdjEnd - ichAdjStart)) == 0)
|
|
return ichAnchor;
|
|
|
|
if (ichAdjStart == ichAnchor && ichAdjEnd == ichAnchor)
|
|
{
|
|
// inserting at the anchor pos
|
|
Assert(cchAdjust > 0);
|
|
if (fGravityRight)
|
|
{
|
|
ichAnchor += cchAdjust;
|
|
}
|
|
}
|
|
else if (ichAdjEnd <= ichAnchor)
|
|
{
|
|
// the adjustment is to the left of the anchor, just add the delta
|
|
ichAnchor += cchAdjust;
|
|
}
|
|
else if (cchAdjust < 0)
|
|
{
|
|
// need to slide the anchor back if it's within the deleted range of text
|
|
ichAnchor = min(ichAnchor, ichAdjEnd + cchAdjust);
|
|
}
|
|
else // cchAdjust > 0
|
|
{
|
|
// there's nothing to do
|
|
}
|
|
|
|
return ichAnchor;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CompareRanges
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int CompareRanges(TfEditCookie ec, ITfRange *pRangeSrc, ITfRange *pRangeCmp)
|
|
{
|
|
int nRet = CR_ERROR;
|
|
BOOL fEqual;
|
|
LONG l;
|
|
|
|
pRangeCmp->CompareEnd(ec, pRangeSrc, TF_ANCHOR_START, &l);
|
|
if (l <= 0)
|
|
return CR_LEFT;
|
|
|
|
pRangeSrc->CompareEnd(ec, pRangeCmp, TF_ANCHOR_START, &l);
|
|
if (l < 0) // incl char to right
|
|
return CR_RIGHT;
|
|
|
|
if (pRangeSrc->IsEqualStart(ec, pRangeCmp, TF_ANCHOR_START, &fEqual) == S_OK && fEqual &&
|
|
pRangeSrc->IsEqualEnd(ec, pRangeCmp, TF_ANCHOR_END, &fEqual) == S_OK && fEqual)
|
|
{
|
|
return CR_EQUAL;
|
|
}
|
|
|
|
pRangeSrc->CompareStart(ec, pRangeCmp, TF_ANCHOR_START, &l);
|
|
if (l <= 0)
|
|
{
|
|
pRangeSrc->CompareEnd(ec, pRangeCmp, TF_ANCHOR_END, &l);
|
|
if (l < 0)
|
|
return CR_RIGHTMEET;
|
|
else
|
|
return CR_PARTIAL;
|
|
}
|
|
else
|
|
{
|
|
pRangeSrc->CompareEnd(ec, pRangeCmp, TF_ANCHOR_END, &l);
|
|
if (l < 0)
|
|
return CR_INCLUSION;
|
|
else
|
|
return CR_LEFTMEET;
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetRangeForWholeDoc
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT GetRangeForWholeDoc(TfEditCookie ec, ITfContext *pic, ITfRange **pprange)
|
|
{
|
|
HRESULT hr;
|
|
ITfRange *pRangeEnd = NULL;
|
|
ITfRange *pRange = NULL;
|
|
|
|
*pprange = NULL;
|
|
|
|
if (FAILED(hr = pic->GetStart(ec,&pRange)))
|
|
return hr;
|
|
|
|
if (FAILED(hr = pic->GetEnd(ec,&pRangeEnd)))
|
|
return hr;
|
|
|
|
hr = pRange->ShiftEndToRange(ec, pRangeEnd, TF_ANCHOR_END);
|
|
pRangeEnd->Release();
|
|
|
|
if (SUCCEEDED(hr))
|
|
*pprange = pRange;
|
|
else
|
|
pRange->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CompareGUIDs
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
__inline int CompUnsigned(ULONG u1, ULONG u2)
|
|
{
|
|
if (u1 == u2)
|
|
return 0;
|
|
|
|
return (u1 > u2) ? 1 : -1;
|
|
}
|
|
|
|
int CompareGUIDs(REFGUID guid1, REFGUID guid2)
|
|
{
|
|
int i;
|
|
int nRet;
|
|
|
|
if (nRet = CompUnsigned(guid1.Data1, guid2.Data1))
|
|
return nRet;
|
|
|
|
if (nRet = CompUnsigned(guid1.Data2, guid2.Data2))
|
|
return nRet;
|
|
|
|
if (nRet = CompUnsigned(guid1.Data3, guid2.Data3))
|
|
return nRet;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (nRet = CompUnsigned(guid1.Data4[i], guid2.Data4[i]))
|
|
return nRet;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsDisabledTextServices
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL IsDisabledTextServices(void)
|
|
{
|
|
static const TCHAR c_szCTFKey[] = TEXT("SOFTWARE\\Microsoft\\CTF");
|
|
static const TCHAR c_szDiableTim[] = TEXT("Disable Thread Input Manager");
|
|
|
|
HKEY hKey;
|
|
|
|
if (RegOpenKey(HKEY_CURRENT_USER, c_szCTFKey, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cb;
|
|
DWORD dwDisableTim = 0;
|
|
|
|
cb = sizeof(DWORD);
|
|
|
|
RegQueryValueEx(hKey,
|
|
c_szDiableTim,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwDisableTim,
|
|
&cb);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
//
|
|
// Ctfmon disabling flag is set, so return fail CreateInstance.
|
|
//
|
|
if (dwDisableTim)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsTIPClsidEnabled
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
const TCHAR c_szLanguageProfile[] = TEXT("\\LanguageProfile");
|
|
const TCHAR c_szCTFTipPath[] = TEXT("SOFTWARE\\Microsoft\\CTF\\TIP\\");
|
|
|
|
BOOL IsTIPClsidEnabled(
|
|
HKEY hkeyTop,
|
|
LPTSTR szTipClsid,
|
|
BOOL *bExistEnable)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HKEY hkeyTipLang;
|
|
HKEY hkeyTipLangid;
|
|
HKEY hkeyTipGuid;
|
|
UINT uIndex;
|
|
UINT uIndex2;
|
|
DWORD cb;
|
|
DWORD cchLangid;
|
|
DWORD cchGuid;
|
|
DWORD dwEnableTIP = 0;
|
|
LPTSTR pszGuid;
|
|
LPTSTR pszLangid;
|
|
TCHAR szTIPLangid[15];
|
|
TCHAR szTIPGuid[128];
|
|
TCHAR szTIPClsidLang[MAX_PATH];
|
|
FILETIME lwt;
|
|
UINT uLangidLen;
|
|
UINT uGuidLen;
|
|
|
|
StringCchCopy(szTIPClsidLang, ARRAYSIZE(szTIPClsidLang), c_szCTFTipPath);
|
|
StringCchCat(szTIPClsidLang, ARRAYSIZE(szTIPClsidLang), szTipClsid);
|
|
StringCchCat(szTIPClsidLang, ARRAYSIZE(szTIPClsidLang), c_szLanguageProfile);
|
|
|
|
pszLangid = szTIPClsidLang + lstrlen(szTIPClsidLang);
|
|
uLangidLen = ARRAYSIZE(szTIPClsidLang) - lstrlen(szTIPClsidLang);
|
|
|
|
if (RegOpenKeyEx(hkeyTop,
|
|
szTIPClsidLang, 0,
|
|
KEY_READ, &hkeyTipLang) != ERROR_SUCCESS)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
for (uIndex = 0; bRet == FALSE; uIndex++)
|
|
{
|
|
cchLangid = sizeof(szTIPLangid) / sizeof(TCHAR);
|
|
|
|
if (RegEnumKeyEx(hkeyTipLang, uIndex,
|
|
szTIPLangid, &cchLangid,
|
|
NULL, NULL, NULL, &lwt) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (cchLangid != 10)
|
|
{
|
|
// string langid subkeys should be like 0x00000409
|
|
continue;
|
|
}
|
|
|
|
if (uLangidLen > (cchLangid + 1))
|
|
{
|
|
StringCchCopy(pszLangid, uLangidLen, TEXT("\\"));
|
|
StringCchCat(szTIPClsidLang, ARRAYSIZE(szTIPClsidLang), szTIPLangid);
|
|
}
|
|
|
|
if (RegOpenKeyEx(hkeyTop,
|
|
szTIPClsidLang, 0,
|
|
KEY_READ, &hkeyTipLangid) != ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pszGuid = szTIPClsidLang + lstrlen(szTIPClsidLang);
|
|
uGuidLen = ARRAYSIZE(szTIPClsidLang) - lstrlen(szTIPClsidLang);
|
|
|
|
for (uIndex2 = 0; bRet == FALSE; uIndex2++)
|
|
{
|
|
cchGuid = sizeof(szTIPGuid) / sizeof(TCHAR);
|
|
|
|
if (RegEnumKeyEx(hkeyTipLangid, uIndex2,
|
|
szTIPGuid, &cchGuid,
|
|
NULL, NULL, NULL, &lwt) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (cchGuid != 38)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (uGuidLen > (cchGuid + 1))
|
|
{
|
|
StringCchCopy(pszGuid, uGuidLen, TEXT("\\"));
|
|
StringCchCat(szTIPClsidLang, ARRAYSIZE(szTIPClsidLang), szTIPGuid);
|
|
}
|
|
|
|
if (RegOpenKeyEx(hkeyTop,
|
|
szTIPClsidLang, 0,
|
|
KEY_READ, &hkeyTipGuid) == ERROR_SUCCESS)
|
|
{
|
|
cb = sizeof(DWORD);
|
|
|
|
if (RegQueryValueEx(hkeyTipGuid,
|
|
TEXT("Enable"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwEnableTIP,
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
*bExistEnable = TRUE;
|
|
|
|
if (dwEnableTIP)
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
else if (hkeyTop == HKEY_LOCAL_MACHINE)
|
|
{
|
|
// Default is the enabled status on HKLM
|
|
*bExistEnable = TRUE;
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*bExistEnable = FALSE;
|
|
}
|
|
|
|
RegCloseKey(hkeyTipGuid);
|
|
}
|
|
|
|
}
|
|
|
|
RegCloseKey(hkeyTipLangid);
|
|
}
|
|
|
|
RegCloseKey(hkeyTipLang);
|
|
|
|
Exit:
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// NoTipsInstalled
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// grab CLSID_SOFTKBDIMX here
|
|
#include <initguid.h>
|
|
#include "SoftKbd.h"
|
|
|
|
BOOL NoTipsInstalled(BOOL *pfOnlyTranslationRunning)
|
|
{
|
|
const CLSID CLSID_SapiLayr = {0xdcbd6fa8, 0x032f, 0x11d3, {0xb5, 0xb1, 0x00, 0xc0, 0x4f, 0xc3, 0x24, 0xa1}};
|
|
|
|
static const TCHAR c_szSpeechRecognizersKey[] = TEXT("Software\\Microsoft\\Speech\\Recognizers\\Tokens");
|
|
static const TCHAR c_szCategory[] = TEXT("\\Category\\Category");
|
|
|
|
BOOL bRet = TRUE;
|
|
BOOL bExistEnable;
|
|
HKEY hkeyTip;
|
|
HKEY hkeyTipSub;
|
|
UINT uIndex;
|
|
DWORD dwSubKeys;
|
|
DWORD cchClsid;
|
|
CLSID clsidTip;
|
|
TCHAR szTipClsid[128];
|
|
TCHAR szTipClsidPath[MAX_PATH];
|
|
FILETIME lwt;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\CTF\\TIP"),
|
|
0, KEY_READ, &hkeyTip) != ERROR_SUCCESS)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// enum through all the TIP subkeys
|
|
for (uIndex = 0; TRUE; uIndex++)
|
|
{
|
|
bExistEnable = FALSE;
|
|
|
|
cchClsid = sizeof(szTipClsid) / sizeof(TCHAR);
|
|
|
|
if (RegEnumKeyEx(hkeyTip, uIndex,
|
|
szTipClsid, &cchClsid,
|
|
NULL, NULL, NULL, &lwt) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (cchClsid != 38)
|
|
{
|
|
// string clsid subkeys should be like {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
|
continue;
|
|
}
|
|
|
|
StringCchCopy(szTipClsidPath, ARRAYSIZE(szTipClsidPath), szTipClsid);
|
|
|
|
// we want subkey\Language Profiles key
|
|
StringCchCat(szTipClsidPath, ARRAYSIZE(szTipClsidPath), c_szLanguageProfile);
|
|
|
|
// is this subkey a tip?
|
|
if (RegOpenKeyEx(hkeyTip,
|
|
szTipClsidPath, 0,
|
|
KEY_READ, &hkeyTipSub) == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeyTipSub);
|
|
|
|
// it's a tip, get the clsid
|
|
if (!StringAToCLSID(szTipClsid, &clsidTip))
|
|
continue;
|
|
|
|
// special case certain known tips
|
|
if (IsEqualGUID(clsidTip, CLSID_SapiLayr))
|
|
{
|
|
//
|
|
// This is SAPI TIP and need to handle it specially, since sptip has
|
|
// a default option as the enabled status.
|
|
//
|
|
if (!IsTIPClsidEnabled(HKEY_CURRENT_USER, szTipClsid, &bExistEnable))
|
|
{
|
|
//
|
|
// If SPTIP has enable registry setting on HKCU with the disabled
|
|
// speech tip, we assume user intentionally disable it.
|
|
//
|
|
if (bExistEnable)
|
|
continue;
|
|
}
|
|
|
|
// this is the sapi tip, which is always installed
|
|
// but it will not activate if sapi is not installed
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
c_szSpeechRecognizersKey, 0,
|
|
KEY_READ, &hkeyTipSub) != ERROR_SUCCESS)
|
|
{
|
|
continue; // this tip doesn't count
|
|
}
|
|
|
|
// need 1 or more subkeys for sapi to be truely installed...whistler has a Tokens with nothing underneath
|
|
if (RegQueryInfoKey(hkeyTipSub,
|
|
NULL, NULL, NULL, &dwSubKeys, NULL,
|
|
NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
{
|
|
dwSubKeys = 0; // assume no sub keys on failure
|
|
}
|
|
|
|
RegCloseKey(hkeyTipSub);
|
|
|
|
if (dwSubKeys != 0)
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(clsidTip, CLSID_SoftkbdIMX))
|
|
{
|
|
// don't count the softkbd, it is disabled until another tip
|
|
// enables it
|
|
continue;
|
|
}
|
|
else if(IsTIPClsidEnabled(HKEY_CURRENT_USER, szTipClsid, &bExistEnable))
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
else if (!bExistEnable)
|
|
{
|
|
if(IsTIPClsidEnabled(HKEY_LOCAL_MACHINE, szTipClsid, &bExistEnable))
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkeyTip);
|
|
|
|
Exit:
|
|
if (bRet == TRUE && pfOnlyTranslationRunning != NULL) // skip the check for aimm, which passes in NULL pfOnlyTranslationRunning
|
|
{
|
|
// word10 compart: check for bookshelf's translation service
|
|
// it uses cicero, but does not formally register itself as a tip.
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Microsoft Reference\\Bilinguals 1.0"),
|
|
0, KEY_READ, &hkeyTip) == ERROR_SUCCESS)
|
|
{
|
|
*pfOnlyTranslationRunning = TRUE;
|
|
bRet = FALSE;
|
|
RegCloseKey(hkeyTip);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RunningOnWow64
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL RunningOnWow64()
|
|
{
|
|
BOOL bOnWow64 = FALSE;
|
|
// check to make sure that we are running on wow64
|
|
LONG lStatus;
|
|
ULONG_PTR Wow64Info;
|
|
|
|
typedef BOOL (WINAPI *PFN_NTQUERYINFORMATIONPROCESS)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
|
|
|
|
PFN_NTQUERYINFORMATIONPROCESS pfnNtQueryInformationProcess;
|
|
HINSTANCE hLibNtDll = NULL;
|
|
hLibNtDll = GetSystemModuleHandle( TEXT("ntdll.dll") );
|
|
if (hLibNtDll)
|
|
{
|
|
pfnNtQueryInformationProcess = (PFN_NTQUERYINFORMATIONPROCESS)GetProcAddress(hLibNtDll, TEXT("NtQueryInformationProcess"));
|
|
if (pfnNtQueryInformationProcess)
|
|
{
|
|
lStatus = pfnNtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL);
|
|
if (NT_SUCCESS(lStatus) && Wow64Info)
|
|
{
|
|
bOnWow64 = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bOnWow64;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetSystemDefaultHKL
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HKL GetSystemDefaultHKL()
|
|
{
|
|
HKL hkl;
|
|
if (SystemParametersInfo( SPI_GETDEFAULTINPUTLANG, 0, &hkl, 0))
|
|
return hkl;
|
|
|
|
return GetKeyboardLayout(0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsDisabledCUAS
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL IsDisabledCUAS()
|
|
{
|
|
static const TCHAR c_szCtfShared[] = TEXT("SOFTWARE\\Microsoft\\CTF\\SystemShared");
|
|
static const TCHAR c_szCUAS[] = TEXT("CUAS");
|
|
|
|
DWORD cb;
|
|
HKEY hkeyCTF;
|
|
BOOL bRet = TRUE;
|
|
DWORD dwEnableCUAS = 0;
|
|
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szCtfShared, &hkeyCTF) == ERROR_SUCCESS)
|
|
{
|
|
cb = sizeof(DWORD);
|
|
|
|
RegQueryValueEx(hkeyCTF,
|
|
c_szCUAS,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwEnableCUAS,
|
|
&cb);
|
|
|
|
if (dwEnableCUAS)
|
|
bRet = FALSE;
|
|
|
|
RegCloseKey(hkeyCTF);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsInstalledEALangPack
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL IsInstalledEALangPack()
|
|
{
|
|
static const TCHAR c_szLangGroup[] = TEXT("System\\CurrentControlSet\\Control\\Nls\\Language Groups");
|
|
static const TCHAR c_szLangJPN[] = TEXT("7");
|
|
|
|
BOOL bRet = FALSE;
|
|
HKEY hkeyLangGroup;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
c_szLangGroup,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyLangGroup) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cb;
|
|
TCHAR szLangInstall[10];
|
|
|
|
cb = sizeof(szLangInstall);
|
|
|
|
//
|
|
// The checking of Japan Language is enough to know EA language pack
|
|
// installation.
|
|
//
|
|
if (RegQueryValueEx(hkeyLangGroup,
|
|
c_szLangJPN,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szLangInstall,
|
|
&cb) == ERROR_SUCCESS)
|
|
{
|
|
if (szLangInstall[0] != 0)
|
|
return TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkeyLangGroup);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetDisableCUAS
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void SetDisableCUAS(
|
|
BOOL bDisableCUAS)
|
|
{
|
|
static const TCHAR c_szCtfShared[] = TEXT("SOFTWARE\\Microsoft\\CTF\\SystemShared");
|
|
static const TCHAR c_szIMM[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\IMM");
|
|
static const TCHAR c_szLoadIMM[] = TEXT("LoadIMM");
|
|
static const TCHAR c_szIMMFile[] = TEXT("IME File");
|
|
static const TCHAR c_szIMMFileName[]= TEXT("msctfime.ime");
|
|
static const TCHAR c_szCUAS[] = TEXT("CUAS");
|
|
|
|
HKEY hkeyIMM;
|
|
HKEY hkeyCTF;
|
|
DWORD cb = sizeof(DWORD);
|
|
DWORD dwIMM32, dwCUAS;
|
|
|
|
if (bDisableCUAS)
|
|
dwIMM32 = dwCUAS = 0;
|
|
else
|
|
dwIMM32 = dwCUAS = 1;
|
|
|
|
if (RegCreateKey(HKEY_LOCAL_MACHINE, c_szIMM, &hkeyIMM) != ERROR_SUCCESS)
|
|
{
|
|
hkeyIMM = NULL;
|
|
}
|
|
|
|
if (RegCreateKey(HKEY_LOCAL_MACHINE, c_szCtfShared, &hkeyCTF) != ERROR_SUCCESS)
|
|
{
|
|
hkeyCTF = NULL;
|
|
}
|
|
|
|
if (!bDisableCUAS)
|
|
{
|
|
//
|
|
// Turn on LoadIMM and CUAS flags
|
|
//
|
|
|
|
if (hkeyIMM)
|
|
{
|
|
RegSetValueEx(hkeyIMM,
|
|
c_szIMMFile,
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)c_szIMMFileName,
|
|
(lstrlen(c_szIMMFileName) + 1) * sizeof(TCHAR));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Turn off LoadIMM and CUAS flags
|
|
//
|
|
|
|
BOOL bEALang = IsInstalledEALangPack();
|
|
|
|
if (bEALang)
|
|
{
|
|
dwIMM32 = 1;
|
|
}
|
|
}
|
|
|
|
if (hkeyIMM)
|
|
{
|
|
RegSetValueEx(hkeyIMM,
|
|
c_szLoadIMM,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwIMM32,
|
|
cb);
|
|
}
|
|
|
|
if (hkeyCTF)
|
|
{
|
|
RegSetValueEx(hkeyCTF,
|
|
c_szCUAS,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwCUAS,
|
|
cb);
|
|
}
|
|
|
|
if (hkeyIMM)
|
|
RegCloseKey(hkeyIMM);
|
|
|
|
if (hkeyCTF)
|
|
RegCloseKey(hkeyCTF);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RebootTheSystem
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void RebootTheSystem()
|
|
{
|
|
HANDLE Token = NULL;
|
|
ULONG ReturnLength, Index;
|
|
PTOKEN_PRIVILEGES NewState = NULL;
|
|
PTOKEN_PRIVILEGES OldState = NULL;
|
|
BOOL Result;
|
|
|
|
// Only allow admin privilege user for system reboot.
|
|
if (!IsAdminPrivilege())
|
|
return;
|
|
|
|
Result = OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&Token );
|
|
if (Result)
|
|
{
|
|
ReturnLength = 4096;
|
|
NewState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
|
|
OldState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
|
|
Result = (BOOL)((NewState != NULL) && (OldState != NULL));
|
|
if (Result)
|
|
{
|
|
Result = GetTokenInformation( Token, // TokenHandle
|
|
TokenPrivileges, // TokenInformationClass
|
|
NewState, // TokenInformation
|
|
ReturnLength, // TokenInformationLength
|
|
&ReturnLength ); // ReturnLength
|
|
if (Result)
|
|
{
|
|
//
|
|
// Set the state settings so that all privileges are
|
|
// enabled...
|
|
//
|
|
if (NewState->PrivilegeCount > 0)
|
|
{
|
|
for (Index = 0; Index < NewState->PrivilegeCount; Index++)
|
|
{
|
|
NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED;
|
|
}
|
|
}
|
|
|
|
Result = AdjustTokenPrivileges( Token, // TokenHandle
|
|
FALSE, // DisableAllPrivileges
|
|
NewState, // NewState
|
|
ReturnLength, // BufferLength
|
|
OldState, // PreviousState
|
|
&ReturnLength ); // ReturnLength
|
|
if (Result)
|
|
{
|
|
ExitWindowsEx(EWX_REBOOT, 0);
|
|
|
|
|
|
AdjustTokenPrivileges( Token,
|
|
FALSE,
|
|
OldState,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NewState != NULL)
|
|
{
|
|
LocalFree(NewState);
|
|
}
|
|
if (OldState != NULL)
|
|
{
|
|
LocalFree(OldState);
|
|
}
|
|
if (Token != NULL)
|
|
{
|
|
CloseHandle(Token);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsAdminPrivilege
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL IsAdminPrivilege()
|
|
{
|
|
BOOL bAdmin = FALSE;
|
|
BOOL bResult = FALSE;
|
|
BOOL fSIDCreated = FALSE;
|
|
HANDLE hToken = NULL;
|
|
PSID AdminSid;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
fSIDCreated = AllocateAndInitializeSid(&NtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&AdminSid);
|
|
|
|
if (!fSIDCreated)
|
|
return FALSE;
|
|
|
|
bResult = OpenProcessToken(GetCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&hToken );
|
|
|
|
if (bResult)
|
|
{
|
|
DWORD dwSize = 0;
|
|
TOKEN_GROUPS *pTokenGrpInfo;
|
|
|
|
GetTokenInformation(hToken,
|
|
TokenGroups,
|
|
NULL,
|
|
dwSize,
|
|
&dwSize);
|
|
|
|
if (dwSize)
|
|
pTokenGrpInfo = (PTOKEN_GROUPS) LocalAlloc(LPTR, dwSize);
|
|
else
|
|
pTokenGrpInfo = NULL;
|
|
|
|
if (pTokenGrpInfo && GetTokenInformation(hToken,
|
|
TokenGroups,
|
|
pTokenGrpInfo,
|
|
dwSize,
|
|
&dwSize))
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < pTokenGrpInfo->GroupCount; i++)
|
|
{
|
|
if (EqualSid(pTokenGrpInfo->Groups[i].Sid, AdminSid) &&
|
|
(pTokenGrpInfo->Groups[i].Attributes & SE_GROUP_ENABLED))
|
|
{
|
|
bAdmin = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pTokenGrpInfo)
|
|
LocalFree(pTokenGrpInfo);
|
|
}
|
|
|
|
if (hToken)
|
|
CloseHandle(hToken);
|
|
|
|
if (AdminSid)
|
|
FreeSid(AdminSid);
|
|
|
|
return bAdmin;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsInteractiveUserLogon
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL IsInteractiveUserLogon()
|
|
{
|
|
PSID InteractiveSid;
|
|
BOOL bCheckSucceeded;
|
|
BOOL bAmInteractive = FALSE;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
if (!AllocateAndInitializeSid(&NtAuthority,
|
|
1,
|
|
SECURITY_INTERACTIVE_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&InteractiveSid))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This checking is for logged on user or not. So we can blcok running
|
|
// ctfmon.exe process from non-authorized user.
|
|
//
|
|
bCheckSucceeded = CheckTokenMembership(NULL,
|
|
InteractiveSid,
|
|
&bAmInteractive);
|
|
|
|
if (InteractiveSid)
|
|
FreeSid(InteractiveSid);
|
|
|
|
return (bCheckSucceeded && bAmInteractive);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetSystemModuleHandle
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HMODULE GetSystemModuleHandle(LPCSTR lpModuleName)
|
|
{
|
|
CicSystemModulePath path;
|
|
|
|
if (!path.Init(lpModuleName))
|
|
return NULL;
|
|
|
|
return GetModuleHandle(path.GetPath());
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// LoadSystemLibrary
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HMODULE LoadSystemLibrary(LPCSTR lpModuleName)
|
|
{
|
|
CicSystemModulePath path;
|
|
|
|
if (!path.Init(lpModuleName))
|
|
return NULL;
|
|
|
|
return LoadLibrary(path.GetPath());
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// LoadSystemLibraryEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HMODULE LoadSystemLibraryEx(LPCSTR lpModuleName, HANDLE hFile, DWORD dwFlags)
|
|
{
|
|
CicSystemModulePath path;
|
|
|
|
if (!path.Init(lpModuleName))
|
|
return NULL;
|
|
|
|
return LoadLibraryEx(path.GetPath(), hFile, dwFlags);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetSystemModuleHandleW
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HMODULE GetSystemModuleHandleW(LPCWSTR lpModuleName)
|
|
{
|
|
CicSystemModulePathW path;
|
|
|
|
if (!path.Init(lpModuleName))
|
|
return NULL;
|
|
|
|
return GetModuleHandleW(path.GetPath());
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// LoadSystemLibraryW
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HMODULE LoadSystemLibraryW(LPCWSTR lpModuleName)
|
|
{
|
|
CicSystemModulePathW path;
|
|
|
|
if (!path.Init(lpModuleName))
|
|
return NULL;
|
|
|
|
return LoadLibraryW(path.GetPath());
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// LoadSystemLibraryEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HMODULE LoadSystemLibraryExW(LPCWSTR lpModuleName, HANDLE hFile, DWORD dwFlags)
|
|
{
|
|
CicSystemModulePathW path;
|
|
|
|
if (!path.Init(lpModuleName))
|
|
return NULL;
|
|
|
|
return LoadLibraryExW(path.GetPath(), hFile, dwFlags);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// FullPathExec
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL FullPathExec(
|
|
LPCSTR pszAppName,
|
|
LPCSTR pszCmdLine,
|
|
WORD wShowWindow,
|
|
BOOL fWinDir)
|
|
{
|
|
char szCmdLine[MAX_PATH + 1];
|
|
CicSystemModulePath fullpath;
|
|
fullpath.Init(pszAppName, fWinDir);
|
|
if (!fullpath.GetLength())
|
|
return FALSE;
|
|
|
|
//
|
|
// CreateProcess() wants an out buffer for CmdLine. So we just have it in
|
|
// stack.
|
|
//
|
|
StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), pszCmdLine);
|
|
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si = {0};
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
|
si.wShowWindow = (WORD)wShowWindow;
|
|
|
|
return CreateProcess(fullpath.GetPath(),
|
|
szCmdLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
NORMAL_PRIORITY_CLASS,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RunCPLs
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL RunCPLSetting(
|
|
LPTSTR pCmdLine)
|
|
{
|
|
const TCHAR c_szRundll32[] = TEXT("Rundll32.exe");
|
|
|
|
if (!pCmdLine)
|
|
return FALSE;
|
|
|
|
return FullPathExec(c_szRundll32,
|
|
pCmdLine,
|
|
SW_SHOWMINNOACTIVE,
|
|
FALSE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// DllShutdownInProgress
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
typedef BYTE (*PFNRTLDLLSHUTDOWININPROGRESS)(void);
|
|
|
|
BOOL DllShutdownInProgress()
|
|
{
|
|
BOOL fRet = FALSE;
|
|
static PFNRTLDLLSHUTDOWININPROGRESS pfn = NULL;
|
|
|
|
if (!pfn)
|
|
{
|
|
HINSTANCE hInst;
|
|
hInst= GetSystemModuleHandle("ntdll.dll");
|
|
if (hInst)
|
|
{
|
|
pfn = (PFNRTLDLLSHUTDOWININPROGRESS)GetProcAddress(hInst,
|
|
"RtlDllShutdownInProgress");
|
|
}
|
|
}
|
|
|
|
if (pfn)
|
|
fRet = pfn() ? TRUE : FALSE;
|
|
|
|
return fRet;
|
|
}
|