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