ole32: Remove redundant variables.
[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     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 }