⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pastespl.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -