stat on memory storage should return a NULL name, not "".
[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 #include "winerror.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wine/unicode.h"
28 #include "objbase.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(ole);
32
33 /* represent the first size table and it's increment block size */
34 #define  BLOCK_TAB_SIZE 10
35 #define  MAX_TAB_SIZE   0xFFFFFFFF
36
37 /* data structure of the BindCtx table elements */
38 typedef struct BindCtxObject{
39
40     IUnknown*   pObj; /* point on a bound object */
41
42     LPOLESTR  pkeyObj; /* key associated to this bound object */
43
44     BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */
45
46 } BindCtxObject;
47
48 /* BindCtx data strucrture */
49 typedef struct BindCtxImpl{
50
51     ICOM_VFIELD(IBindCtx); /* VTable relative to the IBindCtx interface.*/
52
53     ULONG ref; /* reference counter for this object */
54
55     BindCtxObject* bindCtxTable; /* this is a table in which all bounded objects are stored*/
56     DWORD          bindCtxTableLastIndex;  /* first free index in the table */
57     DWORD          bindCtxTableSize;   /* size table */
58
59     BIND_OPTS2 bindOption2; /* a structure which contains the bind options*/
60
61 } BindCtxImpl;
62
63 /* IBindCtx prototype functions : */
64
65 /* IUnknown functions*/
66 static HRESULT WINAPI BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject);
67 static ULONG   WINAPI BindCtxImpl_AddRef(IBindCtx* iface);
68 static ULONG   WINAPI BindCtxImpl_Release(IBindCtx* iface);
69 /* IBindCtx functions */
70 static HRESULT WINAPI BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk);
71 static HRESULT WINAPI BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk);
72 static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface);
73 static HRESULT WINAPI BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts);
74 static HRESULT WINAPI BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts);
75 static HRESULT WINAPI BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot);
76 static HRESULT WINAPI BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk);
77 static HRESULT WINAPI BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk);
78 static HRESULT WINAPI BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** ppenum);
79 static HRESULT WINAPI BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR pszkey);
80 /* Local functions*/
81 HRESULT WINAPI BindCtxImpl_Construct(BindCtxImpl* This);
82 HRESULT WINAPI BindCtxImpl_Destroy(BindCtxImpl* This);
83 HRESULT WINAPI BindCtxImpl_GetObjectIndex(BindCtxImpl* This,IUnknown* punk,LPOLESTR pszkey,DWORD *index);
84
85 /* Virtual function table for the BindCtx class. */
86 static ICOM_VTABLE(IBindCtx) VT_BindCtxImpl =
87     {
88     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
89     BindCtxImpl_QueryInterface,
90     BindCtxImpl_AddRef,
91     BindCtxImpl_Release,
92     BindCtxImpl_RegisterObjectBound,
93     BindCtxImpl_RevokeObjectBound,
94     BindCtxImpl_ReleaseBoundObjects,
95     BindCtxImpl_SetBindOptions,
96     BindCtxImpl_GetBindOptions,
97     BindCtxImpl_GetRunningObjectTable,
98     BindCtxImpl_RegisterObjectParam,
99     BindCtxImpl_GetObjectParam,
100     BindCtxImpl_EnumObjectParam,
101     BindCtxImpl_RevokeObjectParam
102 };
103
104 /*******************************************************************************
105  *        BindCtx_QueryInterface
106  *******************************************************************************/
107 HRESULT WINAPI BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject)
108 {
109   ICOM_THIS(BindCtxImpl,iface);
110
111   TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
112
113   /* Perform a sanity check on the parameters.*/
114   if ( (This==0) || (ppvObject==0) )
115       return E_INVALIDARG;
116
117   /* Initialize the return parameter.*/
118   *ppvObject = 0;
119
120   /* Compare the riid with the interface IDs implemented by this object.*/
121   if (IsEqualIID(&IID_IUnknown, riid))
122       *ppvObject = (IBindCtx*)This;
123   else
124       if (IsEqualIID(&IID_IBindCtx, riid))
125           *ppvObject = (IBindCtx*)This;
126
127   /* Check that we obtained an interface.*/
128   if ((*ppvObject)==0)
129       return E_NOINTERFACE;
130
131    /* Query Interface always increases the reference count by one when it is successful */
132   BindCtxImpl_AddRef(iface);
133
134   return S_OK;
135 }
136
137 /******************************************************************************
138  *       BindCtx_AddRef
139  ******************************************************************************/
140 ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface)
141 {
142     ICOM_THIS(BindCtxImpl,iface);
143
144     TRACE("(%p)\n",This);
145
146     return ++(This->ref);
147 }
148
149 /******************************************************************************
150  *        BindCtx_Release
151  ******************************************************************************/
152 ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface)
153 {
154     ICOM_THIS(BindCtxImpl,iface);
155
156     TRACE("(%p)\n",This);
157
158     This->ref--;
159
160     if (This->ref==0){
161
162         /* release all registered objects */
163         BindCtxImpl_ReleaseBoundObjects((IBindCtx*)This);
164
165         BindCtxImpl_Destroy(This);
166
167         return 0;
168     }
169     return This->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     ICOM_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     ICOM_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     if(This->bindCtxTable[index].pkeyObj)
279         HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
280     
281     /* left-shift all elements in the right side of the current revoked object */
282     for(j=index; j<This->bindCtxTableLastIndex-1; j++)
283         This->bindCtxTable[j]= This->bindCtxTable[j+1];
284
285     This->bindCtxTableLastIndex--;
286
287     return S_OK;
288 }
289
290 /******************************************************************************
291  *        BindCtx_ReleaseBoundObjects
292  ******************************************************************************/
293 HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface)
294 {
295     DWORD i;
296
297     ICOM_THIS(BindCtxImpl,iface);
298
299     TRACE("(%p)\n",This);
300
301     for(i=0;i<This->bindCtxTableLastIndex;i++)
302     {
303         if(This->bindCtxTable[i].pObj)
304             IUnknown_Release(This->bindCtxTable[i].pObj);
305         if(This->bindCtxTable[i].pkeyObj)
306             HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj);
307     }
308     
309     This->bindCtxTableLastIndex = 0;
310
311     return S_OK;
312 }
313
314 /******************************************************************************
315  *        BindCtx_SetBindOptions
316  ******************************************************************************/
317 HRESULT WINAPI BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
318 {
319     ICOM_THIS(BindCtxImpl,iface);
320
321     TRACE("(%p,%p)\n",This,pbindopts);
322
323     if (pbindopts==NULL)
324         return E_POINTER;
325
326     if (pbindopts->cbStruct > sizeof(BIND_OPTS2))
327     {
328         WARN("invalid size\n");
329         return E_INVALIDARG; /* FIXME : not verified */
330     }
331     memcpy(&This->bindOption2, pbindopts, pbindopts->cbStruct);
332     return S_OK;
333 }
334
335 /******************************************************************************
336  *        BindCtx_GetBindOptions
337  ******************************************************************************/
338 HRESULT WINAPI BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts)
339 {
340     ICOM_THIS(BindCtxImpl,iface);
341
342     TRACE("(%p,%p)\n",This,pbindopts);
343
344     if (pbindopts==NULL)
345         return E_POINTER;
346
347     if (pbindopts->cbStruct > sizeof(BIND_OPTS2))
348     {
349         WARN("invalid size\n");
350         return E_INVALIDARG; /* FIXME : not verified */
351     }
352     memcpy(pbindopts, &This->bindOption2, pbindopts->cbStruct);
353     return S_OK;
354 }
355
356 /******************************************************************************
357  *        BindCtx_GetRunningObjectTable
358  ******************************************************************************/
359 HRESULT WINAPI BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot)
360 {
361     HRESULT res;
362
363     ICOM_THIS(BindCtxImpl,iface);
364
365     TRACE("(%p,%p)\n",This,pprot);
366
367     if (pprot==NULL)
368         return E_POINTER;
369
370     res=GetRunningObjectTable(0, pprot);
371
372     return res;
373 }
374
375 /******************************************************************************
376  *        BindCtx_RegisterObjectParam
377  ******************************************************************************/
378 HRESULT WINAPI BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
379 {
380     DWORD index=0;
381     ICOM_THIS(BindCtxImpl,iface);
382
383     TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
384
385     if (punk==NULL)
386         return E_INVALIDARG;
387
388     if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK)
389     {
390         TRACE("Overwriting existing key\n");
391         if(This->bindCtxTable[index].pObj!=NULL)
392             IUnknown_Release(This->bindCtxTable[index].pObj);
393         This->bindCtxTable[index].pObj=punk;
394         IUnknown_AddRef(punk);
395         return S_OK;
396     }
397     This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk;
398     This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1;
399
400     if (pszkey==NULL)
401
402         This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL;
403
404     else{
405
406         This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=
407             HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey))));
408
409         if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL)
410             return E_OUTOFMEMORY;
411         strcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey);
412     }
413
414     This->bindCtxTableLastIndex++;
415
416     if (This->bindCtxTableLastIndex == This->bindCtxTableSize){ /* table is full ! must be resized */
417
418         This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
419
420         if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){
421             FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize);
422             return E_FAIL;
423         }
424         This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
425                                          This->bindCtxTableSize * sizeof(BindCtxObject));
426         if (!This->bindCtxTable)
427             return E_OUTOFMEMORY;
428     }
429     IUnknown_AddRef(punk);
430     return S_OK;
431 }
432
433 /******************************************************************************
434  *        BindCtx_GetObjectParam
435  ******************************************************************************/
436 HRESULT WINAPI BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
437 {
438     DWORD index;
439     ICOM_THIS(BindCtxImpl,iface);
440
441     TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk);
442
443     if (punk==NULL)
444         return E_POINTER;
445
446     *punk=0;
447
448     if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
449         return E_FAIL;
450
451     IUnknown_AddRef(This->bindCtxTable[index].pObj);
452
453     *punk = This->bindCtxTable[index].pObj;
454
455     return S_OK;
456 }
457
458 /******************************************************************************
459  *        BindCtx_RevokeObjectParam
460  ******************************************************************************/
461 HRESULT WINAPI BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
462 {
463     DWORD index,j;
464
465     ICOM_THIS(BindCtxImpl,iface);
466
467     TRACE("(%p,%s)\n",This,debugstr_w(ppenum));
468
469     if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
470         return E_FAIL;
471
472     /* release the object if it's found */
473     if(This->bindCtxTable[index].pObj)
474         IUnknown_Release(This->bindCtxTable[index].pObj);
475     if(This->bindCtxTable[index].pkeyObj)
476         HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj);
477     
478     /* remove the object from the table with a left-shifting of all objects in the right side */
479     for(j=index; j<This->bindCtxTableLastIndex-1; j++)
480         This->bindCtxTable[j]= This->bindCtxTable[j+1];
481
482     This->bindCtxTableLastIndex--;
483
484     return S_OK;
485 }
486
487 /******************************************************************************
488  *        BindCtx_EnumObjectParam
489  ******************************************************************************/
490 HRESULT WINAPI BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
491 {
492     FIXME("(%p,%p),stub!\n",iface,pszkey);
493     return E_NOTIMPL;
494 }
495
496 /********************************************************************************
497  *        GetObjectIndex (local function)
498  ********************************************************************************/
499 HRESULT WINAPI BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
500                                           IUnknown* punk,
501                                           LPOLESTR pszkey,
502                                           DWORD *index)
503 {
504
505     DWORD i;
506     BYTE found=0;
507
508     TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
509
510     if (punk==NULL)
511         /* search object identified by a register key */
512         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++){
513
514             if(This->bindCtxTable[i].regType==1){
515
516                 if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
517                      ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
518                        (pszkey!=NULL) &&
519                        (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0)
520                      )
521                    )
522
523                     found=1;
524             }
525         }
526     else
527         /* search object identified by a moniker*/
528         for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
529             if(This->bindCtxTable[i].pObj==punk)
530                 found=1;
531
532     if (index != NULL)
533         *index=i-1;
534
535     if (found)
536         return S_OK;
537     TRACE("key not found\n");
538     return S_FALSE;
539 }
540
541 /******************************************************************************
542  *        CreateBindCtx16
543  ******************************************************************************/
544 HRESULT WINAPI CreateBindCtx16(DWORD reserved, LPBC * ppbc)
545 {
546     FIXME("(%ld,%p),stub!\n",reserved,ppbc);
547     return E_NOTIMPL;
548 }
549
550 /******************************************************************************
551  *        CreateBindCtx (OLE32.@)
552  ******************************************************************************/
553 HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
554 {
555     BindCtxImpl* newBindCtx = 0;
556     HRESULT hr;
557     IID riid=IID_IBindCtx;
558
559     TRACE("(%ld,%p)\n",reserved,ppbc);
560
561     newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl));
562
563     if (newBindCtx == 0)
564         return E_OUTOFMEMORY;
565
566     hr = BindCtxImpl_Construct(newBindCtx);
567
568     if (FAILED(hr)){
569
570         HeapFree(GetProcessHeap(),0,newBindCtx);
571         return hr;
572     }
573
574     hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc);
575
576     return hr;
577 }
578
579 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult)
580 {
581     HRESULT res;
582     IBindCtx * pbc;
583
584     TRACE("(%p, %lx, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult);
585
586     res = CreateBindCtx(grfOpt, &pbc);
587     if (SUCCEEDED(res))
588         res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult);
589     return res;
590 }