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