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