1 /*
2  * Unit tests for DDE functions
3  *
4  * Copyright (c) 2004 Dmitry Timoshkov
5  * Copyright (c) 2007 James Hawkins
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdarg.h>
23 #include <stdio.h>
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "dde.h"
30 #include "ddeml.h"
31 #include "winerror.h"
32 
33 #include "wine/test.h"
34 
35 static const WCHAR TEST_DDE_SERVICE[] = {'T','e','s','t','D','D','E','S','e','r','v','i','c','e',0};
36 
37 static char exec_cmdA[] = "ANSI dde command";
38 static WCHAR exec_cmdAW[] = {'A','N','S','I',' ','d','d','e',' ','c','o','m','m','a','n','d',0};
39 static WCHAR exec_cmdW[] = {'u','n','i','c','o','d','e',' ','d','d','e',' ','c','o','m','m','a','n','d',0};
40 static char exec_cmdWA[] = "unicode dde command";
41 
42 static WNDPROC old_dde_client_wndproc;
43 
44 static const DWORD default_timeout = 200;
45 
46 static BOOL is_cjk(void)
47 {
48     int lang_id = PRIMARYLANGID(GetUserDefaultLangID());
49 
50     if (lang_id == LANG_CHINESE || lang_id == LANG_JAPANESE || lang_id == LANG_KOREAN)
51         return TRUE;
52     return FALSE;
53 }
54 
55 static void flush_events(void)
56 {
57     MSG msg;
58     int diff = default_timeout;
59     int min_timeout = 50;
60     DWORD time = GetTickCount() + diff;
61 
62     while (diff > 0)
63     {
64         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
65         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
66         diff = time - GetTickCount();
67         min_timeout = 10;
68     }
69 }
70 
71 static void create_dde_window(HWND *hwnd, LPCSTR name, WNDPROC wndproc)
72 {
73     WNDCLASSA wcA;
74     ATOM aclass;
75 
76     memset(&wcA, 0, sizeof(wcA));
77     wcA.lpfnWndProc = wndproc;
78     wcA.lpszClassName = name;
79     wcA.hInstance = GetModuleHandleA(0);
80     aclass = RegisterClassA(&wcA);
81     ok (aclass, "RegisterClass failed\n");
82 
83     *hwnd = CreateWindowExA(0, name, NULL, WS_POPUP,
84                             500, 500, CW_USEDEFAULT, CW_USEDEFAULT,
85                             GetDesktopWindow(), 0, GetModuleHandleA(0), NULL);
86     ok(*hwnd != NULL, "CreateWindowExA failed\n");
87 }
88 
89 static void destroy_dde_window(HWND *hwnd, LPCSTR name)
90 {
91     DestroyWindow(*hwnd);
92     UnregisterClassA(name, GetModuleHandleA(NULL));
93 }
94 
95 static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
96 {
97     UINT_PTR lo, hi;
98     char str[MAX_PATH], *ptr;
99     HGLOBAL hglobal;
100     DDEDATA *data;
101     DDEPOKE *poke;
102     DWORD size;
103 
104     static int msg_index = 0;
105     static HWND client = 0;
106     static BOOL executed = FALSE;
107 
108     if (msg < WM_DDE_FIRST || msg > WM_DDE_LAST)
109         return DefWindowProcA(hwnd, msg, wparam, lparam);
110 
111     msg_index++;
112 
113     switch (msg)
114     {
115     case WM_DDE_INITIATE:
116     {
117         client = (HWND)wparam;
118         ok(msg_index == 1, "Expected 1, got %d\n", msg_index);
119 
120         GlobalGetAtomNameA(LOWORD(lparam), str, MAX_PATH);
121         ok(!lstrcmpA(str, "TestDDEService"), "Expected TestDDEService, got %s\n", str);
122 
123         GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH);
124         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
125 
126         SendMessageA(client, WM_DDE_ACK, (WPARAM)hwnd, lparam);
127 
128         break;
129     }
130 
131     case WM_DDE_REQUEST:
132     {
133         ok((msg_index >= 2 && msg_index <= 4) ||
134            (msg_index >= 7 && msg_index <= 8),
135            "Expected 2, 3, 4, 7 or 8, got %d\n", msg_index);
136         ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam);
137         ok(LOWORD(lparam) == CF_TEXT, "Expected CF_TEXT, got %d\n", LOWORD(lparam));
138 
139         GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH);
140         if (msg_index < 8)
141             ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str);
142         else
143             ok(!lstrcmpA(str, "executed"), "Expected executed, got %s\n", str);
144 
145         if (msg_index == 8)
146         {
147             if (executed)
148                 lstrcpyA(str, "command executed\r\n");
149             else
150                 lstrcpyA(str, "command not executed\r\n");
151         }
152         else
153             lstrcpyA(str, "requested data\r\n");
154 
155         size = FIELD_OFFSET(DDEDATA, Value[lstrlenA(str) + 1]);
156         hglobal = GlobalAlloc(GMEM_MOVEABLE, size);
157         ok(hglobal != NULL, "Expected non-NULL hglobal\n");
158 
159         data = GlobalLock(hglobal);
160         ZeroMemory(data, size);
161 
162         /* setting fResponse to FALSE at this point destroys
163          * the internal messaging state of native dde
164          */
165         data->fResponse = TRUE;
166 
167         if (msg_index == 2)
168             data->fRelease = TRUE;
169         else if (msg_index == 3)
170             data->fAckReq = TRUE;
171 
172         data->cfFormat = CF_TEXT;
173         lstrcpyA((LPSTR)data->Value, str);
174         GlobalUnlock(hglobal);
175 
176         lparam = PackDDElParam(WM_DDE_DATA, (UINT_PTR)hglobal, HIWORD(lparam));
177         PostMessageA(client, WM_DDE_DATA, (WPARAM)hwnd, lparam);
178 
179         break;
180     }
181 
182     case WM_DDE_POKE:
183     {
184         ok(msg_index == 5 || msg_index == 6, "Expected 5 or 6, got %d\n", msg_index);
185         ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam);
186 
187         UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi);
188 
189         GlobalGetAtomNameA(hi, str, MAX_PATH);
190         ok(!lstrcmpA(str, "poker"), "Expected poker, got %s\n", str);
191 
192         poke = GlobalLock((HGLOBAL)lo);
193         ok(poke != NULL, "Expected non-NULL poke\n");
194         ok(poke->fReserved == 0, "Expected 0, got %d\n", poke->fReserved);
195         ok(poke->unused == 0, "Expected 0, got %d\n", poke->unused);
196         ok(poke->fRelease == TRUE, "Expected TRUE, got %d\n", poke->fRelease);
197         ok(poke->cfFormat == CF_TEXT, "Expected CF_TEXT, got %d\n", poke->cfFormat);
198 
199         if (msg_index == 5)
200         {
201             size = GlobalSize((HGLOBAL)lo);
202             ok(size == 4 || broken(size == 32), /* sizes are rounded up on win9x */ "got %d\n", size);
203         }
204         else
205             ok(!lstrcmpA((LPSTR)poke->Value, "poke data\r\n"),
206                "Expected 'poke data\\r\\n', got %s\n", poke->Value);
207 
208         GlobalUnlock((HGLOBAL)lo);
209 
210         lparam = PackDDElParam(WM_DDE_ACK, DDE_FACK, hi);
211         PostMessageA(client, WM_DDE_ACK, (WPARAM)hwnd, lparam);
212 
213         break;
214     }
215 
216     case WM_DDE_EXECUTE:
217     {
218         ok(msg_index == 7, "Expected 7, got %d\n", msg_index);
219         ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam);
220 
221         ptr = GlobalLock((HGLOBAL)lparam);
222         ok(!lstrcmpA(ptr, "[Command(Var)]"), "Expected [Command(Var)], got %s\n", ptr);
223         GlobalUnlock((HGLOBAL)lparam);
224 
225         executed = TRUE;
226 
227         lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, DDE_FACK, lparam);
228         PostMessageA(client, WM_DDE_ACK, (WPARAM)hwnd, lparam);
229 
230         break;
231     }
232 
233     case WM_DDE_TERMINATE:
234     {
235         ok(msg_index == 9, "Expected 9, got %d\n", msg_index);
236         ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam);
237         ok(lparam == 0, "Expected 0, got %08lx\n", lparam);
238 
239         PostMessageA(client, WM_DDE_TERMINATE, (WPARAM)hwnd, 0);
240 
241         break;
242     }
243 
244     case WM_DDE_ACK:  /* happens on win9x when fAckReq is TRUE, ignore it */
245         ok(msg_index == 4, "Expected 4, got %d\n", msg_index);
246         msg_index--;
247         break;
248 
249     default:
250         ok(FALSE, "Unhandled msg: %08x\n", msg);
251     }
252 
253     return DefWindowProcA(hwnd, msg, wparam, lparam);
254 }
255 
256 static void test_msg_server(HANDLE hproc, HANDLE hthread)
257 {
258     MSG msg;
259     HWND hwnd;
260     DWORD res;
261 
262     create_dde_window(&hwnd, "dde_server", dde_server_wndproc);
263     ResumeThread( hthread );
264 
265     while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0)
266     {
267         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
268     }
269 
270     destroy_dde_window(&hwnd, "dde_server");
271     GetExitCodeProcess( hproc, &res );
272     ok( !res, "client failed with %u error(s)\n", res );
273 }
274 
275 static HDDEDATA CALLBACK client_ddeml_callback(UINT uType, UINT uFmt, HCONV hconv,
276                                                HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
277                                                ULONG_PTR dwData1, ULONG_PTR dwData2)
278 {
279     ok(FALSE, "Unhandled msg: %08x\n", uType);
280     return 0;
281 }
282 
283 static void test_ddeml_client(void)
284 {
285     UINT ret;
286     char buffer[32];
287     LPSTR str;
288     DWORD size, res;
289     HDDEDATA hdata, op;
290     HSZ server, topic, item;
291     DWORD client_pid;
292     HCONV conversation;
293 
294     client_pid = 0;
295     ret = DdeInitializeA(&client_pid, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
296     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
297 
298     /* FIXME: make these atoms global and check them in the server */
299 
300     server = DdeCreateStringHandleA(client_pid, "TestDDEService", CP_WINANSI);
301     topic = DdeCreateStringHandleA(client_pid, "TestDDETopic", CP_WINANSI);
302 
303     DdeGetLastError(client_pid);
304     conversation = DdeConnect(client_pid, server, topic, NULL);
305     ok(conversation != NULL, "Expected non-NULL conversation\n");
306     ret = DdeGetLastError(client_pid);
307     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
308 
309     DdeFreeStringHandle(client_pid, server);
310 
311     item = DdeCreateStringHandleA(client_pid, "request", CP_WINANSI);
312 
313     /* XTYP_REQUEST, fRelease = TRUE */
314     res = 0xdeadbeef;
315     DdeGetLastError(client_pid);
316     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
317     ret = DdeGetLastError(client_pid);
318     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
319     ok(res == DDE_FNOTPROCESSED || broken(res == 0xdeadbeef), /* win9x */
320        "Expected DDE_FNOTPROCESSED, got %08x\n", res);
321     ok( hdata != NULL, "hdata is NULL\n" );
322     if (hdata)
323     {
324         str = (LPSTR)DdeAccessData(hdata, &size);
325         ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str);
326         ok(size == 17, "Expected 17, got %d\n", size);
327 
328         ret = DdeUnaccessData(hdata);
329         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
330     }
331 
332     /* XTYP_REQUEST, fAckReq = TRUE */
333     res = 0xdeadbeef;
334     DdeGetLastError(client_pid);
335     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
336     ret = DdeGetLastError(client_pid);
337     ok(res == DDE_FNOTPROCESSED || broken(res == 0xdeadbeef), /* win9x */
338        "Expected DDE_FNOTPROCESSED, got %x\n", res);
339 todo_wine
340     ok(ret == DMLERR_MEMORY_ERROR || broken(ret == 0), /* win9x */
341        "Expected DMLERR_MEMORY_ERROR, got %d\n", ret);
342     ok( hdata != NULL, "hdata is NULL\n" );
343     if (hdata)
344     {
345         str = (LPSTR)DdeAccessData(hdata, &size);
346         ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str);
347         ok(size == 17, "Expected 17, got %d\n", size);
348 
349         ret = DdeUnaccessData(hdata);
350         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
351     }
352 
353     /* XTYP_REQUEST, all params normal */
354     res = 0xdeadbeef;
355     DdeGetLastError(client_pid);
356     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
357     ret = DdeGetLastError(client_pid);
358     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
359     ok(res == DDE_FNOTPROCESSED || broken(res == 0xdeadbeef), /* win9x */
360        "Expected DDE_FNOTPROCESSED, got %x\n", res);
361     if (hdata == NULL)
362         ok(FALSE, "hdata is NULL\n");
363     else
364     {
365         str = (LPSTR)DdeAccessData(hdata, &size);
366         ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str);
367         ok(size == 17, "Expected 17, got %d\n", size);
368 
369         ret = DdeUnaccessData(hdata);
370         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
371     }
372 
373     /* XTYP_REQUEST, no item */
374     res = 0xdeadbeef;
375     DdeGetLastError(client_pid);
376     hdata = DdeClientTransaction(NULL, 0, conversation, 0, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
377     ret = DdeGetLastError(client_pid);
378     ok(hdata == NULL, "Expected NULL hdata, got %p\n", hdata);
379     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08x\n", res);
380     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
381 
382     DdeFreeStringHandle(client_pid, item);
383 
384     item = DdeCreateStringHandleA(client_pid, "poker", CP_WINANSI);
385 
386     lstrcpyA(buffer, "poke data\r\n");
387     hdata = DdeCreateDataHandle(client_pid, (LPBYTE)buffer, lstrlenA(buffer) + 1,
388                                 0, item, CF_TEXT, 0);
389     ok(hdata != NULL, "Expected non-NULL hdata\n");
390 
391     /* XTYP_POKE, no item */
392     res = 0xdeadbeef;
393     DdeGetLastError(client_pid);
394     op = DdeClientTransaction((LPBYTE)hdata, -1, conversation, 0, CF_TEXT, XTYP_POKE, default_timeout, &res);
395     ret = DdeGetLastError(client_pid);
396     ok(op == NULL, "Expected NULL, got %p\n", op);
397     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
398     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
399 
400     /* XTYP_POKE, no data */
401     res = 0xdeadbeef;
402     DdeGetLastError(client_pid);
403     op = DdeClientTransaction(NULL, 0, conversation, 0, CF_TEXT, XTYP_POKE, default_timeout, &res);
404     ret = DdeGetLastError(client_pid);
405     ok(op == NULL, "Expected NULL, got %p\n", op);
406     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
407     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
408 
409     /* XTYP_POKE, wrong size */
410     res = 0xdeadbeef;
411     DdeGetLastError(client_pid);
412     op = DdeClientTransaction((LPBYTE)hdata, 0, conversation, item, CF_TEXT, XTYP_POKE, default_timeout, &res);
413     ret = DdeGetLastError(client_pid);
414     ok(op == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", op);
415     ok(res == DDE_FACK || broken(res == (0xdead0000 | DDE_FACK)), /* win9x */
416        "Expected DDE_FACK, got %x\n", res);
417     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
418 
419     /* XTYP_POKE, correct params */
420     res = 0xdeadbeef;
421     DdeGetLastError(client_pid);
422     op = DdeClientTransaction((LPBYTE)hdata, -1, conversation, item, CF_TEXT, XTYP_POKE, default_timeout, &res);
423     ret = DdeGetLastError(client_pid);
424     ok(op == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", op);
425     ok(res == DDE_FACK || broken(res == (0xdead0000 | DDE_FACK)), /* win9x */
426        "Expected DDE_FACK, got %x\n", res);
427     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
428 
429     DdeFreeDataHandle(hdata);
430 
431     lstrcpyA(buffer, "[Command(Var)]");
432     hdata = DdeCreateDataHandle(client_pid, (LPBYTE)buffer, lstrlenA(buffer) + 1,
433                                 0, NULL, CF_TEXT, 0);
434     ok(hdata != NULL, "Expected non-NULL hdata\n");
435 
436     /* XTYP_EXECUTE, correct params */
437     res = 0xdeadbeef;
438     DdeGetLastError(client_pid);
439     op = DdeClientTransaction((LPBYTE)hdata, -1, conversation, NULL, 0, XTYP_EXECUTE, default_timeout, &res);
440     ret = DdeGetLastError(client_pid);
441     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
442     ok(op == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", op);
443     ok(res == DDE_FACK || broken(res == (0xdead0000 | DDE_FACK)), /* win9x */
444        "Expected DDE_FACK, got %x\n", res);
445 
446     /* XTYP_EXECUTE, no data */
447     res = 0xdeadbeef;
448     DdeGetLastError(client_pid);
449     op = DdeClientTransaction(NULL, 0, conversation, NULL, 0, XTYP_EXECUTE, default_timeout, &res);
450     ret = DdeGetLastError(client_pid);
451     ok(op == NULL || broken(op == (HDDEDATA)TRUE), /* win9x */ "Expected NULL, got %p\n", op);
452     if (!op)
453     {
454         ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
455         ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret);
456     }
457     else  /* win9x */
458     {
459         ok(res == (0xdead0000 | DDE_FACK), "Expected DDE_FACK, got %x\n", res);
460         ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
461     }
462 
463     /* XTYP_EXECUTE, no data, -1 size */
464     res = 0xdeadbeef;
465     DdeGetLastError(client_pid);
466     op = DdeClientTransaction(NULL, -1, conversation, NULL, 0, XTYP_EXECUTE, default_timeout, &res);
467     ret = DdeGetLastError(client_pid);
468     ok(op == NULL, "Expected NULL, got %p\n", op);
469     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
470     ok(ret == DMLERR_INVALIDPARAMETER || broken(ret == DMLERR_NO_ERROR), /* win9x */
471        "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
472 
473     DdeFreeStringHandle(client_pid, topic);
474     DdeFreeDataHandle(hdata);
475 
476     item = DdeCreateStringHandleA(client_pid, "executed", CP_WINANSI);
477 
478     /* verify the execute */
479     res = 0xdeadbeef;
480     DdeGetLastError(client_pid);
481     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
482     ret = DdeGetLastError(client_pid);
483     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
484     ok(res == DDE_FNOTPROCESSED || broken(res == (0xdead0000 | DDE_FNOTPROCESSED)), /* win9x */
485        "Expected DDE_FNOTPROCESSED, got %d\n", res);
486     if (hdata == NULL)
487         ok(FALSE, "hdata is NULL\n");
488     else
489     {
490         str = (LPSTR)DdeAccessData(hdata, &size);
491         ok(!lstrcmpA(str, "command executed\r\n"), "Expected 'command executed\\r\\n', got %s\n", str);
492         ok(size == 19, "Expected 19, got %d\n", size);
493 
494         ret = DdeUnaccessData(hdata);
495         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
496     }
497 
498     /* invalid transactions */
499     res = 0xdeadbeef;
500     DdeGetLastError(client_pid);
501     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_ADVREQ, default_timeout, &res);
502     ret = DdeGetLastError(client_pid);
503     ok(op == NULL, "Expected NULL, got %p\n", op);
504     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
505     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
506 
507     res = 0xdeadbeef;
508     DdeGetLastError(client_pid);
509     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_CONNECT, default_timeout, &res);
510     ret = DdeGetLastError(client_pid);
511     ok(op == NULL, "Expected NULL, got %p\n", op);
512     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
513     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
514 
515     res = 0xdeadbeef;
516     DdeGetLastError(client_pid);
517     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_CONNECT_CONFIRM, default_timeout, &res);
518     ret = DdeGetLastError(client_pid);
519     ok(op == NULL, "Expected NULL, got %p\n", op);
520     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
521     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
522 
523     res = 0xdeadbeef;
524     DdeGetLastError(client_pid);
525     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_DISCONNECT, default_timeout, &res);
526     ret = DdeGetLastError(client_pid);
527     ok(op == NULL, "Expected NULL, got %p\n", op);
528     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
529     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
530 
531     res = 0xdeadbeef;
532     DdeGetLastError(client_pid);
533     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_ERROR, default_timeout, &res);
534     ret = DdeGetLastError(client_pid);
535     ok(op == NULL, "Expected NULL, got %p\n", op);
536     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
537     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
538 
539     res = 0xdeadbeef;
540     DdeGetLastError(client_pid);
541     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_MONITOR, default_timeout, &res);
542     ret = DdeGetLastError(client_pid);
543     ok(op == NULL, "Expected NULL, got %p\n", op);
544     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
545     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
546 
547     res = 0xdeadbeef;
548     DdeGetLastError(client_pid);
549     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REGISTER, default_timeout, &res);
550     ret = DdeGetLastError(client_pid);
551     ok(op == NULL, "Expected NULL, got %p\n", op);
552     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
553     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
554 
555     res = 0xdeadbeef;
556     DdeGetLastError(client_pid);
557     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_UNREGISTER, default_timeout, &res);
558     ret = DdeGetLastError(client_pid);
559     ok(op == NULL, "Expected NULL, got %p\n", op);
560     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
561     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
562 
563     res = 0xdeadbeef;
564     DdeGetLastError(client_pid);
565     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_WILDCONNECT, default_timeout, &res);
566     ret = DdeGetLastError(client_pid);
567     ok(op == NULL, "Expected NULL, got %p\n", op);
568     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
569     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
570 
571     res = 0xdeadbeef;
572     DdeGetLastError(client_pid);
573     op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_XACT_COMPLETE, default_timeout, &res);
574     ret = DdeGetLastError(client_pid);
575     ok(op == NULL, "Expected NULL, got %p\n", op);
576     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
577     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
578 
579     DdeFreeStringHandle(client_pid, item);
580 
581     ret = DdeDisconnect(conversation);
582     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
583 
584     ret = DdeUninitialize(client_pid);
585     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
586 }
587 
588 static DWORD server_pid;
589 
590 static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hconv,
591                                                HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
592                                                ULONG_PTR dwData1, ULONG_PTR dwData2)
593 {
594     char str[MAX_PATH], *ptr;
595     HDDEDATA ret = NULL;
596     DWORD size;
597 
598     static int msg_index = 0;
599     static HCONV conversation = 0;
600 
601     msg_index++;
602 
603     switch (uType)
604     {
605     case XTYP_REGISTER:
606     {
607         ok(msg_index == 1, "Expected 1, got %d\n", msg_index);
608         ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
609         ok(hconv == 0, "Expected 0, got %p\n", hconv);
610         ok(hdata == 0, "Expected 0, got %p\n", hdata);
611         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
612         ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2);
613 
614         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
615         ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str);
616         ok(size == 13, "Expected 13, got %d\n", size);
617 
618         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
619         if (!strncmp( str, "TestDDEServer:(", 15 ))  /* win9x style */
620         {
621             ok(size == 16 + 2*sizeof(WORD), "Got size %d for %s\n", size, str);
622         }
623         else
624         {
625             ok(!strncmp(str, "TestDDEServer(", 14), "Expected TestDDEServer(, got %s\n", str);
626             ok(size == 17 + 2*sizeof(ULONG_PTR), "Got size %d for %s\n", size, str);
627         }
628             ok(str[size - 1] == ')', "Expected ')', got %c\n", str[size - 1]);
629 
630         return (HDDEDATA)TRUE;
631     }
632 
633     case XTYP_CONNECT:
634     {
635         ok(msg_index == 2, "Expected 2, got %d\n", msg_index);
636         ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
637         ok(hconv == 0, "Expected 0, got %p\n", hconv);
638         ok(hdata == 0, "Expected 0, got %p\n", hdata);
639         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
640         ok(dwData2 == FALSE, "Expected FALSE, got %08lx\n", dwData2);
641 
642         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
643         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
644         ok(size == 12, "Expected 12, got %d\n", size);
645 
646         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
647         ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str);
648         ok(size == 13, "Expected 13, got %d\n", size);
649 
650         return (HDDEDATA)TRUE;
651     }
652 
653     case XTYP_CONNECT_CONFIRM:
654     {
655         conversation = hconv;
656 
657         ok(msg_index == 3, "Expected 3, got %d\n", msg_index);
658         ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
659         ok(hconv != NULL, "Expected non-NULL hconv\n");
660         ok(hdata == 0, "Expected 0, got %p\n", hdata);
661         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
662         ok(dwData2 == FALSE, "Expected FALSE, got %08lx\n", dwData2);
663 
664         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
665         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
666         ok(size == 12, "Expected 12, got %d\n", size);
667 
668         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
669         ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str);
670         ok(size == 13, "Expected 13, got %d\n", size);
671 
672         return (HDDEDATA)TRUE;
673     }
674 
675     case XTYP_REQUEST:
676     {
677         ok(msg_index == 4 || msg_index == 5 || msg_index == 6,
678            "Expected 4, 5 or 6, got %d\n", msg_index);
679         ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv);
680         ok(hdata == 0, "Expected 0, got %p\n", hdata);
681         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
682         ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2);
683 
684         if (msg_index == 4)
685             ok(uFmt == 0xbeef, "Expected 0xbeef, got %08x\n", uFmt);
686         else
687             ok(uFmt == CF_TEXT, "Expected CF_TEXT, got %08x\n", uFmt);
688 
689         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
690         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
691         ok(size == 12, "Expected 12, got %d\n", size);
692 
693         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
694 
695         if (msg_index == 5)
696         {
697             {
698                 ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str);
699                 ok(size == 1, "Expected 1, got %d\n", size);
700             }
701         }
702         else if (msg_index == 6)
703         {
704             ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str);
705             ok(size == 7, "Expected 7, got %d\n", size);
706         }
707 
708         if (msg_index == 6)
709         {
710             lstrcpyA(str, "requested data\r\n");
711             return DdeCreateDataHandle(server_pid, (LPBYTE)str, lstrlenA(str) + 1,
712                                         0, hsz2, CF_TEXT, 0);
713         }
714 
715         return NULL;
716     }
717 
718     case XTYP_POKE:
719     {
720         ok(msg_index == 7 || msg_index == 8, "Expected 7 or 8, got %d\n", msg_index);
721         ok(uFmt == CF_TEXT, "Expected CF_TEXT, got %d\n", uFmt);
722         ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv);
723         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
724         ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2);
725 
726         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
727         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
728         ok(size == 12, "Expected 12, got %d\n", size);
729 
730         ptr = (LPSTR)DdeAccessData(hdata, &size);
731         ok(!lstrcmpA(ptr, "poke data\r\n"), "Expected 'poke data\\r\\n', got %s\n", ptr);
732         ok(size == 12 || broken(size == 28), /* sizes are rounded up on win9x */
733            "Expected 12, got %d\n", size);
734         DdeUnaccessData(hdata);
735 
736         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
737         if (msg_index == 7)
738         {
739             {
740                 ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str);
741                 ok(size == 1, "Expected 1, got %d\n", size);
742             }
743         }
744         else
745         {
746             ok(!lstrcmpA(str, "poke"), "Expected poke, got %s\n", str);
747             ok(size == 4, "Expected 4, got %d\n", size);
748         }
749 
750         return (HDDEDATA)DDE_FACK;
751     }
752 
753     case XTYP_EXECUTE:
754     {
755         ok(msg_index >= 9 && msg_index <= 11, "Expected 9 or 11, got %d\n", msg_index);
756         ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
757         ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv);
758         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
759         ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2);
760         ok(hsz2 == 0, "Expected 0, got %p\n", hsz2);
761 
762         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
763         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
764         ok(size == 12, "Expected 12, got %d\n", size);
765 
766         if (msg_index == 9 || msg_index == 11)
767         {
768             ptr = (LPSTR)DdeAccessData(hdata, &size);
769 
770             if (msg_index == 9)
771             {
772                 ok(!lstrcmpA(ptr, "[Command(Var)]"), "Expected '[Command(Var)]', got %s\n", ptr);
773                 ok(size == 15, "Expected 15, got %d\n", size);
774                 ret = (HDDEDATA)DDE_FACK;
775             }
776             else
777             {
778                 ok(!lstrcmpA(ptr, "[BadCommand(Var)]"), "Expected '[BadCommand(Var)]', got %s\n", ptr);
779                 ok(size == 18, "Expected 18, got %d\n", size);
780                 ret = DDE_FNOTPROCESSED;
781             }
782 
783             DdeUnaccessData(hdata);
784         }
785         else if (msg_index == 10)
786         {
787             DWORD rsize = 0;
788 
789             size = DdeGetData(hdata, NULL, 0, 0);
790             ok(size == 17, "DdeGetData should have returned 17 not %d\n", size);
791             ptr = HeapAlloc(GetProcessHeap(), 0, size);
792             ok(ptr != NULL,"HeapAlloc should have returned ptr not NULL\n");
793             rsize = DdeGetData(hdata, (LPBYTE)ptr, size, 0);
794             ok(rsize == size, "DdeGetData did not return %d bytes but %d\n", size, rsize);
795 
796             ok(!lstrcmpA(ptr, "[Command-2(Var)]"), "Expected '[Command-2(Var)]' got %s\n", ptr);
797             ok(size == 17, "Expected 17, got %d\n", size);
798             ret = (HDDEDATA)DDE_FACK;
799 
800             HeapFree(GetProcessHeap(), 0, ptr);
801         }
802 
803         return ret;
804     }
805 
806     case XTYP_DISCONNECT:
807     {
808         ok(msg_index == 12, "Expected 12, got %d\n", msg_index);
809         ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
810         ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv);
811         ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1);
812         ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2);
813         ok(hsz1 == 0, "Expected 0, got %p\n", hsz2);
814         ok(hsz2 == 0, "Expected 0, got %p\n", hsz2);
815 
816         return 0;
817     }
818 
819     default:
820         ok(FALSE, "Unhandled msg: %08x\n", uType);
821     }
822 
823     return 0;
824 }
825 
826 static void test_ddeml_server(HANDLE hproc)
827 {
828     MSG msg;
829     UINT res;
830     BOOL ret;
831     HSZ server;
832     HDDEDATA hdata;
833 
834     /* set up DDE server */
835     server_pid = 0;
836     res = DdeInitializeA(&server_pid, server_ddeml_callback, APPCLASS_STANDARD, 0);
837     ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res);
838 
839     server = DdeCreateStringHandleA(server_pid, "TestDDEServer", CP_WINANSI);
840     ok(server != NULL, "Expected non-NULL string handle\n");
841 
842     hdata = DdeNameService(server_pid, server, 0, DNS_REGISTER);
843     ok(hdata == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", hdata);
844 
845     while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0)
846     {
847         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
848     }
849     ret = DdeUninitialize(server_pid);
850     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
851     GetExitCodeProcess( hproc, &res );
852     ok( !res, "client failed with %u error(s)\n", res );
853 }
854 
855 static HWND client_hwnd, server_hwnd;
856 static ATOM server, topic, item;
857 static HGLOBAL execute_hglobal;
858 
859 static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
860 {
861     char str[MAX_PATH];
862     UINT_PTR lo, hi;
863     DDEDATA *data;
864     DDEACK *ack;
865     DWORD size;
866     LPSTR ptr;
867 
868     static int msg_index = 0;
869 
870     if (msg < WM_DDE_FIRST || msg > WM_DDE_LAST)
871         return DefWindowProcA(hwnd, msg, wparam, lparam);
872 
873     msg_index++;
874 
875     switch (msg)
876     {
877     case WM_DDE_INITIATE:
878     {
879         ok(msg_index == 1, "Expected 1, got %d\n", msg_index);
880         ok(wparam == (WPARAM)client_hwnd, "Expected client hwnd, got %08lx\n", wparam);
881 
882         size = GlobalGetAtomNameA(LOWORD(lparam), str, MAX_PATH);
883         ok(LOWORD(lparam) == server, "Expected server atom, got %08x\n", LOWORD(lparam));
884         ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str);
885         ok(size == 13, "Expected 13, got %d\n", size);
886 
887         size = GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH);
888         ok(HIWORD(lparam) == topic, "Expected topic atom, got %08x\n", HIWORD(lparam));
889         ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
890         ok(size == 12, "Expected 12, got %d\n", size);
891 
892         break;
893     }
894 
895     case WM_DDE_ACK:
896     {
897         ok((msg_index >= 2 && msg_index <= 4) || (msg_index >= 6 && msg_index <= 11),
898            "Expected 2, 3, 4, 6, 7, 8, 9, 10 or 11, got %d\n", msg_index);
899 
900         if (msg_index == 2)
901         {
902             server_hwnd = (HWND)wparam;
903             ok(wparam != 0, "Expected non-NULL wparam, got %08lx\n", wparam);
904 
905             size = GlobalGetAtomNameA(LOWORD(lparam), str, MAX_PATH);
906             ok(LOWORD(lparam) == server, "Expected server atom, got %08x\n", LOWORD(lparam));
907             ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str);
908             ok(size == 13, "Expected 13, got %d\n", size);
909 
910             size = GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH);
911             ok(HIWORD(lparam) == topic, "Expected topic atom, got %08x\n", HIWORD(lparam));
912             ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str);
913             ok(size == 12, "Expected 12, got %d\n", size);
914         }
915         else if (msg_index >= 9 && msg_index <= 11)
916         {
917             ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam);
918 
919             UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
920 
921             ack = (DDEACK *)&lo;
922             ok(ack->bAppReturnCode == 0, "Expected 0, got %d\n", ack->bAppReturnCode);
923             ok(ack->reserved == 0, "Expected 0, got %d\n", ack->reserved);
924             ok(ack->fBusy == FALSE, "Expected FALSE, got %d\n", ack->fBusy);
925 
926             ok(hi == (UINT_PTR)execute_hglobal, "Expected execute hglobal, got %08lx\n", hi);
927             ptr = GlobalLock((HGLOBAL)hi);
928 
929             if (msg_index == 9)
930             {
931                 ok(ack->fAck == TRUE, "Expected TRUE, got %d\n", ack->fAck);
932                 ok(!lstrcmpA(ptr, "[Command(Var)]"), "Expected '[Command(Var)]', got %s\n", ptr);
933             } else if (msg_index == 10)
934             {
935                 ok(ack->fAck == TRUE, "Expected TRUE, got %d\n", ack->fAck);
936                 ok(!lstrcmpA(ptr, "[Command-2(Var)]"), "Expected '[Command-2(Var)]', got %s\n", ptr);
937             }
938             else
939             {
940                 ok(ack->fAck == FALSE, "Expected FALSE, got %d\n", ack->fAck);
941                 ok(!lstrcmpA(ptr, "[BadCommand(Var)]"), "Expected '[BadCommand(Var)]', got %s\n", ptr);
942             }
943 
944             GlobalUnlock((HGLOBAL)hi);
945         }
946         else
947         {
948             ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam);
949 
950             UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
951 
952             ack = (DDEACK *)&lo;
953             ok(ack->bAppReturnCode == 0, "Expected 0, got %d\n", ack->bAppReturnCode);
954             ok(ack->reserved == 0, "Expected 0, got %d\n", ack->reserved);
955             ok(ack->fBusy == FALSE, "Expected FALSE, got %d\n", ack->fBusy);
956 
957             if (msg_index >= 7)
958                 ok(ack->fAck == TRUE, "Expected TRUE, got %d\n", ack->fAck);
959             else
960             {
961                 if (msg_index == 6) todo_wine
962                 ok(ack->fAck == FALSE, "Expected FALSE, got %d\n", ack->fAck);
963             }
964 
965             size = GlobalGetAtomNameA(hi, str, MAX_PATH);
966             if (msg_index == 3)
967             {
968                 ok(hi == item, "Expected item atom, got %08lx\n", hi);
969                 ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str);
970                 ok(size == 7, "Expected 7, got %d\n", size);
971             }
972             else if (msg_index == 4 || msg_index == 7)
973             {
974                 ok(hi == 0, "Expected 0, got %08lx\n", hi);
975                 ok(size == 0, "Expected empty string, got %d\n", size);
976             }
977             else
978             {
979                 ok(hi == item, "Expected item atom, got %08lx\n", hi);
980                 if (msg_index == 6) todo_wine
981                 {
982                     ok(!lstrcmpA(str, "poke"), "Expected poke, got %s\n", str);
983                     ok(size == 4, "Expected 4, got %d\n", size);
984                 }
985             }
986         }
987 
988         break;
989     }
990 
991     case WM_DDE_DATA:
992     {
993         ok(msg_index == 5, "Expected 5, got %d\n", msg_index);
994         ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam);
995 
996         UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi);
997 
998         data = GlobalLock((HGLOBAL)lo);
999         ok(data->unused == 0, "Expected 0, got %d\n", data->unused);
1000         ok(data->fResponse == TRUE, "Expected TRUE, got %d\n", data->fResponse);
1001         todo_wine
1002         {
1003             ok(data->fRelease == TRUE, "Expected TRUE, got %d\n", data->fRelease);
1004         }
1005         ok(data->fAckReq == 0, "Expected 0, got %d\n", data->fAckReq);
1006         ok(data->cfFormat == CF_TEXT, "Expected CF_TEXT, got %d\n", data->cfFormat);
1007         ok(!lstrcmpA((LPSTR)data->Value, "requested data\r\n"),
1008            "Expected 'requested data\\r\\n', got %s\n", data->Value);
1009         GlobalUnlock((HGLOBAL)lo);
1010 
1011         size = GlobalGetAtomNameA(hi, str, MAX_PATH);
1012         ok(hi == item, "Expected item atom, got %08x\n", HIWORD(lparam));
1013         ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str);
1014         ok(size == 7, "Expected 7, got %d\n", size);
1015 
1016         GlobalFree((HGLOBAL)lo);
1017         GlobalDeleteAtom(hi);
1018 
1019         break;
1020     }
1021 
1022     default:
1023         ok(FALSE, "Unhandled msg: %08x\n", msg);
1024     }
1025 
1026     return DefWindowProcA(hwnd, msg, wparam, lparam);
1027 }
1028 
1029 static HGLOBAL create_poke(void)
1030 {
1031     HGLOBAL hglobal;
1032     DDEPOKE *poke;
1033     DWORD size;
1034 
1035     size = FIELD_OFFSET(DDEPOKE, Value[sizeof("poke data\r\n")]);
1036     hglobal = GlobalAlloc(GMEM_DDESHARE, size);
1037     ok(hglobal != 0, "Expected non-NULL hglobal\n");
1038 
1039     poke = GlobalLock(hglobal);
1040     poke->unused = 0;
1041     poke->fRelease = TRUE;
1042     poke->fReserved = TRUE;
1043     poke->cfFormat = CF_TEXT;
1044     lstrcpyA((LPSTR)poke->Value, "poke data\r\n");
1045     GlobalUnlock(hglobal);
1046 
1047     return hglobal;
1048 }
1049 
1050 static HGLOBAL create_execute(LPCSTR command)
1051 {
1052     HGLOBAL hglobal;
1053     LPSTR ptr;
1054 
1055     hglobal = GlobalAlloc(GMEM_DDESHARE, lstrlenA(command) + 1);
1056     ok(hglobal != 0, "Expected non-NULL hglobal\n");
1057 
1058     ptr = GlobalLock(hglobal);
1059     lstrcpyA(ptr, command);
1060     GlobalUnlock(hglobal);
1061 
1062     return hglobal;
1063 }
1064 
1065 static void test_msg_client(void)
1066 {
1067     HGLOBAL hglobal;
1068     LPARAM lparam;
1069 
1070     create_dde_window(&client_hwnd, "dde_client", dde_msg_client_wndproc);
1071 
1072     server = GlobalAddAtomA("TestDDEServer");
1073     ok(server != 0, "Expected non-NULL server\n");
1074 
1075     topic = GlobalAddAtomA("TestDDETopic");
1076     ok(topic != 0, "Expected non-NULL topic\n");
1077 
1078     SendMessageA(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)client_hwnd, MAKELONG(server, topic));
1079 
1080     GlobalDeleteAtom(server);
1081     GlobalDeleteAtom(topic);
1082 
1083     flush_events();
1084 
1085     item = GlobalAddAtomA("request");
1086     ok(item != 0, "Expected non-NULL item\n");
1087 
1088     /* WM_DDE_REQUEST, bad clipboard format */
1089     lparam = PackDDElParam(WM_DDE_REQUEST, 0xdeadbeef, item);
1090     PostMessageA(server_hwnd, WM_DDE_REQUEST, (WPARAM)client_hwnd, lparam);
1091 
1092     flush_events();
1093 
1094     /* WM_DDE_REQUEST, no item */
1095     lparam = PackDDElParam(WM_DDE_REQUEST, CF_TEXT, 0);
1096     PostMessageA(server_hwnd, WM_DDE_REQUEST, (WPARAM)client_hwnd, lparam);
1097 
1098     flush_events();
1099 
1100     /* WM_DDE_REQUEST, no client hwnd */
1101     lparam = PackDDElParam(WM_DDE_REQUEST, CF_TEXT, item);
1102     PostMessageA(server_hwnd, WM_DDE_REQUEST, 0, lparam);
1103 
1104     flush_events();
1105 
1106     /* WM_DDE_REQUEST, correct params */
1107     lparam = PackDDElParam(WM_DDE_REQUEST, CF_TEXT, item);
1108     PostMessageA(server_hwnd, WM_DDE_REQUEST, (WPARAM)client_hwnd, lparam);
1109 
1110     flush_events();
1111 
1112     GlobalDeleteAtom(item);
1113     item = GlobalAddAtomA("poke");
1114     ok(item != 0, "Expected non-NULL item\n");
1115 
1116     hglobal = create_poke();
1117 
1118     /* WM_DDE_POKE, no ddepoke */
1119     lparam = PackDDElParam(WM_DDE_POKE, 0, item);
1120     /* win9x returns 0 here and crashes in PostMessageA */
1121     if (lparam) {
1122         PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam);
1123         flush_events();
1124     }
1125     else
1126         win_skip("no lparam for WM_DDE_POKE\n");
1127 
1128 
1129     /* WM_DDE_POKE, no item */
1130     lparam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)hglobal, 0);
1131     PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam);
1132 
1133     flush_events();
1134 
1135     hglobal = create_poke();
1136 
1137     /* WM_DDE_POKE, no client hwnd */
1138     lparam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)hglobal, item);
1139     PostMessageA(server_hwnd, WM_DDE_POKE, 0, lparam);
1140 
1141     flush_events();
1142 
1143     /* WM_DDE_POKE, all params correct */
1144     lparam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)hglobal, item);
1145     PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam);
1146 
1147     flush_events();
1148 
1149     execute_hglobal = create_execute("[Command(Var)]");
1150 
1151     /* WM_DDE_EXECUTE, no lparam */
1152     PostMessageA(server_hwnd, WM_DDE_EXECUTE, (WPARAM)client_hwnd, 0);
1153 
1154     flush_events();
1155 
1156     /* WM_DDE_EXECUTE, no hglobal */
1157     lparam = PackDDElParam(WM_DDE_EXECUTE, 0, 0);
1158     PostMessageA(server_hwnd, WM_DDE_EXECUTE, (WPARAM)client_hwnd, lparam);
1159 
1160     flush_events();
1161 
1162     /* WM_DDE_EXECUTE, no client hwnd */
1163     lparam = PackDDElParam(WM_DDE_EXECUTE, 0, (UINT_PTR)execute_hglobal);
1164     PostMessageA(server_hwnd, WM_DDE_EXECUTE, 0, lparam);
1165 
1166     flush_events();
1167 
1168     /* WM_DDE_EXECUTE, all params correct */
1169     lparam = PackDDElParam(WM_DDE_EXECUTE, 0, (UINT_PTR)execute_hglobal);
1170     PostMessageA(server_hwnd, WM_DDE_EXECUTE, (WPARAM)client_hwnd, lparam);
1171 
1172     flush_events();
1173 
1174     GlobalFree(execute_hglobal);
1175     execute_hglobal = create_execute("[Command-2(Var)]");
1176 
1177     /* WM_DDE_EXECUTE, all params correct */
1178     lparam = PackDDElParam(WM_DDE_EXECUTE, 0, (UINT_PTR)execute_hglobal);
1179     PostMessageA(server_hwnd, WM_DDE_EXECUTE, (WPARAM)client_hwnd, lparam);
1180 
1181     flush_events();
1182 
1183     GlobalFree(execute_hglobal);
1184     execute_hglobal = create_execute("[BadCommand(Var)]");
1185 
1186     /* WM_DDE_EXECUTE that will get rejected */
1187     lparam = PackDDElParam(WM_DDE_EXECUTE, 0, (UINT_PTR)execute_hglobal);
1188     PostMessageA(server_hwnd, WM_DDE_EXECUTE, (WPARAM)client_hwnd, lparam);
1189 
1190     flush_events();
1191 
1192     destroy_dde_window(&client_hwnd, "dde_client");
1193 }
1194 
1195 static LRESULT WINAPI hook_dde_client_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1196 {
1197     UINT_PTR lo, hi;
1198 
1199     trace("hook_dde_client_wndprocA: %p %04x %08lx %08lx\n", hwnd, msg, wparam, lparam);
1200 
1201     switch (msg)
1202     {
1203     case WM_DDE_ACK:
1204         UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
1205         trace("WM_DDE_ACK: status %04lx hglobal %p\n", lo, (HGLOBAL)hi);
1206         break;
1207 
1208     default:
1209         break;
1210     }
1211     return CallWindowProcA(old_dde_client_wndproc, hwnd, msg, wparam, lparam);
1212 }
1213 
1214 static LRESULT WINAPI hook_dde_client_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1215 {
1216     UINT_PTR lo, hi;
1217 
1218     trace("hook_dde_client_wndprocW: %p %04x %08lx %08lx\n", hwnd, msg, wparam, lparam);
1219 
1220     switch (msg)
1221     {
1222     case WM_DDE_ACK:
1223         UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
1224         trace("WM_DDE_ACK: status %04lx hglobal %p\n", lo, (HGLOBAL)hi);
1225         break;
1226 
1227     default:
1228         break;
1229     }
1230     return CallWindowProcW(old_dde_client_wndproc, hwnd, msg, wparam, lparam);
1231 }
1232 
1233 static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1234 {
1235     static BOOL client_unicode, conv_unicode;
1236     static int step;
1237 
1238     switch (msg)
1239     {
1240     case WM_DDE_INITIATE:
1241     {
1242         ATOM aService = GlobalAddAtomW(TEST_DDE_SERVICE);
1243 
1244         trace("server A: got WM_DDE_INITIATE from %p (%s) with %08lx\n",
1245               (HWND)wparam, client_unicode ? "Unicode" : "ANSI", lparam);
1246 
1247         if (LOWORD(lparam) == aService)
1248         {
1249             client_unicode = IsWindowUnicode((HWND)wparam);
1250             conv_unicode = client_unicode;
1251             if (step >= 10) client_unicode = !client_unicode;  /* change the client window type */
1252 
1253             if (client_unicode)
1254                 old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrW((HWND)wparam, GWLP_WNDPROC,
1255                                                                     (ULONG_PTR)hook_dde_client_wndprocW);
1256             else
1257                 old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrA((HWND)wparam, GWLP_WNDPROC,
1258                                                                     (ULONG_PTR)hook_dde_client_wndprocA);
1259             trace("server: sending WM_DDE_ACK to %p\n", (HWND)wparam);
1260             SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK, aService, 0));
1261         }
1262         else
1263             GlobalDeleteAtom(aService);
1264         return 0;
1265     }
1266 
1267     case WM_DDE_EXECUTE:
1268     {
1269         DDEACK ack;
1270         WORD status;
1271         LPCSTR cmd;
1272         UINT_PTR lo, hi;
1273 
1274         trace("server A: got WM_DDE_EXECUTE from %p with %08lx\n", (HWND)wparam, lparam);
1275 
1276         UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi);
1277         trace("%08lx => lo %04lx hi %04lx\n", lparam, lo, hi);
1278 
1279         ack.bAppReturnCode = 0;
1280         ack.reserved = 0;
1281         ack.fBusy = 0;
1282         /* We have to send a negative acknowledge even if we don't
1283          * accept the command, otherwise Windows goes mad and next time
1284          * we send an acknowledge DDEML drops the connection.
1285          * Not sure how to call it: a bug or a feature.
1286          */
1287         ack.fAck = 0;
1288 
1289         if ((cmd = GlobalLock((HGLOBAL)hi)))
1290         {
1291             ack.fAck = !lstrcmpA(cmd, exec_cmdA) || !lstrcmpW((LPCWSTR)cmd, exec_cmdW);
1292 
1293             switch (step % 5)
1294             {
1295             case 0:  /* bad command */
1296                 trace( "server A got unhandled command\n" );
1297                 break;
1298 
1299             case 1:  /* ANSI command */
1300                 if (!conv_unicode)
1301                     ok( !lstrcmpA(cmd, exec_cmdA), "server A got wrong command '%s'\n", cmd );
1302                 else  /* we get garbage as the A command was mapped W->A */
1303                     ok( cmd[0] != exec_cmdA[0], "server A got wrong command '%s'\n", cmd );
1304                 break;
1305 
1306             case 2:  /* ANSI command in Unicode format */
1307                 if (conv_unicode)
1308                     ok( !lstrcmpA(cmd, exec_cmdA), "server A got wrong command '%s'\n", cmd );
1309                 else
1310                     ok( !lstrcmpW((LPCWSTR)cmd, exec_cmdAW), "server A got wrong command '%s'\n", cmd );
1311                 break;
1312 
1313             case 3:  /* Unicode command */
1314                 if (!conv_unicode)
1315                     ok( !lstrcmpW((LPCWSTR)cmd, exec_cmdW), "server A got wrong command '%s'\n", cmd );
1316                 else  /* correctly mapped W->A */
1317                     ok( !lstrcmpA(cmd, exec_cmdWA), "server A got wrong command '%s'\n", cmd );
1318                 break;
1319 
1320             case 4:  /* Unicode command in ANSI format */
1321                 if (!conv_unicode)
1322                     ok( !lstrcmpA(cmd, exec_cmdWA), "server A got wrong command '%s'\n", cmd );
1323                 else  /* we get garbage as the A command was mapped W->A */
1324                     ok( cmd[0] != exec_cmdWA[0], "server A got wrong command '%s'\n", cmd );
1325                 break;
1326             }
1327             GlobalUnlock((HGLOBAL)hi);
1328         }
1329         else ok( 0, "bad command data %lx\n", hi );
1330 
1331         step++;
1332         trace("server A: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam);
1333 
1334         status = *((WORD *)&ack);
1335         lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, status, hi);
1336 
1337         PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
1338         return 0;
1339     }
1340 
1341     case WM_DDE_TERMINATE:
1342     {
1343         DDEACK ack;
1344         WORD status;
1345 
1346         trace("server A: got WM_DDE_TERMINATE from %p with %08lx\n", (HWND)wparam, lparam);
1347 
1348         ack.bAppReturnCode = 0;
1349         ack.reserved = 0;
1350         ack.fBusy = 0;
1351         ack.fAck = 1;
1352 
1353         trace("server A: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam);
1354 
1355         status = *((WORD *)&ack);
1356         lparam = PackDDElParam(WM_DDE_ACK, status, 0);
1357 
1358         PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
1359         return 0;
1360     }
1361 
1362     default:
1363         break;
1364     }
1365 
1366     return DefWindowProcA(hwnd, msg, wparam, lparam);
1367 }
1368 
1369 static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1370 {
1371     static BOOL client_unicode, conv_unicode;
1372     static int step;
1373 
1374     switch (msg)
1375     {
1376     case WM_DDE_INITIATE:
1377     {
1378         ATOM aService = GlobalAddAtomW(TEST_DDE_SERVICE);
1379 
1380         if (LOWORD(lparam) == aService)
1381         {
1382             client_unicode = IsWindowUnicode((HWND)wparam);
1383             conv_unicode = client_unicode;
1384             if (step >= 10) client_unicode = !client_unicode;  /* change the client window type */
1385 
1386             if (client_unicode)
1387                 old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrW((HWND)wparam, GWLP_WNDPROC,
1388                                                                     (ULONG_PTR)hook_dde_client_wndprocW);
1389             else
1390                 old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrA((HWND)wparam, GWLP_WNDPROC,
1391                                                                     (ULONG_PTR)hook_dde_client_wndprocA);
1392             trace("server W: sending WM_DDE_ACK to %p\n", (HWND)wparam);
1393             SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK, aService, 0));
1394         }
1395         else
1396             GlobalDeleteAtom(aService);
1397 
1398         trace("server W: got WM_DDE_INITIATE from %p with %08lx (client %s conv %s)\n", (HWND)wparam,
1399               lparam, client_unicode ? "Unicode" : "ANSI", conv_unicode ? "Unicode" : "ANSI" );
1400 
1401         return 0;
1402     }
1403 
1404     case WM_DDE_EXECUTE:
1405     {
1406         DDEACK ack;
1407         WORD status;
1408         LPCSTR cmd;
1409         UINT_PTR lo, hi;
1410 
1411         trace("server W: got WM_DDE_EXECUTE from %p with %08lx\n", (HWND)wparam, lparam);
1412 
1413         UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi);
1414         trace("%08lx => lo %04lx hi %04lx\n", lparam, lo, hi);
1415 
1416         ack.bAppReturnCode = 0;
1417         ack.reserved = 0;
1418         ack.fBusy = 0;
1419         /* We have to send a negative acknowledge even if we don't
1420          * accept the command, otherwise Windows goes mad and next time
1421          * we send an acknowledge DDEML drops the connection.
1422          * Not sure how to call it: a bug or a feature.
1423          */
1424         ack.fAck = 0;
1425 
1426         if ((cmd = GlobalLock((HGLOBAL)hi)))
1427         {
1428             ack.fAck = !lstrcmpA(cmd, exec_cmdA) || !lstrcmpW((LPCWSTR)cmd, exec_cmdW);
1429 
1430             switch (step % 5)
1431             {
1432             case 0:  /* bad command */
1433                 trace( "server W got unhandled command\n" );
1434                 break;
1435 
1436             case 1:  /* ANSI command */
1437                 if (conv_unicode && !client_unicode) /* W->A mapping -> garbage */
1438                     ok( cmd[0] != exec_cmdA[0], "server W got wrong command '%s'\n", cmd );
1439                 else if (!conv_unicode && client_unicode)  /* A->W mapping */
1440                     ok( !lstrcmpW((LPCWSTR)cmd, exec_cmdAW), "server W got wrong command '%s'\n", cmd );
1441                 else
1442                     ok( !lstrcmpA(cmd, exec_cmdA), "server W got wrong command '%s'\n", cmd );
1443                 break;
1444 
1445             case 2:  /* ANSI command in Unicode format */
1446                 if (conv_unicode && !client_unicode) /* W->A mapping */
1447                     ok( !lstrcmpA(cmd, exec_cmdA), "server W got wrong command '%s'\n", cmd );
1448                 else if (!conv_unicode && client_unicode)  /* A->W mapping */
1449                     ok( *(WCHAR *)cmd == exec_cmdAW[0], "server W got wrong command '%s'\n", cmd );
1450                 else
1451                     ok( !lstrcmpW((LPCWSTR)cmd, exec_cmdAW), "server W got wrong command '%s'\n", cmd );
1452                 break;
1453 
1454             case 3:  /* Unicode command */
1455                 if (conv_unicode && !client_unicode) /* W->A mapping */
1456                     ok( !lstrcmpA(cmd, exec_cmdWA), "server W got wrong command '%s'\n", cmd );
1457                 else if (!conv_unicode && client_unicode)  /* A->W mapping */
1458                     ok( *(WCHAR *)cmd == exec_cmdW[0], "server W got wrong command '%s'\n", cmd );
1459                 else
1460                     ok( !lstrcmpW((LPCWSTR)cmd, exec_cmdW), "server W got wrong command '%s'\n", cmd );
1461                 break;
1462 
1463             case 4:  /* Unicode command in ANSI format */
1464                 if (conv_unicode && !client_unicode) /* W->A mapping -> garbage */
1465                     ok( cmd[0] != exec_cmdWA[0], "server W got wrong command '%s'\n", cmd );
1466                 else if (!conv_unicode && client_unicode)  /* A->W mapping */
1467                     ok( !lstrcmpW((LPCWSTR)cmd, exec_cmdW), "server W got wrong command '%s'\n", cmd );
1468                 else
1469                     ok( !lstrcmpA(cmd, exec_cmdWA), "server W got wrong command '%s'\n", cmd );
1470                 break;
1471             }
1472             GlobalUnlock((HGLOBAL)hi);
1473         }
1474         else ok( 0, "bad command data %lx\n", hi );
1475 
1476         step++;
1477         trace("server W: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam);
1478 
1479         status = *((WORD *)&ack);
1480         lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, status, hi);
1481 
1482         PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
1483         return 0;
1484     }
1485 
1486     case WM_DDE_TERMINATE:
1487     {
1488         DDEACK ack;
1489         WORD status;
1490 
1491         trace("server W: got WM_DDE_TERMINATE from %p with %08lx\n", (HWND)wparam, lparam);
1492 
1493         ack.bAppReturnCode = 0;
1494         ack.reserved = 0;
1495         ack.fBusy = 0;
1496         ack.fAck = 1;
1497 
1498         trace("server W: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam);
1499 
1500         status = *((WORD *)&ack);
1501         lparam = PackDDElParam(WM_DDE_ACK, status, 0);
1502 
1503         PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
1504         return 0;
1505     }
1506 
1507     default:
1508         break;
1509     }
1510 
1511     return DefWindowProcW(hwnd, msg, wparam, lparam);
1512 }
1513 
1514 static HWND create_dde_server( BOOL unicode )
1515 {
1516     WNDCLASSA wcA;
1517     WNDCLASSW wcW;
1518     HWND server;
1519     static const char server_class_nameA[] = "dde_server_windowA";
1520     static const WCHAR server_class_nameW[] = {'d','d','e','_','s','e','r','v','e','r','_','w','i','n','d','o','w','W',0};
1521 
1522     if (unicode)
1523     {
1524         memset(&wcW, 0, sizeof(wcW));
1525         wcW.lpfnWndProc = dde_server_wndprocW;
1526         wcW.lpszClassName = server_class_nameW;
1527         wcW.hInstance = GetModuleHandleA(0);
1528         RegisterClassW(&wcW);
1529 
1530         server = CreateWindowExW(0, server_class_nameW, NULL, WS_POPUP,
1531                                  100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1532                                  GetDesktopWindow(), 0, GetModuleHandleA(0), NULL);
1533     }
1534     else
1535     {
1536         memset(&wcA, 0, sizeof(wcA));
1537         wcA.lpfnWndProc = dde_server_wndprocA;
1538         wcA.lpszClassName = server_class_nameA;
1539         wcA.hInstance = GetModuleHandleA(0);
1540         RegisterClassA(&wcA);
1541 
1542         server = CreateWindowExA(0, server_class_nameA, NULL, WS_POPUP,
1543                                  100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1544                                  GetDesktopWindow(), 0, GetModuleHandleA(0), NULL);
1545     }
1546     ok(!IsWindowUnicode(server) == !unicode, "wrong unicode type\n");
1547     return server;
1548 }
1549 
1550 static HDDEDATA CALLBACK client_dde_callback(UINT uType, UINT uFmt, HCONV hconv,
1551                                      HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
1552                                      ULONG_PTR dwData1, ULONG_PTR dwData2)
1553 {
1554     static const char * const cmd_type[15] = {
1555         "XTYP_ERROR", "XTYP_ADVDATA", "XTYP_ADVREQ", "XTYP_ADVSTART",
1556         "XTYP_ADVSTOP", "XTYP_EXECUTE", "XTYP_CONNECT", "XTYP_CONNECT_CONFIRM",
1557         "XTYP_XACT_COMPLETE", "XTYP_POKE", "XTYP_REGISTER", "XTYP_REQUEST",
1558         "XTYP_DISCONNECT", "XTYP_UNREGISTER", "XTYP_WILDCONNECT" };
1559     UINT type;
1560     const char *cmd_name;
1561 
1562     type = (uType & XTYP_MASK) >> XTYP_SHIFT;
1563     cmd_name = (type <= 14) ? cmd_type[type] : "unknown";
1564 
1565     trace("client_dde_callback: %04x (%s) %d %p %p %p %p %08lx %08lx\n",
1566           uType, cmd_name, uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
1567     return 0;
1568 }
1569 
1570 static void test_dde_aw_transaction( BOOL client_unicode, BOOL server_unicode )
1571 {
1572     HSZ hsz_server;
1573     DWORD dde_inst, ret, err;
1574     HCONV hconv;
1575     HWND hwnd_server;
1576     CONVINFO info;
1577     HDDEDATA hdata;
1578     BOOL conv_unicode = client_unicode;
1579     BOOL got;
1580     static char test_cmd[] = "test dde command";
1581 
1582     if (!(hwnd_server = create_dde_server( server_unicode ))) return;
1583 
1584     dde_inst = 0;
1585     if (client_unicode)
1586         ret = DdeInitializeW(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0);
1587     else
1588         ret = DdeInitializeA(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0);
1589     ok(ret == DMLERR_NO_ERROR, "DdeInitializeA failed with error %04x (%x)\n",
1590        ret, DdeGetLastError(dde_inst));
1591 
1592     hsz_server = DdeCreateStringHandleW(dde_inst, TEST_DDE_SERVICE, CP_WINUNICODE);
1593 
1594     hconv = DdeConnect(dde_inst, hsz_server, 0, NULL);
1595     ok(hconv != 0, "DdeConnect error %x\n", DdeGetLastError(dde_inst));
1596     err = DdeGetLastError(dde_inst);
1597     ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
1598 
1599     info.cb = sizeof(info);
1600     ret = DdeQueryConvInfo(hconv, QID_SYNC, &info);
1601     ok(ret, "wrong info size %d, DdeQueryConvInfo error %x\n", ret, DdeGetLastError(dde_inst));
1602     ok(info.ConvCtxt.iCodePage == (client_unicode ? CP_WINUNICODE : CP_WINANSI),
1603        "wrong iCodePage %d\n", info.ConvCtxt.iCodePage);
1604     ok(!info.hConvPartner, "unexpected info.hConvPartner: %p\n", info.hConvPartner);
1605 todo_wine {
1606     ok((info.wStatus & DDE_FACK), "unexpected info.wStatus: %04x\n", info.wStatus);
1607 }
1608     ok((info.wStatus & (ST_CONNECTED | ST_CLIENT)) == (ST_CONNECTED | ST_CLIENT), "unexpected info.wStatus: %04x\n", info.wStatus);
1609     ok(info.wConvst == XST_CONNECTED, "unexpected info.wConvst: %04x\n", info.wConvst);
1610     ok(info.wType == 0, "unexpected info.wType: %04x\n", info.wType);
1611 
1612     client_unicode = IsWindowUnicode( info.hwnd );
1613     trace("hwnd %p, hwndPartner %p, unicode %u\n", info.hwnd, info.hwndPartner, client_unicode);
1614 
1615     trace("sending test client transaction command\n");
1616     ret = 0xdeadbeef;
1617     hdata = DdeClientTransaction((LPBYTE)test_cmd, strlen(test_cmd) + 1, hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret);
1618     ok(!hdata, "DdeClientTransaction succeeded\n");
1619     ok(ret == DDE_FNOTPROCESSED || broken(ret == (0xdead0000 | DDE_FNOTPROCESSED)), /* win9x */
1620        "wrong status code %04x\n", ret);
1621     err = DdeGetLastError(dde_inst);
1622     ok(err == DMLERR_NOTPROCESSED, "wrong dde error %x\n", err);
1623 
1624     trace("sending ANSI client transaction command\n");
1625     ret = 0xdeadbeef;
1626     hdata = DdeClientTransaction((LPBYTE)exec_cmdA, lstrlenA(exec_cmdA) + 1, hconv, 0, 0, XTYP_EXECUTE, 1000, &ret);
1627     err = DdeGetLastError(dde_inst);
1628     if (conv_unicode && (!client_unicode || !server_unicode))  /* W->A mapping -> garbage */
1629     {
1630         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1631         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1632         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1633     }
1634     else if (!conv_unicode && client_unicode && server_unicode)  /* A->W mapping -> wrong cmd */
1635     {
1636         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1637         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1638         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1639     }
1640     else  /* no mapping */
1641     {
1642         ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1643         ok(ret == DDE_FACK, "wrong status code %04x\n", ret);
1644         ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
1645     }
1646 
1647     trace("sending ANSI-as-Unicode client transaction command\n");
1648     ret = 0xdeadbeef;
1649     hdata = DdeClientTransaction((LPBYTE)exec_cmdAW, (lstrlenW(exec_cmdAW) + 1) * sizeof(WCHAR),
1650                                  hconv, 0, 0, XTYP_EXECUTE, 1000, &ret);
1651     err = DdeGetLastError(dde_inst);
1652     if (conv_unicode && (!client_unicode || !server_unicode))  /* W->A mapping */
1653     {
1654         ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1655         ok(ret == DDE_FACK, "wrong status code %04x\n", ret);
1656         ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
1657     }
1658     else if (!conv_unicode && client_unicode && server_unicode)  /* A->W mapping -> garbage */
1659     {
1660         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1661         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1662         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1663     }
1664     else  /* no mapping */
1665     {
1666         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1667         ok(ret == DDE_FNOTPROCESSED || broken(ret == (0xdead0000 | DDE_FNOTPROCESSED)), /* win9x */
1668            "wrong status code %04x\n", ret);
1669         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1670     }
1671 
1672     trace("sending unicode client transaction command\n");
1673     ret = 0xdeadbeef;
1674     hdata = DdeClientTransaction((LPBYTE)exec_cmdW, (lstrlenW(exec_cmdW) + 1) * sizeof(WCHAR), hconv, 0, 0, XTYP_EXECUTE, 1000, &ret);
1675     err = DdeGetLastError(dde_inst);
1676     if (conv_unicode && (!client_unicode || !server_unicode))  /* W->A mapping -> wrong cmd */
1677     {
1678         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1679         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1680         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1681     }
1682     else if (!conv_unicode && client_unicode && server_unicode)  /* A->W mapping -> garbage */
1683     {
1684         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1685         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1686         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1687     }
1688     else  /* no mapping */
1689     {
1690         ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1691         ok(ret == DDE_FACK, "wrong status code %04x\n", ret);
1692         ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
1693     }
1694 
1695     trace("sending Unicode-as-ANSI client transaction command\n");
1696     ret = 0xdeadbeef;
1697     hdata = DdeClientTransaction((LPBYTE)exec_cmdWA, lstrlenA(exec_cmdWA) + 1, hconv, 0, 0, XTYP_EXECUTE, 1000, &ret);
1698     err = DdeGetLastError(dde_inst);
1699     if (conv_unicode && (!client_unicode || !server_unicode))  /* W->A mapping -> garbage */
1700     {
1701         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1702         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1703         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1704     }
1705     else if (!conv_unicode && client_unicode && server_unicode)  /* A->W mapping */
1706     {
1707         ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1708         ok(ret == DDE_FACK, "wrong status code %04x\n", ret);
1709         ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
1710     }
1711     else  /* no mapping */
1712     {
1713         ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err);
1714         ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret);
1715         ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err);
1716     }
1717 
1718     got = DdeDisconnect(hconv);
1719     ok(got, "DdeDisconnect error %x\n", DdeGetLastError(dde_inst));
1720 
1721     info.cb = sizeof(info);
1722     ret = DdeQueryConvInfo(hconv, QID_SYNC, &info);
1723     ok(!ret, "DdeQueryConvInfo should fail\n");
1724     err = DdeGetLastError(dde_inst);
1725 todo_wine {
1726     ok(err == DMLERR_INVALIDPARAMETER, "wrong dde error %x\n", err);
1727 }
1728 
1729     got = DdeFreeStringHandle(dde_inst, hsz_server);
1730     ok(got, "DdeFreeStringHandle error %x\n", DdeGetLastError(dde_inst));
1731 
1732     /* This call hangs on win2k SP4 and XP SP1.
1733     DdeUninitialize(dde_inst);*/
1734 
1735     DestroyWindow(hwnd_server);
1736 }
1737 
1738 static void test_initialisation(void)
1739 {
1740     UINT ret;
1741     DWORD res;
1742     HDDEDATA hdata;
1743     HSZ server, topic, item;
1744     DWORD client_pid;
1745     HCONV conversation;
1746 
1747     /* Initialise without a valid server window. */
1748     client_pid = 0;
1749     ret = DdeInitializeA(&client_pid, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
1750     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
1751 
1752 
1753     server = DdeCreateStringHandleA(client_pid, "TestDDEService", CP_WINANSI);
1754     topic = DdeCreateStringHandleA(client_pid, "TestDDETopic", CP_WINANSI);
1755 
1756     DdeGetLastError(client_pid);
1757 
1758     /* There is no server window so no conversation can be extracted */
1759     conversation = DdeConnect(client_pid, server, topic, NULL);
1760     ok(conversation == NULL, "Expected NULL conversation, %p\n", conversation);
1761     ret = DdeGetLastError(client_pid);
1762     ok(ret == DMLERR_NO_CONV_ESTABLISHED, "Expected DMLERR_NO_CONV_ESTABLISHED, got %d\n", ret);
1763 
1764     DdeFreeStringHandle(client_pid, server);
1765 
1766     item = DdeCreateStringHandleA(client_pid, "request", CP_WINANSI);
1767 
1768     /* There is no conversation so an invalid parameter results */
1769     res = 0xdeadbeef;
1770     DdeGetLastError(client_pid);
1771     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
1772     ok(hdata == NULL, "Expected NULL, got %p\n", hdata);
1773     ret = DdeGetLastError(client_pid);
1774 todo_wine
1775     ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
1776     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08x\n", res);
1777 
1778     DdeFreeStringHandle(client_pid, server);
1779     ret = DdeDisconnect(conversation);
1780     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
1781 
1782     ret = DdeUninitialize(client_pid);
1783     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1784 }
1785 
1786 static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage)
1787 {
1788     static const WCHAR dde_string[] = {'D','D','E',' ','S','t','r','i','n','g',0};
1789     HSZ str_handle;
1790     WCHAR bufW[256];
1791     char buf[256];
1792     ATOM atom;
1793     int ret;
1794 
1795     str_handle = DdeCreateStringHandleW(dde_inst, dde_string, codepage);
1796     ok(str_handle != 0, "DdeCreateStringHandleW failed with error %08x\n",
1797        DdeGetLastError(dde_inst));
1798 
1799     ret = DdeQueryStringW(dde_inst, str_handle, NULL, 0, codepage);
1800     if (codepage == CP_WINANSI)
1801         ok(ret == 1, "DdeQueryStringW returned wrong length %d\n", ret);
1802     else
1803         ok(ret == lstrlenW(dde_string), "DdeQueryStringW returned wrong length %d\n", ret);
1804 
1805     ret = DdeQueryStringW(dde_inst, str_handle, bufW, 256, codepage);
1806     if (codepage == CP_WINANSI)
1807     {
1808         ok(ret == 1, "DdeQueryStringW returned wrong length %d\n", ret);
1809         ok(!lstrcmpA("D", (LPCSTR)bufW), "DdeQueryStringW returned wrong string\n");
1810     }
1811     else
1812     {
1813         ok(ret == lstrlenW(dde_string), "DdeQueryStringW returned wrong length %d\n", ret);
1814         ok(!lstrcmpW(dde_string, bufW), "DdeQueryStringW returned wrong string\n");
1815     }
1816 
1817     ret = DdeQueryStringA(dde_inst, str_handle, buf, 256, CP_WINANSI);
1818     if (codepage == CP_WINANSI)
1819     {
1820         ok(ret == 1, "DdeQueryStringA returned wrong length %d\n", ret);
1821         ok(!lstrcmpA("D", buf), "DdeQueryStringW returned wrong string\n");
1822     }
1823     else
1824     {
1825         ok(ret == lstrlenA("DDE String"), "DdeQueryStringA returned wrong length %d\n", ret);
1826         ok(!lstrcmpA("DDE String", buf), "DdeQueryStringA returned wrong string %s\n", buf);
1827     }
1828 
1829     ret = DdeQueryStringA(dde_inst, str_handle, buf, 256, CP_WINUNICODE);
1830     if (codepage == CP_WINANSI)
1831     {
1832         ok(ret == 1, "DdeQueryStringA returned wrong length %d\n", ret);
1833         ok(!lstrcmpA("D", buf), "DdeQueryStringA returned wrong string %s\n", buf);
1834     }
1835     else
1836     {
1837         ok(ret == lstrlenA("DDE String"), "DdeQueryStringA returned wrong length %d\n", ret);
1838         ok(!lstrcmpW(dde_string, (LPCWSTR)buf), "DdeQueryStringW returned wrong string\n");
1839     }
1840 
1841     if (codepage == CP_WINANSI)
1842     {
1843         atom = FindAtomA((LPSTR)dde_string);
1844         ok(atom != 0, "Expected a valid atom\n");
1845 
1846         SetLastError(0xdeadbeef);
1847         atom = GlobalFindAtomA((LPSTR)dde_string);
1848         ok(atom == 0, "Expected 0, got %d\n", atom);
1849         ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1850            "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1851     }
1852     else
1853     {
1854         atom = FindAtomW(dde_string);
1855         ok(atom != 0, "Expected a valid atom\n");
1856 
1857         SetLastError(0xdeadbeef);
1858         atom = GlobalFindAtomW(dde_string);
1859         ok(atom == 0, "Expected 0, got %d\n", atom);
1860         ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1861            "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1862     }
1863 
1864     ok(DdeFreeStringHandle(dde_inst, str_handle), "DdeFreeStringHandle failed\n");
1865 }
1866 
1867 static void test_DdeCreateDataHandle(void)
1868 {
1869     HDDEDATA hdata;
1870     DWORD dde_inst, dde_inst2;
1871     DWORD size;
1872     UINT res, err;
1873     BOOL ret;
1874     HSZ item;
1875     LPBYTE ptr;
1876     WCHAR item_str[] = {'i','t','e','m',0};
1877 
1878     dde_inst = 0;
1879     dde_inst2 = 0;
1880     res = DdeInitializeA(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
1881     ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res);
1882 
1883     res = DdeInitializeA(&dde_inst2, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
1884     ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res);
1885 
1886     /* 0 instance id
1887      * This block tests an invalid instance Id.  The correct behaviour is that if the instance Id
1888      * is invalid then the lastError of all instances is set to the error.  There are two instances
1889      * created, lastError is cleared, an error is generated and then both instances are checked to
1890      * ensure that they both have the same error set
1891      */
1892     item = DdeCreateStringHandleA(0, "item", CP_WINANSI);
1893     ok(item == NULL, "Expected NULL hsz got %p\n", item);
1894     err = DdeGetLastError(dde_inst);
1895     ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
1896     err = DdeGetLastError(dde_inst2);
1897     ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
1898     item = DdeCreateStringHandleW(0, item_str, CP_WINUNICODE);
1899     ok(item == NULL, "Expected NULL hsz got %p\n", item);
1900     err = DdeGetLastError(dde_inst);
1901     ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
1902     err = DdeGetLastError(dde_inst2);
1903     ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
1904 
1905     item = DdeCreateStringHandleA(dde_inst, "item", CP_WINANSI);
1906     ok(item != NULL, "Expected non-NULL hsz\n");
1907     item = DdeCreateStringHandleA(dde_inst2, "item", CP_WINANSI);
1908     ok(item != NULL, "Expected non-NULL hsz\n");
1909 
1910     if (0) {
1911         /* do not test with an invalid instance id: that crashes on win9x */
1912         hdata = DdeCreateDataHandle(0xdeadbeef, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0);
1913     }
1914 
1915     /* 0 instance id
1916      * This block tests an invalid instance Id.  The correct behaviour is that if the instance Id
1917      * is invalid then the lastError of all instances is set to the error.  There are two instances
1918      * created, lastError is cleared, an error is generated and then both instances are checked to
1919      * ensure that they both have the same error set
1920      */
1921     DdeGetLastError(dde_inst);
1922     DdeGetLastError(dde_inst2);
1923     hdata = DdeCreateDataHandle(0, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0);
1924     err = DdeGetLastError(dde_inst);
1925     ok(hdata == NULL, "Expected NULL, got %p\n", hdata);
1926     ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
1927     err = DdeGetLastError(dde_inst2);
1928     ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
1929 
1930     ret = DdeUninitialize(dde_inst2);
1931     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1932 
1933 
1934     /* NULL pSrc */
1935     DdeGetLastError(dde_inst);
1936     hdata = DdeCreateDataHandle(dde_inst, NULL, MAX_PATH, 0, item, CF_TEXT, 0);
1937     err = DdeGetLastError(dde_inst);
1938     ok(hdata != NULL, "Expected non-NULL hdata\n");
1939     ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err);
1940 
1941     ptr = DdeAccessData(hdata, &size);
1942     ok(ptr != NULL, "Expected non-NULL ptr\n");
1943     ok(size == 260, "Expected 260, got %d\n", size);
1944 
1945     ret = DdeUnaccessData(hdata);
1946     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1947 
1948     ret = DdeFreeDataHandle(hdata);
1949     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1950 
1951     /* cb is zero */
1952     DdeGetLastError(dde_inst);
1953     hdata = DdeCreateDataHandle(dde_inst, (LPBYTE)"data", 0, 0, item, CF_TEXT, 0);
1954     err = DdeGetLastError(dde_inst);
1955     ok(hdata != NULL, "Expected non-NULL hdata\n");
1956     ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err);
1957 
1958     ptr = DdeAccessData(hdata, &size);
1959     ok(ptr != NULL, "Expected non-NULL ptr\n");
1960     ok(size == 0, "Expected 0, got %d\n", size);
1961 
1962     ret = DdeUnaccessData(hdata);
1963     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1964 
1965     ret = DdeFreeDataHandle(hdata);
1966     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1967 
1968     /* cbOff is non-zero */
1969     DdeGetLastError(dde_inst);
1970     hdata = DdeCreateDataHandle(dde_inst, (LPBYTE)"data", MAX_PATH, 2, item, CF_TEXT, 0);
1971     err = DdeGetLastError(dde_inst);
1972     ok(hdata != NULL, "Expected non-NULL hdata\n");
1973     ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err);
1974 
1975     ptr = DdeAccessData(hdata, &size);
1976     ok(ptr != NULL, "Expected non-NULL ptr\n");
1977     ok(size == 262, "Expected 262, got %d\n", size);
1978     todo_wine
1979     {
1980         ok(lstrlenA((LPSTR)ptr) == 0, "Expected 0, got %d\n", lstrlenA((LPSTR)ptr));
1981     }
1982 
1983     ret = DdeUnaccessData(hdata);
1984     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1985 
1986     ret = DdeFreeDataHandle(hdata);
1987     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1988 
1989     /* NULL item */
1990     DdeGetLastError(dde_inst);
1991     hdata = DdeCreateDataHandle(dde_inst, (LPBYTE)"data", MAX_PATH, 0, 0, CF_TEXT, 0);
1992     err = DdeGetLastError(dde_inst);
1993     ok(hdata != NULL, "Expected non-NULL hdata\n");
1994     ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err);
1995 
1996     ptr = DdeAccessData(hdata, &size);
1997     ok(ptr != NULL, "Expected non-NULL ptr\n");
1998     ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr);
1999     ok(size == 260, "Expected 260, got %d\n", size);
2000 
2001     ret = DdeUnaccessData(hdata);
2002     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2003 
2004     ret = DdeFreeDataHandle(hdata);
2005     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2006 
2007     /* NULL item */
2008     DdeGetLastError(dde_inst);
2009     hdata = DdeCreateDataHandle(dde_inst, (LPBYTE)"data", MAX_PATH, 0, (HSZ)0xdeadbeef, CF_TEXT, 0);
2010     err = DdeGetLastError(dde_inst);
2011     ok(hdata != NULL, "Expected non-NULL hdata\n");
2012     ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err);
2013 
2014     ptr = DdeAccessData(hdata, &size);
2015     ok(ptr != NULL, "Expected non-NULL ptr\n");
2016     ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr);
2017     ok(size == 260, "Expected 260, got %d\n", size);
2018 
2019     ret = DdeUnaccessData(hdata);
2020     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2021 
2022     ret = DdeFreeDataHandle(hdata);
2023     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2024 
2025     /* invalid clipboard format */
2026     DdeGetLastError(dde_inst);
2027     hdata = DdeCreateDataHandle(dde_inst, (LPBYTE)"data", MAX_PATH, 0, item, 0xdeadbeef, 0);
2028     err = DdeGetLastError(dde_inst);
2029     ok(hdata != NULL, "Expected non-NULL hdata\n");
2030     ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err);
2031 
2032     ptr = DdeAccessData(hdata, &size);
2033     ok(ptr != NULL, "Expected non-NULL ptr\n");
2034     ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr);
2035     ok(size == 260, "Expected 260, got %d\n", size);
2036 
2037     ret = DdeUnaccessData(hdata);
2038     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2039 
2040     ret = DdeFreeDataHandle(hdata);
2041     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2042 
2043     ret = DdeUninitialize(dde_inst);
2044     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2045 }
2046 
2047 static void test_DdeCreateStringHandle(void)
2048 {
2049     DWORD dde_inst, ret;
2050 
2051     dde_inst = 0xdeadbeef;
2052     SetLastError(0xdeadbeef);
2053     ret = DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
2054     ok(ret == DMLERR_INVALIDPARAMETER, "DdeInitializeW should fail, but got %04x instead\n", ret);
2055     ok(DdeGetLastError(dde_inst) == DMLERR_INVALIDPARAMETER, "expected DMLERR_INVALIDPARAMETER\n");
2056 
2057     dde_inst = 0;
2058     ret = DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
2059     ok(ret == DMLERR_NO_ERROR, "DdeInitializeW failed with error %04x (%08x)\n",
2060        ret, DdeGetLastError(dde_inst));
2061 
2062     test_DdeCreateStringHandleW(dde_inst, 0);
2063     test_DdeCreateStringHandleW(dde_inst, CP_WINUNICODE);
2064     test_DdeCreateStringHandleW(dde_inst, CP_WINANSI);
2065 
2066     ok(DdeUninitialize(dde_inst), "DdeUninitialize failed\n");
2067 }
2068 
2069 static void test_FreeDDElParam(void)
2070 {
2071     HGLOBAL val, hglobal;
2072     BOOL ret;
2073 
2074     ret = FreeDDElParam(WM_DDE_INITIATE, 0);
2075     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2076 
2077     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2078     ret = FreeDDElParam(WM_DDE_INITIATE, (LPARAM)hglobal);
2079     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2080     val = GlobalFree(hglobal);
2081     ok(val == NULL, "Expected NULL, got %p\n", val);
2082 
2083     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2084     ret = FreeDDElParam(WM_DDE_ADVISE, (LPARAM)hglobal);
2085     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2086 
2087     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2088     ret = FreeDDElParam(WM_DDE_UNADVISE, (LPARAM)hglobal);
2089     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2090     val = GlobalFree(hglobal);
2091     ok(val == NULL, "Expected NULL, got %p\n", val);
2092 
2093     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2094     ret = FreeDDElParam(WM_DDE_ACK, (LPARAM)hglobal);
2095     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2096 
2097     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2098     ret = FreeDDElParam(WM_DDE_DATA, (LPARAM)hglobal);
2099     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2100 
2101     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2102     ret = FreeDDElParam(WM_DDE_REQUEST, (LPARAM)hglobal);
2103     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2104     val = GlobalFree(hglobal);
2105     ok(val == NULL, "Expected NULL, got %p\n", val);
2106 
2107     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2108     ret = FreeDDElParam(WM_DDE_POKE, (LPARAM)hglobal);
2109     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2110 
2111     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
2112     ret = FreeDDElParam(WM_DDE_EXECUTE, (LPARAM)hglobal);
2113     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2114     val = GlobalFree(hglobal);
2115     ok(val == NULL, "Expected NULL, got %p\n", val);
2116 }
2117 
2118 static void test_PackDDElParam(void)
2119 {
2120     UINT_PTR lo, hi, *ptr;
2121     LPARAM lparam;
2122     BOOL ret;
2123 
2124     lparam = PackDDElParam(WM_DDE_INITIATE, 0xcafe, 0xbeef);
2125     /* value gets sign-extended despite being an LPARAM */
2126     ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam);
2127 
2128     lo = hi = 0;
2129     ret = UnpackDDElParam(WM_DDE_INITIATE, lparam, &lo, &hi);
2130     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2131     ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2132     ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2133 
2134     ret = FreeDDElParam(WM_DDE_INITIATE, lparam);
2135     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2136 
2137     lparam = PackDDElParam(WM_DDE_TERMINATE, 0xcafe, 0xbeef);
2138     ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam);
2139 
2140     lo = hi = 0;
2141     ret = UnpackDDElParam(WM_DDE_TERMINATE, lparam, &lo, &hi);
2142     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2143     ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2144     ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2145 
2146     ret = FreeDDElParam(WM_DDE_TERMINATE, lparam);
2147     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2148 
2149     lparam = PackDDElParam(WM_DDE_ADVISE, 0xcafe, 0xbeef);
2150     /* win9x returns 0 here */
2151     if (lparam) {
2152         ptr = GlobalLock((HGLOBAL)lparam);
2153         ok(ptr != NULL, "Expected non-NULL ptr\n");
2154         ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
2155         ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
2156 
2157         ret = GlobalUnlock((HGLOBAL)lparam);
2158         ok(ret == 1, "Expected 1, got %d\n", ret);
2159 
2160         lo = hi = 0;
2161         ret = UnpackDDElParam(WM_DDE_ADVISE, lparam, &lo, &hi);
2162         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2163         ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2164         ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2165     }
2166     else
2167         win_skip("no lparam for WM_DDE_ADVISE\n");
2168 
2169     ret = FreeDDElParam(WM_DDE_ADVISE, lparam);
2170     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2171 
2172     lparam = PackDDElParam(WM_DDE_UNADVISE, 0xcafe, 0xbeef);
2173     ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam);
2174 
2175     lo = hi = 0;
2176     ret = UnpackDDElParam(WM_DDE_UNADVISE, lparam, &lo, &hi);
2177     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2178     ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2179     ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2180 
2181     ret = FreeDDElParam(WM_DDE_UNADVISE, lparam);
2182     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2183 
2184     lparam = PackDDElParam(WM_DDE_ACK, 0xcafe, 0xbeef);
2185     /* win9x returns the input (0xbeef<<16 | 0xcafe) here */
2186     if (lparam != (int)0xbeefcafe) {
2187         ptr = GlobalLock((HGLOBAL)lparam);
2188         ok(ptr != NULL, "Expected non-NULL ptr\n");
2189         ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
2190         ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
2191 
2192         ret = GlobalUnlock((HGLOBAL)lparam);
2193         ok(ret == 1, "Expected 1, got %d\n", ret);
2194 
2195         lo = hi = 0;
2196         ret = UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
2197         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2198         ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2199         ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2200 
2201         ret = FreeDDElParam(WM_DDE_ACK, lparam);
2202         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2203     }
2204     else
2205         win_skip("got lparam 0x%lx for WM_DDE_ACK\n", lparam);
2206 
2207     lparam = PackDDElParam(WM_DDE_DATA, 0xcafe, 0xbeef);
2208     /* win9x returns 0 here */
2209     if (lparam) {
2210         ptr = GlobalLock((HGLOBAL)lparam);
2211         ok(ptr != NULL, "Expected non-NULL ptr\n");
2212         ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
2213         ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
2214 
2215         ret = GlobalUnlock((HGLOBAL)lparam);
2216         ok(ret == 1, "Expected 1, got %d\n", ret);
2217 
2218         lo = hi = 0;
2219         ret = UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi);
2220         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2221         ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2222         ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2223     }
2224     else
2225         win_skip("no lparam for WM_DDE_DATA\n");
2226 
2227     ret = FreeDDElParam(WM_DDE_DATA, lparam);
2228     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2229 
2230     lparam = PackDDElParam(WM_DDE_REQUEST, 0xcafe, 0xbeef);
2231     ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam);
2232 
2233     lo = hi = 0;
2234     ret = UnpackDDElParam(WM_DDE_REQUEST, lparam, &lo, &hi);
2235     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2236     ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2237     ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2238 
2239     ret = FreeDDElParam(WM_DDE_REQUEST, lparam);
2240     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2241 
2242     lparam = PackDDElParam(WM_DDE_POKE, 0xcafe, 0xbeef);
2243     /* win9x returns 0 here */
2244     if (lparam) {
2245         ptr = GlobalLock((HGLOBAL)lparam);
2246         ok(ptr != NULL, "Expected non-NULL ptr\n");
2247         ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
2248         ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
2249 
2250         ret = GlobalUnlock((HGLOBAL)lparam);
2251         ok(ret == 1, "Expected 1, got %d\n", ret);
2252 
2253         lo = hi = 0;
2254         ret = UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi);
2255         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2256         ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
2257         ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2258     }
2259     else
2260         win_skip("no lparam for WM_DDE_POKE\n");
2261 
2262     ret = FreeDDElParam(WM_DDE_POKE, lparam);
2263     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2264 
2265     lparam = PackDDElParam(WM_DDE_EXECUTE, 0xcafe, 0xbeef);
2266     ok(lparam == 0xbeef, "Expected 0xbeef, got %08lx\n", lparam);
2267 
2268     lo = hi = 0;
2269     ret = UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi);
2270     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2271     ok(lo == 0, "Expected 0, got %08lx\n", lo);
2272     ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2273 
2274     ret = FreeDDElParam(WM_DDE_EXECUTE, lparam);
2275     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2276 }
2277 
2278 static void test_UnpackDDElParam(void)
2279 {
2280     UINT_PTR lo, hi, *ptr;
2281     HGLOBAL hglobal;
2282     BOOL ret;
2283 
2284     /* NULL lParam */
2285     lo = 0xdead;
2286     hi = 0xbeef;
2287     ret = UnpackDDElParam(WM_DDE_INITIATE, 0, &lo, &hi);
2288     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2289     ok(lo == 0, "Expected 0, got %08lx\n", lo);
2290     ok(hi == 0, "Expected 0, got %08lx\n", hi);
2291 
2292     /* NULL lo */
2293     lo = 0xdead;
2294     hi = 0xbeef;
2295     ret = UnpackDDElParam(WM_DDE_INITIATE, 0xcafebabe, NULL, &hi);
2296     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2297     ok(lo == 0xdead, "Expected 0xdead, got %08lx\n", lo);
2298     ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi);
2299 
2300     /* NULL hi */
2301     lo = 0xdead;
2302     hi = 0xbeef;
2303     ret = UnpackDDElParam(WM_DDE_INITIATE, 0xcafebabe, &lo, NULL);
2304     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2305     ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo);
2306     ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
2307 
2308     lo = 0xdead;
2309     hi = 0xbeef;
2310     ret = UnpackDDElParam(WM_DDE_INITIATE, 0xcafebabe, &lo, &hi);
2311     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2312     ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo);
2313     ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi);
2314 
2315     lo = 0xdead;
2316     hi = 0xbeef;
2317     ret = UnpackDDElParam(WM_DDE_TERMINATE, 0xcafebabe, &lo, &hi);
2318     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2319     ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo);
2320     ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi);
2321 
2322     lo = 0xdead;
2323     hi = 0xbeef;
2324     ret = UnpackDDElParam(WM_DDE_ADVISE, 0, &lo, &hi);
2325     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
2326     ok(lo == 0 ||
2327        broken(lo == 0xdead), /* win2k */
2328        "Expected 0, got %08lx\n", lo);
2329     ok(hi == 0 ||
2330        broken(hi == 0xbeef), /* win2k */
2331        "Expected 0, got %08lx\n", hi);
2332 
2333     hglobal = GlobalAlloc(GMEM_DDESHARE, 2 * sizeof(*ptr));
2334     ptr = GlobalLock(hglobal);
2335     ptr[0] = 0xcafebabe;
2336     ptr[1] = 0xdeadbeef;
2337     GlobalUnlock(hglobal);
2338 
2339     lo = 0xdead;
2340     hi = 0xbeef;
2341     ret = UnpackDDElParam(WM_DDE_ADVISE, (LPARAM)hglobal, &lo, &hi);
2342     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2343     ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo);
2344     ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi);
2345 
2346     lo = 0xdead;
2347     hi = 0xbeef;
2348     ret = UnpackDDElParam(WM_DDE_UNADVISE, 0xcafebabe, &lo, &hi);
2349     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2350     ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo);
2351     ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi);
2352 
2353     lo = 0xdead;
2354     hi = 0xbeef;
2355     ret = UnpackDDElParam(WM_DDE_ACK, (LPARAM)hglobal, &lo, &hi);
2356     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2357     ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo);
2358     ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi);
2359 
2360     lo = 0xdead;
2361     hi = 0xbeef;
2362     ret = UnpackDDElParam(WM_DDE_DATA, (LPARAM)hglobal, &lo, &hi);
2363     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2364     ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo);
2365     ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi);
2366 
2367     lo = 0xdead;
2368     hi = 0xbeef;
2369     ret = UnpackDDElParam(WM_DDE_REQUEST, 0xcafebabe, &lo, &hi);
2370     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2371     ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo);
2372     ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi);
2373 
2374     lo = 0xdead;
2375     hi = 0xbeef;
2376     ret = UnpackDDElParam(WM_DDE_POKE, (LPARAM)hglobal, &lo, &hi);
2377     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2378     ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo);
2379     ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi);
2380 
2381     lo = 0xdead;
2382     hi = 0xbeef;
2383     ret = UnpackDDElParam(WM_DDE_EXECUTE, 0xcafebabe, &lo, &hi);
2384     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2385     ok(lo == 0, "Expected 0, got %08lx\n", lo);
2386     ok(hi == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", hi);
2387 
2388     GlobalFree(hglobal);
2389 }
2390 
2391 static char test_cmd_a_to_a[] = "Test dde command";
2392 static WCHAR test_cmd_w_to_w[][32] = {
2393     {'t','e','s','t',' ','d','d','e',' ','c','o','m','m','a','n','d',0},
2394     { 0x2018, 0x2019, 0x0161, 0x0041, 0x02dc, 0 },  /* some chars that should map properly to CP1252 */
2395     { 0x2026, 0x2020, 0x2021, 0x0d0a, 0 },  /* false negative for IsTextUnicode */
2396     { 0x4efa, 0x4efc, 0x0061, 0x4efe, 0 },  /* some Chinese chars */
2397     { 0x0061, 0x0062, 0x0063, 0x9152, 0 },  /* Chinese with latin characters begin */
2398 };
2399 static const int nb_callbacks = 5 + sizeof(test_cmd_w_to_w)/sizeof(test_cmd_w_to_w[0]);
2400 
2401 static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv,
2402                                                HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
2403                                                ULONG_PTR dwData1, ULONG_PTR dwData2)
2404 {
2405     DWORD size, rsize;
2406     char str[MAX_PATH];
2407     static int msg_index = 0;
2408     static HCONV conversation = 0;
2409     static const char test_service [] = "TestDDEService";
2410     static const char test_topic [] = "TestDDETopic";
2411 
2412     msg_index++;
2413 
2414     switch (uType)
2415     {
2416     case XTYP_REGISTER:
2417     {
2418         ok(msg_index % nb_callbacks == 1, "Expected 1 modulo %u, got %d\n", nb_callbacks, msg_index);
2419         return (HDDEDATA)TRUE;
2420     }
2421 
2422     case XTYP_CONNECT:
2423     {
2424         ok(msg_index % nb_callbacks == 2, "Expected 2 modulo %u, got %d\n", nb_callbacks, msg_index);
2425         ok(uFmt == 0, "Expected 0, got %d, msg_index=%d\n", uFmt, msg_index);
2426         ok(hconv == 0, "Expected 0, got %p, msg_index=%d\n", hconv, msg_index);
2427         ok(hdata == 0, "Expected 0, got %p, msg_index=%d\n", hdata, msg_index);
2428         ok(dwData1 != 0, "Expected not 0, got %08lx, msg_index=%d\n", dwData1, msg_index);
2429         ok(dwData2 == FALSE, "Expected FALSE, got %08lx, msg_index=%d\n", dwData2, msg_index);
2430 
2431         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
2432         ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n",
2433                              test_topic, str, msg_index);
2434         ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index);
2435 
2436         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
2437         ok(!lstrcmpA(str, test_service), "Expected %s, got %s, msg_index=%d\n",
2438                              test_service, str, msg_index);
2439         ok(size == 14, "Expected 14, got %d, msg_index=%d\n", size, msg_index);
2440 
2441         return (HDDEDATA) TRUE;
2442     }
2443     case XTYP_CONNECT_CONFIRM:
2444     {
2445         ok(msg_index % nb_callbacks == 3, "Expected 3 modulo %u, got %d\n", nb_callbacks, msg_index);
2446         conversation = hconv;
2447         return (HDDEDATA) TRUE;
2448     }
2449     case XTYP_EXECUTE:
2450     {
2451         BYTE *buffer = NULL;
2452         WCHAR *cmd_w;
2453         char test_cmd_w_to_a[64];
2454         WCHAR test_cmd_a_to_w[64];
2455         DWORD size_a, size_w, size_w_to_a, size_a_to_w;
2456         BOOL unicode_server, unicode_client, str_index;
2457 
2458         ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
2459         ok(hconv == conversation, "Expected conversation handle, got %p, msg_index=%d\n",
2460                              hconv, msg_index);
2461         ok(dwData1 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData1, msg_index);
2462         ok(dwData2 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData2, msg_index);
2463         ok(hsz2 == 0, "Expected 0, got %p, msg_index=%d\n", hsz2, msg_index);
2464         size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
2465         ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n",
2466                              test_topic, str, msg_index);
2467         ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index);
2468 
2469         size = DdeGetData(hdata, NULL, 0, 0);
2470         ok((buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size)) != NULL, "should not be null\n");
2471         rsize = DdeGetData(hdata, buffer, size, 0);
2472         ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n",
2473            size, rsize, msg_index);
2474         trace("msg %u strA \"%s\" strW %s\n", msg_index, buffer, wine_dbgstr_w((WCHAR*)buffer));
2475 
2476         unicode_server = (msg_index / nb_callbacks == 1 || msg_index / nb_callbacks == 2);
2477         unicode_client = (msg_index / nb_callbacks == 1 || msg_index / nb_callbacks == 3);
2478         str_index = msg_index % nb_callbacks - 4;
2479         cmd_w = test_cmd_w_to_w[str_index - 1];
2480         size_a = strlen(test_cmd_a_to_a) + 1;
2481         size_w = (lstrlenW(cmd_w) + 1) * sizeof(WCHAR);
2482         size_a_to_w = MultiByteToWideChar( CP_ACP, 0, test_cmd_a_to_a, -1, test_cmd_a_to_w,
2483                                            sizeof(test_cmd_a_to_w)/sizeof(WCHAR) ) * sizeof(WCHAR);
2484         size_w_to_a = WideCharToMultiByte( CP_ACP, 0, cmd_w, -1,
2485                                            test_cmd_w_to_a, sizeof(test_cmd_w_to_a), NULL, NULL );
2486         switch (str_index)
2487         {
2488         case 0:  /* ASCII string */
2489             if (unicode_server)
2490             {
2491                 ok(size == size_a_to_w, "Wrong size %d/%d, msg_index=%d\n", size, size_a_to_w, msg_index);
2492                 ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w),
2493                    "Expected %s, msg_index=%d\n", wine_dbgstr_w(test_cmd_a_to_w), msg_index);
2494             }
2495             else if (unicode_client)
2496             {
2497                 /* ASCII string mapped W->A -> garbage */
2498             }
2499             else
2500             {
2501                 ok(size == size_a, "Wrong size %d/%d, msg_index=%d\n", size, size_a, msg_index);
2502                 ok(!lstrcmpA((CHAR*)buffer, test_cmd_a_to_a), "Expected %s, got %s, msg_index=%d\n",
2503                    test_cmd_a_to_a, buffer, msg_index);
2504             }
2505             break;
2506 
2507         case 1:  /* Unicode string with only 8-bit chars */
2508             if (unicode_server)
2509             {
2510                 ok(size == size_w, "Wrong size %d/%d, msg_index=%d\n", size, size_w, msg_index);
2511                 ok(!lstrcmpW((WCHAR*)buffer, cmd_w),
2512                    "Expected %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), msg_index);
2513             }
2514             else
2515             {
2516                 ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n",
2517                    size, size_w_to_a, msg_index);
2518                 ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n",
2519                    test_cmd_w_to_a, buffer, msg_index);
2520             }
2521             break;
2522 
2523         case 2:  /* normal Unicode string */
2524         case 3:  /* IsTextUnicode false negative */
2525         case 4:  /* Chinese chars */
2526             if (unicode_server)
2527             {
2528                 /* double A->W mapping */
2529                 /* NT uses the full size, XP+ only until the first null */
2530                 DWORD nt_size = MultiByteToWideChar( CP_ACP, 0, (char *)cmd_w, size_w, test_cmd_a_to_w,
2531                                                      sizeof(test_cmd_a_to_w)/sizeof(WCHAR) ) * sizeof(WCHAR);
2532                 DWORD xp_size = MultiByteToWideChar( CP_ACP, 0, (char *)cmd_w, -1, NULL, 0 ) * sizeof(WCHAR);
2533                 ok(size == xp_size || broken(size == nt_size) ||
2534                    broken(str_index == 4 && IsDBCSLeadByte(cmd_w[0])) /* East Asian */,
2535                    "Wrong size %d/%d, msg_index=%d\n", size, size_a_to_w, msg_index);
2536                 ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w),
2537                    "Expected %s, msg_index=%d\n", wine_dbgstr_w(test_cmd_a_to_w), msg_index);
2538             }
2539             else if (unicode_client)
2540             {
2541                 ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n", size, size_w_to_a, msg_index);
2542                 ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n",
2543                    test_cmd_w_to_a, buffer, msg_index);
2544             }
2545             else
2546             {
2547                 ok(size == size_w, "Wrong size %d/%d, msg_index=%d\n", size, size_w, msg_index);
2548                 ok(!lstrcmpW((WCHAR*)buffer, cmd_w),
2549                    "Expected %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), msg_index);
2550             }
2551             break;
2552         case 5: /* Chinese with latin characters begin */
2553             if (unicode_server && unicode_client)
2554             {
2555                 todo_wine ok(size == size_w, "Wrong size %d expected %d, msg_index=%d\n", size, size_w, msg_index);
2556                 MultiByteToWideChar(CP_ACP, 0, test_cmd_w_to_a, size_w, test_cmd_a_to_w,
2557                                     sizeof(test_cmd_a_to_w)/sizeof(WCHAR));
2558                 todo_wine ok(!lstrcmpW((WCHAR*)buffer, cmd_w),
2559                              "Expected %s got %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), wine_dbgstr_w((WCHAR *)buffer), msg_index);
2560             }
2561             else if (unicode_server)
2562             {
2563                 todo_wine ok(size == size_w, "Wrong size %d expected %d, msg_index=%d\n", size, size_w, msg_index);
2564                 MultiByteToWideChar(CP_ACP, 0, test_cmd_w_to_a, size_w, test_cmd_a_to_w,
2565                                     sizeof(test_cmd_a_to_w)/sizeof(WCHAR));
2566                 if (!is_cjk())
2567                     todo_wine ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w), "Expected %s, got %s, msg_index=%d\n",
2568                                  wine_dbgstr_w(test_cmd_a_to_w), wine_dbgstr_w((WCHAR*)buffer), msg_index);
2569                 else
2570                     todo_wine ok(!lstrcmpW((WCHAR*)buffer, cmd_w),
2571                                  "Expected %s got %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), wine_dbgstr_w((WCHAR *)buffer), msg_index);
2572             }
2573             else if (unicode_client)
2574             {
2575                 ok(size == size_w_to_a, "Wrong size %d expected %d, msg_index=%d\n", size, size_w_to_a, msg_index);
2576                 ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n",
2577                    test_cmd_w_to_a, buffer, msg_index);
2578             }
2579             else
2580             {
2581                 todo_wine ok(size == size_w_to_a || size == (size_w_to_a - 1), "Wrong size %d expected %d or %d, msg_index=%d\n",
2582                              size, size_w_to_a, size_w_to_a - 1, msg_index);
2583                 todo_wine ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n",
2584                              test_cmd_w_to_a, buffer, msg_index);
2585             }
2586             break;
2587 
2588         default:
2589             ok( 0, "Invalid message %u\n", msg_index );
2590             break;
2591         }
2592         HeapFree(GetProcessHeap(), 0, buffer);
2593         return (HDDEDATA) DDE_FACK;
2594     }
2595     case XTYP_DISCONNECT:
2596         return (HDDEDATA) TRUE;
2597 
2598     default:
2599         ok(FALSE, "Unhandled msg: %08x, msg_index=%d\n", uType, msg_index);
2600     }
2601 
2602     return NULL;
2603 }
2604 
2605 static HDDEDATA CALLBACK client_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv,
2606                                                HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
2607                                                ULONG_PTR dwData1, ULONG_PTR dwData2)
2608 {
2609     switch (uType)
2610     {
2611     case XTYP_DISCONNECT:
2612         return (HDDEDATA) TRUE;
2613 
2614     default:
2615         ok(FALSE, "Unhandled msg: %08x\n", uType);
2616     }
2617 
2618     return NULL;
2619 }
2620 
2621 static void test_end_to_end_client(BOOL type_a)
2622 {
2623     DWORD i, ret, err;
2624     DWORD client_pid = 0;
2625     HSZ server, topic;
2626     HCONV hconv;
2627     HDDEDATA hdata;
2628     static const char test_service[] = "TestDDEService";
2629     static const WCHAR test_service_w[] = {'T','e','s','t','D','D','E','S','e','r','v','i','c','e',0};
2630     static const char test_topic[] = "TestDDETopic";
2631     static const WCHAR test_topic_w[] = {'T','e','s','t','D','D','E','T','o','p','i','c',0};
2632 
2633     trace("Start end to end client %s\n", type_a ? "ASCII" : "UNICODE");
2634 
2635     if (type_a)
2636         ret = DdeInitializeA(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0);
2637     else
2638         ret = DdeInitializeW(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0);
2639     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret);
2640 
2641     if (type_a)
2642     {
2643         server = DdeCreateStringHandleA(client_pid, test_service, CP_WINANSI);
2644         topic = DdeCreateStringHandleA(client_pid, test_topic, CP_WINANSI);
2645     }
2646     else {
2647         server = DdeCreateStringHandleW(client_pid, test_service_w, CP_WINUNICODE);
2648         topic = DdeCreateStringHandleW(client_pid, test_topic_w, CP_WINUNICODE);
2649     }
2650 
2651     DdeGetLastError(client_pid);
2652     hconv = DdeConnect(client_pid, server, topic, NULL);
2653     ok(hconv != NULL, "Expected non-NULL conversation\n");
2654     ret = DdeGetLastError(client_pid);
2655     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret);
2656     DdeFreeStringHandle(client_pid, server);
2657 
2658     /* Test both A and W data being passed to DdeClientTransaction */
2659     hdata = DdeClientTransaction((LPBYTE)test_cmd_a_to_a, sizeof(test_cmd_a_to_a),
2660             hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret);
2661     ok(hdata != NULL, "DdeClientTransaction failed\n");
2662     ok(ret == DDE_FACK, "wrong status code %x\n", ret);
2663     err = DdeGetLastError(client_pid);
2664     ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
2665 
2666     for (i = 0; i < sizeof(test_cmd_w_to_w)/sizeof(test_cmd_w_to_w[0]); i++)
2667     {
2668         hdata = DdeClientTransaction((LPBYTE)test_cmd_w_to_w[i],
2669                                      (lstrlenW(test_cmd_w_to_w[i]) + 1) * sizeof(WCHAR),
2670                                      hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret);
2671         ok(hdata != NULL, "DdeClientTransaction failed\n");
2672         ok(ret == DDE_FACK, "wrong status code %x\n", ret);
2673         err = DdeGetLastError(client_pid);
2674         ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
2675     }
2676 
2677     DdeFreeStringHandle(client_pid, topic);
2678     ret = DdeDisconnect(hconv);
2679     ok(ret == TRUE, "Expected TRUE, got %x\n", ret);
2680 
2681     ret = DdeUninitialize(client_pid);
2682     ok(ret == TRUE, "Expected TRUE, got %x\n", ret);
2683 
2684 }
2685 
2686 static void test_end_to_end_server(HANDLE hproc, HANDLE hthread, BOOL type_a)
2687 {
2688     MSG msg;
2689     HSZ server;
2690     BOOL ret;
2691     DWORD res;
2692     HDDEDATA hdata;
2693     static const char test_service[] = "TestDDEService";
2694 
2695     trace("start end to end server %s\n", type_a ? "ASCII" : "UNICODE");
2696     server_pid = 0;
2697 
2698     if (type_a)
2699         res = DdeInitializeA(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0);
2700     else
2701         res = DdeInitializeW(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0);
2702     ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res);
2703 
2704     server = DdeCreateStringHandleA(server_pid, test_service, CP_WINANSI);
2705     ok(server != NULL, "Expected non-NULL string handle\n");
2706 
2707     hdata = DdeNameService(server_pid, server, 0, DNS_REGISTER);
2708     ok(hdata == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", hdata);
2709     ResumeThread( hthread );
2710 
2711 
2712     while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0)
2713     {
2714         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2715     }
2716 
2717     ret = DdeUninitialize(server_pid);
2718     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
2719     GetExitCodeProcess( hproc, &res );
2720     ok( !res, "client failed with %u error(s)\n", res );
2721 }
2722 
2723 START_TEST(dde)
2724 {
2725     int argc;
2726     char **argv;
2727     char buffer[MAX_PATH];
2728     STARTUPINFOA startup;
2729     PROCESS_INFORMATION proc;
2730     DWORD dde_inst = 0xdeadbeef;
2731 
2732     argc = winetest_get_mainargs(&argv);
2733     if (argc == 3)
2734     {
2735         if (!lstrcmpA(argv[2], "ddeml"))
2736             test_ddeml_client();
2737         else if (!lstrcmpA(argv[2], "msg"))
2738             test_msg_client();
2739         else if (!lstrcmpA(argv[2], "enda"))
2740             test_end_to_end_client(TRUE);
2741         else if (!lstrcmpA(argv[2], "endw"))
2742             test_end_to_end_client(FALSE);
2743 
2744         return;
2745     }
2746 
2747     test_initialisation();
2748 
2749     SetLastError(0xdeadbeef);
2750     DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
2751     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2752     {
2753         win_skip("Skipping tests on win9x because of brokenness\n");
2754         return;
2755     }
2756 
2757     ZeroMemory(&startup, sizeof(STARTUPINFOA));
2758     sprintf(buffer, "%s dde ddeml", argv[0]);
2759     startup.cb = sizeof(startup);
2760     startup.dwFlags = STARTF_USESHOWWINDOW;
2761     startup.wShowWindow = SW_SHOWNORMAL;
2762 
2763     CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
2764                    CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
2765 
2766     test_msg_server(proc.hProcess, proc.hThread);
2767 
2768     sprintf(buffer, "%s dde msg", argv[0]);
2769     CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
2770                    0, NULL, NULL, &startup, &proc);
2771 
2772     test_ddeml_server(proc.hProcess);
2773 
2774     /* Test the combinations of A and W interfaces with A and W data
2775        end to end to ensure that data conversions are accurate */
2776     sprintf(buffer, "%s dde enda", argv[0]);
2777     CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
2778                    CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
2779 
2780     test_end_to_end_server(proc.hProcess, proc.hThread, TRUE);
2781 
2782     /* Don't bother testing W interfaces on Win9x/WinMe */
2783     SetLastError(0xdeadbeef);
2784     lstrcmpW(NULL, NULL);
2785     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2786     {
2787         win_skip("Skipping W-interface tests\n");
2788     }
2789     else
2790     {
2791         sprintf(buffer, "%s dde endw", argv[0]);
2792         CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
2793                        CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
2794 
2795         test_end_to_end_server(proc.hProcess, proc.hThread, FALSE);
2796 
2797         sprintf(buffer, "%s dde enda", argv[0]);
2798         CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
2799                        CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
2800 
2801         test_end_to_end_server(proc.hProcess, proc.hThread, FALSE);
2802 
2803         sprintf(buffer, "%s dde endw", argv[0]);
2804         CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
2805                        CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
2806 
2807         test_end_to_end_server(proc.hProcess, proc.hThread, TRUE);
2808 
2809         test_dde_aw_transaction( FALSE, TRUE );
2810         test_dde_aw_transaction( TRUE, FALSE );
2811         test_dde_aw_transaction( TRUE, TRUE );
2812         test_dde_aw_transaction( FALSE, FALSE );
2813 
2814         test_dde_aw_transaction( FALSE, TRUE );
2815         test_dde_aw_transaction( TRUE, FALSE );
2816         test_dde_aw_transaction( TRUE, TRUE );
2817     }
2818     test_dde_aw_transaction( FALSE, FALSE );
2819 
2820     test_DdeCreateDataHandle();
2821     test_DdeCreateStringHandle();
2822     test_FreeDDElParam();
2823     test_PackDDElParam();
2824     test_UnpackDDElParam();
2825 }
2826