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
impl_from_IBindCtx(IBindCtx * iface)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
BindCtxImpl_QueryInterface(IBindCtx * iface,REFIID riid,void ** ppvObject)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 ******************************************************************************/
BindCtxImpl_AddRef(IBindCtx * iface)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 *******************************************************************************/
BindCtxImpl_Destroy(BindCtxImpl * This)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 ******************************************************************************/
BindCtxImpl_Release(IBindCtx * iface)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
BindCtxImpl_RegisterObjectBound(IBindCtx * iface,IUnknown * punk)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
BindCtxImpl_RevokeObjectBound(IBindCtx * iface,IUnknown * punk)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
BindCtxImpl_ReleaseBoundObjects(IBindCtx * iface)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
BindCtxImpl_SetBindOptions(IBindCtx * iface,BIND_OPTS * pbindopts)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
BindCtxImpl_GetBindOptions(IBindCtx * iface,BIND_OPTS * pbindopts)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
BindCtxImpl_GetRunningObjectTable(IBindCtx * iface,IRunningObjectTable ** pprot)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
BindCtxImpl_RegisterObjectParam(IBindCtx * iface,LPOLESTR pszkey,IUnknown * punk)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
BindCtxImpl_GetObjectParam(IBindCtx * iface,LPOLESTR pszkey,IUnknown ** punk)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
BindCtxImpl_RevokeObjectParam(IBindCtx * iface,LPOLESTR ppenum)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
BindCtxImpl_EnumObjectParam(IBindCtx * iface,IEnumString ** pszkey)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 ********************************************************************************/
BindCtxImpl_GetObjectIndex(BindCtxImpl * This,IUnknown * punk,LPOLESTR pszkey,DWORD * index)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 (wcscmp(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
BindCtxImpl_ExpandTable(BindCtxImpl * This)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 *******************************************************************************/
BindCtxImpl_Construct(BindCtxImpl * This)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 */
CreateBindCtx(DWORD reserved,LPBC * ppbc)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 */
BindMoniker(LPMONIKER pmk,DWORD grfOpt,REFIID riid,LPVOID * ppvResult)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