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