Added SystemHandleInformation tests.
[wine] / dlls / ole32 / moniker.c
1 /*
2  *      Monikers
3  *
4  *      Copyright 1998  Marcus Meissner
5  *      Copyright 1999  Noomen Hamza
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * TODO:
22  * - IRunningObjectTable should work interprocess, but currently doesn't.
23  *   Native (on Win2k at least) uses an undocumented RPC interface, IROT, to
24  *   communicate with RPCSS which contains the table of marshalled data.
25  * - IRunningObjectTable should use marshalling instead of simple ref
26  *   counting as there is the possibility of using the running object table
27  *   to access objects in other apartments.
28  */
29
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
33
34 #define COBJMACROS
35
36 #include "winerror.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "wtypes.h"
41 #include "wine/debug.h"
42 #include "ole2.h"
43
44 #include "compobj_private.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
47
48 #define  BLOCK_TAB_SIZE 20 /* represent the first size table and it's increment block size */
49
50 /* define the structure of the running object table elements */
51 typedef struct RunObject{
52
53     IUnknown*  pObj; /* points on a running object*/
54     IMoniker*  pmkObj; /* points on a moniker who identifies this object */
55     FILETIME   lastModifObj;
56     DWORD      identRegObj; /* registration key relative to this object */
57     DWORD      regTypeObj; /* registration type : strong or weak */
58 }RunObject;
59
60 /* define the RunningObjectTableImpl structure */
61 typedef struct RunningObjectTableImpl{
62
63     IRunningObjectTableVtbl *lpVtbl;
64     ULONG      ref;
65
66     RunObject* runObjTab;            /* pointer to the first object in the table       */
67     DWORD      runObjTabSize;       /* current table size                            */
68     DWORD      runObjTabLastIndx;  /* first free index element in the table.        */
69     DWORD      runObjTabRegister; /* registration key of the next registered object */
70
71 } RunningObjectTableImpl;
72
73 static RunningObjectTableImpl* runningObjectTableInstance = NULL;
74
75 /* IRunningObjectTable prototype functions : */
76 /* IUnknown functions*/
77 static HRESULT WINAPI RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface,REFIID riid,void** ppvObject);
78 static ULONG   WINAPI RunningObjectTableImpl_AddRef(IRunningObjectTable* iface);
79 static ULONG   WINAPI RunningObjectTableImpl_Release(IRunningObjectTable* iface);
80 /* IRunningObjectTable functions */
81 static HRESULT WINAPI RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags,IUnknown* punkObject,IMoniker* pmkObjectName,DWORD* pdwRegister);
82 static HRESULT WINAPI RunningObjectTableImpl_Revoke(IRunningObjectTable* iface, DWORD dwRegister);
83 static HRESULT WINAPI RunningObjectTableImpl_IsRunning(IRunningObjectTable* iface, IMoniker* pmkObjectName);
84 static HRESULT WINAPI RunningObjectTableImpl_GetObject(IRunningObjectTable* iface, IMoniker* pmkObjectName,IUnknown** ppunkObject);
85 static HRESULT WINAPI RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface, DWORD dwRegister,FILETIME* pfiletime);
86 static HRESULT WINAPI RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface, IMoniker* pmkObjectName,FILETIME* pfiletime);
87 static HRESULT WINAPI RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface, IEnumMoniker** ppenumMoniker);
88 /* Local functions*/
89 HRESULT WINAPI RunningObjectTableImpl_Initialize(void);
90 HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void);
91 HRESULT WINAPI RunningObjectTableImpl_Destroy(void);
92 HRESULT WINAPI RunningObjectTableImpl_GetObjectIndex(RunningObjectTableImpl* This,DWORD identReg,IMoniker* pmk,DWORD *indx);
93
94 /* Virtual function table for the IRunningObjectTable class. */
95 static IRunningObjectTableVtbl VT_RunningObjectTableImpl =
96 {
97     RunningObjectTableImpl_QueryInterface,
98     RunningObjectTableImpl_AddRef,
99     RunningObjectTableImpl_Release,
100     RunningObjectTableImpl_Register,
101     RunningObjectTableImpl_Revoke,
102     RunningObjectTableImpl_IsRunning,
103     RunningObjectTableImpl_GetObject,
104     RunningObjectTableImpl_NoteChangeTime,
105     RunningObjectTableImpl_GetTimeOfLastChange,
106     RunningObjectTableImpl_EnumRunning
107 };
108
109 /***********************************************************************
110  *        RunningObjectTable_QueryInterface
111  */
112 HRESULT WINAPI RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface,REFIID riid,void** ppvObject)
113 {
114     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
115
116     TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
117
118     /* validate arguments */
119     if (This==0)
120         return CO_E_NOTINITIALIZED;
121
122     if (ppvObject==0)
123         return E_INVALIDARG;
124
125     *ppvObject = 0;
126
127     if (IsEqualIID(&IID_IUnknown, riid))
128         *ppvObject = (IRunningObjectTable*)This;
129     else
130         if (IsEqualIID(&IID_IRunningObjectTable, riid))
131             *ppvObject = (IRunningObjectTable*)This;
132
133     if ((*ppvObject)==0)
134         return E_NOINTERFACE;
135
136     RunningObjectTableImpl_AddRef(iface);
137
138     return S_OK;
139 }
140
141 /***********************************************************************
142  *        RunningObjectTable_AddRef
143  */
144 ULONG   WINAPI RunningObjectTableImpl_AddRef(IRunningObjectTable* iface)
145 {
146     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
147
148     TRACE("(%p)\n",This);
149
150     return InterlockedIncrement(&This->ref);
151 }
152
153 /***********************************************************************
154  *        RunningObjectTable_Initialize
155  */
156 HRESULT WINAPI RunningObjectTableImpl_Destroy(void)
157 {
158     TRACE("()\n");
159
160     if (runningObjectTableInstance==NULL)
161         return E_INVALIDARG;
162
163     /* free the ROT table memory */
164     HeapFree(GetProcessHeap(),0,runningObjectTableInstance->runObjTab);
165
166     /* free the ROT structure memory */
167     HeapFree(GetProcessHeap(),0,runningObjectTableInstance);
168     runningObjectTableInstance = NULL;
169
170     return S_OK;
171 }
172
173 /***********************************************************************
174  *        RunningObjectTable_Release
175  */
176 ULONG   WINAPI RunningObjectTableImpl_Release(IRunningObjectTable* iface)
177 {
178     DWORD i;
179     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
180     ULONG ref;
181
182     TRACE("(%p)\n",This);
183
184     ref = InterlockedDecrement(&This->ref);
185
186     /* unitialize ROT structure if there's no more reference to it*/
187     if (ref == 0) {
188
189         /* release all registered objects */
190         for(i=0;i<This->runObjTabLastIndx;i++)
191         {
192             if (( This->runObjTab[i].regTypeObj &  ROTFLAGS_REGISTRATIONKEEPSALIVE) != 0)
193                 IUnknown_Release(This->runObjTab[i].pObj);
194
195             IMoniker_Release(This->runObjTab[i].pmkObj);
196         }
197        /*  RunningObjectTable data structure will be not destroyed here ! the destruction will be done only
198         *  when RunningObjectTableImpl_UnInitialize function is called
199         */
200
201         /* there's no more elements in the table */
202         This->runObjTabRegister=0;
203         This->runObjTabLastIndx=0;
204     }
205
206     return ref;
207 }
208
209 /***********************************************************************
210  *        RunningObjectTable_Initialize
211  */
212 HRESULT WINAPI RunningObjectTableImpl_Initialize()
213 {
214     TRACE("()\n");
215
216     /* create the unique instance of the RunningObjectTableImpl structure */
217     runningObjectTableInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(RunningObjectTableImpl));
218
219     if (runningObjectTableInstance == 0)
220         return E_OUTOFMEMORY;
221
222     /* initialize the virtual table function */
223     runningObjectTableInstance->lpVtbl = &VT_RunningObjectTableImpl;
224
225     /* the initial reference is set to "1" ! because if set to "0" it will be not practis when */
226     /* the ROT referred many times not in the same time (all the objects in the ROT will  */
227     /* be removed every time the ROT is removed ) */
228     runningObjectTableInstance->ref = 1;
229
230     /* allocate space memory for the table which contains all the running objects */
231     runningObjectTableInstance->runObjTab = HeapAlloc(GetProcessHeap(), 0, sizeof(RunObject[BLOCK_TAB_SIZE]));
232
233     if (runningObjectTableInstance->runObjTab == NULL)
234         return E_OUTOFMEMORY;
235
236     runningObjectTableInstance->runObjTabSize=BLOCK_TAB_SIZE;
237     runningObjectTableInstance->runObjTabRegister=1;
238     runningObjectTableInstance->runObjTabLastIndx=0;
239
240     return S_OK;
241 }
242
243 /***********************************************************************
244  *        RunningObjectTable_UnInitialize
245  */
246 HRESULT WINAPI RunningObjectTableImpl_UnInitialize()
247 {
248     TRACE("()\n");
249
250     if (runningObjectTableInstance==NULL)
251         return E_POINTER;
252
253     RunningObjectTableImpl_Release((IRunningObjectTable*)runningObjectTableInstance);
254
255     RunningObjectTableImpl_Destroy();
256
257     return S_OK;
258 }
259
260 /***********************************************************************
261  *        RunningObjectTable_Register
262  */
263 HRESULT WINAPI RunningObjectTableImpl_Register(IRunningObjectTable* iface,
264                                                DWORD grfFlags,           /* Registration options */
265                                                IUnknown *punkObject,     /* Pointer to the object being registered */
266                                                IMoniker *pmkObjectName,  /* Pointer to the moniker of the object being registered */
267                                                DWORD *pdwRegister)       /* Pointer to the value identifying the  registration */
268 {
269     HRESULT res=S_OK;
270     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
271
272     TRACE("(%p,%ld,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister);
273
274     /* there's only two types of register : strong and or weak registration (only one must be passed on parameter) */
275     if ( ( (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || !(grfFlags & ROTFLAGS_ALLOWANYCLIENT)) &&
276          (!(grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ||  (grfFlags & ROTFLAGS_ALLOWANYCLIENT)) &&
277          (grfFlags) )
278         return E_INVALIDARG;
279
280     if (punkObject==NULL || pmkObjectName==NULL || pdwRegister==NULL)
281         return E_INVALIDARG;
282
283     /* verify if the object to be registered was registered before */
284     if (RunningObjectTableImpl_GetObjectIndex(This,-1,pmkObjectName,NULL)==S_OK)
285         res = MK_S_MONIKERALREADYREGISTERED;
286
287     /* put the new registered object in the first free element in the table */
288     This->runObjTab[This->runObjTabLastIndx].pObj = punkObject;
289     This->runObjTab[This->runObjTabLastIndx].pmkObj = pmkObjectName;
290     This->runObjTab[This->runObjTabLastIndx].regTypeObj = grfFlags;
291     This->runObjTab[This->runObjTabLastIndx].identRegObj = This->runObjTabRegister;
292     CoFileTimeNow(&(This->runObjTab[This->runObjTabLastIndx].lastModifObj));
293
294     /* gives a registration identifier to the registered object*/
295     (*pdwRegister)= This->runObjTabRegister;
296
297     if (This->runObjTabRegister == 0xFFFFFFFF){
298
299         FIXME("runObjTabRegister: %ld is out of data limite \n",This->runObjTabRegister);
300         return E_FAIL;
301     }
302     This->runObjTabRegister++;
303     This->runObjTabLastIndx++;
304
305     if (This->runObjTabLastIndx == This->runObjTabSize){ /* table is full ! so it must be resized */
306
307         This->runObjTabSize+=BLOCK_TAB_SIZE; /* newsize table */
308         This->runObjTab=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->runObjTab,
309                         This->runObjTabSize * sizeof(RunObject));
310         if (!This->runObjTab)
311             return E_OUTOFMEMORY;
312     }
313     /* add a reference to the object in the strong registration case */
314     if ((grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) !=0 ) {
315         TRACE("strong registration, reffing %p\n", punkObject);
316         /* this is wrong; we should always add a reference to the object */
317         IUnknown_AddRef(punkObject);
318     }
319     
320     IMoniker_AddRef(pmkObjectName);
321
322     return res;
323 }
324
325 /***********************************************************************
326  *        RunningObjectTable_Revoke
327  */
328 HRESULT WINAPI RunningObjectTableImpl_Revoke(  IRunningObjectTable* iface,
329                                                DWORD dwRegister)  /* Value identifying registration to be revoked*/
330 {
331
332     DWORD index,j;
333     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
334
335     TRACE("(%p,%ld)\n",This,dwRegister);
336
337     /* verify if the object to be revoked was registered before or not */
338     if (RunningObjectTableImpl_GetObjectIndex(This,dwRegister,NULL,&index)==S_FALSE)
339
340         return E_INVALIDARG;
341
342     /* release the object if it was registered with a strong registrantion option */
343     if ((This->runObjTab[index].regTypeObj & ROTFLAGS_REGISTRATIONKEEPSALIVE)!=0) {
344         TRACE("releasing %p\n", This->runObjTab[index].pObj);
345         /* this is also wrong; we should always release the object (see above) */
346         IUnknown_Release(This->runObjTab[index].pObj);
347     }
348     
349     IMoniker_Release(This->runObjTab[index].pmkObj);
350
351     /* remove the object from the table */
352     for(j=index; j<This->runObjTabLastIndx-1; j++)
353         This->runObjTab[j]= This->runObjTab[j+1];
354
355     This->runObjTabLastIndx--;
356
357     return S_OK;
358 }
359
360 /***********************************************************************
361  *        RunningObjectTable_IsRunning
362  */
363 HRESULT WINAPI RunningObjectTableImpl_IsRunning(  IRunningObjectTable* iface,
364                                                   IMoniker *pmkObjectName)  /* Pointer to the moniker of the object whose status is desired */
365 {
366     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
367
368     TRACE("(%p,%p)\n",This,pmkObjectName);
369
370     return RunningObjectTableImpl_GetObjectIndex(This,-1,pmkObjectName,NULL);
371 }
372
373 /***********************************************************************
374  *        RunningObjectTable_GetObject
375  */
376 HRESULT WINAPI RunningObjectTableImpl_GetObject(  IRunningObjectTable* iface,
377                                                   IMoniker *pmkObjectName,/* Pointer to the moniker on the object */
378                                                   IUnknown **ppunkObject) /* Address of output variable that receives the IUnknown interface pointer */
379 {
380     DWORD index;
381     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
382
383     TRACE("(%p,%p,%p)\n",This,pmkObjectName,ppunkObject);
384
385     if (ppunkObject==NULL)
386         return E_POINTER;
387
388     *ppunkObject=0;
389
390     /* verify if the object was registered before or not */
391     if (RunningObjectTableImpl_GetObjectIndex(This,-1,pmkObjectName,&index)==S_FALSE) {
392         WARN("Moniker unavailable - needs to work interprocess?\n");
393         return MK_E_UNAVAILABLE;
394     }
395
396     /* add a reference to the object then set output object argument */
397     IUnknown_AddRef(This->runObjTab[index].pObj);
398     *ppunkObject=This->runObjTab[index].pObj;
399
400     return S_OK;
401 }
402
403 /***********************************************************************
404  *        RunningObjectTable_NoteChangeTime
405  */
406 HRESULT WINAPI RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface,
407                                                      DWORD dwRegister,  /* Value identifying registration being updated */
408                                                      FILETIME *pfiletime) /* Pointer to structure containing object's last change time */
409 {
410     DWORD index=-1;
411     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
412
413     TRACE("(%p,%ld,%p)\n",This,dwRegister,pfiletime);
414
415     /* verify if the object to be changed was registered before or not */
416     if (RunningObjectTableImpl_GetObjectIndex(This,dwRegister,NULL,&index)==S_FALSE)
417         return E_INVALIDARG;
418
419     /* set the new value of the last time change */
420     This->runObjTab[index].lastModifObj= (*pfiletime);
421
422     return S_OK;
423 }
424
425 /***********************************************************************
426  *        RunningObjectTable_GetTimeOfLastChange
427  */
428 HRESULT WINAPI RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface,
429                                                           IMoniker *pmkObjectName,  /* Pointer to moniker on the object whose status is desired */
430                                                           FILETIME *pfiletime)       /* Pointer to structure that receives object's last change time */
431 {
432     DWORD index=-1;
433     RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
434
435     TRACE("(%p,%p,%p)\n",This,pmkObjectName,pfiletime);
436
437     if (pmkObjectName==NULL || pfiletime==NULL)
438         return E_INVALIDARG;
439
440     /* verify if the object was registered before or not */
441     if (RunningObjectTableImpl_GetObjectIndex(This,-1,pmkObjectName,&index)==S_FALSE)
442         return MK_E_UNAVAILABLE;
443
444     (*pfiletime)= This->runObjTab[index].lastModifObj;
445
446     return S_OK;
447 }
448
449 /***********************************************************************
450  *        RunningObjectTable_EnumRunning
451  */
452 HRESULT WINAPI RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface,
453                                                   IEnumMoniker **ppenumMoniker) /* Address of output variable that receives the IEnumMoniker interface pointer */
454 {
455     FIXME("(%p,%p) needs the IEnumMoniker implementation  \n",iface,ppenumMoniker);
456     return E_NOTIMPL;
457 }
458
459 /***********************************************************************
460  *        GetObjectIndex
461  */
462 HRESULT WINAPI RunningObjectTableImpl_GetObjectIndex(RunningObjectTableImpl* This,
463                                                      DWORD identReg,
464                                                      IMoniker* pmk,
465                                                      DWORD *indx)
466 {
467
468     DWORD i;
469
470     TRACE("(%p,%ld,%p,%p)\n",This,identReg,pmk,indx);
471
472     if (pmk!=NULL)
473         /* search object identified by a moniker */
474         for(i=0 ; (i < This->runObjTabLastIndx) &&(!IMoniker_IsEqual(This->runObjTab[i].pmkObj,pmk)==S_OK);i++);
475     else
476         /* search object identified by a register identifier */
477         for(i=0;((i<This->runObjTabLastIndx)&&(This->runObjTab[i].identRegObj!=identReg));i++);
478
479     if (i==This->runObjTabLastIndx)  return S_FALSE;
480
481     if (indx != NULL)  *indx=i;
482
483     return S_OK;
484 }
485
486 /******************************************************************************
487  *              GetRunningObjectTable (OLE2.30)
488  */
489 HRESULT WINAPI GetRunningObjectTable16(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot)
490 {
491         FIXME("(%ld,%p),stub!\n",reserved,pprot);
492     return E_NOTIMPL;
493 }
494
495 /***********************************************************************
496  *           GetRunningObjectTable (OLE32.@)
497  */
498 HRESULT WINAPI GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot)
499 {
500     IID riid=IID_IRunningObjectTable;
501     HRESULT res;
502
503     TRACE("()\n");
504
505     if (reserved!=0)
506         return E_UNEXPECTED;
507
508     if(runningObjectTableInstance==NULL)
509         return CO_E_NOTINITIALIZED;
510
511     res = RunningObjectTableImpl_QueryInterface((IRunningObjectTable*)runningObjectTableInstance,&riid,(void**)pprot);
512
513     return res;
514 }
515
516 /******************************************************************************
517  *              OleRun        [OLE32.@]
518  */
519 HRESULT WINAPI OleRun(LPUNKNOWN pUnknown)
520 {
521   IRunnableObject       *runable;
522   IRunnableObject *This = (IRunnableObject *)pUnknown;
523   LRESULT               ret;
524
525   ret = IRunnableObject_QueryInterface(This,&IID_IRunnableObject,(LPVOID*)&runable);
526   if (ret)
527         return 0; /* Appears to return no error. */
528   ret  = IRunnableObject_Run(runable,NULL);
529   IRunnableObject_Release(runable);
530   return ret;
531 }
532
533 /******************************************************************************
534  *              MkParseDisplayName        [OLE32.@]
535  */
536 HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szUserName,
537                                 LPDWORD pchEaten, LPMONIKER *ppmk)
538 {
539     FIXME("(%p, %s, %p, %p): stub.\n", pbc, debugstr_w(szUserName), pchEaten, *ppmk);
540     if (!(IsValidInterface((LPUNKNOWN) pbc)))
541         return E_INVALIDARG;
542
543     return MK_E_SYNTAX;
544 }
545
546 /******************************************************************************
547  *              CreateClassMoniker        [OLE32.@]
548  */
549  HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker ** ppmk)
550  {
551      FIXME("%s\n", debugstr_guid( rclsid ));
552      if( ppmk )
553          *ppmk = NULL;
554      return E_NOTIMPL;
555  }