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