dbghelp: Implement SymEnumSourceFilesW.
[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 #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
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
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;
96         IBindCtx_AddRef(iface);
97         return S_OK;
98     }
99
100     return E_NOINTERFACE;
101 }
102
103 /******************************************************************************
104  *       BindCtx_AddRef
105  ******************************************************************************/
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  *******************************************************************************/
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  ******************************************************************************/
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
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
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
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
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
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
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
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
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
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
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  ********************************************************************************/
430 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
431                                           IUnknown* punk,
432                                           LPOLESTR pszkey,
433                                           DWORD *index)
434 {
435
436     DWORD i;
437     BYTE found=0;
438
439     TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
440
441     if (punk==NULL)
442         /* search object identified by a register key */
443         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
444         {
445             if(This->bindCtxTable[i].regType==1){
446
447                 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
448                      ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
449                        (pszkey!=NULL) &&
450                        (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0)
451                      )
452                    )
453
454                     found=1;
455             }
456         }
457     else
458         /* search object identified by a moniker*/
459         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
460             if(This->bindCtxTable[i].pObj==punk)
461                 found=1;
462
463     if (index != NULL)
464         *index=i-1;
465
466     if (found)
467         return S_OK;
468     TRACE("key not found\n");
469     return S_FALSE;
470 }
471
472 static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *This)
473 {
474     if (!This->bindCtxTableSize)
475     {
476         This->bindCtxTableSize = BINDCTX_FIRST_TABLE_SIZE;
477         This->bindCtxTable = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
478                                        This->bindCtxTableSize * sizeof(BindCtxObject));
479     }
480     else
481     {
482         This->bindCtxTableSize *= 2;
483
484         This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
485                                          This->bindCtxTableSize * sizeof(BindCtxObject));
486     }
487
488     if (!This->bindCtxTable)
489         return E_OUTOFMEMORY;
490
491     return S_OK;
492 }
493
494
495 /* Virtual function table for the BindCtx class. */
496 static const IBindCtxVtbl VT_BindCtxImpl =
497 {
498     BindCtxImpl_QueryInterface,
499     BindCtxImpl_AddRef,
500     BindCtxImpl_Release,
501     BindCtxImpl_RegisterObjectBound,
502     BindCtxImpl_RevokeObjectBound,
503     BindCtxImpl_ReleaseBoundObjects,
504     BindCtxImpl_SetBindOptions,
505     BindCtxImpl_GetBindOptions,
506     BindCtxImpl_GetRunningObjectTable,
507     BindCtxImpl_RegisterObjectParam,
508     BindCtxImpl_GetObjectParam,
509     BindCtxImpl_EnumObjectParam,
510     BindCtxImpl_RevokeObjectParam
511 };
512
513 /******************************************************************************
514  *         BindCtx_Construct (local function)
515  *******************************************************************************/
516 static HRESULT BindCtxImpl_Construct(BindCtxImpl* This)
517 {
518     TRACE("(%p)\n",This);
519
520     /* Initialize the virtual function table.*/
521     This->IBindCtx_iface.lpVtbl = &VT_BindCtxImpl;
522     This->ref          = 0;
523
524     /* Initialize the BIND_OPTS2 structure */
525     This->bindOption2.cbStruct  = sizeof(BIND_OPTS2);
526     This->bindOption2.grfFlags = 0;
527     This->bindOption2.grfMode = STGM_READWRITE;
528     This->bindOption2.dwTickCountDeadline = 0;
529
530     This->bindOption2.dwTrackFlags = 0;
531     This->bindOption2.dwClassContext = CLSCTX_SERVER;
532     This->bindOption2.locale = GetThreadLocale();
533     This->bindOption2.pServerInfo = 0;
534
535     /* Initialize the bindctx table */
536     This->bindCtxTableSize=0;
537     This->bindCtxTableLastIndex=0;
538     This->bindCtxTable = NULL;
539
540     return S_OK;
541 }
542
543 /******************************************************************************
544  *        CreateBindCtx (OLE32.@)
545  *
546  * Creates a bind context. A bind context encompasses information and options
547  * used when binding to a moniker.
548  *
549  * PARAMS
550  *  reserved [I] Reserved. Set to 0.
551  *  ppbc     [O] Address that receives the bind context object.
552  *
553  * RETURNS
554  *  Success: S_OK.
555  *  Failure: Any HRESULT code.
556  */
557 HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
558 {
559     BindCtxImpl* newBindCtx;
560     HRESULT hr;
561
562     TRACE("(%d,%p)\n",reserved,ppbc);
563
564     if (!ppbc) return E_INVALIDARG;
565
566     *ppbc = NULL;
567
568     if (reserved != 0)
569     {
570         ERR("reserved should be 0, not 0x%x\n", reserved);
571         return E_INVALIDARG;
572     }
573
574     newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl));
575     if (newBindCtx == 0)
576         return E_OUTOFMEMORY;
577
578     hr = BindCtxImpl_Construct(newBindCtx);
579     if (FAILED(hr))
580     {
581         HeapFree(GetProcessHeap(),0,newBindCtx);
582         return hr;
583     }
584
585     return BindCtxImpl_QueryInterface(&newBindCtx->IBindCtx_iface,&IID_IBindCtx,(void**)ppbc);
586 }
587
588 /******************************************************************************
589  *              BindMoniker        [OLE32.@]
590  *
591  * Binds to a moniker.
592  *
593  * PARAMS
594  *  pmk      [I] Moniker to bind to.
595  *  grfOpt   [I] Reserved option flags. Set to 0.
596  *  riid     [I] ID of the interface to bind to.
597  *  pvResult [O] Address that receives the interface of the object that was bound to.
598  *
599  * RETURNS
600  *  Success: S_OK.
601  *  Failure: Any HRESULT code.
602  */
603 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
604 {
605     HRESULT res;
606     IBindCtx * pbc;
607
608     TRACE("(%p, %x, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
609
610     res = CreateBindCtx(grfOpt, &pbc);
611     if (SUCCEEDED(res))
612     {
613         res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
614         IBindCtx_Release(pbc);
615     }
616     return res;
617 }