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