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