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