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