Release 1.5.29.
[wine] / dlls / oledlg / pastespl.c
1 /*
2  * OleUIPasteSpecial implementation
3  *
4  * Copyright 2006 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "oledlg.h"
34
35 #include "oledlg_private.h"
36 #include "resource.h"
37
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42
43 typedef struct
44 {
45     OLEUIPASTESPECIALW *ps;
46     DWORD flags;
47     WCHAR *source_name;
48     WCHAR *link_source_name;
49     WCHAR *type_name;
50     WCHAR *link_type_name;
51     LPOLESTR app_name;
52 } ps_struct_t;
53
54 static const struct ps_flag
55 {
56     DWORD flag;
57     const char *name;
58 } ps_flags[] = {
59 #define PS_FLAG_ENTRY(p) {p, #p}
60     PS_FLAG_ENTRY(PSF_SHOWHELP),
61     PS_FLAG_ENTRY(PSF_SELECTPASTE),
62     PS_FLAG_ENTRY(PSF_SELECTPASTELINK),
63     PS_FLAG_ENTRY(PSF_CHECKDISPLAYASICON),
64     PS_FLAG_ENTRY(PSF_DISABLEDISPLAYASICON),
65     PS_FLAG_ENTRY(PSF_HIDECHANGEICON),
66     PS_FLAG_ENTRY(PSF_STAYONCLIPBOARDCHANGE),
67     PS_FLAG_ENTRY(PSF_NOREFRESHDATAOBJECT),
68     {-1, NULL}
69 #undef PS_FLAG_ENTRY
70 };
71
72 static void dump_ps_flags(DWORD flags)
73 {
74     char flagstr[1000] = "";
75
76     const struct ps_flag *flag = ps_flags;
77     for( ; flag->name; flag++) {
78         if(flags & flag->flag) {
79             strcat(flagstr, flag->name);
80             strcat(flagstr, "|");
81         }
82     }
83     TRACE("flags %08x %s\n", flags, flagstr);
84 }
85
86 static void dump_pastespecial(const OLEUIPASTESPECIALW *ps)
87 {
88     INT i;
89     UINT j;
90
91     dump_ps_flags(ps->dwFlags);
92     TRACE("hwnd %p caption %s hook %p custdata %lx\n",
93           ps->hWndOwner, debugstr_w(ps->lpszCaption), ps->lpfnHook, ps->lCustData);
94     if(IS_INTRESOURCE(ps->lpszTemplate))
95         TRACE("hinst %p template %04x hresource %p\n", ps->hInstance, (WORD)(ULONG_PTR)ps->lpszTemplate, ps->hResource);
96     else
97         TRACE("hinst %p template %s hresource %p\n", ps->hInstance, debugstr_w(ps->lpszTemplate), ps->hResource);
98     TRACE("dataobj %p arrpasteent %p cpasteent %d arrlinktype %p clinktype %d\n",
99           ps->lpSrcDataObj, ps->arrPasteEntries, ps->cPasteEntries,
100           ps->arrLinkTypes, ps->cLinkTypes);
101     TRACE("cclsidex %d lpclsidex %p nselect %d flink %d hmetapict %p size(%d,%d)\n",
102           ps->cClsidExclude, ps->lpClsidExclude, ps->nSelectedIndex, ps->fLink,
103           ps->hMetaPict, ps->sizel.cx, ps->sizel.cy);
104     for(i = 0; i < ps->cPasteEntries; i++)
105     {
106         TRACE("arrPasteEntries[%d]: cFormat %08x pTargetDevice %p dwAspect %d lindex %d tymed %d\n",
107               i, ps->arrPasteEntries[i].fmtetc.cfFormat, ps->arrPasteEntries[i].fmtetc.ptd,
108               ps->arrPasteEntries[i].fmtetc.dwAspect, ps->arrPasteEntries[i].fmtetc.lindex,
109               ps->arrPasteEntries[i].fmtetc.tymed);
110         TRACE("\tformat name %s result text %s flags %04x\n", debugstr_w(ps->arrPasteEntries[i].lpstrFormatName),
111               debugstr_w(ps->arrPasteEntries[i].lpstrResultText), ps->arrPasteEntries[i].dwFlags);
112     }
113     for(i = 0; i < ps->cLinkTypes; i++)
114         TRACE("arrLinkTypes[%d] %08x\n", i, ps->arrLinkTypes[i]);
115     for(j = 0; j < ps->cClsidExclude; j++)
116         TRACE("lpClsidExclude[%u] %s\n", j, debugstr_guid(&ps->lpClsidExclude[j]));
117
118 }
119
120 static inline WCHAR *strdupAtoW(const char *str)
121 {
122     DWORD len;
123     WCHAR *ret;
124     if(!str) return NULL;
125     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
126     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
127     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
128     return ret;
129 }
130
131 static inline WCHAR *strdupW(const WCHAR *str)
132 {
133     DWORD len;
134     WCHAR *ret;
135     if(!str) return NULL;
136     len = lstrlenW(str) + 1;
137     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
138     memcpy(ret, str, len * sizeof(WCHAR));
139     return ret;
140 }
141
142 static void get_descriptors(HWND hdlg, ps_struct_t *ps_struct)
143 {
144     FORMATETC fmtetc;
145     STGMEDIUM stg;
146
147     fmtetc.tymed = TYMED_HGLOBAL;
148     fmtetc.dwAspect = DVASPECT_CONTENT;
149     fmtetc.ptd = NULL;
150     fmtetc.lindex = -1;
151
152     fmtetc.cfFormat = cf_object_descriptor;
153     if(IDataObject_GetData(ps_struct->ps->lpSrcDataObj, &fmtetc, &stg) == S_OK)
154     {
155         OBJECTDESCRIPTOR *obj_desc = GlobalLock(stg.u.hGlobal);
156         if(obj_desc->dwSrcOfCopy)
157             ps_struct->source_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwSrcOfCopy));
158         if(obj_desc->dwFullUserTypeName)
159             ps_struct->type_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwFullUserTypeName));
160         OleRegGetUserType(&obj_desc->clsid, USERCLASSTYPE_APPNAME, &ps_struct->app_name);
161         /* Get the icon here.  If dwDrawAspect & DVASCPECT_ICON call GetData(CF_METAFILEPICT), otherwise
162            native calls OleGetIconFromClass(obj_desc->clsid) */
163         GlobalUnlock(stg.u.hGlobal);
164         GlobalFree(stg.u.hGlobal);
165     }
166     else
167     {
168         /* Try to get some data using some of the other clipboard formats */
169     }
170
171     fmtetc.cfFormat = cf_link_src_descriptor;
172     if(IDataObject_GetData(ps_struct->ps->lpSrcDataObj, &fmtetc, &stg) == S_OK)
173     {
174         OBJECTDESCRIPTOR *obj_desc = GlobalLock(stg.u.hGlobal);
175         if(obj_desc->dwSrcOfCopy)
176             ps_struct->link_source_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwSrcOfCopy));
177         if(obj_desc->dwFullUserTypeName)
178             ps_struct->link_type_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwFullUserTypeName));
179         GlobalUnlock(stg.u.hGlobal);
180         GlobalFree(stg.u.hGlobal);
181     }
182
183     if(ps_struct->source_name == NULL && ps_struct->link_source_name == NULL)
184     {
185         WCHAR buf[200];
186         LoadStringW(OLEDLG_hInstance, IDS_PS_UNKNOWN_SRC, buf, sizeof(buf)/sizeof(WCHAR));
187         ps_struct->source_name = strdupW(buf);
188     }
189
190     if(ps_struct->type_name == NULL && ps_struct->link_type_name == NULL)
191     {
192         WCHAR buf[200];
193         LoadStringW(OLEDLG_hInstance, IDS_PS_UNKNOWN_TYPE, buf, sizeof(buf)/sizeof(WCHAR));
194         ps_struct->type_name = strdupW(buf);
195     }
196 }
197
198 static BOOL add_entry_to_lb(HWND hdlg, UINT id, OLEUIPASTEENTRYW *pe)
199 {
200     HWND hwnd = GetDlgItem(hdlg, id);
201     BOOL ret = FALSE;
202
203     /* FIXME %s handling */
204
205     /* Note that this suffers from the same bug as native, in that if a new string
206        is a substring of an already added string, then the FINDSTRING will succeed
207        this is probably not what we want */
208     if(SendMessageW(hwnd, LB_FINDSTRING, 0, (LPARAM)pe->lpstrFormatName) == -1)
209     {
210         LRESULT pos = SendMessageW(hwnd, LB_ADDSTRING, 0, (LPARAM)pe->lpstrFormatName);
211         SendMessageW(hwnd, LB_SETITEMDATA, pos, (LPARAM)pe);
212         ret = TRUE;
213     }
214     return ret;
215 }
216
217 static DWORD init_pastelist(HWND hdlg, OLEUIPASTESPECIALW *ps)
218 {
219     IEnumFORMATETC *penum;
220     HRESULT hr;
221     FORMATETC fmts[20];
222     DWORD fetched, items_added = 0;
223
224     hr = IDataObject_EnumFormatEtc(ps->lpSrcDataObj, DATADIR_GET, &penum);
225     if(FAILED(hr))
226     {
227         WARN("Unable to create IEnumFORMATETC\n");
228         return 0;
229     }
230
231     /* The native version grabs only the first 20 fmts and we do the same */
232     hr = IEnumFORMATETC_Next(penum, sizeof(fmts)/sizeof(fmts[0]), fmts, &fetched);
233     TRACE("got %d formats hr %08x\n", fetched, hr);
234
235     if(SUCCEEDED(hr))
236     {
237         DWORD src_fmt, req_fmt;
238         for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
239         {
240             /* This is used by update_structure() to set nSelectedIndex on exit */
241             ps->arrPasteEntries[req_fmt].dwScratchSpace = req_fmt;
242             TRACE("req_fmt %x\n", ps->arrPasteEntries[req_fmt].fmtetc.cfFormat);
243             for(src_fmt = 0; src_fmt < fetched; src_fmt++)
244             {
245                 TRACE("\tenum'ed fmt %x\n", fmts[src_fmt].cfFormat);
246                 if(ps->arrPasteEntries[req_fmt].fmtetc.cfFormat == fmts[src_fmt].cfFormat)
247                 {
248                     add_entry_to_lb(hdlg, IDC_PS_PASTELIST, ps->arrPasteEntries + req_fmt);
249                     items_added++;
250                     break;
251                 }
252             }
253         }
254     }
255
256     IEnumFORMATETC_Release(penum);
257     EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTE), items_added != 0);
258     return items_added;
259 }
260
261 static DWORD init_linklist(HWND hdlg, OLEUIPASTESPECIALW *ps)
262 {
263     HRESULT hr;
264     DWORD supported_mask = 0;
265     DWORD items_added = 0;
266     int link, req_fmt;
267     FORMATETC fmt = {0, NULL, DVASPECT_CONTENT, -1, -1};
268
269     for(link = 0; link < ps->cLinkTypes && link < PS_MAXLINKTYPES; link++)
270     {
271         fmt.cfFormat = ps->arrLinkTypes[link];
272         hr = IDataObject_QueryGetData(ps->lpSrcDataObj, &fmt);
273         if(hr == S_OK)
274             supported_mask |= 1 << link;
275     }
276     TRACE("supported_mask %02x\n", supported_mask);
277     for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
278     {
279         DWORD linktypes;
280         if(ps->arrPasteEntries[req_fmt].dwFlags & OLEUIPASTE_LINKANYTYPE)
281             linktypes = 0xff;
282         else
283             linktypes = ps->arrPasteEntries[req_fmt].dwFlags & 0xff;
284
285         if(linktypes & supported_mask)
286         {
287             add_entry_to_lb(hdlg, IDC_PS_PASTELINKLIST, ps->arrPasteEntries + req_fmt);
288             items_added++;
289         }
290     }
291
292     EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTELINK), items_added != 0);
293     return items_added;
294 }
295
296 /* copies src_list_id into the display list */
297 static void update_display_list(HWND hdlg, UINT src_list_id)
298 {
299     LONG count, i, old_pos;
300     WCHAR txt[256];
301     LONG item_data;
302     HWND display_list = GetDlgItem(hdlg, IDC_PS_DISPLAYLIST);
303     HWND list = GetDlgItem(hdlg, src_list_id);
304
305     old_pos = SendMessageW(display_list, LB_GETCURSEL, 0, 0);
306     if(old_pos == -1) old_pos = 0;
307
308     SendMessageW(display_list, WM_SETREDRAW, 0, 0);
309     SendMessageW(display_list, LB_RESETCONTENT, 0, 0);
310     count = SendMessageW(list, LB_GETCOUNT, 0, 0);
311     for(i = 0; i < count; i++)
312     {
313         SendMessageW(list, LB_GETTEXT, i, (LPARAM)txt);
314         item_data = SendMessageW(list, LB_GETITEMDATA, i, 0);
315         SendMessageW(display_list, LB_INSERTSTRING, i, (LPARAM)txt);
316         SendMessageW(display_list, LB_SETITEMDATA, i, item_data);
317     }
318     SendMessageW(display_list, LB_SETCURSEL, 0, 0);
319     SendMessageW(display_list, WM_SETREDRAW, 1, 0);
320     if(GetForegroundWindow() == hdlg)
321         SetFocus(display_list);
322 }
323
324 static void init_lists(HWND hdlg, ps_struct_t *ps_struct)
325 {
326     DWORD pastes_added = init_pastelist(hdlg, ps_struct->ps);
327     DWORD links_added = init_linklist(hdlg, ps_struct->ps);
328     UINT check_id, list_id;
329
330     if((ps_struct->flags & (PSF_SELECTPASTE | PSF_SELECTPASTELINK)) == 0)
331         ps_struct->flags |= PSF_SELECTPASTE;
332
333     if(!pastes_added && !links_added)
334         ps_struct->flags &= ~(PSF_SELECTPASTE | PSF_SELECTPASTELINK);
335     else if(!pastes_added && (ps_struct->flags & PSF_SELECTPASTE))
336     {
337         ps_struct->flags &= ~PSF_SELECTPASTE;
338         ps_struct->flags |= PSF_SELECTPASTELINK;
339     }
340     else if(!links_added && (ps_struct->flags & PSF_SELECTPASTELINK))
341     {
342         ps_struct->flags &= ~PSF_SELECTPASTELINK;
343         ps_struct->flags |= PSF_SELECTPASTE;
344     }
345
346     check_id = 0;
347     list_id = 0;
348     if(ps_struct->flags & PSF_SELECTPASTE)
349     {
350         check_id = IDC_PS_PASTE;
351         list_id = IDC_PS_PASTELIST;
352     }
353     else if(ps_struct->flags & PSF_SELECTPASTELINK)
354     {
355         check_id = IDC_PS_PASTELINK;
356         list_id = IDC_PS_PASTELINKLIST;
357     }
358
359     CheckRadioButton(hdlg, IDC_PS_PASTE, IDC_PS_PASTELINK, check_id);
360
361     if(list_id)
362         update_display_list(hdlg, list_id);
363     else
364         EnableWindow(GetDlgItem(hdlg, IDOK), 0);
365 }
366
367 static void update_src_text(HWND hdlg, const ps_struct_t *ps_struct)
368 {
369     WCHAR *str;
370
371     if(ps_struct->flags & PSF_SELECTPASTE)
372     {
373         if(ps_struct->source_name)
374             str = ps_struct->source_name;
375         else
376             str = ps_struct->link_source_name;
377
378     }
379     else
380     {
381         if(ps_struct->link_source_name)
382             str = ps_struct->link_source_name;
383         else
384             str = ps_struct->source_name;
385
386     }
387     SetDlgItemTextW(hdlg, IDC_PS_SOURCETEXT, str);
388 }
389
390 static void update_as_icon(HWND hdlg, ps_struct_t *ps_struct)
391 {
392     HWND icon_display = GetDlgItem(hdlg, IDC_PS_ICONDISPLAY);
393     HWND display_as_icon = GetDlgItem(hdlg, IDC_PS_DISPLAYASICON);
394     HWND change_icon = GetDlgItem(hdlg, IDC_PS_CHANGEICON);
395
396     /* FIXME. No as icon handling */
397     ps_struct->flags &= ~PSF_CHECKDISPLAYASICON;
398
399     CheckDlgButton(hdlg, IDC_PS_DISPLAYASICON, ps_struct->flags & PSF_CHECKDISPLAYASICON);
400     EnableWindow(display_as_icon, 0);
401     ShowWindow(icon_display, SW_HIDE);
402     EnableWindow(icon_display, 0);
403     ShowWindow(change_icon, SW_HIDE);
404     EnableWindow(change_icon, 0);
405 }
406
407 static void update_result_text(HWND hdlg, const ps_struct_t *ps_struct)
408 {
409     WCHAR resource_txt[200];
410     UINT res_id;
411     OLEUIPASTEENTRYW *pent;
412     LONG cur_sel;
413     static const WCHAR percent_s[] = {'%','s',0};
414     WCHAR *result_txt, *ptr;
415
416     cur_sel = SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETCURSEL, 0, 0);
417     if(cur_sel == -1) return;
418     pent = (OLEUIPASTEENTRYW*)SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETITEMDATA, cur_sel, 0);
419
420     if(ps_struct->flags & PSF_SELECTPASTE)
421     {
422         if(ps_struct->flags & PSF_CHECKDISPLAYASICON)
423             res_id = IDS_PS_PASTE_OBJECT_AS_ICON;
424         else
425             res_id = IDS_PS_PASTE_DATA;
426     }
427     else
428     {
429         if(ps_struct->flags & PSF_CHECKDISPLAYASICON)
430             res_id = IDS_PS_PASTE_LINK_OBJECT_AS_ICON;
431         else
432             res_id = IDS_PS_PASTE_LINK_DATA;
433     }
434
435     LoadStringW(OLEDLG_hInstance, res_id, resource_txt, sizeof(resource_txt)/sizeof(WCHAR));
436     if((ptr = strstrW(resource_txt, percent_s)))
437     {
438         /* FIXME handle %s in ResultText. Sub appname if IDS_PS_PASTE_OBJECT{_AS_ICON}.  Else sub appropriate type name */
439         size_t result_txt_len = strlenW(pent->lpstrResultText);
440         ptrdiff_t offs = (char*)ptr - (char*)resource_txt;
441         result_txt = HeapAlloc(GetProcessHeap(), 0, (strlenW(resource_txt) + result_txt_len - 1) * sizeof(WCHAR));
442         memcpy(result_txt, resource_txt, offs);
443         memcpy((char*)result_txt + offs, pent->lpstrResultText, result_txt_len * sizeof(WCHAR));
444         memcpy((char*)result_txt + offs + result_txt_len * sizeof(WCHAR), ptr + 2, (strlenW(ptr + 2) + 1) * sizeof(WCHAR));
445     }
446     else
447         result_txt = resource_txt;
448
449     SetDlgItemTextW(hdlg, IDC_PS_RESULTTEXT, result_txt);
450
451     if(result_txt != resource_txt)
452         HeapFree(GetProcessHeap(), 0, result_txt);
453
454 }
455
456 static void selection_change(HWND hdlg, ps_struct_t *ps_struct)
457 {
458     update_as_icon(hdlg, ps_struct);
459     update_result_text(hdlg, ps_struct);
460 }
461
462 static void mode_change(HWND hdlg, ps_struct_t *ps_struct, UINT id)
463 {
464     if(id == IDC_PS_PASTE)
465     {
466         ps_struct->flags &= ~PSF_SELECTPASTELINK;
467         ps_struct->flags |= PSF_SELECTPASTE;
468     }
469     else
470     {
471         ps_struct->flags &= ~PSF_SELECTPASTE;
472         ps_struct->flags |= PSF_SELECTPASTELINK;
473     }
474
475     update_src_text(hdlg, ps_struct);
476     update_display_list(hdlg, id == IDC_PS_PASTE ? IDC_PS_PASTELIST : IDC_PS_PASTELINKLIST);
477     selection_change(hdlg, ps_struct);
478 }
479
480 static void post_help_msg(HWND hdlg, ps_struct_t *ps_struct)
481 {
482     PostMessageW(ps_struct->ps->hWndOwner, oleui_msg_help, (WPARAM)hdlg, IDD_PASTESPECIAL);
483 }
484
485 static void send_end_dialog_msg(HWND hdlg, ps_struct_t *ps_struct, UINT id)
486 {
487     SendMessageW(hdlg, oleui_msg_enddialog, id, 0);
488 }
489
490 static void update_structure(HWND hdlg, ps_struct_t *ps_struct)
491 {
492     LONG cur_sel = SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETCURSEL, 0, 0);
493     if(cur_sel != -1)
494     {
495         OLEUIPASTEENTRYW *pent;
496         pent = (OLEUIPASTEENTRYW *)SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETITEMDATA, cur_sel, 0);
497         ps_struct->ps->nSelectedIndex = pent->dwScratchSpace;
498     }
499     ps_struct->ps->dwFlags = ps_struct->flags;
500     ps_struct->ps->fLink = (ps_struct->flags & PSF_SELECTPASTELINK) != 0;
501 }
502
503 static void free_structure(ps_struct_t *ps_struct)
504 {
505     HeapFree(GetProcessHeap(), 0, ps_struct->type_name);
506     HeapFree(GetProcessHeap(), 0, ps_struct->source_name);
507     HeapFree(GetProcessHeap(), 0, ps_struct->link_type_name);
508     HeapFree(GetProcessHeap(), 0, ps_struct->link_source_name);
509     CoTaskMemFree(ps_struct->app_name);
510     HeapFree(GetProcessHeap(), 0, ps_struct);
511 }
512
513 static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
514 {
515     /* native uses prop name "Structure", but we're not compatible
516        with that so we'll prepend "Wine_". */
517     static const WCHAR prop_name[] = {'W','i','n','e','_','S','t','r','u','c','t','u','r','e',0};
518     ps_struct_t *ps_struct;
519
520     TRACE("(%p, %04x, %08lx, %08lx)\n", hdlg, msg, wp, lp);
521
522     ps_struct = GetPropW(hdlg, prop_name);
523
524     if(msg != WM_INITDIALOG)
525     {
526         if(!ps_struct)
527             return 0;
528
529         if(ps_struct->ps->lpfnHook)
530         {
531             INT_PTR ret = ps_struct->ps->lpfnHook(hdlg, msg, wp, lp);
532             if(ret) return ret;
533         }
534     }
535
536     switch(msg)
537     {
538     case WM_INITDIALOG:
539     {
540         ps_struct = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps_struct));
541         ps_struct->ps = (OLEUIPASTESPECIALW*)lp;
542         ps_struct->type_name = NULL;
543         ps_struct->source_name = NULL;
544         ps_struct->link_type_name = NULL;
545         ps_struct->link_source_name = NULL;
546         ps_struct->app_name = NULL;
547         ps_struct->flags = ps_struct->ps->dwFlags;
548
549         SetPropW(hdlg, prop_name, ps_struct);
550
551         if(!(ps_struct->ps->dwFlags & PSF_SHOWHELP))
552         {
553             ShowWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), SW_HIDE);
554             EnableWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), 0);
555         }
556
557         if(ps_struct->ps->lpszCaption)
558             SetWindowTextW(hdlg, ps_struct->ps->lpszCaption);
559
560         get_descriptors(hdlg, ps_struct);
561
562         init_lists(hdlg, ps_struct);
563
564         update_src_text(hdlg, ps_struct);
565
566         selection_change(hdlg, ps_struct);
567
568         SetFocus(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST));
569
570         if(ps_struct->ps->lpfnHook)
571             ps_struct->ps->lpfnHook(hdlg, msg, 0, 0);
572         return FALSE; /* use new focus */
573     }
574     case WM_COMMAND:
575         switch(LOWORD(wp))
576         {
577         case IDC_PS_DISPLAYLIST:
578             switch(HIWORD(wp))
579             {
580             case LBN_SELCHANGE:
581                 selection_change(hdlg, ps_struct);
582                 return FALSE;
583             default:
584                 return FALSE;
585             }
586         case IDC_PS_PASTE:
587         case IDC_PS_PASTELINK:
588             switch(HIWORD(wp))
589             {
590             case BN_CLICKED:
591                 mode_change(hdlg, ps_struct, LOWORD(wp));
592                 return FALSE;
593
594             default:
595                 return FALSE;
596             }
597         case IDC_OLEUIHELP:
598             switch(HIWORD(wp))
599             {
600             case BN_CLICKED:
601                 post_help_msg(hdlg, ps_struct);
602                 return FALSE;
603             default:
604                 return FALSE;
605             }
606         case IDOK:
607         case IDCANCEL:
608             switch(HIWORD(wp))
609             {
610             case BN_CLICKED:
611                 send_end_dialog_msg(hdlg, ps_struct, LOWORD(wp));
612                 return FALSE;
613             default:
614                 return FALSE;
615             }
616         }
617         return FALSE;
618     default:
619         if(msg == oleui_msg_enddialog)
620         {
621             if(wp == IDOK)
622                 update_structure(hdlg, ps_struct);
623             EndDialog(hdlg, wp);
624             /* native does its cleanup in WM_DESTROY */
625             RemovePropW(hdlg, prop_name);
626             free_structure(ps_struct);
627             return TRUE;
628         }
629         return FALSE;
630     }
631
632 }
633
634 /***********************************************************************
635  *           OleUIPasteSpecialA (OLEDLG.4)
636  */
637 UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
638 {
639     OLEUIPASTESPECIALW ps;
640     UINT ret;
641     TRACE("(%p)\n", psA);
642
643     memcpy(&ps, psA, psA->cbStruct);
644
645     ps.lpszCaption = strdupAtoW(psA->lpszCaption);
646     if(!IS_INTRESOURCE(ps.lpszTemplate))
647         ps.lpszTemplate = strdupAtoW(psA->lpszTemplate);
648
649     if(psA->cPasteEntries > 0)
650     {
651         DWORD size = psA->cPasteEntries * sizeof(ps.arrPasteEntries[0]);
652         INT i;
653
654         ps.arrPasteEntries = HeapAlloc(GetProcessHeap(), 0, size);
655         memcpy(ps.arrPasteEntries, psA->arrPasteEntries, size);
656         for(i = 0; i < psA->cPasteEntries; i++)
657         {
658             ps.arrPasteEntries[i].lpstrFormatName =
659                 strdupAtoW(psA->arrPasteEntries[i].lpstrFormatName);
660             ps.arrPasteEntries[i].lpstrResultText =
661                 strdupAtoW(psA->arrPasteEntries[i].lpstrResultText);
662         }
663     }
664
665     ret = OleUIPasteSpecialW(&ps);
666
667     if(psA->cPasteEntries > 0)
668     {
669         INT i;
670         for(i = 0; i < psA->cPasteEntries; i++)
671         {
672             HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrFormatName);
673             HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrResultText);
674         }
675         HeapFree(GetProcessHeap(), 0, ps.arrPasteEntries);
676     }
677     if(!IS_INTRESOURCE(ps.lpszTemplate))
678         HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszTemplate);
679     HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszCaption);
680
681     /* Copy back the output fields */
682     psA->dwFlags = ps.dwFlags;
683     psA->lpSrcDataObj = ps.lpSrcDataObj;
684     psA->nSelectedIndex = ps.nSelectedIndex;
685     psA->fLink = ps.fLink;
686     psA->hMetaPict = ps.hMetaPict;
687     psA->sizel = ps.sizel;
688
689     return ret;
690 }
691
692 /***********************************************************************
693  *           OleUIPasteSpecialW (OLEDLG.22)
694  */
695 UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW ps)
696 {
697     LPCDLGTEMPLATEW dlg_templ = (LPCDLGTEMPLATEW)ps->hResource;
698     UINT ret;
699
700     TRACE("(%p)\n", ps);
701
702     if(TRACE_ON(ole)) dump_pastespecial(ps);
703
704     if(!ps->lpSrcDataObj)
705         OleGetClipboard(&ps->lpSrcDataObj);
706
707     if(ps->hInstance || !ps->hResource)
708     {
709         HINSTANCE hInst = ps->hInstance ? ps->hInstance : OLEDLG_hInstance;
710         const WCHAR *name = ps->hInstance ? ps->lpszTemplate : MAKEINTRESOURCEW(IDD_PASTESPECIAL4);
711         HRSRC hrsrc;
712
713         if(name == NULL) return OLEUI_ERR_LPSZTEMPLATEINVALID;
714         hrsrc = FindResourceW(hInst, name, MAKEINTRESOURCEW(RT_DIALOG));
715         if(!hrsrc) return OLEUI_ERR_FINDTEMPLATEFAILURE;
716         dlg_templ = LoadResource(hInst, hrsrc);
717         if(!dlg_templ) return OLEUI_ERR_LOADTEMPLATEFAILURE;
718     }
719
720     ret = DialogBoxIndirectParamW(OLEDLG_hInstance, dlg_templ, ps->hWndOwner, ps_dlg_proc, (LPARAM)ps);
721
722     return ret;
723 }