kernelbase: Ignore URL_PARTFLAG_KEEPSCHEME when used with URL_PART_SCHEME or URL_PART...
[wine.git] / dlls / ole32 / classmoniker.c
blob6199a5a5182d62d47a3e232e7cb8b0dd8b4b0535
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 "wine/heap.h"
34 #include "ole2.h"
35 #include "moniker.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 #define CHARS_IN_GUID 39
41 /* ClassMoniker data structure */
42 typedef struct ClassMoniker
44 IMoniker IMoniker_iface;
45 IROTData IROTData_iface;
46 LONG ref;
48 struct
50 CLSID clsid;
51 DWORD data_len;
52 } header;
53 WCHAR *data;
55 IUnknown *pMarshal; /* custom marshaler */
56 } ClassMoniker;
58 static inline ClassMoniker *impl_from_IMoniker(IMoniker *iface)
60 return CONTAINING_RECORD(iface, ClassMoniker, IMoniker_iface);
63 static inline ClassMoniker *impl_from_IROTData(IROTData *iface)
65 return CONTAINING_RECORD(iface, ClassMoniker, IROTData_iface);
68 static const IMonikerVtbl ClassMonikerVtbl;
70 static ClassMoniker *unsafe_impl_from_IMoniker(IMoniker *iface)
72 if (iface->lpVtbl != &ClassMonikerVtbl)
73 return NULL;
74 return CONTAINING_RECORD(iface, ClassMoniker, IMoniker_iface);
77 /*******************************************************************************
78 * ClassMoniker_QueryInterface
79 *******************************************************************************/
80 static HRESULT WINAPI ClassMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppvObject)
82 ClassMoniker *This = impl_from_IMoniker(iface);
84 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppvObject);
86 if (!ppvObject)
87 return E_POINTER;
89 *ppvObject = 0;
91 if (IsEqualIID(&IID_IUnknown, riid) ||
92 IsEqualIID(&IID_IPersist, riid) ||
93 IsEqualIID(&IID_IPersistStream, riid) ||
94 IsEqualIID(&IID_IMoniker, riid) ||
95 IsEqualGUID(&CLSID_ClassMoniker, riid))
97 *ppvObject = iface;
99 else if (IsEqualIID(&IID_IROTData, riid))
100 *ppvObject = &This->IROTData_iface;
101 else if (IsEqualIID(&IID_IMarshal, riid))
103 HRESULT hr = S_OK;
104 if (!This->pMarshal)
105 hr = MonikerMarshal_Create(iface, &This->pMarshal);
106 if (hr != S_OK)
107 return hr;
108 return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
111 if (!*ppvObject)
112 return E_NOINTERFACE;
114 IMoniker_AddRef(iface);
116 return S_OK;
119 /******************************************************************************
120 * ClassMoniker_AddRef
121 ******************************************************************************/
122 static ULONG WINAPI ClassMoniker_AddRef(IMoniker* iface)
124 ClassMoniker *This = impl_from_IMoniker(iface);
126 TRACE("(%p)\n",This);
128 return InterlockedIncrement(&This->ref);
131 static ULONG WINAPI ClassMoniker_Release(IMoniker* iface)
133 ClassMoniker *moniker = impl_from_IMoniker(iface);
134 ULONG ref = InterlockedDecrement(&moniker->ref);
136 TRACE("%p, refcount %lu.\n", iface, ref);
138 if (!ref)
140 if (moniker->pMarshal) IUnknown_Release(moniker->pMarshal);
141 heap_free(moniker->data);
142 heap_free(moniker);
145 return ref;
148 /******************************************************************************
149 * ClassMoniker_GetClassID
150 ******************************************************************************/
151 static HRESULT WINAPI ClassMoniker_GetClassID(IMoniker* iface,CLSID *pClassID)
153 TRACE("(%p, %p)\n", iface, pClassID);
155 if (pClassID==NULL)
156 return E_POINTER;
158 *pClassID = CLSID_ClassMoniker;
160 return S_OK;
163 /******************************************************************************
164 * ClassMoniker_IsDirty
165 ******************************************************************************/
166 static HRESULT WINAPI ClassMoniker_IsDirty(IMoniker* iface)
168 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
169 method in the OLE-provided moniker interfaces always return S_FALSE because
170 their internal state never changes. */
172 TRACE("(%p)\n",iface);
174 return S_FALSE;
177 static HRESULT WINAPI ClassMoniker_Load(IMoniker *iface, IStream *stream)
179 ClassMoniker *moniker = impl_from_IMoniker(iface);
180 ULONG length;
181 HRESULT hr;
183 TRACE("%p, %p\n", iface, stream);
185 hr = IStream_Read(stream, &moniker->header, sizeof(moniker->header), &length);
186 if (hr != S_OK || length != sizeof(moniker->header)) return STG_E_READFAULT;
188 if (moniker->header.data_len)
190 heap_free(moniker->data);
191 if (!(moniker->data = heap_alloc(moniker->header.data_len)))
193 WARN("Failed to allocate moniker data of size %lu.\n", moniker->header.data_len);
194 moniker->header.data_len = 0;
195 return E_OUTOFMEMORY;
197 hr = IStream_Read(stream, moniker->data, moniker->header.data_len, &length);
198 if (hr != S_OK || length != moniker->header.data_len) return STG_E_READFAULT;
201 return S_OK;
204 static HRESULT WINAPI ClassMoniker_Save(IMoniker *iface, IStream *stream, BOOL clear_dirty)
206 ClassMoniker *moniker = impl_from_IMoniker(iface);
207 HRESULT hr;
209 TRACE("%p, %p, %d\n", iface, stream, clear_dirty);
211 hr = IStream_Write(stream, &moniker->header, sizeof(moniker->header), NULL);
213 if (SUCCEEDED(hr) && moniker->header.data_len)
214 hr = IStream_Write(stream, moniker->data, moniker->header.data_len, NULL);
216 return hr;
219 static HRESULT WINAPI ClassMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *size)
221 ClassMoniker *moniker = impl_from_IMoniker(iface);
223 TRACE("%p, %p\n", iface, size);
225 size->QuadPart = sizeof(moniker->header) + moniker->header.data_len;
227 return S_OK;
230 /******************************************************************************
231 * ClassMoniker_BindToObject
232 ******************************************************************************/
233 static HRESULT WINAPI ClassMoniker_BindToObject(IMoniker* iface,
234 IBindCtx* pbc,
235 IMoniker* pmkToLeft,
236 REFIID riid,
237 VOID** ppvResult)
239 ClassMoniker *moniker = impl_from_IMoniker(iface);
240 BIND_OPTS2 bindopts;
241 IClassActivator *pActivator;
242 HRESULT hr;
244 TRACE("(%p, %p, %s, %p)\n", pbc, pmkToLeft, debugstr_guid(riid), ppvResult);
246 bindopts.cbStruct = sizeof(bindopts);
247 IBindCtx_GetBindOptions(pbc, (BIND_OPTS *)&bindopts);
249 if (!pmkToLeft)
250 return CoGetClassObject(&moniker->header.clsid, bindopts.dwClassContext, NULL,
251 riid, ppvResult);
252 else
254 hr = IMoniker_BindToObject(pmkToLeft, pbc, NULL, &IID_IClassActivator,
255 (void **)&pActivator);
256 if (FAILED(hr)) return hr;
258 hr = IClassActivator_GetClassObject(pActivator, &moniker->header.clsid,
259 bindopts.dwClassContext,
260 bindopts.locale, riid, ppvResult);
262 IClassActivator_Release(pActivator);
264 return hr;
268 /******************************************************************************
269 * ClassMoniker_BindToStorage
270 ******************************************************************************/
271 static HRESULT WINAPI ClassMoniker_BindToStorage(IMoniker* iface,
272 IBindCtx* pbc,
273 IMoniker* pmkToLeft,
274 REFIID riid,
275 VOID** ppvResult)
277 TRACE("(%p, %p, %s, %p)\n", pbc, pmkToLeft, debugstr_guid(riid), ppvResult);
278 return IMoniker_BindToObject(iface, pbc, pmkToLeft, riid, ppvResult);
281 static HRESULT WINAPI ClassMoniker_Reduce(IMoniker* iface, IBindCtx *pbc,
282 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
284 TRACE("%p, %p, %ld, %p, %p.\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
286 if (!ppmkReduced)
287 return E_POINTER;
289 IMoniker_AddRef(iface);
291 *ppmkReduced = iface;
293 return MK_S_REDUCED_TO_SELF;
296 static HRESULT WINAPI ClassMoniker_ComposeWith(IMoniker *iface, IMoniker *right,
297 BOOL only_if_not_generic, IMoniker **result)
299 DWORD order;
301 TRACE("%p, %p, %d, %p.\n", iface, right, only_if_not_generic, result);
303 if (!result || !right)
304 return E_POINTER;
306 *result = NULL;
308 if (is_anti_moniker(right, &order))
309 return S_OK;
311 return only_if_not_generic ? MK_E_NEEDGENERIC : CreateGenericComposite(iface, right, result);
314 /******************************************************************************
315 * ClassMoniker_Enum
316 ******************************************************************************/
317 static HRESULT WINAPI ClassMoniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
319 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
321 if (ppenumMoniker == NULL)
322 return E_POINTER;
324 *ppenumMoniker = NULL;
326 return S_OK;
329 static HRESULT WINAPI ClassMoniker_IsEqual(IMoniker *iface, IMoniker *other)
331 ClassMoniker *moniker = impl_from_IMoniker(iface), *other_moniker;
333 TRACE("%p, %p.\n", iface, other);
335 if (!other)
336 return E_INVALIDARG;
338 other_moniker = unsafe_impl_from_IMoniker(other);
339 if (!other_moniker)
340 return S_FALSE;
342 return IsEqualGUID(&moniker->header.clsid, &other_moniker->header.clsid) ? S_OK : S_FALSE;
345 static HRESULT WINAPI ClassMoniker_Hash(IMoniker *iface, DWORD *hash)
347 ClassMoniker *moniker = impl_from_IMoniker(iface);
349 TRACE("%p, %p\n", iface, hash);
351 *hash = moniker->header.clsid.Data1;
353 return S_OK;
356 /******************************************************************************
357 * ClassMoniker_IsRunning
358 ******************************************************************************/
359 static HRESULT WINAPI ClassMoniker_IsRunning(IMoniker* iface,
360 IBindCtx* pbc,
361 IMoniker* pmkToLeft,
362 IMoniker* pmkNewlyRunning)
364 TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pmkNewlyRunning);
366 /* as in native */
367 return E_NOTIMPL;
370 /******************************************************************************
371 * ClassMoniker_GetTimeOfLastChange
372 ******************************************************************************/
373 static HRESULT WINAPI ClassMoniker_GetTimeOfLastChange(IMoniker* iface,
374 IBindCtx* pbc,
375 IMoniker* pmkToLeft,
376 FILETIME* pItemTime)
378 TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pItemTime);
380 return MK_E_UNAVAILABLE;
383 /******************************************************************************
384 * ClassMoniker_Inverse
385 ******************************************************************************/
386 static HRESULT WINAPI ClassMoniker_Inverse(IMoniker* iface,IMoniker** ppmk)
388 TRACE("(%p)\n",ppmk);
390 if (!ppmk)
391 return E_POINTER;
393 return CreateAntiMoniker(ppmk);
396 static HRESULT WINAPI ClassMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *other, IMoniker **prefix)
398 ClassMoniker *moniker = impl_from_IMoniker(iface), *other_moniker;
400 TRACE("%p, %p, %p\n", iface, other, prefix);
402 *prefix = NULL;
404 other_moniker = unsafe_impl_from_IMoniker(other);
406 if (other_moniker)
408 if (!IsEqualGUID(&moniker->header.clsid, &other_moniker->header.clsid)) return MK_E_NOPREFIX;
410 *prefix = iface;
411 IMoniker_AddRef(iface);
413 return MK_S_US;
416 return MonikerCommonPrefixWith(iface, other, prefix);
419 /******************************************************************************
420 * ClassMoniker_RelativePathTo
421 ******************************************************************************/
422 static HRESULT WINAPI ClassMoniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
424 TRACE("(%p, %p)\n",pmOther,ppmkRelPath);
426 if (!ppmkRelPath)
427 return E_POINTER;
429 *ppmkRelPath = NULL;
431 return MK_E_NOTBINDABLE;
434 static HRESULT WINAPI ClassMoniker_GetDisplayName(IMoniker *iface,
435 IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *name)
437 ClassMoniker *moniker = impl_from_IMoniker(iface);
438 static const int name_len = CHARS_IN_GUID + 5 /* prefix */;
439 const GUID *guid = &moniker->header.clsid;
441 TRACE("%p, %p, %p, %p.\n", iface, pbc, pmkToLeft, name);
443 if (!name)
444 return E_POINTER;
446 if (pmkToLeft)
447 return E_INVALIDARG;
449 if (!(*name = CoTaskMemAlloc(name_len * sizeof(WCHAR) + moniker->header.data_len)))
450 return E_OUTOFMEMORY;
452 swprintf(*name, name_len, L"clsid:%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
453 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
454 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
456 if (moniker->header.data_len)
457 lstrcatW(*name, moniker->data);
458 lstrcatW(*name, L":");
460 TRACE("Returning %s\n", debugstr_w(*name));
462 return S_OK;
465 static HRESULT WINAPI ClassMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
466 IMoniker *pmkToLeft, LPOLESTR display_name, ULONG *eaten, IMoniker **result)
468 IParseDisplayName *parser;
469 HRESULT hr;
471 TRACE("%p, %p, %p, %s, %p, %p\n", iface, pbc, pmkToLeft, debugstr_w(display_name), eaten, result);
473 if (SUCCEEDED(hr = IMoniker_BindToObject(iface, pbc, pmkToLeft, &IID_IParseDisplayName, (void **)&parser)))
475 hr = IParseDisplayName_ParseDisplayName(parser, pbc, display_name, eaten, result);
476 IParseDisplayName_Release(parser);
479 return hr;
482 /******************************************************************************
483 * ClassMoniker_IsSystemMoniker
484 ******************************************************************************/
485 static HRESULT WINAPI ClassMoniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
487 TRACE("(%p,%p)\n",iface,pwdMksys);
489 if (!pwdMksys)
490 return E_POINTER;
492 *pwdMksys = MKSYS_CLASSMONIKER;
494 return S_OK;
497 /*******************************************************************************
498 * ClassMonikerIROTData_QueryInterface
499 *******************************************************************************/
500 static HRESULT WINAPI ClassMonikerROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
503 ClassMoniker *This = impl_from_IROTData(iface);
505 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
507 return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
510 /***********************************************************************
511 * ClassMonikerIROTData_AddRef
513 static ULONG WINAPI ClassMonikerROTData_AddRef(IROTData *iface)
515 ClassMoniker *This = impl_from_IROTData(iface);
517 TRACE("(%p)\n",iface);
519 return IMoniker_AddRef(&This->IMoniker_iface);
522 /***********************************************************************
523 * ClassMonikerIROTData_Release
525 static ULONG WINAPI ClassMonikerROTData_Release(IROTData* iface)
527 ClassMoniker *This = impl_from_IROTData(iface);
529 TRACE("(%p)\n",iface);
531 return IMoniker_Release(&This->IMoniker_iface);
534 /******************************************************************************
535 * ClassMonikerIROTData_GetComparisonData
536 ******************************************************************************/
537 static HRESULT WINAPI ClassMonikerROTData_GetComparisonData(IROTData* iface,
538 BYTE* pbData,
539 ULONG cbMax,
540 ULONG* pcbData)
542 ClassMoniker *This = impl_from_IROTData(iface);
544 TRACE("%p, %p, %lu, %p.\n", iface, pbData, cbMax, pcbData);
546 *pcbData = 2*sizeof(CLSID);
547 if (cbMax < *pcbData)
548 return E_OUTOFMEMORY;
550 /* write CLSID of the moniker */
551 memcpy(pbData, &CLSID_ClassMoniker, sizeof(CLSID));
552 /* write CLSID the moniker represents */
553 memcpy(pbData+sizeof(CLSID), &This->header.clsid, sizeof(CLSID));
555 return S_OK;
558 static const IMonikerVtbl ClassMonikerVtbl =
560 ClassMoniker_QueryInterface,
561 ClassMoniker_AddRef,
562 ClassMoniker_Release,
563 ClassMoniker_GetClassID,
564 ClassMoniker_IsDirty,
565 ClassMoniker_Load,
566 ClassMoniker_Save,
567 ClassMoniker_GetSizeMax,
568 ClassMoniker_BindToObject,
569 ClassMoniker_BindToStorage,
570 ClassMoniker_Reduce,
571 ClassMoniker_ComposeWith,
572 ClassMoniker_Enum,
573 ClassMoniker_IsEqual,
574 ClassMoniker_Hash,
575 ClassMoniker_IsRunning,
576 ClassMoniker_GetTimeOfLastChange,
577 ClassMoniker_Inverse,
578 ClassMoniker_CommonPrefixWith,
579 ClassMoniker_RelativePathTo,
580 ClassMoniker_GetDisplayName,
581 ClassMoniker_ParseDisplayName,
582 ClassMoniker_IsSystemMoniker
585 /********************************************************************************/
586 /* Virtual function table for the IROTData class. */
587 static const IROTDataVtbl ROTDataVtbl =
589 ClassMonikerROTData_QueryInterface,
590 ClassMonikerROTData_AddRef,
591 ClassMonikerROTData_Release,
592 ClassMonikerROTData_GetComparisonData
595 static HRESULT create_class_moniker(const CLSID *clsid, const WCHAR *data,
596 unsigned int data_len, IMoniker **moniker)
598 ClassMoniker *object;
600 if (!(object = heap_alloc_zero(sizeof(*object))))
601 return E_OUTOFMEMORY;
603 object->IMoniker_iface.lpVtbl = &ClassMonikerVtbl;
604 object->IROTData_iface.lpVtbl = &ROTDataVtbl;
605 object->ref = 1;
606 object->header.clsid = *clsid;
607 if (data_len)
609 object->header.data_len = (data_len + 1) * sizeof(WCHAR);
611 if (!(object->data = heap_alloc(object->header.data_len)))
613 IMoniker_Release(&object->IMoniker_iface);
614 return E_OUTOFMEMORY;
616 memcpy(object->data, data, data_len * sizeof(WCHAR));
617 object->data[data_len] = 0;
620 *moniker = &object->IMoniker_iface;
622 return S_OK;
625 /******************************************************************************
626 * CreateClassMoniker [OLE32.@]
627 ******************************************************************************/
628 HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **moniker)
630 TRACE("%s, %p\n", debugstr_guid(rclsid), moniker);
632 return create_class_moniker(rclsid, NULL, 0, moniker);
635 HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, const WCHAR *display_name,
636 DWORD *eaten, IMoniker **moniker)
638 const WCHAR *end, *s;
639 BOOL has_braces;
640 WCHAR uuid[37];
641 CLSID clsid;
642 HRESULT hr;
643 int len;
645 s = display_name;
647 /* Skip prefix */
648 if (wcsnicmp(s, L"clsid:", 6)) return MK_E_SYNTAX;
649 s += 6;
651 /* Terminating marker is optional */
652 if (!(end = wcschr(s, ':')))
653 end = s + lstrlenW(s);
655 len = end - s;
656 if (len < 36)
657 return MK_E_SYNTAX;
659 if ((has_braces = *s == '{')) s++;
661 memcpy(uuid, s, 36 * sizeof(WCHAR));
662 uuid[36] = 0;
664 if (UuidFromStringW(uuid, &clsid))
666 WARN("Failed to parse clsid string.\n");
667 return MK_E_SYNTAX;
670 s += 36;
671 if (has_braces)
673 if (*s != '}') return MK_E_SYNTAX;
674 s++;
677 /* Consume terminal marker */
678 len = end - s;
679 if (*end == ':') end++;
681 hr = create_class_moniker(&clsid, len ? s : NULL, len, moniker);
682 if (SUCCEEDED(hr))
683 *eaten = end - display_name;
684 return hr;
687 HRESULT WINAPI ClassMoniker_CreateInstance(IClassFactory *iface,
688 IUnknown *pUnk, REFIID riid, void **ppv)
690 HRESULT hr;
691 IMoniker *pmk;
693 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
695 *ppv = NULL;
697 if (pUnk)
698 return CLASS_E_NOAGGREGATION;
700 hr = CreateClassMoniker(&CLSID_NULL, &pmk);
701 if (FAILED(hr)) return hr;
703 hr = IMoniker_QueryInterface(pmk, riid, ppv);
704 IMoniker_Release(pmk);
706 return hr;