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