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