ole32: The default handler needs to have its own implementation of IPersistStorage.
[wine] / dlls / ole32 / moniker.c
1 /*
2  *      Monikers
3  *
4  *      Copyright 1998  Marcus Meissner
5  *      Copyright 1999  Noomen Hamza
6  *      Copyright 2005  Robert Shearman (for CodeWeavers)
7  *      Copyright 2007  Robert Shearman
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  *
23  * TODO:
24  * - IRunningObjectTable should work interprocess, but currently doesn't.
25  *   Native (on Win2k at least) uses an undocumented RPC interface, IROT, to
26  *   communicate with RPCSS which contains the table of marshalled data.
27  */
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <string.h>
32
33 #define COBJMACROS
34
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "wtypes.h"
40 #include "ole2.h"
41
42 #include "wine/list.h"
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
45
46 #include "compobj_private.h"
47 #include "moniker.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(ole);
50
51 /* see MSDN docs for IROTData::GetComparisonData, which states what this
52  * constant is (http://msdn2.microsoft.com/en-us/library/ms693773.aspx) */
53 #define MAX_COMPARISON_DATA 2048
54
55 /* define the structure of the running object table elements */
56 struct rot_entry
57 {
58     struct list        entry;
59     MInterfacePointer* object; /* marshaled running object*/
60     MInterfacePointer* moniker; /* marshaled moniker that identifies this object */
61     MInterfacePointer* moniker_data; /* moniker comparison data that identifies this object */
62     DWORD              cookie; /* cookie identifying this object */
63     FILETIME           last_modified;
64 };
65
66 /* define the RunningObjectTableImpl structure */
67 typedef struct RunningObjectTableImpl
68 {
69     const IRunningObjectTableVtbl *lpVtbl;
70     LONG ref;
71
72     struct list rot; /* list of ROT entries */
73     CRITICAL_SECTION lock;
74 } RunningObjectTableImpl;
75
76 static RunningObjectTableImpl* runningObjectTableInstance = NULL;
77
78
79
80 static inline HRESULT WINAPI
81 IrotRegister(DWORD *cookie)
82 {
83     static LONG last_cookie = 1;
84     *cookie = InterlockedIncrement(&last_cookie);
85     return S_OK;
86 }
87
88 /* define the EnumMonikerImpl structure */
89 typedef struct EnumMonikerImpl
90 {
91     const IEnumMonikerVtbl *lpVtbl;
92     LONG ref;
93
94     MInterfacePointer **monikers;
95     ULONG moniker_count;
96     ULONG pos;
97 } EnumMonikerImpl;
98
99
100 /* IEnumMoniker Local functions*/
101 static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers,
102     ULONG moniker_count, ULONG pos, IEnumMoniker **ppenumMoniker);
103
104 static HRESULT create_stream_on_mip_ro(const MInterfacePointer *mip, IStream **stream)
105 {
106     HGLOBAL hglobal = GlobalAlloc(0, mip->ulCntData);
107     void *pv = GlobalLock(hglobal);
108     memcpy(pv, mip->abData, mip->ulCntData);
109     GlobalUnlock(hglobal);
110     return CreateStreamOnHGlobal(hglobal, TRUE, stream);
111 }
112
113 static inline void rot_entry_delete(struct rot_entry *rot_entry)
114 {
115     /* FIXME: revoke entry from rpcss's copy of the ROT */
116     if (rot_entry->object)
117     {
118         IStream *stream;
119         HRESULT hr;
120         hr = create_stream_on_mip_ro(rot_entry->object, &stream);
121         if (hr == S_OK)
122         {
123             CoReleaseMarshalData(stream);
124             IUnknown_Release(stream);
125         }
126     }
127     if (rot_entry->moniker)
128     {
129         IStream *stream;
130         HRESULT hr;
131         hr = create_stream_on_mip_ro(rot_entry->moniker, &stream);
132         if (hr == S_OK)
133         {
134             CoReleaseMarshalData(stream);
135             IUnknown_Release(stream);
136         }
137     }
138     HeapFree(GetProcessHeap(), 0, rot_entry->object);
139     HeapFree(GetProcessHeap(), 0, rot_entry->moniker);
140     HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
141     HeapFree(GetProcessHeap(), 0, rot_entry);
142 }
143
144 /* moniker_data must be freed with HeapFree when no longer in use */
145 static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MInterfacePointer **moniker_data)
146 {
147     HRESULT hr;
148     IROTData *pROTData = NULL;
149     hr = IMoniker_QueryInterface(pMoniker, &IID_IROTData, (void *)&pROTData);
150     if (SUCCEEDED(hr))
151     {
152         ULONG size = MAX_COMPARISON_DATA;
153         *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
154         hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size);
155         if (hr != S_OK)
156         {
157             ERR("Failed to copy comparison data into buffer, hr = 0x%08x\n", hr);
158             HeapFree(GetProcessHeap(), 0, *moniker_data);
159             return hr;
160         }
161         (*moniker_data)->ulCntData = size;
162     }
163     else
164     {
165         IBindCtx *pbc;
166         LPOLESTR pszDisplayName;
167         CLSID clsid;
168         int len;
169
170         TRACE("generating comparison data from display name\n");
171
172         hr = CreateBindCtx(0, &pbc);
173         if (FAILED(hr))
174             return hr;
175         hr = IMoniker_GetDisplayName(pMoniker, pbc, NULL, &pszDisplayName);
176         IBindCtx_Release(pbc);
177         if (FAILED(hr))
178             return hr;
179         hr = IMoniker_GetClassID(pMoniker, &clsid);
180         if (FAILED(hr))
181         {
182             CoTaskMemFree(pszDisplayName);
183             return hr;
184         }
185
186         len = strlenW(pszDisplayName);
187         *moniker_data = HeapAlloc(GetProcessHeap(), 0,
188             FIELD_OFFSET(MInterfacePointer, abData[sizeof(CLSID) + (len+1)*sizeof(WCHAR)]));
189         if (!*moniker_data)
190         {
191             CoTaskMemFree(pszDisplayName);
192             return E_OUTOFMEMORY;
193         }
194         (*moniker_data)->ulCntData = sizeof(CLSID) + (len+1)*sizeof(WCHAR);
195
196         memcpy(&(*moniker_data)->abData[0], &clsid, sizeof(clsid));
197         memcpy(&(*moniker_data)->abData[sizeof(clsid)], pszDisplayName, (len+1)*sizeof(WCHAR));
198     }
199     return S_OK;
200 }
201
202 static HRESULT reduce_moniker(IMoniker *pmk, IBindCtx *pbc, IMoniker **pmkReduced)
203 {
204     IBindCtx *pbcNew = NULL;
205     HRESULT hr;
206     if (!pbc)
207     {
208         hr = CreateBindCtx(0, &pbcNew);
209         if (FAILED(hr))
210             return hr;
211         pbc = pbcNew;
212     }
213     hr = IMoniker_Reduce(pmk, pbc, MKRREDUCE_ALL, NULL, pmkReduced);
214     if (FAILED(hr))
215         ERR("reducing moniker failed with error 0x%08x\n", hr);
216     if (pbcNew) IBindCtx_Release(pbcNew);
217     return hr;
218 }
219
220 /***********************************************************************
221  *        RunningObjectTable_QueryInterface
222  */
223 static HRESULT WINAPI
224 RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface,
225                                       REFIID riid,void** ppvObject)
226 {
227     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
228
229     TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
230
231     /* validate arguments */
232
233     if (ppvObject==0)
234         return E_INVALIDARG;
235
236     *ppvObject = 0;
237
238     if (IsEqualIID(&IID_IUnknown, riid) ||
239         IsEqualIID(&IID_IRunningObjectTable, riid))
240         *ppvObject = (IRunningObjectTable*)This;
241
242     if ((*ppvObject)==0)
243         return E_NOINTERFACE;
244
245     IRunningObjectTable_AddRef(iface);
246
247     return S_OK;
248 }
249
250 /***********************************************************************
251  *        RunningObjectTable_AddRef
252  */
253 static ULONG WINAPI
254 RunningObjectTableImpl_AddRef(IRunningObjectTable* iface)
255 {
256     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
257
258     TRACE("(%p)\n",This);
259
260     return InterlockedIncrement(&This->ref);
261 }
262
263 /***********************************************************************
264  *        RunningObjectTable_Initialize
265  */
266 static HRESULT WINAPI
267 RunningObjectTableImpl_Destroy(void)
268 {
269     struct list *cursor, *cursor2;
270
271     TRACE("()\n");
272
273     if (runningObjectTableInstance==NULL)
274         return E_INVALIDARG;
275
276     /* free the ROT table memory */
277     LIST_FOR_EACH_SAFE(cursor, cursor2, &runningObjectTableInstance->rot)
278     {
279         struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry);
280         list_remove(&rot_entry->entry);
281         rot_entry_delete(rot_entry);
282     }
283
284     DEBUG_CLEAR_CRITSEC_NAME(&runningObjectTableInstance->lock);
285     DeleteCriticalSection(&runningObjectTableInstance->lock);
286
287     /* free the ROT structure memory */
288     HeapFree(GetProcessHeap(),0,runningObjectTableInstance);
289     runningObjectTableInstance = NULL;
290
291     return S_OK;
292 }
293
294 /***********************************************************************
295  *        RunningObjectTable_Release
296  */
297 static ULONG WINAPI
298 RunningObjectTableImpl_Release(IRunningObjectTable* iface)
299 {
300     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
301     ULONG ref;
302
303     TRACE("(%p)\n",This);
304
305     ref = InterlockedDecrement(&This->ref);
306
307     /* uninitialize ROT structure if there's no more references to it */
308     if (ref == 0)
309     {
310         struct list *cursor, *cursor2;
311         LIST_FOR_EACH_SAFE(cursor, cursor2, &This->rot)
312         {
313             struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry);
314             list_remove(&rot_entry->entry);
315             rot_entry_delete(rot_entry);
316         }
317         /*  RunningObjectTable data structure will be not destroyed here ! the destruction will be done only
318          *  when RunningObjectTableImpl_UnInitialize function is called
319          */
320     }
321
322     return ref;
323 }
324
325 /***********************************************************************
326  *        RunningObjectTable_Register
327  *
328  * PARAMS
329  * grfFlags       [in] Registration options 
330  * punkObject     [in] the object being registered
331  * pmkObjectName  [in] the moniker of the object being registered
332  * pdwRegister    [in] the value identifying the registration
333  */
334 static HRESULT WINAPI
335 RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags,
336                IUnknown *punkObject, IMoniker *pmkObjectName, DWORD *pdwRegister)
337 {
338     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
339     struct rot_entry *rot_entry;
340     HRESULT hr = S_OK;
341     IStream *pStream = NULL;
342     DWORD mshlflags;
343     IBindCtx *pbc;
344
345     TRACE("(%p,%d,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister);
346
347     if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT))
348     {
349         ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT));
350         return E_INVALIDARG;
351     }
352
353     if (punkObject==NULL || pmkObjectName==NULL || pdwRegister==NULL)
354         return E_INVALIDARG;
355
356     rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry));
357     if (!rot_entry)
358         return E_OUTOFMEMORY;
359
360     /* marshal object */
361     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
362     if (hr != S_OK)
363     {
364         rot_entry_delete(rot_entry);
365         return hr;
366     }
367     mshlflags = (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_TABLEWEAK;
368     hr = CoMarshalInterface(pStream, &IID_IUnknown, punkObject, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, mshlflags);
369     /* FIXME: a cleaner way would be to create an IStream class that writes
370      * directly to an MInterfacePointer */
371     if (hr == S_OK)
372     {
373         HGLOBAL hglobal;
374         hr = GetHGlobalFromStream(pStream, &hglobal);
375         if (hr == S_OK)
376         {
377             SIZE_T size = GlobalSize(hglobal);
378             const void *pv = GlobalLock(hglobal);
379             rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
380             rot_entry->object->ulCntData = size;
381             memcpy(&rot_entry->object->abData, pv, size);
382             GlobalUnlock(hglobal);
383         }
384     }
385     IStream_Release(pStream);
386     if (hr != S_OK)
387     {
388         rot_entry_delete(rot_entry);
389         return hr;
390     }
391
392     hr = CreateBindCtx(0, &pbc);
393     if (FAILED(hr))
394     {
395         rot_entry_delete(rot_entry);
396         return hr;
397     }
398
399     hr = reduce_moniker(pmkObjectName, pbc, &pmkObjectName);
400     if (FAILED(hr))
401     {
402         rot_entry_delete(rot_entry);
403         IBindCtx_Release(pbc);
404         return hr;
405     }
406
407     hr = IMoniker_GetTimeOfLastChange(pmkObjectName, pbc, NULL,
408                                       &rot_entry->last_modified);
409     IBindCtx_Release(pbc);
410     if (FAILED(hr))
411     {
412         CoFileTimeNow(&rot_entry->last_modified);
413         hr = S_OK;
414     }
415
416     hr = get_moniker_comparison_data(pmkObjectName,
417                                      &rot_entry->moniker_data);
418     if (hr != S_OK)
419     {
420         rot_entry_delete(rot_entry);
421         IMoniker_Release(pmkObjectName);
422         return hr;
423     }
424
425     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
426     if (hr != S_OK)
427     {
428         rot_entry_delete(rot_entry);
429         IMoniker_Release(pmkObjectName);
430         return hr;
431     }
432     /* marshal moniker */
433     hr = CoMarshalInterface(pStream, &IID_IMoniker, (IUnknown *)pmkObjectName,
434                             MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG);
435     /* FIXME: a cleaner way would be to create an IStream class that writes
436      * directly to an MInterfacePointer */
437     if (hr == S_OK)
438     {
439         HGLOBAL hglobal;
440         hr = GetHGlobalFromStream(pStream, &hglobal);
441         if (hr == S_OK)
442         {
443             SIZE_T size = GlobalSize(hglobal);
444             const void *pv = GlobalLock(hglobal);
445             rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
446             rot_entry->moniker->ulCntData = size;
447             memcpy(&rot_entry->moniker->abData, pv, size);
448             GlobalUnlock(hglobal);
449         }
450     }
451     IStream_Release(pStream);
452     IMoniker_Release(pmkObjectName);
453     if (hr != S_OK)
454     {
455         rot_entry_delete(rot_entry);
456         return hr;
457     }
458
459     /* FIXME: not the right signature of IrotRegister function */
460     hr = IrotRegister(&rot_entry->cookie);
461     if (hr != S_OK)
462     {
463         rot_entry_delete(rot_entry);
464         return hr;
465     }
466
467     /* gives a registration identifier to the registered object*/
468     *pdwRegister = rot_entry->cookie;
469
470     EnterCriticalSection(&This->lock);
471     /* FIXME: see if object was registered before and return MK_S_MONIKERALREADYREGISTERED */
472     list_add_tail(&This->rot, &rot_entry->entry);
473     LeaveCriticalSection(&This->lock);
474
475     return hr;
476 }
477
478 /***********************************************************************
479  *        RunningObjectTable_Revoke
480  *
481  * PARAMS
482  *  dwRegister [in] Value identifying registration to be revoked
483  */
484 static HRESULT WINAPI
485 RunningObjectTableImpl_Revoke( IRunningObjectTable* iface, DWORD dwRegister) 
486 {
487     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
488     struct rot_entry *rot_entry;
489
490     TRACE("(%p,%d)\n",This,dwRegister);
491
492     EnterCriticalSection(&This->lock);
493     LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
494     {
495         if (rot_entry->cookie == dwRegister)
496         {
497             list_remove(&rot_entry->entry);
498             LeaveCriticalSection(&This->lock);
499
500             rot_entry_delete(rot_entry);
501             return S_OK;
502         }
503     }
504     LeaveCriticalSection(&This->lock);
505
506     return E_INVALIDARG;
507 }
508
509 /***********************************************************************
510  *        RunningObjectTable_IsRunning
511  *
512  * PARAMS
513  *  pmkObjectName [in]  moniker of the object whose status is desired 
514  */
515 static HRESULT WINAPI
516 RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjectName)
517 {
518     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
519     MInterfacePointer *moniker_data;
520     HRESULT hr;
521     struct rot_entry *rot_entry;
522
523     TRACE("(%p,%p)\n",This,pmkObjectName);
524
525     hr = reduce_moniker(pmkObjectName, NULL, &pmkObjectName);
526     if (FAILED(hr))
527         return hr;
528     hr = get_moniker_comparison_data(pmkObjectName, &moniker_data);
529     IMoniker_Release(pmkObjectName);
530     if (hr != S_OK)
531         return hr;
532
533     hr = S_FALSE;
534     EnterCriticalSection(&This->lock);
535     LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
536     {
537         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
538             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
539         {
540             hr = S_OK;
541             break;
542         }
543     }
544     LeaveCriticalSection(&This->lock);
545
546     /* FIXME: call IrotIsRunning */
547
548     HeapFree(GetProcessHeap(), 0, moniker_data);
549
550     return hr;
551 }
552
553 /***********************************************************************
554  *        RunningObjectTable_GetObject
555  *
556  * PARAMS
557  * pmkObjectName [in] Pointer to the moniker on the object 
558  * ppunkObject   [out] variable that receives the IUnknown interface pointer
559  */
560 static HRESULT WINAPI
561 RunningObjectTableImpl_GetObject( IRunningObjectTable* iface,
562                      IMoniker *pmkObjectName, IUnknown **ppunkObject)
563 {
564     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
565     MInterfacePointer *moniker_data;
566     HRESULT hr;
567     struct rot_entry *rot_entry;
568
569     TRACE("(%p,%p,%p)\n",This,pmkObjectName,ppunkObject);
570
571     if (ppunkObject == NULL)
572         return E_POINTER;
573
574     *ppunkObject = NULL;
575
576     hr = reduce_moniker(pmkObjectName, NULL, &pmkObjectName);
577     if (FAILED(hr))
578         return hr;
579     hr = get_moniker_comparison_data(pmkObjectName, &moniker_data);
580     IMoniker_Release(pmkObjectName);
581     if (hr != S_OK)
582         return hr;
583
584     EnterCriticalSection(&This->lock);
585     LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
586     {
587         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
588             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
589         {
590             IStream *pStream;
591             hr = create_stream_on_mip_ro(rot_entry->object, &pStream);
592             if (hr == S_OK)
593             {
594                 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)ppunkObject);
595                 IStream_Release(pStream);
596             }
597
598             LeaveCriticalSection(&This->lock);
599             HeapFree(GetProcessHeap(), 0, moniker_data);
600
601             return hr;
602         }
603     }
604     LeaveCriticalSection(&This->lock);
605
606     /* FIXME: call IrotGetObject */
607     WARN("Moniker unavailable - app may require interprocess running object table\n");
608     hr = MK_E_UNAVAILABLE;
609
610     HeapFree(GetProcessHeap(), 0, moniker_data);
611
612     return hr;
613 }
614
615 /***********************************************************************
616  *        RunningObjectTable_NoteChangeTime
617  *
618  * PARAMS
619  *  dwRegister [in] Value identifying registration being updated
620  *  pfiletime  [in] Pointer to structure containing object's last change time
621  */
622 static HRESULT WINAPI
623 RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface,
624                                       DWORD dwRegister, FILETIME *pfiletime)
625 {
626     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
627     struct rot_entry *rot_entry;
628
629     TRACE("(%p,%d,%p)\n",This,dwRegister,pfiletime);
630
631     EnterCriticalSection(&This->lock);
632     LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
633     {
634         if (rot_entry->cookie == dwRegister)
635         {
636             rot_entry->last_modified = *pfiletime;
637             LeaveCriticalSection(&This->lock);
638             return S_OK;
639         }
640     }
641     LeaveCriticalSection(&This->lock);
642
643     /* FIXME: call IrotNoteChangeTime */
644
645     return E_INVALIDARG;
646 }
647
648 /***********************************************************************
649  *        RunningObjectTable_GetTimeOfLastChange
650  *
651  * PARAMS
652  *  pmkObjectName  [in]  moniker of the object whose status is desired 
653  *  pfiletime      [out] structure that receives object's last change time
654  */
655 static HRESULT WINAPI
656 RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface,
657                             IMoniker *pmkObjectName, FILETIME *pfiletime)
658 {
659     HRESULT hr = MK_E_UNAVAILABLE;
660     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
661     MInterfacePointer *moniker_data;
662     struct rot_entry *rot_entry;
663
664     TRACE("(%p,%p,%p)\n",This,pmkObjectName,pfiletime);
665
666     if (pmkObjectName==NULL || pfiletime==NULL)
667         return E_INVALIDARG;
668
669     hr = reduce_moniker(pmkObjectName, NULL, &pmkObjectName);
670     if (FAILED(hr))
671         return hr;
672     hr = get_moniker_comparison_data(pmkObjectName, &moniker_data);
673     IMoniker_Release(pmkObjectName);
674     if (hr != S_OK)
675         return hr;
676
677     hr = MK_E_UNAVAILABLE;
678
679     EnterCriticalSection(&This->lock);
680     LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
681     {
682         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
683             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
684         {
685             *pfiletime = rot_entry->last_modified;
686             hr = S_OK;
687             break;
688         }
689     }
690     LeaveCriticalSection(&This->lock);
691
692     /* FIXME: if (hr != S_OK) call IrotGetTimeOfLastChange */
693
694     HeapFree(GetProcessHeap(), 0, moniker_data);
695     return hr;
696 }
697
698 /***********************************************************************
699  *        RunningObjectTable_EnumRunning
700  *
701  * PARAMS
702  *  ppenumMoniker  [out]  receives the IEnumMoniker interface pointer 
703  */
704 static HRESULT WINAPI
705 RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface,
706                                    IEnumMoniker **ppenumMoniker)
707 {
708     HRESULT hr;
709     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
710     MInterfacePointer **monikers;
711     ULONG moniker_count = 0;
712     const struct rot_entry *rot_entry;
713     ULONG i = 0;
714
715     EnterCriticalSection(&This->lock);
716
717     LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry )
718         moniker_count++;
719
720     monikers = HeapAlloc(GetProcessHeap(), 0, moniker_count * sizeof(*monikers));
721
722     LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry )
723     {
724         SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[rot_entry->moniker->ulCntData]);
725         monikers[i] = HeapAlloc(GetProcessHeap(), 0, size);
726         memcpy(monikers[i], rot_entry->moniker, size);
727         i++;
728     }
729
730     LeaveCriticalSection(&This->lock);
731     
732     /* FIXME: call IrotEnumRunning and append data */
733
734     hr = EnumMonikerImpl_CreateEnumROTMoniker(monikers, moniker_count, 0, ppenumMoniker);
735
736     return hr;
737 }
738
739 /* Virtual function table for the IRunningObjectTable class. */
740 static const IRunningObjectTableVtbl VT_RunningObjectTableImpl =
741 {
742     RunningObjectTableImpl_QueryInterface,
743     RunningObjectTableImpl_AddRef,
744     RunningObjectTableImpl_Release,
745     RunningObjectTableImpl_Register,
746     RunningObjectTableImpl_Revoke,
747     RunningObjectTableImpl_IsRunning,
748     RunningObjectTableImpl_GetObject,
749     RunningObjectTableImpl_NoteChangeTime,
750     RunningObjectTableImpl_GetTimeOfLastChange,
751     RunningObjectTableImpl_EnumRunning
752 };
753
754 /***********************************************************************
755  *        RunningObjectTable_Initialize
756  */
757 HRESULT WINAPI RunningObjectTableImpl_Initialize(void)
758 {
759     TRACE("\n");
760
761     /* create the unique instance of the RunningObjectTableImpl structure */
762     runningObjectTableInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(RunningObjectTableImpl));
763
764     if (!runningObjectTableInstance)
765         return E_OUTOFMEMORY;
766
767     /* initialize the virtual table function */
768     runningObjectTableInstance->lpVtbl = &VT_RunningObjectTableImpl;
769
770     /* the initial reference is set to "1" ! because if set to "0" it will be not practis when */
771     /* the ROT referred many times not in the same time (all the objects in the ROT will  */
772     /* be removed every time the ROT is removed ) */
773     runningObjectTableInstance->ref = 1;
774
775     list_init(&runningObjectTableInstance->rot);
776     InitializeCriticalSection(&runningObjectTableInstance->lock);
777     DEBUG_SET_CRITSEC_NAME(&runningObjectTableInstance->lock, "RunningObjectTableImpl.lock");
778
779     return S_OK;
780 }
781
782 /***********************************************************************
783  *        RunningObjectTable_UnInitialize
784  */
785 HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void)
786 {
787     TRACE("\n");
788
789     if (runningObjectTableInstance==NULL)
790         return E_POINTER;
791
792     RunningObjectTableImpl_Release((IRunningObjectTable*)runningObjectTableInstance);
793
794     RunningObjectTableImpl_Destroy();
795
796     return S_OK;
797 }
798
799 /***********************************************************************
800  *           GetRunningObjectTable (OLE32.@)
801  *
802  * Retrieves the global running object table.
803  *
804  * PARAMS
805  *  reserved [I] Reserved. Set to 0.
806  *  pprot    [O] Address that receives the pointer to the running object table.
807  *
808  * RETURNS
809  *  Success: S_OK.
810  *  Failure: Any HRESULT code.
811  */
812 HRESULT WINAPI
813 GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot)
814 {
815     IID riid=IID_IRunningObjectTable;
816     HRESULT res;
817
818     TRACE("()\n");
819
820     if (reserved!=0)
821         return E_UNEXPECTED;
822
823     if(runningObjectTableInstance==NULL)
824         return CO_E_NOTINITIALIZED;
825
826     res = IRunningObjectTable_QueryInterface((IRunningObjectTable*)runningObjectTableInstance,&riid,(void**)pprot);
827
828     return res;
829 }
830
831 static HRESULT get_moniker_for_progid_display_name(LPBC pbc,
832                                                    LPCOLESTR szDisplayName,
833                                                    LPDWORD pchEaten,
834                                                    LPMONIKER *ppmk)
835 {
836     CLSID clsid;
837     HRESULT hr;
838     LPWSTR progid;
839     LPCWSTR start = szDisplayName;
840     LPCWSTR end;
841     int len;
842     IMoniker *class_moniker;
843
844     if (*start == '@')
845         start++;
846
847     /* find end delimiter */
848     for (end = start; *end; end++)
849         if (*end == ':')
850             break;
851
852     len = end - start;
853
854     /* must start with '@' or have a ':' somewhere and mustn't be one character
855      * long (since that looks like an absolute path) */
856     if (((start == szDisplayName) && (*end == '\0')) || (len <= 1))
857         return MK_E_SYNTAX;
858
859     progid = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
860     if (progid)
861     {
862         memcpy(progid, start, len * sizeof(WCHAR));
863         progid[len] = '\0';
864     }
865     hr = CLSIDFromProgID(progid, &clsid);
866     HeapFree(GetProcessHeap(), 0, progid);
867     if (FAILED(hr))
868         return MK_E_SYNTAX;
869
870     hr = CreateClassMoniker(&clsid, &class_moniker);
871     if (SUCCEEDED(hr))
872     {
873         IParseDisplayName *pdn;
874         hr = IMoniker_BindToObject(class_moniker, pbc, NULL,
875                                    &IID_IParseDisplayName, (void **)&pdn);
876         IMoniker_Release(class_moniker);
877         if (SUCCEEDED(hr))
878         {
879             hr = IParseDisplayName_ParseDisplayName(pdn, pbc,
880                                                     (LPOLESTR)szDisplayName,
881                                                     pchEaten, ppmk);
882             IParseDisplayName_Release(pdn);
883         }
884     }
885     return hr;
886 }
887
888 /******************************************************************************
889  *              MkParseDisplayName        [OLE32.@]
890  */
891 HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
892                                 LPDWORD pchEaten, LPMONIKER *ppmk)
893 {
894     HRESULT hr = MK_E_SYNTAX;
895     static const WCHAR wszClsidColon[] = {'c','l','s','i','d',':'};
896     IMoniker *moniker;
897     DWORD chEaten;
898
899     TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
900
901     if (!(IsValidInterface((LPUNKNOWN) pbc)))
902         return E_INVALIDARG;
903
904     *pchEaten = 0;
905     *ppmk = NULL;
906
907     if (!strncmpiW(szDisplayName, wszClsidColon, sizeof(wszClsidColon)/sizeof(wszClsidColon[0])))
908     {
909         hr = ClassMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker);
910         if (FAILED(hr) && (hr != MK_E_SYNTAX))
911             return hr;
912     }
913     else
914     {
915         hr = get_moniker_for_progid_display_name(pbc, szDisplayName, &chEaten, &moniker);
916         if (FAILED(hr) && (hr != MK_E_SYNTAX))
917             return hr;
918     }
919
920     if (FAILED(hr))
921     {
922         hr = FileMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker);
923         if (FAILED(hr) && (hr != MK_E_SYNTAX))
924             return hr;
925     }
926
927     if (SUCCEEDED(hr))
928     {
929         while (TRUE)
930         {
931             IMoniker *next_moniker;
932             *pchEaten += chEaten;
933             szDisplayName += chEaten;
934             if (!*szDisplayName)
935             {
936                 *ppmk = moniker;
937                 return S_OK;
938             }
939             chEaten = 0;
940             hr = IMoniker_ParseDisplayName(moniker, pbc, NULL,
941                                            (LPOLESTR)szDisplayName, &chEaten,
942                                            &next_moniker);
943             IMoniker_Release(moniker);
944             if (FAILED(hr))
945             {
946                 *pchEaten = 0;
947                 break;
948             }
949             moniker = next_moniker;
950         }
951     }
952
953     return hr;
954 }
955
956 /***********************************************************************
957  *        GetClassFile (OLE32.@)
958  *
959  * Retrieves the class ID associated with the given filename.
960  *
961  * PARAMS
962  *  filePathName [I] Filename to retrieve the class ID for.
963  *  pclsid       [O] Address that receives the class ID for the file.
964  *
965  * RETURNS
966  *  Success: S_OK.
967  *  Failure: Any HRESULT code.
968  */
969 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
970 {
971     IStorage *pstg=0;
972     HRESULT res;
973     int nbElm, length, i;
974     LONG sizeProgId;
975     LPOLESTR *pathDec=0,absFile=0,progId=0;
976     LPWSTR extension;
977     static const WCHAR bkslashW[] = {'\\',0};
978     static const WCHAR dotW[] = {'.',0};
979
980     TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
981
982     /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
983     if((StgIsStorageFile(filePathName))==S_OK){
984
985         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
986
987         if (SUCCEEDED(res))
988             res=ReadClassStg(pstg,pclsid);
989
990         IStorage_Release(pstg);
991
992         return res;
993     }
994     /* if the file is not a storage object then attemps to match various bits in the file against a
995        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
996        this case
997
998      for(i=0;i<nFileTypes;i++)
999
1000         for(i=0;j<nPatternsForType;j++){
1001
1002             PATTERN pat;
1003             HANDLE  hFile;
1004
1005             pat=ReadPatternFromRegistry(i,j);
1006             hFile=CreateFileW(filePathName,,,,,,hFile);
1007             SetFilePosition(hFile,pat.offset);
1008             ReadFile(hFile,buf,pat.size,&r,NULL);
1009             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1010
1011                 *pclsid=ReadCLSIDFromRegistry(i);
1012                 return S_OK;
1013             }
1014         }
1015      */
1016
1017     /* if the above strategies fail then search for the extension key in the registry */
1018
1019     /* get the last element (absolute file) in the path name */
1020     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1021     absFile=pathDec[nbElm-1];
1022
1023     /* failed if the path represente a directory and not an absolute file name*/
1024     if (!lstrcmpW(absFile, bkslashW))
1025         return MK_E_INVALIDEXTENSION;
1026
1027     /* get the extension of the file */
1028     extension = NULL;
1029     length=lstrlenW(absFile);
1030     for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1031         /* nothing */;
1032
1033     if (!extension || !lstrcmpW(extension, dotW))
1034         return MK_E_INVALIDEXTENSION;
1035
1036     res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1037
1038     /* get the progId associated to the extension */
1039     progId = CoTaskMemAlloc(sizeProgId);
1040     res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1041
1042     if (res==ERROR_SUCCESS)
1043         /* return the clsid associated to the progId */
1044         res= CLSIDFromProgID(progId,pclsid);
1045
1046     for(i=0; pathDec[i]!=NULL;i++)
1047         CoTaskMemFree(pathDec[i]);
1048     CoTaskMemFree(pathDec);
1049
1050     CoTaskMemFree(progId);
1051
1052     if (res==ERROR_SUCCESS)
1053         return res;
1054
1055     return MK_E_INVALIDEXTENSION;
1056 }
1057
1058 /***********************************************************************
1059  *        EnumMoniker_QueryInterface
1060  */
1061 static HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1062 {
1063     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1064
1065     TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
1066
1067     /* validate arguments */
1068     if (ppvObject == NULL)
1069         return E_INVALIDARG;
1070
1071     *ppvObject = NULL;
1072
1073     if (IsEqualIID(&IID_IUnknown, riid))
1074         *ppvObject = (IEnumMoniker*)This;
1075     else
1076         if (IsEqualIID(&IID_IEnumMoniker, riid))
1077             *ppvObject = (IEnumMoniker*)This;
1078
1079     if ((*ppvObject)==NULL)
1080         return E_NOINTERFACE;
1081
1082     IEnumMoniker_AddRef(iface);
1083
1084     return S_OK;
1085 }
1086
1087 /***********************************************************************
1088  *        EnumMoniker_AddRef
1089  */
1090 static ULONG   WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1091 {
1092     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1093
1094     TRACE("(%p)\n",This);
1095
1096     return InterlockedIncrement(&This->ref);
1097 }
1098
1099 /***********************************************************************
1100  *        EnumMoniker_release
1101  */
1102 static ULONG   WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface)
1103 {
1104     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1105     ULONG ref;
1106
1107     TRACE("(%p)\n",This);
1108
1109     ref = InterlockedDecrement(&This->ref);
1110
1111     /* uninitialize rot structure if there's no more reference to it*/
1112     if (ref == 0)
1113     {
1114         ULONG i;
1115
1116         TRACE("(%p) Deleting\n",This);
1117
1118         for (i = 0; i < This->moniker_count; i++)
1119             HeapFree(GetProcessHeap(), 0, This->monikers[i]);
1120         HeapFree(GetProcessHeap(), 0, This->monikers);
1121         HeapFree(GetProcessHeap(), 0, This);
1122     }
1123
1124     return ref;
1125 }
1126 /***********************************************************************
1127  *        EnmumMoniker_Next
1128  */
1129 static HRESULT   WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface, ULONG celt, IMoniker** rgelt, ULONG * pceltFetched)
1130 {
1131     ULONG i;
1132     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1133     HRESULT hr = S_OK;
1134
1135     TRACE("(%p) TabCurrentPos %d Tablastindx %d\n", This, This->pos, This->moniker_count);
1136
1137     /* retrieve the requested number of moniker from the current position */
1138     for(i = 0; (This->pos < This->moniker_count) && (i < celt); i++)
1139     {
1140         IStream *stream;
1141         hr = create_stream_on_mip_ro(This->monikers[This->pos++], &stream);
1142         if (hr != S_OK) break;
1143         hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&rgelt[i]);
1144         IStream_Release(stream);
1145         if (hr != S_OK) break;
1146     }
1147
1148     if (pceltFetched != NULL)
1149         *pceltFetched= i;
1150
1151     if (hr != S_OK)
1152         return hr;
1153
1154     if (i == celt)
1155         return S_OK;
1156     else
1157         return S_FALSE;
1158
1159 }
1160
1161 /***********************************************************************
1162  *        EnmumMoniker_Skip
1163  */
1164 static HRESULT   WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface, ULONG celt)
1165 {
1166     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1167
1168     TRACE("(%p)\n",This);
1169
1170     if  (This->pos + celt >= This->moniker_count)
1171         return S_FALSE;
1172
1173     This->pos += celt;
1174
1175     return S_OK;
1176 }
1177
1178 /***********************************************************************
1179  *        EnmumMoniker_Reset
1180  */
1181 static HRESULT   WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface)
1182 {
1183     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1184
1185     This->pos = 0;      /* set back to start of list */
1186
1187     TRACE("(%p)\n",This);
1188
1189     return S_OK;
1190 }
1191
1192 /***********************************************************************
1193  *        EnmumMoniker_Clone
1194  */
1195 static HRESULT   WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface, IEnumMoniker ** ppenum)
1196 {
1197     EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1198     MInterfacePointer **monikers = HeapAlloc(GetProcessHeap(), 0, sizeof(*monikers)*This->moniker_count);
1199     ULONG i;
1200
1201     TRACE("(%p)\n",This);
1202
1203     for (i = 0; i < This->moniker_count; i++)
1204     {
1205         SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[This->monikers[i]->ulCntData]);
1206         monikers[i] = HeapAlloc(GetProcessHeap(), 0, size);
1207         memcpy(monikers[i], This->monikers[i], size);
1208     }
1209
1210     /* copy the enum structure */ 
1211     return EnumMonikerImpl_CreateEnumROTMoniker(monikers, This->moniker_count,
1212         This->pos, ppenum);
1213 }
1214
1215 /* Virtual function table for the IEnumMoniker class. */
1216 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1217 {
1218     EnumMonikerImpl_QueryInterface,
1219     EnumMonikerImpl_AddRef,
1220     EnumMonikerImpl_Release,
1221     EnumMonikerImpl_Next,
1222     EnumMonikerImpl_Skip,
1223     EnumMonikerImpl_Reset,
1224     EnumMonikerImpl_Clone
1225 };
1226
1227 /***********************************************************************
1228  *        EnumMonikerImpl_CreateEnumROTMoniker
1229  *        Used by EnumRunning to create the structure and EnumClone
1230  *        to copy the structure
1231  */
1232 static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers,
1233                                                  ULONG moniker_count,
1234                                                  ULONG current_pos,
1235                                                  IEnumMoniker **ppenumMoniker)
1236 {
1237     EnumMonikerImpl* This = NULL;
1238
1239     if (!ppenumMoniker)
1240         return E_INVALIDARG;
1241
1242     This = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1243     if (!This) return E_OUTOFMEMORY;
1244
1245     TRACE("(%p)\n", This);
1246
1247     /* initialize the virtual table function */
1248     This->lpVtbl = &VT_EnumMonikerImpl;
1249
1250     /* the initial reference is set to "1" */
1251     This->ref = 1;                      /* set the ref count to one         */
1252     This->pos = current_pos;            /* Set the list start posn */
1253     This->moniker_count = moniker_count; /* Need the same size table as ROT */
1254     This->monikers = monikers;
1255
1256     *ppenumMoniker =  (IEnumMoniker*)This;
1257
1258     return S_OK;
1259 }
1260
1261
1262 /* Shared implementation of moniker marshaler based on saving and loading of
1263  * monikers */
1264
1265 typedef struct MonikerMarshal
1266 {
1267     const IUnknownVtbl *lpVtbl;
1268     const IMarshalVtbl *lpVtblMarshal;
1269     
1270     LONG ref;
1271     IMoniker *moniker;
1272 } MonikerMarshal;
1273
1274 static inline MonikerMarshal *impl_from_IMarshal( IMarshal *iface )
1275 {
1276     return (MonikerMarshal *)((char*)iface - FIELD_OFFSET(MonikerMarshal, lpVtblMarshal));
1277 }
1278
1279 static HRESULT WINAPI MonikerMarshalInner_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppv)
1280 {
1281     MonikerMarshal *This = (MonikerMarshal *)iface;
1282     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1283     *ppv = NULL;
1284     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
1285     {
1286         *ppv = &This->lpVtblMarshal;
1287         IUnknown_AddRef((IUnknown *)&This->lpVtblMarshal);
1288         return S_OK;
1289     }
1290     FIXME("No interface for %s\n", debugstr_guid(riid));
1291     return E_NOINTERFACE;
1292 }
1293
1294 static ULONG WINAPI MonikerMarshalInner_AddRef(IUnknown *iface)
1295 {
1296     MonikerMarshal *This = (MonikerMarshal *)iface;
1297     return InterlockedIncrement(&This->ref);
1298 }
1299
1300 static ULONG WINAPI MonikerMarshalInner_Release(IUnknown *iface)
1301 {
1302     MonikerMarshal *This = (MonikerMarshal *)iface;
1303     ULONG ref = InterlockedDecrement(&This->ref);
1304
1305     if (!ref) HeapFree(GetProcessHeap(), 0, This);
1306     return ref;
1307 }
1308
1309 static const IUnknownVtbl VT_MonikerMarshalInner =
1310 {
1311     MonikerMarshalInner_QueryInterface,
1312     MonikerMarshalInner_AddRef,
1313     MonikerMarshalInner_Release
1314 };
1315
1316 static HRESULT WINAPI MonikerMarshal_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1317 {
1318     MonikerMarshal *This = impl_from_IMarshal(iface);
1319     return IMoniker_QueryInterface(This->moniker, riid, ppv);
1320 }
1321
1322 static ULONG WINAPI MonikerMarshal_AddRef(IMarshal *iface)
1323 {
1324     MonikerMarshal *This = impl_from_IMarshal(iface);
1325     return IMoniker_AddRef(This->moniker);
1326 }
1327
1328 static ULONG WINAPI MonikerMarshal_Release(IMarshal *iface)
1329 {
1330     MonikerMarshal *This = impl_from_IMarshal(iface);
1331     return IMoniker_Release(This->moniker);
1332 }
1333
1334 static HRESULT WINAPI MonikerMarshal_GetUnmarshalClass(
1335   LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1336   void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1337 {
1338     MonikerMarshal *This = impl_from_IMarshal(iface);
1339
1340     TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1341         dwDestContext, pvDestContext, mshlflags, pCid);
1342
1343     return IMoniker_GetClassID(This->moniker, pCid);
1344 }
1345
1346 static HRESULT WINAPI MonikerMarshal_GetMarshalSizeMax(
1347   LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1348   void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1349 {
1350     MonikerMarshal *This = impl_from_IMarshal(iface);
1351     HRESULT hr;
1352     ULARGE_INTEGER size;
1353
1354     TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1355         dwDestContext, pvDestContext, mshlflags, pSize);
1356
1357     hr = IMoniker_GetSizeMax(This->moniker, &size);
1358     if (hr == S_OK)
1359         *pSize = (DWORD)size.QuadPart;
1360     return hr;
1361 }
1362
1363 static HRESULT WINAPI MonikerMarshal_MarshalInterface(LPMARSHAL iface, IStream *pStm, 
1364     REFIID riid, void* pv, DWORD dwDestContext,
1365     void* pvDestContext, DWORD mshlflags)
1366 {
1367     MonikerMarshal *This = impl_from_IMarshal(iface);
1368
1369     TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
1370         dwDestContext, pvDestContext, mshlflags);
1371
1372     return IMoniker_Save(This->moniker, pStm, FALSE);
1373 }
1374
1375 static HRESULT WINAPI MonikerMarshal_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1376 {
1377     MonikerMarshal *This = impl_from_IMarshal(iface);
1378     HRESULT hr;
1379
1380     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1381
1382     hr = IMoniker_Load(This->moniker, pStm);
1383     if (hr == S_OK)
1384         hr = IMoniker_QueryInterface(This->moniker, riid, ppv);
1385     return hr;
1386 }
1387
1388 static HRESULT WINAPI MonikerMarshal_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1389 {
1390     TRACE("()\n");
1391     /* can't release a state-based marshal as nothing on server side to
1392      * release */
1393     return S_OK;
1394 }
1395
1396 static HRESULT WINAPI MonikerMarshal_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1397 {
1398     TRACE("()\n");
1399     /* can't disconnect a state-based marshal as nothing on server side to
1400      * disconnect from */
1401     return S_OK;
1402 }
1403
1404 static const IMarshalVtbl VT_MonikerMarshal =
1405 {
1406     MonikerMarshal_QueryInterface,
1407     MonikerMarshal_AddRef,
1408     MonikerMarshal_Release,
1409     MonikerMarshal_GetUnmarshalClass,
1410     MonikerMarshal_GetMarshalSizeMax,
1411     MonikerMarshal_MarshalInterface,
1412     MonikerMarshal_UnmarshalInterface,
1413     MonikerMarshal_ReleaseMarshalData,
1414     MonikerMarshal_DisconnectObject
1415 };
1416
1417 HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer)
1418 {
1419     MonikerMarshal *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1420     if (!This) return E_OUTOFMEMORY;
1421
1422     This->lpVtbl = &VT_MonikerMarshalInner;
1423     This->lpVtblMarshal = &VT_MonikerMarshal;
1424     This->ref = 1;
1425     This->moniker = inner;
1426
1427     *outer = (IUnknown *)&This->lpVtbl;
1428     return S_OK;
1429 }