xref: /reactos/dll/win32/ole32/ole2impl.c (revision aeea2943)
1 /*
2  * Ole 2 Create functions implementation
3  *
4  * Copyright (C) 1999-2000 Abey George
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <string.h>
23 
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "wine/debug.h"
32 #include "ole2.h"
33 #include "olestd.h"
34 #include "compobj_private.h"
35 
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 
38 /******************************************************************************
39  *		OleQueryCreateFromData [OLE32.@]
40  *
41  * Checks whether an object can become an embedded object.
42  * the clipboard or OLE drag and drop.
43  * Returns  : S_OK - Format that supports Embedded object creation are present.
44  *            OLE_E_STATIC - Format that supports static object creation are present.
45  *            S_FALSE - No acceptable format is available.
46  */
47 
OleQueryCreateFromData(IDataObject * data)48 HRESULT WINAPI OleQueryCreateFromData(IDataObject *data)
49 {
50     IEnumFORMATETC *enum_fmt;
51     FORMATETC fmt;
52     BOOL found_static = FALSE;
53     HRESULT hr;
54 
55     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
56 
57     if(FAILED(hr)) return hr;
58 
59     do
60     {
61         hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
62         if(hr == S_OK)
63         {
64             if(fmt.cfFormat == embedded_object_clipboard_format ||
65                fmt.cfFormat == embed_source_clipboard_format ||
66                fmt.cfFormat == filename_clipboard_format)
67             {
68                 IEnumFORMATETC_Release(enum_fmt);
69                 return S_OK;
70             }
71 
72             if(fmt.cfFormat == CF_METAFILEPICT ||
73                fmt.cfFormat == CF_BITMAP ||
74                fmt.cfFormat == CF_DIB)
75                 found_static = TRUE;
76         }
77     } while (hr == S_OK);
78 
79     IEnumFORMATETC_Release(enum_fmt);
80 
81     return found_static ? OLE_S_STATIC : S_FALSE;
82 }
83 
init_fmtetc(FORMATETC * fmt,CLIPFORMAT cf,TYMED tymed)84 static inline void init_fmtetc(FORMATETC *fmt, CLIPFORMAT cf, TYMED tymed)
85 {
86     fmt->cfFormat = cf;
87     fmt->ptd = NULL;
88     fmt->dwAspect = DVASPECT_CONTENT;
89     fmt->lindex = -1;
90     fmt->tymed = tymed;
91 }
92 
93 /***************************************************************************
94  *         get_storage
95  *
96  * Retrieve an object's storage from a variety of sources.
97  *
98  * FIXME: CF_FILENAME.
99  */
get_storage(IDataObject * data,IStorage * stg,UINT * src_cf,BOOL other_fmts)100 static HRESULT get_storage(IDataObject *data, IStorage *stg, UINT *src_cf, BOOL other_fmts)
101 {
102     static const UINT fmt_id[] = { CF_METAFILEPICT, CF_BITMAP, CF_DIB };
103     UINT i;
104     HRESULT hr;
105     FORMATETC fmt;
106     STGMEDIUM med;
107     IPersistStorage *persist;
108     CLSID clsid;
109 
110     if (src_cf) *src_cf = 0;
111 
112     /* CF_EMBEDEDOBJECT */
113     init_fmtetc(&fmt, embedded_object_clipboard_format, TYMED_ISTORAGE);
114     med.tymed = TYMED_ISTORAGE;
115     med.u.pstg = stg;
116     med.pUnkForRelease = NULL;
117     hr = IDataObject_GetDataHere(data, &fmt, &med);
118     if(SUCCEEDED(hr))
119     {
120         if (src_cf) *src_cf = embedded_object_clipboard_format;
121         return hr;
122     }
123 
124     /* CF_EMBEDSOURCE */
125     init_fmtetc(&fmt, embed_source_clipboard_format, TYMED_ISTORAGE);
126     med.tymed = TYMED_ISTORAGE;
127     med.u.pstg = stg;
128     med.pUnkForRelease = NULL;
129     hr = IDataObject_GetDataHere(data, &fmt, &med);
130     if(SUCCEEDED(hr))
131     {
132         if (src_cf) *src_cf = embed_source_clipboard_format;
133         return hr;
134     }
135 
136     if (other_fmts)
137     {
138         for (i = 0; i < ARRAY_SIZE(fmt_id); i++)
139         {
140             init_fmtetc(&fmt, fmt_id[i], TYMED_ISTORAGE);
141             hr = IDataObject_QueryGetData(data, &fmt);
142             if (SUCCEEDED(hr))
143             {
144                 if (src_cf) *src_cf = fmt_id[i];
145                 return hr;
146             }
147         }
148     }
149 
150     /* IPersistStorage */
151     hr = IDataObject_QueryInterface(data, &IID_IPersistStorage, (void**)&persist);
152     if(FAILED(hr)) return hr;
153 
154     hr = IPersistStorage_GetClassID(persist, &clsid);
155     if(FAILED(hr)) goto end;
156 
157     hr = IStorage_SetClass(stg, &clsid);
158     if(FAILED(hr)) goto end;
159 
160     hr = IPersistStorage_Save(persist, stg, FALSE);
161     if(FAILED(hr)) goto end;
162 
163     hr = IPersistStorage_SaveCompleted(persist, NULL);
164 
165 end:
166     IPersistStorage_Release(persist);
167 
168     return hr;
169 }
170 
171 /******************************************************************************
172  *		OleCreateFromDataEx        [OLE32.@]
173  *
174  * Creates an embedded object from data transfer object retrieved from
175  * the clipboard or OLE drag and drop.
176  */
OleCreateFromDataEx(IDataObject * data,REFIID iid,DWORD flags,DWORD renderopt,ULONG num_cache_fmts,DWORD * adv_flags,FORMATETC * cache_fmts,IAdviseSink * sink,DWORD * conns,IOleClientSite * client_site,IStorage * stg,void ** obj)177 HRESULT WINAPI OleCreateFromDataEx(IDataObject *data, REFIID iid, DWORD flags,
178                                    DWORD renderopt, ULONG num_cache_fmts, DWORD *adv_flags, FORMATETC *cache_fmts,
179                                    IAdviseSink *sink, DWORD *conns,
180                                    IOleClientSite *client_site, IStorage *stg, void **obj)
181 {
182     HRESULT hr;
183     UINT src_cf;
184 
185     FIXME("(%p, %s, %08x, %08x, %d, %p, %p, %p, %p, %p, %p, %p): stub\n",
186           data, debugstr_guid(iid), flags, renderopt, num_cache_fmts, adv_flags, cache_fmts,
187           sink, conns, client_site, stg, obj);
188 
189     hr = get_storage(data, stg, &src_cf, TRUE);
190     if(FAILED(hr)) return hr;
191 
192     hr = OleLoad(stg, iid, client_site, obj);
193     if(FAILED(hr)) return hr;
194 
195     /* FIXME: Init cache */
196 
197     return hr;
198 }
199 
200 /******************************************************************************
201  *		OleCreateFromData        [OLE32.@]
202  */
OleCreateFromData(LPDATAOBJECT data,REFIID iid,DWORD renderopt,LPFORMATETC fmt,LPOLECLIENTSITE client_site,LPSTORAGE stg,LPVOID * obj)203 HRESULT WINAPI OleCreateFromData(LPDATAOBJECT data, REFIID iid,
204                                  DWORD renderopt, LPFORMATETC fmt,
205                                  LPOLECLIENTSITE client_site, LPSTORAGE stg,
206                                  LPVOID* obj)
207 {
208     DWORD advf = ADVF_PRIMEFIRST;
209 
210     return OleCreateFromDataEx(data, iid, 0, renderopt, fmt ? 1 : 0, fmt ? &advf : NULL,
211                                fmt, NULL, NULL, client_site, stg, obj);
212 }
213 
214 /******************************************************************************
215  *              OleCreateLinkFromData        [OLE32.@]
216  */
OleCreateLinkFromData(IDataObject * data,REFIID iid,DWORD renderopt,FORMATETC * fmt,IOleClientSite * client_site,IStorage * stg,void ** obj)217 HRESULT WINAPI OleCreateLinkFromData(IDataObject *data, REFIID iid,
218                                      DWORD renderopt, FORMATETC *fmt,
219                                      IOleClientSite *client_site, IStorage *stg,
220                                      void **obj)
221 {
222     FIXME("%p,%s,%08x,%p,%p,%p,%p: semi-stub\n",
223           data, debugstr_guid(iid), renderopt, fmt, client_site, stg, obj);
224     return OleCreateFromData(data, iid, renderopt, fmt, client_site, stg, obj);
225 }
226 
227 /******************************************************************************
228  *              OleCreateStaticFromData        [OLE32.@]
229  */
OleCreateStaticFromData(IDataObject * data,REFIID iid,DWORD renderopt,FORMATETC * fmt,IOleClientSite * client_site,IStorage * stg,void ** obj)230 HRESULT WINAPI OleCreateStaticFromData(IDataObject *data, REFIID iid,
231                                        DWORD renderopt, FORMATETC *fmt,
232                                        IOleClientSite *client_site, IStorage *stg,
233                                        void **obj)
234 {
235     HRESULT hr;
236     CLSID clsid;
237     IOleObject * ole_object = NULL;
238     IOleCache2 *ole_cache = NULL;
239     IPersistStorage *persist = NULL;
240     DWORD connection;
241     STGMEDIUM stgmedium;
242     LPOLESTR ole_typename;
243 
244     TRACE("(%p, %s, 0x%08x, %p, %p, %p, %p)\n",
245           data, debugstr_guid(iid), renderopt, fmt, client_site, stg, obj);
246 
247     if (!obj || !stg)
248         return E_INVALIDARG;
249 
250     if (renderopt != OLERENDER_FORMAT)
251     {
252         FIXME("semi-stub\n");
253         return OleCreateFromData(data, iid, renderopt, fmt, client_site, stg, obj);
254     }
255 
256     if (!fmt)
257         return E_INVALIDARG;
258 
259     hr = IDataObject_GetData(data, fmt, &stgmedium);
260     if (FAILED(hr)) return hr;
261 
262     switch (fmt->cfFormat)
263     {
264         case CF_BITMAP:
265         case CF_DIB:
266             clsid = CLSID_Picture_Dib;
267             break;
268         case CF_ENHMETAFILE:
269             clsid = CLSID_Picture_EnhMetafile;
270             break;
271         case CF_METAFILEPICT:
272             clsid = CLSID_Picture_Metafile;
273             break;
274         default:
275             ReleaseStgMedium(&stgmedium);
276             return DV_E_CLIPFORMAT;
277     }
278     hr = OleCreateDefaultHandler(&clsid, NULL, &IID_IOleObject, (void **)&ole_object);
279     if (FAILED(hr)) goto end;
280 
281     if (client_site)
282     {
283         hr = IOleObject_SetClientSite(ole_object, client_site);
284         if (FAILED(hr)) goto end;
285     }
286 
287     hr = IOleObject_QueryInterface(ole_object, &IID_IOleCache2, (void **)&ole_cache);
288     if (FAILED(hr)) goto end;
289 
290     hr = IOleObject_QueryInterface(ole_object, &IID_IPersistStorage, (void **)&persist);
291     if (FAILED(hr)) goto end;
292 
293     hr = WriteClassStg(stg, &clsid);
294     if (FAILED(hr)) goto end;
295 
296     hr = IPersistStorage_InitNew(persist, stg);
297     if (FAILED(hr)) goto end;
298 
299     hr = IOleCache2_Cache(ole_cache, fmt, ADVF_PRIMEFIRST, &connection);
300     if (FAILED(hr)) goto end;
301 
302     hr = IOleCache2_SetData(ole_cache, fmt, &stgmedium, TRUE);
303     if (FAILED(hr)) goto end;
304     stgmedium.tymed = TYMED_NULL;
305 
306     hr = IOleObject_GetUserType(ole_object, USERCLASSTYPE_FULL, &ole_typename);
307     if(FAILED(hr))
308         ole_typename = NULL;
309     hr = WriteFmtUserTypeStg(stg, fmt->cfFormat, ole_typename);
310     CoTaskMemFree(ole_typename);
311     if (FAILED(hr)) goto end;
312 
313     hr = IPersistStorage_Save(persist, stg, TRUE);
314     if (FAILED(hr)) goto end;
315 
316     hr = IPersistStorage_SaveCompleted(persist, NULL);
317     if (FAILED(hr)) goto end;
318 
319     hr = IOleObject_QueryInterface(ole_object, iid, obj);
320 
321 end:
322     if (stgmedium.tymed == TYMED_NULL)
323         ReleaseStgMedium(&stgmedium);
324     if (persist)
325         IPersistStorage_Release(persist);
326     if (ole_cache)
327         IOleCache2_Release(ole_cache);
328     if (ole_object)
329         IOleObject_Release(ole_object);
330     return hr;
331 }
332 
333 /******************************************************************************
334  *              OleCreateFromFileEx        [OLE32.@]
335  */
OleCreateFromFileEx(REFCLSID clsid,const OLECHAR * filename,REFIID iid,DWORD flags,DWORD renderopt,ULONG num_fmts,DWORD * adv_flags,FORMATETC * fmts,IAdviseSink * sink,DWORD * conns,IOleClientSite * client_site,IStorage * stg,void ** obj)336 HRESULT WINAPI OleCreateFromFileEx(REFCLSID clsid, const OLECHAR *filename, REFIID iid, DWORD flags,
337                                    DWORD renderopt, ULONG num_fmts, DWORD *adv_flags, FORMATETC *fmts, IAdviseSink *sink,
338                                    DWORD *conns, IOleClientSite *client_site, IStorage *stg, void **obj)
339 {
340     HRESULT hr;
341     IMoniker *mon;
342     IDataObject *data;
343     IUnknown *unk = NULL;
344     IOleCache *cache = NULL;
345     ULONG i;
346 
347     TRACE("cls %s, %s, iid %s, flags %d, render opts %d, num fmts %d, adv flags %p, fmts %p\n", debugstr_guid(clsid),
348           debugstr_w(filename), debugstr_guid(iid), flags, renderopt, num_fmts, adv_flags, fmts);
349     TRACE("sink %p, conns %p, client site %p, storage %p, obj %p\n", sink, conns, client_site, stg, obj);
350     for (i = 0; i < num_fmts; i++)
351         TRACE("\t%d: fmt %s adv flags %d\n", i, debugstr_formatetc(fmts + i), adv_flags[i]);
352 
353     hr = CreateFileMoniker( filename, &mon );
354     if (FAILED(hr)) return hr;
355 
356     hr = BindMoniker( mon, 0, &IID_IDataObject, (void**)&data );
357     IMoniker_Release( mon );
358     if (FAILED(hr)) return hr;
359 
360     hr = get_storage( data, stg, NULL, FALSE );
361     if (FAILED(hr)) goto end;
362 
363     hr = OleLoad( stg, &IID_IUnknown, client_site, (void**)&unk );
364     if (FAILED(hr)) goto end;
365 
366     if (renderopt == OLERENDER_FORMAT)
367     {
368         hr = IUnknown_QueryInterface( unk, &IID_IOleCache, (void**)&cache );
369         if (FAILED(hr)) goto end;
370 
371         for (i = 0; i < num_fmts; i++)
372         {
373             STGMEDIUM med;
374             DWORD dummy_conn;
375 
376             memset( &med, 0, sizeof(med) );
377             hr = IDataObject_GetData( data, fmts + i, &med );
378             if (FAILED(hr)) goto end;
379             hr = IOleCache_Cache( cache, fmts + i, adv_flags[i], &dummy_conn );
380             if (SUCCEEDED(hr))
381                 hr = IOleCache_SetData( cache, fmts + i, &med, TRUE );
382             if (FAILED(hr))
383             {
384                 ReleaseStgMedium( &med );
385                 goto end;
386             }
387         }
388     }
389 
390     hr = IUnknown_QueryInterface( unk, iid, obj );
391 
392 end:
393     if (cache) IOleCache_Release( cache );
394     if (unk) IUnknown_Release( unk );
395     IDataObject_Release( data );
396     return hr;
397 }
398 
399 /******************************************************************************
400  *              OleCreateFromFile        [OLE32.@]
401  */
OleCreateFromFile(REFCLSID clsid,const OLECHAR * filename,REFIID iid,DWORD renderopt,FORMATETC * fmt,IOleClientSite * client_site,IStorage * storage,void ** obj)402 HRESULT WINAPI OleCreateFromFile(REFCLSID clsid, const OLECHAR *filename, REFIID iid, DWORD renderopt,
403                                  FORMATETC *fmt, IOleClientSite *client_site, IStorage *storage, void **obj)
404 {
405     DWORD advf = ADVF_PRIMEFIRST;
406 
407     return OleCreateFromFileEx(clsid, filename, iid, 0, renderopt, fmt ? 1 : 0, fmt ? &advf : NULL, fmt,
408                                NULL, NULL, client_site, storage, obj);
409 }
410 
411 /******************************************************************************
412  *              OleDuplicateData        [OLE32.@]
413  *
414  * Duplicates clipboard data.
415  *
416  * PARAMS
417  *  hSrc     [I] Handle of the source clipboard data.
418  *  cfFormat [I] The clipboard format of hSrc.
419  *  uiFlags  [I] Flags to pass to GlobalAlloc.
420  *
421  * RETURNS
422  *  Success: handle to the duplicated data.
423  *  Failure: NULL.
424  */
OleDuplicateData(HANDLE hSrc,CLIPFORMAT cfFormat,UINT uiFlags)425 HANDLE WINAPI OleDuplicateData(HANDLE hSrc, CLIPFORMAT cfFormat,
426 	                          UINT uiFlags)
427 {
428     HANDLE hDst = NULL;
429 
430     TRACE("(%p,%x,%x)\n", hSrc, cfFormat, uiFlags);
431 
432     if (!uiFlags) uiFlags = GMEM_MOVEABLE;
433 
434     switch (cfFormat)
435     {
436     case CF_ENHMETAFILE:
437         hDst = CopyEnhMetaFileW(hSrc, NULL);
438         break;
439     case CF_METAFILEPICT:
440         hDst = CopyMetaFileW(hSrc, NULL);
441         break;
442     case CF_PALETTE:
443         {
444             LOGPALETTE * logpalette;
445             UINT nEntries = GetPaletteEntries(hSrc, 0, 0, NULL);
446             if (!nEntries) return NULL;
447             logpalette = HeapAlloc(GetProcessHeap(), 0,
448                 FIELD_OFFSET(LOGPALETTE, palPalEntry[nEntries]));
449             if (!logpalette) return NULL;
450             if (!GetPaletteEntries(hSrc, 0, nEntries, logpalette->palPalEntry))
451             {
452                 HeapFree(GetProcessHeap(), 0, logpalette);
453                 return NULL;
454             }
455             logpalette->palVersion = 0x300;
456             logpalette->palNumEntries = (WORD)nEntries;
457 
458             hDst = CreatePalette(logpalette);
459 
460             HeapFree(GetProcessHeap(), 0, logpalette);
461             break;
462         }
463     case CF_BITMAP:
464         {
465             LONG size;
466             BITMAP bm;
467             if (!GetObjectW(hSrc, sizeof(bm), &bm))
468                 return NULL;
469             size = GetBitmapBits(hSrc, 0, NULL);
470             if (!size) return NULL;
471             bm.bmBits = HeapAlloc(GetProcessHeap(), 0, size);
472             if (!bm.bmBits) return NULL;
473             if (GetBitmapBits(hSrc, size, bm.bmBits))
474                 hDst = CreateBitmapIndirect(&bm);
475             HeapFree(GetProcessHeap(), 0, bm.bmBits);
476             break;
477         }
478     default:
479         {
480             SIZE_T size = GlobalSize(hSrc);
481             LPVOID pvSrc = NULL;
482             LPVOID pvDst = NULL;
483 
484             /* allocate space for object */
485             if (!size) return NULL;
486             hDst = GlobalAlloc(uiFlags, size);
487             if (!hDst) return NULL;
488 
489             /* lock pointers */
490             pvSrc = GlobalLock(hSrc);
491             if (!pvSrc)
492             {
493                 GlobalFree(hDst);
494                 return NULL;
495             }
496             pvDst = GlobalLock(hDst);
497             if (!pvDst)
498             {
499                 GlobalUnlock(hSrc);
500                 GlobalFree(hDst);
501                 return NULL;
502             }
503             /* copy data */
504             memcpy(pvDst, pvSrc, size);
505 
506             /* cleanup */
507             GlobalUnlock(hDst);
508             GlobalUnlock(hSrc);
509         }
510     }
511 
512     TRACE("returning %p\n", hDst);
513     return hDst;
514 }
515