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