wine/dlls/oledlg/pastespl.c
2011-07-14 14:45:06 +02:00

721 lines
23 KiB
C

/*
* OleUIPasteSpecial implementation
*
* Copyright 2006 Huw Davies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "oledlg.h"
#include "oledlg_private.h"
#include "resource.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
typedef struct
{
OLEUIPASTESPECIALW *ps;
DWORD flags;
WCHAR *source_name;
WCHAR *link_source_name;
WCHAR *type_name;
WCHAR *link_type_name;
LPOLESTR app_name;
} ps_struct_t;
static const struct ps_flag
{
DWORD flag;
const char *name;
} ps_flags[] = {
#define PS_FLAG_ENTRY(p) {p, #p}
PS_FLAG_ENTRY(PSF_SHOWHELP),
PS_FLAG_ENTRY(PSF_SELECTPASTE),
PS_FLAG_ENTRY(PSF_SELECTPASTELINK),
PS_FLAG_ENTRY(PSF_CHECKDISPLAYASICON),
PS_FLAG_ENTRY(PSF_DISABLEDISPLAYASICON),
PS_FLAG_ENTRY(PSF_HIDECHANGEICON),
PS_FLAG_ENTRY(PSF_STAYONCLIPBOARDCHANGE),
PS_FLAG_ENTRY(PSF_NOREFRESHDATAOBJECT),
{-1, NULL}
#undef PS_FLAG_ENTRY
};
static void dump_ps_flags(DWORD flags)
{
char flagstr[1000] = "";
const struct ps_flag *flag = ps_flags;
for( ; flag->name; flag++) {
if(flags & flag->flag) {
strcat(flagstr, flag->name);
strcat(flagstr, "|");
}
}
TRACE("flags %08x %s\n", flags, flagstr);
}
static void dump_pastespecial(const OLEUIPASTESPECIALW *ps)
{
UINT i;
dump_ps_flags(ps->dwFlags);
TRACE("hwnd %p caption %s hook %p custdata %lx\n",
ps->hWndOwner, debugstr_w(ps->lpszCaption), ps->lpfnHook, ps->lCustData);
if(IS_INTRESOURCE(ps->lpszTemplate))
TRACE("hinst %p template %04x hresource %p\n", ps->hInstance, (WORD)(ULONG_PTR)ps->lpszTemplate, ps->hResource);
else
TRACE("hinst %p template %s hresource %p\n", ps->hInstance, debugstr_w(ps->lpszTemplate), ps->hResource);
TRACE("dataobj %p arrpasteent %p cpasteent %d arrlinktype %p clinktype %d\n",
ps->lpSrcDataObj, ps->arrPasteEntries, ps->cPasteEntries,
ps->arrLinkTypes, ps->cLinkTypes);
TRACE("cclsidex %d lpclsidex %p nselect %d flink %d hmetapict %p size(%d,%d)\n",
ps->cClsidExclude, ps->lpClsidExclude, ps->nSelectedIndex, ps->fLink,
ps->hMetaPict, ps->sizel.cx, ps->sizel.cy);
for(i = 0; i < ps->cPasteEntries; i++)
{
TRACE("arrPasteEntries[%d]: cFormat %08x pTargetDevice %p dwAspect %d lindex %d tymed %d\n",
i, ps->arrPasteEntries[i].fmtetc.cfFormat, ps->arrPasteEntries[i].fmtetc.ptd,
ps->arrPasteEntries[i].fmtetc.dwAspect, ps->arrPasteEntries[i].fmtetc.lindex,
ps->arrPasteEntries[i].fmtetc.tymed);
TRACE("\tformat name %s result text %s flags %04x\n", debugstr_w(ps->arrPasteEntries[i].lpstrFormatName),
debugstr_w(ps->arrPasteEntries[i].lpstrResultText), ps->arrPasteEntries[i].dwFlags);
}
for(i = 0; i < ps->cLinkTypes; i++)
TRACE("arrLinkTypes[%d] %08x\n", i, ps->arrLinkTypes[i]);
for(i = 0; i < ps->cClsidExclude; i++)
TRACE("lpClsidExclude[%d] %s\n", i, debugstr_guid(&ps->lpClsidExclude[i]));
}
static inline WCHAR *strdupAtoW(const char *str)
{
DWORD len;
WCHAR *ret;
if(!str) return NULL;
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
return ret;
}
static inline WCHAR *strdupW(const WCHAR *str)
{
DWORD len;
WCHAR *ret;
if(!str) return NULL;
len = lstrlenW(str) + 1;
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
memcpy(ret, str, len * sizeof(WCHAR));
return ret;
}
static void get_descriptors(HWND hdlg, ps_struct_t *ps_struct)
{
FORMATETC fmtetc;
STGMEDIUM stg;
fmtetc.tymed = TYMED_HGLOBAL;
fmtetc.dwAspect = DVASPECT_CONTENT;
fmtetc.ptd = NULL;
fmtetc.lindex = -1;
fmtetc.cfFormat = cf_object_descriptor;
if(IDataObject_GetData(ps_struct->ps->lpSrcDataObj, &fmtetc, &stg) == S_OK)
{
OBJECTDESCRIPTOR *obj_desc = GlobalLock(stg.u.hGlobal);
if(obj_desc->dwSrcOfCopy)
ps_struct->source_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwSrcOfCopy));
if(obj_desc->dwFullUserTypeName)
ps_struct->type_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwFullUserTypeName));
OleRegGetUserType(&obj_desc->clsid, USERCLASSTYPE_APPNAME, &ps_struct->app_name);
/* Get the icon here. If dwDrawAspect & DVASCPECT_ICON call GetData(CF_METAFILEPICT), otherwise
native calls OleGetIconFromClass(obj_desc->clsid) */
GlobalUnlock(stg.u.hGlobal);
GlobalFree(stg.u.hGlobal);
}
else
{
/* Try to get some data using some of the other clipboard formats */
}
fmtetc.cfFormat = cf_link_src_descriptor;
if(IDataObject_GetData(ps_struct->ps->lpSrcDataObj, &fmtetc, &stg) == S_OK)
{
OBJECTDESCRIPTOR *obj_desc = GlobalLock(stg.u.hGlobal);
if(obj_desc->dwSrcOfCopy)
ps_struct->link_source_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwSrcOfCopy));
if(obj_desc->dwFullUserTypeName)
ps_struct->link_type_name = strdupW((WCHAR*)((char*)obj_desc + obj_desc->dwFullUserTypeName));
GlobalUnlock(stg.u.hGlobal);
GlobalFree(stg.u.hGlobal);
}
if(ps_struct->source_name == NULL && ps_struct->link_source_name == NULL)
{
WCHAR buf[200];
LoadStringW(OLEDLG_hInstance, IDS_PS_UNKNOWN_SRC, buf, sizeof(buf)/sizeof(WCHAR));
ps_struct->source_name = strdupW(buf);
}
if(ps_struct->type_name == NULL && ps_struct->link_type_name == NULL)
{
WCHAR buf[200];
LoadStringW(OLEDLG_hInstance, IDS_PS_UNKNOWN_TYPE, buf, sizeof(buf)/sizeof(WCHAR));
ps_struct->type_name = strdupW(buf);
}
}
static BOOL add_entry_to_lb(HWND hdlg, UINT id, OLEUIPASTEENTRYW *pe)
{
HWND hwnd = GetDlgItem(hdlg, id);
BOOL ret = FALSE;
/* FIXME %s handling */
/* Note that this suffers from the same bug as native, in that if a new string
is a substring of an already added string, then the FINDSTRING will succeed
this is probably not what we want */
if(SendMessageW(hwnd, LB_FINDSTRING, 0, (LPARAM)pe->lpstrFormatName) == -1)
{
LRESULT pos = SendMessageW(hwnd, LB_ADDSTRING, 0, (LPARAM)pe->lpstrFormatName);
SendMessageW(hwnd, LB_SETITEMDATA, pos, (LPARAM)pe);
ret = TRUE;
}
return ret;
}
static DWORD init_pastelist(HWND hdlg, OLEUIPASTESPECIALW *ps)
{
IEnumFORMATETC *penum;
HRESULT hr;
FORMATETC fmts[20];
DWORD fetched, items_added = 0;
hr = IDataObject_EnumFormatEtc(ps->lpSrcDataObj, DATADIR_GET, &penum);
if(FAILED(hr))
{
WARN("Unable to create IEnumFORMATETC\n");
return 0;
}
/* The native version grabs only the first 20 fmts and we do the same */
hr = IEnumFORMATETC_Next(penum, sizeof(fmts)/sizeof(fmts[0]), fmts, &fetched);
TRACE("got %d formats hr %08x\n", fetched, hr);
if(SUCCEEDED(hr))
{
DWORD src_fmt, req_fmt;
for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
{
/* This is used by update_structure() to set nSelectedIndex on exit */
ps->arrPasteEntries[req_fmt].dwScratchSpace = req_fmt;
TRACE("req_fmt %x\n", ps->arrPasteEntries[req_fmt].fmtetc.cfFormat);
for(src_fmt = 0; src_fmt < fetched; src_fmt++)
{
TRACE("\tenum'ed fmt %x\n", fmts[src_fmt].cfFormat);
if(ps->arrPasteEntries[req_fmt].fmtetc.cfFormat == fmts[src_fmt].cfFormat)
{
add_entry_to_lb(hdlg, IDC_PS_PASTELIST, ps->arrPasteEntries + req_fmt);
items_added++;
break;
}
}
}
}
IEnumFORMATETC_Release(penum);
EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTE), items_added ? TRUE : FALSE);
return items_added;
}
static DWORD init_linklist(HWND hdlg, OLEUIPASTESPECIALW *ps)
{
HRESULT hr;
DWORD supported_mask = 0;
DWORD items_added = 0;
int link, req_fmt;
FORMATETC fmt = {0, NULL, DVASPECT_CONTENT, -1, -1};
for(link = 0; link < ps->cLinkTypes && link < PS_MAXLINKTYPES; link++)
{
fmt.cfFormat = ps->arrLinkTypes[link];
hr = IDataObject_QueryGetData(ps->lpSrcDataObj, &fmt);
if(hr == S_OK)
supported_mask |= 1 << link;
}
TRACE("supported_mask %02x\n", supported_mask);
for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
{
DWORD linktypes;
if(ps->arrPasteEntries[req_fmt].dwFlags & OLEUIPASTE_LINKANYTYPE)
linktypes = 0xff;
else
linktypes = ps->arrPasteEntries[req_fmt].dwFlags & 0xff;
if(linktypes & supported_mask)
{
add_entry_to_lb(hdlg, IDC_PS_PASTELINKLIST, ps->arrPasteEntries + req_fmt);
items_added++;
}
}
EnableWindow(GetDlgItem(hdlg, IDC_PS_PASTELINK), items_added ? TRUE : FALSE);
return items_added;
}
/* copies src_list_id into the display list */
static void update_display_list(HWND hdlg, UINT src_list_id)
{
LONG count, i, old_pos;
WCHAR txt[256];
LONG item_data;
HWND display_list = GetDlgItem(hdlg, IDC_PS_DISPLAYLIST);
HWND list = GetDlgItem(hdlg, src_list_id);
old_pos = SendMessageW(display_list, LB_GETCURSEL, 0, 0);
if(old_pos == -1) old_pos = 0;
SendMessageW(display_list, WM_SETREDRAW, 0, 0);
SendMessageW(display_list, LB_RESETCONTENT, 0, 0);
count = SendMessageW(list, LB_GETCOUNT, 0, 0);
for(i = 0; i < count; i++)
{
SendMessageW(list, LB_GETTEXT, i, (LPARAM)txt);
item_data = SendMessageW(list, LB_GETITEMDATA, i, 0);
SendMessageW(display_list, LB_INSERTSTRING, i, (LPARAM)txt);
SendMessageW(display_list, LB_SETITEMDATA, i, item_data);
}
SendMessageW(display_list, LB_SETCURSEL, 0, 0);
SendMessageW(display_list, WM_SETREDRAW, 1, 0);
if(GetForegroundWindow() == hdlg)
SetFocus(display_list);
}
static void init_lists(HWND hdlg, ps_struct_t *ps_struct)
{
DWORD pastes_added = init_pastelist(hdlg, ps_struct->ps);
DWORD links_added = init_linklist(hdlg, ps_struct->ps);
UINT check_id, list_id;
if((ps_struct->flags & (PSF_SELECTPASTE | PSF_SELECTPASTELINK)) == 0)
ps_struct->flags |= PSF_SELECTPASTE;
if(!pastes_added && !links_added)
ps_struct->flags &= ~(PSF_SELECTPASTE | PSF_SELECTPASTELINK);
else if(!pastes_added && (ps_struct->flags & PSF_SELECTPASTE))
{
ps_struct->flags &= ~PSF_SELECTPASTE;
ps_struct->flags |= PSF_SELECTPASTELINK;
}
else if(!links_added && (ps_struct->flags & PSF_SELECTPASTELINK))
{
ps_struct->flags &= ~PSF_SELECTPASTELINK;
ps_struct->flags |= PSF_SELECTPASTE;
}
check_id = 0;
list_id = 0;
if(ps_struct->flags & PSF_SELECTPASTE)
{
check_id = IDC_PS_PASTE;
list_id = IDC_PS_PASTELIST;
}
else if(ps_struct->flags & PSF_SELECTPASTELINK)
{
check_id = IDC_PS_PASTELINK;
list_id = IDC_PS_PASTELINKLIST;
}
CheckRadioButton(hdlg, IDC_PS_PASTE, IDC_PS_PASTELINK, check_id);
if(list_id)
update_display_list(hdlg, list_id);
else
EnableWindow(GetDlgItem(hdlg, IDOK), 0);
}
static void update_src_text(HWND hdlg, const ps_struct_t *ps_struct)
{
WCHAR *str;
if(ps_struct->flags & PSF_SELECTPASTE)
{
if(ps_struct->source_name)
str = ps_struct->source_name;
else
str = ps_struct->link_source_name;
}
else
{
if(ps_struct->link_source_name)
str = ps_struct->link_source_name;
else
str = ps_struct->source_name;
}
SetDlgItemTextW(hdlg, IDC_PS_SOURCETEXT, str);
}
static void update_as_icon(HWND hdlg, ps_struct_t *ps_struct)
{
HWND icon_display = GetDlgItem(hdlg, IDC_PS_ICONDISPLAY);
HWND display_as_icon = GetDlgItem(hdlg, IDC_PS_DISPLAYASICON);
HWND change_icon = GetDlgItem(hdlg, IDC_PS_CHANGEICON);
/* FIXME. No as icon handling */
ps_struct->flags &= ~PSF_CHECKDISPLAYASICON;
CheckDlgButton(hdlg, IDC_PS_DISPLAYASICON, ps_struct->flags & PSF_CHECKDISPLAYASICON);
EnableWindow(display_as_icon, 0);
ShowWindow(icon_display, SW_HIDE);
EnableWindow(icon_display, 0);
ShowWindow(change_icon, SW_HIDE);
EnableWindow(change_icon, 0);
}
static void update_result_text(HWND hdlg, const ps_struct_t *ps_struct)
{
WCHAR resource_txt[200];
UINT res_id;
OLEUIPASTEENTRYW *pent;
LONG cur_sel;
static const WCHAR percent_s[] = {'%','s',0};
WCHAR *result_txt, *ptr;
cur_sel = SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETCURSEL, 0, 0);
if(cur_sel == -1) return;
pent = (OLEUIPASTEENTRYW*)SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETITEMDATA, cur_sel, 0);
if(ps_struct->flags & PSF_SELECTPASTE)
{
if(ps_struct->flags & PSF_CHECKDISPLAYASICON)
res_id = IDS_PS_PASTE_OBJECT_AS_ICON;
else
res_id = IDS_PS_PASTE_DATA;
}
else
{
if(ps_struct->flags & PSF_CHECKDISPLAYASICON)
res_id = IDS_PS_PASTE_LINK_OBJECT_AS_ICON;
else
res_id = IDS_PS_PASTE_LINK_DATA;
}
LoadStringW(OLEDLG_hInstance, res_id, resource_txt, sizeof(resource_txt)/sizeof(WCHAR));
if((ptr = strstrW(resource_txt, percent_s)))
{
/* FIXME handle %s in ResultText. Sub appname if IDS_PS_PASTE_OBJECT{_AS_ICON}. Else sub appropriate type name */
size_t result_txt_len = strlenW(pent->lpstrResultText);
ptrdiff_t offs = (char*)ptr - (char*)resource_txt;
result_txt = HeapAlloc(GetProcessHeap(), 0, (strlenW(resource_txt) + result_txt_len - 1) * sizeof(WCHAR));
memcpy(result_txt, resource_txt, offs);
memcpy((char*)result_txt + offs, pent->lpstrResultText, result_txt_len * sizeof(WCHAR));
memcpy((char*)result_txt + offs + result_txt_len * sizeof(WCHAR), ptr + 2, (strlenW(ptr + 2) + 1) * sizeof(WCHAR));
}
else
result_txt = resource_txt;
SetDlgItemTextW(hdlg, IDC_PS_RESULTTEXT, result_txt);
if(result_txt != resource_txt)
HeapFree(GetProcessHeap(), 0, result_txt);
}
static void selection_change(HWND hdlg, ps_struct_t *ps_struct)
{
update_as_icon(hdlg, ps_struct);
update_result_text(hdlg, ps_struct);
}
static void mode_change(HWND hdlg, ps_struct_t *ps_struct, UINT id)
{
if(id == IDC_PS_PASTE)
{
ps_struct->flags &= ~PSF_SELECTPASTELINK;
ps_struct->flags |= PSF_SELECTPASTE;
}
else
{
ps_struct->flags &= ~PSF_SELECTPASTE;
ps_struct->flags |= PSF_SELECTPASTELINK;
}
update_src_text(hdlg, ps_struct);
update_display_list(hdlg, id == IDC_PS_PASTE ? IDC_PS_PASTELIST : IDC_PS_PASTELINKLIST);
selection_change(hdlg, ps_struct);
}
static void post_help_msg(HWND hdlg, ps_struct_t *ps_struct)
{
PostMessageW(ps_struct->ps->hWndOwner, oleui_msg_help, (WPARAM)hdlg, IDD_PASTESPECIAL);
}
static void send_end_dialog_msg(HWND hdlg, ps_struct_t *ps_struct, UINT id)
{
SendMessageW(hdlg, oleui_msg_enddialog, id, 0);
}
static void update_structure(HWND hdlg, ps_struct_t *ps_struct)
{
LONG cur_sel = SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETCURSEL, 0, 0);
if(cur_sel != -1)
{
OLEUIPASTEENTRYW *pent;
pent = (OLEUIPASTEENTRYW *)SendMessageW(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST), LB_GETITEMDATA, cur_sel, 0);
ps_struct->ps->nSelectedIndex = pent->dwScratchSpace;
}
ps_struct->ps->dwFlags = ps_struct->flags;
ps_struct->ps->fLink = (ps_struct->flags & PSF_SELECTPASTELINK) ? TRUE : FALSE;
}
static void free_structure(ps_struct_t *ps_struct)
{
HeapFree(GetProcessHeap(), 0, ps_struct->type_name);
HeapFree(GetProcessHeap(), 0, ps_struct->source_name);
HeapFree(GetProcessHeap(), 0, ps_struct->link_type_name);
HeapFree(GetProcessHeap(), 0, ps_struct->link_source_name);
CoTaskMemFree(ps_struct->app_name);
HeapFree(GetProcessHeap(), 0, ps_struct);
}
static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
{
/* native uses prop name "Structure", but we're not compatible
with that so we'll prepend "Wine_". */
static const WCHAR prop_name[] = {'W','i','n','e','_','S','t','r','u','c','t','u','r','e',0};
ps_struct_t *ps_struct;
TRACE("(%p, %04x, %08lx, %08lx)\n", hdlg, msg, wp, lp);
ps_struct = GetPropW(hdlg, prop_name);
if(msg != WM_INITDIALOG)
{
if(!ps_struct)
return 0;
if(ps_struct->ps->lpfnHook)
{
INT_PTR ret = ps_struct->ps->lpfnHook(hdlg, msg, wp, lp);
if(ret) return ret;
}
}
switch(msg)
{
case WM_INITDIALOG:
{
ps_struct = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps_struct));
ps_struct->ps = (OLEUIPASTESPECIALW*)lp;
ps_struct->type_name = NULL;
ps_struct->source_name = NULL;
ps_struct->link_type_name = NULL;
ps_struct->link_source_name = NULL;
ps_struct->app_name = NULL;
ps_struct->flags = ps_struct->ps->dwFlags;
SetPropW(hdlg, prop_name, ps_struct);
if(!(ps_struct->ps->dwFlags & PSF_SHOWHELP))
{
ShowWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), SW_HIDE);
EnableWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), 0);
}
if(ps_struct->ps->lpszCaption)
SetWindowTextW(hdlg, ps_struct->ps->lpszCaption);
get_descriptors(hdlg, ps_struct);
init_lists(hdlg, ps_struct);
update_src_text(hdlg, ps_struct);
selection_change(hdlg, ps_struct);
SetFocus(GetDlgItem(hdlg, IDC_PS_DISPLAYLIST));
if(ps_struct->ps->lpfnHook)
ps_struct->ps->lpfnHook(hdlg, msg, 0, 0);
return FALSE; /* use new focus */
}
case WM_COMMAND:
switch(LOWORD(wp))
{
case IDC_PS_DISPLAYLIST:
switch(HIWORD(wp))
{
case LBN_SELCHANGE:
selection_change(hdlg, ps_struct);
return FALSE;
default:
return FALSE;
}
case IDC_PS_PASTE:
case IDC_PS_PASTELINK:
switch(HIWORD(wp))
{
case BN_CLICKED:
mode_change(hdlg, ps_struct, LOWORD(wp));
return FALSE;
default:
return FALSE;
}
case IDC_OLEUIHELP:
switch(HIWORD(wp))
{
case BN_CLICKED:
post_help_msg(hdlg, ps_struct);
return FALSE;
default:
return FALSE;
}
case IDOK:
case IDCANCEL:
switch(HIWORD(wp))
{
case BN_CLICKED:
send_end_dialog_msg(hdlg, ps_struct, LOWORD(wp));
return FALSE;
default:
return FALSE;
}
}
return FALSE;
default:
if(msg == oleui_msg_enddialog)
{
if(wp == IDOK)
update_structure(hdlg, ps_struct);
EndDialog(hdlg, wp);
/* native does its cleanup in WM_DESTROY */
RemovePropW(hdlg, prop_name);
free_structure(ps_struct);
return TRUE;
}
return FALSE;
}
}
/***********************************************************************
* OleUIPasteSpecialA (OLEDLG.4)
*/
UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
{
OLEUIPASTESPECIALW ps;
UINT ret;
TRACE("(%p)\n", psA);
memcpy(&ps, psA, psA->cbStruct);
ps.lpszCaption = strdupAtoW(psA->lpszCaption);
if(!IS_INTRESOURCE(ps.lpszTemplate))
ps.lpszTemplate = strdupAtoW(psA->lpszTemplate);
if(psA->cPasteEntries > 0)
{
DWORD size = psA->cPasteEntries * sizeof(ps.arrPasteEntries[0]);
INT i;
ps.arrPasteEntries = HeapAlloc(GetProcessHeap(), 0, size);
memcpy(ps.arrPasteEntries, psA->arrPasteEntries, size);
for(i = 0; i < psA->cPasteEntries; i++)
{
ps.arrPasteEntries[i].lpstrFormatName =
strdupAtoW(psA->arrPasteEntries[i].lpstrFormatName);
ps.arrPasteEntries[i].lpstrResultText =
strdupAtoW(psA->arrPasteEntries[i].lpstrResultText);
}
}
ret = OleUIPasteSpecialW(&ps);
if(psA->cPasteEntries > 0)
{
INT i;
for(i = 0; i < psA->cPasteEntries; i++)
{
HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrFormatName);
HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrResultText);
}
HeapFree(GetProcessHeap(), 0, ps.arrPasteEntries);
}
if(!IS_INTRESOURCE(ps.lpszTemplate))
HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszTemplate);
HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.lpszCaption);
/* Copy back the output fields */
psA->dwFlags = ps.dwFlags;
psA->lpSrcDataObj = ps.lpSrcDataObj;
psA->nSelectedIndex = ps.nSelectedIndex;
psA->fLink = ps.fLink;
psA->hMetaPict = ps.hMetaPict;
psA->sizel = ps.sizel;
return ret;
}
/***********************************************************************
* OleUIPasteSpecialW (OLEDLG.22)
*/
UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW ps)
{
LPCDLGTEMPLATEW dlg_templ = (LPCDLGTEMPLATEW)ps->hResource;
UINT ret;
TRACE("(%p)\n", ps);
if(TRACE_ON(ole)) dump_pastespecial(ps);
if(!ps->lpSrcDataObj)
OleGetClipboard(&ps->lpSrcDataObj);
if(ps->hInstance || !ps->hResource)
{
HINSTANCE hInst = ps->hInstance ? ps->hInstance : OLEDLG_hInstance;
const WCHAR *name = ps->hInstance ? ps->lpszTemplate : MAKEINTRESOURCEW(IDD_PASTESPECIAL4);
HRSRC hrsrc;
if(name == NULL) return OLEUI_ERR_LPSZTEMPLATEINVALID;
hrsrc = FindResourceW(hInst, name, MAKEINTRESOURCEW(RT_DIALOG));
if(!hrsrc) return OLEUI_ERR_FINDTEMPLATEFAILURE;
dlg_templ = LoadResource(hInst, hrsrc);
if(!dlg_templ) return OLEUI_ERR_LOADTEMPLATEFAILURE;
}
ret = DialogBoxIndirectParamW(OLEDLG_hInstance, dlg_templ, ps->hWndOwner, ps_dlg_proc, (LPARAM)ps);
return ret;
}