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 IBindCtx IBindCtx_iface; 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 static inline BindCtxImpl *impl_from_IBindCtx(IBindCtx *iface) 70 { 71 return CONTAINING_RECORD(iface, BindCtxImpl, IBindCtx_iface); 72 } 73 74 /******************************************************************************* 75 * BindCtx_QueryInterface 76 *******************************************************************************/ 77 static HRESULT WINAPI 78 BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject) 79 { 80 BindCtxImpl *This = impl_from_IBindCtx(iface); 81 82 TRACE("(%p %s %p)\n",This, debugstr_guid(riid), ppvObject); 83 84 /* Perform a sanity check on the parameters.*/ 85 if (!ppvObject) 86 return E_POINTER; 87 88 /* Initialize the return parameter.*/ 89 *ppvObject = 0; 90 91 /* Compare the riid with the interface IDs implemented by this object.*/ 92 if (IsEqualIID(&IID_IUnknown, riid) || 93 IsEqualIID(&IID_IBindCtx, riid)) 94 { 95 *ppvObject = &This->IBindCtx_iface; 96 IBindCtx_AddRef(iface); 97 return S_OK; 98 } 99 100 return E_NOINTERFACE; 101 } 102 103 /****************************************************************************** 104 * BindCtx_AddRef 105 ******************************************************************************/ 106 static ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface) 107 { 108 BindCtxImpl *This = impl_from_IBindCtx(iface); 109 110 TRACE("(%p)\n",This); 111 112 return InterlockedIncrement(&This->ref); 113 } 114 115 /****************************************************************************** 116 * BindCtx_Destroy (local function) 117 *******************************************************************************/ 118 static HRESULT BindCtxImpl_Destroy(BindCtxImpl* This) 119 { 120 TRACE("(%p)\n",This); 121 122 /* free the table space memory */ 123 HeapFree(GetProcessHeap(),0,This->bindCtxTable); 124 125 /* free the bindctx structure */ 126 HeapFree(GetProcessHeap(),0,This); 127 128 return S_OK; 129 } 130 131 /****************************************************************************** 132 * BindCtx_Release 133 ******************************************************************************/ 134 static ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface) 135 { 136 BindCtxImpl *This = impl_from_IBindCtx(iface); 137 ULONG ref; 138 139 TRACE("(%p)\n",This); 140 141 ref = InterlockedDecrement(&This->ref); 142 if (ref == 0) 143 { 144 /* release all registered objects */ 145 BindCtxImpl_ReleaseBoundObjects(&This->IBindCtx_iface); 146 147 BindCtxImpl_Destroy(This); 148 } 149 return ref; 150 } 151 152 153 /****************************************************************************** 154 * BindCtx_RegisterObjectBound 155 ******************************************************************************/ 156 static HRESULT WINAPI 157 BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk) 158 { 159 BindCtxImpl *This = impl_from_IBindCtx(iface); 160 DWORD lastIndex=This->bindCtxTableLastIndex; 161 162 TRACE("(%p,%p)\n",This,punk); 163 164 if (punk==NULL) 165 return S_OK; 166 167 if (lastIndex == This->bindCtxTableSize) 168 { 169 HRESULT hr = BindCtxImpl_ExpandTable(This); 170 if (FAILED(hr)) 171 return hr; 172 } 173 174 IUnknown_AddRef(punk); 175 176 /* put the object in the first free element in the table */ 177 This->bindCtxTable[lastIndex].pObj = punk; 178 This->bindCtxTable[lastIndex].pkeyObj = NULL; 179 This->bindCtxTable[lastIndex].regType = 0; 180 lastIndex= ++This->bindCtxTableLastIndex; 181 182 return S_OK; 183 } 184 185 /****************************************************************************** 186 * BindCtx_RevokeObjectBound 187 ******************************************************************************/ 188 static HRESULT WINAPI 189 BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk) 190 { 191 DWORD index,j; 192 193 BindCtxImpl *This = impl_from_IBindCtx(iface); 194 195 TRACE("(%p,%p)\n",This,punk); 196 197 if (!punk) 198 return E_INVALIDARG; 199 200 /* check if the object was registered or not */ 201 if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE) 202 return MK_E_NOTBOUND; 203 204 if(This->bindCtxTable[index].pObj) 205 IUnknown_Release(This->bindCtxTable[index].pObj); 206 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); 207 208 /* left-shift all elements in the right side of the current revoked object */ 209 for(j=index; j<This->bindCtxTableLastIndex-1; j++) 210 This->bindCtxTable[j]= This->bindCtxTable[j+1]; 211 212 This->bindCtxTableLastIndex--; 213 214 return S_OK; 215 } 216 217 /****************************************************************************** 218 * BindCtx_ReleaseBoundObjects 219 ******************************************************************************/ 220 static HRESULT WINAPI 221 BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface) 222 { 223 DWORD i; 224 225 BindCtxImpl *This = impl_from_IBindCtx(iface); 226 227 TRACE("(%p)\n",This); 228 229 for(i=0;i<This->bindCtxTableLastIndex;i++) 230 { 231 if(This->bindCtxTable[i].pObj) 232 IUnknown_Release(This->bindCtxTable[i].pObj); 233 HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj); 234 } 235 236 This->bindCtxTableLastIndex = 0; 237 238 return S_OK; 239 } 240 241 /****************************************************************************** 242 * BindCtx_SetBindOptions 243 ******************************************************************************/ 244 static HRESULT WINAPI 245 BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) 246 { 247 BindCtxImpl *This = impl_from_IBindCtx(iface); 248 249 TRACE("(%p,%p)\n",This,pbindopts); 250 251 if (pbindopts==NULL) 252 return E_POINTER; 253 254 if (pbindopts->cbStruct > sizeof(BIND_OPTS2)) 255 { 256 WARN("invalid size\n"); 257 return E_INVALIDARG; /* FIXME : not verified */ 258 } 259 memcpy(&This->bindOption2, pbindopts, pbindopts->cbStruct); 260 return S_OK; 261 } 262 263 /****************************************************************************** 264 * BindCtx_GetBindOptions 265 ******************************************************************************/ 266 static HRESULT WINAPI 267 BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) 268 { 269 BindCtxImpl *This = impl_from_IBindCtx(iface); 270 ULONG cbStruct; 271 272 TRACE("(%p,%p)\n",This,pbindopts); 273 274 if (pbindopts==NULL) 275 return E_POINTER; 276 277 cbStruct = pbindopts->cbStruct; 278 if (cbStruct > sizeof(BIND_OPTS2)) 279 cbStruct = sizeof(BIND_OPTS2); 280 281 memcpy(pbindopts, &This->bindOption2, cbStruct); 282 pbindopts->cbStruct = cbStruct; 283 284 return S_OK; 285 } 286 287 /****************************************************************************** 288 * BindCtx_GetRunningObjectTable 289 ******************************************************************************/ 290 static HRESULT WINAPI 291 BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot) 292 { 293 BindCtxImpl *This = impl_from_IBindCtx(iface); 294 295 TRACE("(%p,%p)\n",This,pprot); 296 297 if (pprot==NULL) 298 return E_POINTER; 299 300 return GetRunningObjectTable(0, pprot); 301 } 302 303 /****************************************************************************** 304 * BindCtx_RegisterObjectParam 305 ******************************************************************************/ 306 static HRESULT WINAPI 307 BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk) 308 { 309 DWORD index=0; 310 BindCtxImpl *This = impl_from_IBindCtx(iface); 311 312 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk); 313 314 if (punk==NULL) 315 return E_INVALIDARG; 316 317 if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK) 318 { 319 TRACE("Overwriting existing key\n"); 320 if(This->bindCtxTable[index].pObj!=NULL) 321 IUnknown_Release(This->bindCtxTable[index].pObj); 322 This->bindCtxTable[index].pObj=punk; 323 IUnknown_AddRef(punk); 324 return S_OK; 325 } 326 327 if (This->bindCtxTableLastIndex == This->bindCtxTableSize) 328 { 329 HRESULT hr = BindCtxImpl_ExpandTable(This); 330 if (FAILED(hr)) 331 return hr; 332 } 333 334 This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk; 335 This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1; 336 337 if (pszkey==NULL) 338 339 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL; 340 341 else 342 { 343 344 This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj= 345 HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey)))); 346 347 if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL) 348 return E_OUTOFMEMORY; 349 lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey); 350 } 351 352 This->bindCtxTableLastIndex++; 353 354 IUnknown_AddRef(punk); 355 return S_OK; 356 } 357 358 /****************************************************************************** 359 * BindCtx_GetObjectParam 360 ******************************************************************************/ 361 static HRESULT WINAPI 362 BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk) 363 { 364 DWORD index; 365 BindCtxImpl *This = impl_from_IBindCtx(iface); 366 367 TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk); 368 369 if (punk==NULL) 370 return E_POINTER; 371 372 *punk=0; 373 374 if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE) 375 return E_FAIL; 376 377 IUnknown_AddRef(This->bindCtxTable[index].pObj); 378 379 *punk = This->bindCtxTable[index].pObj; 380 381 return S_OK; 382 } 383 384 /****************************************************************************** 385 * BindCtx_RevokeObjectParam 386 ******************************************************************************/ 387 static HRESULT WINAPI 388 BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum) 389 { 390 DWORD index,j; 391 392 BindCtxImpl *This = impl_from_IBindCtx(iface); 393 394 TRACE("(%p,%s)\n",This,debugstr_w(ppenum)); 395 396 if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE) 397 return E_FAIL; 398 399 /* release the object if it's found */ 400 if(This->bindCtxTable[index].pObj) 401 IUnknown_Release(This->bindCtxTable[index].pObj); 402 HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); 403 404 /* remove the object from the table with a left-shifting of all objects in the right side */ 405 for(j=index; j<This->bindCtxTableLastIndex-1; j++) 406 This->bindCtxTable[j]= This->bindCtxTable[j+1]; 407 408 This->bindCtxTableLastIndex--; 409 410 return S_OK; 411 } 412 413 /****************************************************************************** 414 * BindCtx_EnumObjectParam 415 ******************************************************************************/ 416 static HRESULT WINAPI 417 BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey) 418 { 419 TRACE("(%p,%p)\n",iface,pszkey); 420 421 *pszkey = NULL; 422 423 /* not implemented in native either */ 424 return E_NOTIMPL; 425 } 426 427 /******************************************************************************** 428 * GetObjectIndex (local function) 429 ********************************************************************************/ 430 static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This, 431 IUnknown* punk, 432 LPOLESTR pszkey, 433 DWORD *index) 434 { 435 DWORD i; 436 BOOL found = FALSE; 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 = TRUE; 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 = TRUE; 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->IBindCtx_iface.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; 559 HRESULT hr; 560 561 TRACE("(%d,%p)\n",reserved,ppbc); 562 563 if (!ppbc) return E_INVALIDARG; 564 565 *ppbc = NULL; 566 567 if (reserved != 0) 568 { 569 ERR("reserved should be 0, not 0x%x\n", reserved); 570 return E_INVALIDARG; 571 } 572 573 newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl)); 574 if (newBindCtx == 0) 575 return E_OUTOFMEMORY; 576 577 hr = BindCtxImpl_Construct(newBindCtx); 578 if (FAILED(hr)) 579 { 580 HeapFree(GetProcessHeap(),0,newBindCtx); 581 return hr; 582 } 583 584 return BindCtxImpl_QueryInterface(&newBindCtx->IBindCtx_iface,&IID_IBindCtx,(void**)ppbc); 585 } 586 587 /****************************************************************************** 588 * BindMoniker [OLE32.@] 589 * 590 * Binds to a moniker. 591 * 592 * PARAMS 593 * pmk [I] Moniker to bind to. 594 * grfOpt [I] Reserved option flags. Set to 0. 595 * riid [I] ID of the interface to bind to. 596 * pvResult [O] Address that receives the interface of the object that was bound to. 597 * 598 * RETURNS 599 * Success: S_OK. 600 * Failure: Any HRESULT code. 601 */ 602 HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult) 603 { 604 HRESULT res; 605 IBindCtx * pbc; 606 607 TRACE("(%p, %x, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult); 608 609 res = CreateBindCtx(grfOpt, &pbc); 610 if (SUCCEEDED(res)) 611 { 612 res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult); 613 IBindCtx_Release(pbc); 614 } 615 return res; 616 } 617