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