widl: Always check the runtimeclass interfaces presence.
[wine/zf.git] / dlls / ole32 / bindctx.c
blob24229568f18cdcec2be2d18faa6ad7d60d9944a5
1 /*
2 * BindCtx implementation
4 * Copyright 1999 Noomen Hamza
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.
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.
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
21 #include <stdarg.h>
22 #include <string.h>
24 #define COBJMACROS
26 #include "winerror.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winnls.h"
30 #include "objbase.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36 #define BINDCTX_FIRST_TABLE_SIZE 4
38 /* data structure of the BindCtx table elements */
39 typedef struct BindCtxObject{
41 IUnknown* pObj; /* point on a bound object */
43 LPOLESTR pkeyObj; /* key associated to this bound object */
45 BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */
47 } BindCtxObject;
49 /* BindCtx data structure */
50 typedef struct BindCtxImpl{
52 IBindCtx IBindCtx_iface;
54 LONG ref; /* reference counter for this object */
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 */
60 BIND_OPTS3 options;
62 } BindCtxImpl;
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 *);
69 static inline BindCtxImpl *impl_from_IBindCtx(IBindCtx *iface)
71 return CONTAINING_RECORD(iface, BindCtxImpl, IBindCtx_iface);
74 /*******************************************************************************
75 * BindCtx_QueryInterface
76 *******************************************************************************/
77 static HRESULT WINAPI
78 BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject)
80 BindCtxImpl *This = impl_from_IBindCtx(iface);
82 TRACE("(%p %s %p)\n",This, debugstr_guid(riid), ppvObject);
84 /* Perform a sanity check on the parameters.*/
85 if (!ppvObject)
86 return E_POINTER;
88 /* Initialize the return parameter.*/
89 *ppvObject = 0;
91 /* Compare the riid with the interface IDs implemented by this object.*/
92 if (IsEqualIID(&IID_IUnknown, riid) ||
93 IsEqualIID(&IID_IBindCtx, riid))
95 *ppvObject = &This->IBindCtx_iface;
96 IBindCtx_AddRef(iface);
97 return S_OK;
100 return E_NOINTERFACE;
103 /******************************************************************************
104 * BindCtx_AddRef
105 ******************************************************************************/
106 static ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface)
108 BindCtxImpl *This = impl_from_IBindCtx(iface);
110 TRACE("(%p)\n",This);
112 return InterlockedIncrement(&This->ref);
115 /******************************************************************************
116 * BindCtx_Destroy (local function)
117 *******************************************************************************/
118 static HRESULT BindCtxImpl_Destroy(BindCtxImpl* This)
120 TRACE("(%p)\n",This);
122 /* free the table space memory */
123 HeapFree(GetProcessHeap(),0,This->bindCtxTable);
125 /* free the bindctx structure */
126 HeapFree(GetProcessHeap(),0,This);
128 return S_OK;
131 /******************************************************************************
132 * BindCtx_Release
133 ******************************************************************************/
134 static ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface)
136 BindCtxImpl *This = impl_from_IBindCtx(iface);
137 ULONG ref;
139 TRACE("(%p)\n",This);
141 ref = InterlockedDecrement(&This->ref);
142 if (ref == 0)
144 /* release all registered objects */
145 BindCtxImpl_ReleaseBoundObjects(&This->IBindCtx_iface);
147 BindCtxImpl_Destroy(This);
149 return ref;
153 /******************************************************************************
154 * BindCtx_RegisterObjectBound
155 ******************************************************************************/
156 static HRESULT WINAPI
157 BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk)
159 BindCtxImpl *This = impl_from_IBindCtx(iface);
160 DWORD lastIndex=This->bindCtxTableLastIndex;
162 TRACE("(%p,%p)\n",This,punk);
164 if (punk==NULL)
165 return S_OK;
167 if (lastIndex == This->bindCtxTableSize)
169 HRESULT hr = BindCtxImpl_ExpandTable(This);
170 if (FAILED(hr))
171 return hr;
174 IUnknown_AddRef(punk);
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;
182 return S_OK;
185 /******************************************************************************
186 * BindCtx_RevokeObjectBound
187 ******************************************************************************/
188 static HRESULT WINAPI
189 BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk)
191 DWORD index,j;
193 BindCtxImpl *This = impl_from_IBindCtx(iface);
195 TRACE("(%p,%p)\n",This,punk);
197 if (!punk)
198 return E_INVALIDARG;
200 /* check if the object was registered or not */
201 if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE)
202 return MK_E_NOTBOUND;
204 if(This->bindCtxTable[index].pObj)
205 IUnknown_Release(This->bindCtxTable[index].pObj);
206 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
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];
212 This->bindCtxTableLastIndex--;
214 return S_OK;
217 /******************************************************************************
218 * BindCtx_ReleaseBoundObjects
219 ******************************************************************************/
220 static HRESULT WINAPI
221 BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface)
223 DWORD i;
225 BindCtxImpl *This = impl_from_IBindCtx(iface);
227 TRACE("(%p)\n",This);
229 for(i=0;i<This->bindCtxTableLastIndex;i++)
231 if(This->bindCtxTable[i].pObj)
232 IUnknown_Release(This->bindCtxTable[i].pObj);
233 HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj);
236 This->bindCtxTableLastIndex = 0;
238 return S_OK;
241 /******************************************************************************
242 * BindCtx_SetBindOptions
243 ******************************************************************************/
244 static HRESULT WINAPI
245 BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
247 BindCtxImpl *This = impl_from_IBindCtx(iface);
249 TRACE("(%p,%p)\n",This, pbindopts);
251 if (pbindopts==NULL)
252 return E_POINTER;
254 if (pbindopts->cbStruct > sizeof(This->options))
256 WARN("invalid size %u.\n", pbindopts->cbStruct);
257 return E_INVALIDARG;
259 memcpy(&This->options, pbindopts, pbindopts->cbStruct);
260 return S_OK;
263 /******************************************************************************
264 * BindCtx_GetBindOptions
265 ******************************************************************************/
266 static HRESULT WINAPI
267 BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
269 BindCtxImpl *This = impl_from_IBindCtx(iface);
270 DWORD size;
272 TRACE("(%p,%p)\n",This,pbindopts);
274 if (pbindopts==NULL)
275 return E_POINTER;
277 size = min(pbindopts->cbStruct, sizeof(This->options));
278 memcpy(pbindopts, &This->options, size);
279 pbindopts->cbStruct = size;
281 return S_OK;
284 /******************************************************************************
285 * BindCtx_GetRunningObjectTable
286 ******************************************************************************/
287 static HRESULT WINAPI
288 BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot)
290 BindCtxImpl *This = impl_from_IBindCtx(iface);
292 TRACE("(%p,%p)\n",This,pprot);
294 if (pprot==NULL)
295 return E_POINTER;
297 return GetRunningObjectTable(0, pprot);
300 /******************************************************************************
301 * BindCtx_RegisterObjectParam
302 ******************************************************************************/
303 static HRESULT WINAPI
304 BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
306 DWORD index=0;
307 BindCtxImpl *This = impl_from_IBindCtx(iface);
309 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
311 if (punk==NULL)
312 return E_INVALIDARG;
314 if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK)
316 TRACE("Overwriting existing key\n");
317 if(This->bindCtxTable[index].pObj!=NULL)
318 IUnknown_Release(This->bindCtxTable[index].pObj);
319 This->bindCtxTable[index].pObj=punk;
320 IUnknown_AddRef(punk);
321 return S_OK;
324 if (This->bindCtxTableLastIndex == This->bindCtxTableSize)
326 HRESULT hr = BindCtxImpl_ExpandTable(This);
327 if (FAILED(hr))
328 return hr;
331 This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk;
332 This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1;
334 if (pszkey==NULL)
336 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL;
338 else
341 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=
342 HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey))));
344 if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL)
345 return E_OUTOFMEMORY;
346 lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey);
349 This->bindCtxTableLastIndex++;
351 IUnknown_AddRef(punk);
352 return S_OK;
355 /******************************************************************************
356 * BindCtx_GetObjectParam
357 ******************************************************************************/
358 static HRESULT WINAPI
359 BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
361 DWORD index;
362 BindCtxImpl *This = impl_from_IBindCtx(iface);
364 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
366 if (punk==NULL)
367 return E_POINTER;
369 *punk=0;
371 if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
372 return E_FAIL;
374 IUnknown_AddRef(This->bindCtxTable[index].pObj);
376 *punk = This->bindCtxTable[index].pObj;
378 return S_OK;
381 /******************************************************************************
382 * BindCtx_RevokeObjectParam
383 ******************************************************************************/
384 static HRESULT WINAPI
385 BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
387 DWORD index,j;
389 BindCtxImpl *This = impl_from_IBindCtx(iface);
391 TRACE("(%p,%s)\n",This,debugstr_w(ppenum));
393 if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
394 return E_FAIL;
396 /* release the object if it's found */
397 if(This->bindCtxTable[index].pObj)
398 IUnknown_Release(This->bindCtxTable[index].pObj);
399 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
401 /* remove the object from the table with a left-shifting of all objects in the right side */
402 for(j=index; j<This->bindCtxTableLastIndex-1; j++)
403 This->bindCtxTable[j]= This->bindCtxTable[j+1];
405 This->bindCtxTableLastIndex--;
407 return S_OK;
410 /******************************************************************************
411 * BindCtx_EnumObjectParam
412 ******************************************************************************/
413 static HRESULT WINAPI
414 BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
416 TRACE("(%p,%p)\n",iface,pszkey);
418 *pszkey = NULL;
420 /* not implemented in native either */
421 return E_NOTIMPL;
424 /********************************************************************************
425 * GetObjectIndex (local function)
426 ********************************************************************************/
427 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
428 IUnknown* punk,
429 LPOLESTR pszkey,
430 DWORD *index)
432 DWORD i;
433 BOOL found = FALSE;
435 TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
437 if (punk==NULL)
438 /* search object identified by a register key */
439 for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
441 if(This->bindCtxTable[i].regType==1){
443 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
444 ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
445 (pszkey!=NULL) &&
446 (wcscmp(This->bindCtxTable[i].pkeyObj,pszkey)==0)
450 found = TRUE;
453 else
454 /* search object identified by a moniker*/
455 for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
456 if(This->bindCtxTable[i].pObj==punk)
457 found = TRUE;
459 if (index != NULL)
460 *index=i-1;
462 if (found)
463 return S_OK;
464 TRACE("key not found\n");
465 return S_FALSE;
468 static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *This)
470 if (!This->bindCtxTableSize)
472 This->bindCtxTableSize = BINDCTX_FIRST_TABLE_SIZE;
473 This->bindCtxTable = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
474 This->bindCtxTableSize * sizeof(BindCtxObject));
476 else
478 This->bindCtxTableSize *= 2;
480 This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
481 This->bindCtxTableSize * sizeof(BindCtxObject));
484 if (!This->bindCtxTable)
485 return E_OUTOFMEMORY;
487 return S_OK;
491 /* Virtual function table for the BindCtx class. */
492 static const IBindCtxVtbl VT_BindCtxImpl =
494 BindCtxImpl_QueryInterface,
495 BindCtxImpl_AddRef,
496 BindCtxImpl_Release,
497 BindCtxImpl_RegisterObjectBound,
498 BindCtxImpl_RevokeObjectBound,
499 BindCtxImpl_ReleaseBoundObjects,
500 BindCtxImpl_SetBindOptions,
501 BindCtxImpl_GetBindOptions,
502 BindCtxImpl_GetRunningObjectTable,
503 BindCtxImpl_RegisterObjectParam,
504 BindCtxImpl_GetObjectParam,
505 BindCtxImpl_EnumObjectParam,
506 BindCtxImpl_RevokeObjectParam
509 /******************************************************************************
510 * BindCtx_Construct (local function)
511 *******************************************************************************/
512 static HRESULT BindCtxImpl_Construct(BindCtxImpl* This)
514 TRACE("(%p)\n",This);
516 /* Initialize the virtual function table.*/
517 This->IBindCtx_iface.lpVtbl = &VT_BindCtxImpl;
518 This->ref = 0;
520 memset(&This->options, 0, sizeof(This->options));
521 This->options.cbStruct = sizeof(This->options);
522 This->options.grfMode = STGM_READWRITE;
523 This->options.dwClassContext = CLSCTX_SERVER;
524 This->options.locale = GetThreadLocale();
526 /* Initialize the bindctx table */
527 This->bindCtxTableSize=0;
528 This->bindCtxTableLastIndex=0;
529 This->bindCtxTable = NULL;
531 return S_OK;
534 /******************************************************************************
535 * CreateBindCtx (OLE32.@)
537 * Creates a bind context. A bind context encompasses information and options
538 * used when binding to a moniker.
540 * PARAMS
541 * reserved [I] Reserved. Set to 0.
542 * ppbc [O] Address that receives the bind context object.
544 * RETURNS
545 * Success: S_OK.
546 * Failure: Any HRESULT code.
548 HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
550 BindCtxImpl* newBindCtx;
551 HRESULT hr;
553 TRACE("(%d,%p)\n",reserved,ppbc);
555 if (!ppbc) return E_INVALIDARG;
557 *ppbc = NULL;
559 if (reserved != 0)
561 ERR("reserved should be 0, not 0x%x\n", reserved);
562 return E_INVALIDARG;
565 newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl));
566 if (newBindCtx == 0)
567 return E_OUTOFMEMORY;
569 hr = BindCtxImpl_Construct(newBindCtx);
570 if (FAILED(hr))
572 HeapFree(GetProcessHeap(),0,newBindCtx);
573 return hr;
576 return BindCtxImpl_QueryInterface(&newBindCtx->IBindCtx_iface,&IID_IBindCtx,(void**)ppbc);
579 /******************************************************************************
580 * BindMoniker [OLE32.@]
582 * Binds to a moniker.
584 * PARAMS
585 * pmk [I] Moniker to bind to.
586 * grfOpt [I] Reserved option flags. Set to 0.
587 * riid [I] ID of the interface to bind to.
588 * pvResult [O] Address that receives the interface of the object that was bound to.
590 * RETURNS
591 * Success: S_OK.
592 * Failure: Any HRESULT code.
594 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
596 HRESULT res;
597 IBindCtx * pbc;
599 TRACE("(%p, %x, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
601 res = CreateBindCtx(grfOpt, &pbc);
602 if (SUCCEEDED(res))
604 res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
605 IBindCtx_Release(pbc);
607 return res;