2 * OleUIPasteSpecial implementation
4 * Copyright 2006 Huw Davies
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.
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.
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
21 #define COM_NO_WINDOWS_H
34 #include "oledlg_private.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 OLEUIPASTESPECIALW *ps;
46 static const struct ps_flag
51 #define PS_FLAG_ENTRY(p) {p, #p}
52 PS_FLAG_ENTRY(PSF_SHOWHELP),
53 PS_FLAG_ENTRY(PSF_SELECTPASTE),
54 PS_FLAG_ENTRY(PSF_SELECTPASTELINK),
55 PS_FLAG_ENTRY(PSF_CHECKDISPLAYASICON),
56 PS_FLAG_ENTRY(PSF_DISABLEDISPLAYASICON),
57 PS_FLAG_ENTRY(PSF_HIDECHANGEICON),
58 PS_FLAG_ENTRY(PSF_STAYONCLIPBOARDCHANGE),
59 PS_FLAG_ENTRY(PSF_NOREFRESHDATAOBJECT),
64 static void dump_ps_flags(DWORD flags)
66 char flagstr[1000] = "";
68 const struct ps_flag *flag = ps_flags;
69 for( ; flag->name; flag++) {
70 if(flags & flag->flag) {
71 strcat(flagstr, flag->name);
75 TRACE("flags %08x %s\n", flags, flagstr);
78 static void dump_pastespecial(LPOLEUIPASTESPECIALW ps)
81 dump_ps_flags(ps->dwFlags);
82 TRACE("hwnd %p caption %s hook %p custdata %lx\n",
83 ps->hWndOwner, debugstr_w(ps->lpszCaption), ps->lpfnHook, ps->lCustData);
84 if(IS_INTRESOURCE(ps->lpszTemplate))
85 TRACE("hinst %p template %04x hresource %p\n", ps->hInstance, (WORD)(ULONG_PTR)ps->lpszTemplate, ps->hResource);
87 TRACE("hinst %p template %s hresource %p\n", ps->hInstance, debugstr_w(ps->lpszTemplate), ps->hResource);
88 TRACE("dataobj %p arrpasteent %p cpasteent %d arrlinktype %p clinktype %d\n",
89 ps->lpSrcDataObj, ps->arrPasteEntries, ps->cPasteEntries,
90 ps->arrLinkTypes, ps->cLinkTypes);
91 TRACE("cclsidex %d lpclsidex %p nselect %d flink %d hmetapict %p size(%d,%d)\n",
92 ps->cClsidExclude, ps->lpClsidExclude, ps->nSelectedIndex, ps->fLink,
93 ps->hMetaPict, ps->sizel.cx, ps->sizel.cy);
94 for(i = 0; i < ps->cPasteEntries; i++)
96 TRACE("arrPasteEntries[%d]: cFormat %08x pTargetDevice %p dwAspect %d lindex %d tymed %d\n",
97 i, ps->arrPasteEntries[i].fmtetc.cfFormat, ps->arrPasteEntries[i].fmtetc.ptd,
98 ps->arrPasteEntries[i].fmtetc.dwAspect, ps->arrPasteEntries[i].fmtetc.lindex,
99 ps->arrPasteEntries[i].fmtetc.tymed);
100 TRACE("\tformat name %s result text %s flags %04x\n", debugstr_w(ps->arrPasteEntries[i].lpstrFormatName),
101 debugstr_w(ps->arrPasteEntries[i].lpstrResultText), ps->arrPasteEntries[i].dwFlags);
103 for(i = 0; i < ps->cLinkTypes; i++)
104 TRACE("arrLinkTypes[%d] %08x\n", i, ps->arrLinkTypes[i]);
105 for(i = 0; i < ps->cClsidExclude; i++)
106 TRACE("lpClsidExclude[%d] %s\n", i, debugstr_guid(&ps->lpClsidExclude[i]));
110 static inline WCHAR *strdupAtoW(const char *str)
114 if(!str) return NULL;
115 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
116 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
117 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
121 static BOOL add_entry_to_lb(HWND hdlg, UINT id, OLEUIPASTEENTRYW *pe)
123 HWND hwnd = GetDlgItem(hdlg, id);
126 /* FIXME %s handling */
128 /* Note that this suffers from the same bug as native, in that if a new string
129 is a substring of an already added string, then the FINDSTRING will succeed
130 this is probably not what we want */
131 if(SendMessageW(hwnd, LB_FINDSTRING, 0, (LPARAM)pe->lpstrFormatName) == -1)
133 LRESULT pos = SendMessageW(hwnd, LB_ADDSTRING, 0, (LPARAM)pe->lpstrFormatName);
134 SendMessageW(hwnd, LB_SETITEMDATA, pos, (LPARAM)pe);
140 static DWORD init_pastelist(HWND hdlg, OLEUIPASTESPECIALW *ps)
142 IEnumFORMATETC *penum;
145 DWORD fetched, items_added = 0;
147 hr = IDataObject_EnumFormatEtc(ps->lpSrcDataObj, DATADIR_GET, &penum);
150 WARN("Unable to create IEnumFORMATETC\n");
154 /* The native version grabs only the first 20 fmts and we do the same */
155 hr = IEnumFORMATETC_Next(penum, sizeof(fmts)/sizeof(fmts[0]), fmts, &fetched);
156 TRACE("got %d formats hr %08x\n", fetched, hr);
160 DWORD src_fmt, req_fmt;
161 for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
163 /* This is used by update_struct() to set nSelectedIndex on exit */
164 ps->arrPasteEntries[req_fmt].dwScratchSpace = req_fmt;
165 TRACE("req_fmt %x\n", ps->arrPasteEntries[req_fmt].fmtetc.cfFormat);
166 for(src_fmt = 0; src_fmt < fetched; src_fmt++)
168 TRACE("\tenum'ed fmt %x\n", fmts[src_fmt].cfFormat);
169 if(ps->arrPasteEntries[req_fmt].fmtetc.cfFormat == fmts[src_fmt].cfFormat)
171 add_entry_to_lb(hdlg, IDC_PS_PASTELIST, ps->arrPasteEntries + req_fmt);
179 IEnumFORMATETC_Release(penum);
180 EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTE), items_added ? TRUE : FALSE);
184 static DWORD init_linklist(HWND hdlg, OLEUIPASTESPECIALW *ps)
187 DWORD supported_mask = 0;
188 DWORD items_added = 0;
190 FORMATETC fmt = {0, NULL, DVASPECT_CONTENT, -1, -1};
192 for(link = 0; link < ps->cLinkTypes && link < PS_MAXLINKTYPES; link++)
194 fmt.cfFormat = ps->arrLinkTypes[link];
195 hr = IDataObject_QueryGetData(ps->lpSrcDataObj, &fmt);
197 supported_mask |= 1 << link;
199 TRACE("supported_mask %02x\n", supported_mask);
200 for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
203 if(ps->arrPasteEntries[req_fmt].dwFlags & OLEUIPASTE_LINKANYTYPE)
206 linktypes = ps->arrPasteEntries[req_fmt].dwFlags & 0xff;
208 if(linktypes & supported_mask)
210 add_entry_to_lb(hdlg, IDC_PS_PASTELINKLIST, ps->arrPasteEntries + req_fmt);
215 EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTELINK), items_added ? TRUE : FALSE);
219 /* copies src_list_id into the display list */
220 static void update_display_list(HWND hdlg, UINT src_list_id)
222 LONG count, i, old_pos;
225 HWND display_list = GetDlgItem(hdlg, IDC_PS_DISPLAYLIST);
226 HWND list = GetDlgItem(hdlg, src_list_id);
228 old_pos = SendMessageW(display_list, LB_GETCURSEL, 0, 0);
229 if(old_pos == -1) old_pos = 0;
231 SendMessageW(display_list, WM_SETREDRAW, 0, 0);
232 SendMessageW(display_list, LB_RESETCONTENT, 0, 0);
233 count = SendMessageW(list, LB_GETCOUNT, 0, 0);
234 for(i = 0; i < count; i++)
236 SendMessageW(list, LB_GETTEXT, i, (LPARAM)txt);
237 item_data = SendMessageW(list, LB_GETITEMDATA, i, 0);
238 SendMessageW(display_list, LB_INSERTSTRING, i, (LPARAM)txt);
239 SendMessageW(display_list, LB_SETITEMDATA, i, item_data);
241 old_pos = max(old_pos, count);
242 SendMessageW(display_list, LB_SETCURSEL, 0, 0);
243 SendMessageW(display_list, WM_SETREDRAW, 1, 0);
244 if(GetForegroundWindow() == hdlg)
245 SetFocus(display_list);
248 static void init_lists(HWND hdlg, ps_struct_t *ps_struct)
250 DWORD pastes_added = init_pastelist(hdlg, ps_struct->ps);
251 DWORD links_added = init_linklist(hdlg, ps_struct->ps);
252 UINT check_id, list_id;
254 if((ps_struct->flags & (PSF_SELECTPASTE | PSF_SELECTPASTELINK)) == 0)
255 ps_struct->flags |= PSF_SELECTPASTE;
257 if(!pastes_added && !links_added)
258 ps_struct->flags &= ~(PSF_SELECTPASTE | PSF_SELECTPASTELINK);
259 else if(!pastes_added && (ps_struct->flags & PSF_SELECTPASTE))
261 ps_struct->flags &= ~PSF_SELECTPASTE;
262 ps_struct->flags |= PSF_SELECTPASTELINK;
264 else if(!links_added && (ps_struct->flags & PSF_SELECTPASTELINK))
266 ps_struct->flags &= ~PSF_SELECTPASTELINK;
267 ps_struct->flags |= PSF_SELECTPASTE;
272 if(ps_struct->flags & PSF_SELECTPASTE)
274 check_id = IDC_PS_PASTE;
275 list_id = IDC_PS_PASTELIST;
277 else if(ps_struct->flags & PSF_SELECTPASTELINK)
279 check_id = IDC_PS_PASTELINK;
280 list_id = IDC_PS_PASTELINKLIST;
283 CheckRadioButton(hdlg, IDC_PS_PASTE, IDC_PS_PASTELINK, check_id);
286 update_display_list(hdlg, list_id);
288 EnableWindow(GetDlgItem(hdlg, IDOK), 0);
291 static void send_end_dialog_msg(HWND hdlg, ps_struct_t *ps_struct, UINT id)
293 SendMessageW(hdlg, oleui_msg_enddialog, id, 0);
296 static void update_structure(HWND hdlg, ps_struct_t *ps_struct)
298 ps_struct->ps->dwFlags = ps_struct->flags;
299 ps_struct->ps->fLink = (ps_struct->flags & PSF_SELECTPASTELINK) ? TRUE : FALSE;
302 static void free_structure(ps_struct_t *ps_struct)
304 HeapFree(GetProcessHeap(), 0, ps_struct);
307 static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
309 /* native uses prop name "Structure", but we're not compatible
310 with that so we'll prepend "Wine_". */
311 static const WCHAR prop_name[] = {'W','i','n','e','_','S','t','r','u','c','t','u','r','e',0};
312 ps_struct_t *ps_struct;
314 TRACE("(%p, %04x, %08x, %08lx)\n", hdlg, msg, wp, lp);
316 ps_struct = GetPropW(hdlg, prop_name);
318 if(msg != WM_INITDIALOG)
328 ps_struct = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps_struct));
329 ps_struct->ps = (OLEUIPASTESPECIALW*)lp;
330 ps_struct->flags = ps_struct->ps->dwFlags;
332 SetPropW(hdlg, prop_name, ps_struct);
334 if(ps_struct->ps->lpszCaption)
335 SetWindowTextW(hdlg, ps_struct->ps->lpszCaption);
337 init_lists(hdlg, ps_struct);
339 return TRUE; /* use default focus */
346 send_end_dialog_msg(hdlg, ps_struct, LOWORD(wp));
351 if(msg == oleui_msg_enddialog)
354 update_structure(hdlg, ps_struct);
356 free_structure(ps_struct);
364 /***********************************************************************
365 * OleUIPasteSpecialA (OLEDLG.4)
367 UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
369 OLEUIPASTESPECIALW ps;
371 TRACE("(%p)\n", psA);
373 memcpy(&ps, psA, psA->cbStruct);
375 ps.lpszCaption = strdupAtoW(psA->lpszCaption);
376 if(!IS_INTRESOURCE(ps.lpszTemplate))
377 ps.lpszTemplate = strdupAtoW(psA->lpszTemplate);
379 if(psA->cPasteEntries > 0)
381 DWORD size = psA->cPasteEntries * sizeof(ps.arrPasteEntries[0]);
384 ps.arrPasteEntries = HeapAlloc(GetProcessHeap(), 0, size);
385 memcpy(ps.arrPasteEntries, psA->arrPasteEntries, size);
386 for(i = 0; i < psA->cPasteEntries; i++)
388 ps.arrPasteEntries[i].lpstrFormatName =
389 strdupAtoW(psA->arrPasteEntries[i].lpstrFormatName);
390 ps.arrPasteEntries[i].lpstrResultText =
391 strdupAtoW(psA->arrPasteEntries[i].lpstrResultText);
395 ret = OleUIPasteSpecialW(&ps);
397 if(psA->cPasteEntries > 0)
400 for(i = 0; i < psA->cPasteEntries; i++)
402 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrFormatName);
403 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrResultText);
405 HeapFree(GetProcessHeap(), 0, ps.arrPasteEntries);
407 if(!IS_INTRESOURCE(ps.lpszTemplate))
408 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszTemplate);
409 HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszCaption);
411 /* Copy back the output fields */
412 psA->dwFlags = ps.dwFlags;
413 psA->lpSrcDataObj = ps.lpSrcDataObj;
414 psA->nSelectedIndex = ps.nSelectedIndex;
415 psA->fLink = ps.fLink;
416 psA->hMetaPict = ps.hMetaPict;
417 psA->sizel = ps.sizel;
422 /***********************************************************************
423 * OleUIPasteSpecialW (OLEDLG.22)
425 UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW ps)
427 LPCDLGTEMPLATEW dlg_templ = (LPCDLGTEMPLATEW)ps->hResource;
431 if(TRACE_ON(ole)) dump_pastespecial(ps);
433 if(!ps->lpSrcDataObj)
434 OleGetClipboard(&ps->lpSrcDataObj);
436 if(ps->hInstance || !ps->hResource)
438 HINSTANCE hInst = ps->hInstance ? ps->hInstance : OLEDLG_hInstance;
439 const WCHAR *name = ps->hInstance ? ps->lpszTemplate : MAKEINTRESOURCEW(IDD_PASTESPECIAL4);
442 if(name == NULL) return OLEUI_ERR_LPSZTEMPLATEINVALID;
443 hrsrc = FindResourceW(hInst, name, MAKEINTRESOURCEW(RT_DIALOG));
444 if(!hrsrc) return OLEUI_ERR_FINDTEMPLATEFAILURE;
445 dlg_templ = LoadResource(hInst, hrsrc);
446 if(!dlg_templ) return OLEUI_ERR_LOADTEMPLATEFAILURE;
449 DialogBoxIndirectParamW(OLEDLG_hInstance, dlg_templ, ps->hWndOwner, ps_dlg_proc, (LPARAM)ps);
451 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);