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.

1257 lines
32 KiB

  1. #include <pch.hxx>
  2. #include "dllmain.h"
  3. #include "demand.h"
  4. #include "resource.h"
  5. #include "viewsrc.h"
  6. #include "util.h"
  7. #define idTimerEditChange 401
  8. /////////////////////////////////////////////////////////////////////////////
  9. // Parsing constants
  10. // Ignore all <'s and >'s in the following environments:
  11. // Script <script> here </script>
  12. // Denali <% here %>
  13. // Comment <!-- here -->
  14. // String literal < ... "here" ... >
  15. // (as tag attribute) < ... 'here' ... >
  16. static enum
  17. {
  18. ENV_NORMAL = 0, // normal
  19. ENV_COMMENT = 1, // ignore <'s and >'s
  20. ENV_QUOTE = 2, // " "
  21. ENV_SCRIPT = 3, // " "
  22. ENV_DENALI = 4, // " "
  23. ENV_QUOTE_SCR= 5, // " "; string literal in SCRIPT tag
  24. };
  25. static const char QUOTE_1 = '\'';
  26. static const char QUOTE_2 = '\"';
  27. HRESULT CALLBACK FreeViewSrcDataObj(PDATAOBJINFO pDataObjInfo, DWORD celt)
  28. {
  29. // Loop through the data and free it all
  30. if (pDataObjInfo)
  31. {
  32. for (DWORD i = 0; i < celt; i++)
  33. SafeMemFree(pDataObjInfo[i].pData);
  34. SafeMemFree(pDataObjInfo);
  35. }
  36. return S_OK;
  37. }
  38. HRESULT ViewSource(HWND hwndParent, IMimeMessage *pMsg)
  39. {
  40. CViewSource *pViewSrc=0;
  41. HRESULT hr;
  42. TraceCall("MimeEditViewSource");
  43. if (!DemandLoadRichEdit())
  44. return TraceResult(MIMEEDIT_E_LOADLIBRARYFAILURE);
  45. pViewSrc = new CViewSource();
  46. if (!pViewSrc)
  47. return E_OUTOFMEMORY;
  48. hr = pViewSrc->Init(hwndParent, pMsg);
  49. if (FAILED(hr))
  50. goto exit;
  51. hr = pViewSrc->Show();
  52. if (FAILED(hr))
  53. goto exit;
  54. // pViewSrc will maintain it's own refcount and self-destruct on close
  55. exit:
  56. ReleaseObj(pViewSrc);
  57. return hr;
  58. }
  59. CViewSource::CViewSource()
  60. {
  61. m_hwnd = NULL;
  62. m_hwndEdit = NULL;
  63. m_pMsg = NULL;
  64. m_cRef = 1;
  65. }
  66. CViewSource::~CViewSource()
  67. {
  68. SafeRelease(m_pMsg);
  69. }
  70. ULONG CViewSource::AddRef()
  71. {
  72. return ++m_cRef;
  73. }
  74. ULONG CViewSource::Release()
  75. {
  76. if (--m_cRef == 0)
  77. {
  78. delete this;
  79. return 0;
  80. }
  81. return m_cRef;
  82. }
  83. HRESULT CViewSource::Init(HWND hwndParent, IMimeMessage *pMsg)
  84. {
  85. ReplaceInterface(m_pMsg, pMsg);
  86. if (!CreateDialogParam(g_hLocRes, MAKEINTRESOURCE(iddMsgSource), hwndParent, CViewSource::_ExtDlgProc, (LPARAM)this))
  87. return E_OUTOFMEMORY;
  88. return S_OK;
  89. }
  90. HRESULT CViewSource::Show()
  91. {
  92. ShowWindow(m_hwnd, SW_SHOW);
  93. return S_OK;
  94. }
  95. INT_PTR CALLBACK CViewSource::_ExtDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  96. {
  97. CViewSource *pThis = (CViewSource *)GetWindowLongPtr(hwnd, DWLP_USER);
  98. if (msg == WM_INITDIALOG)
  99. {
  100. pThis = (CViewSource *)lParam;
  101. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  102. }
  103. return pThis ? pThis->_DlgProc(hwnd, msg, wParam, lParam) : FALSE;
  104. }
  105. INT_PTR CViewSource::_DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  106. {
  107. LPSTREAM pstm;
  108. CHARFORMAT cf;
  109. BODYOFFSETS rOffset;
  110. CREMenu *pMenu;
  111. switch(msg)
  112. {
  113. case WM_INITDIALOG:
  114. m_hwnd = hwnd;
  115. m_hwndEdit=GetDlgItem(hwnd, idcTxtSource);
  116. DllAddRef();
  117. AddRef();
  118. if (m_pMsg &&
  119. m_pMsg->GetMessageSource(&pstm, 0)==S_OK)
  120. {
  121. ZeroMemory((LPVOID)&cf, sizeof(CHARFORMAT));
  122. cf.cbSize = sizeof(CHARFORMAT);
  123. cf.dwMask = CFM_SIZE|CFM_COLOR|CFM_FACE|CFM_BOLD|
  124. CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
  125. StrCpyN(cf.szFaceName, TEXT("Courier New"), ARRAYSIZE(cf.szFaceName));
  126. cf.yHeight = 200;
  127. cf.crTextColor = 0;
  128. cf.dwEffects |= CFE_AUTOCOLOR;
  129. cf.bPitchAndFamily = FIXED_PITCH;
  130. cf.yOffset = 0;
  131. SendMessage(m_hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf);
  132. SendMessage(m_hwndEdit, EM_SETBKGNDCOLOR, 0, (LONG)GetSysColor(COLOR_3DFACE));
  133. SendMessage(m_hwndEdit, EM_SETLIMITTEXT, 0, 0x100000);
  134. pMenu = new CREMenu();
  135. if (pMenu)
  136. {
  137. pMenu->Init(m_hwndEdit, idmrCtxtViewSrc);
  138. SendMessage(m_hwndEdit, EM_SETOLECALLBACK, 0, (LPARAM)pMenu);
  139. pMenu->Release();
  140. }
  141. RicheditStreamIn(m_hwndEdit, pstm, SF_TEXT);
  142. _BoldKids();
  143. pstm->Release();
  144. }
  145. PostMessage(m_hwndEdit, EM_SETSEL, 0, 0);
  146. return TRUE;
  147. case WM_COMMAND:
  148. switch (GET_WM_COMMAND_ID(wParam, lParam))
  149. {
  150. case idmCopy:
  151. SendMessage(m_hwndEdit, WM_COPY, 0, 0);
  152. return TRUE;
  153. case idmSelectAll:
  154. Edit_SetSel(m_hwndEdit, 0, -1);
  155. return TRUE;
  156. }
  157. break;
  158. case WM_SIZE:
  159. SetWindowPos(m_hwndEdit,0,0,0,
  160. LOWORD(lParam), HIWORD(lParam),SWP_NOACTIVATE|SWP_NOZORDER);
  161. break;
  162. case WM_DESTROY:
  163. DllRelease();
  164. Release();
  165. break;
  166. case WM_CLOSE:
  167. DestroyWindow(hwnd);
  168. break;
  169. }
  170. return FALSE;
  171. }
  172. HRESULT CViewSource::_BoldKids()
  173. {
  174. HBODY hBody;
  175. FINDBODY fb={0};
  176. CHARFORMAT cf;
  177. BODYOFFSETS rOffset;
  178. ZeroMemory((LPVOID)&cf, sizeof(CHARFORMAT));
  179. cf.cbSize = sizeof(CHARFORMAT);
  180. cf.dwMask = CFM_BOLD|CFM_ITALIC;
  181. // bold the root
  182. m_pMsg->GetBodyOffsets(HBODY_ROOT, &rOffset);
  183. Edit_SetSel(m_hwndEdit, 0, rOffset.cbBodyStart);
  184. cf.dwEffects=CFE_BOLD;
  185. SendMessage(m_hwndEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  186. // bold the kids
  187. if (m_pMsg->FindFirst(&fb, &hBody)==S_OK)
  188. {
  189. do
  190. {
  191. // italic the boundaries and bold the headers
  192. m_pMsg->GetBodyOffsets(hBody, &rOffset);
  193. Edit_SetSel(m_hwndEdit, rOffset.cbBoundaryStart, rOffset.cbHeaderStart);
  194. cf.dwEffects=CFE_ITALIC;
  195. SendMessage(m_hwndEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  196. Edit_SetSel(m_hwndEdit, rOffset.cbHeaderStart, rOffset.cbBodyStart);
  197. cf.dwEffects=CFE_BOLD;
  198. SendMessage(m_hwndEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  199. }
  200. while (m_pMsg->FindNext(&fb, &hBody)==S_OK);
  201. }
  202. return S_OK;
  203. }
  204. CREMenu::CREMenu()
  205. {
  206. m_hwndEdit = NULL;
  207. m_cRef = 1;
  208. }
  209. CREMenu::~CREMenu()
  210. {
  211. }
  212. ULONG CREMenu::AddRef()
  213. {
  214. return ++m_cRef;
  215. }
  216. ULONG CREMenu::Release()
  217. {
  218. if (--m_cRef == 0)
  219. {
  220. delete this;
  221. return 0;
  222. }
  223. return m_cRef;
  224. }
  225. HRESULT CREMenu::QueryInterface(REFIID riid, LPVOID FAR * lplpObj)
  226. {
  227. *lplpObj = NULL;
  228. if (IsEqualIID(riid, IID_IUnknown))
  229. *lplpObj = (void*)(IUnknown*)this;
  230. else if (IsEqualIID(riid, IID_IRichEditOleCallback))
  231. *lplpObj = (void*)(IRichEditOleCallback*)this;
  232. else
  233. return E_NOINTERFACE;
  234. AddRef();
  235. return NOERROR;
  236. }
  237. HRESULT CREMenu::Init(HWND hwndEdit, int idMenu)
  238. {
  239. m_hwndEdit = hwndEdit;
  240. m_idMenu = idMenu;
  241. return S_OK;
  242. }
  243. HRESULT CREMenu::GetNewStorage (LPSTORAGE FAR * ppstg)
  244. {
  245. return E_NOTIMPL;
  246. }
  247. HRESULT CREMenu::GetInPlaceContext( LPOLEINPLACEFRAME *lplpFrame, LPOLEINPLACEUIWINDOW *lplpDoc,
  248. LPOLEINPLACEFRAMEINFO lpFrameInfo)
  249. {
  250. return E_NOTIMPL;
  251. }
  252. HRESULT CREMenu::ShowContainerUI(BOOL fShow)
  253. {
  254. return E_NOTIMPL;
  255. }
  256. HRESULT CREMenu::QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp)
  257. {
  258. return E_NOTIMPL;
  259. }
  260. HRESULT CREMenu::DeleteObject(LPOLEOBJECT lpoleobj)
  261. {
  262. return E_NOTIMPL;
  263. }
  264. HRESULT CREMenu::QueryAcceptData( LPDATAOBJECT pdataobj, CLIPFORMAT *pcfFormat, DWORD reco,
  265. BOOL fReally, HGLOBAL hMetaPict)
  266. {
  267. *pcfFormat = CF_TEXT;
  268. return S_OK;
  269. }
  270. HRESULT CREMenu::ContextSensitiveHelp(BOOL fEnterMode)
  271. {
  272. return E_NOTIMPL;
  273. }
  274. HRESULT CREMenu::GetClipboardData(CHARRANGE *pchrg, DWORD reco, LPDATAOBJECT *ppdataobj)
  275. {
  276. HRESULT hr;
  277. DATAOBJINFO *pDataInfo=NULL;
  278. FORMATETC fetc;
  279. TEXTRANGE txtRange;
  280. CHARRANGE chrg;
  281. LONG cchStart=0,
  282. cchEnd=0,
  283. cchMax=0,
  284. cchLen=0;
  285. LPSTR pszData=0;
  286. *ppdataobj = NULL;
  287. if (pchrg)
  288. {
  289. chrg = *pchrg;
  290. cchMax = (LONG) SendMessage(m_hwndEdit, WM_GETTEXTLENGTH, 0, 0);
  291. // validate the range
  292. chrg.cpMin = max(0, chrg.cpMin);
  293. chrg.cpMin = min(cchMax, chrg.cpMin);
  294. if(chrg.cpMax < 0 || chrg.cpMax > cchMax)
  295. chrg.cpMax = cchMax;
  296. }
  297. else
  298. {
  299. // if no charrange, then get the current selection
  300. SendMessage(m_hwndEdit, EM_GETSEL, (WPARAM)&cchStart, (LPARAM)&cchEnd);
  301. chrg.cpMin = cchStart;
  302. chrg.cpMax = cchEnd;
  303. }
  304. if (chrg.cpMin >= chrg.cpMax)
  305. {
  306. *ppdataobj = NULL;
  307. return chrg.cpMin == chrg.cpMax ? NOERROR : E_INVALIDARG;
  308. }
  309. cchLen = chrg.cpMax - chrg.cpMin;
  310. if (!MemAlloc((LPVOID *)&pszData, cchLen+1))
  311. {
  312. hr = E_OUTOFMEMORY;
  313. goto error;
  314. }
  315. txtRange.chrg = chrg;
  316. txtRange.lpstrText = pszData;
  317. SendMessage(m_hwndEdit, EM_GETTEXTRANGE, 0, (LPARAM)&txtRange);
  318. if (!MemAlloc((LPVOID*)&pDataInfo, sizeof(DATAOBJINFO)))
  319. {
  320. hr = E_OUTOFMEMORY;
  321. goto error;
  322. }
  323. SETDefFormatEtc(pDataInfo->fe, CF_TEXT, TYMED_HGLOBAL);
  324. pDataInfo->cbData = cchLen+1;
  325. pDataInfo->pData = pszData;
  326. hr = CreateDataObject(pDataInfo, 1, (PFNFREEDATAOBJ)FreeViewSrcDataObj, ppdataobj);
  327. if (FAILED(hr))
  328. goto error;
  329. pDataInfo = NULL; // freed by dataobject
  330. pszData = NULL;
  331. error:
  332. SafeMemFree(pszData);
  333. SafeMemFree(pDataInfo);
  334. return hr;
  335. }
  336. HRESULT CREMenu::GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect)
  337. {
  338. return E_NOTIMPL;
  339. }
  340. HRESULT CREMenu::GetContextMenu(WORD seltype, LPOLEOBJECT pOleObject, CHARRANGE *pchrg, HMENU *phMenu)
  341. {
  342. HMENU hMenu;
  343. if (!(hMenu=LoadPopupMenu(m_idMenu)))
  344. return E_OUTOFMEMORY;
  345. if (SendMessage(m_hwndEdit, EM_SELECTIONTYPE, 0, 0)==SEL_EMPTY)
  346. {
  347. EnableMenuItem(hMenu, idmCopy, MF_GRAYED|MF_BYCOMMAND);
  348. EnableMenuItem(hMenu, idmCut, MF_GRAYED|MF_BYCOMMAND);
  349. }
  350. if (GetWindowLong(m_hwndEdit, GWL_STYLE) & ES_READONLY)
  351. {
  352. EnableMenuItem(hMenu, idmCut, MF_GRAYED|MF_BYCOMMAND);
  353. EnableMenuItem(hMenu, idmPaste, MF_GRAYED|MF_BYCOMMAND);
  354. }
  355. *phMenu=hMenu;
  356. return S_OK;
  357. }
  358. ULONG CMsgSource::AddRef()
  359. {
  360. return ++m_cRef;
  361. };
  362. ULONG CMsgSource::Release()
  363. {
  364. m_cRef--;
  365. if (m_cRef == 0)
  366. {
  367. delete this;
  368. return 0;
  369. }
  370. return m_cRef;
  371. }
  372. CMsgSource::CMsgSource()
  373. {
  374. m_hwnd = 0;
  375. m_cRef = 1;
  376. m_fColor=0;
  377. m_fDisabled=0;
  378. m_pCmdTargetParent=0;
  379. m_pszLastText = 0;
  380. }
  381. CMsgSource::~CMsgSource()
  382. {
  383. SafeMemFree(m_pszLastText);
  384. }
  385. HRESULT CMsgSource::Init(HWND hwndParent, int id, IOleCommandTarget *pCmdTargetParent)
  386. {
  387. CHARFORMAT cf;
  388. CREMenu *pMenu;
  389. DemandLoadRichEdit();
  390. m_hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
  391. "RICHEDIT",
  392. NULL,
  393. WS_CHILD|WS_TABSTOP|ES_MULTILINE|ES_SAVESEL|ES_WANTRETURN|WS_VSCROLL|ES_AUTOVSCROLL,
  394. 0, 0, 0, 0,
  395. hwndParent,
  396. (HMENU)IntToPtr(id),
  397. g_hLocRes,
  398. NULL);
  399. if (!m_hwnd)
  400. return E_FAIL;
  401. ZeroMemory((LPVOID)&cf, sizeof(CHARFORMAT));
  402. cf.cbSize = sizeof(CHARFORMAT);
  403. cf.dwMask = CFM_SIZE|CFM_COLOR|CFM_FACE|CFM_BOLD|
  404. CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
  405. StrCpyN(cf.szFaceName, TEXT("Courier New"), ARRAYSIZE(cf.szFaceName));
  406. cf.yHeight = 200;
  407. cf.crTextColor = 0;
  408. cf.dwEffects |= CFE_AUTOCOLOR;
  409. cf.bPitchAndFamily = FIXED_PITCH;
  410. cf.bCharSet = DEFAULT_CHARSET;
  411. cf.yOffset = 0;
  412. SendMessage(m_hwnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf);
  413. SendMessage(m_hwnd, EM_SETEVENTMASK, 0, ENM_KEYEVENTS|ENM_CHANGE|ENM_SELCHANGE|ENM_UPDATE);
  414. SendMessage(m_hwnd, EM_SETOPTIONS, ECOOP_OR, ECO_SELECTIONBAR);
  415. pMenu = new CREMenu();
  416. if (pMenu)
  417. {
  418. pMenu->Init(m_hwnd, idmrCtxtViewSrc);
  419. SendMessage(m_hwnd, EM_SETOLECALLBACK, 0, (LPARAM)pMenu);
  420. pMenu->Release();
  421. }
  422. m_pCmdTargetParent = pCmdTargetParent; // loose reference, as parent never changes
  423. return S_OK;
  424. }
  425. HRESULT CMsgSource::Show(BOOL fOn, BOOL fColor)
  426. {
  427. ShowWindow(m_hwnd, fOn?SW_SHOW:SW_HIDE);
  428. m_fDisabled = !fColor;
  429. return S_OK;
  430. }
  431. HRESULT CMsgSource::Load(IStream *pstm)
  432. {
  433. RicheditStreamIn(m_hwnd, pstm, SF_TEXT);
  434. Edit_SetModify(m_hwnd, FALSE);
  435. return S_OK;
  436. }
  437. HRESULT CMsgSource::IsDirty()
  438. {
  439. return Edit_GetModify(m_hwnd) ? S_OK : S_FALSE;
  440. }
  441. HRESULT CMsgSource::Save(IStream **ppstm)
  442. {
  443. if (MimeOleCreateVirtualStream(ppstm)!=S_OK)
  444. return E_FAIL;
  445. RicheditStreamOut(m_hwnd, *ppstm, SF_TEXT);
  446. return S_OK;
  447. }
  448. HRESULT CMsgSource::SetRect(RECT *prc)
  449. {
  450. SetWindowPos(m_hwnd, 0, prc->left, prc->top, prc->right-prc->left, prc->bottom-prc->top, SWP_NOACTIVATE|SWP_NOZORDER);
  451. return S_OK;
  452. }
  453. HRESULT CMsgSource::QueryInterface(REFIID riid, LPVOID FAR *lplpObj)
  454. {
  455. if(!lplpObj)
  456. return E_INVALIDARG;
  457. *lplpObj = NULL; // set to NULL, in case we fail.
  458. if (IsEqualIID(riid, IID_IUnknown))
  459. *lplpObj = (LPVOID)(LPOLECOMMANDTARGET)this;
  460. else if (IsEqualIID(riid, IID_IOleCommandTarget))
  461. *lplpObj = (LPVOID)(LPOLECOMMANDTARGET)this;
  462. else
  463. return E_NOINTERFACE;
  464. AddRef();
  465. return NOERROR;
  466. }
  467. HRESULT CMsgSource::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  468. {
  469. ULONG uCmd;
  470. if (pguidCmdGroup == NULL)
  471. {
  472. for (uCmd=0;uCmd<cCmds; uCmd++)
  473. {
  474. prgCmds[uCmd].cmdf = 0;
  475. if (GetFocus() == m_hwnd)
  476. {
  477. switch (prgCmds[uCmd].cmdID)
  478. {
  479. case OLECMDID_CUT:
  480. case OLECMDID_COPY:
  481. if (SendMessage(m_hwnd, EM_SELECTIONTYPE, 0, 0)!=SEL_EMPTY)
  482. prgCmds[uCmd].cmdf = MSOCMDF_ENABLED;
  483. break;
  484. case OLECMDID_SELECTALL:
  485. prgCmds[uCmd].cmdf = MSOCMDF_ENABLED;
  486. break;
  487. case OLECMDID_UNDO:
  488. if (SendMessage(m_hwnd, EM_CANUNDO, 0, 0))
  489. prgCmds[uCmd].cmdf = MSOCMDF_ENABLED;
  490. break;
  491. case OLECMDID_PASTE:
  492. if (SendMessage(m_hwnd, EM_CANPASTE, 0, 0))
  493. prgCmds[uCmd].cmdf = MSOCMDF_ENABLED;
  494. break;
  495. }
  496. }
  497. }
  498. return S_OK;
  499. }
  500. else if (IsEqualGUID(*pguidCmdGroup, CMDSETID_MimeEdit))
  501. {
  502. // disable all these commands
  503. for (uCmd=0; uCmd < cCmds; uCmd++)
  504. {
  505. // bail if we see MECMDID_SHOWSOURCETABS and goto default handler
  506. if (prgCmds[uCmd].cmdID == MECMDID_SHOWSOURCETABS)
  507. return OLECMDERR_E_UNKNOWNGROUP;
  508. prgCmds[uCmd].cmdf = 0;
  509. }
  510. return S_OK;
  511. }
  512. else if (IsEqualGUID(*pguidCmdGroup, CMDSETID_Forms3))
  513. {
  514. // disable all these commands
  515. for (uCmd=0; uCmd < cCmds; uCmd++)
  516. {
  517. prgCmds[uCmd].cmdf = 0;
  518. }
  519. return S_OK;
  520. }
  521. return OLECMDERR_E_UNKNOWNGROUP;
  522. }
  523. HRESULT CMsgSource::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  524. {
  525. if (pguidCmdGroup == NULL)
  526. {
  527. switch (nCmdID)
  528. {
  529. case OLECMDID_CUT:
  530. SendMessage(m_hwnd, WM_CUT, 0, 0);
  531. return S_OK;
  532. case OLECMDID_COPY:
  533. SendMessage(m_hwnd, WM_COPY, 0, 0);
  534. return S_OK;
  535. case OLECMDID_PASTE:
  536. SendMessage(m_hwnd, WM_PASTE, 0, 0);
  537. return S_OK;
  538. case OLECMDID_SELECTALL:
  539. SendMessage(m_hwnd, EM_SETSEL, 0, -1);
  540. return S_OK;
  541. case OLECMDID_UNDO:
  542. SendMessage(m_hwnd, EM_UNDO, 0, 0);
  543. return S_OK;
  544. default:
  545. return OLECMDERR_E_NOTSUPPORTED;
  546. }
  547. }
  548. return OLECMDERR_E_UNKNOWNGROUP;
  549. }
  550. HRESULT CMsgSource::OnWMNotify(WPARAM wParam, NMHDR* pnmhdr, LRESULT *plRet)
  551. {
  552. MSGFILTER *pmf;
  553. *plRet = 0;
  554. if (pnmhdr->hwndFrom != m_hwnd)
  555. return S_FALSE;
  556. switch (pnmhdr->code)
  557. {
  558. case EN_MSGFILTER:
  559. {
  560. // if we get a control-tab, then richedit snags this and inserts a
  561. // tab char, we hook the wm_keydown and never pass to richedit
  562. if (((MSGFILTER *)pnmhdr)->msg == WM_KEYDOWN &&
  563. ((MSGFILTER *)pnmhdr)->wParam == VK_TAB &&
  564. (GetKeyState(VK_CONTROL) & 0x8000))
  565. {
  566. *plRet = TRUE;
  567. return S_OK;
  568. }
  569. }
  570. break;
  571. case EN_SELCHANGE:
  572. {
  573. if (m_pCmdTargetParent)
  574. m_pCmdTargetParent->Exec(NULL, OLECMDID_UPDATECOMMANDS, NULL, NULL, NULL);
  575. return S_OK;
  576. }
  577. }
  578. return S_FALSE;
  579. }
  580. static HACCEL g_hAccelSrc=0;
  581. HRESULT CMsgSource::TranslateAccelerator(LPMSG lpmsg)
  582. {
  583. MSG msg;
  584. if (GetFocus() != m_hwnd)
  585. return S_FALSE;
  586. if (!g_hAccelSrc) // cache this as NT4 SP3 leaks internal accerator tables
  587. g_hAccelSrc = LoadAccelerators(g_hLocRes, MAKEINTRESOURCE(idacSrcView));
  588. // see if it one of ours
  589. if (::TranslateAcceleratorWrapW(GetParent(m_hwnd), g_hAccelSrc, &msg))
  590. return S_OK;
  591. // insert tabs
  592. if (lpmsg->message == WM_KEYDOWN &&
  593. lpmsg->wParam == VK_TAB &&
  594. !(GetKeyState(VK_CONTROL) & 0x8000) &&
  595. !(GetKeyState(VK_SHIFT) & 0x8000))
  596. {
  597. Edit_ReplaceSel(m_hwnd, TEXT("\t"));
  598. return S_OK;
  599. }
  600. return S_FALSE;
  601. }
  602. HRESULT CMsgSource::OnWMCommand(HWND hwnd, int id, WORD wCmd)
  603. {
  604. if (GetFocus() == m_hwnd)
  605. {
  606. // context menu commands
  607. switch (id)
  608. {
  609. case idmTab:
  610. Edit_ReplaceSel(m_hwnd, TEXT("\t"));
  611. return S_OK;
  612. case idmCopy:
  613. SendMessage(m_hwnd, WM_COPY, 0, 0);
  614. return S_OK;
  615. case idmPaste:
  616. SendMessage(m_hwnd, WM_PASTE, 0, 0);
  617. return S_OK;
  618. case idmCut:
  619. SendMessage(m_hwnd, WM_CUT, 0, 0);
  620. return S_OK;
  621. case idmUndo:
  622. SendMessage(m_hwnd, EM_UNDO, 0, 0);
  623. return S_OK;
  624. case idmSelectAll:
  625. SendMessage(m_hwnd, EM_SETSEL, 0, -1);
  626. return S_OK;
  627. }
  628. }
  629. if (hwnd != m_hwnd) // not our window
  630. return S_FALSE;
  631. if (wCmd == EN_CHANGE)
  632. {
  633. OnChange();
  634. return S_OK;
  635. }
  636. return S_FALSE;
  637. }
  638. HRESULT CMsgSource::HasFocus()
  639. {
  640. return GetFocus() == m_hwnd ? S_OK : S_FALSE;
  641. }
  642. HRESULT CMsgSource::SetFocus()
  643. {
  644. ::SetFocus(m_hwnd);
  645. return S_OK;
  646. }
  647. void CMsgSource::OnChange()
  648. {
  649. // batch up the change commands with a timer
  650. if (!m_fColor)
  651. {
  652. KillTimer(GetParent(m_hwnd), idTimerEditChange);
  653. SetTimer(GetParent(m_hwnd), idTimerEditChange, 200, NULL);
  654. }
  655. }
  656. HRESULT CMsgSource::OnTimer(WPARAM idTimer)
  657. {
  658. CHARFORMAT cf;
  659. int inTag = 0;
  660. BOOL pastTag = FALSE;
  661. COLORREF crTag = RGB(0x80, 0, 0x80);
  662. COLORREF crInTag = RGB(0xFF, 0, 0);
  663. COLORREF crNormal = RGB(0, 0, 0);
  664. COLORREF crLiteral = RGB(0, 0, 0xFF);
  665. COLORREF crHere;
  666. COLORREF crLast = crNormal;
  667. int i, n;
  668. int nChange=0;
  669. BOOL bHidden = FALSE;
  670. CHARRANGE cr;
  671. int ignoreTags = ENV_NORMAL;
  672. char quote_1 = QUOTE_1;
  673. char quote_2 = QUOTE_2;
  674. BOOL fRestoreScroll=FALSE,
  675. fShowProgress=FALSE;
  676. DWORD dwStartTime = GetTickCount();
  677. HCURSOR hCur = NULL;
  678. DWORD dwProgress=0,
  679. dwTmp;
  680. VARIANTARG va;
  681. TCHAR rgch[CCHMAX_STRINGRES],
  682. rgchFmt[CCHMAX_STRINGRES];
  683. LPSTR pszText=0;
  684. int cch;
  685. BOOL fSetTimer=FALSE;
  686. // Save modificationness
  687. BOOL bModified = Edit_GetModify(m_hwnd);
  688. if (idTimer!=idTimerEditChange)
  689. return S_FALSE;
  690. // Kill outstanding timer
  691. KillTimer(GetParent(m_hwnd), idTimerEditChange);
  692. //
  693. // If the user is mousing around (say for scrolling) then don't drag down
  694. // his performance!
  695. //
  696. if (GetCapture())
  697. {
  698. SetTimer(GetParent(m_hwnd), idTimerEditChange, 200, NULL);
  699. return S_OK;
  700. }
  701. // Turn off the color syntax
  702. if (m_fDisabled)
  703. {
  704. // Already all one color
  705. m_fColor = TRUE;
  706. // Save current selection and hide
  707. GetSel(&cr);
  708. HideSelection(TRUE, FALSE);
  709. bHidden = TRUE;
  710. SetSel(0, -1); // select all
  711. GetSelectionCharFormat(&cf);
  712. cf.dwMask = CFM_COLOR;
  713. cf.dwEffects = 0;
  714. cf.crTextColor = crNormal;
  715. SetSelectionCharFormat(&cf);
  716. }
  717. else
  718. {
  719. // Start color fiddling
  720. // Get text, find the change
  721. if (_GetText(&pszText)!=S_OK)
  722. return E_FAIL;
  723. const char* start = (const char*)pszText;
  724. const char* old = (const char*) m_pszLastText;
  725. const char* s;
  726. for (s = start; *s && old && *old && *s == *old; s++, old++)
  727. continue;
  728. // If no change, nothing to do
  729. if (*s == 0)
  730. {
  731. MemFree(pszText);
  732. return S_OK;
  733. }
  734. // Otherwise, track place where we'll start to examine colors for changes
  735. nChange = (int) (s - start);
  736. // Only examine 2000 chars at a time
  737. if (lstrlen(s) > 2000)
  738. {
  739. // Reset timer to process other characters
  740. fSetTimer = TRUE;
  741. // Truncate text so we only examine limited amount
  742. cch = lstrlen(pszText);
  743. cch = min(cch, nChange + 2000);
  744. pszText[cch] = 0;
  745. start = (const char*)pszText;
  746. }
  747. SafeMemFree(m_pszLastText);
  748. m_pszLastText = pszText;
  749. m_fColor = TRUE;
  750. // Workaround for scrolling bug in REC 1.0
  751. if (GetFocus() == m_hwnd)
  752. {
  753. SendMessage(m_hwnd, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
  754. // BUGBUG: richedit1.0 on NT4 will remove the WS_VISIBLE bit when XORing ECO_AUTOVSCROLL
  755. // call show window after this to esure that the visible bit is displayed
  756. ShowWindow(m_hwnd, SW_SHOW);
  757. fRestoreScroll=TRUE;
  758. }
  759. const char* range = start;
  760. for (s = start; *s; s++)
  761. {
  762. // if we've been going for >2 seconds then show an hourglass and
  763. // start showing progress
  764. if (hCur == NULL &&
  765. GetTickCount() >= dwStartTime + 2000)
  766. {
  767. hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  768. if (m_pCmdTargetParent)
  769. {
  770. fShowProgress=TRUE;
  771. *rgchFmt=NULL;
  772. LoadString(g_hLocRes, idsColorSourcePC, rgchFmt, ARRAYSIZE(rgchFmt));
  773. }
  774. }
  775. if (fShowProgress)
  776. {
  777. dwTmp = (DWORD) ((((s - start))*100)/cch);
  778. if (dwTmp > dwProgress)
  779. {
  780. // did overall percentage change, if so update statusbar
  781. dwProgress = dwTmp;
  782. wnsprintf(rgch, ARRAYSIZE(rgch), rgchFmt, dwProgress);
  783. va.vt = VT_BSTR;
  784. if (HrLPSZToBSTR(rgch, &va.bstrVal)==S_OK)
  785. {
  786. m_pCmdTargetParent->Exec(NULL, OLECMDID_SETPROGRESSTEXT, 0, &va, NULL);
  787. SysFreeString(va.bstrVal);
  788. }
  789. }
  790. }
  791. // entering/leaving string literal in tag
  792. if (inTag && (*s == quote_1 || *s == quote_2))
  793. {
  794. if (ignoreTags == ENV_QUOTE ||
  795. ignoreTags == ENV_QUOTE_SCR) //leaving
  796. {
  797. ignoreTags = (ignoreTags == ENV_QUOTE) ?
  798. ENV_NORMAL : ENV_SCRIPT;
  799. quote_1 = QUOTE_1;
  800. quote_2 = QUOTE_2;
  801. }
  802. else if (ignoreTags == ENV_NORMAL) // entering
  803. {
  804. ignoreTags = ENV_QUOTE;
  805. quote_1 = quote_2 = *s;
  806. }
  807. else if (ignoreTags == ENV_SCRIPT) // entering
  808. {
  809. ignoreTags = ENV_QUOTE_SCR;
  810. quote_1 = quote_2 = *s;
  811. }
  812. }
  813. // Update leaving tag
  814. else if (*s == '>')
  815. {
  816. switch (ignoreTags) // end of env?
  817. {
  818. case ENV_DENALI:
  819. if (s-1>=start && *(s-1) == '%')
  820. ignoreTags = ENV_NORMAL;
  821. break;
  822. case ENV_COMMENT:
  823. if (s-2>=start && *(s-1) == '-' && *(s-2) == '-')
  824. ignoreTags = ENV_NORMAL;
  825. break;
  826. case ENV_SCRIPT:
  827. if (s-7>=start &&
  828. StrCmpNIA(s-7, "/SCRIPT", 7)==0)
  829. {
  830. ignoreTags = ENV_NORMAL;
  831. // Color </SCRIPT> properly
  832. pastTag = TRUE;
  833. inTag = 0;
  834. s-=8;
  835. }
  836. else // end of <script ...>
  837. inTag = 0;
  838. break;
  839. default: // <SCRIPT> (no attribs)
  840. if (inTag && s-7>=start &&
  841. StrCmpNIA(s-7, "<SCRIPT", 7)==0)
  842. {
  843. ignoreTags = ENV_SCRIPT;
  844. pastTag = TRUE;
  845. inTag = 0;
  846. }
  847. }
  848. if (ignoreTags == ENV_NORMAL)
  849. {
  850. pastTag = TRUE;
  851. inTag--;
  852. if (inTag < 0)
  853. inTag = 0;
  854. }
  855. }
  856. // Check color
  857. crHere = inTag ?
  858. (pastTag ?
  859. ( (*s != '\"' &&
  860. (ignoreTags == ENV_QUOTE || ignoreTags == ENV_QUOTE_SCR)
  861. ) ?
  862. crLiteral : crInTag )
  863. : crTag)
  864. : crNormal;
  865. // If different from last, need to update previous range
  866. if (crHere != crLast)
  867. {
  868. i = (int) (range - start);
  869. n = (int)(s - range);
  870. if (i+n >= nChange)
  871. {
  872. if (!bHidden)
  873. {
  874. // Save current selection and hide
  875. GetSel(&cr);
  876. HideSelection(TRUE, FALSE);
  877. bHidden = TRUE;
  878. }
  879. SetSel(i, i+n);
  880. GetSelectionCharFormat(&cf);
  881. // If color over range varies or doesn't match, need to apply color
  882. if ((cf.dwMask & CFM_COLOR) == 0 || cf.crTextColor != crLast)
  883. {
  884. cf.dwMask = CFM_COLOR;
  885. cf.dwEffects = 0;
  886. cf.crTextColor = crLast;
  887. SetSelectionCharFormat(&cf);
  888. }
  889. }
  890. // Reset range
  891. range = s;
  892. crLast = crHere;
  893. }
  894. // Now update entering tag
  895. if (*s == '<' && ignoreTags == ENV_NORMAL)
  896. {
  897. inTag++;
  898. if (inTag == 1)
  899. pastTag = FALSE;
  900. }
  901. else if (inTag && !pastTag && isspace(*s))
  902. {
  903. pastTag = TRUE;
  904. if (s-1 >= start && *(s-1) == '%')
  905. ignoreTags = ENV_DENALI;
  906. else if (s-3 >= start && *(s-1) == '-'
  907. && *(s-2) == '-' && *(s-3) == '!')
  908. ignoreTags = ENV_COMMENT;
  909. else if (inTag && s-7>=start &&
  910. StrCmpNIA(s-7, "<SCRIPT", 7)==0)
  911. ignoreTags = ENV_SCRIPT;
  912. }
  913. }
  914. // Make sure last range is right
  915. i = (int) (range - start);
  916. n = (int) (s - range);
  917. if (i+n >= nChange)
  918. {
  919. if (!bHidden)
  920. {
  921. // Save current selection and hide
  922. GetSel(&cr);
  923. HideSelection(TRUE, FALSE);
  924. bHidden = TRUE;
  925. }
  926. SetSel(i, i+n);
  927. GetSelectionCharFormat(&cf);
  928. // If color over range varies or doesn't match, need to apply color
  929. if ((cf.dwMask & CFM_COLOR) == 0 || cf.crTextColor != crLast)
  930. {
  931. cf.dwMask = CFM_COLOR;
  932. cf.dwEffects = 0;
  933. cf.crTextColor = crLast;
  934. SetSelectionCharFormat(&cf);
  935. }
  936. }
  937. // Workaround for scrolling bug in REC 1.0
  938. if (fRestoreScroll)
  939. {
  940. // BUGBUG: richedit1.0 on NT4 will remove the WS_VISIBLE bit when ORing ECO_AUTOVSCROLL
  941. // call show window after this to esure that the visible bit is displayed
  942. SendMessage(m_hwnd, EM_SETOPTIONS, ECOOP_OR, ECO_AUTOVSCROLL);
  943. ShowWindow(m_hwnd, SW_SHOW);
  944. }
  945. } // End color fiddling
  946. // Restore selection visibility
  947. if (bHidden)
  948. {
  949. SetSel(cr.cpMin, cr.cpMax);
  950. HideSelection(FALSE, FALSE);
  951. }
  952. // Restore modificationness
  953. if (!bModified)
  954. Edit_SetModify(m_hwnd, bModified);
  955. if (fShowProgress)
  956. {
  957. va.vt = VT_BSTR;
  958. va.bstrVal=NULL;
  959. m_pCmdTargetParent->Exec(NULL, OLECMDID_SETPROGRESSTEXT, 0, &va, NULL);
  960. }
  961. if (hCur)
  962. SetCursor(hCur);
  963. m_fColor = FALSE;
  964. if (fSetTimer)
  965. SetTimer(GetParent(m_hwnd), idTimerEditChange, 200, NULL);
  966. return S_OK;
  967. }
  968. void CMsgSource::HideSelection(BOOL fHide, BOOL fChangeStyle)
  969. {
  970. SendMessage(m_hwnd, EM_HIDESELECTION, fHide, fChangeStyle);
  971. }
  972. void CMsgSource::GetSel(CHARRANGE *pcr)
  973. {
  974. SendMessage(m_hwnd, EM_EXGETSEL, 0, (LPARAM)pcr);
  975. }
  976. void CMsgSource::SetSel(int nStart, int nEnd)
  977. {
  978. SendMessage(m_hwnd, EM_SETSEL, nStart, nEnd);
  979. }
  980. extern BOOL g_fCanEditBiDi;
  981. void CMsgSource::GetSelectionCharFormat(CHARFORMAT *pcf)
  982. {
  983. pcf->cbSize = sizeof(CHARFORMAT);
  984. pcf->dwMask = CFM_BOLD|CFM_COLOR|CFM_FACE|CFM_ITALIC|CFM_OFFSET|CFM_PROTECTED|CFM_SIZE|CFM_STRIKEOUT|CFM_UNDERLINE;
  985. SendMessage(m_hwnd, EM_GETCHARFORMAT, TRUE, (LPARAM)pcf);
  986. // On BiDi win9x, DEFAULT_CHARSET is treated as ANSI !!
  987. // need to reassign charset (Arabic for Arabic and Hebrew for Hebrew)
  988. if(g_fCanEditBiDi && (!pcf->bCharSet || pcf->bCharSet == DEFAULT_CHARSET))
  989. {
  990. // The best way to determine the OS language is from system font charset
  991. LOGFONT lfSystem;
  992. static BYTE lfCharSet = 0 ; // RunOnce
  993. if(!lfCharSet && GetObject(GetStockObject(SYSTEM_FONT), sizeof(lfSystem), (LPVOID)& lfSystem))
  994. {
  995. if (lfSystem.lfCharSet == ARABIC_CHARSET
  996. || lfSystem.lfCharSet == HEBREW_CHARSET)
  997. {
  998. lfCharSet = lfSystem.lfCharSet; // Arabic/Hebrew charset for Arabic/Hebrew OS
  999. }
  1000. }
  1001. pcf->bCharSet = lfCharSet;
  1002. }
  1003. }
  1004. void CMsgSource::SetSelectionCharFormat(CHARFORMAT *pcf)
  1005. {
  1006. pcf->cbSize = sizeof(CHARFORMAT);
  1007. SendMessage(m_hwnd, EM_SETCHARFORMAT, TRUE, (LPARAM)pcf);
  1008. }
  1009. HRESULT CMsgSource::SetDirty(BOOL fDirty)
  1010. {
  1011. Edit_SetModify(m_hwnd, fDirty);
  1012. return S_OK;
  1013. }
  1014. HRESULT CMsgSource::_GetText(LPSTR *ppsz)
  1015. {
  1016. LPSTR psz;
  1017. int cch;
  1018. *ppsz = 0;
  1019. cch = GetWindowTextLength(m_hwnd);
  1020. if (!MemAlloc((LPVOID *)&psz, sizeof(TCHAR) * cch+1))
  1021. return E_OUTOFMEMORY;
  1022. *psz = 0;
  1023. GetWindowText(m_hwnd, psz, cch);
  1024. *ppsz = psz;
  1025. return S_OK;
  1026. }