|  | /* | 
|  | * 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); | 
|  | } | 
|  | old_pos = max(old_pos, count); | 
|  | 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; | 
|  | } |