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