sane.ds: Add partial stub support for ICAP_PIXELTYPE, with tests. Fixes a first crash...
[wine] / dlls / oledlg / pastespl.c
index 23c9985..ae5e2f2 100644 (file)
@@ -18,8 +18,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define COM_NO_WINDOWS_H
 #define COBJMACROS
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
 
 #include <stdarg.h>
 
 #include "oledlg.h"
 
 #include "oledlg_private.h"
+#include "resource.h"
 
 #include "wine/debug.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
@@ -41,6 +44,11 @@ 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
@@ -75,7 +83,7 @@ static void dump_ps_flags(DWORD flags)
     TRACE("flags %08x %s\n", flags, flagstr);
 }
 
-static void dump_pastespecial(LPOLEUIPASTESPECIALW ps)
+static void dump_pastespecial(const OLEUIPASTESPECIALW *ps)
 {
     UINT i;
     dump_ps_flags(ps->dwFlags);
@@ -118,6 +126,73 @@ static inline WCHAR *strdupAtoW(const char *str)
     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);
@@ -160,7 +235,7 @@ static DWORD init_pastelist(HWND hdlg, OLEUIPASTESPECIALW *ps)
         DWORD src_fmt, req_fmt;
         for(req_fmt = 0; req_fmt < ps->cPasteEntries; req_fmt++)
         {
-            /* This is used by update_struct() to set nSelectedIndex on exit */
+            /* 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++)
@@ -288,6 +363,119 @@ static void init_lists(HWND hdlg, ps_struct_t *ps_struct)
         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);
@@ -300,12 +488,24 @@ static void send_end_dialog_msg(HWND hdlg, ps_struct_t *ps_struct, UINT id)
 
 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);
 }
 
@@ -316,7 +516,7 @@ static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
     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, %08x, %08lx)\n", hdlg, msg, wp, lp);
+    TRACE("(%p, %04x, %08lx, %08lx)\n", hdlg, msg, wp, lp);
 
     ps_struct = GetPropW(hdlg, prop_name);
 
@@ -324,6 +524,12 @@ static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
     {
         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)
@@ -332,6 +538,11 @@ static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
     {
         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);
@@ -342,16 +553,46 @@ static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
             EnableWindow(GetDlgItem(hdlg, IDC_OLEUIHELP), 0);
         }
 
-       if(ps_struct->ps->lpszCaption)
+        if(ps_struct->ps->lpszCaption)
             SetWindowTextW(hdlg, ps_struct->ps->lpszCaption);
 
+        get_descriptors(hdlg, ps_struct);
+
         init_lists(hdlg, ps_struct);
 
-        return TRUE; /* use default focus */
+        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))
             {
@@ -363,8 +604,14 @@ static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
             }
         case IDOK:
         case IDCANCEL:
-            send_end_dialog_msg(hdlg, ps_struct, LOWORD(wp));
-            return FALSE;
+            switch(HIWORD(wp))
+            {
+            case BN_CLICKED:
+                send_end_dialog_msg(hdlg, ps_struct, LOWORD(wp));
+                return FALSE;
+            default:
+                return FALSE;
+            }
         }
         return FALSE;
     default:
@@ -373,6 +620,8 @@ static INT_PTR CALLBACK ps_dlg_proc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
             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;
         }
@@ -399,7 +648,7 @@ UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
     if(psA->cPasteEntries > 0)
     {
         DWORD size = psA->cPasteEntries * sizeof(ps.arrPasteEntries[0]);
-        UINT i;
+        INT i;
 
         ps.arrPasteEntries = HeapAlloc(GetProcessHeap(), 0, size);
         memcpy(ps.arrPasteEntries, psA->arrPasteEntries, size);
@@ -416,7 +665,7 @@ UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
 
     if(psA->cPasteEntries > 0)
     {
-        UINT i;
+        INT i;
         for(i = 0; i < psA->cPasteEntries; i++)
         {
             HeapFree(GetProcessHeap(), 0, (WCHAR*)ps.arrPasteEntries[i].lpstrFormatName);
@@ -445,6 +694,7 @@ UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA psA)
 UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW ps)
 {
     LPCDLGTEMPLATEW dlg_templ = (LPCDLGTEMPLATEW)ps->hResource;
+    UINT ret;
 
     TRACE("(%p)\n", ps);
 
@@ -466,8 +716,7 @@ UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW ps)
         if(!dlg_templ) return OLEUI_ERR_LOADTEMPLATEFAILURE;
     }
 
-    DialogBoxIndirectParamW(OLEDLG_hInstance, dlg_templ, ps->hWndOwner, ps_dlg_proc, (LPARAM)ps);
+    ret = DialogBoxIndirectParamW(OLEDLG_hInstance, dlg_templ, ps->hWndOwner, ps_dlg_proc, (LPARAM)ps);
 
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return OLEUI_FALSE;
+    return ret;
 }