Leaked source code of windows server 2003
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

/*
* 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;
}