我使用WM_SETTEXT将大约1 MB的Unicode文本发送到多行TEXTBOX。需要30秒或更长时间才能完成。但是从剪贴板粘贴相同的1MB速度非常快。问题是什么?任何想法或链接表示赞赏。 我为所有代码使用VS2017社区。 p>
编辑:我删除了以前的编辑以澄清问题。 这是最小,完整,可验证的代码
#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;
}
答案 0 :(得分:0)
对话框模板具有非常特定的格式,并且需要DWORD
对齐。您的实现不正确,可能会导致未定义的行为。
一个更简单的解决方案是使用资源编辑器创建一个对话框,然后简单地调用DialogBox(hinstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc)
。这种方法更容易,更通用,更安全。
默认情况下,编辑控件的限制为32K。在上面的示例中,此限制没有更改,因此不清楚如何插入1 MB。
编辑控件将自动处理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;
}