comctl32/button: Implement BCM_{GETNOTE,SETNOTE,GETNOTELENGTH} message.
Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3a6c724e90
commit
06d2ad29ae
|
@ -92,6 +92,8 @@ typedef struct _BUTTON_INFO
|
|||
HWND hwnd;
|
||||
LONG state;
|
||||
HFONT font;
|
||||
WCHAR *note;
|
||||
INT note_length;
|
||||
union
|
||||
{
|
||||
HICON icon;
|
||||
|
@ -234,6 +236,14 @@ HRGN set_control_clipping( HDC hdc, const RECT *rect )
|
|||
return hrgn;
|
||||
}
|
||||
|
||||
static WCHAR *heap_strndupW(const WCHAR *src, size_t length)
|
||||
{
|
||||
size_t size = (length + 1) * sizeof(WCHAR);
|
||||
WCHAR *dst = heap_alloc(size);
|
||||
if (dst) memcpy(dst, src, size);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Convert button styles to flags used by DrawText.
|
||||
*/
|
||||
|
@ -336,6 +346,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||
|
||||
case WM_NCDESTROY:
|
||||
SetWindowLongPtrW( hWnd, 0, 0 );
|
||||
heap_free(infoPtr->note);
|
||||
heap_free(infoPtr);
|
||||
break;
|
||||
|
||||
|
@ -574,6 +585,81 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||
return 1; /* success. FIXME: check text length */
|
||||
}
|
||||
|
||||
case BCM_SETNOTE:
|
||||
{
|
||||
WCHAR *note = (WCHAR *)lParam;
|
||||
if (btn_type != BS_COMMANDLINK && btn_type != BS_DEFCOMMANDLINK)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
heap_free(infoPtr->note);
|
||||
if (note)
|
||||
{
|
||||
infoPtr->note_length = lstrlenW(note);
|
||||
infoPtr->note = heap_strndupW(note, infoPtr->note_length);
|
||||
}
|
||||
|
||||
if (!note || !infoPtr->note)
|
||||
{
|
||||
infoPtr->note_length = 0;
|
||||
infoPtr->note = heap_alloc_zero(sizeof(WCHAR));
|
||||
}
|
||||
|
||||
SetLastError(NO_ERROR);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case BCM_GETNOTE:
|
||||
{
|
||||
DWORD *size = (DWORD *)wParam;
|
||||
WCHAR *buffer = (WCHAR *)lParam;
|
||||
INT length = 0;
|
||||
|
||||
if (btn_type != BS_COMMANDLINK && btn_type != BS_DEFCOMMANDLINK)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!buffer || !size || !infoPtr->note)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*size > 0)
|
||||
{
|
||||
length = min(*size - 1, infoPtr->note_length);
|
||||
memcpy(buffer, infoPtr->note, length * sizeof(WCHAR));
|
||||
buffer[length] = '\0';
|
||||
}
|
||||
|
||||
if (*size < infoPtr->note_length + 1)
|
||||
{
|
||||
*size = infoPtr->note_length + 1;
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(NO_ERROR);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
case BCM_GETNOTELENGTH:
|
||||
{
|
||||
if (btn_type != BS_COMMANDLINK && btn_type != BS_DEFCOMMANDLINK)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return infoPtr->note_length;
|
||||
}
|
||||
|
||||
case WM_SETFONT:
|
||||
infoPtr->font = (HFONT)wParam;
|
||||
if (lParam) InvalidateRect(hWnd, NULL, TRUE);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "msg.h"
|
||||
|
||||
#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
|
||||
static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
|
||||
|
@ -805,6 +806,162 @@ static void test_button_class(void)
|
|||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
static void test_note(void)
|
||||
{
|
||||
HWND hwnd;
|
||||
BOOL ret;
|
||||
WCHAR test_w[] = {'t', 'e', 's', 't', 0};
|
||||
WCHAR tes_w[] = {'t', 'e', 's', 0};
|
||||
WCHAR deadbeef_w[] = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f', 0};
|
||||
WCHAR buffer_w[10];
|
||||
DWORD size;
|
||||
DWORD error;
|
||||
INT type;
|
||||
|
||||
hwnd = create_button(BS_COMMANDLINK, NULL);
|
||||
ok(hwnd != NULL, "Expect hwnd not null\n");
|
||||
SetLastError(0xdeadbeef);
|
||||
size = ARRAY_SIZE(buffer_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
error = GetLastError();
|
||||
if (!ret && error == 0xdeadbeef)
|
||||
{
|
||||
win_skip("BCM_GETNOTE message is unavailable. Skipping note tests\n"); /* xp or 2003 */
|
||||
DestroyWindow(hwnd);
|
||||
return;
|
||||
}
|
||||
DestroyWindow(hwnd);
|
||||
|
||||
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
|
||||
{
|
||||
if (type == BS_DEFCOMMANDLINK || type == BS_COMMANDLINK)
|
||||
{
|
||||
hwnd = create_button(type, NULL);
|
||||
ok(hwnd != NULL, "Expect hwnd not null\n");
|
||||
|
||||
/* Get note when note hasn't been not set yet */
|
||||
SetLastError(0xdeadbeef);
|
||||
lstrcpyW(buffer_w, deadbeef_w);
|
||||
size = ARRAY_SIZE(buffer_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
error = GetLastError();
|
||||
ok(!ret, "Expect BCM_GETNOTE return false\n");
|
||||
ok(!lstrcmpW(buffer_w, deadbeef_w), "Expect note: %s, got: %s\n",
|
||||
wine_dbgstr_w(deadbeef_w), wine_dbgstr_w(buffer_w));
|
||||
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
|
||||
ok(error == ERROR_INVALID_PARAMETER, "Expect last error: 0x%08x, got: 0x%08x\n",
|
||||
ERROR_INVALID_PARAMETER, error);
|
||||
|
||||
/* Get note length when note is not set */
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTELENGTH, 0, 0);
|
||||
ok(ret == 0, "Expect note length: %d, got: %d\n", 0, ret);
|
||||
|
||||
/* Successful set note, get note and get note length */
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)test_w);
|
||||
ok(ret, "Expect BCM_SETNOTE return true\n");
|
||||
error = GetLastError();
|
||||
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
lstrcpyW(buffer_w, deadbeef_w);
|
||||
size = ARRAY_SIZE(buffer_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
ok(ret, "Expect BCM_GETNOTE return true\n");
|
||||
ok(!lstrcmpW(buffer_w, test_w), "Expect note: %s, got: %s\n", wine_dbgstr_w(test_w),
|
||||
wine_dbgstr_w(buffer_w));
|
||||
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
|
||||
error = GetLastError();
|
||||
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
|
||||
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTELENGTH, 0, 0);
|
||||
ok(ret == ARRAY_SIZE(test_w) - 1, "Got: %d\n", ret);
|
||||
|
||||
/* Insufficient buffer, return partial string */
|
||||
SetLastError(0xdeadbeef);
|
||||
lstrcpyW(buffer_w, deadbeef_w);
|
||||
size = ARRAY_SIZE(test_w) - 1;
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
ok(!ret, "Expect BCM_GETNOTE return false\n");
|
||||
ok(!lstrcmpW(buffer_w, tes_w), "Expect note: %s, got: %s\n", wine_dbgstr_w(tes_w),
|
||||
wine_dbgstr_w(buffer_w));
|
||||
ok(size == ARRAY_SIZE(test_w), "Got: %d\n", size);
|
||||
error = GetLastError();
|
||||
ok(error == ERROR_INSUFFICIENT_BUFFER, "Expect last error: 0x%08x, got: 0x%08x\n",
|
||||
ERROR_INSUFFICIENT_BUFFER, error);
|
||||
|
||||
/* Set note with NULL buffer */
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, 0);
|
||||
ok(ret, "Expect BCM_SETNOTE return false\n");
|
||||
error = GetLastError();
|
||||
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
|
||||
|
||||
/* Check that set note with NULL buffer make note empty */
|
||||
SetLastError(0xdeadbeef);
|
||||
lstrcpyW(buffer_w, deadbeef_w);
|
||||
size = ARRAY_SIZE(buffer_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
ok(ret, "Expect BCM_GETNOTE return true\n");
|
||||
ok(lstrlenW(buffer_w) == 0, "Expect note length 0\n");
|
||||
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
|
||||
error = GetLastError();
|
||||
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTELENGTH, 0, 0);
|
||||
ok(ret == 0, "Expect note length: %d, got: %d\n", 0, ret);
|
||||
|
||||
/* Get note with NULL buffer */
|
||||
SetLastError(0xdeadbeef);
|
||||
size = ARRAY_SIZE(buffer_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, 0);
|
||||
ok(!ret, "Expect BCM_SETNOTE return false\n");
|
||||
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
|
||||
error = GetLastError();
|
||||
ok(error == ERROR_INVALID_PARAMETER, "Expect last error: 0x%08x, got: 0x%08x\n",
|
||||
ERROR_INVALID_PARAMETER, error);
|
||||
|
||||
/* Get note with NULL size */
|
||||
SetLastError(0xdeadbeef);
|
||||
lstrcpyW(buffer_w, deadbeef_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, 0, (LPARAM)buffer_w);
|
||||
ok(!ret, "Expect BCM_SETNOTE return false\n");
|
||||
ok(!lstrcmpW(buffer_w, deadbeef_w), "Expect note: %s, got: %s\n",
|
||||
wine_dbgstr_w(deadbeef_w), wine_dbgstr_w(buffer_w));
|
||||
error = GetLastError();
|
||||
ok(error == ERROR_INVALID_PARAMETER, "Expect last error: 0x%08x, got: 0x%08x\n",
|
||||
ERROR_INVALID_PARAMETER, error);
|
||||
|
||||
/* Get note with zero size */
|
||||
SetLastError(0xdeadbeef);
|
||||
size = 0;
|
||||
lstrcpyW(buffer_w, deadbeef_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
ok(!ret, "Expect BCM_GETNOTE return false\n");
|
||||
ok(!lstrcmpW(buffer_w, deadbeef_w), "Expect note: %s, got: %s\n",
|
||||
wine_dbgstr_w(deadbeef_w), wine_dbgstr_w(buffer_w));
|
||||
ok(size == 1, "Got: %d\n", size);
|
||||
error = GetLastError();
|
||||
ok(error == ERROR_INSUFFICIENT_BUFFER, "Expect last error: 0x%08x, got: 0x%08x\n",
|
||||
ERROR_INSUFFICIENT_BUFFER, error);
|
||||
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
hwnd = create_button(type, NULL);
|
||||
ok(hwnd != NULL, "Expect hwnd not null\n");
|
||||
SetLastError(0xdeadbeef);
|
||||
size = ARRAY_SIZE(buffer_w);
|
||||
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
|
||||
ok(!ret, "Expect BCM_GETNOTE return false\n");
|
||||
error = GetLastError();
|
||||
ok(error == ERROR_NOT_SUPPORTED, "Expect last error: 0x%08x, got: 0x%08x\n",
|
||||
ERROR_NOT_SUPPORTED, error);
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void register_parent_class(void)
|
||||
{
|
||||
WNDCLASSA cls;
|
||||
|
@ -837,6 +994,7 @@ START_TEST(button)
|
|||
|
||||
test_button_class();
|
||||
test_button_messages();
|
||||
test_note();
|
||||
|
||||
unload_v6_module(ctx_cookie, hCtx);
|
||||
}
|
||||
|
|
|
@ -1093,6 +1093,14 @@ typedef struct tagNMBCHOTITEM
|
|||
#define BS_COMMANDLINK 0x0000000E
|
||||
#define BS_DEFCOMMANDLINK 0x0000000F
|
||||
|
||||
/* Button macros */
|
||||
#define Button_SetNote(button, note) \
|
||||
(BOOL)SNDMSG(button, BCM_SETNOTE, 0, (LPARAM)(note))
|
||||
#define Button_GetNote(button, buffer, size) \
|
||||
(BOOL)SNDMSG(button, BCM_GETNOTE, (WPARAM)(size), (LPARAM)(buffer))
|
||||
#define Button_GetNoteLength(button) \
|
||||
(LRESULT)SNDMSG(button, BCM_GETNOTELENGTH, 0, 0)
|
||||
|
||||
/* Toolbar */
|
||||
|
||||
#define TOOLBARCLASSNAMEA "ToolbarWindow32"
|
||||
|
|
Loading…
Reference in New Issue