gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / ole32 / classmoniker.c
blob4b95f577b84682f281aa3beb3ab5bcf3cf428896
1 /*
2 * Class Monikers
4 * Copyright 1999 Noomen Hamza
5 * Copyright 2005-2007 Robert Shearman
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <string.h>
26 #define COBJMACROS
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "wine/debug.h"
33 #include "ole2.h"
34 #include "moniker.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 #define CHARS_IN_GUID 39
40 /* ClassMoniker data structure */
41 typedef struct ClassMoniker
43 IMoniker IMoniker_iface;
44 IROTData IROTData_iface;
45 LONG ref;
47 struct
49 CLSID clsid;
50 DWORD data_len;
51 } header;
52 WCHAR *data;
54 IUnknown *pMarshal; /* custom marshaler */
55 } ClassMoniker;
57 static inline ClassMoniker *impl_from_IMoniker(IMoniker *iface)
59 return CONTAINING_RECORD(iface, ClassMoniker, IMoniker_iface);
62 static inline ClassMoniker *impl_from_IROTData(IROTData *iface)
64 return CONTAINING_RECORD(iface, ClassMoniker, IROTData_iface);
67 static const IMonikerVtbl ClassMonikerVtbl;
69 static ClassMoniker *unsafe_impl_from_IMoniker(IMoniker *iface)
71 if (iface->lpVtbl != &ClassMonikerVtbl)
72 return NULL;
73 return CONTAINING_RECORD(iface, ClassMoniker, IMoniker_iface);
76 /*******************************************************************************
77 * ClassMoniker_QueryInterface
78 *******************************************************************************/
79 static HRESULT WINAPI ClassMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppvObject)
81 ClassMoniker *This = impl_from_IMoniker(iface);
83 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppvObject);
85 if (!ppvObject)
86 return E_POINTER;
88 *ppvObject = 0;
90 if (IsEqualIID(&IID_IUnknown, riid) ||
91 IsEqualIID(&IID_IPersist, riid) ||
92 IsEqualIID(&IID_IPersistStream, riid) ||
93 IsEqualIID(&IID_IMoniker, riid) ||
94 IsEqualGUID(&CLSID_ClassMoniker, riid))
96 *ppvObject = iface;
98 else if (IsEqualIID(&IID_IROTData, riid))
99 *ppvObject = &This->IROTData_iface;
100 else if (IsEqualIID(&IID_IMarshal, riid))
102 HRESULT hr = S_OK;
103 if (!This->pMarshal)
104 hr = MonikerMarshal_Create(iface, &This->pMarshal);
105 if (hr != S_OK)
106 return hr;
107 return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
110 if (!*ppvObject)
111 return E_NOINTERFACE;
113 IMoniker_AddRef(iface);
115 return S_OK;
118 /******************************************************************************
119 * ClassMoniker_AddRef
120 ******************************************************************************/
121 static ULONG WINAPI ClassMoniker_AddRef(IMoniker* iface)
123 ClassMoniker *This = impl_from_IMoniker(iface);
125 TRACE("(%p)\n",This);
127 return InterlockedIncrement(&This->ref);
130 static ULONG WINAPI ClassMoniker_Release(IMoniker* iface)
132 ClassMoniker *moniker = impl_from_IMoniker(iface);
133 ULONG ref = InterlockedDecrement(&moniker->ref);
135 TRACE("%p, refcount %lu.\n", iface, ref);
137 if (!ref)
139 if (moniker->pMarshal) IUnknown_Release(moniker->pMarshal);
140 free(moniker->data);
141 free(moniker);
144 return ref;
147 /******************************************************************************
148 * ClassMoniker_GetClassID
149 ******************************************************************************/
150 static HRESULT WINAPI ClassMoniker_GetClassID(IMoniker* iface,CLSID *pClassID)
152 TRACE("(%p, %p)\n", iface, pClassID);
154 if (pClassID==NULL)
155 return E_POINTER;
157 *pClassID = CLSID_ClassMoniker;
159 return S_OK;
162 /******************************************************************************
163 * ClassMoniker_IsDirty
164 ******************************************************************************/
165 static HRESULT WINAPI ClassMoniker_IsDirty(IMoniker* iface)
167 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
168 method in the OLE-provided moniker interfaces always return S_FALSE because
169 their internal state never changes. */
171 TRACE("(%p)\n",iface);
173 return S_FALSE;
176 static HRESULT WINAPI ClassMoniker_Load(IMoniker *iface, IStream *stream)
178 ClassMoniker *moniker = impl_from_IMoniker(iface);
179 ULONG length;
180 HRESULT hr;
182 TRACE("%p, %p\n", iface, stream);
184 hr = IStream_Read(stream, &moniker->header, sizeof(moniker->header), &length);
185 if (hr != S_OK || length != sizeof(moniker->header)) return STG_E_READFAULT;
187 if (moniker->header.data_len)
189 free(moniker->data);
190 if (!(moniker->data = malloc(moniker->header.data_len)))
192 WARN("Failed to allocate moniker data of size %lu.\n", moniker->header.data_len);
193 moniker->header.data_len = 0;
194 return E_OUTOFMEMORY;
196 hr = IStream_Read(stream, moniker->data, moniker->header.data_len, &length);
197 if (hr != S_OK || length != moniker->header.data_len) return STG_E_READFAULT;
200 return S_OK;
203 static HRESULT WINAPI ClassMoniker_Save(IMoniker *iface, IStream *stream, BOOL clear_dirty)
205 ClassMoniker *moniker = impl_from_IMoniker(iface);
206 HRESULT hr;
208 TRACE("%p, %p, %d\n", iface, stream, clear_dirty);
210 hr = IStream_Write(stream, &moniker->header, sizeof(moniker->header), NULL);
212 if (SUCCEEDED(hr) && moniker->header.data_len)
213 hr = IStream_Write(stream, moniker->data, moniker->header.data_len, NULL);
215 return hr;
218 static HRESULT WINAPI ClassMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *size)
220 ClassMoniker *moniker = impl_from_IMoniker(iface);
222 TRACE("%p, %p\n", iface, size);
224 size->QuadPart = sizeof(moniker->header) + moniker->header.data_len;
226 return S_OK;
229 /******************************************************************************
230 * ClassMoniker_BindToObject
231 ******************************************************************************/
232 static HRESULT WINAPI ClassMoniker_BindToObject(IMoniker* iface,
233 IBindCtx* pbc,
234 IMoniker* pmkToLeft,
235 REFIID riid,
236 VOID** ppvResult)
238 ClassMoniker *moniker = impl_from_IMoniker(iface);
239 BIND_OPTS2 bindopts;
240 IClassActivator *pActivator;
241 HRESULT hr;
243 TRACE("(%p, %p, %s, %p)\n", pbc, pmkToLeft, debugstr_guid(riid), ppvResult);
245 bindopts.cbStruct = sizeof(bindopts);
246 IBindCtx_GetBindOptions(pbc, (BIND_OPTS *)&bindopts);
248 if (!pmkToLeft)
249 return CoGetClassObject(&moniker->header.clsid, bindopts.dwClassContext, NULL,
250 riid, ppvResult);
251 else
253 hr = IMoniker_BindToObject(pmkToLeft, pbc, NULL, &IID_IClassActivator,
254 (void **)&pActivator);
255 if (FAILED(hr)) return hr;
257 hr = IClassActivator_GetClassObject(pActivator, &moniker->header.clsid,
258 bindopts.dwClassContext,
259 bindopts.locale, riid, ppvResult);
261 IClassActivator_Release(pActivator);
263 return hr;
267 /******************************************************************************
268 * ClassMoniker_BindToStorage
269 ******************************************************************************/
270 static HRESULT WINAPI ClassMoniker_BindToStorage(IMoniker* iface,
271 IBindCtx* pbc,
272 IMoniker* pmkToLeft,
273 REFIID riid,
274 VOID** ppvResult)
276 TRACE("(%p, %p, %s, %p)\n", pbc, pmkToLeft, debugstr_guid(riid), ppvResult);
277 return IMoniker_BindToObject(iface, pbc, pmkToLeft, riid, ppvResult);
280 static HRESULT WINAPI ClassMoniker_Reduce(IMoniker* iface, IBindCtx *pbc,
281 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
283 TRACE("%p, %p, %ld, %p, %p.\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
285 if (!ppmkReduced)
286 return E_POINTER;
288 IMoniker_AddRef(iface);
290 *ppmkReduced = iface;
292 return MK_S_REDUCED_TO_SELF;
295 static HRESULT WINAPI ClassMoniker_ComposeWith(IMoniker *iface, IMoniker *right,
296 BOOL only_if_not_generic, IMoniker **result)
298 DWORD order;
300 TRACE("%p, %p, %d, %p.\n", iface, right, only_if_not_generic, result);
302 if (!result || !right)
303 return E_POINTER;
305 *result = NULL;
307 if (is_anti_moniker(right, &order))
308 return S_OK;
310 return only_if_not_generic ? MK_E_NEEDGENERIC : CreateGenericComposite(iface, right, result);
313 /******************************************************************************
314 * ClassMoniker_Enum
315 ******************************************************************************/
316 static HRESULT WINAPI ClassMoniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
318 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
320 if (ppenumMoniker == NULL)
321 return E_POINTER;
323 *ppenumMoniker = NULL;
325 return S_OK;
328 static HRESULT WINAPI ClassMoniker_IsEqual(IMoniker *iface, IMoniker *other)
330 ClassMoniker *moniker = impl_from_IMoniker(iface), *other_moniker;
332 TRACE("%p, %p.\n", iface, other);
334 if (!other)
335 return E_INVALIDARG;
337 other_moniker = unsafe_impl_from_IMoniker(other);
338 if (!other_moniker)
339 return S_FALSE;
341 return IsEqualGUID(&moniker->header.clsid, &other_moniker->header.clsid) ? S_OK : S_FALSE;
344 static HRESULT WINAPI ClassMoniker_Hash(IMoniker *iface, DWORD *hash)
346 ClassMoniker *moniker = impl_from_IMoniker(iface);
348 TRACE("%p, %p\n", iface, hash);
350 *hash = moniker->header.clsid.Data1;
352 return S_OK;
355 /******************************************************************************
356 * ClassMoniker_IsRunning
357 ******************************************************************************/
358 static HRESULT WINAPI ClassMoniker_IsRunning(IMoniker* iface,
359 IBindCtx* pbc,
360 IMoniker* pmkToLeft,
361 IMoniker* pmkNewlyRunning)
363 TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pmkNewlyRunning);
365 /* as in native */
366 return E_NOTIMPL;
369 /******************************************************************************
370 * ClassMoniker_GetTimeOfLastChange
371 ******************************************************************************/
372 static HRESULT WINAPI ClassMoniker_GetTimeOfLastChange(IMoniker* iface,
373 IBindCtx* pbc,
374 IMoniker* pmkToLeft,
375 FILETIME* pItemTime)
377 TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pItemTime);
379 return MK_E_UNAVAILABLE;
382 /******************************************************************************
383 * ClassMoniker_Inverse
384 ******************************************************************************/
385 static HRESULT WINAPI ClassMoniker_Inverse(IMoniker* iface,IMoniker** ppmk)
387 TRACE("(%p)\n",ppmk);
389 if (!ppmk)
390 return E_POINTER;
392 return CreateAntiMoniker(ppmk);
395 static HRESULT WINAPI ClassMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *other, IMoniker **prefix)
397 ClassMoniker *moniker = impl_from_IMoniker(iface), *other_moniker;
399 TRACE("%p, %p, %p\n", iface, other, prefix);
401 *prefix = NULL;
403 other_moniker = unsafe_impl_from_IMoniker(other);
405 if (other_moniker)
407 if (!IsEqualGUID(&moniker->header.clsid, &other_moniker->header.clsid)) return MK_E_NOPREFIX;
409 *prefix = iface;
410 IMoniker_AddRef(iface);
412 return MK_S_US;
415 return MonikerCommonPrefixWith(iface, other, prefix);
418 /******************************************************************************
419 * ClassMoniker_RelativePathTo
420 ******************************************************************************/
421 static HRESULT WINAPI ClassMoniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
423 TRACE("(%p, %p)\n",pmOther,ppmkRelPath);
425 if (!ppmkRelPath)
426 return E_POINTER;
428 *ppmkRelPath = NULL;
430 return MK_E_NOTBINDABLE;
433 static HRESULT WINAPI ClassMoniker_GetDisplayName(IMoniker *iface,
434 IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *name)
436 ClassMoniker *moniker = impl_from_IMoniker(iface);
437 static const int name_len = CHARS_IN_GUID + 5 /* prefix */;
438 const GUID *guid = &moniker->header.clsid;
440 TRACE("%p, %p, %p, %p.\n", iface, pbc, pmkToLeft, name);
442 if (!name)
443 return E_POINTER;
445 if (pmkToLeft)
446 return E_INVALIDARG;
448 if (!(*name = CoTaskMemAlloc(name_len * sizeof(WCHAR) + moniker->header.data_len)))
449 return E_OUTOFMEMORY;
451 swprintf(*name, name_len, L"clsid:%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
452 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
453 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
455 if (moniker->header.data_len)
456 lstrcatW(*name, moniker->data);
457 lstrcatW(*name, L":");
459 TRACE("Returning %s\n", debugstr_w(*name));
461 return S_OK;
464 static HRESULT WINAPI ClassMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
465 IMoniker *pmkToLeft, LPOLESTR display_name, ULONG *eaten, IMoniker **result)
467 IParseDisplayName *parser;
468 HRESULT hr;
470 TRACE("%p, %p, %p, %s, %p, %p\n", iface, pbc, pmkToLeft, debugstr_w(display_name), eaten, result);
472 if (SUCCEEDED(hr = IMoniker_BindToObject(iface, pbc, pmkToLeft, &IID_IParseDisplayName, (void **)&parser)))
474 hr = IParseDisplayName_ParseDisplayName(parser, pbc, display_name, eaten, result);
475 IParseDisplayName_Release(parser);
478 return hr;
481 /******************************************************************************
482 * ClassMoniker_IsSystemMoniker
483 ******************************************************************************/
484 static HRESULT WINAPI ClassMoniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
486 TRACE("(%p,%p)\n",iface,pwdMksys);
488 if (!pwdMksys)
489 return E_POINTER;
491 *pwdMksys = MKSYS_CLASSMONIKER;
493 return S_OK;
496 /*******************************************************************************
497 * ClassMonikerIROTData_QueryInterface
498 *******************************************************************************/
499 static HRESULT WINAPI ClassMonikerROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
502 ClassMoniker *This = impl_from_IROTData(iface);
504 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
506 return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
509 /***********************************************************************
510 * ClassMonikerIROTData_AddRef
512 static ULONG WINAPI ClassMonikerROTData_AddRef(IROTData *iface)
514 ClassMoniker *This = impl_from_IROTData(iface);
516 TRACE("(%p)\n",iface);
518 return IMoniker_AddRef(&This->IMoniker_iface);
521 /***********************************************************************
522 * ClassMonikerIROTData_Release
524 static ULONG WINAPI ClassMonikerROTData_Release(IROTData* iface)
526 ClassMoniker *This = impl_from_IROTData(iface);
528 TRACE("(%p)\n",iface);
530 return IMoniker_Release(&This->IMoniker_iface);
533 /******************************************************************************
534 * ClassMonikerIROTData_GetComparisonData
535 ******************************************************************************/
536 static HRESULT WINAPI ClassMonikerROTData_GetComparisonData(IROTData* iface,
537 BYTE* pbData,
538 ULONG cbMax,
539 ULONG* pcbData)
541 ClassMoniker *This = impl_from_IROTData(iface);
543 TRACE("%p, %p, %lu, %p.\n", iface, pbData, cbMax, pcbData);
545 *pcbData = 2*sizeof(CLSID);
546 if (cbMax < *pcbData)
547 return E_OUTOFMEMORY;
549 /* write CLSID of the moniker */
550 memcpy(pbData, &CLSID_ClassMoniker, sizeof(CLSID));
551 /* write CLSID the moniker represents */
552 memcpy(pbData+sizeof(CLSID), &This->header.clsid, sizeof(CLSID));
554 return S_OK;
557 static const IMonikerVtbl ClassMonikerVtbl =
559 ClassMoniker_QueryInterface,
560 ClassMoniker_AddRef,
561 ClassMoniker_Release,
562 ClassMoniker_GetClassID,
563 ClassMoniker_IsDirty,
564 ClassMoniker_Load,
565 ClassMoniker_Save,
566 ClassMoniker_GetSizeMax,
567 ClassMoniker_BindToObject,
568 ClassMoniker_BindToStorage,
569 ClassMoniker_Reduce,
570 ClassMoniker_ComposeWith,
571 ClassMoniker_Enum,
572 ClassMoniker_IsEqual,
573 ClassMoniker_Hash,
574 ClassMoniker_IsRunning,
575 ClassMoniker_GetTimeOfLastChange,
576 ClassMoniker_Inverse,
577 ClassMoniker_CommonPrefixWith,
578 ClassMoniker_RelativePathTo,
579 ClassMoniker_GetDisplayName,
580 ClassMoniker_ParseDisplayName,
581 ClassMoniker_IsSystemMoniker
584 /********************************************************************************/
585 /* Virtual function table for the IROTData class. */
586 static const IROTDataVtbl ROTDataVtbl =
588 ClassMonikerROTData_QueryInterface,
589 ClassMonikerROTData_AddRef,
590 ClassMonikerROTData_Release,
591 ClassMonikerROTData_GetComparisonData
594 static HRESULT create_class_moniker(const CLSID *clsid, const WCHAR *data,
595 unsigned int data_len, IMoniker **moniker)
597 ClassMoniker *object;
599 if (!(object = calloc(1, sizeof(*object))))
600 return E_OUTOFMEMORY;
602 object->IMoniker_iface.lpVtbl = &ClassMonikerVtbl;
603 object->IROTData_iface.lpVtbl = &ROTDataVtbl;
604 object->ref = 1;
605 object->header.clsid = *clsid;
606 if (data_len)
608 object->header.data_len = (data_len + 1) * sizeof(WCHAR);
610 if (!(object->data = malloc(object->header.data_len)))
612 IMoniker_Release(&object->IMoniker_iface);
613 return E_OUTOFMEMORY;
615 memcpy(object->data, data, data_len * sizeof(WCHAR));
616 object->data[data_len] = 0;
619 *moniker = &object->IMoniker_iface;
621 return S_OK;
624 /******************************************************************************
625 * CreateClassMoniker [OLE32.@]
626 ******************************************************************************/
627 HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **moniker)
629 TRACE("%s, %p\n", debugstr_guid(rclsid), moniker);
631 return create_class_moniker(rclsid, NULL, 0, moniker);
634 HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, const WCHAR *display_name,
635 DWORD *eaten, IMoniker **moniker)
637 const WCHAR *end, *s;
638 BOOL has_braces;
639 WCHAR uuid[37];
640 CLSID clsid;
641 HRESULT hr;
642 int len;
644 s = display_name;
646 /* Skip prefix */
647 if (wcsnicmp(s, L"clsid:", 6)) return MK_E_SYNTAX;
648 s += 6;
650 /* Terminating marker is optional */
651 if (!(end = wcschr(s, ':')))
652 end = s + lstrlenW(s);
654 len = end - s;
655 if (len < 36)
656 return MK_E_SYNTAX;
658 if ((has_braces = *s == '{')) s++;
660 memcpy(uuid, s, 36 * sizeof(WCHAR));
661 uuid[36] = 0;
663 if (UuidFromStringW(uuid, &clsid))
665 WARN("Failed to parse clsid string.\n");
666 return MK_E_SYNTAX;
669 s += 36;
670 if (has_braces)
672 if (*s != '}') return MK_E_SYNTAX;
673 s++;
676 /* Consume terminal marker */
677 len = end - s;
678 if (*end == ':') end++;
680 hr = create_class_moniker(&clsid, len ? s : NULL, len, moniker);
681 if (SUCCEEDED(hr))
682 *eaten = end - display_name;
683 return hr;
686 HRESULT WINAPI ClassMoniker_CreateInstance(IClassFactory *iface,
687 IUnknown *pUnk, REFIID riid, void **ppv)
689 HRESULT hr;
690 IMoniker *pmk;
692 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
694 *ppv = NULL;
696 if (pUnk)
697 return CLASS_E_NOAGGREGATION;
699 hr = CreateClassMoniker(&CLSID_NULL, &pmk);
700 if (FAILED(hr)) return hr;
702 hr = IMoniker_QueryInterface(pmk, riid, ppv);
703 IMoniker_Release(pmk);
705 return hr;