diff --git a/dlls/user32/dde_server.c b/dlls/user32/dde_server.c index 2dc8ae84e9..0d62c49a46 100644 --- a/dlls/user32/dde_server.c +++ b/dlls/user32/dde_server.c @@ -29,9 +29,11 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" +#include "winnls.h" #include "dde.h" #include "ddeml.h" #include "win.h" +#include "wine/unicode.h" #include "wine/debug.h" #include "dde_private.h" @@ -756,6 +758,54 @@ static WDML_XACT* WDML_ServerQueueExecute(WDML_CONV* pConv, LPARAM lParam) return pXAct; } +static BOOL data_looks_unicode( const WCHAR *data, DWORD size ) +{ + DWORD i; + + if (size % sizeof(WCHAR)) return FALSE; + for (i = 0; i < size / sizeof(WCHAR); i++) if (data[i] > 255) return FALSE; + return TRUE; +} + +/* convert data to Unicode, unless it looks like it's already Unicode */ +static HDDEDATA map_A_to_W( DWORD instance, void *ptr, DWORD size ) +{ + HDDEDATA ret; + DWORD len; + const char *end; + + if (!data_looks_unicode( ptr, size )) + { + if ((end = memchr( ptr, 0, size ))) size = end + 1 - (const char *)ptr; + len = MultiByteToWideChar( CP_ACP, 0, ptr, size, NULL, 0 ); + ret = DdeCreateDataHandle( instance, NULL, len * sizeof(WCHAR), 0, 0, CF_TEXT, 0); + MultiByteToWideChar( CP_ACP, 0, ptr, size, (WCHAR *)DdeAccessData(ret, NULL), len ); + } + else ret = DdeCreateDataHandle( instance, ptr, size, 0, 0, CF_TEXT, 0 ); + + return ret; +} + +/* convert data to ASCII, unless it looks like it's not in Unicode format */ +static HDDEDATA map_W_to_A( DWORD instance, void *ptr, DWORD size ) +{ + HDDEDATA ret; + DWORD len; + const WCHAR *end; + + if (data_looks_unicode( ptr, size )) + { + size /= sizeof(WCHAR); + if ((end = memchrW( ptr, 0, size ))) size = end + 1 - (const WCHAR *)ptr; + len = WideCharToMultiByte( CP_ACP, 0, ptr, size, NULL, 0, NULL, NULL ); + ret = DdeCreateDataHandle( instance, NULL, len, 0, 0, CF_TEXT, 0); + WideCharToMultiByte( CP_ACP, 0, ptr, size, (char *)DdeAccessData(ret, NULL), len, NULL, NULL ); + } + else ret = DdeCreateDataHandle( instance, ptr, size, 0, 0, CF_TEXT, 0 ); + + return ret; +} + /****************************************************************** * WDML_ServerHandleExecute * @@ -769,11 +819,16 @@ static WDML_QUEUE_STATE WDML_ServerHandleExecute(WDML_CONV* pConv, WDML_XACT* pX if (!(pConv->instance->CBFflags & CBF_FAIL_EXECUTES)) { LPVOID ptr = GlobalLock(pXAct->hMem); + DWORD size = GlobalSize(pXAct->hMem); if (ptr) { - hDdeData = DdeCreateDataHandle(pConv->instance->instanceID, ptr, GlobalSize(pXAct->hMem), - 0, 0, CF_TEXT, 0); + if (pConv->instance->unicode) /* Unicode server, try to map A->W */ + hDdeData = map_A_to_W( pConv->instance->instanceID, ptr, size ); + else if (!IsWindowUnicode( pConv->hwndClient )) /* ASCII server and client, try to map W->A */ + hDdeData = map_W_to_A( pConv->instance->instanceID, ptr, size ); + else + hDdeData = DdeCreateDataHandle(pConv->instance->instanceID, ptr, size, 0, 0, CF_TEXT, 0); GlobalUnlock(pXAct->hMem); } hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_EXECUTE, 0, (HCONV)pConv, diff --git a/dlls/user32/tests/dde.c b/dlls/user32/tests/dde.c index ce6d9643d7..529c527f2e 100644 --- a/dlls/user32/tests/dde.c +++ b/dlls/user32/tests/dde.c @@ -2486,11 +2486,9 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV case 0: /* ASCII string */ if (unicode_server) { - todo_wine { ok(size == size_a_to_w, "Wrong size %d/%d, msg_index=%d\n", size, size_a_to_w, msg_index); ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w), "Expected %s, msg_index=%d\n", wine_dbgstr_w(test_cmd_a_to_w), msg_index); - } } else if (unicode_client) { @@ -2519,7 +2517,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", test_cmd_w_to_a, buffer, msg_index); } - else todo_wine + else { ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n", size, size_w_to_a, msg_index); @@ -2531,7 +2529,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV case 2: /* normal Unicode string */ case 3: /* IsTextUnicode false negative */ case 4: /* Chinese chars */ - if (unicode_server) todo_wine + if (unicode_server) { /* double A->W mapping */ /* NT uses the full size, XP+ only until the first null */