WM_SETTEXT занимает слишком много времени для многострочного редактора со стилем ES_RIGHT - PullRequest
0 голосов
/ 06 декабря 2018

Я отправляю около одного мегабайта текста Unicode в многострочное текстовое поле TEXTBOX, используя WM_SETTEXT.Это займет 30 секунд или более.Но вставить тот же 1МБ из буфера обмена очень быстро.В чем проблема?Любая идея или ссылка приветствуется.Я использую сообщество VS2017 для всего своего кода.

Редактировать: я удалил предыдущие изменения, чтобы прояснить проблему.Вот минимальный, полный, проверяемый код

#include "stdafx.h"
#include <windows.h>

struct VIEWTEMPLATE : public DLGTEMPLATE {
    unsigned __int16 nMenu;
    unsigned __int16 nClass;
    unsigned __int16 nTitle;
    unsigned __int16 nPointSize;
    wchar_t wszFaceName[10];
};

WNDPROC g_lpfnOriginalWndProc;
HINSTANCE g_hInstance;

static void uPasteFromClipBoard(HWND hwndControl)
{
    HWND wndParent = GetParent(hwndControl);
    if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return;
    if (!OpenClipboard(hwndControl)) return;
    const wchar_t * lpwszText = nullptr;
    HGLOBAL hgClipboardData = GetClipboardData(CF_UNICODETEXT);
    if (hgClipboardData)
    {
        lpwszText = (const wchar_t *)GlobalLock(hgClipboardData);
    }
    if (!lpwszText)
    {
        CloseClipboard();
        return;
    }
    SendMessageW(hwndControl, WM_SETTEXT, 0, (LPARAM)lpwszText);
    GlobalUnlock(hgClipboardData);
    CloseClipboard();
}

static LRESULT uCtrlProc(HWND hwndControl, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_PASTE: uPasteFromClipBoard(hwndControl); return 1;
    default: break;
    }
    return CallWindowProc(g_lpfnOriginalWndProc, hwndControl, uMsg, wParam, lParam);
}

static int uInitDialog(HWND hwndDlg)
{
    //create a multiline edit control
    int iStyle1 = ES_RIGHT | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL;
    //I discovered that removing ES_RIGHT solves the problem
    int iStyle2 = WS_CHILD | WS_BORDER | WS_VSCROLL;
    int cpLeft = 10;
    int cpTop = 10;
    int cpWidth = 500;
    int cpHeight = 200;
    HWND hwndEdit = CreateWindowExW(
        0, L"EDIT", L"Paste here", iStyle1 | iStyle2,
        cpLeft, cpTop, cpWidth, cpHeight,
        hwndDlg, nullptr, g_hInstance, nullptr
    );
    if (!hwndEdit)
        return false;
    ShowWindow(hwndEdit, SW_SHOW);
    g_lpfnOriginalWndProc = (WNDPROC)GetWindowLongPtrW(hwndEdit, GWLP_WNDPROC);
    SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (ULONG_PTR)uCtrlProc);
    return true;
}

static INT_PTR uDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_INITDIALOG: return uInitDialog(hwndDlg);
    default: return 0L;
    }
};

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    //create a dialog template. resource dialogs have no problem
    VIEWTEMPLATE *dt;
    dt = (VIEWTEMPLATE *)malloc(sizeof(VIEWTEMPLATE));
    if (!dt) return 0;
    memset(dt, 0, sizeof(*dt));
    dt->style =
        DS_SETFONT | WS_POPUP | WS_VISIBLE |
        DS_MODALFRAME | DS_3DLOOK | WS_CAPTION | WS_SYSMENU |
        WS_BORDER | WS_MINIMIZEBOX;
    dt->dwExtendedStyle = WS_EX_OVERLAPPEDWINDOW;
    dt->cdit = 0;
    dt->x = 0;
    dt->y = 0;
    dt->cx = 520;
    dt->cy = 220;
    dt->nPointSize = 10;
    LRESULT iResult = DialogBoxIndirectParamW(
        nullptr,
        dt,
        nullptr,
        uDlgProc,
        0
    );
    free(dt);
    return 0;
}

1 Ответ

0 голосов
/ 07 декабря 2018

Шаблоны диалогов имеют очень специфический формат и требуют выравнивания DWORD.Ваша реализация неверна и, вероятно, вызывает неопределенное поведение.

Более простое решение - использовать редактор ресурсов для создания диалога и просто вызвать DialogBox(hinstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc).Этот метод намного проще, универсальнее и безопаснее.

По умолчанию для элемента управления редактирования установлено ограничение в 32 КБ.Этот предел не изменяется в приведенном выше примере, поэтому неясно, как вы вставляете 1 МБ.

Элемент управления Edit автоматически обрабатывает сообщение WM_PASTE, если оно имеет фокус.Если элемент управления для редактирования не имеет фокуса, то WM_PASTE отправляется в диалоговое окно, вы можете просто передать WM_PASTE в элемент управления для редактирования.

SetWindowLongPtr является устаревшим методом для элементов управления подклассами.Вместо этого используйте SetWindowSubclass.

Попробуйте пример ниже.Я снова использовал метод шаблона диалога, но настоятельно рекомендуется использовать редактор ресурсов.Этот код должен быть скомпилирован в Unicode.

//#define UNICODE
#include <Windows.h>
#include <stdio.h>
#include <CommCtrl.h>

//adding library (Visual Studio specific)
#pragma comment(lib, "comctl32.lib")

#define ID_EDIT 200

LRESULT CALLBACK EditProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
    UINT_PTR, DWORD_PTR)
{
    switch(msg) 
    {
    case WM_PASTE: 
    {
        if(!IsClipboardFormatAvailable(CF_UNICODETEXT)) break;
        if(!OpenClipboard(hwnd)) break;
        HANDLE hdata = GetClipboardData(CF_UNICODETEXT);
        const wchar_t *lpwszText = (const wchar_t*)GlobalLock(hdata);
        SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)lpwszText);
        GlobalUnlock(hdata);
        CloseClipboard();
        return FALSE;
    }
    case WM_NCDESTROY:
        RemoveWindowSubclass(hwnd, EditProc, 0);
        return DefSubclassProc(hwnd, msg, wp, lp);
    }
    return DefSubclassProc(hwnd, msg, wp, lp);
}

INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM)
{
    switch(uMsg)
    {
    case WM_INITDIALOG: 
    {
        HWND hedit = GetDlgItem(hwnd, ID_EDIT);

        //increase the text limit
        SendMessage(hedit, EM_LIMITTEXT, 0x7FFF'FFFF, 0);

        //subclass edit control if necessary
        SetWindowSubclass(hedit, EditProc, 0, 0);
        return TRUE;
    }

    case WM_COMMAND:
        switch(LOWORD(wparam))
        {
        case IDOK: EndDialog(hwnd, IDOK);
        case IDCANCEL: EndDialog(hwnd, IDCANCEL);
        }
        break;
    }
    return FALSE;
};

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int)
{
    HGLOBAL hgbl = GlobalAlloc(GMEM_ZEROINIT, 2048);
    if(!hgbl)
        return -1;

    const wchar_t *buf;
    int buflen;
    DLGITEMTEMPLATE *item;

    LPWORD ptr = (LPWORD)GlobalLock(hgbl);

    DLGTEMPLATE *dlgtemplate = (DLGTEMPLATE*)ptr;
    dlgtemplate->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION;
    dlgtemplate->cdit = 1; /* Number of controls */
    dlgtemplate->x = 10;
    dlgtemplate->y = 10;
    dlgtemplate->cx = 200;
    dlgtemplate->cy = 200;
    ptr = (LPWORD)(dlgtemplate + 1);

    //no menu
    *ptr++ = 0;

    //predefined dialog box class (by default)
    *ptr++ = 0;

    //Title
    buf = L"Dialog title";
    buflen = wcslen(buf);
    memcpy(ptr, buf, buflen * sizeof(wchar_t));
    ptr += buflen + (buflen % 2);

    ptr++;

    //-----------------------
    // Define a edit control.
    //-----------------------
    item = (DLGITEMTEMPLATE*)ptr;
    item->x = 10;
    item->y = 10;
    item->cx = 180;
    item->cy = 180;
    item->id = ID_EDIT;
    item->style = WS_BORDER | WS_CHILD | WS_VISIBLE |
        ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL;
    ptr = (LPWORD)(item + 1);

    //edit class
    *ptr++ = 0xFFFF;
    *ptr++ = 0x0081;

    //edit window text not set...

    ptr++;

    GlobalUnlock(hgbl);
    LRESULT ret = DialogBoxIndirect(hInstance, dlgtemplate, NULL, DlgProc);
    GlobalFree(hgbl);
    return ret; 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...