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.
1095 lines
33 KiB
1095 lines
33 KiB
/*
|
|
* spell.c
|
|
*
|
|
* Implementation of spelling
|
|
*
|
|
* Owner: v-brakol
|
|
* [email protected]
|
|
*/
|
|
#include "pch.hxx"
|
|
#define SPID
|
|
#include "richedit.h"
|
|
#include "resource.h"
|
|
#include <mshtml.h>
|
|
#include <mshtmcid.h>
|
|
#include "mshtmhst.h"
|
|
#include <docobj.h>
|
|
#include "spell.h"
|
|
#include "strconst.h"
|
|
#include <options.h>
|
|
#include <goptions.h>
|
|
#include "mailnews.h"
|
|
#include "hotlinks.h"
|
|
#include "bodyutil.h"
|
|
#include <shlwapi.h>
|
|
#include <error.h>
|
|
#include "htmlstr.h"
|
|
#include "optres.h"
|
|
#include "mlang.h"
|
|
#include "lid.h"
|
|
#include "shlwapip.h"
|
|
#include "msi.h"
|
|
#include "demand.h"
|
|
|
|
#ifdef ImageList_GetIcon
|
|
#undef ImageList_GetIcon
|
|
#endif
|
|
|
|
#include <shfusion.h>
|
|
|
|
#define cchMaxPathName (256)
|
|
|
|
#define TESTHR(hr) (FAILED(hr) || hr == HR_S_ABORT || hr == HR_S_SPELLCANCEL)
|
|
#define SPELLER_GUID "{CC29EB3F-7BC2-11D1-A921-00A0C91E2AA2}"
|
|
#define DICTIONARY_GUID "{CC29EB3D-7BC2-11D1-A921-00A0C91E2AA2}"
|
|
#ifdef DEBUG
|
|
#define SPELLER_DEBUG_GUID "{CC29EB3F-7BC2-11D1-A921-10A0C91E2AA2}"
|
|
#define DICTIONARY_DEBUG_GUID "{CC29EB3D-7BC2-11D1-A921-10A0C91E2AA2}"
|
|
#endif // DEBUG
|
|
|
|
typedef BOOL (LPFNENUMLANG)(DWORD_PTR, LPTSTR);
|
|
typedef BOOL (LPFNENUMUSERDICT)(DWORD_PTR, LPTSTR);
|
|
|
|
typedef struct _FILLLANG
|
|
{
|
|
HWND hwndCombo;
|
|
BOOL fUnknownFound;
|
|
BOOL fDefaultFound;
|
|
BOOL fCurrentFound;
|
|
UINT lidDefault;
|
|
UINT lidCurrent;
|
|
} FILLLANG, * LPFILLLANG;
|
|
|
|
BOOL FDBCSEnabled(void);
|
|
BOOL TestLangID(LPCTSTR szLangId);
|
|
BOOL GetLangID(LPTSTR szLangID, DWORD cchLangId);
|
|
WORD WGetLangID(void);
|
|
BOOL SetLangID(LPTSTR szLandID);
|
|
DWORD GetSpellingPaths(LPCTSTR szKey, LPTSTR szReturnBuffer, LPTSTR szMdr, UINT cchReturnBufer);
|
|
VOID OpenCustomDictionary(VOID);
|
|
VOID FillLanguageDropDown(HWND hwndLang);
|
|
VOID EnumLanguages(DWORD_PTR, LPFNENUMLANG);
|
|
BOOL FindLangCallback(DWORD_PTR dwLangId, LPTSTR lpszLang);
|
|
BOOL EnumLangCallback(DWORD_PTR dwLangId, LPTSTR lpszLang);
|
|
BOOL FBadSpellChecker(LPSTR rgchBufDigit);
|
|
BOOL GetNewSpellerEngine(LANGID lgid, TCHAR *rgchEngine, DWORD cchEngine, TCHAR *rgchLex, DWORD cchLex, BOOL bTestAvail);
|
|
HRESULT OpenDirectory(TCHAR *szDir);
|
|
|
|
////Spelling tab CS-help
|
|
const static HELPMAP g_rgCtxMapSpell[] = {
|
|
{CHK_AlwaysSuggest, IDH_NEWS_SPELL_SUGGEST_REPL},
|
|
{CHK_CheckSpellingOnSend, IDH_NEWS_SPELL_CHECK_BEFORE_SEND},
|
|
{CHK_IgnoreUppercase, IDH_NEWS_SPELL_IGNORE_UPPERCASE},
|
|
{CHK_IgnoreNumbers, IDH_NEWS_SPELL_IGNORE_WITH_NUMBERS},
|
|
{CHK_IgnoreOriginalMessage, IDH_NEWS_SPELL_ORIGINAL_TEXT},
|
|
{CHK_IgnoreURL, IDH_OPTIONS_SPELLING_INTERNET_ADDRESSES},
|
|
{idcSpellLanguages, IDH_OPTIONS_SPELLING_LANGUAGE},
|
|
{idcViewDictionary, IDH_OPTIONS_SPELLING_DICTIONARY},
|
|
{CHK_CheckSpellingOnType, 0},
|
|
{idcStatic1, IDH_NEWS_COMM_GROUPBOX},
|
|
{idcStatic2, IDH_NEWS_COMM_GROUPBOX},
|
|
{idcStatic3, IDH_NEWS_COMM_GROUPBOX},
|
|
{idcStatic4, IDH_NEWS_COMM_GROUPBOX},
|
|
{idcStatic5, IDH_NEWS_COMM_GROUPBOX},
|
|
{idcStatic6, IDH_NEWS_COMM_GROUPBOX},
|
|
{IDC_SPELL_SETTINGS_ICON, IDH_NEWS_COMM_GROUPBOX},
|
|
{IDC_SPELL_IGNORE_ICON, IDH_NEWS_COMM_GROUPBOX},
|
|
{IDC_SPELL_LANGUAGE_ICON, IDH_NEWS_COMM_GROUPBOX},
|
|
{0, 0}};
|
|
|
|
|
|
ASSERTDATA
|
|
|
|
BOOL FIgnoreNumber(void) { return(DwGetOption(OPT_SPELLIGNORENUMBER)); }
|
|
BOOL FIgnoreUpper(void) { return(DwGetOption(OPT_SPELLIGNOREUPPER)); }
|
|
BOOL FIgnoreDBCS(void) { return(DwGetOption(OPT_SPELLIGNOREDBCS)); }
|
|
BOOL FIgnoreProtect(void) { return(DwGetOption(OPT_SPELLIGNOREPROTECT)); }
|
|
BOOL FAlwaysSuggest(void) { return(DwGetOption(OPT_SPELLALWAYSSUGGEST)); }
|
|
BOOL FCheckOnSend(void) { return(DwGetOption(OPT_SPELLCHECKONSEND)); }
|
|
BOOL FIgnoreURL(void) { return(DwGetOption(OPT_SPELLIGNOREURL)); }
|
|
|
|
typedef struct
|
|
{
|
|
LPTSTR pszString;
|
|
DWORD cchSize;
|
|
} STRING_AND_SIZE;
|
|
|
|
|
|
BOOL TestLangID(LPCTSTR szLangId)
|
|
{
|
|
// check for new speller
|
|
{
|
|
TCHAR rgchEngine[MAX_PATH];
|
|
int cchEngine = sizeof(rgchEngine) / sizeof(rgchEngine[0]);
|
|
TCHAR rgchLex[MAX_PATH];
|
|
int cchLex = sizeof(rgchLex) / sizeof(rgchLex[0]);
|
|
|
|
if (GetNewSpellerEngine((LANGID) StrToInt(szLangId), rgchEngine, cchEngine, rgchLex, cchLex, TRUE))
|
|
return TRUE;
|
|
}
|
|
|
|
// use the old code to check for an old speller
|
|
{
|
|
TCHAR rgchBufKeyTest[cchMaxPathName];
|
|
TCHAR rgchBufTest[cchMaxPathName];
|
|
TCHAR szMdr[cchMaxPathName];
|
|
|
|
wnsprintf(rgchBufKeyTest, ARRAYSIZE(rgchBufKeyTest), c_szRegSpellKeyDef, szLangId);
|
|
if (GetSpellingPaths(rgchBufKeyTest, rgchBufTest, szMdr, sizeof(rgchBufTest)/sizeof(TCHAR)))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL SetLangID(LPTSTR szLangId)
|
|
{
|
|
return SetOption(OPT_SPELL_LANGID, szLangId, lstrlen(szLangId) + 1, NULL, 0);
|
|
}
|
|
|
|
/*
|
|
* GetSpellLangID
|
|
*
|
|
* Returns the LangID that should be used as the base for all registry
|
|
* operations
|
|
*
|
|
*/
|
|
BOOL GetLangID(LPTSTR szLangId, DWORD cchLangId)
|
|
{
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
TCHAR rgchBufKey[cchMaxPathName];
|
|
BOOL fRet;
|
|
|
|
if (GetOption(OPT_SPELL_LANGID, szLangId, cchLangId) != 5)
|
|
{
|
|
// For Arabic, we should consider all sub-langs also
|
|
// since spelling checker for Aarbic uses Saudi Aarbia sub lang
|
|
|
|
LANGID langid = GetUserDefaultLangID();
|
|
if (PRIMARYLANGID(langid) == LANG_ARABIC)
|
|
{
|
|
langid = MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA);
|
|
}
|
|
wnsprintf(szLangId, cchLangId, "%d", langid);
|
|
Assert(lstrlen(szLangId) == 4);
|
|
}
|
|
|
|
wnsprintf(rgchBufKey, ARRAYSIZE(rgchBufKey), c_szRegSpellKeyDef, szLangId);
|
|
// copy c_szRegSpellProfile to buffer
|
|
StrCpyN(rgchBuf, c_szRegSpellProfile, ARRAYSIZE(rgchBuf));
|
|
// add key to buffer
|
|
StrCatBuff(rgchBuf, rgchBufKey, ARRAYSIZE(rgchBuf));
|
|
|
|
// and see if it's legit:
|
|
if(!(fRet = TestLangID(szLangId)))
|
|
{
|
|
STRING_AND_SIZE stringAndSize;
|
|
|
|
stringAndSize.pszString = szLangId;
|
|
stringAndSize.cchSize = cchLangId;
|
|
|
|
// couldn't open it!
|
|
// check for other languages that might be installed...
|
|
szLangId[0] = 0;
|
|
EnumLanguages((DWORD_PTR) &stringAndSize, FindLangCallback);
|
|
if(*szLangId == 0)
|
|
wnsprintf(szLangId, cchLangId, "%d", GetUserDefaultLangID());
|
|
}
|
|
|
|
fRet = (szLangId[0] != 0) && TestLangID(szLangId);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
WORD WGetLangID()
|
|
{
|
|
TCHAR rgchBufDigit[10];
|
|
|
|
GetLangID(rgchBufDigit, ARRAYSIZE(rgchBufDigit));
|
|
|
|
return (WORD) StrToInt(rgchBufDigit);
|
|
}
|
|
|
|
BOOL FindLangCallback(DWORD_PTR dwLangId, LPTSTR lpszLang)
|
|
{
|
|
// dwLangID is long pointer to szLang ID. Copy it and return FALSE
|
|
STRING_AND_SIZE * pStringAndSize = (STRING_AND_SIZE *) dwLangId;
|
|
|
|
if (pStringAndSize && pStringAndSize->pszString)
|
|
{
|
|
StrCpyN(pStringAndSize->pszString, lpszLang, pStringAndSize->cchSize);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL EnumOldSpellerLanguages(DWORD_PTR dwCookie, LPFNENUMLANG pfn)
|
|
{
|
|
DWORD iKey = 0;
|
|
FILETIME ft;
|
|
HKEY hkey = NULL;
|
|
LONG lRet;
|
|
TCHAR szLangId[cchMaxPathName];
|
|
DWORD cchLangId;
|
|
BOOL fContinue = TRUE;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegSpellKeyDefRoot, 0, KEY_ENUMERATE_SUB_KEYS, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
do
|
|
{
|
|
cchLangId = (cchMaxPathName - 1) * sizeof(TCHAR);
|
|
|
|
lRet = RegEnumKeyEx(hkey,
|
|
iKey++,
|
|
szLangId,
|
|
&cchLangId,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ft);
|
|
|
|
if (lRet != ERROR_SUCCESS || lRet == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
|
|
|
|
// do some quick sanity checking
|
|
if (cchLangId != 4 ||
|
|
!IsCharAlphaNumeric(szLangId[0]) ||
|
|
IsCharAlpha(szLangId[0]))
|
|
{
|
|
fContinue = TRUE;
|
|
}
|
|
else
|
|
fContinue = (!TestLangID(szLangId) || (*pfn)(dwCookie, szLangId));
|
|
|
|
} while (fContinue);
|
|
}
|
|
|
|
if (hkey)
|
|
RegCloseKey(hkey);
|
|
|
|
return fContinue;
|
|
}
|
|
|
|
BOOL EnumNewSpellerLanguages(DWORD_PTR dwCookie, LPFNENUMLANG pfn)
|
|
{
|
|
BOOL fContinue = TRUE;
|
|
|
|
DWORD i;
|
|
UINT installState;
|
|
UINT componentState;
|
|
TCHAR rgchQualifier[MAX_PATH];
|
|
DWORD cchQualifier;
|
|
|
|
#ifdef DEBUG
|
|
for(i=0; fContinue; i++)
|
|
{
|
|
cchQualifier = sizeof(rgchQualifier) / sizeof(rgchQualifier[0]);
|
|
componentState = MsiEnumComponentQualifiers(DICTIONARY_DEBUG_GUID, i, rgchQualifier, &cchQualifier, NULL, NULL);
|
|
|
|
if (componentState != ERROR_SUCCESS)
|
|
break;
|
|
|
|
// find the language ID
|
|
// the string is formatted as 1033\xxxxxx
|
|
// or 1042
|
|
{
|
|
TCHAR szLangId[cchMaxPathName];
|
|
TCHAR *pSlash;
|
|
|
|
StrCpyN(szLangId, rgchQualifier, ARRAYSIZE(szLangId));
|
|
pSlash = StrChr(szLangId, '\\');
|
|
if (pSlash)
|
|
*pSlash = 0;
|
|
|
|
fContinue = (*pfn)(dwCookie, szLangId);
|
|
}
|
|
}
|
|
#endif // DEBUG
|
|
|
|
for(i=0; fContinue; i++)
|
|
{
|
|
cchQualifier = sizeof(rgchQualifier) / sizeof(rgchQualifier[0]);
|
|
componentState = MsiEnumComponentQualifiers(DICTIONARY_GUID, i, rgchQualifier, &cchQualifier, NULL, NULL);
|
|
|
|
if (componentState != ERROR_SUCCESS)
|
|
break;
|
|
|
|
// find the language ID
|
|
// the string is formatted as 1033\xxxxxx
|
|
// or 1042
|
|
{
|
|
TCHAR szLangId[cchMaxPathName];
|
|
TCHAR *pSlash;
|
|
|
|
StrCpyN(szLangId, rgchQualifier, ARRAYSIZE(szLangId));
|
|
pSlash = StrChr(szLangId, '\\');
|
|
if (pSlash)
|
|
*pSlash = 0;
|
|
|
|
fContinue = (*pfn)(dwCookie, szLangId);
|
|
}
|
|
}
|
|
|
|
return fContinue;
|
|
}
|
|
|
|
VOID EnumLanguages(DWORD_PTR dwCookie, LPFNENUMLANG pfn)
|
|
{
|
|
// enum all languages
|
|
EnumNewSpellerLanguages(dwCookie, pfn);
|
|
EnumOldSpellerLanguages(dwCookie, pfn);
|
|
}
|
|
|
|
/*
|
|
* GetSpellingPaths
|
|
*
|
|
* Purpose:
|
|
* Function to get Spelling DLL names.
|
|
*
|
|
* Arguments:
|
|
* szKey c_szRegSpellKeyDef (with correct language)
|
|
* szDefault c_szRegSpellEmpty
|
|
* szReturnBuffer dll filename
|
|
* szMdr dictionary filename
|
|
* cchReturnBufer
|
|
*
|
|
* Returns:
|
|
* DWORD
|
|
*/
|
|
DWORD GetSpellingPaths(LPCTSTR szKey, LPTSTR szReturnBuffer, LPTSTR szMdr, UINT cchReturnBufer)
|
|
{
|
|
DWORD dwRet = 0;
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
DWORD dwType, cbData;
|
|
HKEY hkey = NULL;
|
|
LPTSTR szValue;
|
|
|
|
szReturnBuffer[0] = 0;
|
|
wnsprintf(rgchBuf, ARRAYSIZE(rgchBuf), TEXT("%s%s"), c_szRegSpellProfile, szKey);
|
|
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, rgchBuf, 0, KEY_QUERY_VALUE, &hkey))
|
|
goto err;
|
|
|
|
cbData = cchReturnBufer * sizeof(TCHAR);
|
|
szValue = (LPTSTR) (szMdr ? c_szRegSpellPath : c_szRegSpellPathDict);
|
|
if (ERROR_SUCCESS != SHQueryValueEx(hkey, szValue, 0L, &dwType, (BYTE *) szReturnBuffer, &cbData))
|
|
goto err;
|
|
|
|
// Parse off the main dictionary filename
|
|
if(szMdr)
|
|
{
|
|
szMdr[0] = 0;
|
|
cbData = cchReturnBufer * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS != SHQueryValueEx(hkey, c_szRegSpellPathLex, 0L, &dwType, (BYTE *) szMdr, &cbData))
|
|
goto err;
|
|
}
|
|
|
|
dwRet = cbData;
|
|
|
|
err:
|
|
if(hkey)
|
|
RegCloseKey(hkey);
|
|
return dwRet;
|
|
}
|
|
|
|
BOOL GetNewSpellerEngine(LANGID lgid, TCHAR *rgchEngine, DWORD cchEngine, TCHAR *rgchLex, DWORD cchLex, BOOL bTestAvail)
|
|
{
|
|
DWORD er;
|
|
LPCSTR rgpszDictionaryTypes[] = {"Normal", "Consise", "Complete"};
|
|
int cDictTypes = sizeof(rgpszDictionaryTypes) / sizeof(LPCSTR);
|
|
int i;
|
|
TCHAR rgchQual[MAX_PATH];
|
|
bool fFound = FALSE;
|
|
DWORD cch;
|
|
INSTALLUILEVEL iuilOriginal;
|
|
|
|
if (rgchEngine == NULL || rgchLex == NULL)
|
|
return FALSE;
|
|
|
|
*rgchEngine = 0;
|
|
*rgchLex = 0;
|
|
|
|
wnsprintf(rgchQual, ARRAYSIZE(rgchQual), "%d\\Normal", lgid);
|
|
cch = cchEngine;
|
|
|
|
if (bTestAvail)
|
|
{
|
|
// Explicitly Turn off internal installer UI
|
|
// Eg: A feature is set to "run from CD," and CD is not present - fail silently
|
|
// OE Bug 74697
|
|
iuilOriginal = MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
er = MsiProvideQualifiedComponent(SPELLER_DEBUG_GUID, rgchQual, (bTestAvail ? INSTALLMODE_EXISTING : INSTALLMODE_DEFAULT), rgchEngine, &cch);
|
|
if ((er != ERROR_SUCCESS) && (er != ERROR_FILE_NOT_FOUND))
|
|
{
|
|
cch = cchEngine;
|
|
er = MsiProvideQualifiedComponent(SPELLER_GUID, rgchQual, (bTestAvail ? INSTALLMODE_EXISTING : INSTALLMODE_DEFAULT), rgchEngine, &cch);
|
|
}
|
|
#else
|
|
er = MsiProvideQualifiedComponent(SPELLER_GUID, rgchQual, (bTestAvail ? INSTALLMODE_EXISTING : INSTALLMODE_DEFAULT), rgchEngine, &cch);
|
|
#endif
|
|
|
|
if ((er != ERROR_SUCCESS) && (er != ERROR_FILE_NOT_FOUND))
|
|
{
|
|
fFound = FALSE;
|
|
goto errorExit;
|
|
}
|
|
|
|
// Hebrew does not have a main lex
|
|
#ifdef OLDHEB
|
|
if (lgid != lidHebrew)
|
|
{
|
|
#endif // OLDHEB
|
|
for (i = 0; i < cDictTypes; i++)
|
|
{
|
|
wnsprintf(rgchQual, ARRAYSIZE(rgchQual), "%d\\%s", lgid, rgpszDictionaryTypes[i]);
|
|
cch = cchLex;
|
|
|
|
#ifdef DEBUG
|
|
er = MsiProvideQualifiedComponent(DICTIONARY_DEBUG_GUID, rgchQual, (bTestAvail ? INSTALLMODE_EXISTING : INSTALLMODE_DEFAULT), rgchLex, &cch);
|
|
if ((er != ERROR_SUCCESS) && (er != ERROR_FILE_NOT_FOUND))
|
|
{
|
|
cch = cchLex;
|
|
er = MsiProvideQualifiedComponent(DICTIONARY_GUID, rgchQual, (bTestAvail ? INSTALLMODE_EXISTING : INSTALLMODE_DEFAULT), rgchLex, &cch);
|
|
}
|
|
#else // DEBUG
|
|
er = MsiProvideQualifiedComponent(DICTIONARY_GUID, rgchQual, (bTestAvail ? INSTALLMODE_EXISTING : INSTALLMODE_DEFAULT), rgchLex, &cch);
|
|
#endif // DEBUG
|
|
|
|
if ((er == ERROR_SUCCESS) || (er == ERROR_FILE_NOT_FOUND))
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef OLDHEB
|
|
}
|
|
#endif //OLDDHEB
|
|
|
|
errorExit:
|
|
if (bTestAvail)
|
|
{
|
|
// Restore original UI Level
|
|
MsiSetInternalUI(iuilOriginal, NULL);
|
|
}
|
|
return fFound;
|
|
}
|
|
|
|
BOOL FIsNewSpellerInstaller()
|
|
{
|
|
LANGID langid;
|
|
TCHAR rgchEngine[MAX_PATH];
|
|
int cchEngine = sizeof(rgchEngine) / sizeof(rgchEngine[0]);
|
|
TCHAR rgchLex[MAX_PATH];
|
|
int cchLex = sizeof(rgchLex) / sizeof(rgchLex[0]);
|
|
|
|
// first try to load dictionaries for various languages
|
|
langid = WGetLangID();
|
|
if (!GetNewSpellerEngine(langid, rgchEngine, cchEngine, rgchLex, cchLex, TRUE))
|
|
{
|
|
langid = GetSystemDefaultLangID();
|
|
if (!GetNewSpellerEngine(langid, rgchEngine, cchEngine, rgchLex, cchLex, TRUE))
|
|
{
|
|
langid = 1033; // bloody cultural imperialists.
|
|
if (!GetNewSpellerEngine(langid, rgchEngine, cchEngine, rgchLex, cchLex, TRUE))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* FIsSpellingInstalled
|
|
*
|
|
* Purpose:
|
|
* Is the spelling stuff installed
|
|
*
|
|
* Arguments:
|
|
* none
|
|
*
|
|
* Returns:
|
|
* BOOL Returns TRUE if spelling is installed, else FALSE.
|
|
*/
|
|
BOOL FIsSpellingInstalled()
|
|
{
|
|
TCHAR rgchBufDigit[10];
|
|
|
|
if (GetLangID(rgchBufDigit, sizeof(rgchBufDigit)/sizeof(TCHAR)) && !FBadSpellChecker(rgchBufDigit))
|
|
return true;
|
|
|
|
if (FIsNewSpellerInstaller())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Does a quick check to see if spelling is available; caches result.
|
|
BOOL FCheckSpellAvail(void)
|
|
{
|
|
static int fSpellAvailable = -1;
|
|
|
|
if (fSpellAvailable < 0)
|
|
fSpellAvailable = (FIsSpellingInstalled() ? 1 : 0);
|
|
|
|
return (fSpellAvailable > 0);
|
|
}
|
|
|
|
BOOL FDBCSEnabled(void)
|
|
{
|
|
static int fDBCS = -1;
|
|
|
|
if (fDBCS < 0)
|
|
fDBCS = GetSystemMetrics(SM_DBCSENABLED);
|
|
|
|
return (fDBCS > 0);
|
|
}
|
|
|
|
// Fill the options list with the available spelling languages
|
|
VOID FillLanguageDropDown(HWND hwndLang)
|
|
{
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
FILLLANG fl;
|
|
int i;
|
|
|
|
// get the current language
|
|
GetLangID(rgchBuf, cchMaxPathName);
|
|
|
|
fl.hwndCombo = hwndLang;
|
|
fl.fUnknownFound = FALSE;
|
|
fl.fDefaultFound = FALSE;
|
|
fl.fCurrentFound = FALSE;
|
|
fl.lidDefault = WGetLangID();
|
|
fl.lidCurrent = StrToInt(rgchBuf);
|
|
|
|
EnumLanguages((DWORD_PTR) &fl, EnumLangCallback);
|
|
|
|
// this should never happen, but just in case
|
|
if (!fl.fDefaultFound)
|
|
{
|
|
LoadString(g_hLocRes, idsDefaultLang, rgchBuf, cchMaxPathName - 1);
|
|
i = ComboBox_AddString(hwndLang, rgchBuf);
|
|
ComboBox_SetItemData(hwndLang, i, fl.lidDefault);
|
|
}
|
|
|
|
// select the current one, if found, else the default one.
|
|
for (i = ComboBox_GetCount(hwndLang) - 1; i >= 0; i--)
|
|
{
|
|
UINT lid = (UINT) ComboBox_GetItemData(hwndLang, i);
|
|
|
|
if ((fl.fCurrentFound && lid == fl.lidCurrent) ||
|
|
(!fl.fCurrentFound && fl.fDefaultFound && lid == fl.lidDefault))
|
|
{
|
|
ComboBox_SetCurSel(hwndLang, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL EnumLangCallback(DWORD_PTR dw, LPTSTR lpszLang)
|
|
{
|
|
LPFILLLANG lpfl = (LPFILLLANG) dw;
|
|
TCHAR szLang[cchMaxPathName];
|
|
LID lidLang = (LID) StrToInt(lpszLang);
|
|
int i;
|
|
HRESULT hr=S_OK;
|
|
IMultiLanguage2 *pMLang2 = NULL;
|
|
RFC1766INFO info;
|
|
|
|
// check to see if we already have the LID in the ComboBox
|
|
{
|
|
for (i = ComboBox_GetCount(lpfl->hwndCombo) - 1; i >= 0; i--)
|
|
{
|
|
LID lid = (UINT) ComboBox_GetItemData(lpfl->hwndCombo, i);
|
|
|
|
if (lid == lidLang)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Try to create an IMultiLanguage2 interface
|
|
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,CLSCTX_INPROC, IID_IMultiLanguage2, (LPVOID *) &pMLang2);
|
|
if (SUCCEEDED(hr))
|
|
hr = pMLang2->GetRfc1766Info(MAKELCID(lidLang, SORT_DEFAULT), MLGetUILanguage(), &info);
|
|
|
|
SafeRelease(pMLang2);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (WideCharToMultiByte (CP_ACP, 0, info.wszLocaleName, -1,
|
|
szLang, sizeof(szLang), NULL, NULL))
|
|
{
|
|
szLang[ARRAYSIZE(szLang) - 1] = '\0'; //better safe than not null terminated
|
|
i = ComboBox_AddString(lpfl->hwndCombo, szLang);
|
|
ComboBox_SetItemData(lpfl->hwndCombo, i, lidLang);
|
|
|
|
if (lidLang == lpfl->lidDefault)
|
|
lpfl->fDefaultFound = TRUE;
|
|
|
|
if (lidLang == lpfl->lidCurrent)
|
|
lpfl->fCurrentFound = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE; // keep enumerating
|
|
}
|
|
|
|
INT_PTR CALLBACK SpellingPageProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL f;
|
|
OPTINFO *pmoi;
|
|
|
|
pmoi = (OPTINFO *)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
UINT uCP;
|
|
|
|
Assert(pmoi == NULL);
|
|
pmoi = (OPTINFO *)(((PROPSHEETPAGE *)lParam)->lParam);
|
|
Assert(pmoi != NULL);
|
|
SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)pmoi);
|
|
|
|
ButtonChkFromOptInfo(hwnd, CHK_AlwaysSuggest, pmoi, OPT_SPELLALWAYSSUGGEST);
|
|
ButtonChkFromOptInfo(hwnd, CHK_CheckSpellingOnSend, pmoi, OPT_SPELLCHECKONSEND);
|
|
ButtonChkFromOptInfo(hwnd, CHK_CheckSpellingOnType, pmoi, OPT_SPELLCHECKONTYPE);
|
|
ButtonChkFromOptInfo(hwnd, CHK_IgnoreUppercase, pmoi, OPT_SPELLIGNOREUPPER);
|
|
ButtonChkFromOptInfo(hwnd, CHK_IgnoreNumbers, pmoi, OPT_SPELLIGNORENUMBER);
|
|
ButtonChkFromOptInfo(hwnd, CHK_IgnoreOriginalMessage, pmoi, OPT_SPELLIGNOREPROTECT);
|
|
ButtonChkFromOptInfo(hwnd, CHK_IgnoreDBCS, pmoi, OPT_SPELLIGNOREDBCS);
|
|
ButtonChkFromOptInfo(hwnd, CHK_IgnoreURL, pmoi, OPT_SPELLIGNOREURL);
|
|
|
|
FillLanguageDropDown(GetDlgItem(hwnd, idcSpellLanguages));
|
|
|
|
uCP = GetACP();
|
|
// 50406: if we're not DBCS or (we're Japaneese or either Chinese) don't show
|
|
// the DBCS option.
|
|
if (!FDBCSEnabled() || ((932==uCP) || (936==uCP) || (950==uCP)))
|
|
{
|
|
ShowWindow(GetDlgItem(hwnd, CHK_IgnoreDBCS), SW_HIDE);
|
|
EnableWindow(GetDlgItem(hwnd, CHK_IgnoreDBCS), FALSE);
|
|
}
|
|
|
|
// Pictures
|
|
HICON hIcon;
|
|
|
|
hIcon = ImageList_GetIcon(pmoi->himl, ID_SPELL, ILD_TRANSPARENT);
|
|
SendDlgItemMessage(hwnd, IDC_SPELL_SETTINGS_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
|
|
|
|
hIcon = ImageList_GetIcon(pmoi->himl, ID_SPELL_IGNORE, ILD_TRANSPARENT);
|
|
SendDlgItemMessage(hwnd, IDC_SPELL_IGNORE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
|
|
|
|
hIcon = ImageList_GetIcon(pmoi->himl, ID_LANGUAGE_ICON, ILD_TRANSPARENT);
|
|
SendDlgItemMessage(hwnd, IDC_SPELL_LANGUAGE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
|
|
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)1);
|
|
}
|
|
return(TRUE);
|
|
|
|
case WM_HELP:
|
|
case WM_CONTEXTMENU:
|
|
return OnContextHelp(hwnd, message, wParam, lParam, g_rgCtxMapSpell);
|
|
|
|
case WM_COMMAND:
|
|
if (1 != GetWindowLongPtr(hwnd, GWLP_USERDATA))
|
|
break;
|
|
|
|
if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
if (LOWORD(wParam) == idcViewDictionary)
|
|
{
|
|
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsSpellCaption), MAKEINTRESOURCEW(idsErrSpellWarnDictionary), NULL, MB_OK | MB_ICONINFORMATION);
|
|
OpenCustomDictionary();
|
|
}
|
|
else
|
|
{
|
|
PropSheet_Changed(GetParent(hwnd), hwnd);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *)lParam)->code)
|
|
{
|
|
case PSN_APPLY:
|
|
{
|
|
int i;
|
|
int lidNew;
|
|
int lidOld;
|
|
TCHAR rgchBuf[10];
|
|
|
|
// get the current language
|
|
GetLangID(rgchBuf, sizeof(rgchBuf) / sizeof(TCHAR));
|
|
lidOld = StrToInt(rgchBuf);
|
|
|
|
Assert(pmoi != NULL);
|
|
|
|
ButtonChkToOptInfo(hwnd, CHK_AlwaysSuggest, pmoi, OPT_SPELLALWAYSSUGGEST);
|
|
ButtonChkToOptInfo(hwnd, CHK_CheckSpellingOnSend, pmoi, OPT_SPELLCHECKONSEND);
|
|
ButtonChkToOptInfo(hwnd, CHK_CheckSpellingOnType, pmoi, OPT_SPELLCHECKONTYPE);
|
|
ButtonChkToOptInfo(hwnd, CHK_IgnoreUppercase, pmoi, OPT_SPELLIGNOREUPPER);
|
|
ButtonChkToOptInfo(hwnd, CHK_IgnoreNumbers, pmoi, OPT_SPELLIGNORENUMBER);
|
|
ButtonChkToOptInfo(hwnd, CHK_IgnoreOriginalMessage, pmoi, OPT_SPELLIGNOREPROTECT);
|
|
ButtonChkToOptInfo(hwnd, CHK_IgnoreDBCS, pmoi, OPT_SPELLIGNOREDBCS);
|
|
ButtonChkToOptInfo(hwnd, CHK_IgnoreURL, pmoi, OPT_SPELLIGNOREURL);
|
|
|
|
i = ComboBox_GetCurSel(GetDlgItem(hwnd, idcSpellLanguages));
|
|
lidNew =(LID) ComboBox_GetItemData(GetDlgItem(hwnd, idcSpellLanguages), i);
|
|
|
|
if (lidNew != lidOld)
|
|
{
|
|
wnsprintf(rgchBuf, ARRAYSIZE(rgchBuf), "%d", lidNew);
|
|
SetLangID(rgchBuf);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
FreeIcon(hwnd, IDC_SPELL_SETTINGS_ICON);
|
|
FreeIcon(hwnd, IDC_SPELL_IGNORE_ICON);
|
|
FreeIcon(hwnd, IDC_SPELL_LANGUAGE_ICON);
|
|
break;
|
|
#if 0
|
|
case WM_HELP:
|
|
{
|
|
NMHDR nmhdr;
|
|
|
|
nmhdr.code = PSN_HELP;
|
|
SendMessage(hwnd, WM_NOTIFY, 0, (LPARAM) &nmhdr);
|
|
SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
BOOL EnumOffice9UserDictionaries(DWORD_PTR dwCookie, LPFNENUMUSERDICT pfn)
|
|
{
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
HKEY hkey = NULL;
|
|
FILETIME ft;
|
|
DWORD iKey = 0;
|
|
LONG lRet;
|
|
TCHAR szValue[cchMaxPathName];
|
|
DWORD cchValue;
|
|
TCHAR szCustDict[cchMaxPathName];
|
|
DWORD cchCustDict;
|
|
BOOL fContinue = TRUE;
|
|
BOOL fFoundUserDict = FALSE;
|
|
TCHAR szOffice9Proof[cchMaxPathName]={0};
|
|
|
|
// SOFTWARE\\Microsoft\\Shared Tools\\Proofing Tools\\Custom Dictionaries
|
|
StrCpyN(rgchBuf, c_szRegSpellProfile, ARRAYSIZE(rgchBuf));
|
|
StrCatBuff(rgchBuf, c_szRegSpellKeyCustom, ARRAYSIZE(rgchBuf));
|
|
|
|
if(RegOpenKeyEx(HKEY_CURRENT_USER, rgchBuf, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
do
|
|
{
|
|
cchValue = sizeof(szValue) / sizeof(szValue[0]);
|
|
cchCustDict = sizeof(szCustDict) / sizeof(szCustDict[0]);
|
|
|
|
lRet = RegEnumValue(hkey,
|
|
iKey++,
|
|
szValue,
|
|
&cchValue,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szCustDict,
|
|
&cchCustDict);
|
|
|
|
if (lRet != ERROR_SUCCESS || lRet == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
|
|
fFoundUserDict = TRUE;
|
|
|
|
// check to see if we have a path
|
|
if (!(StrChr(szCustDict, ':') || StrChr(szCustDict, '\\')))
|
|
{
|
|
TCHAR szTemp[cchMaxPathName];
|
|
|
|
if (!strlen(szOffice9Proof))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
if (S_OK == SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl))
|
|
SHGetPathFromIDList(pidl, szOffice9Proof);
|
|
|
|
// if this fails then we will try the current path
|
|
}
|
|
|
|
StrCpyN(szTemp, szOffice9Proof, ARRAYSIZE(szTemp));
|
|
PathAppend(szTemp, c_szSpellOffice9ProofPath);
|
|
StrCatBuff(szTemp, szCustDict, ARRAYSIZE(szTemp));
|
|
StrCpyN(szCustDict, szTemp, ARRAYSIZE(szCustDict));
|
|
}
|
|
|
|
fContinue = (*pfn)(dwCookie, szCustDict);
|
|
|
|
} while (fContinue);
|
|
}
|
|
|
|
if (hkey)
|
|
RegCloseKey(hkey);
|
|
|
|
return fFoundUserDict;
|
|
}
|
|
|
|
BOOL EnumOfficeUserDictionaries(DWORD_PTR dwCookie, LPFNENUMUSERDICT pfn)
|
|
{
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
HKEY hkey = NULL;
|
|
FILETIME ft;
|
|
DWORD iKey = 0;
|
|
LONG lRet;
|
|
TCHAR szValue[cchMaxPathName];
|
|
DWORD cchValue;
|
|
TCHAR szCustDict[cchMaxPathName];
|
|
DWORD cchCustDict;
|
|
BOOL fFoundUserDict = FALSE;
|
|
BOOL fContinue = TRUE;
|
|
|
|
// SOFTWARE\\Microsoft\\Shared Tools\\Proofing Tools\\Custom Dictionaries
|
|
StrCpyN(rgchBuf, c_szRegSpellProfile, ARRAYSIZE(rgchBuf));
|
|
StrCatBuff(rgchBuf, c_szRegSpellKeyCustom, ARRAYSIZE(rgchBuf));
|
|
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, rgchBuf, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
do
|
|
{
|
|
cchValue = sizeof(szValue) / sizeof(szValue[0]);
|
|
cchCustDict = sizeof(szCustDict) / sizeof(szCustDict[0]);
|
|
|
|
lRet = RegEnumValue(hkey,
|
|
iKey++,
|
|
szValue,
|
|
&cchValue,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szCustDict,
|
|
&cchCustDict);
|
|
|
|
if (lRet != ERROR_SUCCESS || lRet == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
|
|
fFoundUserDict = TRUE;
|
|
|
|
fContinue = (*pfn)(dwCookie, szCustDict);
|
|
|
|
} while (fContinue);
|
|
}
|
|
|
|
if (hkey)
|
|
RegCloseKey(hkey);
|
|
|
|
return fFoundUserDict;
|
|
}
|
|
|
|
VOID EnumUserDictionaries(DWORD_PTR dwCookie, LPFNENUMUSERDICT pfn)
|
|
{
|
|
// check for Office9 user dictionaries. If we find any
|
|
// we bail.
|
|
if (EnumOffice9UserDictionaries(dwCookie, pfn))
|
|
return;
|
|
|
|
EnumOfficeUserDictionaries(dwCookie, pfn);
|
|
}
|
|
|
|
BOOL GetDefaultUserDictionary(TCHAR *rgchUserDict, int cchBuff)
|
|
{
|
|
DWORD dwType;
|
|
DWORD cchUserDict;
|
|
HKEY hkey = NULL;
|
|
BOOL fFound = FALSE;
|
|
|
|
if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegSharedTools, 0, KEY_QUERY_VALUE, &hkey))
|
|
{
|
|
cchUserDict = cchBuff;
|
|
|
|
if (SHQueryValueEx(hkey, c_szRegSharedToolsPath, 0L, &dwType, rgchUserDict, &cchUserDict) == ERROR_SUCCESS)
|
|
{
|
|
StrCatBuff(rgchUserDict, c_szRegDefCustomDict, cchBuff);
|
|
|
|
fFound = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
// if we where able to create a path to the user dict store it in the regdb
|
|
if (fFound)
|
|
{
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
|
|
StrCpyN(rgchBuf, c_szRegSpellProfile, ARRAYSIZE(rgchBuf));
|
|
StrCatBuff(rgchBuf, c_szRegSpellKeyCustom, ARRAYSIZE(rgchBuf));
|
|
|
|
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, rgchBuf, 0, rgchBuf, REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(hkey, c_szRegSpellPathDict, 0, REG_SZ, (BYTE *)rgchUserDict, (lstrlen(rgchUserDict) + 1) * sizeof(TCHAR));
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
return fFound;
|
|
}
|
|
|
|
BOOL EnumUserDictCallback(DWORD_PTR dwCookie, LPTSTR lpszDict)
|
|
{
|
|
STRING_AND_SIZE * pStringAndSize = (STRING_AND_SIZE *) dwCookie;
|
|
|
|
if (pStringAndSize && pStringAndSize->pszString)
|
|
{
|
|
StrCpyN(pStringAndSize->pszString, lpszDict, pStringAndSize->cchSize);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GetDefUserDictionaries(LPTSTR lpszDict, DWORD cchDict)
|
|
{
|
|
STRING_AND_SIZE stringAndSize;
|
|
|
|
stringAndSize.pszString = lpszDict;
|
|
stringAndSize.cchSize = cchDict;
|
|
|
|
lpszDict[0] = 0;
|
|
|
|
EnumUserDictionaries((DWORD_PTR)&stringAndSize, EnumUserDictCallback);
|
|
|
|
if (strlen(lpszDict))
|
|
return TRUE;
|
|
|
|
if (GetDefaultUserDictionary(lpszDict, cchDict))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID OpenCustomDictionary(VOID)
|
|
{
|
|
HKEY hkey = NULL;
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
DWORD cbData = 0;
|
|
DWORD dwType;
|
|
|
|
// Verify that .DIC files can be handled:
|
|
rgchBuf[0] = '\0';
|
|
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, c_szRegDICHandlerKEY, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (hkey)
|
|
{
|
|
SHQueryValueEx(hkey, NULL, 0L, &dwType, (BYTE *) rgchBuf, &cbData);
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
if (cbData == 0 || !rgchBuf[0])
|
|
{
|
|
if (RegCreateKeyEx(HKEY_CLASSES_ROOT,
|
|
c_szRegDICHandlerKEY,
|
|
0,
|
|
rgchBuf,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
0,
|
|
&hkey,
|
|
NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (hkey)
|
|
{
|
|
RegSetValueEx(hkey, NULL, 0L, REG_SZ, (BYTE *) c_szRegDICHandlerDefault, (lstrlen(c_szRegDICHandlerDefault) + 1) * sizeof(TCHAR));
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetDefUserDictionaries(rgchBuf, sizeof(rgchBuf)/sizeof(TCHAR)))
|
|
{
|
|
// make sure our directory exists
|
|
{
|
|
TCHAR rgchDictDir[MAX_PATH];
|
|
|
|
StrCpyN(rgchDictDir, rgchBuf, ARRAYSIZE(rgchDictDir));
|
|
|
|
PathRemoveFileSpec(rgchDictDir);
|
|
OpenDirectory(rgchDictDir);
|
|
}
|
|
|
|
// now make sure the file exists
|
|
// if it does not create it
|
|
{
|
|
HANDLE hFile;
|
|
|
|
hFile = CreateFile(rgchBuf, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
{
|
|
SHELLEXECUTEINFO see;
|
|
ZeroMemory(&see, sizeof(SHELLEXECUTEINFO));
|
|
|
|
see.cbSize = sizeof(see);
|
|
see.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
see.lpFile = rgchBuf;
|
|
see.nShow = SW_SHOWNORMAL;
|
|
|
|
if (ShellExecuteEx(&see))
|
|
{
|
|
Assert(see.hProcess);
|
|
WaitForInputIdle(see.hProcess, 20000);
|
|
CloseHandle(see.hProcess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL FBadSpellChecker(LPSTR rgchBufDigit)
|
|
{
|
|
TCHAR rgchBufKey[cchMaxPathName];
|
|
TCHAR rgchBuf[cchMaxPathName];
|
|
TCHAR szMdr[cchMaxPathName];
|
|
LPSTR pszSpell;
|
|
|
|
wnsprintf(rgchBufKey, ARRAYSIZE(rgchBufKey), c_szRegSpellKeyDef, rgchBufDigit);
|
|
|
|
if (!GetSpellingPaths(rgchBufKey, rgchBuf, szMdr, sizeof(rgchBuf)/sizeof(TCHAR)))
|
|
return TRUE;
|
|
|
|
pszSpell = PathFindFileNameA(rgchBuf);
|
|
if (!pszSpell)
|
|
return TRUE;
|
|
|
|
if (lstrcmpi(pszSpell, "msspell.dll")==0 ||
|
|
lstrcmpi(pszSpell, "mssp32.dll")==0)
|
|
return TRUE;
|
|
|
|
// [email protected] - check that the dict exists (also check the spell dll
|
|
// for good measure) - 40081
|
|
|
|
// spell dll must exist
|
|
if (!PathFileExists(rgchBuf))
|
|
return TRUE;
|
|
|
|
// main dict must exist
|
|
if (!PathFileExists(szMdr))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|