|
|
/*
* spell.c * * Implementation of spelling * * Owner: v-brakol * bradk@directeq.com */ #include "pch.hxx"
#include "richedit.h"
#include "resource.h"
#include "util.h"
#include <mshtml.h>
#include <mshtmcid.h>
#include "mshtmhst.h"
#include "mshtmdid.h"
#include <docobj.h>
#include "spell.h"
#include "strconst.h"
#include "bodyutil.h"
#include <error.h>
#include "htmlstr.h"
#include "dllmain.h"
#include "msi.h"
#include "lid.h"
#include "demand.h"
typedef struct { LPTSTR pszString; DWORD cchSize; } STRING_AND_SIZE;
#define GetAddr(var, cast, name) {if ((var = (cast)GetProcAddress(m_hinstDll, name)) == NULL) \
goto error;}
#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}"
#define CSAPI3T1_GUID "{CC29EB41-7BC2-11D1-A921-00A0C91E2AA2}"
#ifdef DEBUG
#define SPELLER_DEBUG_GUID "{CC29EB3F-7BC2-11D1-A921-10A0C91E2AA2}"
#define DICTIONARY_DEBUG_GUID "{CC29EB3D-7BC2-11D1-A921-10A0C91E2AA2}"
#define CSAPI3T1_DEBUG_GUID "{CC29EB41-7BC2-11D1-A921-10A0C91E2AA2}"
#endif // DEBUG
#define MAX_SPELLWORDS 10
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 TestLangID(LPCTSTR szLangId); BOOL GetLangID(IOleCommandTarget* pParentCmdTarget, LPTSTR szLangID, DWORD cchLangId); WORD WGetLangID(IOleCommandTarget* pParentCmdTarget); DWORD GetSpellingPaths(LPCTSTR szKey, LPTSTR szReturnBuffer, LPTSTR szMdr, UINT cchReturnBufer); VOID EnumLanguages(DWORD_PTR, LPFNENUMLANG); BOOL FindLangCallback(DWORD_PTR dwLangId, LPTSTR lpszLang); void RemoveTrailingSpace(LPTSTR lpszWord); void DumpRange(IHTMLTxtRange *pRange); BOOL FBadSpellChecker(LPSTR rgchBufDigit); void EnableRepeatedWindows(CSpell* pSpell, HWND hwndDlg); BOOL GetNewSpellerEngine(LANGID lgid, TCHAR *rgchEngine, DWORD cchEngine, TCHAR *rgchLex, DWORD cchLex, BOOL bTestAvail); VOID EnumUserDictionaries(DWORD_PTR dwCookie, LPFNENUMUSERDICT pfn); BOOL GetDefaultUserDictionary(TCHAR *rgchUserDict, int cchBuff); WORD GetWCharType(WCHAR wc); HRESULT OpenDirectory(TCHAR *szDir);
BOOL TestLangID(LPCTSTR pszLangId) { // 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((USHORT) StrToInt(pszLangId), 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, pszLangId); if (GetSpellingPaths(rgchBufKeyTest, rgchBufTest, szMdr, sizeof(rgchBufTest)/sizeof(TCHAR))) return TRUE; }
return FALSE; }
/*
* GetSpellLangID * * Returns the LangID that should be used as the base for all registry * operations * */ BOOL GetLangID(IOleCommandTarget* pParentCmdTarget, LPTSTR pszLangId, DWORD cchLangId) { TCHAR rgchBuf[cchMaxPathName]; TCHAR rgchBufKey[cchMaxPathName]; BOOL fRet; VARIANT va;
pszLangId[0] = 0;
Assert(pParentCmdTarget); if (pParentCmdTarget && pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SPELL_LANGUAGE, 0, NULL, &va)== S_OK) { TCHAR rgchLangId[cchMaxPathName];
if (WideCharToMultiByte (CP_ACP, 0, va.bstrVal, -1, rgchLangId, sizeof(rgchLangId), NULL, NULL)) { StrCpyN(pszLangId, rgchLangId, cchLangId); }
SysFreeString(va.bstrVal); } if (*pszLangId == 0) { wnsprintf(pszLangId, cchLangId, "%d", GetUserDefaultLangID()); Assert(lstrlen(pszLangId) == 4); }
wnsprintf(rgchBufKey, ARRAYSIZE(rgchBufKey), c_szRegSpellKeyDef, pszLangId); // 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(pszLangId))) { // couldn't open it!
// check for other languages that might be installed...
STRING_AND_SIZE stringAndSize;
stringAndSize.pszString = pszLangId; stringAndSize.cchSize = cchLangId;
pszLangId[0] = 0; EnumLanguages((DWORD_PTR) &stringAndSize, FindLangCallback); if(*pszLangId == 0) wnsprintf(pszLangId, cchLangId, TEXT("%d"), GetUserDefaultLangID()); }
fRet = (pszLangId[0] != 0) && TestLangID(pszLangId);
return fRet; }
WORD WGetLangID(IOleCommandTarget* pParentCmdTarget) { TCHAR rgchBufDigit[10]; if (!GetLangID(pParentCmdTarget, rgchBufDigit, sizeof(rgchBufDigit)/sizeof(TCHAR))) return GetUserDefaultLangID();
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;
// [email protected] - changed KEY_QUERY_VALUE to KEY_ENUMERATE_SUB_KEYS - 26203
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) { EnumNewSpellerLanguages(dwCookie, pfn); EnumOldSpellerLanguages(dwCookie, pfn); }
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); else { // if the Shell call fails (as it can on Win9x sometimes) let's get the info
// from the registry
HKEY hKeyShellFolders; ULONG cchAppData; if(RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegShellFoldersKey, 0, KEY_QUERY_VALUE, &hKeyShellFolders) == ERROR_SUCCESS) { cchAppData = ARRAYSIZE(szOffice9Proof); RegQueryValueEx(hKeyShellFolders, c_szValueAppData, 0, NULL, (LPBYTE)szOffice9Proof, &cchAppData); RegCloseKey(hKeyShellFolders); } }
// if this fails then we will try the current path
}
StrCpyN(szTemp, szOffice9Proof, ARRAYSIZE(szTemp)); StrCatBuff(szTemp, "\\", ARRAYSIZE(szTemp)); StrCatBuff(szTemp, c_szSpellOffice9ProofPath, ARRAYSIZE(szTemp)); 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); }
/*
* 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; StrCpyN(rgchBuf, c_szRegSpellProfile, ARRAYSIZE(rgchBuf)); StrCatBuff(rgchBuf, szKey, ARRAYSIZE(rgchBuf));
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; }
/*
* SpellingDlgProc * * Purpose: * Dialog procedure for the Tools.Spelling dialog * * Arguments: * HWND Dialog procedure arguments. * UINT * WPARAM * LPARAM * * Returns: * BOOL TRUE if the message has been processed. */ INT_PTR CALLBACK SpellingDlgProc(HWND hwndDlg, UINT wMsg, WPARAM wparam, LPARAM lparam) { CSpell* pSpell; HWND hwndEdited; HWND hwndSuggest;
switch (wMsg) { case WM_INITDIALOG: SetWindowLongPtr(hwndDlg, DWLP_USER, lparam); pSpell = (CSpell*)lparam; pSpell->m_hwndDlg = hwndDlg;
hwndEdited = GetDlgItem(hwndDlg, EDT_Spell_ChangeTo); hwndSuggest = GetDlgItem(hwndDlg, LBX_Spell_Suggest);
pSpell->m_fEditWasEmpty = TRUE; SetDlgItemText(hwndDlg, TXT_Spell_Error, pSpell->m_szErrType); SetDlgItemText(hwndDlg, EDT_Spell_WrongWord, pSpell->m_szWrongWord); SetWindowText(hwndEdited, pSpell->m_szEdited);
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Options), FALSE); EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Add), (0 != pSpell->m_rgprflex[1])); pSpell->m_fRepeat = (pSpell->m_wsrb.sstat == sstatRepeatWord); EnableRepeatedWindows(pSpell, hwndDlg);
if (!pSpell->m_fRepeat) pSpell->FillSuggestLbx(); else ListBox_ResetContent(GetDlgItem(hwndDlg, LBX_Spell_Suggest));
if (pSpell->m_fSuggestions && !pSpell->m_fNoneSuggested && !pSpell->m_fRepeat) { EnableWindow(hwndSuggest, TRUE); ListBox_SetCurSel(hwndSuggest, 0); UpdateEditedFromSuggest(hwndDlg, hwndEdited, hwndSuggest); EnableWindow(GetDlgItem(hwndDlg, TXT_Spell_Suggest), TRUE);
// Set initial default button to "Change"
SendMessage(hwndDlg, DM_SETDEFID, PSB_Spell_Change, 0L); Button_SetStyle(GetDlgItem(hwndDlg, PSB_Spell_Change), BS_DEFPUSHBUTTON, TRUE);
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Suggest), FALSE); } else { Edit_SetSel(hwndEdited, 0, 32767); // select the whole thing
EnableWindow(hwndSuggest, FALSE); EnableWindow(GetDlgItem(hwndDlg, TXT_Spell_Suggest), FALSE);
// Set initial default button to "Ignore"
SendMessage(hwndDlg, DM_SETDEFID, PSB_Spell_Ignore, 0L); Button_SetStyle(GetDlgItem(hwndDlg, PSB_Spell_Ignore), BS_DEFPUSHBUTTON, TRUE);
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Suggest), !pSpell->m_fSuggestions && !pSpell->m_fRepeat); }
AthFixDialogFonts(hwndDlg); SetFocus(hwndEdited); break;
case WM_DESTROY: break;
case WM_COMMAND: return SpellingOnCommand(hwndDlg, wMsg, wparam, lparam);
}
return FALSE; }
void EnableRepeatedWindows(CSpell* pSpell, HWND hwndDlg) { INT ids;
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Add), (!pSpell->m_fRepeat && (0 != pSpell->m_rgprflex[1]))); EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_IgnoreAll), !pSpell->m_fRepeat); EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_ChangeAll), !pSpell->m_fRepeat); if (pSpell->m_fRepeat) { SetWindowText(GetDlgItem(hwndDlg, EDT_Spell_ChangeTo), ""); *pSpell->m_szEdited = 0; }
}
BOOL SpellingOnCommand(HWND hwndDlg, UINT wMsg, WPARAM wparam, LPARAM lparam) { CSpell* pSpell; BOOL fChange; BOOL fAlwaysSuggest; BOOL fUndoing = FALSE; HRESULT hr = 0;
pSpell = (CSpell*) GetWindowLongPtr(hwndDlg, DWLP_USER); Assert(pSpell);
// Update our replacement word? Only do this when a button is clicked
// or a double-click from the suggest listbox, and the word has been modified.
if ((GET_WM_COMMAND_CMD(wparam, lparam) == BN_CLICKED || GET_WM_COMMAND_CMD(wparam, lparam) == LBN_DBLCLK) && Edit_GetModify(GetDlgItem(hwndDlg, EDT_Spell_ChangeTo))) { HWND hwndEditChangeTo;
hwndEditChangeTo = GetDlgItem(pSpell->m_hwndDlg, EDT_Spell_ChangeTo); Edit_SetModify(hwndEditChangeTo, FALSE); pSpell->m_fSuggestions = FALSE; GetWindowText(hwndEditChangeTo, pSpell->m_szEdited, 512); }
switch(GET_WM_COMMAND_ID(wparam, lparam)) { case LBX_Spell_Suggest: if (GET_WM_COMMAND_CMD(wparam, lparam) == LBN_SELCHANGE) { UpdateEditedFromSuggest(hwndDlg, GetDlgItem(hwndDlg, EDT_Spell_ChangeTo), GetDlgItem(hwndDlg, LBX_Spell_Suggest)); return TRUE; } else if (GET_WM_COMMAND_CMD(wparam, lparam) == LBN_DBLCLK) { goto ChangeIt; } else { return FALSE; }
case EDT_Spell_ChangeTo: if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) { INT idClearDefault; INT idSetDefault; BOOL fEditModified;
// We get EN_CHANGE notifications for both a SetWindowText() and user modifications.
// Look at the dirty flag (only set on user mods) and the state of the suggestions
// selection to see which button should get the default style.
fEditModified = Edit_GetModify(GET_WM_COMMAND_HWND(wparam, lparam)); if (fEditModified || pSpell->m_fSuggestions && !pSpell->m_fNoneSuggested) { idClearDefault = PSB_Spell_Ignore; idSetDefault = PSB_Spell_Change; } else { idClearDefault = PSB_Spell_Change; idSetDefault = PSB_Spell_Ignore; }
// Enable/disable Suggest button
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Suggest), fEditModified);
// Set default button
Button_SetStyle(GetDlgItem(hwndDlg, idClearDefault), BS_PUSHBUTTON, TRUE); SendMessage(hwndDlg, DM_SETDEFID, idSetDefault, 0L); Button_SetStyle(GetDlgItem(hwndDlg, idSetDefault), BS_DEFPUSHBUTTON, TRUE);
// "Change" button title
if (GetWindowTextLength(GET_WM_COMMAND_HWND(wparam, lparam)) && pSpell->m_fEditWasEmpty) { pSpell->m_fEditWasEmpty = FALSE; LoadString(g_hLocRes, idsSpellChange, pSpell->m_szTempBuffer, sizeof(pSpell->m_szTempBuffer)/sizeof(TCHAR)); SetDlgItemText(hwndDlg, PSB_Spell_Change, pSpell->m_szTempBuffer); LoadString(g_hLocRes, idsSpellChangeAll, pSpell->m_szTempBuffer, sizeof(pSpell->m_szTempBuffer)/sizeof(TCHAR)); SetDlgItemText(hwndDlg, PSB_Spell_ChangeAll, pSpell->m_szTempBuffer); } else if (GetWindowTextLength(GET_WM_COMMAND_HWND(wparam, lparam)) == 0) { pSpell->m_fEditWasEmpty = TRUE; LoadString(g_hLocRes, idsSpellDelete, pSpell->m_szTempBuffer, sizeof(pSpell->m_szTempBuffer)/sizeof(TCHAR)); SetDlgItemText(hwndDlg, PSB_Spell_Change, pSpell->m_szTempBuffer); LoadString(g_hLocRes, idsSpellDeleteAll, pSpell->m_szTempBuffer, sizeof(pSpell->m_szTempBuffer)/sizeof(TCHAR)); SetDlgItemText(hwndDlg, PSB_Spell_ChangeAll, pSpell->m_szTempBuffer); } } return TRUE;
case PSB_Spell_IgnoreAll: { PROOFLEX lexIgnoreAll;
lexIgnoreAll = pSpell->m_pfnSpellerBuiltInUdr(pSpell->m_pid, lxtIgnoreAlways); if (0 != lexIgnoreAll) { RemoveTrailingSpace(pSpell->m_szWrongWord); pSpell->AddToUdrA(pSpell->m_szWrongWord, lexIgnoreAll); pSpell->m_fCanUndo = FALSE; } } // [email protected] - remove the annoying dialog and just break out of here - 34229
break;
case PSB_Spell_Ignore: // Due to limitations with the spelling engine and our single undo level,
// we can't allow undo's of Ignore if the error was a Repeated Word.
if (pSpell->m_wsrb.sstat == sstatRepeatWord) pSpell->m_fCanUndo = FALSE; else pSpell->SpellSaveUndo(PSB_Spell_Ignore);
// [email protected] - remove the annoying dialog and just break out of here - 34229
break;
case PSB_Spell_ChangeAll: if (pSpell->FVerifyThisText(pSpell->m_szEdited, FALSE)) { pSpell->m_fCanUndo = FALSE; hr = pSpell->HrReplaceErrorText(TRUE, TRUE); break; } else { return TRUE; }
case PSB_Spell_Change: ChangeIt: if (pSpell->FVerifyThisText(pSpell->m_szEdited, FALSE)) { pSpell->m_fUndoChange = TRUE; pSpell->SpellSaveUndo(PSB_Spell_Change); hr = pSpell->HrReplaceErrorText(FALSE, TRUE); break; } else { return TRUE; }
case PSB_Spell_Add: Assert(pSpell->m_rgprflex[1]); pSpell->m_fCanUndo = FALSE; fChange = FALSE; RemoveTrailingSpace(pSpell->m_szWrongWord); // [email protected] - removed the FVerifyThisText that was here - no need
// to FVerifyThisText if the user is asking us to Add this word - fixes 55587
pSpell->AddToUdrA(pSpell->m_szWrongWord, pSpell->m_rgprflex[1]); if (fChange) hr = pSpell->HrReplaceErrorText(FALSE, TRUE); break;
case PSB_Spell_UndoLast: pSpell->SpellDoUndo(); fUndoing = TRUE; break;
case PSB_Spell_Suggest: hr = pSpell->HrSpellSuggest(); if (FAILED(hr)) goto bail; goto loadcache;
case IDCANCEL: pSpell->m_fShowDoneMsg = FALSE; EndDialog(hwndDlg, IDCANCEL); return TRUE;
default: return FALSE; }
// If no current error, then proceed with checking the rest
if (SUCCEEDED(hr)) { // Change "Cancel" button to "Close"
LoadString(g_hLocRes, idsSpellClose, pSpell->m_szTempBuffer, sizeof(pSpell->m_szTempBuffer)/sizeof(TCHAR)); SetDlgItemText(hwndDlg, IDCANCEL, pSpell->m_szTempBuffer);
pSpell->m_wsrb.sstat = sstatNoErrors; hr = pSpell->HrFindErrors(); if(FAILED(hr)) goto bail;
if(pSpell->m_wsrb.sstat==sstatNoErrors) { EndDialog(hwndDlg, GET_WM_COMMAND_ID(wparam, lparam)); return TRUE; }
}
bail: if(FAILED(hr)) { EndDialog(hwndDlg, IDCANCEL); return TRUE; }
SetDlgItemText(hwndDlg, EDT_Spell_WrongWord, pSpell->m_szWrongWord); SetDlgItemText(hwndDlg, TXT_Spell_Error, pSpell->m_szErrType); SetDlgItemText(hwndDlg, EDT_Spell_ChangeTo, pSpell->m_szEdited);
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_UndoLast), pSpell->m_fCanUndo); EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Add), (0 != pSpell->m_rgprflex[1]));
pSpell->m_fRepeat = (pSpell->m_wsrb.sstat == sstatRepeatWord); EnableRepeatedWindows(pSpell, hwndDlg);
loadcache: if (!pSpell->m_fRepeat) pSpell->FillSuggestLbx(); else ListBox_ResetContent(GetDlgItem(hwndDlg, LBX_Spell_Suggest));
EnableWindow(GetDlgItem(hwndDlg, PSB_Spell_Suggest), !pSpell->m_fSuggestions && !pSpell->m_fRepeat); if (pSpell->m_fSuggestions && !pSpell->m_fNoneSuggested && !pSpell->m_fRepeat) { EnableWindow(GetDlgItem(hwndDlg, TXT_Spell_Suggest), TRUE); EnableWindow(GetDlgItem(hwndDlg, LBX_Spell_Suggest), TRUE); ListBox_SetCurSel(GetDlgItem(hwndDlg, LBX_Spell_Suggest), 0); UpdateEditedFromSuggest(hwndDlg, GetDlgItem(hwndDlg, EDT_Spell_ChangeTo), GetDlgItem(hwndDlg, LBX_Spell_Suggest)); } else { EnableWindow(GetDlgItem(hwndDlg, TXT_Spell_Suggest), FALSE); EnableWindow(GetDlgItem(hwndDlg, LBX_Spell_Suggest), FALSE); }
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, EDT_Spell_ChangeTo), MAKELONG(TRUE,0));
return TRUE; }
void RemoveTrailingSpace(LPTSTR lpszWord) { LPTSTR lpsz;
lpsz = StrChrI(lpszWord, ' '); if(lpsz) *lpsz = 0; }
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 has main lex in new speller
for (i = 0; i < cDictTypes; i++) { int nDictionaryIndex = (int)min(i, ARRAYSIZE(rgpszDictionaryTypes)-1); wnsprintf(rgchQual, ARRAYSIZE(rgchQual), "%d\\%s", lgid, rgpszDictionaryTypes[nDictionaryIndex]); 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; } }
errorExit: if (bTestAvail) { // Restore original UI Level
MsiSetInternalUI(iuilOriginal, NULL); } return fFound; }
BOOL FIsNewSpellerInstaller(IOleCommandTarget* pParentCmdTarget) { 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(pParentCmdTarget); 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; }
// [email protected] - copied from "old" spell code - 32675
/*
* FIsSpellingInstalled * * Purpose: * Is the spelling stuff installed * * Arguments: * none * * Returns: * BOOL Returns TRUE if spelling is installed, else FALSE. */ BOOL FIsSpellingInstalled(IOleCommandTarget* pParentCmdTarget) { TCHAR rgchBufDigit[10];
if (GetLangID(pParentCmdTarget, rgchBufDigit, sizeof(rgchBufDigit)/sizeof(TCHAR)) && !FBadSpellChecker(rgchBufDigit)) return true;
if (FIsNewSpellerInstaller(pParentCmdTarget)) return true;
return false; }
// Does a quick check to see if spelling is available; caches result.
BOOL FCheckSpellAvail(IOleCommandTarget* pParentCmdTarget) { // [email protected] - copied from "old" spell code - 32675
static int fSpellAvailable = -1;
if (fSpellAvailable < 0) fSpellAvailable = (FIsSpellingInstalled(pParentCmdTarget) ? 1 : 0);
return (fSpellAvailable > 0); }
HRESULT CSpell::HrSpellReset() { m_fSpellContinue = FALSE;
return NOERROR; }
/*
* UlNoteCmdToolsSpelling * * Purpose: * An interface layer between the note and core spelling code * * Arguments: * HWND Owning window handle, main window * HWND Subject line window, checked first, actually. * BOOL Suppress done message (used when spell-check on send) * * Returns: * ULONG Returns 0 if spelling check was completed, else returns non-zero * if an error occurred or user cancelled the spell check. */ HRESULT CSpell::HrSpellChecking(IHTMLTxtRange *pRangeIgnore, HWND hwndMain, BOOL fSuppressDoneMsg) { HRESULT hr = NOERROR;
hr = HrSpellReset(); if (FAILED(hr)) goto End;
hr = HrInitRanges(pRangeIgnore, hwndMain, fSuppressDoneMsg); if(FAILED(hr)) goto End;
hr = HrFindErrors(); if(FAILED(hr)) goto End;
if(m_wsrb.sstat==sstatNoErrors && m_fShowDoneMsg) AthMessageBoxW(m_hwndNote, MAKEINTRESOURCEW(idsSpellCaption), MAKEINTRESOURCEW(idsSpellMsgDone), NULL, MB_OK | MB_ICONINFORMATION);
End: DeInitRanges();
return hr; }
#ifdef BACKGROUNDSPELL
HRESULT CSpell::HrBkgrndSpellTimer() { HRESULT hr=NOERROR; LONG cSpellWords = 0; IHTMLTxtRange *pTxtRange=0; LONG cb; VARIANT_BOOL fSuccess;
if (m_Stack.fEmpty()) goto error;
while (!(m_Stack.fEmpty()) && cSpellWords <= MAX_SPELLWORDS) { m_Stack.HrGetRange(&pTxtRange); if (pTxtRange) { while(cSpellWords <= MAX_SPELLWORDS) { pTxtRange->collapse(VARIANT_TRUE); if (SUCCEEDED(pTxtRange->expand((BSTR)c_bstr_Word, &fSuccess)) && fSuccess==VARIANT_TRUE) { HrBkgrndSpellCheck(pTxtRange); cSpellWords++; } else { m_Stack.pop(); SafeRelease(pTxtRange); break; }
cb=0; if (FAILED(pTxtRange->moveStart((BSTR)c_bstr_Word, 1, &cb)) || cb!=1) { m_Stack.pop(); SafeRelease(pTxtRange); break; } }
} }
error: SafeRelease(pTxtRange); return hr; } #endif // BACKGROUNDSPELL
#ifdef BACKGROUNDSPELL
HRESULT CSpell::HrBkgrndSpellCheck(IHTMLTxtRange *pTxtRange) { HRESULT hr = NOERROR; LPSTR pszText = 0; VARIANT_BOOL fSuccess;
hr = pTxtRange->expand((BSTR)c_bstr_Word, &fSuccess); if(FAILED(hr)) goto error;
hr = HrGetText(pTxtRange, &pszText); if(FAILED(hr)) goto error; if (hr == HR_S_SPELLCONTINUE) goto error;
StripNBSPs(pszText);
// ignore words with wildcards
if (StrChr(pszText, '*')) goto error;
RemoveTrailingSpace(pszText); hr = HrCheckWord(pszText); if(FAILED(hr)) goto error;
if(m_wsrb.sstat!=sstatNoErrors && m_wsrb.sstat!=sstatRepeatWord) //found an error.
{ // FIgnore should take pTxtRange as the parameter.
if(FIgnore(pTxtRange)) { m_wsrb.sstat = sstatNoErrors; goto error; }
if (HrHasSquiggle(pTxtRange)==S_OK) { DebugTrace("Spell: Bad word %s\n", pszText); goto error; }
//put red squiggle
HrSetSquiggle(pTxtRange);
} else //if the wrong word is corrected, delete <U> tag.
{ if (HrHasSquiggle(pTxtRange)==S_OK) HrDeleteSquiggle(pTxtRange);
}
error: SafeMemFree(pszText); return hr; } #endif // BACKGROUNDSPELL
#ifdef BACKGROUNDSPELL
//const static CHAR c_szSquiggleFmt[] = "<U style='color:red'>%s</U>";
const static CHAR c_szSquiggleFmt[] = "<SPAN class=badspelling STYLE='text-decoration:underline;color:red'>%s</SPAN>"; HRESULT CSpell::HrSetSquiggle(IHTMLTxtRange *pTxtRange) { CHAR szBuf[MAX_PATH]={0}; BSTR bstr=0; HRESULT hr=NOERROR; LPSTR pszText=0; INT nSpaces=0; int i;
hr = HrGetText(pTxtRange, &pszText); if(FAILED(hr)) goto error; if (hr == HR_S_SPELLCONTINUE) goto error; hr = HrGetSpaces(pszText, &nSpaces); if(FAILED(hr)) goto error; RemoveTrailingSpace(pszText); wnsprintf(szBuf, ARRAYSIZE(szBuf), c_szSquiggleFmt, pszText); for(i=0; i<(nSpaces-1); i++) StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf)); if (nSpaces>0) StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf));
HrLPSZToBSTR(szBuf, &bstr); hr = pTxtRange->pasteHTML(bstr); if(FAILED(hr)) goto error;
error: SafeSysFreeString(bstr); SafeMemFree(pszText); return hr; } #endif // BACKGROUNDSPELL
#ifdef BACKGROUNDSPELL
HRESULT CSpell::HrDeleteSquiggle(IHTMLTxtRange *pTxtRange) { CHAR szBuf[MAX_PATH]={0}; BSTR bstr=0; HRESULT hr=NOERROR; LPSTR pszText=0; INT nSpaces=0; int i;
hr = HrGetText(pTxtRange, &pszText); if(FAILED(hr)) goto error; if (hr == HR_S_SPELLCONTINUE) goto error; hr = HrGetSpaces(pszText, &nSpaces); if(FAILED(hr)) goto error;
StrCpyN(szBuf, pszText, ARRAYSIZE(szBuf)); for(i=0; i<(nSpaces-1); i++) StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf)); if (nSpaces>0) StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf)); HrLPSZToBSTR(szBuf, &bstr); hr = pTxtRange->pasteHTML(bstr); if(FAILED(hr)) goto error;
error: SafeSysFreeString(bstr); SafeMemFree(pszText); return hr; } #endif // BACKGROUNDSPELL
HRESULT CSpell::HrGetSpaces(LPSTR pszText, INT* pnSpaces) { LPSTR p; *pnSpaces = 0; p = StrChrI(pszText, ' '); if(p) { *pnSpaces = (INT) (&pszText[lstrlen(pszText)] - p); Assert(*pnSpaces>=0); } return NOERROR; }
HRESULT CSpell::HrInsertMenu(HMENU hmenu, IHTMLTxtRange *pTxtRange) { LPSTR pch=0; LPSTR pszText=0; INT index=0; HRESULT hr; VARIANT_BOOL fSuccess;
hr = pTxtRange->expand((BSTR)c_bstr_Word, &fSuccess); if(FAILED(hr)) goto error;
hr = HrGetText(pTxtRange, &pszText); if(FAILED(hr)) goto error; if (pszText==NULL || *pszText=='\0') { hr = E_FAIL; goto error; } StrCpyN(m_szEdited, pszText, ARRAYSIZE(m_szEdited)); HrSpellSuggest(); pch = m_szSuggest; if (*pch == '\0') { LoadString(g_hLocRes, idsSpellNoSuggestions, m_szTempBuffer, sizeof(m_szTempBuffer)/sizeof(TCHAR)); InsertMenu(hmenu, (UINT)0, MF_BYPOSITION|MF_STRING, idmSuggest0, m_szTempBuffer); EnableMenuItem(hmenu, idmSuggest0, MF_BYCOMMAND|MF_GRAYED); //ListBox_AddString(hwndLbx, m_szTempBuffer);
} else { while(*pch != '\0' && index<5) { InsertMenu(hmenu, (UINT)index, MF_BYPOSITION|MF_STRING, idmSuggest0 + index, pch); index++; //ListBox_AddString(hwndLbx, pch);
while(*pch != '\0') pch++; pch++; } }
error: SafeMemFree(pszText); return hr; }
const static TCHAR c_szFmt[] = "%s%s"; HRESULT CSpell::HrReplaceBySuggest(IHTMLTxtRange *pTxtRange, INT index) { CHAR szBuf[MAX_PATH] = {0}; BSTR bstr=0; BSTR bstrPut=0; LPSTR pch=0; INT i=0; HRESULT hr;
pch = m_szSuggest; while(*pch != '\0' && i<5) { if (index == i) { StrCpyN(szBuf, pch, ARRAYSIZE(szBuf));
if (SUCCEEDED(pTxtRange->get_text(&bstr)) && bstr) { LPSTR pszText = 0; if (SUCCEEDED(HrBSTRToLPSZ(CP_ACP, bstr, &pszText)) && pszText) { LPSTR psz; INT nSpaces=0; psz = StrChrI(pszText, ' '); if(psz) { nSpaces = (INT) (&pszText[lstrlen(pszText)] - psz); Assert(nSpaces>=0); for(int i=0; i<(nSpaces-1); i++) StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf)); if (nSpaces>0) StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf)); } hr = HrLPSZToBSTR(szBuf, &bstrPut);
SafeMemFree(pszText); } SafeSysFreeString(bstr); } if (bstrPut) { pTxtRange->pasteHTML(bstrPut); SafeSysFreeString(bstrPut); } break; } i++; while(*pch != '\0') pch++; pch++; }
return NOERROR; }
HRESULT CSpell::HrFindErrors() { HRESULT hr = NOERROR;
if(m_State == SEL) { hr = HrCheckRange(m_pRangeSelExpand); // if hr==HR_S_ABORT, quit so as to pass control to dialog procedure which calls HrFindErrors.
if(TESTHR(hr)) goto error;
if(AthMessageBoxW(m_hwndDlg ? m_hwndDlg : m_hwndNote, MAKEINTRESOURCEW(idsSpellCaption), MAKEINTRESOURCEW(idsSpellMsgContinue), NULL, MB_YESNO | MB_ICONEXCLAMATION ) != IDYES) { m_fShowDoneMsg = FALSE; goto error; }
CleanupState(); }
if(m_State == SELENDDOCEND) { DumpRange(m_pRangeSelEndDocEnd); m_fIgnoreScope = TRUE; hr = HrCheckRange(m_pRangeSelEndDocEnd); m_fIgnoreScope = FALSE; if(TESTHR(hr)) goto error;
CleanupState();
hr = HrSpellReset(); if (FAILED(hr)) goto error; }
if(m_State == DOCSTARTSELSTART) { hr = HrCheckRange(m_pRangeDocStartSelStart); if(TESTHR(hr)) goto error;
CleanupState(); }
error: // save the hr so as to know if something went wrong when dialog procedure calls HrFindErrors.
m_hr = hr; return hr; }
VOID CSpell::CleanupState() { m_State++; SafeRelease(m_pRangeChecking); }
HRESULT CSpell::HrCheckRange(IHTMLTxtRange* pRange) { HRESULT hr = NOERROR; INT_PTR nCode; LPSTR pszText = 0; VARIANT_BOOL fSuccess;
if(m_pRangeChecking == NULL) { hr = pRange->duplicate(&m_pRangeChecking); if(FAILED(hr)) goto error;
hr = m_pRangeChecking->collapse(VARIANT_TRUE); if(FAILED(hr)) goto error; }
while(TRUE) { SafeMemFree(pszText);
hr = HrGetNextWordRange(m_pRangeChecking); if(FAILED(hr)) goto error; if (hr == HR_S_SPELLBREAK) break; if (hr == HR_S_SPELLCONTINUE) continue;
// Do we really need it?
if (!m_fIgnoreScope) { hr = pRange->inRange(m_pRangeChecking, &fSuccess); if(FAILED(hr)) goto error; if(fSuccess != VARIANT_TRUE) break; }
// check if we are on the original text of a reply/forward message.
if(m_pRangeIgnore) { fSuccess = VARIANT_FALSE;
m_pRangeIgnore->inRange(m_pRangeChecking, &fSuccess);
// normally don't spellcheck words in m_pRangeIgnore.
// but if it's selected, we check it.
if(fSuccess==VARIANT_TRUE) { hr = m_pRangeSelExpand->inRange(m_pRangeChecking, &fSuccess); if(FAILED(hr)) goto error; if(fSuccess != VARIANT_TRUE) continue; } }
tryWordAgain: hr = HrGetText(m_pRangeChecking, &pszText); if(FAILED(hr)) goto error; if (hr == HR_S_SPELLBREAK) break; if (hr == HR_S_SPELLCONTINUE) continue;
hr = HrCheckWord(pszText); if(FAILED(hr)) goto error;
if(m_wsrb.sstat!=sstatNoErrors) //found an error.
{ if(FIgnore(m_pRangeChecking)) { m_wsrb.sstat = sstatNoErrors; continue; }
// if it contains a period, remove it for processing
if (StrChr(pszText, '.')) { BOOL fResult; hr = HrStripTrailingPeriod(m_pRangeChecking, &fResult); if (FAILED(hr)) goto error;
if (fResult) goto tryWordAgain; }
HrProcessSpellErrors(); if(!m_hwndDlg) //spellchecking dialog is lauched only once.
{ nCode = DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddSpelling), m_hwndNote, SpellingDlgProc, (LPARAM)this);
} if(nCode == -1) hr = E_FAIL; else if(FAILED(m_hr)) // something was wrong when dialog calls HrFindErrors.
// it has higher priority than IDCANCEL.
hr = m_hr; else if(nCode == IDCANCEL) hr = HR_S_SPELLCANCEL; else // we quit here to pass control to the dialog procedure which calls HrFindErrors.
hr = HR_S_ABORT; goto error; }
}
error: SafeMemFree(pszText);
return hr; }
HRESULT CSpell::HrGetText(IMarkupPointer* pRangeStart, IMarkupPointer* pRangeEnd, LPSTR *ppszText) { HRESULT hr = NOERROR; IHTMLTxtRange *pTxtRange = NULL; BSTR bstr = NULL;
if (ppszText == NULL || pRangeStart == NULL || pRangeEnd == NULL) return E_INVALIDARG;
*ppszText = NULL;
hr = _EnsureInited(); if (FAILED(hr)) goto error;
hr = m_pBodyElem->createTextRange(&pTxtRange); if (FAILED(hr)) goto error;
hr = m_pMarkup->MoveRangeToPointers(pRangeStart, pRangeEnd, pTxtRange); if (FAILED(hr)) goto error;
hr = pTxtRange->get_text(&bstr); if (FAILED(hr)) goto error;
if(bstr==NULL || SysStringLen(bstr)==0) { hr = HR_S_SPELLBREAK; goto error; }
// never spell check Japanese.
if(((WORD)*bstr > (WORD)0x3000) && //DBCS
(GetACP() == 932 || FIgnoreDBCS())) { hr = HR_S_SPELLCONTINUE; goto error; } hr = HrBSTRToLPSZ(CP_ACP, bstr, ppszText); if (FAILED(hr)) goto error; if (*ppszText == NULL) { hr = E_FAIL; goto error; } error: SafeRelease(pTxtRange); SafeSysFreeString(bstr);
return hr; }
HRESULT CSpell::HrGetText(IHTMLTxtRange* pRange, LPSTR *ppszText) { BSTR bstr=0; HRESULT hr = NOERROR; UINT uCodePage;
if (ppszText==NULL || pRange==NULL) return E_INVALIDARG;
*ppszText = 0;
hr = pRange->get_text(&bstr); if(FAILED(hr)) goto error; if(bstr==NULL || SysStringLen(bstr)==0) { hr = HR_S_SPELLBREAK; goto error; }
// never spell check Japanese.
if(((WORD)*bstr > (WORD)0x3000) && //DBCS
(GetACP() == 932 || FIgnoreDBCS())) { hr = HR_S_SPELLCONTINUE; goto error; }
uCodePage = GetCodePage(); *ppszText = PszToANSI(uCodePage, bstr); if (*ppszText == NULL) { hr = E_FAIL; goto error; }
error: SafeSysFreeString(bstr); return hr; }
HRESULT CSpell::HrStripTrailingPeriod(IHTMLTxtRange* pRange, BOOL* pfResult) { HRESULT hr = NOERROR; IMarkupPointer *pRangeStart = NULL; IMarkupPointer *pRangeEnd = NULL; IMarkupPointer *pRangeTemp = NULL; MARKUP_CONTEXT_TYPE markupContext; long cch; OLECHAR chText[64]; BOOL fResult;
if (pRange==NULL || pfResult == NULL) return E_INVALIDARG;
*pfResult = FALSE;
hr = _EnsureInited(); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeStart); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeEnd); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeTemp); if (FAILED(hr)) goto error;
hr = m_pMarkup->MovePointersToRange(pRange, pRangeStart, pRangeEnd); if (FAILED(hr)) goto error;
hr = pRangeStart->IsEqualTo(pRangeEnd, &fResult); if (FAILED(hr)) goto error;
if (fResult) { hr = HR_S_SPELLBREAK; goto error; } // check for '.' and remove
{ hr = pRangeTemp->MoveToPointer(pRangeEnd); if (FAILED(hr)) goto error; while(TRUE) { cch = 1; hr = pRangeTemp->Left(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto finished;
hr = pRangeTemp->IsRightOf(pRangeStart, &fResult); if (FAILED(hr)) goto error;
if (!fResult) { hr = HR_S_SPELLBREAK; goto error; }
if (markupContext == CONTEXT_TYPE_Text && chText[0] != L'.') goto finished;
cch = 1; hr = pRangeTemp->Left(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_Text) { hr = pRangeEnd->MoveToPointer(pRangeTemp); if (FAILED(hr)) goto error;
*pfResult = TRUE; } } }
finished: hr = m_pMarkup->MoveRangeToPointers(pRangeStart, pRangeEnd, pRange); if (FAILED(hr)) goto error;
error: SafeRelease(pRangeStart); SafeRelease(pRangeEnd); SafeRelease(pRangeTemp); return hr; }
HRESULT CSpell::HrHasWhitespace(IMarkupPointer* pRangeStart, IMarkupPointer* pRangeEnd, BOOL *pfResult) { HRESULT hr = NOERROR; LPSTR pszText = NULL; LPSTR psz; if (pRangeStart == NULL || pRangeEnd == NULL || pfResult == NULL) return E_INVALIDARG;
*pfResult = FALSE;
hr = HrGetText(pRangeStart, pRangeEnd, &pszText); if (FAILED(hr) || HR_S_SPELLCONTINUE == hr || HR_S_SPELLBREAK == hr) goto error;
Assert(NULL != pszText); for(psz = pszText; *psz; psz = CharNext(psz)) { if (IsSpace(psz)) { *pfResult = TRUE; break; } } error: SafeMemFree(pszText);
return hr; }
HRESULT CSpell::HrGetNextWordRange(IHTMLTxtRange* pRange) { HRESULT hr = NOERROR; IMarkupPointer *pRangeStart = NULL; IMarkupPointer *pRangeEnd = NULL; IMarkupPointer *pRangeTemp = NULL; MARKUP_CONTEXT_TYPE markupContext; long cch; OLECHAR chText[64]; BOOL fResult; BOOL fFoundWhite; if (pRange==NULL) return E_INVALIDARG;
hr = _EnsureInited(); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeStart); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeEnd); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeTemp); if (FAILED(hr)) goto error;
hr = m_pMarkup->MovePointersToRange(pRange, pRangeStart, pRangeEnd); if (FAILED(hr)) goto error;
hr = pRangeStart->IsEqualTo(pRangeEnd, &fResult); if (FAILED(hr)) goto error;
if (!fResult) { do { hr = pRangeStart->MoveUnit(MOVEUNIT_NEXTWORDBEGIN); if (FAILED(hr)) goto error;
// make sure beyond the old end
hr = pRangeStart->IsLeftOf(pRangeEnd, &fResult); if (FAILED(hr)) goto error; } while(fResult);
hr = pRangeEnd->MoveToPointer(pRangeStart); if (FAILED(hr)) goto error; } hr = pRangeEnd->MoveUnit(MOVEUNIT_NEXTWORDEND); if (FAILED(hr)) goto error; processNextWord: // check to see if we have anything
hr = pRangeEnd->IsRightOf(pRangeStart, &fResult); if (FAILED(hr)) goto error;
// if the end is not to the right of the start then we do not have a word
if (!fResult) { hr = HR_S_SPELLBREAK; goto error; }
// strip preceding puncts or white space
// words can also be created with just puncts and whitespace
{ while(TRUE) { cch = 1; hr = pRangeStart->Right(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto finished;
hr = pRangeStart->IsLeftOf(pRangeEnd, &fResult); if (FAILED(hr)) goto error;
if (!fResult) { hr = pRangeEnd->MoveUnit(MOVEUNIT_NEXTWORDEND); if (FAILED(hr)) goto error;
continue; }
if (markupContext == CONTEXT_TYPE_Text && 0 == ((C1_SPACE | C1_PUNCT) & GetWCharType(chText[0]))) break;
cch = 1; hr = pRangeStart->Right(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error; } }
// check for white space and remove
{ fFoundWhite = FALSE;
hr = pRangeTemp->MoveToPointer(pRangeEnd); if (FAILED(hr)) goto error; while(TRUE) { cch = 1; hr = pRangeTemp->Left(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto finished;
hr = pRangeTemp->IsRightOf(pRangeStart, &fResult); if (FAILED(hr)) goto error;
if (!fResult) { hr = HR_S_SPELLBREAK; goto error; }
if (markupContext == CONTEXT_TYPE_Text) { if (0 == (C1_SPACE & GetWCharType(chText[0]))) { if (!fFoundWhite) break; goto finished; }
fFoundWhite = TRUE; }
cch = 1; hr = pRangeTemp->Left(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_Text) { hr = pRangeEnd->MoveToPointer(pRangeTemp); if (FAILED(hr)) goto error; } } }
// now look for a period
{ hr = pRangeTemp->MoveToPointer(pRangeEnd); if (FAILED(hr)) goto error; while(TRUE) { cch = 1; hr = pRangeTemp->Right(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto finished;
if (markupContext == CONTEXT_TYPE_Text && chText[0] != L'.') goto finished;
cch = 1; hr = pRangeTemp->Right(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_Text && chText[0] == L'.') { hr = HrHasWhitespace(pRangeStart, pRangeTemp, &fResult); if (FAILED(hr)) goto error;
if (fResult) goto finished; hr = pRangeEnd->MoveToPointer(pRangeTemp); if (FAILED(hr)) goto error;
// scan ahead for characters
// need to check for i.e. -- abbreviations
// it sure would be nice if Trident could do this!!
{ while(TRUE) { cch = 1; hr = pRangeTemp->Right(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto finished;
if (markupContext == CONTEXT_TYPE_Text && 0 == (C1_SPACE & GetWCharType(chText[0]))) goto finished;
cch = 1; hr = pRangeTemp->Right(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error;
// we found more text
// need to check to see if we crossed white space to get here
if (markupContext == CONTEXT_TYPE_Text) { hr = pRangeTemp->MoveToPointer(pRangeEnd); if (FAILED(hr)) goto error;
hr = pRangeTemp->MoveUnit(MOVEUNIT_NEXTWORDEND); if (FAILED(hr)) goto finished;
hr = HrHasWhitespace(pRangeStart, pRangeTemp, &fResult); if (FAILED(hr)) goto error;
if (fResult) goto finished; pRangeEnd->MoveToPointer(pRangeTemp); if (FAILED(hr)) goto error; goto processNextWord; } } } goto finished; }
} }
finished: hr = m_pMarkup->MoveRangeToPointers(pRangeStart, pRangeEnd, pRange); if (FAILED(hr)) goto error;
error: SafeRelease(pRangeStart); SafeRelease(pRangeEnd); SafeRelease(pRangeTemp); return hr; }
BOOL CSpell::FIgnore(IHTMLTxtRange *pRangeChecking) { HRESULT hr; IHTMLAnchorElement *pAE=0; IHTMLElement *pElemParent=0; BOOL fRet = FALSE; BSTR bstr=0; IHTMLTxtRange *pRange=0; VARIANT_BOOL fSuccess;
if(pRangeChecking == NULL) return fRet;
if(FIgnoreURL()) { hr = pRangeChecking->duplicate(&pRange); if(FAILED(hr)) goto Cleanup;
hr = pRange->collapse(VARIANT_TRUE); if(FAILED(hr)) goto Cleanup;
hr = pRange->expand((BSTR)c_bstr_Character, &fSuccess); if(FAILED(hr)) goto Cleanup;
// check pRangeChecking if we are on URL
hr = pRange->parentElement(&pElemParent); if(FAILED(hr)) goto Cleanup;
hr = pElemParent->QueryInterface(IID_IHTMLAnchorElement, (LPVOID *)&pAE); if(FAILED(hr)) goto Cleanup;
hr = pAE->get_href(&bstr); if(FAILED(hr)) goto Cleanup;
if(bstr != NULL) { fRet = TRUE; goto Cleanup; } }
Cleanup: ReleaseObj(pElemParent); ReleaseObj(pAE); ReleaseObj(pRange); SafeSysFreeString(bstr); return fRet; }
// [email protected] - can now specify dict index - 53193
HRESULT CSpell::AddToUdrW(WCHAR* pwsz, PROOFLEX lex) { m_pfnSpellerAddUdr(m_pid, lex, pwsz); return NOERROR; }
// [email protected] - can now specify dict index - 53193
HRESULT CSpell::AddToUdrA(CHAR* psz, PROOFLEX lex) { WCHAR wszBuf[cchEditBufferMax]={0}; MultiByteToWideChar(CP_ACP, 0, psz, -1, wszBuf, ARRAYSIZE(wszBuf)-1); return AddToUdrW(wszBuf, lex); }
HRESULT CSpell::HrProcessSpellErrors() { int idSpellErrorString; HRESULT hr = S_OK;
WideCharToMultiByte(GetCodePage(), 0, m_wsib.pwsz, -1, m_szWrongWord, sizeof(m_szWrongWord)-1, NULL, NULL);
// Select error word in edit control except for Abbreviation warnings
if (m_wsrb.sstat != sstatWordConsideredAbbreviation && m_pRangeChecking) { hr = m_pRangeChecking->select(); if(FAILED(hr)) goto End; }
// Process spelling error
if (m_wsrb.sstat == sstatReturningChangeAlways || m_wsrb.sstat == sstatReturningChangeOnce) { WideCharToMultiByte(GetCodePage(), 0, m_wsrb.pwsz, -1, m_szEdited, sizeof(m_szEdited)-1, NULL, NULL);
// "Change always" was returned. This means we have to do the replacement
// automatically and then find the next spelling error.
if (m_wsrb.sstat==sstatReturningChangeAlways) { FVerifyThisText(m_szEdited, TRUE); m_fCanUndo = FALSE; // can't undo automatic replacements
hr = HrReplaceErrorText(TRUE, FALSE); if (FAILED(hr)) goto End; m_wsrb.sstat = sstatNoErrors; HrFindErrors(); } } else if (m_wsrb.sstat == sstatWordConsideredAbbreviation) { // An abbreviation was returned. We need to add it to the IgnoreAlways cache and
// find the next spelling error.
AddToUdrW((WCHAR*)m_wsib.pwsz, m_rgprflex[1]); m_wsrb.sstat = sstatNoErrors; HrFindErrors();
} else StrCpyN(m_szEdited, m_szWrongWord, ARRAYSIZE(m_szEdited));
// Load the right error description string
switch (m_wsrb.sstat) { case sstatUnknownInputWord: case sstatReturningChangeOnce: case sstatInitialNumeral: idSpellErrorString = idsSpellWordNotFound; break; case sstatRepeatWord: idSpellErrorString = idsSpellRepeatWord; break; case sstatErrorCapitalization: idSpellErrorString = idsSpellWordNeedsCap; break; }
LoadString(g_hLocRes, idSpellErrorString, m_szErrType, sizeof(m_szErrType)/sizeof(TCHAR));
// Handle suggestions
m_fSuggestions = FALSE; #ifdef __WBK__NEVER__
if (m_wsrb.sstat == sstatReturningChangeOnce) { // Automatic suggestion of one word
m_fSuggestions = TRUE; m_fNoneSuggested = FALSE; } else #endif // __WBK__NEVER__
{ // Enumerate suggestion list if requested
if (m_fAlwaysSuggest) hr = HrSpellSuggest(); }
End: return hr; }
HRESULT CSpell::HrReplaceErrorText(BOOL fChangeAll, BOOL fAddToUdr) { HRESULT hr=NOERROR; WCHAR wszWrong[cchEditBufferMax]={0}; WCHAR wszEdited[cchEditBufferMax]={0}; int cwch; if (fAddToUdr) { RemoveTrailingSpace(m_szWrongWord); cwch = MultiByteToWideChar(GetCodePage(), 0, m_szWrongWord, -1, wszWrong, ARRAYSIZE(wszWrong)-1); Assert(cwch); cwch = MultiByteToWideChar(GetCodePage(), 0, m_szEdited, -1, wszEdited, ARRAYSIZE(wszEdited)-1); Assert(cwch); hr = m_pfnSpellerAddChangeUdr(m_pid, fChangeAll ? lxtChangeAlways : lxtChangeOnce, wszWrong, wszEdited); if (FAILED(hr)) goto error; }
hr = HrReplaceSel(m_szEdited); if (FAILED(hr)) goto error;
error: return hr; }
HRESULT CSpell::HrCheckWord(LPCSTR pszWord) { DWORD cwchWord; PTEC ptec; SPELLERSUGGESTION sugg; cwchWord = MultiByteToWideChar(GetCodePage(), 0, pszWord, -1, m_wszIn, ARRAYSIZE(m_wszIn)-1); ZeroMemory(&m_wsrb, sizeof(m_wsrb)); ZeroMemory(&m_wsib, sizeof(m_wsib)); m_wsib.pwsz = m_wszIn; m_wsib.cch = cwchWord;
m_wsib.clex = m_clex; m_wsib.prglex = m_rgprflex; m_wsib.ichStart = 0; m_wsib.cchUse = cwchWord; m_wsrb.pwsz = m_wszRet; m_wsrb.cchAlloc = ARRAYSIZE(m_wszRet); m_wsrb.cszAlloc = 1; // we've got space for 1 speller suggestion
m_wsrb.prgsugg = &sugg;
// [email protected] - "repeat word" bug fix - 2757, 13573, 56057
// m_wsib.sstate should only be sstateIsContinued after the first call to this function
// (e.g., when a new speller session is invoked using F7 or the menu item).
// This allows the spell code to accurately track "repeat" words.
if (m_fSpellContinue) m_wsib.sstate = sstateIsContinued; else m_fSpellContinue = TRUE;
ptec = m_pfnSpellerCheck(m_pid, scmdVerifyBuffer, &m_wsib, &m_wsrb);
// do we haveinvalid characters, if so return NOERR
if (ProofMajorErr(ptec) != ptecNoErrors && ProofMinorErr(ptec) == ptecInvalidEntry) { // force it to be correct
m_wsrb.sstat = sstatNoErrors;
return NOERROR; } if (ptec != ptecNoErrors) return E_FAIL;
return NOERROR; }
HRESULT CSpell::HrSpellSuggest() { int cchWord; WCHAR wszBuff[cchMaxSuggestBuff]={0}; WCHAR wszWord[cchEditBufferMax]={0}; SPELLERSUGGESTION rgsugg[20]; TCHAR *pchNextSlot=0; ULONG iszSuggestion; int cchSuggestion; SPELLERSUGGESTION *pSuggestion; TCHAR *pchLim=0; PTEC ptec; SPELLERSTATUS sstat;
sstat = m_wsrb.sstat; cchWord = MultiByteToWideChar(GetCodePage(), 0, m_szEdited, -1, wszWord, ARRAYSIZE(wszWord)-1); m_wsib.cch = cchWord; m_wsib.clex = m_clex; m_wsib.prglex = m_rgprflex; m_wsib.ichStart = 0; m_wsib.cchUse = cchWord; m_wsib.pwsz = wszWord;
m_wsrb.prgsugg = rgsugg; m_wsrb.cszAlloc = ARRAYSIZE(rgsugg); m_wsrb.pwsz = wszBuff; m_wsrb.cchAlloc = ARRAYSIZE(wszBuff);
ptec = m_pfnSpellerCheck(m_pid, scmdSuggest, &m_wsib, &m_wsrb); m_fNoneSuggested = (m_wsrb.csz == 0);
pchLim = &m_szSuggest[ARRAYSIZE(m_szSuggest)-1]; pchNextSlot = m_szSuggest;; do { pSuggestion = m_wsrb.prgsugg; if (sstatMoreInfoThanBufferCouldHold == m_wsrb.sstat) { m_wsrb.csz = m_wsrb.cszAlloc; } for (iszSuggestion = 0; iszSuggestion < m_wsrb.csz; iszSuggestion++) { cchSuggestion = WideCharToMultiByte(GetCodePage(), 0, pSuggestion->pwsz, -1, pchNextSlot, (int) (pchLim-pchNextSlot), NULL, NULL);
// [email protected] - raid 29322
// make sure words do not have trailing spaces
// only the French speller returns words with trailing spaces
RemoveTrailingSpace(pchNextSlot); cchSuggestion = lstrlen(pchNextSlot)+1;
pSuggestion++; if (cchSuggestion > 0) pchNextSlot += cchSuggestion; Assert(pchNextSlot <= pchLim); } ptec = m_pfnSpellerCheck(m_pid, scmdSuggestMore, &m_wsib, &m_wsrb); } while (ptec == ptecNoErrors && m_wsrb.sstat!=sstatNoMoreSuggestions); *pchNextSlot = '\0'; m_wsrb.sstat = sstat; m_fSuggestions = TRUE;
return NOERROR; }
VOID CSpell::FillSuggestLbx() { HWND hwndLbx; INT isz; LPTSTR sz; LPTSTR pch;
// Empty contents regardless
hwndLbx = GetDlgItem(m_hwndDlg, LBX_Spell_Suggest); ListBox_ResetContent(hwndLbx);
// We didn't even try to get any suggestions
if (!m_fSuggestions) return;
// We tried to get suggestions
pch = m_szSuggest; if (*pch == '\0') { LoadString(g_hLocRes, idsSpellNoSuggestions, m_szTempBuffer, sizeof(m_szTempBuffer)/sizeof(TCHAR)); ListBox_AddString(hwndLbx, m_szTempBuffer); } else { while(*pch != '\0') { ListBox_AddString(hwndLbx, pch); while(*pch != '\0') pch++; pch++; } }
}
VOID UpdateEditedFromSuggest(HWND hwndDlg, HWND hwndEdited, HWND hwndSuggest) { INT nSel; INT cch; LPSTR szTemp;
nSel = ListBox_GetCurSel(hwndSuggest); cch = ListBox_GetTextLen(hwndSuggest, nSel) + 1; if (MemAlloc((LPVOID *) &szTemp, cch)) { ListBox_GetText(hwndSuggest, nSel, szTemp); SetWindowText(hwndEdited, szTemp);
// Clear default button style from "Ignore" button and set default to "Change"
Button_SetStyle(GetDlgItem(hwndDlg, PSB_Spell_Ignore), BS_PUSHBUTTON, TRUE); SendMessage(hwndDlg, DM_SETDEFID, PSB_Spell_Change, 0L); Button_SetStyle(GetDlgItem(hwndDlg, PSB_Spell_Change), BS_DEFPUSHBUTTON, TRUE);
Edit_SetSel(hwndEdited, 0, 32767); // select the whole thing
Edit_SetModify(hwndEdited, TRUE); MemFree(szTemp); } }
BOOL CSpell::FVerifyThisText(LPSTR szThisText, BOOL /*fProcessOnly*/) { BOOL fReturn=FALSE; HRESULT hr;
Assert(szThisText);
hr = HrCheckWord(szThisText); if (FAILED(hr)) goto error;
switch (m_wsrb.sstat) { case sstatUnknownInputWord: case sstatInitialNumeral: case sstatErrorCapitalization: if (AthMessageBoxW(m_hwndDlg, MAKEINTRESOURCEW(idsSpellCaption), MAKEINTRESOURCEW(idsSpellMsgConfirm), NULL, MB_YESNO | MB_ICONEXCLAMATION ) == IDYES) fReturn = TRUE; else fReturn = FALSE; break; default: fReturn = TRUE; break; }
error: return fReturn; }
VOID CSpell::SpellSaveUndo(INT idButton) { HRESULT hr = NOERROR;
if(!m_pRangeChecking) return;
SafeRelease(m_pRangeUndoSave); m_pRangeChecking->duplicate(&m_pRangeUndoSave); if(!m_pRangeUndoSave) goto error;
m_fCanUndo = TRUE;
error: return; }
VOID CSpell::SpellDoUndo() { HRESULT hr = NOERROR; IOleCommandTarget* pCmdTarget = NULL; CHARRANGE chrg = {0}; LONG lMin = 0;
m_fCanUndo = FALSE;
if(!m_pRangeUndoSave) goto Cleanup;
SafeRelease(m_pRangeChecking); m_pRangeUndoSave->duplicate(&m_pRangeChecking); if(!m_pRangeChecking) goto Cleanup;
hr = m_pRangeChecking->collapse(VARIANT_TRUE); if(FAILED(hr)) goto Cleanup;
if (m_fUndoChange) { m_fUndoChange = FALSE; hr = m_pDoc->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pCmdTarget); if(FAILED(hr)) goto Cleanup; hr = pCmdTarget->Exec(&CMDSETID_Forms3, IDM_UNDO, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL); if(FAILED(hr)) goto Cleanup; }
Cleanup: ReleaseObj(pCmdTarget);
}
CSpell::CSpell(IHTMLDocument2* pDoc, IOleCommandTarget* pParentCmdTarget, DWORD dwSpellOpt) { HRESULT hr; Assert(pDoc); m_pDoc = pDoc; m_pDoc->AddRef();
Assert(pParentCmdTarget); m_pParentCmdTarget = pParentCmdTarget; m_pParentCmdTarget->AddRef();
m_hwndDlg = NULL; m_cRef = 1; m_fSpellContinue = FALSE; m_fCanUndo = FALSE; m_fUndoChange = FALSE; m_State = SEL; m_pRangeDocStartSelStart = NULL; m_pRangeSel = NULL; m_pRangeSelExpand = NULL; m_pRangeSelEndDocEnd = NULL; m_pRangeChecking = NULL; m_pRangeUndoSave = NULL; m_hr = NOERROR; m_hinstDll = NULL; ZeroMemory(&m_wsib, sizeof(m_wsib)); ZeroMemory(&m_wsrb, sizeof(m_wsrb)); ZeroMemory(&m_pid, sizeof(m_pid)); m_fIgnoreScope = FALSE; m_dwCookieNotify = 0; m_dwOpt = dwSpellOpt;
m_langid = lidUnknown;
m_clex = 0; ZeroMemory(&m_rgprflex, sizeof(m_rgprflex));
m_pMarkup = NULL; m_pBodyElem = NULL;
m_fCSAPI3T1 = FALSE; }
CSpell::~CSpell() { CloseSpeller();
SafeRelease(m_pDoc); SafeRelease(m_pParentCmdTarget);
SafeRelease(m_pMarkup);
SafeRelease(m_pBodyElem); }
ULONG CSpell::AddRef() { return ++m_cRef; }
ULONG CSpell::Release() { if (--m_cRef==0) { delete this; return 0; } return m_cRef; }
HRESULT CSpell::QueryInterface(REFIID riid, LPVOID *lplpObj) { if(!lplpObj) return E_INVALIDARG;
*lplpObj = NULL; // set to NULL, in case we fail.
if (IsEqualIID(riid, IID_IUnknown)) *lplpObj = (LPVOID)this;
else if (IsEqualIID(riid, IID_IDispatch)) *lplpObj = (LPVOID)(IDispatch*)this;
else return E_NOINTERFACE;
AddRef(); return NOERROR; }
/////////////////////////////////////////////////////////////////////////////
//
// IDispatch
//
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CSpell::GetIDsOfNames( REFIID /*riid*/, OLECHAR ** /*rgszNames*/, UINT /*cNames*/, LCID /*lcid*/, DISPID * /*rgDispId*/) { return E_NOTIMPL; }
STDMETHODIMP CSpell::GetTypeInfo( UINT /*iTInfo*/, LCID /*lcid*/, ITypeInfo **ppTInfo) { if (ppTInfo) *ppTInfo=NULL; return E_NOTIMPL; }
STDMETHODIMP CSpell::GetTypeInfoCount(UINT *pctinfo) { if (pctinfo) { *pctinfo=0; return NOERROR; } else return E_POINTER; }
#ifdef BACKGROUNDSPELL
STDMETHODIMP CSpell::Invoke( DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, WORD wFlags, DISPPARAMS FAR* /*pDispParams*/, VARIANT * /*pVarResult*/, EXCEPINFO * /*pExcepInfo*/, UINT * /*puArgErr*/) { IHTMLWindow2 *pWindow=0; IHTMLEventObj *pEvent=0; BSTR bstr=0; HRESULT hr=E_NOTIMPL; LONG lKeyCode=0; LONG cb;
if (dispIdMember == DISPID_HTMLDOCUMENTEVENTS_ONKEYUP && (wFlags & DISPATCH_METHOD)) { // Order of events:
// document gives us window gives us event object
// the event object can tell us which button was clicked
// event gives us source element gives us ID
// a couple lstrcmps will tell us which one got hit
if (!m_pDoc) return E_UNEXPECTED;
m_pDoc->get_parentWindow(&pWindow); if (pWindow) { pWindow->get_event(&pEvent); if (pEvent) { pEvent->get_keyCode(&lKeyCode); if (lKeyCode == 32 || lKeyCode == 188/*','*/ || lKeyCode == 190/*'.'*/ || lKeyCode == 185/*':'*/ || lKeyCode == 186/*';'*/) { IHTMLTxtRange *pTxtRange=0; VARIANT_BOOL fSuccess; GetSelection(&pTxtRange); if (pTxtRange) { pTxtRange->move((BSTR)c_bstr_Character, -2, &cb); pTxtRange->expand((BSTR)c_bstr_Word, &fSuccess); //DumpRange(pRangeDup);
//pTxtRange->setEndPoint((BSTR)c_bstr_StartToStart, pRangeDup);
//DumpRange(pTxtRange);
//pRangeDup->Release();
m_Stack.push(pTxtRange); pTxtRange->Release(); } } else if (lKeyCode == 8 /*backspace*/|| lKeyCode == 46/*del*/) { IHTMLTxtRange *pTxtRange=0; VARIANT_BOOL fSuccess; LONG cb; GetSelection(&pTxtRange); if (pTxtRange) { pTxtRange->expand((BSTR)c_bstr_Word, &fSuccess); if (HrHasSquiggle(pTxtRange)==S_OK) { //DumpRange(pTxtRange);
m_Stack.push(pTxtRange); } pTxtRange->Release(); } } pEvent->Release(); } pWindow->Release(); } } else if (dispIdMember == DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS && (wFlags & DISPATCH_METHOD)) { if (!m_pDoc) return E_UNEXPECTED;
m_pDoc->get_parentWindow(&pWindow); if (pWindow) { pWindow->get_event(&pEvent); if (pEvent) { pEvent->get_keyCode(&lKeyCode); if (lKeyCode == 18)// CTRL+R
{ IHTMLTxtRange* pRangeDoc = NULL;
if (m_pBodyElem) m_pBodyElem->createTextRange(&pRangeDoc);
if (pRangeDoc) { pRangeDoc->move((BSTR)c_bstr_Character, -1, &cb); m_Stack.push(pRangeDoc); pRangeDoc->Release(); }
} pEvent->Release(); } pWindow->Release(); } }
return hr; } #endif // BACKGROUNDSPELL
#ifdef BACKGROUNDSPELL
HRESULT CSpell::HrHasSquiggle(IHTMLTxtRange *pTxtRange) { BSTR bstr=0; HRESULT hr; LPWSTR pwszSquiggleStart=0, pwszSquiggleEnd=0, pwszSquiggleAfter=0;
hr = pTxtRange->get_htmlText(&bstr); if(FAILED(hr) || bstr==0 || *bstr==L'\0') { hr = S_FALSE; goto error; }
hr = S_FALSE; pwszSquiggleStart = StrStrIW(bstr, L"<SPAN class=badspelling"); if (pwszSquiggleStart) { pwszSquiggleEnd = StrStrIW(bstr, L"</SPAN>"); if (pwszSquiggleEnd) { pwszSquiggleAfter = pwszSquiggleEnd + 7; if (*pwszSquiggleAfter == L' ' || *pwszSquiggleAfter == L'\0' || *pwszSquiggleAfter == L'&') hr = S_OK; } }
error: SafeSysFreeString(bstr); return hr; } #endif // BACKGROUNDSPELL
BOOL CSpell::OpenSpeller() { SpellerParams params; DWORD dwSel; LANGID langid; // LoadOldSpeller is called within LoadNewSpeller
// We should be checking for V1 spellers after failing
// for the desired V3 speller, then go on to check for
// default speller and the speller for 1033.
if (!LoadNewSpeller()) goto error;
if (!OpenUserDictionaries()) goto error;
dwSel = sobitStdOptions; m_fAlwaysSuggest = !!FAlwaysSuggest(); if (FIgnoreNumber()) dwSel |= sobitIgnoreMixedDigits; else dwSel &= ~sobitIgnoreMixedDigits;
if (FIgnoreUpper()) dwSel |= sobitIgnoreAllCaps; else dwSel &= ~sobitIgnoreAllCaps;
if (m_pfnSpellerSetOptions(m_pid, soselBits, dwSel) != ptecNoErrors) goto error;
return TRUE;
error: CloseSpeller(); return FALSE; }
BOOL FNewer(WORD *pwVerOld, WORD *pwVerNew) { BOOL fOK = FALSE; Assert(pwVerOld); Assert(pwVerNew);
if (pwVerNew[0] > pwVerOld[0]) fOK = TRUE; else if (pwVerNew[0] == pwVerOld[0]) { if (pwVerNew[1] > pwVerOld[1]) fOK = TRUE; else if (pwVerNew[1] == pwVerOld[1]) { if (pwVerNew[2] > pwVerOld[2]) fOK = TRUE; else if (pwVerNew[2] == pwVerOld[2]) { if (pwVerNew[3] >= pwVerOld[3]) fOK = TRUE; } } }
return fOK; }
BOOL GetDllVersion(LPTSTR pszDll, WORD *pwVer, int nCountOfVers) { Assert(pszDll); Assert(pwVer);
BOOL fOK = FALSE; DWORD dwVerInfoSize, dwVerHnd; LPSTR pszInfo, pszVersion, pszT; LPWORD pwTrans; UINT uLen; char szGet[MAX_PATH]; int i;
ZeroMemory(pwVer, nCountOfVers * sizeof(pwVer[0]));
if (dwVerInfoSize = GetFileVersionInfoSize(pszDll, &dwVerHnd)) { if (pszInfo = (LPSTR)GlobalAlloc(GPTR, dwVerInfoSize)) { if (GetFileVersionInfo(pszDll, dwVerHnd, dwVerInfoSize, pszInfo)) { if (VerQueryValue(pszInfo, "\\VarFileInfo\\Translation", (LPVOID*)&pwTrans, &uLen) && uLen >= (2 * sizeof(WORD))) { // set up buffer for calls to VerQueryValue()
wnsprintf(szGet, ARRAYSIZE(szGet), "\\StringFileInfo\\%04X%04X\\FileVersion", pwTrans[0], pwTrans[1]); if (VerQueryValue(pszInfo, szGet, (LPVOID *)&pszVersion, &uLen) && uLen) { i = 0; while (*pszVersion) { if ((',' == *pszVersion) || ('.' == *pszVersion)) i++; else { pwVer[i] *= 10; pwVer[i] += (*pszVersion - '0'); }
pszVersion++; } fOK = TRUE; } } }
GlobalFree((HGLOBAL)pszInfo); } }
return fOK; }
HINSTANCE LoadCSAPI3T1() { static BOOL s_fInit = FALSE; HINSTANCE hinstLocal;
EnterCriticalSection(&g_csCSAPI3T1);
// Avoid doing this for every note!
if (!s_fInit) { typedef enum { CSAPI_FIRST, CSAPI_DARWIN = CSAPI_FIRST, CSAPI_COMMON, CSAPI_OE, CSAPI_MAX, } CSAPISRC;
BOOL fCheck; // cb is for BYTE counts, cch for CHARACTER counts
DWORD cbDllPath; DWORD cchDllPath;
int csapisrc; // Info about the dll currently being examined
TCHAR szDllPath[MAX_PATH]; WORD wVer[4] = {0};
// Info about the dll we will ultimately load
TCHAR szNewestDllPath[MAX_PATH]; WORD wVerNewest[4] = {0};
szDllPath[0] = TEXT('\0'); szNewestDllPath[0] = TEXT('\0');
// Avoid doing this for every note!
s_fInit = TRUE; for (csapisrc = CSAPI_FIRST; csapisrc < CSAPI_MAX; csapisrc++) { // Assume we can't find the dll using the current method, so there's no need to look at its version
fCheck = FALSE; switch (csapisrc) { // see if Darwin knows where it is
case CSAPI_DARWIN: { UINT installState;
cchDllPath = ARRAYSIZE(szDllPath); #ifdef DEBUG
installState = MsiLocateComponent(CSAPI3T1_DEBUG_GUID, szDllPath, &cchDllPath); if (installState != INSTALLSTATE_LOCAL) { cchDllPath = ARRAYSIZE(szDllPath); installState = MsiLocateComponent(CSAPI3T1_GUID, szDllPath, &cchDllPath); } #else // DEBUG
installState = MsiLocateComponent(CSAPI3T1_GUID, szDllPath, &cchDllPath); #endif // DEBUG
// Only bother looking at the version if dll is installed
fCheck = (INSTALLSTATE_LOCAL == installState); } break;
// Is it in Common Files\Microsoft Shared\Proof?
case CSAPI_COMMON: { DWORD dwType; HKEY hkey = NULL; LPTSTR pszEnd;
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegSharedTools, 0, KEY_QUERY_VALUE, &hkey)) { cbDllPath = sizeof(szDllPath); if (SHQueryValueEx(hkey, c_szRegSharedToolsPath, 0L, &dwType, szDllPath, &cbDllPath) == ERROR_SUCCESS) { pszEnd = PathAddBackslash(szDllPath); StrCpyN(pszEnd, c_szSpellCSAPI3T1Path, ARRAYSIZE(szDllPath) - (DWORD)(pszEnd - szDllPath)); fCheck = TRUE; }
RegCloseKey(hkey); } } break;
// Is it in the OE directory?
case CSAPI_OE: { DWORD dwType; HKEY hkey = NULL; LPTSTR pszEnd;
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegFlat, 0, KEY_QUERY_VALUE, &hkey)) { cbDllPath = sizeof(szDllPath); if (SHQueryValueEx(hkey, c_szInstallRoot, 0L, &dwType, szDllPath, &cbDllPath) == ERROR_SUCCESS) { pszEnd = PathAddBackslash(szDllPath); StrCpyN(pszEnd, c_szCSAPI3T1, ARRAYSIZE(szDllPath) - (DWORD)(pszEnd - szDllPath)); fCheck = TRUE; }
RegCloseKey(hkey); } } break; default: AssertSz(FALSE, "Unhandled case hit while looking for csapi3t1.dll!"); break; }
// Figure out the version of the dll if needed
if (fCheck && GetDllVersion(szDllPath, wVer, ARRAYSIZE(wVer))) { // If it's newer, remember the new version and the file's location
if (FNewer(wVerNewest, wVer)) { CopyMemory(wVerNewest, wVer, sizeof(wVer)); StrCpyN(szNewestDllPath, szDllPath, ARRAYSIZE(szNewestDllPath)); } }
}
// Assuming we found something, try to load it
if (szNewestDllPath[0]) g_hinstCSAPI3T1 = LoadLibrary(szNewestDllPath); } hinstLocal = g_hinstCSAPI3T1; LeaveCriticalSection(&g_csCSAPI3T1);
return hinstLocal; }
BOOL CSpell::LoadOldSpeller() { TCHAR szLangId[MAX_PATH] = {0}; TCHAR rgchBufKeyTest[MAX_PATH] = {0}; TCHAR rgchBuf[MAX_PATH] = {0}; WCHAR rgchBufW[MAX_PATH] = {0}; TCHAR rgchLex[MAX_PATH] = {0}; WCHAR rgchLexW[MAX_PATH] = {0}; WCHAR rgchUserDictW[MAX_PATH]={0}; PROOFLEXIN plxin; PROOFLEXOUT plxout; SpellerParams params; LANGID langid;
m_hinstDll = LoadCSAPI3T1(); if (!m_hinstDll) { m_pfnSpellerCloseLex = 0; m_pfnSpellerTerminate = 0; return FALSE; } // We are using the global csapi3t1.dll, so don't free it!
m_fCSAPI3T1 = TRUE;
GetAddr(m_pfnSpellerSetDllName, PROOFSETDLLNAME,"SpellerSetDllName"); GetAddr(m_pfnSpellerVersion, PROOFVERSION, "SpellerVersion"); GetAddr(m_pfnSpellerInit, PROOFINIT, "SpellerInit"); GetAddr(m_pfnSpellerTerminate, PROOFTERMINATE, "SpellerTerminate"); GetAddr(m_pfnSpellerSetOptions, PROOFSETOPTIONS,"SpellerSetOptions"); GetAddr(m_pfnSpellerOpenLex, PROOFOPENLEX, "SpellerOpenLex"); GetAddr(m_pfnSpellerCloseLex, PROOFCLOSELEX, "SpellerCloseLex"); GetAddr(m_pfnSpellerCheck, SPELLERCHECK, "SpellerCheck"); GetAddr(m_pfnSpellerAddUdr, SPELLERADDUDR, "SpellerAddUdr"); GetAddr(m_pfnSpellerBuiltInUdr, SPELLERBUILTINUDR, "SpellerBuiltinUdr"); GetAddr(m_pfnSpellerAddChangeUdr, SPELLERADDCHANGEUDR, "SpellerAddChangeUdr");
langid = WGetLangID(m_pParentCmdTarget); wnsprintf(szLangId, ARRAYSIZE(szLangId), "%d", langid); wnsprintf(rgchBufKeyTest, ARRAYSIZE(rgchBufKeyTest), c_szRegSpellKeyDef, szLangId); GetSpellingPaths(rgchBufKeyTest, rgchBuf, rgchLex, sizeof(rgchBuf)/sizeof(TCHAR));
if (!*rgchBuf) return FALSE; MultiByteToWideChar(GetCodePage(), 0, rgchBuf, -1, rgchBufW, ARRAYSIZE(rgchBufW)-1); m_pfnSpellerSetDllName(rgchBufW, GetCodePage()); params.versionAPI = PROOFTHISAPIVERSION; if (m_pfnSpellerInit(&m_pid, ¶ms) != ptecNoErrors) return FALSE;
m_langid = langid;
// Tell the speller the name of the dictionary. This requires unicode conversion.
MultiByteToWideChar(CP_ACP, 0, rgchLex, -1, rgchLexW, ARRAYSIZE(rgchLexW)-1);
// open the main dict
plxin.pwszLex = rgchLexW; plxin.fCreate = FALSE; plxin.lxt = lxtMain; plxin.lidExpected = langid;
memset(&plxout, 0, sizeof(plxout)); if (m_pfnSpellerOpenLex(m_pid, &plxin, &plxout) != ptecNoErrors) return FALSE; m_rgprflex[0] = plxout.lex; m_clex++;
return TRUE;
// needed by the GetAddr macro -- bite me!!!!!!
error: return FALSE; }
BOOL CSpell::LoadNewSpeller() { SpellerParams params; LANGID langid; TCHAR rgchEngine[MAX_PATH]; int cchEngine = sizeof(rgchEngine) / sizeof(rgchEngine[0]); TCHAR rgchLex[MAX_PATH]; int cchLex = sizeof(rgchLex) / sizeof(rgchLex[0]);
langid = WGetLangID(m_pParentCmdTarget); if (!GetNewSpellerEngine(langid, rgchEngine, cchEngine, rgchLex, cchLex)) { if (!LoadOldSpeller()) { langid = GetSystemDefaultLangID(); if (!GetNewSpellerEngine(langid, rgchEngine, cchEngine, rgchLex, cchLex)) { langid = 1033; // bloody cultural imperialists.
if (!GetNewSpellerEngine(langid, rgchEngine, cchEngine, rgchLex, cchLex)) { return FALSE; } } } else return TRUE; }
Assert(rgchEngine[0]); // should be something in the engine name!
m_hinstDll = LoadLibrary(rgchEngine); if (!m_hinstDll) { m_pfnSpellerCloseLex = 0; m_pfnSpellerTerminate = 0; return FALSE; }
// We are not using csapi3t1.dll, so we should free it
m_fCSAPI3T1 = FALSE;
GetAddr(m_pfnSpellerVersion, PROOFVERSION, "SpellerVersion"); GetAddr(m_pfnSpellerInit, PROOFINIT, "SpellerInit"); GetAddr(m_pfnSpellerTerminate, PROOFTERMINATE, "SpellerTerminate"); GetAddr(m_pfnSpellerSetOptions, PROOFSETOPTIONS,"SpellerSetOptions"); GetAddr(m_pfnSpellerOpenLex, PROOFOPENLEX, "SpellerOpenLex"); GetAddr(m_pfnSpellerCloseLex, PROOFCLOSELEX, "SpellerCloseLex"); GetAddr(m_pfnSpellerCheck, SPELLERCHECK, "SpellerCheck"); GetAddr(m_pfnSpellerAddUdr, SPELLERADDUDR, "SpellerAddUdr"); GetAddr(m_pfnSpellerBuiltInUdr, SPELLERBUILTINUDR, "SpellerBuiltinUdr"); GetAddr(m_pfnSpellerAddChangeUdr, SPELLERADDCHANGEUDR, "SpellerAddChangeUdr");
params.versionAPI = PROOFTHISAPIVERSION; if (m_pfnSpellerInit(&m_pid, ¶ms) != ptecNoErrors) return FALSE; if (m_pfnSpellerSetOptions(m_pid, soselBits, sobitSuggestFromUserLex | sobitIgnoreAllCaps | sobitIgnoreSingleLetter) != ptecNoErrors) return FALSE;
m_langid = langid;
// Hebrew does not have a main lex
if ((langid != lidHebrew) || !m_fCSAPI3T1) { PROOFLEXIN plxin; PROOFLEXOUT plxout; WCHAR rgchLexW[MAX_PATH]={0}; // Tell the speller the name of the dictionary. This requires unicode conversion.
MultiByteToWideChar(CP_ACP, 0, rgchLex, -1, rgchLexW, ARRAYSIZE(rgchLexW)-1);
// open the main dict
plxin.pwszLex = rgchLexW; plxin.fCreate = FALSE; plxin.lxt = lxtMain; plxin.lidExpected = langid;
memset(&plxout, 0, sizeof(plxout)); if (m_pfnSpellerOpenLex(m_pid, &plxin, &plxout) != ptecNoErrors) return FALSE; m_rgprflex[0] = plxout.lex; m_clex++; } return TRUE;
// needed by the GetAddr macro -- bite me!!!!!!
error: return FALSE; }
BOOL EnumUserDictCallback(DWORD_PTR dwCookie, LPTSTR lpszDict) { CSpell *pSpell = (CSpell*)dwCookie; Assert(pSpell); return pSpell->OpenUserDictionary(lpszDict); }
BOOL CSpell::OpenUserDictionary(LPTSTR lpszDict) { PROOFLEXIN plxin; PROOFLEXOUT plxout; WCHAR rgchUserDictW[MAX_PATH]={0};
// make sure our directory exists
{ TCHAR rgchDictDir[MAX_PATH];
StrCpyN(rgchDictDir, lpszDict, ARRAYSIZE(rgchDictDir));
PathRemoveFileSpec(rgchDictDir); OpenDirectory(rgchDictDir); }
MultiByteToWideChar(CP_ACP, 0, lpszDict, -1, rgchUserDictW, ARRAYSIZE(rgchUserDictW)-1);
plxin.pwszLex = rgchUserDictW; plxin.fCreate = TRUE; plxin.lxt = lxtUser; plxin.lidExpected = m_langid;
memset(&plxout, 0, sizeof(plxout)); if ( m_pfnSpellerOpenLex(m_pid, &plxin, &plxout) != ptecNoErrors) return TRUE; m_rgprflex[m_clex++] = plxout.lex;
return TRUE; }
BOOL CSpell::OpenUserDictionaries() { // now open the user dicts
EnumUserDictionaries((DWORD_PTR)this, EnumUserDictCallback);
// if only one dict open then we need to create default user dict
if (m_clex == 1) { PROOFLEXIN plxin; PROOFLEXOUT plxout; TCHAR rgchUserDict[MAX_PATH]={0};
if (GetDefaultUserDictionary(rgchUserDict, ARRAYSIZE(rgchUserDict))) { WCHAR rgchUserDictW[MAX_PATH]; // make sure our directory exists
{ TCHAR rgchDictDir[MAX_PATH];
StrCpyN(rgchDictDir, rgchUserDict, ARRAYSIZE(rgchDictDir));
PathRemoveFileSpec(rgchDictDir); OpenDirectory(rgchDictDir); }
MultiByteToWideChar(CP_ACP, 0, rgchUserDict, -1, rgchUserDictW, ARRAYSIZE(rgchUserDictW)-1);
plxin.pwszLex = rgchUserDictW; plxin.fCreate = TRUE; plxin.lxt = lxtUser; plxin.lidExpected = m_langid;
memset(&plxout, 0, sizeof(plxout));
if (m_pfnSpellerOpenLex(m_pid, &plxin, &plxout) != ptecNoErrors) return TRUE; m_rgprflex[m_clex++] = plxout.lex; } } return TRUE; }
VOID CSpell::CloseSpeller() { SafeRelease(m_pDoc); SafeRelease(m_pParentCmdTarget);
if (m_pfnSpellerCloseLex) { for(int i=0; i<cchMaxDicts; i++) { if (m_rgprflex[i]) { m_pfnSpellerCloseLex(m_pid, m_rgprflex[i], TRUE); m_rgprflex[i] = NULL; } } }
if (m_pfnSpellerTerminate) m_pfnSpellerTerminate(m_pid, TRUE);
m_pid = 0; m_pfnSpellerVersion = 0; m_pfnSpellerInit = 0; m_pfnSpellerTerminate = 0; m_pfnSpellerSetOptions = 0; m_pfnSpellerOpenLex = 0; m_pfnSpellerCloseLex = 0; m_pfnSpellerCheck = 0; m_pfnSpellerAddUdr = 0; m_pfnSpellerAddChangeUdr= 0; m_pfnSpellerBuiltInUdr = 0;
// As long as we are not using the global CSAPI3T1.DLL, free it
if (m_hinstDll && !m_fCSAPI3T1) { FreeLibrary(m_hinstDll); m_hinstDll = NULL; } }
BOOL CSpell::GetNewSpellerEngine(LANGID lgid, TCHAR *rgchEngine, DWORD cchEngine, TCHAR *rgchLex, DWORD cchLex) { DWORD er; LPCSTR rgpszDictionaryTypes[] = {"Normal", "Consise", "Complete"}; int cDictTypes = sizeof(rgpszDictionaryTypes) / sizeof(LPCSTR); int i; TCHAR rgchQual[MAX_PATH]; DWORD cch;
if (rgchEngine == NULL || rgchLex == NULL) return FALSE;
*rgchEngine = 0; *rgchLex = 0; wnsprintf(rgchQual, ARRAYSIZE(rgchQual), "%d\\Normal", lgid); cch = cchEngine;
#ifdef DEBUG
er = MsiProvideQualifiedComponent(SPELLER_DEBUG_GUID, rgchQual, INSTALLMODE_DEFAULT, rgchEngine, &cch); if (er != ERROR_SUCCESS) { cch = cchEngine; er = MsiProvideQualifiedComponent(SPELLER_GUID, rgchQual, INSTALLMODE_DEFAULT, rgchEngine, &cch); } #else
er = MsiProvideQualifiedComponent(SPELLER_GUID, rgchQual, INSTALLMODE_DEFAULT, rgchEngine, &cch); #endif
if (er != ERROR_SUCCESS) return FALSE;
bool fFound = FALSE;
// Hebrew does not have a lex
if ((lgid != lidHebrew) || !m_fCSAPI3T1) { 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, INSTALLMODE_DEFAULT, rgchLex, &cch); if (er != ERROR_SUCCESS) { cch = cchLex; er = MsiProvideQualifiedComponent(DICTIONARY_GUID, rgchQual, INSTALLMODE_DEFAULT, rgchLex, &cch); } #else // DEBUG
er = MsiProvideQualifiedComponent(DICTIONARY_GUID, rgchQual, INSTALLMODE_DEFAULT, rgchLex, &cch); #endif // DEBUG
if (ERROR_SUCCESS == er) { fFound = TRUE; break; } } } return fFound; }
BOOL GetDefaultUserDictionary(TCHAR *rgchUserDict, int cchBuff) { DWORD dwType; DWORD cbUserDict; HKEY hkey = NULL; BOOL fFound = FALSE; LPTSTR pszEnd; if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegSharedTools, 0, KEY_QUERY_VALUE, &hkey)) { cbUserDict = cchBuff * sizeof(rgchUserDict[0]); if (SHQueryValueEx(hkey, c_szRegSharedToolsPath, 0L, &dwType, rgchUserDict, &cbUserDict) == ERROR_SUCCESS) { pszEnd = PathAddBackslash(rgchUserDict); if (pszEnd) { StrCpyN(pszEnd, c_szRegDefCustomDict, cchBuff - (DWORD)(pszEnd - rgchUserDict));
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; }
VOID CSpell::DeInitRanges() { VARIANT_BOOL fSuccess;
if(m_pRangeSel) m_pRangeSel->select();
SafeRelease(m_pRangeDocStartSelStart); SafeRelease(m_pRangeSel); SafeRelease(m_pRangeSelExpand); SafeRelease(m_pRangeSelEndDocEnd); SafeRelease(m_pRangeChecking); SafeRelease(m_pRangeUndoSave); SafeRelease(m_pBodyElem); SafeRelease(m_pMarkup); m_hwndDlg = NULL; }
HRESULT CSpell::HrInitRanges(IHTMLTxtRange *pRangeIgnore, HWND hwndMain, BOOL fSuppressDoneMsg) { HRESULT hr = NOERROR; IDispatch* pID=0; VARIANT_BOOL fSuccess; IHTMLTxtRange* pRangeDoc = NULL; IHTMLSelectionObject* pSel = NULL; BSTR bstr = NULL; IMarkupPointer *pRangeStart = NULL; IMarkupPointer *pRangeEnd = NULL; IMarkupPointer *pRangeTemp = NULL; MARKUP_CONTEXT_TYPE markupContext; long cch; OLECHAR chText[64]; BOOL fResult;
Assert(m_pDoc);
m_hwndNote = hwndMain; m_fShowDoneMsg = !fSuppressDoneMsg;
m_pRangeIgnore = pRangeIgnore;
hr = _EnsureInited(); if (FAILED(hr)) goto error;
m_pBodyElem->createTextRange(&pRangeDoc); if(!pRangeDoc) { hr = E_FAIL; goto error; }
m_pDoc->get_selection(&pSel); if(!pSel) { hr = E_FAIL; goto error; }
pSel->createRange(&pID); if(!pID) { hr = E_FAIL; goto error; }
pID->QueryInterface(IID_IHTMLTxtRange, (LPVOID *)&m_pRangeSel); if(!m_pRangeSel) { // if the selection is on an image or something rather than text, it fails.
// So we just start spellchecking from the beginning.
pRangeDoc->duplicate(&m_pRangeSel); if(!m_pRangeSel) { hr = E_FAIL; goto error; }
hr = m_pRangeSel->collapse(VARIANT_TRUE); if(FAILED(hr)) goto error; }
Assert(m_pRangeSel); m_pRangeSel->duplicate(&m_pRangeSelExpand); if(!m_pRangeSelExpand) { hr = E_FAIL; goto error; }
hr = m_pRangeSelExpand->expand((BSTR)c_bstr_Word, &fSuccess); if(FAILED(hr)) goto error;
hr = m_pRangeSel->get_text(&bstr); if(FAILED(hr)) goto error;
if(!bstr || lstrlenW(bstr) == 0) { m_State = SELENDDOCEND; hr = m_pRangeSelExpand->collapse(VARIANT_TRUE); if(FAILED(hr)) goto error; } else m_State = SEL;
// make sure we backup over any abbreviations
// it would be nice if Trident could do this!
{ hr = m_pMarkup->CreateMarkupPointer(&pRangeStart); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeEnd); if (FAILED(hr)) goto error;
hr = m_pMarkup->CreateMarkupPointer(&pRangeTemp); if (FAILED(hr)) goto error;
hr = m_pMarkup->MovePointersToRange(m_pRangeSelExpand, pRangeStart, pRangeEnd); if (FAILED(hr)) goto error;
// first check to see if we have a character to the right or a '.'
// if not it's not an abbreviation
{ hr = pRangeTemp->MoveToPointer(pRangeStart); if (FAILED(hr)) goto error; while(TRUE) { cch = 1; hr = pRangeTemp->Right(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto noAbbreviation;
if (markupContext == CONTEXT_TYPE_Text) { WORD wType;
wType = GetWCharType(chText[0]); if ((C1_SPACE & wType) || ((C1_PUNCT & wType) && chText[0] != L'.')) goto noAbbreviation; }
cch = 1; hr = pRangeTemp->Right(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_Text) { hr = HrHasWhitespace(pRangeStart, pRangeTemp, &fResult); if (FAILED(hr)) goto error;
if (fResult) goto noAbbreviation; break; } } }
// now look for a period
{ processNextWord: hr = pRangeEnd->MoveToPointer(pRangeStart); if (FAILED(hr)) goto error;
hr = pRangeTemp->MoveToPointer(pRangeStart); if (FAILED(hr)) goto error; while(TRUE) { cch = 1; hr = pRangeTemp->Left(FALSE, &markupContext, NULL, &cch, chText); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_None) goto finishedAbbreviation;
if (markupContext == CONTEXT_TYPE_Text) { WORD wType;
wType = GetWCharType(chText[0]); if ((C1_SPACE & wType) || ((C1_PUNCT & wType) && chText[0] != L'.')) goto finishedAbbreviation; }
cch = 1; hr = pRangeTemp->Left(TRUE, NULL, NULL, &cch, NULL); if (FAILED(hr)) goto error;
if (markupContext == CONTEXT_TYPE_Text && chText[0] == L'.') { hr = pRangeTemp->MoveUnit(MOVEUNIT_PREVWORDBEGIN); if (FAILED(hr)) goto finishedAbbreviation;
hr = HrHasWhitespace(pRangeTemp, pRangeEnd, &fResult); if (FAILED(hr)) goto error;
if (fResult) goto finishedAbbreviation; pRangeStart->MoveToPointer(pRangeTemp); if (FAILED(hr)) goto error; goto processNextWord; } } }
finishedAbbreviation: hr = m_pMarkup->MovePointersToRange(m_pRangeSelExpand, pRangeTemp, pRangeEnd); if (FAILED(hr)) goto error;
// check to see if we had a selection
// if not be sure to set new selection correctly
hr = pRangeTemp->IsEqualTo(pRangeEnd, &fResult); if (FAILED(hr)) goto error;
hr = m_pMarkup->MoveRangeToPointers(pRangeStart, fResult ? pRangeStart : pRangeEnd, m_pRangeSelExpand); if (FAILED(hr)) goto error; noAbbreviation: ; }
m_pBodyElem->createTextRange(&m_pRangeSelEndDocEnd); if(!m_pRangeSelEndDocEnd) { hr = E_FAIL; goto error; }
m_pRangeSelEndDocEnd->duplicate(&m_pRangeDocStartSelStart); if(!m_pRangeDocStartSelStart) { hr = E_FAIL; goto error; }
hr = m_pRangeSelEndDocEnd->setEndPoint((BSTR)c_bstr_StartToEnd, m_pRangeSelExpand); if(FAILED(hr)) goto error;
hr = m_pRangeSelEndDocEnd->setEndPoint((BSTR)c_bstr_EndToEnd, pRangeDoc); if(FAILED(hr)) goto error;
hr = m_pRangeDocStartSelStart->setEndPoint((BSTR)c_bstr_StartToStart, pRangeDoc); if(FAILED(hr)) goto error;
hr = m_pRangeDocStartSelStart->setEndPoint((BSTR)c_bstr_EndToStart, m_pRangeSelExpand); if(FAILED(hr)) goto error;
error: ReleaseObj(pRangeDoc); ReleaseObj(pID); ReleaseObj(pSel); SafeSysFreeString(bstr); SafeRelease(pRangeStart); SafeRelease(pRangeEnd); SafeRelease(pRangeTemp);
return hr; }
HRESULT CSpell::HrReplaceSel(LPSTR szWord) { HRESULT hr = NOERROR; BSTR bstrGet=0, bstrPut=0; INT cch; TCHAR szBuf[cchEditBufferMax]={0}; UINT uCodePage; LPSTR psz; BOOL fSquiggle=FALSE; LONG cb = 0;
if(!m_pRangeChecking || szWord==NULL) return E_INVALIDARG;
if (*szWord == 0) { hr = m_pRangeChecking->moveStart((BSTR)c_bstr_Character, -1, &cb); //If we failed to movestart, we just delete the word.
hr = m_pRangeChecking->put_text(L""); goto error; }
#ifdef BACKGROUNDSPELL
if (HrHasSquiggle(m_pRangeChecking)==S_OK) fSquiggle = TRUE; #endif // BACKGROUNDSPELL
hr = m_pRangeChecking->get_text(&bstrGet); if(!bstrGet || lstrlenW(bstrGet)==0) goto error;
uCodePage = GetCodePage();
cch = SysStringLen(bstrGet); if (!WideCharToMultiByte(uCodePage, 0, bstrGet, -1, szBuf, sizeof(szBuf), NULL, NULL)) { hr = E_FAIL; goto error; }
psz = StrChr(szBuf, ' '); if(psz) { TCHAR szPut[cchEditBufferMax]={0}; wnsprintf(szPut, ARRAYSIZE(szPut), c_szFmt, szWord, psz); hr = HrLPSZToBSTR(szPut, &bstrPut); } else hr = HrLPSZToBSTR(szWord, &bstrPut);
if (FAILED(hr)) goto error;
if (!fSquiggle) hr = m_pRangeChecking->put_text(bstrPut); else hr = m_pRangeChecking->pasteHTML(bstrPut);
if(FAILED(hr)) goto error;
error: if (SUCCEEDED(hr)) hr = HrUpdateSelection();
SysFreeString(bstrGet); SysFreeString(bstrPut); return hr; }
HRESULT CSpell::GetSelection(IHTMLTxtRange **ppRange) { IHTMLSelectionObject* pSel = NULL; IHTMLTxtRange *pTxtRange=0; IDispatch *pID=0; HRESULT hr=E_FAIL;
if (ppRange == NULL) return TraceResult(E_INVALIDARG);
*ppRange = NULL;
if(m_pDoc) { m_pDoc->get_selection(&pSel); if (pSel) { pSel->createRange(&pID); if (pID) { hr = pID->QueryInterface(IID_IHTMLTxtRange, (LPVOID *)ppRange); pID->Release(); } pSel->Release(); } } return hr; }
#ifdef BACKGROUNDSPELL
HRESULT CSpell::HrRegisterKeyPressNotify(BOOL fRegister) { IConnectionPointContainer * pCPContainer=0; IConnectionPoint * pCP=0; HRESULT hr;
Assert(m_pDoc)
hr = m_pDoc->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPContainer); if (FAILED(hr)) goto error;
hr = pCPContainer->FindConnectionPoint(DIID_HTMLDocumentEvents, &pCP); pCPContainer->Release(); if (FAILED(hr)) goto error;
if (fRegister) { Assert(0==m_dwCookieNotify); hr = pCP->Advise(this, &m_dwCookieNotify); if (FAILED(hr)) goto error; } else { if (m_dwCookieNotify) { hr = pCP->Unadvise(m_dwCookieNotify); if (FAILED(hr)) goto error; } } error: ReleaseObj(pCP); return hr; } #endif // BACKGROUNDSPELL
HRESULT CSpell::OnWMCommand(int id, IHTMLTxtRange *pTxtRange) { switch (id) { case idmSuggest0: case idmSuggest1: case idmSuggest2: case idmSuggest3: case idmSuggest4: HrReplaceBySuggest(pTxtRange, id-idmSuggest0); break; case idmIgnore: case idmIgnoreAll: case idmAdd: #ifdef BACKGROUNDSPELL
HrDeleteSquiggle(pTxtRange); #endif // BACKGROUNDSPELL
break; default: return S_FALSE; }
return S_OK; }
HRESULT CSpell::HrUpdateSelection() { HRESULT hr; VARIANT_BOOL fSuccess;
SafeRelease(m_pRangeSel); m_pRangeSelEndDocEnd->duplicate(&m_pRangeSel); if (!m_pRangeSel) { hr = E_FAIL; goto error; } hr = m_pRangeSel->setEndPoint((BSTR)c_bstr_EndToStart, m_pRangeSelEndDocEnd); if (FAILED(hr)) goto error;
hr = m_pRangeSel->setEndPoint((BSTR)c_bstr_StartToEnd, m_pRangeDocStartSelStart); if (FAILED(hr)) goto error;
SafeRelease(m_pRangeSelExpand); m_pRangeSel->duplicate(&m_pRangeSelExpand); if(!m_pRangeSelExpand) { hr = E_FAIL; goto error; }
hr = m_pRangeSelExpand->expand((BSTR)c_bstr_Word, &fSuccess); if(FAILED(hr)) goto error;
error: return hr; }
BOOL CSpell::FIgnoreNumber() { return (m_dwOpt & MESPELLOPT_IGNORENUMBER); }
BOOL CSpell::FIgnoreUpper() { return (m_dwOpt & MESPELLOPT_IGNOREUPPER); }
BOOL CSpell::FIgnoreDBCS() { return (m_dwOpt & MESPELLOPT_IGNOREDBCS); }
BOOL CSpell::FIgnoreProtect() { return (m_dwOpt & MESPELLOPT_IGNOREPROTECT); }
BOOL CSpell::FAlwaysSuggest() { return (m_dwOpt & MESPELLOPT_ALWAYSSUGGEST); }
BOOL CSpell::FCheckOnSend() { return (m_dwOpt & MESPELLOPT_CHECKONSEND); }
BOOL CSpell::FIgnoreURL() { return (m_dwOpt & MESPELLOPT_IGNOREURL); }
UINT CSpell::GetCodePage() { UINT uCodePage; TCHAR szBuf[cchEditBufferMax]={0};
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, szBuf, sizeof(szBuf))) uCodePage = StrToInt(szBuf); else uCodePage = CP_ACP;
return uCodePage; }
void DumpRange(IHTMLTxtRange *pRange) { #ifdef DEBUG
BSTR bstrGet=0;
if (!pRange) return; pRange->get_text(&bstrGet); SysFreeString(bstrGet); #endif
}
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) - 42208
// spell dll must exist
if (!PathFileExists(rgchBuf)) return TRUE;
// main dict must exist
if (!PathFileExists(szMdr)) return TRUE;
return FALSE; }
#ifdef BACKGROUNDSPELL
CSpellStack::CSpellStack() { m_cRef = 1; m_sp = -1; ZeroMemory(&m_rgStack, sizeof(CCell)*MAX_SPELLSTACK); }
CSpellStack::~CSpellStack() { while (m_sp>=0) { SafeRelease(m_rgStack[m_sp].pTextRange); m_sp--; } }
ULONG CSpellStack::AddRef() { return ++m_cRef; }
ULONG CSpellStack::Release() { if (--m_cRef==0) { delete this; return 0; } return m_cRef; }
HRESULT CSpellStack::HrGetRange(IHTMLTxtRange **ppTxtRange) { HRESULT hr;
Assert(ppTxtRange); *ppTxtRange = 0; if (m_sp < 0) return E_FAIL;
*ppTxtRange = m_rgStack[m_sp].pTextRange; if (*ppTxtRange) (*ppTxtRange)->AddRef();
return NOERROR; }
HRESULT CSpellStack::push(IHTMLTxtRange *pTxtRange) { HRESULT hr; BSTR bstr=0;
Assert(m_sp >= -1 && m_sp <= (MAX_SPELLSTACK-2));
if (pTxtRange == NULL) return E_INVALIDARG;
hr = pTxtRange->get_text(&bstr); if (FAILED(hr) || bstr==NULL || *bstr==L'\0' || *bstr==L' ') { Assert(0); goto error; }
m_sp++; m_rgStack[m_sp].pTextRange = pTxtRange; pTxtRange->AddRef();
error: SafeSysFreeString(bstr); return NOERROR; }
HRESULT CSpellStack::pop() { if (m_sp < 0) return NOERROR;
Assert(m_sp>=0 && m_sp<=(MAX_SPELLSTACK-1));
SafeRelease(m_rgStack[m_sp].pTextRange); m_sp--;
return NOERROR; }
BOOL CSpellStack::fEmpty() { Assert(m_sp>=-1 && m_sp<=(MAX_SPELLSTACK-1));
if (m_sp < 0) return TRUE; else return FALSE; } #endif // BACKGROUNDSPELL
WORD GetWCharType(WCHAR wc) { BOOL fResult; WORD wResult;
fResult = GetStringTypeExWrapW(CP_ACP, CT_CTYPE1, &wc, 1, &wResult); if (FALSE == fResult) return 0; else return wResult; }
/*******************************************************************
NAME: OpenDirectory SYNOPSIS: checks for existence of directory, if it doesn't exist it is created ********************************************************************/ HRESULT OpenDirectory(TCHAR *szDir) { TCHAR *sz, ch; HRESULT hr; Assert(szDir != NULL); hr = S_OK; if (!CreateDirectory(szDir, NULL) && ERROR_ALREADY_EXISTS != GetLastError()) { Assert(szDir[1] == TEXT(':')); Assert(szDir[2] == TEXT('\\')); sz = &szDir[3]; while (TRUE) { while (*sz != 0) { if (!IsDBCSLeadByte(*sz)) { if (*sz == TEXT('\\')) break; } sz = CharNext(sz); } ch = *sz; *sz = 0; if (!CreateDirectory(szDir, NULL)) { if (GetLastError() != ERROR_ALREADY_EXISTS) { hr = E_FAIL; *sz = ch; break; } } *sz = ch; if (*sz == 0) break; sz++; } } return(hr); }
HRESULT CSpell::_EnsureInited() { HRESULT hr=S_OK;
if (m_pMarkup == NULL) { hr = m_pDoc->QueryInterface(IID_IMarkupServices, (LPVOID *)&m_pMarkup); if (FAILED(hr)) goto error; } if (m_pBodyElem == NULL) { hr = HrGetBodyElement(m_pDoc, &m_pBodyElem); if (FAILED(hr)) goto error; }
error: return hr; }
|