gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / ole32 / bindctx.c
blob360464d13c5b32477a9757fbe3f85c93fb92ce07
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"
33 #include "wine/heap.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 #define BINDCTX_FIRST_TABLE_SIZE 4
39 /* data structure of the BindCtx table elements */
40 typedef struct BindCtxObject{
42 IUnknown* pObj; /* point on a bound object */
44 LPOLESTR pkeyObj; /* key associated to this bound object */
46 BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */
48 } BindCtxObject;
50 /* BindCtx data structure */
51 typedef struct BindCtxImpl{
53 IBindCtx IBindCtx_iface;
55 LONG ref; /* reference counter for this object */
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 */
61 BIND_OPTS3 options;
63 } BindCtxImpl;
65 /* IBindCtx prototype functions : */
66 static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx*);
67 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl*, IUnknown*, LPOLESTR, DWORD *);
68 static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *);
70 static inline BindCtxImpl *impl_from_IBindCtx(IBindCtx *iface)
72 return CONTAINING_RECORD(iface, BindCtxImpl, IBindCtx_iface);
75 /*******************************************************************************
76 * BindCtx_QueryInterface
77 *******************************************************************************/
78 static HRESULT WINAPI
79 BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject)
81 BindCtxImpl *This = impl_from_IBindCtx(iface);
83 TRACE("(%p %s %p)\n",This, debugstr_guid(riid), ppvObject);
85 /* Perform a sanity check on the parameters.*/
86 if (!ppvObject)
87 return E_POINTER;
89 /* Initialize the return parameter.*/
90 *ppvObject = 0;
92 /* Compare the riid with the interface IDs implemented by this object.*/
93 if (IsEqualIID(&IID_IUnknown, riid) ||
94 IsEqualIID(&IID_IBindCtx, riid))
96 *ppvObject = &This->IBindCtx_iface;
97 IBindCtx_AddRef(iface);
98 return S_OK;
101 return E_NOINTERFACE;
104 /******************************************************************************
105 * BindCtx_AddRef
106 ******************************************************************************/
107 static ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface)
109 BindCtxImpl *This = impl_from_IBindCtx(iface);
111 TRACE("(%p)\n",This);
113 return InterlockedIncrement(&This->ref);
116 static ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface)
118 BindCtxImpl *context = impl_from_IBindCtx(iface);
119 ULONG refcount = InterlockedDecrement(&context->ref);
121 TRACE("%p, refcount %lu.\n", iface, refcount);
123 if (!refcount)
125 BindCtxImpl_ReleaseBoundObjects(&context->IBindCtx_iface);
126 heap_free(context->bindCtxTable);
127 heap_free(context);
130 return refcount;
134 /******************************************************************************
135 * BindCtx_RegisterObjectBound
136 ******************************************************************************/
137 static HRESULT WINAPI
138 BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk)
140 BindCtxImpl *This = impl_from_IBindCtx(iface);
141 DWORD lastIndex=This->bindCtxTableLastIndex;
143 TRACE("(%p,%p)\n",This,punk);
145 if (punk==NULL)
146 return S_OK;
148 if (lastIndex == This->bindCtxTableSize)
150 HRESULT hr = BindCtxImpl_ExpandTable(This);
151 if (FAILED(hr))
152 return hr;
155 IUnknown_AddRef(punk);
157 /* put the object in the first free element in the table */
158 This->bindCtxTable[lastIndex].pObj = punk;
159 This->bindCtxTable[lastIndex].pkeyObj = NULL;
160 This->bindCtxTable[lastIndex].regType = 0;
161 lastIndex= ++This->bindCtxTableLastIndex;
163 return S_OK;
166 /******************************************************************************
167 * BindCtx_RevokeObjectBound
168 ******************************************************************************/
169 static HRESULT WINAPI
170 BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk)
172 DWORD index,j;
174 BindCtxImpl *This = impl_from_IBindCtx(iface);
176 TRACE("(%p,%p)\n",This,punk);
178 if (!punk)
179 return E_INVALIDARG;
181 /* check if the object was registered or not */
182 if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE)
183 return MK_E_NOTBOUND;
185 if(This->bindCtxTable[index].pObj)
186 IUnknown_Release(This->bindCtxTable[index].pObj);
187 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
189 /* left-shift all elements in the right side of the current revoked object */
190 for(j=index; j<This->bindCtxTableLastIndex-1; j++)
191 This->bindCtxTable[j]= This->bindCtxTable[j+1];
193 This->bindCtxTableLastIndex--;
195 return S_OK;
198 /******************************************************************************
199 * BindCtx_ReleaseBoundObjects
200 ******************************************************************************/
201 static HRESULT WINAPI
202 BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface)
204 DWORD i;
206 BindCtxImpl *This = impl_from_IBindCtx(iface);
208 TRACE("(%p)\n",This);
210 for(i=0;i<This->bindCtxTableLastIndex;i++)
212 if(This->bindCtxTable[i].pObj)
213 IUnknown_Release(This->bindCtxTable[i].pObj);
214 HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj);
217 This->bindCtxTableLastIndex = 0;
219 return S_OK;
222 /******************************************************************************
223 * BindCtx_SetBindOptions
224 ******************************************************************************/
225 static HRESULT WINAPI
226 BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
228 BindCtxImpl *This = impl_from_IBindCtx(iface);
230 TRACE("(%p,%p)\n",This, pbindopts);
232 if (pbindopts==NULL)
233 return E_POINTER;
235 if (pbindopts->cbStruct > sizeof(This->options))
237 WARN("invalid size %lu.\n", pbindopts->cbStruct);
238 return E_INVALIDARG;
240 memcpy(&This->options, pbindopts, pbindopts->cbStruct);
241 return S_OK;
244 /******************************************************************************
245 * BindCtx_GetBindOptions
246 ******************************************************************************/
247 static HRESULT WINAPI
248 BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
250 BindCtxImpl *This = impl_from_IBindCtx(iface);
251 DWORD size;
253 TRACE("(%p,%p)\n",This,pbindopts);
255 if (pbindopts==NULL)
256 return E_POINTER;
258 size = min(pbindopts->cbStruct, sizeof(This->options));
259 memcpy(pbindopts, &This->options, size);
260 pbindopts->cbStruct = size;
262 return S_OK;
265 /******************************************************************************
266 * BindCtx_GetRunningObjectTable
267 ******************************************************************************/
268 static HRESULT WINAPI
269 BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot)
271 BindCtxImpl *This = impl_from_IBindCtx(iface);
273 TRACE("(%p,%p)\n",This,pprot);
275 if (pprot==NULL)
276 return E_POINTER;
278 return GetRunningObjectTable(0, pprot);
281 /******************************************************************************
282 * BindCtx_RegisterObjectParam
283 ******************************************************************************/
284 static HRESULT WINAPI
285 BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
287 DWORD index=0;
288 BindCtxImpl *This = impl_from_IBindCtx(iface);
290 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
292 if (punk==NULL)
293 return E_INVALIDARG;
295 if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK)
297 TRACE("Overwriting existing key\n");
298 if(This->bindCtxTable[index].pObj!=NULL)
299 IUnknown_Release(This->bindCtxTable[index].pObj);
300 This->bindCtxTable[index].pObj=punk;
301 IUnknown_AddRef(punk);
302 return S_OK;
305 if (This->bindCtxTableLastIndex == This->bindCtxTableSize)
307 HRESULT hr = BindCtxImpl_ExpandTable(This);
308 if (FAILED(hr))
309 return hr;
312 This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk;
313 This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1;
315 if (pszkey==NULL)
317 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL;
319 else
322 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=
323 HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey))));
325 if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL)
326 return E_OUTOFMEMORY;
327 lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey);
330 This->bindCtxTableLastIndex++;
332 IUnknown_AddRef(punk);
333 return S_OK;
336 /******************************************************************************
337 * BindCtx_GetObjectParam
338 ******************************************************************************/
339 static HRESULT WINAPI
340 BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
342 DWORD index;
343 BindCtxImpl *This = impl_from_IBindCtx(iface);
345 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
347 if (punk==NULL)
348 return E_POINTER;
350 *punk=0;
352 if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
353 return E_FAIL;
355 IUnknown_AddRef(This->bindCtxTable[index].pObj);
357 *punk = This->bindCtxTable[index].pObj;
359 return S_OK;
362 /******************************************************************************
363 * BindCtx_RevokeObjectParam
364 ******************************************************************************/
365 static HRESULT WINAPI
366 BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
368 DWORD index,j;
370 BindCtxImpl *This = impl_from_IBindCtx(iface);
372 TRACE("(%p,%s)\n",This,debugstr_w(ppenum));
374 if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
375 return E_FAIL;
377 /* release the object if it's found */
378 if(This->bindCtxTable[index].pObj)
379 IUnknown_Release(This->bindCtxTable[index].pObj);
380 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
382 /* remove the object from the table with a left-shifting of all objects in the right side */
383 for(j=index; j<This->bindCtxTableLastIndex-1; j++)
384 This->bindCtxTable[j]= This->bindCtxTable[j+1];
386 This->bindCtxTableLastIndex--;
388 return S_OK;
391 /******************************************************************************
392 * BindCtx_EnumObjectParam
393 ******************************************************************************/
394 static HRESULT WINAPI
395 BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
397 TRACE("(%p,%p)\n",iface,pszkey);
399 *pszkey = NULL;
401 /* not implemented in native either */
402 return E_NOTIMPL;
405 /********************************************************************************
406 * GetObjectIndex (local function)
407 ********************************************************************************/
408 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
409 IUnknown* punk,
410 LPOLESTR pszkey,
411 DWORD *index)
413 DWORD i;
414 BOOL found = FALSE;
416 TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
418 if (punk==NULL)
419 /* search object identified by a register key */
420 for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
422 if(This->bindCtxTable[i].regType==1){
424 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
425 ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
426 (pszkey!=NULL) &&
427 (wcscmp(This->bindCtxTable[i].pkeyObj,pszkey)==0)
431 found = TRUE;
434 else
435 /* search object identified by a moniker*/
436 for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
437 if(This->bindCtxTable[i].pObj==punk)
438 found = TRUE;
440 if (index != NULL)
441 *index=i-1;
443 if (found)
444 return S_OK;
445 TRACE("key not found\n");
446 return S_FALSE;
449 static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *This)
451 if (!This->bindCtxTableSize)
453 This->bindCtxTableSize = BINDCTX_FIRST_TABLE_SIZE;
454 This->bindCtxTable = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
455 This->bindCtxTableSize * sizeof(BindCtxObject));
457 else
459 This->bindCtxTableSize *= 2;
461 This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
462 This->bindCtxTableSize * sizeof(BindCtxObject));
465 if (!This->bindCtxTable)
466 return E_OUTOFMEMORY;
468 return S_OK;
471 static const IBindCtxVtbl VT_BindCtxImpl =
473 BindCtxImpl_QueryInterface,
474 BindCtxImpl_AddRef,
475 BindCtxImpl_Release,
476 BindCtxImpl_RegisterObjectBound,
477 BindCtxImpl_RevokeObjectBound,
478 BindCtxImpl_ReleaseBoundObjects,
479 BindCtxImpl_SetBindOptions,
480 BindCtxImpl_GetBindOptions,
481 BindCtxImpl_GetRunningObjectTable,
482 BindCtxImpl_RegisterObjectParam,
483 BindCtxImpl_GetObjectParam,
484 BindCtxImpl_EnumObjectParam,
485 BindCtxImpl_RevokeObjectParam
488 /******************************************************************************
489 * CreateBindCtx (OLE32.@)
491 HRESULT WINAPI CreateBindCtx(DWORD reserved, IBindCtx **bind_context)
493 BindCtxImpl *object;
495 TRACE("%#lx, %p.\n", reserved, bind_context);
497 if (!bind_context) return E_INVALIDARG;
499 *bind_context = NULL;
501 if (reserved)
503 WARN("reserved should be 0, not %#lx.\n", reserved);
504 return E_INVALIDARG;
507 if (!(object = heap_alloc_zero(sizeof(*object))))
508 return E_OUTOFMEMORY;
510 object->IBindCtx_iface.lpVtbl = &VT_BindCtxImpl;
511 object->ref = 1;
512 object->options.cbStruct = sizeof(object->options);
513 object->options.grfMode = STGM_READWRITE;
514 object->options.dwClassContext = CLSCTX_SERVER;
515 object->options.locale = GetThreadLocale();
517 *bind_context = &object->IBindCtx_iface;
519 return S_OK;
522 /******************************************************************************
523 * BindMoniker [OLE32.@]
525 * Binds to a moniker.
527 * PARAMS
528 * pmk [I] Moniker to bind to.
529 * grfOpt [I] Reserved option flags. Set to 0.
530 * riid [I] ID of the interface to bind to.
531 * pvResult [O] Address that receives the interface of the object that was bound to.
533 * RETURNS
534 * Success: S_OK.
535 * Failure: Any HRESULT code.
537 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
539 HRESULT res;
540 IBindCtx * pbc;
542 TRACE("%p, %lx, %s, %p.\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
544 res = CreateBindCtx(grfOpt, &pbc);
545 if (SUCCEEDED(res))
547 res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
548 IBindCtx_Release(pbc);
550 return res;