move mesa32 over to new dir
[reactos.git] / reactos / lib / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ***************************************************************************************/
20
21 #include <stdarg.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #define COBJMACROS
26
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(ole);
34
35 /* represent the first size table and it's increment block size */
36 #define BLOCK_TAB_SIZE 10
37 #define MAX_TAB_SIZE 0xFFFFFFFF
38
39 /* data structure of the BindCtx table elements */
40 typedef struct BindCtxObject{
41
42 IUnknown* pObj; /* point on a bound object */
43
44 LPOLESTR pkeyObj; /* key associated to this bound object */
45
46 BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */
47
48 } BindCtxObject;
49
50 /* BindCtx data strucrture */
51 typedef struct BindCtxImpl{
52
53 const IBindCtxVtbl *lpVtbl; /* VTable relative to the IBindCtx interface.*/
54
55 LONG ref; /* reference counter for this object */
56
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 */
60
61 BIND_OPTS2 bindOption2; /* a structure which contains the bind options*/
62
63 } BindCtxImpl;
64
65 /* IBindCtx prototype functions : */
66 static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx*);
67 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl*, IUnknown*, LPOLESTR, DWORD *);
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,%p,%p)\n",This,riid,ppvObject);
78
79 /* Perform a sanity check on the parameters.*/
80 if ( (This==0) || (ppvObject==0) )
81 return E_INVALIDARG;
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 = (IBindCtx*)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 E_POINTER;
161
162 IUnknown_AddRef(punk);
163
164 /* put the object in the first free element in the table */
165 This->bindCtxTable[lastIndex].pObj = punk;
166 This->bindCtxTable[lastIndex].pkeyObj = NULL;
167 This->bindCtxTable[lastIndex].regType = 0;
168 lastIndex= ++This->bindCtxTableLastIndex;
169
170 if (lastIndex == This->bindCtxTableSize){ /* the table is full so it must be resized */
171
172 if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){
173 FIXME("This->bindCtxTableSize: %ld is out of data limite\n", This->bindCtxTableSize);
174 return E_FAIL;
175 }
176
177 This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
178
179 This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
180 This->bindCtxTableSize * sizeof(BindCtxObject));
181 if (!This->bindCtxTable)
182 return E_OUTOFMEMORY;
183 }
184 return S_OK;
185 }
186
187 /******************************************************************************
188 * BindCtx_RevokeObjectBound
189 ******************************************************************************/
190 static HRESULT WINAPI
191 BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk)
192 {
193 DWORD index,j;
194
195 BindCtxImpl *This = (BindCtxImpl *)iface;
196
197 TRACE("(%p,%p)\n",This,punk);
198
199 /* check if the object was registered or not */
200 if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE)
201 return MK_E_NOTBOUND;
202
203 if(This->bindCtxTable[index].pObj)
204 IUnknown_Release(This->bindCtxTable[index].pObj);
205 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
206
207 /* left-shift all elements in the right side of the current revoked object */
208 for(j=index; j<This->bindCtxTableLastIndex-1; j++)
209 This->bindCtxTable[j]= This->bindCtxTable[j+1];
210
211 This->bindCtxTableLastIndex--;
212
213 return S_OK;
214 }
215
216 /******************************************************************************
217 * BindCtx_ReleaseBoundObjects
218 ******************************************************************************/
219 static HRESULT WINAPI
220 BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface)
221 {
222 DWORD i;
223
224 BindCtxImpl *This = (BindCtxImpl *)iface;
225
226 TRACE("(%p)\n",This);
227
228 for(i=0;i<This->bindCtxTableLastIndex;i++)
229 {
230 if(This->bindCtxTable[i].pObj)
231 IUnknown_Release(This->bindCtxTable[i].pObj);
232 HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj);
233 }
234
235 This->bindCtxTableLastIndex = 0;
236
237 return S_OK;
238 }
239
240 /******************************************************************************
241 * BindCtx_SetBindOptions
242 ******************************************************************************/
243 static HRESULT WINAPI
244 BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
245 {
246 BindCtxImpl *This = (BindCtxImpl *)iface;
247
248 TRACE("(%p,%p)\n",This,pbindopts);
249
250 if (pbindopts==NULL)
251 return E_POINTER;
252
253 if (pbindopts->cbStruct > sizeof(BIND_OPTS2))
254 {
255 WARN("invalid size\n");
256 return E_INVALIDARG; /* FIXME : not verified */
257 }
258 memcpy(&This->bindOption2, pbindopts, pbindopts->cbStruct);
259 return S_OK;
260 }
261
262 /******************************************************************************
263 * BindCtx_GetBindOptions
264 ******************************************************************************/
265 static HRESULT WINAPI
266 BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
267 {
268 BindCtxImpl *This = (BindCtxImpl *)iface;
269
270 TRACE("(%p,%p)\n",This,pbindopts);
271
272 if (pbindopts==NULL)
273 return E_POINTER;
274
275 if (pbindopts->cbStruct > sizeof(BIND_OPTS2))
276 {
277 WARN("invalid size\n");
278 return E_INVALIDARG; /* FIXME : not verified */
279 }
280 memcpy(pbindopts, &This->bindOption2, pbindopts->cbStruct);
281 return S_OK;
282 }
283
284 /******************************************************************************
285 * BindCtx_GetRunningObjectTable
286 ******************************************************************************/
287 static HRESULT WINAPI
288 BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot)
289 {
290 HRESULT res;
291
292 BindCtxImpl *This = (BindCtxImpl *)iface;
293
294 TRACE("(%p,%p)\n",This,pprot);
295
296 if (pprot==NULL)
297 return E_POINTER;
298
299 res=GetRunningObjectTable(0, pprot);
300
301 return res;
302 }
303
304 /******************************************************************************
305 * BindCtx_RegisterObjectParam
306 ******************************************************************************/
307 static HRESULT WINAPI
308 BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
309 {
310 DWORD index=0;
311 BindCtxImpl *This = (BindCtxImpl *)iface;
312
313 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
314
315 if (punk==NULL)
316 return E_INVALIDARG;
317
318 if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK)
319 {
320 TRACE("Overwriting existing key\n");
321 if(This->bindCtxTable[index].pObj!=NULL)
322 IUnknown_Release(This->bindCtxTable[index].pObj);
323 This->bindCtxTable[index].pObj=punk;
324 IUnknown_AddRef(punk);
325 return S_OK;
326 }
327 This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk;
328 This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1;
329
330 if (pszkey==NULL)
331
332 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL;
333
334 else
335 {
336
337 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=
338 HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey))));
339
340 if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL)
341 return E_OUTOFMEMORY;
342 lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey);
343 }
344
345 This->bindCtxTableLastIndex++;
346
347 if (This->bindCtxTableLastIndex == This->bindCtxTableSize)
348 {
349 /* table is full ! must be resized */
350
351 This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
352 if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE))
353 {
354 FIXME("This->bindCtxTableSize: %ld is out of data limite\n", This->bindCtxTableSize);
355 return E_FAIL;
356 }
357 This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
358 This->bindCtxTableSize * sizeof(BindCtxObject));
359 if (!This->bindCtxTable)
360 return E_OUTOFMEMORY;
361 }
362 IUnknown_AddRef(punk);
363 return S_OK;
364 }
365
366 /******************************************************************************
367 * BindCtx_GetObjectParam
368 ******************************************************************************/
369 static HRESULT WINAPI
370 BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
371 {
372 DWORD index;
373 BindCtxImpl *This = (BindCtxImpl *)iface;
374
375 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
376
377 if (punk==NULL)
378 return E_POINTER;
379
380 *punk=0;
381
382 if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
383 return E_FAIL;
384
385 IUnknown_AddRef(This->bindCtxTable[index].pObj);
386
387 *punk = This->bindCtxTable[index].pObj;
388
389 return S_OK;
390 }
391
392 /******************************************************************************
393 * BindCtx_RevokeObjectParam
394 ******************************************************************************/
395 static HRESULT WINAPI
396 BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
397 {
398 DWORD index,j;
399
400 BindCtxImpl *This = (BindCtxImpl *)iface;
401
402 TRACE("(%p,%s)\n",This,debugstr_w(ppenum));
403
404 if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
405 return E_FAIL;
406
407 /* release the object if it's found */
408 if(This->bindCtxTable[index].pObj)
409 IUnknown_Release(This->bindCtxTable[index].pObj);
410 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
411
412 /* remove the object from the table with a left-shifting of all objects in the right side */
413 for(j=index; j<This->bindCtxTableLastIndex-1; j++)
414 This->bindCtxTable[j]= This->bindCtxTable[j+1];
415
416 This->bindCtxTableLastIndex--;
417
418 return S_OK;
419 }
420
421 /******************************************************************************
422 * BindCtx_EnumObjectParam
423 ******************************************************************************/
424 static HRESULT WINAPI
425 BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
426 {
427 FIXME("(%p,%p),stub!\n",iface,pszkey);
428 return E_NOTIMPL;
429 }
430
431 /********************************************************************************
432 * GetObjectIndex (local function)
433 ********************************************************************************/
434 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
435 IUnknown* punk,
436 LPOLESTR pszkey,
437 DWORD *index)
438 {
439
440 DWORD i;
441 BYTE found=0;
442
443 TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
444
445 if (punk==NULL)
446 /* search object identified by a register key */
447 for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
448 {
449 if(This->bindCtxTable[i].regType==1){
450
451 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
452 ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
453 (pszkey!=NULL) &&
454 (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0)
455 )
456 )
457
458 found=1;
459 }
460 }
461 else
462 /* search object identified by a moniker*/
463 for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
464 if(This->bindCtxTable[i].pObj==punk)
465 found=1;
466
467 if (index != NULL)
468 *index=i-1;
469
470 if (found)
471 return S_OK;
472 TRACE("key not found\n");
473 return S_FALSE;
474 }
475
476 /* Virtual function table for the BindCtx class. */
477 static const IBindCtxVtbl VT_BindCtxImpl =
478 {
479 BindCtxImpl_QueryInterface,
480 BindCtxImpl_AddRef,
481 BindCtxImpl_Release,
482 BindCtxImpl_RegisterObjectBound,
483 BindCtxImpl_RevokeObjectBound,
484 BindCtxImpl_ReleaseBoundObjects,
485 BindCtxImpl_SetBindOptions,
486 BindCtxImpl_GetBindOptions,
487 BindCtxImpl_GetRunningObjectTable,
488 BindCtxImpl_RegisterObjectParam,
489 BindCtxImpl_GetObjectParam,
490 BindCtxImpl_EnumObjectParam,
491 BindCtxImpl_RevokeObjectParam
492 };
493
494 /******************************************************************************
495 * BindCtx_Construct (local function)
496 *******************************************************************************/
497 static HRESULT BindCtxImpl_Construct(BindCtxImpl* This)
498 {
499 TRACE("(%p)\n",This);
500
501 /* Initialize the virtual function table.*/
502 This->lpVtbl = &VT_BindCtxImpl;
503 This->ref = 0;
504
505 /* Initialize the BIND_OPTS2 structure */
506 This->bindOption2.cbStruct = sizeof(BIND_OPTS2);
507 This->bindOption2.grfFlags = 0;
508 This->bindOption2.grfMode = STGM_READWRITE;
509 This->bindOption2.dwTickCountDeadline = 0;
510
511 This->bindOption2.dwTrackFlags = 0;
512 This->bindOption2.dwClassContext = CLSCTX_SERVER;
513 This->bindOption2.locale = 1033;
514 This->bindOption2.pServerInfo = 0;
515
516 /* Initialize the bindctx table */
517 This->bindCtxTableSize=BLOCK_TAB_SIZE;
518 This->bindCtxTableLastIndex=0;
519 This->bindCtxTable = HeapAlloc(GetProcessHeap(), 0,
520 This->bindCtxTableSize*sizeof(BindCtxObject));
521
522 if (This->bindCtxTable==NULL)
523 return E_OUTOFMEMORY;
524
525 return S_OK;
526 }
527
528 /******************************************************************************
529 * CreateBindCtx (OLE32.@)
530 ******************************************************************************/
531 HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
532 {
533 BindCtxImpl* newBindCtx = 0;
534 HRESULT hr;
535 IID riid=IID_IBindCtx;
536
537 TRACE("(%ld,%p)\n",reserved,ppbc);
538
539 newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl));
540 if (newBindCtx == 0)
541 return E_OUTOFMEMORY;
542
543 hr = BindCtxImpl_Construct(newBindCtx);
544 if (FAILED(hr))
545 {
546 HeapFree(GetProcessHeap(),0,newBindCtx);
547 return hr;
548 }
549
550 hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc);
551
552 return hr;
553 }
554
555 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
556 {
557 HRESULT res;
558 IBindCtx * pbc;
559
560 TRACE("(%p, %lx, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
561
562 res = CreateBindCtx(grfOpt, &pbc);
563 if (SUCCEEDED(res))
564 res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
565 return res;
566 }