- Add a generic moniker marshaler that works by saving & loading
[wine] / dlls / ole32 / bindctx.c
1 /***************************************************************************************
2  *                            BindCtx implementation
3  *
4  *  Copyright 1999  Noomen Hamza
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  ***************************************************************************************/
20
21 #include <stdarg.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #define COBJMACROS
26
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(ole);
34
35 /* represent the first size table and it's increment block size */
36 #define  BLOCK_TAB_SIZE 10
37 #define  MAX_TAB_SIZE   0xFFFFFFFF
38
39 /* data structure of the BindCtx table elements */
40 typedef struct BindCtxObject{
41
42     IUnknown*   pObj; /* point on a bound object */
43
44     LPOLESTR  pkeyObj; /* key associated to this bound object */
45
46     BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */
47
48 } BindCtxObject;
49
50 /* BindCtx data strucrture */
51 typedef struct BindCtxImpl{
52
53     IBindCtxVtbl *lpVtbl; /* VTable relative to the IBindCtx interface.*/
54
55     ULONG ref; /* reference counter for this object */
56
57     BindCtxObject* bindCtxTable; /* this is a table in which all bounded objects are stored*/
58     DWORD          bindCtxTableLastIndex;  /* first free index in the table */
59     DWORD          bindCtxTableSize;   /* size table */
60
61     BIND_OPTS2 bindOption2; /* a structure which contains the bind options*/
62
63 } BindCtxImpl;
64
65 /* IBindCtx prototype functions : */
66 static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx*);
67 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl*, IUnknown*, LPOLESTR, DWORD *);
68
69 /*******************************************************************************
70  *        BindCtx_QueryInterface
71  *******************************************************************************/
72 static HRESULT WINAPI
73 BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject)
74 {
75     BindCtxImpl *This = (BindCtxImpl *)iface;
76
77     TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
78
79     /* Perform a sanity check on the parameters.*/
80     if ( (This==0) || (ppvObject==0) )
81         return E_INVALIDARG;
82
83     /* Initialize the return parameter.*/
84     *ppvObject = 0;
85
86     /* Compare the riid with the interface IDs implemented by this object.*/
87     if (IsEqualIID(&IID_IUnknown, riid) ||
88         IsEqualIID(&IID_IBindCtx, riid))
89     {
90         *ppvObject = (IBindCtx*)This;
91         IBindCtx_AddRef(iface);
92         return S_OK;
93     }
94
95     return E_NOINTERFACE;
96 }
97
98 /******************************************************************************
99  *       BindCtx_AddRef
100  ******************************************************************************/
101 static ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface)
102 {
103     BindCtxImpl *This = (BindCtxImpl *)iface;
104
105     TRACE("(%p)\n",This);
106
107     return InterlockedIncrement(&This->ref);
108 }
109
110 /******************************************************************************
111  *        BindCtx_Destroy    (local function)
112  *******************************************************************************/
113 static HRESULT BindCtxImpl_Destroy(BindCtxImpl* This)
114 {
115     TRACE("(%p)\n",This);
116
117     /* free the table space memory */
118     HeapFree(GetProcessHeap(),0,This->bindCtxTable);
119
120     /* free the bindctx structure */
121     HeapFree(GetProcessHeap(),0,This);
122
123     return S_OK;
124 }
125
126 /******************************************************************************
127  *        BindCtx_Release
128  ******************************************************************************/
129 static ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface)
130 {
131     BindCtxImpl *This = (BindCtxImpl *)iface;
132     ULONG ref;
133
134     TRACE("(%p)\n",This);
135
136     ref = InterlockedDecrement(&This->ref);
137     if (ref == 0)
138     {
139         /* release all registered objects */
140         BindCtxImpl_ReleaseBoundObjects((IBindCtx*)This);
141
142         BindCtxImpl_Destroy(This);
143     }
144     return ref;
145 }
146
147
148 /******************************************************************************
149  *        BindCtx_RegisterObjectBound
150  ******************************************************************************/
151 static HRESULT WINAPI
152 BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk)
153 {
154     BindCtxImpl *This = (BindCtxImpl *)iface;
155     DWORD lastIndex=This->bindCtxTableLastIndex;
156
157     TRACE("(%p,%p)\n",This,punk);
158
159     if (punk==NULL)
160         return E_POINTER;
161
162     IUnknown_AddRef(punk);
163
164     /* put the object in the first free element in the table */
165     This->bindCtxTable[lastIndex].pObj = punk;
166     This->bindCtxTable[lastIndex].pkeyObj = NULL;
167     This->bindCtxTable[lastIndex].regType = 0;
168     lastIndex= ++This->bindCtxTableLastIndex;
169
170     if (lastIndex == This->bindCtxTableSize){ /* the table is full so it must be resized */
171
172         if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){
173             FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize);
174             return E_FAIL;
175         }
176
177         This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
178
179         This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
180                                          This->bindCtxTableSize * sizeof(BindCtxObject));
181         if (!This->bindCtxTable)
182             return E_OUTOFMEMORY;
183     }
184     return S_OK;
185 }
186
187 /******************************************************************************
188  *        BindCtx_RevokeObjectBound
189  ******************************************************************************/
190 static HRESULT WINAPI
191 BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk)
192 {
193     DWORD index,j;
194
195     BindCtxImpl *This = (BindCtxImpl *)iface;
196
197     TRACE("(%p,%p)\n",This,punk);
198
199     /* check if the object was registered or not */
200     if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE)
201         return MK_E_NOTBOUND;
202
203     if(This->bindCtxTable[index].pObj)
204         IUnknown_Release(This->bindCtxTable[index].pObj);
205     HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
206     
207     /* left-shift all elements in the right side of the current revoked object */
208     for(j=index; j<This->bindCtxTableLastIndex-1; j++)
209         This->bindCtxTable[j]= This->bindCtxTable[j+1];
210
211     This->bindCtxTableLastIndex--;
212
213     return S_OK;
214 }
215
216 /******************************************************************************
217  *        BindCtx_ReleaseBoundObjects
218  ******************************************************************************/
219 static HRESULT WINAPI
220 BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface)
221 {
222     DWORD i;
223
224     BindCtxImpl *This = (BindCtxImpl *)iface;
225
226     TRACE("(%p)\n",This);
227
228     for(i=0;i<This->bindCtxTableLastIndex;i++)
229     {
230         if(This->bindCtxTable[i].pObj)
231             IUnknown_Release(This->bindCtxTable[i].pObj);
232         HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj);
233     }
234     
235     This->bindCtxTableLastIndex = 0;
236
237     return S_OK;
238 }
239
240 /******************************************************************************
241  *        BindCtx_SetBindOptions
242  ******************************************************************************/
243 static HRESULT WINAPI
244 BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
245 {
246     BindCtxImpl *This = (BindCtxImpl *)iface;
247
248     TRACE("(%p,%p)\n",This,pbindopts);
249
250     if (pbindopts==NULL)
251         return E_POINTER;
252
253     if (pbindopts->cbStruct > sizeof(BIND_OPTS2))
254     {
255         WARN("invalid size\n");
256         return E_INVALIDARG; /* FIXME : not verified */
257     }
258     memcpy(&This->bindOption2, pbindopts, pbindopts->cbStruct);
259     return S_OK;
260 }
261
262 /******************************************************************************
263  *        BindCtx_GetBindOptions
264  ******************************************************************************/
265 static HRESULT WINAPI
266 BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
267 {
268     BindCtxImpl *This = (BindCtxImpl *)iface;
269
270     TRACE("(%p,%p)\n",This,pbindopts);
271
272     if (pbindopts==NULL)
273         return E_POINTER;
274
275     if (pbindopts->cbStruct > sizeof(BIND_OPTS2))
276     {
277         WARN("invalid size\n");
278         return E_INVALIDARG; /* FIXME : not verified */
279     }
280     memcpy(pbindopts, &This->bindOption2, pbindopts->cbStruct);
281     return S_OK;
282 }
283
284 /******************************************************************************
285  *        BindCtx_GetRunningObjectTable
286  ******************************************************************************/
287 static HRESULT WINAPI
288 BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot)
289 {
290     HRESULT res;
291
292     BindCtxImpl *This = (BindCtxImpl *)iface;
293
294     TRACE("(%p,%p)\n",This,pprot);
295
296     if (pprot==NULL)
297         return E_POINTER;
298
299     res=GetRunningObjectTable(0, pprot);
300
301     return res;
302 }
303
304 /******************************************************************************
305  *        BindCtx_RegisterObjectParam
306  ******************************************************************************/
307 static HRESULT WINAPI
308 BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
309 {
310     DWORD index=0;
311     BindCtxImpl *This = (BindCtxImpl *)iface;
312
313     TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
314
315     if (punk==NULL)
316         return E_INVALIDARG;
317
318     if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK)
319     {
320         TRACE("Overwriting existing key\n");
321         if(This->bindCtxTable[index].pObj!=NULL)
322             IUnknown_Release(This->bindCtxTable[index].pObj);
323         This->bindCtxTable[index].pObj=punk;
324         IUnknown_AddRef(punk);
325         return S_OK;
326     }
327     This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk;
328     This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1;
329
330     if (pszkey==NULL)
331
332         This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL;
333
334     else
335     {
336
337         This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=
338             HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey))));
339
340         if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL)
341             return E_OUTOFMEMORY;
342         lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey);
343     }
344
345     This->bindCtxTableLastIndex++;
346
347     if (This->bindCtxTableLastIndex == This->bindCtxTableSize)
348     {
349         /* table is full ! must be resized */
350
351         This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
352         if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE))
353         {
354             FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize);
355             return E_FAIL;
356         }
357         This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
358                                          This->bindCtxTableSize * sizeof(BindCtxObject));
359         if (!This->bindCtxTable)
360             return E_OUTOFMEMORY;
361     }
362     IUnknown_AddRef(punk);
363     return S_OK;
364 }
365
366 /******************************************************************************
367  *        BindCtx_GetObjectParam
368  ******************************************************************************/
369 static HRESULT WINAPI
370 BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
371 {
372     DWORD index;
373     BindCtxImpl *This = (BindCtxImpl *)iface;
374
375     TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
376
377     if (punk==NULL)
378         return E_POINTER;
379
380     *punk=0;
381
382     if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
383         return E_FAIL;
384
385     IUnknown_AddRef(This->bindCtxTable[index].pObj);
386
387     *punk = This->bindCtxTable[index].pObj;
388
389     return S_OK;
390 }
391
392 /******************************************************************************
393  *        BindCtx_RevokeObjectParam
394  ******************************************************************************/
395 static HRESULT WINAPI
396 BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
397 {
398     DWORD index,j;
399
400     BindCtxImpl *This = (BindCtxImpl *)iface;
401
402     TRACE("(%p,%s)\n",This,debugstr_w(ppenum));
403
404     if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
405         return E_FAIL;
406
407     /* release the object if it's found */
408     if(This->bindCtxTable[index].pObj)
409         IUnknown_Release(This->bindCtxTable[index].pObj);
410     HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
411     
412     /* remove the object from the table with a left-shifting of all objects in the right side */
413     for(j=index; j<This->bindCtxTableLastIndex-1; j++)
414         This->bindCtxTable[j]= This->bindCtxTable[j+1];
415
416     This->bindCtxTableLastIndex--;
417
418     return S_OK;
419 }
420
421 /******************************************************************************
422  *        BindCtx_EnumObjectParam
423  ******************************************************************************/
424 static HRESULT WINAPI
425 BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
426 {
427     FIXME("(%p,%p),stub!\n",iface,pszkey);
428     return E_NOTIMPL;
429 }
430
431 /********************************************************************************
432  *        GetObjectIndex (local function)
433  ********************************************************************************/
434 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
435                                           IUnknown* punk,
436                                           LPOLESTR pszkey,
437                                           DWORD *index)
438 {
439
440     DWORD i;
441     BYTE found=0;
442
443     TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
444
445     if (punk==NULL)
446         /* search object identified by a register key */
447         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
448         {
449             if(This->bindCtxTable[i].regType==1){
450
451                 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
452                      ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
453                        (pszkey!=NULL) &&
454                        (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0)
455                      )
456                    )
457
458                     found=1;
459             }
460         }
461     else
462         /* search object identified by a moniker*/
463         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
464             if(This->bindCtxTable[i].pObj==punk)
465                 found=1;
466
467     if (index != NULL)
468         *index=i-1;
469
470     if (found)
471         return S_OK;
472     TRACE("key not found\n");
473     return S_FALSE;
474 }
475
476 /* Virtual function table for the BindCtx class. */
477 static IBindCtxVtbl VT_BindCtxImpl =
478 {
479     BindCtxImpl_QueryInterface,
480     BindCtxImpl_AddRef,
481     BindCtxImpl_Release,
482     BindCtxImpl_RegisterObjectBound,
483     BindCtxImpl_RevokeObjectBound,
484     BindCtxImpl_ReleaseBoundObjects,
485     BindCtxImpl_SetBindOptions,
486     BindCtxImpl_GetBindOptions,
487     BindCtxImpl_GetRunningObjectTable,
488     BindCtxImpl_RegisterObjectParam,
489     BindCtxImpl_GetObjectParam,
490     BindCtxImpl_EnumObjectParam,
491     BindCtxImpl_RevokeObjectParam
492 };
493
494 /******************************************************************************
495  *         BindCtx_Construct (local function)
496  *******************************************************************************/
497 static HRESULT BindCtxImpl_Construct(BindCtxImpl* This)
498 {
499     TRACE("(%p)\n",This);
500
501     /* Initialize the virtual function table.*/
502     This->lpVtbl       = &VT_BindCtxImpl;
503     This->ref          = 0;
504
505     /* Initialize the BIND_OPTS2 structure */
506     This->bindOption2.cbStruct  = sizeof(BIND_OPTS2);
507     This->bindOption2.grfFlags = 0;
508     This->bindOption2.grfMode = STGM_READWRITE;
509     This->bindOption2.dwTickCountDeadline = 0;
510
511     This->bindOption2.dwTrackFlags = 0;
512     This->bindOption2.dwClassContext = CLSCTX_SERVER;
513     This->bindOption2.locale = 1033;
514     This->bindOption2.pServerInfo = 0;
515
516     /* Initialize the bindctx table */
517     This->bindCtxTableSize=BLOCK_TAB_SIZE;
518     This->bindCtxTableLastIndex=0;
519     This->bindCtxTable = HeapAlloc(GetProcessHeap(), 0,
520                                 This->bindCtxTableSize*sizeof(BindCtxObject));
521
522     if (This->bindCtxTable==NULL)
523         return E_OUTOFMEMORY;
524
525     return S_OK;
526 }
527
528 /******************************************************************************
529  *        CreateBindCtx16
530  ******************************************************************************/
531 HRESULT WINAPI CreateBindCtx16(DWORD reserved, LPBC * ppbc)
532 {
533     FIXME("(%ld,%p),stub!\n",reserved,ppbc);
534     return E_NOTIMPL;
535 }
536
537 /******************************************************************************
538  *        CreateBindCtx (OLE32.@)
539  ******************************************************************************/
540 HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
541 {
542     BindCtxImpl* newBindCtx = 0;
543     HRESULT hr;
544     IID riid=IID_IBindCtx;
545
546     TRACE("(%ld,%p)\n",reserved,ppbc);
547
548     newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl));
549     if (newBindCtx == 0)
550         return E_OUTOFMEMORY;
551
552     hr = BindCtxImpl_Construct(newBindCtx);
553     if (FAILED(hr))
554     {
555         HeapFree(GetProcessHeap(),0,newBindCtx);
556         return hr;
557     }
558
559     hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc);
560
561     return hr;
562 }
563
564 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
565 {
566     HRESULT res;
567     IBindCtx * pbc;
568
569     TRACE("(%p, %lx, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
570
571     res = CreateBindCtx(grfOpt, &pbc);
572     if (SUCCEEDED(res))
573         res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
574     return res;
575 }