ole32: Add documentation for CreateBindCtx, BindMoniker, GetRunningObjectTable and...
[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 strucrture */
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,%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 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     HRESULT res;
289
290     BindCtxImpl *This = (BindCtxImpl *)iface;
291
292     TRACE("(%p,%p)\n",This,pprot);
293
294     if (pprot==NULL)
295         return E_POINTER;
296
297     res=GetRunningObjectTable(0, pprot);
298
299     return res;
300 }
301
302 /******************************************************************************
303  *        BindCtx_RegisterObjectParam
304  ******************************************************************************/
305 static HRESULT WINAPI
306 BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
307 {
308     DWORD index=0;
309     BindCtxImpl *This = (BindCtxImpl *)iface;
310
311     TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
312
313     if (punk==NULL)
314         return E_INVALIDARG;
315
316     if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK)
317     {
318         TRACE("Overwriting existing key\n");
319         if(This->bindCtxTable[index].pObj!=NULL)
320             IUnknown_Release(This->bindCtxTable[index].pObj);
321         This->bindCtxTable[index].pObj=punk;
322         IUnknown_AddRef(punk);
323         return S_OK;
324     }
325
326     if (This->bindCtxTableLastIndex == This->bindCtxTableSize)
327     {
328         HRESULT hr = BindCtxImpl_ExpandTable(This);
329         if (FAILED(hr))
330             return hr;
331     }
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     IUnknown_AddRef(punk);
354     return S_OK;
355 }
356
357 /******************************************************************************
358  *        BindCtx_GetObjectParam
359  ******************************************************************************/
360 static HRESULT WINAPI
361 BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
362 {
363     DWORD index;
364     BindCtxImpl *This = (BindCtxImpl *)iface;
365
366     TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
367
368     if (punk==NULL)
369         return E_POINTER;
370
371     *punk=0;
372
373     if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
374         return E_FAIL;
375
376     IUnknown_AddRef(This->bindCtxTable[index].pObj);
377
378     *punk = This->bindCtxTable[index].pObj;
379
380     return S_OK;
381 }
382
383 /******************************************************************************
384  *        BindCtx_RevokeObjectParam
385  ******************************************************************************/
386 static HRESULT WINAPI
387 BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
388 {
389     DWORD index,j;
390
391     BindCtxImpl *This = (BindCtxImpl *)iface;
392
393     TRACE("(%p,%s)\n",This,debugstr_w(ppenum));
394
395     if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
396         return E_FAIL;
397
398     /* release the object if it's found */
399     if(This->bindCtxTable[index].pObj)
400         IUnknown_Release(This->bindCtxTable[index].pObj);
401     HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
402     
403     /* remove the object from the table with a left-shifting of all objects in the right side */
404     for(j=index; j<This->bindCtxTableLastIndex-1; j++)
405         This->bindCtxTable[j]= This->bindCtxTable[j+1];
406
407     This->bindCtxTableLastIndex--;
408
409     return S_OK;
410 }
411
412 /******************************************************************************
413  *        BindCtx_EnumObjectParam
414  ******************************************************************************/
415 static HRESULT WINAPI
416 BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
417 {
418     TRACE("(%p,%p)\n",iface,pszkey);
419
420     *pszkey = NULL;
421
422     /* not implemented in native either */
423     return E_NOTIMPL;
424 }
425
426 /********************************************************************************
427  *        GetObjectIndex (local function)
428  ********************************************************************************/
429 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
430                                           IUnknown* punk,
431                                           LPOLESTR pszkey,
432                                           DWORD *index)
433 {
434
435     DWORD i;
436     BYTE found=0;
437
438     TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
439
440     if (punk==NULL)
441         /* search object identified by a register key */
442         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
443         {
444             if(This->bindCtxTable[i].regType==1){
445
446                 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
447                      ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
448                        (pszkey!=NULL) &&
449                        (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0)
450                      )
451                    )
452
453                     found=1;
454             }
455         }
456     else
457         /* search object identified by a moniker*/
458         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
459             if(This->bindCtxTable[i].pObj==punk)
460                 found=1;
461
462     if (index != NULL)
463         *index=i-1;
464
465     if (found)
466         return S_OK;
467     TRACE("key not found\n");
468     return S_FALSE;
469 }
470
471 static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *This)
472 {
473     if (!This->bindCtxTableSize)
474     {
475         This->bindCtxTableSize = BINDCTX_FIRST_TABLE_SIZE;
476         This->bindCtxTable = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
477                                        This->bindCtxTableSize * sizeof(BindCtxObject));
478     }
479     else
480     {
481         This->bindCtxTableSize *= 2;
482
483         This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
484                                          This->bindCtxTableSize * sizeof(BindCtxObject));
485     }
486
487     if (!This->bindCtxTable)
488         return E_OUTOFMEMORY;
489
490     return S_OK;
491 }
492
493
494 /* Virtual function table for the BindCtx class. */
495 static const IBindCtxVtbl VT_BindCtxImpl =
496 {
497     BindCtxImpl_QueryInterface,
498     BindCtxImpl_AddRef,
499     BindCtxImpl_Release,
500     BindCtxImpl_RegisterObjectBound,
501     BindCtxImpl_RevokeObjectBound,
502     BindCtxImpl_ReleaseBoundObjects,
503     BindCtxImpl_SetBindOptions,
504     BindCtxImpl_GetBindOptions,
505     BindCtxImpl_GetRunningObjectTable,
506     BindCtxImpl_RegisterObjectParam,
507     BindCtxImpl_GetObjectParam,
508     BindCtxImpl_EnumObjectParam,
509     BindCtxImpl_RevokeObjectParam
510 };
511
512 /******************************************************************************
513  *         BindCtx_Construct (local function)
514  *******************************************************************************/
515 static HRESULT BindCtxImpl_Construct(BindCtxImpl* This)
516 {
517     TRACE("(%p)\n",This);
518
519     /* Initialize the virtual function table.*/
520     This->lpVtbl       = &VT_BindCtxImpl;
521     This->ref          = 0;
522
523     /* Initialize the BIND_OPTS2 structure */
524     This->bindOption2.cbStruct  = sizeof(BIND_OPTS2);
525     This->bindOption2.grfFlags = 0;
526     This->bindOption2.grfMode = STGM_READWRITE;
527     This->bindOption2.dwTickCountDeadline = 0;
528
529     This->bindOption2.dwTrackFlags = 0;
530     This->bindOption2.dwClassContext = CLSCTX_SERVER;
531     This->bindOption2.locale = GetThreadLocale();
532     This->bindOption2.pServerInfo = 0;
533
534     /* Initialize the bindctx table */
535     This->bindCtxTableSize=0;
536     This->bindCtxTableLastIndex=0;
537     This->bindCtxTable = NULL;
538
539     return S_OK;
540 }
541
542 /******************************************************************************
543  *        CreateBindCtx (OLE32.@)
544  *
545  * Creates a bind context. A bind context encompasses information and options
546  * used when binding to a moniker.
547  *
548  * PARAMS
549  *  reserved [I] Reserved. Set to 0.
550  *  ppbc     [O] Address that receives the bind context object.
551  *
552  * RETURNS
553  *  Success: S_OK.
554  *  Failure: Any HRESULT code.
555  */
556 HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
557 {
558     BindCtxImpl* newBindCtx = 0;
559     HRESULT hr;
560     IID riid=IID_IBindCtx;
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     hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc);
586
587     return hr;
588 }
589
590 /******************************************************************************
591  *              BindMoniker        [OLE32.@]
592  *
593  * Binds to a moniker.
594  *
595  * PARAMS
596  *  pmk      [I] Moniker to bind to.
597  *  grfOpt   [I] Reserved option flags. Set to 0.
598  *  riid     [I] ID of the interface to bind to.
599  *  pvResult [O] Address that receives the interface of the object that was bound to.
600  *
601  * RETURNS
602  *  Success: S_OK.
603  *  Failure: Any HRESULT code.
604  */
605 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
606 {
607     HRESULT res;
608     IBindCtx * pbc;
609
610     TRACE("(%p, %x, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
611
612     res = CreateBindCtx(grfOpt, &pbc);
613     if (SUCCEEDED(res))
614         res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
615     return res;
616 }