You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinAPI C语言创建RichEdit时修改行距及相关问题咨询

问题解决与代码修正

核心错误:误用普通EDIT控件而非RichEdit控件

你代码中创建的是普通EDIT控件(类名"EDIT"),而普通EDIT控件不支持PARAFORMAT2结构和EM_SETPARAFORMAT消息,这是行距修改无效的根本原因。必须将控件类名改为RichEdit对应的类名:

  • ANSI版本:"RichEdit20A"
  • 宽字符版本:"RichEdit20W"

LoadLibrary("riched20.dll")的必要性

是必要的。RichEdit控件的窗口类并非系统默认注册,必须先加载riched20.dll(或更高版本如riched32.dll、msftedit.dll)才能完成类注册,否则CreateWindowEx创建RichEdit控件会失败。建议保存模块句柄并在程序退出时释放,避免内存泄漏:

HMODULE hRichEdit = LoadLibrary("riched20.dll");
// ... 程序逻辑 ...
FreeLibrary(hRichEdit);

行距修改函数(LSpaceA、LSpaceB)修正

要正确设置行距,需结合bLineSpacingRule和dyLineSpacing,同时确保dwMask覆盖必要的格式位。建议先获取当前段落格式再修改,避免丢失原有设置:

修正后的LSpaceA(固定行距示例)

void LSpaceA()
{
    PARAFORMAT2 pf2 = {0};
    pf2.cbSize = sizeof(PARAFORMAT2);
    // 先获取当前段落格式
    SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
    pf2.dwMask |= PFM_LINESPACING;
    // 设置为固定行距(LS_EXACT),dyLineSpacing为像素值
    pf2.bLineSpacingRule = LS_EXACT;
    pf2.dyLineSpacing = 40; // 固定40像素行距
    SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
}

修正后的LSpaceB(多倍行距示例)

void LSpaceB(HWND hwnd, int spaceFactor)
{
    PARAFORMAT2 pf = {0};
    pf.cbSize = sizeof(PARAFORMAT2);
    SendMessage(hwnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
    pf.dwMask |= PFM_LINESPACING;
    // 设置为多倍行距(LS_MULTIPLE),spaceFactor为1/20点的倍数(如40=2倍行距)
    pf.bLineSpacingRule = LS_MULTIPLE;
    pf.dyLineSpacing = spaceFactor;
    SendMessage(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
}

bLineSpacingRule常用取值说明:

  • LS_SINGLE(0):单倍行距
  • LS_ONEHALF(1):1.5倍行距
  • LS_DOUBLE(2):双倍行距
  • LS_EXACT(4):固定行距,dyLineSpacing为像素值
  • LS_MULTIPLE(5):多倍行距,dyLineSpacing为1/20点的倍数(例如20=1倍,30=1.5倍)

完整修正后的测试代码

#include <stdio.h>
#include <windows.h>
#include <richedit.h>

#define ID_EDIT 1
#define ID_BUTTON 2

HWND hEdit, hButton;
HINSTANCE hInstance;
HMODULE hRichEdit;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

char sbuf[900];
void MkBuf()
{
    char sta[300];
    int ii;
 
    _strcpy_s(sbuf, sizeof(sbuf), "");
    for(ii=0; ii<6; ii++){ 
        _snprintf_s(sta, sizeof(sta), _TRUNCATE, "%dth line Test WinApi Test WinApi Test WinApi Test WinApi Test WinApi\r\n", 1+ii);
        _strcat_s(sbuf, sizeof(sbuf), sta);
    }
}
void LSpaceA()
{
    PARAFORMAT2 pf2 = {0};
    pf2.cbSize = sizeof(PARAFORMAT2);
    SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
    pf2.dwMask |= PFM_LINESPACING;
    pf2.bLineSpacingRule = LS_EXACT;
    pf2.dyLineSpacing = 40;
    SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
}
void LSpaceB(HWND hwnd, int spaceFactor)
{
    PARAFORMAT2 pf = {0};
    pf.cbSize = sizeof(PARAFORMAT2);
    SendMessage(hwnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
    pf.dwMask |= PFM_LINESPACING;
    pf.bLineSpacingRule = LS_MULTIPLE;
    pf.dyLineSpacing = spaceFactor;
    SendMessage(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    hRichEdit = LoadLibrary("riched20.dll");
    if (!hRichEdit) {
        MessageBox(NULL, "Failed to load riched20.dll", "Error", MB_ICONERROR);
        return 1;
    }

    WNDCLASSEX wc = {0};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = "EditorWindowClass";
    RegisterClassEx(&wc);

    HWND hwnd = CreateWindowEx(0, "EditorWindowClass", "Text Editor", WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);

    // 创建RichEdit20A控件(ANSI版本)
    hEdit = CreateWindowEx(0, "RichEdit20A", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE,
        0, 0, 800, 500, hwnd, (HMENU)ID_EDIT, hInstance, NULL);

    hButton = CreateWindowEx(0, "BUTTON", "Change Line Spacing", WS_CHILD | WS_VISIBLE,
        10, 510, 150, 30, hwnd, (HMENU)ID_BUTTON, hInstance, NULL);

    MkBuf();
    SetWindowText(hEdit, sbuf);
    LSpaceA();

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    FreeLibrary(hRichEdit);
    return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_COMMAND:
        if (LOWORD(wParam) == ID_BUTTON) {
            LSpaceB(hEdit, 40); // 设置2倍行距(40=2*20)
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

VS编译兼容性说明

将strcpy、sprintf、strcat替换为安全版本_strcpy_s、_snprintf_s、_strcat_s,即可在Visual Studio中正常编译。

内容的提问来源于stack exchange,提问作者land cc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:20:21