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;
|
HWND hwnd;
|
||||||
LONG state;
|
LONG state;
|
||||||
HFONT font;
|
HFONT font;
|
||||||
|
WCHAR *note;
|
||||||
|
INT note_length;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
HICON icon;
|
HICON icon;
|
||||||
|
@ -234,6 +236,14 @@ HRGN set_control_clipping( HDC hdc, const RECT *rect )
|
||||||
return hrgn;
|
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.
|
* 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:
|
case WM_NCDESTROY:
|
||||||
SetWindowLongPtrW( hWnd, 0, 0 );
|
SetWindowLongPtrW( hWnd, 0, 0 );
|
||||||
|
heap_free(infoPtr->note);
|
||||||
heap_free(infoPtr);
|
heap_free(infoPtr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -574,6 +585,81 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
||||||
return 1; /* success. FIXME: check text length */
|
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:
|
case WM_SETFONT:
|
||||||
infoPtr->font = (HFONT)wParam;
|
infoPtr->font = (HFONT)wParam;
|
||||||
if (lParam) InvalidateRect(hWnd, NULL, TRUE);
|
if (lParam) InvalidateRect(hWnd, NULL, TRUE);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "msg.h"
|
#include "msg.h"
|
||||||
|
|
||||||
#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
|
#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 *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
|
||||||
static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
|
static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
|
||||||
|
@ -805,6 +806,162 @@ static void test_button_class(void)
|
||||||
DestroyWindow(hwnd);
|
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)
|
static void register_parent_class(void)
|
||||||
{
|
{
|
||||||
WNDCLASSA cls;
|
WNDCLASSA cls;
|
||||||
|
@ -837,6 +994,7 @@ START_TEST(button)
|
||||||
|
|
||||||
test_button_class();
|
test_button_class();
|
||||||
test_button_messages();
|
test_button_messages();
|
||||||
|
test_note();
|
||||||
|
|
||||||
unload_v6_module(ctx_cookie, hCtx);
|
unload_v6_module(ctx_cookie, hCtx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1093,6 +1093,14 @@ typedef struct tagNMBCHOTITEM
|
||||||
#define BS_COMMANDLINK 0x0000000E
|
#define BS_COMMANDLINK 0x0000000E
|
||||||
#define BS_DEFCOMMANDLINK 0x0000000F
|
#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 */
|
/* Toolbar */
|
||||||
|
|
||||||
#define TOOLBARCLASSNAMEA "ToolbarWindow32"
|
#define TOOLBARCLASSNAMEA "ToolbarWindow32"
|
||||||
|
|
Loading…
Reference in New Issue