📄 pastespl.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(LPOLEUIPASTESPECIALW 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -