win32u: Convert inter-process messages to Unicode.

Based on user32 WINPROC_CallProcWtoA.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53744
This commit is contained in:
Jacek Caban 2022-12-20 13:53:04 +01:00 committed by Alexandre Julliard
parent 2b0cd25b5f
commit d222dcc2a4
4 changed files with 366 additions and 2 deletions

View file

@ -3619,6 +3619,60 @@ CPTABLEINFO *get_cptable( WORD cp )
return &tables[i];
}
/* Based on NlsValidateLocale */
const NLS_LOCALE_DATA *get_locale_data( LCID lcid )
{
static const NLS_LOCALE_HEADER *locale_table;
static const NLS_LOCALE_LCID_INDEX *lcids_index;
int min = 0, max;
if (!locale_table)
{
LARGE_INTEGER size;
void *addr;
LCID lcid;
NTSTATUS status;
static struct
{
UINT ctypes;
UINT unknown1;
UINT unknown2;
UINT unknown3;
UINT locales;
UINT charmaps;
UINT geoids;
UINT scripts;
} *header;
status = NtInitializeNlsFiles( &addr, &lcid, &size );
if (status)
{
ERR( "Failed to load nls file\n" );
return NULL;
}
if (InterlockedCompareExchangePointer( (void **)&header, addr, NULL ))
NtUnmapViewOfSection( GetCurrentProcess(), addr );
locale_table = (const NLS_LOCALE_HEADER *)((char *)header + header->locales);
lcids_index = (const NLS_LOCALE_LCID_INDEX *)((char *)locale_table + locale_table->lcids_offset);
}
max = locale_table->nb_lcids - 1;
while (min <= max)
{
int pos = (min + max) / 2;
if (lcid < lcids_index[pos].id) max = pos - 1;
else if (lcid > lcids_index[pos].id) min = pos + 1;
else
{
ULONG offset = locale_table->locales_offset + pos * locale_table->locale_size;
return (const NLS_LOCALE_DATA *)((const char *)locale_table + offset);
}
}
return NULL;
}
DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen )
{
DWORD ret;
@ -3665,6 +3719,34 @@ DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *sr
return ret / sizeof(WCHAR);
}
DWORD win32u_mbtowc_size( CPTABLEINFO *info, const char *src, DWORD srclen )
{
DWORD ret;
if (info->CodePage == CP_UTF8)
{
RtlUTF8ToUnicodeN( NULL, 0, &ret, src, srclen );
ret /= sizeof(WCHAR);
}
else if (info->DBCSCodePage)
{
for (ret = 0; srclen; srclen--, src++, ret++)
{
if (info->DBCSOffsets[(unsigned char)*src] && srclen > 1)
{
src++;
srclen--;
}
}
}
else
{
ret = srclen;
}
return ret;
}
static BOOL wc_to_index( UINT cp, WCHAR wc, unsigned char *dst, BOOL allow_default )
{
const CPTABLEINFO *info;

View file

@ -29,6 +29,7 @@
#define WIN32_NO_STATUS
#include "win32u_private.h"
#include "ntuser_private.h"
#include "winnls.h"
#include "hidusage.h"
#include "dbt.h"
#include "dde.h"
@ -2521,6 +2522,17 @@ static LRESULT send_inter_thread_message( const struct send_message_info *info,
return retrieve_reply( info, reply_size, res_ptr );
}
static LRESULT send_inter_thread_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
LRESULT *result, void *arg )
{
struct send_message_info *info = arg;
info->hwnd = hwnd;
info->msg = msg;
info->wparam = wp;
info->lparam = lp;
return send_inter_thread_message( info, result );
}
/***********************************************************************
* send_internal_message_timeout
*
@ -2835,6 +2847,268 @@ static BOOL process_packed_message( struct send_message_info *info, LRESULT *res
return TRUE;
}
static inline void *get_buffer( void *static_buffer, size_t size, size_t need )
{
if (size >= need) return static_buffer;
return malloc( need );
}
static inline void free_buffer( void *static_buffer, void *buffer )
{
if (buffer != static_buffer) free( buffer );
}
typedef LRESULT (*winproc_callback_t)( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
LRESULT *result, void *arg );
/**********************************************************************
* test_lb_for_string
*
* Return TRUE if the lparam is a string
*/
static inline BOOL test_lb_for_string( HWND hwnd, UINT msg )
{
DWORD style = get_window_long( hwnd, GWL_STYLE );
if (msg <= CB_MSGMAX)
return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS));
else
return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS));
}
static CPTABLEINFO *get_input_codepage( void )
{
const NLS_LOCALE_DATA *locale;
HKL hkl = NtUserGetKeyboardLayout( 0 );
CPTABLEINFO *ret = NULL;
locale = get_locale_data( LOWORD(hkl) );
if (locale && locale->idefaultansicodepage != CP_UTF8)
ret = get_cptable( locale->idefaultansicodepage );
return ret ? ret : &ansi_cp;
}
/***********************************************************************
* map_wparam_AtoW
*
* Convert the wparam of an ASCII message to Unicode.
*/
static BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping )
{
char ch[2];
WCHAR wch[2];
wch[0] = wch[1] = 0;
switch(message)
{
case WM_CHARTOITEM:
case EM_SETPASSWORDCHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
ch[0] = LOBYTE(*wparam);
ch[1] = HIBYTE(*wparam);
win32u_mbtowc( get_input_codepage(), wch, 2, ch, 2 );
*wparam = MAKEWPARAM(wch[0], wch[1]);
break;
case WM_IME_CHAR:
ch[0] = HIBYTE(*wparam);
ch[1] = LOBYTE(*wparam);
if (ch[0]) win32u_mbtowc( get_input_codepage(), wch, 2, ch, 2 );
else win32u_mbtowc( get_input_codepage(), wch, 1, ch + 1, 1 );
*wparam = MAKEWPARAM(wch[0], HIWORD(*wparam));
break;
}
return TRUE;
}
/**********************************************************************
* call_messageAtoW
*
* Call a window procedure, translating args from Ansi to Unicode.
*/
LRESULT call_messageAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wparam,
LPARAM lparam, LRESULT *result, void *arg, enum wm_char_mapping mapping )
{
LRESULT ret = 0;
TRACE( "(hwnd=%p,msg=%s,wp=%#lx,lp=%#lx)\n", hwnd, debugstr_msg_name( msg, hwnd ),
(long)wparam, (long)lparam );
switch(msg)
{
case WM_MDICREATE:
{
WCHAR *ptr, buffer[512];
DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0;
MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lparam;
MDICREATESTRUCTW csW;
memcpy( &csW, csA, sizeof(csW) );
if (!IS_INTRESOURCE(csA->szTitle))
{
title_lenA = strlen(csA->szTitle) + 1;
title_lenW = win32u_mbtowc_size( &ansi_cp, csA->szTitle, title_lenA );
}
if (!IS_INTRESOURCE(csA->szClass))
{
class_lenA = strlen(csA->szClass) + 1;
class_lenW = win32u_mbtowc_size( &ansi_cp, csA->szClass, class_lenA );
}
if (!(ptr = get_buffer( buffer, sizeof(buffer), (title_lenW + class_lenW) * sizeof(WCHAR) )))
break;
if (title_lenW)
{
csW.szTitle = ptr;
win32u_mbtowc( &ansi_cp, ptr, title_lenW, csA->szTitle, title_lenA );
}
if (class_lenW)
{
csW.szClass = ptr + title_lenW;
win32u_mbtowc( &ansi_cp, ptr + title_lenW, class_lenW, csA->szClass, class_lenA );
}
ret = callback( hwnd, msg, wparam, (LPARAM)&csW, result, arg );
free_buffer( buffer, ptr );
}
break;
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
WCHAR *ptr, buffer[512];
LPSTR str = (LPSTR)lparam;
DWORD len = wparam * sizeof(WCHAR);
if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break;
ret = callback( hwnd, msg, wparam, (LPARAM)ptr, result, arg );
if (wparam)
{
len = 0;
len = *result ? win32u_wctomb( &ansi_cp, str, wparam - 1, ptr, *result ) : 0;
str[len] = 0;
*result = len;
}
free_buffer( buffer, ptr );
}
break;
case LB_ADDSTRING:
case LB_INSERTSTRING:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_SELECTSTRING:
case CB_ADDSTRING:
case CB_INSERTSTRING:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_SELECTSTRING:
if (!lparam || !test_lb_for_string( hwnd, msg ))
{
ret = callback( hwnd, msg, wparam, lparam, result, arg );
break;
}
/* fall through */
case WM_SETTEXT:
case WM_WININICHANGE:
case WM_DEVMODECHANGE:
case CB_DIR:
case LB_DIR:
case LB_ADDFILE:
case EM_REPLACESEL:
if (!lparam)
{
ret = callback( hwnd, msg, wparam, lparam, result, arg );
}
else
{
WCHAR *ptr, buffer[512];
LPCSTR strA = (LPCSTR)lparam;
DWORD lenW, lenA = strlen(strA) + 1;
lenW = win32u_mbtowc_size( &ansi_cp, strA, lenA );
if ((ptr = get_buffer( buffer, sizeof(buffer), lenW * sizeof(WCHAR) )))
{
win32u_mbtowc( &ansi_cp, ptr, lenW, strA, lenA );
ret = callback( hwnd, msg, wparam, (LPARAM)ptr, result, arg );
free_buffer( buffer, ptr );
}
}
break;
case EM_GETLINE:
{
WCHAR *ptr, buffer[512];
WORD len = *(WORD *)lparam;
if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
*((WORD *)ptr) = len; /* store the length */
ret = callback( hwnd, msg, wparam, (LPARAM)ptr, result, arg );
if (*result)
{
DWORD reslen;
reslen = win32u_wctomb( &ansi_cp, (char *)lparam, len, ptr, *result );
if (reslen < len) ((LPSTR)lparam)[reslen] = 0;
*result = reslen;
}
free_buffer( buffer, ptr );
}
break;
case WM_GETDLGCODE:
if (lparam)
{
MSG newmsg = *(MSG *)lparam;
if (map_wparam_AtoW( newmsg.message, &newmsg.wParam, WMCHAR_MAP_NOMAPPING ))
ret = callback( hwnd, msg, wparam, (LPARAM)&newmsg, result, arg );
}
else ret = callback( hwnd, msg, wparam, lparam, result, arg );
break;
case WM_CHARTOITEM:
case WM_MENUCHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case EM_SETPASSWORDCHAR:
case WM_IME_CHAR:
if (map_wparam_AtoW( msg, &wparam, mapping ))
ret = callback( hwnd, msg, wparam, lparam, result, arg );
break;
case WM_GETTEXTLENGTH:
case CB_GETLBTEXTLEN:
case LB_GETTEXTLEN:
ret = callback( hwnd, msg, wparam, lparam, result, arg );
if (*result >= 0)
{
WCHAR *ptr, buffer[512];
LRESULT res;
DWORD len = *result + 1;
/* Determine respective GETTEXT message */
UINT msg_get_text = msg == WM_GETTEXTLENGTH ? WM_GETTEXT :
(msg == CB_GETLBTEXTLEN ? CB_GETLBTEXT : LB_GETTEXT);
/* wparam differs between the messages */
WPARAM wp = msg == WM_GETTEXTLENGTH ? len : wparam;
if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
res = send_message( hwnd, msg_get_text, wp, (LPARAM)ptr );
*result = win32u_wctomb_size( &ansi_cp, ptr, res );
free_buffer( buffer, ptr );
}
break;
default:
ret = callback( hwnd, msg, wparam, lparam, result, arg );
break;
}
return ret;
}
/***********************************************************************
* process_message
@ -2871,7 +3145,13 @@ static BOOL process_message( struct send_message_info *info, DWORD_PTR *res_ptr,
{
if (dest_pid != GetCurrentProcessId() && (info->type == MSG_ASCII || info->type == MSG_UNICODE))
info->type = MSG_OTHER_PROCESS;
ret = send_inter_thread_message( info, &result );
/* MSG_ASCII can be sent unconverted except for WM_CHAR; everything else needs to be Unicode */
if (ansi && (info->type != MSG_ASCII || info->msg == WM_CHAR))
ret = call_messageAtoW( send_inter_thread_callback, info->hwnd, info->msg,
info->wparam, info->lparam, &result, info, info->wm_char );
else
ret = send_inter_thread_message( info, &result );
}
else if (info->type != MSG_OTHER_PROCESS)
{

View file

@ -339,7 +339,6 @@ extern int add_gdi_face( const WCHAR *family_name, const WCHAR *second_name,
DWORD ntmflags, DWORD version, DWORD flags,
const struct bitmap_font_size *size ) DECLSPEC_HIDDEN;
extern UINT font_init(void) DECLSPEC_HIDDEN;
extern CPTABLEINFO *get_cptable( WORD cp ) DECLSPEC_HIDDEN;
extern const struct font_backend_funcs *init_freetype_lib(void) DECLSPEC_HIDDEN;
/* opentype.c */

View file

@ -453,11 +453,14 @@ static inline WCHAR win32u_towupper( WCHAR ch )
extern CPTABLEINFO ansi_cp DECLSPEC_HIDDEN;
CPTABLEINFO *get_cptable( WORD cp ) DECLSPEC_HIDDEN;
const NLS_LOCALE_DATA *get_locale_data( LCID lcid ) DECLSPEC_HIDDEN;
DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src,
DWORD srclen ) DECLSPEC_HIDDEN;
DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src,
DWORD srclen ) DECLSPEC_HIDDEN;
DWORD win32u_wctomb_size( CPTABLEINFO *info, const WCHAR *src, DWORD srclen ) DECLSPEC_HIDDEN;
DWORD win32u_mbtowc_size( CPTABLEINFO *info, const char *src, DWORD srclen ) DECLSPEC_HIDDEN;
static inline WCHAR *win32u_wcsdup( const WCHAR *str )
{