Rich Edit EM_SETPARAFORMAT fails when text mode is TM_PLAINTEXT

141 Views Asked by At

EDIT: this question is significantly edited based on further investigation of the problem.

I am working on a program API that displays programmatically created rich edit controls. It allows the caller to specify whether to use plain text or rich text like this:

void SetUseRichText(bool state)
{
    DWORD textMode = SendDlgItemMessageW(GetWindowHandle(), GetControlID(), EM_GETTEXTMODE, 0, 0);
    if (state)
    {
        textMode &= ~TM_PLAINTEXT;
        textMode |= TM_RICHTEXT;
    }
    else
    {
        textMode &= ~TM_RICHTEXT;
        textMode |= TM_PLAINTEXT;
    }
    SendDlgItemMessageW(GetWindowHandle(), GetControlID(), EM_SETTEXTMODE, textMode, 0);
}

The primary goal of this setting is to prevent text in the control from picking up the formatting of text pasted into the control. It would be nice if the program itself could modify the formatting beyond the font (which it can and does modify).

I have run into an issue where I would like to be able to control the line spacing of the text in the control. I have this code to do it:

    PARAFORMAT2 pf{};
    pf.cbSize = sizeof(pf);
    pf.dwMask = PFM_LINESPACING;
    pf.bLineSpacingRule = value ? 3 : 0; // use twips, but no smaller than single-space
    pf.dyLineSpacing = std::lround(value * 20.0);
    SendDlgItemMessageW(GetWindowHandle(), GetControlID(), EM_SETPARAFORMAT, 0, reinterpret_cast<LPARAM>(&pf));

The problem is that if the caller has set the control to TM_PLAINTEXT, then EM_SETPARAFORMAT does not work. (The SendMessage returns 0.) I guess my quesion is multi-part.

  • Is there a way to control the line spacing of a TM_PLAINTEXT rich edit control? Perhaps some way that is not using messages specific to the control?
  • Given that TM_PLAINTEXT and TM_RICHTEXT are bit-values, what does it mean of both are set? (Or if neither are set?)
  • Should I take a different approach to prevent formatting from being pasted in?
1

There are 1 best solutions below

12
Torrecto - MSFT On

About setting TM_PLAINTEXT and TM_RICHTEXT.

I found a mistake If you want to set TM_RICHTEXT and TM_PLAINTEXT on text, you need use CHARFORMAT2W. PARAFORMAT2 just set the paragraph formatting. I already tested it. enter image description here

If you set CHARFORMAT2W. It always displays character formatting of a rich edit control. Whatever you set one of them, both of them and none. enter image description here

It also can change the line-spacing when richtext and plaintext exist. enter image description here

Here is my code, hope it helpful.(Modified)

#include <windows.h>
#include <richedit.h>
#include <commctrl.h>
static LRESULT CALLBACK WndProc
(
    HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
)
{
    switch (message)
    {
    case WM_CREATE:
    {
        // Must load rich edit library
    }
    case WM_SETTEXT:
    {
        LoadLibrary(L"riched20.dll");

        HWND hWndRichEdit;
        hWndRichEdit = CreateWindow(RICHEDIT_CLASS, NULL,
            WS_CHILD | ES_SAVESEL | ES_NOHIDESEL | WS_CHILDWINDOW | WS_BORDER
            | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL | WS_EX_STATICEDGE,
            0, 0, 300, 200, hWnd, 0, GetModuleHandle(0), 0);

        CHARFORMAT cf;
        ZeroMemory(&cf, sizeof(CHARFORMAT));

        PARAFORMAT2 pf;
        pf.cbSize = sizeof(PARAFORMAT2); 
        pf.dwMask = PFM_LINESPACING;
        pf.dyLineSpacing = 600; //
        pf.bLineSpacingRule = 4;

        LRESULT res3 = SendMessage(hWndRichEdit, EM_SETPARAFORMAT, 0, LPARAM(&pf));     
        LRESULT res4 = SendMessage(hWndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, (LPARAM)&cf);
        LRESULT res5 = SendMessage(hWndRichEdit, EM_REPLACESEL, 0, (LPARAM)L"555");
        return 0;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}
int APIENTRY wWinMain
(
    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR lpCmdLine,
    _In_ int nCmdShow
)
{
    wchar_t szAppName[] = L"TestRicheditCharFormat";
    WNDCLASSEX wndclass;

    wndclass.cbSize = sizeof(wndclass);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = GetModuleHandle(0);
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszClassName = szAppName;
    wndclass.lpszMenuName = NULL;
    RegisterClassEx(&wndclass);

    HWND hWnd = CreateWindow(szAppName, L"Hello, world!", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
        NULL, NULL, GetModuleHandle(0), NULL);

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}

Edit:New rules as you said:enter image description here Also modified the code.