1 /* 2 * Implementation of Active Template Library (atl.dll) 3 * 4 * Copyright 2004 Aric Stewart for CodeWeavers 5 * Copyright 2005 Jacek Caban 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdio.h> 23 24 #define COBJMACROS 25 26 #include "objidl.h" 27 #include "rpcproxy.h" 28 #include "wine/atlbase.h" 29 #include "wine/atlwin.h" 30 31 #include "wine/debug.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(atl); 34 35 extern HINSTANCE atl_instance; 36 37 #define ATLVer1Size FIELD_OFFSET(_ATL_MODULEW, dwAtlBuildVer) 38 39 HRESULT WINAPI AtlModuleInit(_ATL_MODULEW* pM, _ATL_OBJMAP_ENTRYW* p, HINSTANCE h) 40 { 41 INT i; 42 UINT size; 43 44 TRACE("(%p %p %p)\n", pM, p, h); 45 46 size = pM->cbSize; 47 switch (size) 48 { 49 case ATLVer1Size: 50 case sizeof(_ATL_MODULEW): 51 #ifdef _WIN64 52 case sizeof(_ATL_MODULEW) + sizeof(void *): 53 #endif 54 break; 55 default: 56 WARN("Unknown structure version (size %i)\n",size); 57 return E_INVALIDARG; 58 } 59 60 memset(pM,0,pM->cbSize); 61 pM->cbSize = size; 62 pM->m_hInst = h; 63 pM->m_hInstResource = h; 64 pM->m_hInstTypeLib = h; 65 pM->m_pObjMap = p; 66 pM->m_hHeap = GetProcessHeap(); 67 68 InitializeCriticalSection(&pM->u.m_csTypeInfoHolder); 69 InitializeCriticalSection(&pM->m_csWindowCreate); 70 InitializeCriticalSection(&pM->m_csObjMap); 71 72 /* call mains */ 73 i = 0; 74 if (pM->m_pObjMap != NULL && size > ATLVer1Size) 75 { 76 while (pM->m_pObjMap[i].pclsid != NULL) 77 { 78 TRACE("Initializing object %i %p\n",i,p[i].pfnObjectMain); 79 if (p[i].pfnObjectMain) 80 p[i].pfnObjectMain(TRUE); 81 i++; 82 } 83 } 84 85 return S_OK; 86 } 87 88 static _ATL_OBJMAP_ENTRYW_V1 *get_objmap_entry( _ATL_MODULEW *mod, unsigned int index ) 89 { 90 _ATL_OBJMAP_ENTRYW_V1 *ret; 91 92 if (mod->cbSize == ATLVer1Size) 93 ret = (_ATL_OBJMAP_ENTRYW_V1 *)mod->m_pObjMap + index; 94 else 95 ret = (_ATL_OBJMAP_ENTRYW_V1 *)(mod->m_pObjMap + index); 96 97 if (!ret->pclsid) ret = NULL; 98 return ret; 99 } 100 101 HRESULT WINAPI AtlModuleLoadTypeLib(_ATL_MODULEW *pM, LPCOLESTR lpszIndex, 102 BSTR *pbstrPath, ITypeLib **ppTypeLib) 103 { 104 TRACE("(%p, %s, %p, %p)\n", pM, debugstr_w(lpszIndex), pbstrPath, ppTypeLib); 105 106 if (!pM) 107 return E_INVALIDARG; 108 109 return AtlLoadTypeLib(pM->m_hInstTypeLib, lpszIndex, pbstrPath, ppTypeLib); 110 } 111 112 HRESULT WINAPI AtlModuleTerm(_ATL_MODULE *pM) 113 { 114 _ATL_TERMFUNC_ELEM *iter, *tmp; 115 116 TRACE("(%p)\n", pM); 117 118 if (pM->cbSize > ATLVer1Size) 119 { 120 iter = pM->m_pTermFuncs; 121 122 while(iter) { 123 iter->pFunc(iter->dw); 124 tmp = iter; 125 iter = iter->pNext; 126 HeapFree(GetProcessHeap(), 0, tmp); 127 } 128 } 129 130 return S_OK; 131 } 132 133 HRESULT WINAPI AtlModuleRegisterClassObjects(_ATL_MODULEW *pM, DWORD dwClsContext, 134 DWORD dwFlags) 135 { 136 _ATL_OBJMAP_ENTRYW_V1 *obj; 137 int i=0; 138 139 TRACE("(%p %i %i)\n",pM, dwClsContext, dwFlags); 140 141 if (pM == NULL) 142 return E_INVALIDARG; 143 144 while ((obj = get_objmap_entry( pM, i++ ))) 145 { 146 IUnknown* pUnknown; 147 HRESULT rc; 148 149 TRACE("Registering object %i\n",i); 150 if (obj->pfnGetClassObject) 151 { 152 rc = obj->pfnGetClassObject(obj->pfnCreateInstance, &IID_IUnknown, 153 (LPVOID*)&pUnknown); 154 if (SUCCEEDED (rc) ) 155 { 156 rc = CoRegisterClassObject(obj->pclsid, pUnknown, dwClsContext, 157 dwFlags, &obj->dwRegister); 158 159 if (FAILED (rc) ) 160 WARN("Failed to register object %i: 0x%08x\n", i, rc); 161 162 if (pUnknown) 163 IUnknown_Release(pUnknown); 164 } 165 } 166 } 167 168 return S_OK; 169 } 170 171 HRESULT WINAPI AtlModuleUnregisterServerEx(_ATL_MODULEW* pM, BOOL bUnRegTypeLib, const CLSID* pCLSID) 172 { 173 FIXME("(%p, %i, %p) stub\n", pM, bUnRegTypeLib, pCLSID); 174 return S_OK; 175 } 176 177 /*********************************************************************** 178 * AtlModuleRegisterServer [ATL.@] 179 * 180 */ 181 HRESULT WINAPI AtlModuleRegisterServer(_ATL_MODULEW* pM, BOOL bRegTypeLib, const CLSID* clsid) 182 { 183 const _ATL_OBJMAP_ENTRYW_V1 *obj; 184 int i; 185 HRESULT hRes; 186 187 TRACE("%p %d %s\n", pM, bRegTypeLib, debugstr_guid(clsid)); 188 189 if (pM == NULL) 190 return E_INVALIDARG; 191 192 for (i = 0; (obj = get_objmap_entry( pM, i )) != NULL; i++) /* register CLSIDs */ 193 { 194 if (!clsid || IsEqualCLSID(obj->pclsid, clsid)) 195 { 196 TRACE("Registering clsid %s\n", debugstr_guid(obj->pclsid)); 197 hRes = obj->pfnUpdateRegistry(TRUE); /* register */ 198 if (FAILED(hRes)) 199 return hRes; 200 201 if(pM->cbSize > ATLVer1Size) { 202 const struct _ATL_CATMAP_ENTRY *catmap; 203 204 catmap = ((const _ATL_OBJMAP_ENTRYW*)obj)->pfnGetCategoryMap(); 205 if(catmap) { 206 hRes = AtlRegisterClassCategoriesHelper(obj->pclsid, catmap, TRUE); 207 if(FAILED(hRes)) 208 return hRes; 209 } 210 } 211 } 212 } 213 214 if (bRegTypeLib) 215 { 216 hRes = AtlRegisterTypeLib(pM->m_hInstTypeLib, NULL); 217 if (FAILED(hRes)) 218 return hRes; 219 } 220 221 return S_OK; 222 } 223 224 /*********************************************************************** 225 * AtlModuleGetClassObject [ATL.@] 226 */ 227 HRESULT WINAPI AtlModuleGetClassObject(_ATL_MODULEW *pm, REFCLSID rclsid, 228 REFIID riid, LPVOID *ppv) 229 { 230 _ATL_OBJMAP_ENTRYW_V1 *obj; 231 int i; 232 HRESULT hres = CLASS_E_CLASSNOTAVAILABLE; 233 234 TRACE("%p %s %s %p\n", pm, debugstr_guid(rclsid), debugstr_guid(riid), ppv); 235 236 if (pm == NULL) 237 return E_INVALIDARG; 238 239 for (i = 0; (obj = get_objmap_entry( pm, i )) != NULL; i++) 240 { 241 if (IsEqualCLSID(obj->pclsid, rclsid)) 242 { 243 TRACE("found object %i\n", i); 244 if (obj->pfnGetClassObject) 245 { 246 if (!obj->pCF) 247 hres = obj->pfnGetClassObject(obj->pfnCreateInstance, 248 &IID_IUnknown, 249 (void **)&obj->pCF); 250 if (obj->pCF) 251 hres = IUnknown_QueryInterface(obj->pCF, riid, ppv); 252 break; 253 } 254 } 255 } 256 257 WARN("no class object found for %s\n", debugstr_guid(rclsid)); 258 259 return hres; 260 } 261 262 /*********************************************************************** 263 * AtlModuleGetClassObject [ATL.@] 264 */ 265 HRESULT WINAPI AtlModuleRegisterTypeLib(_ATL_MODULEW *pm, LPCOLESTR lpszIndex) 266 { 267 TRACE("%p %s\n", pm, debugstr_w(lpszIndex)); 268 269 if (!pm) 270 return E_INVALIDARG; 271 272 return AtlRegisterTypeLib(pm->m_hInstTypeLib, lpszIndex); 273 } 274 275 /*********************************************************************** 276 * AtlModuleRevokeClassObjects [ATL.@] 277 */ 278 HRESULT WINAPI AtlModuleRevokeClassObjects(_ATL_MODULEW *pm) 279 { 280 FIXME("%p\n", pm); 281 return E_FAIL; 282 } 283 284 /*********************************************************************** 285 * AtlModuleUnregisterServer [ATL.@] 286 */ 287 HRESULT WINAPI AtlModuleUnregisterServer(_ATL_MODULEW *pm, const CLSID *clsid) 288 { 289 FIXME("%p %s\n", pm, debugstr_guid(clsid)); 290 return E_FAIL; 291 } 292 293 /*********************************************************************** 294 * AtlModuleRegisterWndClassInfoA [ATL.@] 295 * 296 * See AtlModuleRegisterWndClassInfoW. 297 */ 298 ATOM WINAPI AtlModuleRegisterWndClassInfoA(_ATL_MODULEA *pm, _ATL_WNDCLASSINFOA *wci, WNDPROC *pProc) 299 { 300 ATOM atom; 301 302 FIXME("%p %p %p semi-stub\n", pm, wci, pProc); 303 304 atom = wci->m_atom; 305 if (!atom) 306 { 307 WNDCLASSEXA wc; 308 309 TRACE("wci->m_wc.lpszClassName = %s\n", wci->m_wc.lpszClassName); 310 311 if (wci->m_lpszOrigName) 312 FIXME( "subclassing %s not implemented\n", debugstr_a(wci->m_lpszOrigName)); 313 314 if (!wci->m_wc.lpszClassName) 315 { 316 sprintf(wci->m_szAutoName, "ATL:%p", wci); 317 TRACE("auto-generated class name %s\n", wci->m_szAutoName); 318 wci->m_wc.lpszClassName = wci->m_szAutoName; 319 } 320 321 atom = GetClassInfoExA(pm->m_hInst, wci->m_wc.lpszClassName, &wc); 322 if (!atom) 323 { 324 wci->m_wc.hInstance = pm->m_hInst; 325 wci->m_wc.hCursor = LoadCursorA( wci->m_bSystemCursor ? NULL : pm->m_hInst, 326 wci->m_lpszCursorID ); 327 atom = RegisterClassExA(&wci->m_wc); 328 } 329 wci->pWndProc = wci->m_wc.lpfnWndProc; 330 wci->m_atom = atom; 331 } 332 333 if (wci->m_lpszOrigName) *pProc = wci->pWndProc; 334 335 TRACE("returning 0x%04x\n", atom); 336 return atom; 337 } 338 339 /*********************************************************************** 340 * AtlModuleRegisterWndClassInfoW [ATL.@] 341 * 342 * PARAMS 343 * pm [IO] Information about the module registering the window. 344 * wci [IO] Information about the window being registered. 345 * pProc [O] Window procedure of the registered class. 346 * 347 * RETURNS 348 * Atom representing the registered class. 349 * 350 * NOTES 351 * Can be called multiple times without error, unlike RegisterClassEx(). 352 * 353 * If the class name is NULL, then a class with a name of "ATL:xxxxxxxx" is 354 * registered, where 'xxxxxxxx' represents a unique hexadecimal value. 355 * 356 */ 357 ATOM WINAPI AtlModuleRegisterWndClassInfoW(_ATL_MODULEW *pm, _ATL_WNDCLASSINFOW *wci, WNDPROC *pProc) 358 { 359 ATOM atom; 360 361 FIXME("%p %p %p semi-stub\n", pm, wci, pProc); 362 363 atom = wci->m_atom; 364 if (!atom) 365 { 366 WNDCLASSEXW wc; 367 368 TRACE("wci->m_wc.lpszClassName = %s\n", debugstr_w(wci->m_wc.lpszClassName)); 369 370 if (wci->m_lpszOrigName) 371 FIXME( "subclassing %s not implemented\n", debugstr_w(wci->m_lpszOrigName)); 372 373 if (!wci->m_wc.lpszClassName) 374 { 375 #ifndef __REACTOS__ 376 swprintf(wci->m_szAutoName, ARRAY_SIZE(wci->m_szAutoName), L"ATL:%p", wci); 377 #else 378 swprintf(wci->m_szAutoName, L"ATL:%p", wci); 379 #endif 380 TRACE("auto-generated class name %s\n", debugstr_w(wci->m_szAutoName)); 381 wci->m_wc.lpszClassName = wci->m_szAutoName; 382 } 383 384 atom = GetClassInfoExW(pm->m_hInst, wci->m_wc.lpszClassName, &wc); 385 if (!atom) 386 { 387 wci->m_wc.hInstance = pm->m_hInst; 388 wci->m_wc.hCursor = LoadCursorW( wci->m_bSystemCursor ? NULL : pm->m_hInst, 389 wci->m_lpszCursorID ); 390 atom = RegisterClassExW(&wci->m_wc); 391 } 392 wci->pWndProc = wci->m_wc.lpfnWndProc; 393 wci->m_atom = atom; 394 } 395 396 if (wci->m_lpszOrigName) *pProc = wci->pWndProc; 397 398 TRACE("returning 0x%04x\n", atom); 399 return atom; 400 } 401 402 /*********************************************************************** 403 * AtlModuleAddCreateWndData [ATL.@] 404 */ 405 void WINAPI AtlModuleAddCreateWndData(_ATL_MODULEW *pM, _AtlCreateWndData *pData, void* pvObject) 406 { 407 TRACE("(%p, %p, %p)\n", pM, pData, pvObject); 408 409 pData->m_pThis = pvObject; 410 pData->m_dwThreadID = GetCurrentThreadId(); 411 412 EnterCriticalSection(&pM->m_csWindowCreate); 413 pData->m_pNext = pM->m_pCreateWndList; 414 pM->m_pCreateWndList = pData; 415 LeaveCriticalSection(&pM->m_csWindowCreate); 416 } 417 418 /*********************************************************************** 419 * AtlModuleExtractCreateWndData [ATL.@] 420 * 421 * NOTE: Tests show that this function extracts one of _AtlCreateWndData 422 * records from the current thread from a list 423 * 424 */ 425 void* WINAPI AtlModuleExtractCreateWndData(_ATL_MODULEW *pM) 426 { 427 _AtlCreateWndData **ppData; 428 void *ret = NULL; 429 430 TRACE("(%p)\n", pM); 431 432 EnterCriticalSection(&pM->m_csWindowCreate); 433 434 for(ppData = &pM->m_pCreateWndList; *ppData!=NULL; ppData = &(*ppData)->m_pNext) 435 { 436 if ((*ppData)->m_dwThreadID == GetCurrentThreadId()) 437 { 438 _AtlCreateWndData *pData = *ppData; 439 *ppData = pData->m_pNext; 440 ret = pData->m_pThis; 441 break; 442 } 443 } 444 445 LeaveCriticalSection(&pM->m_csWindowCreate); 446 return ret; 447 } 448 449 /*********************************************************************** 450 * AtlModuleUpdateRegistryFromResourceD [ATL.@] 451 * 452 */ 453 HRESULT WINAPI AtlModuleUpdateRegistryFromResourceD(_ATL_MODULEW* pM, LPCOLESTR lpszRes, 454 BOOL bRegister, struct _ATL_REGMAP_ENTRY* pMapEntries, IRegistrar* pReg) 455 { 456 TRACE("(%p %s %d %p %p)\n", pM, debugstr_w(lpszRes), bRegister, pMapEntries, pReg); 457 458 return AtlUpdateRegistryFromResourceD(pM->m_hInst, lpszRes, bRegister, pMapEntries, pReg); 459 } 460 461 static HRESULT WINAPI RegistrarCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppvObject) 462 { 463 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject); 464 465 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) { 466 *ppvObject = iface; 467 IClassFactory_AddRef( iface ); 468 return S_OK; 469 } 470 471 return E_NOINTERFACE; 472 } 473 474 static ULONG WINAPI RegistrarCF_AddRef(IClassFactory *iface) 475 { 476 return 2; 477 } 478 479 static ULONG WINAPI RegistrarCF_Release(IClassFactory *iface) 480 { 481 return 1; 482 } 483 484 static HRESULT WINAPI RegistrarCF_CreateInstance(IClassFactory *iface, LPUNKNOWN pUnkOuter, 485 REFIID riid, void **ppv) 486 { 487 IRegistrar *registrar; 488 HRESULT hres; 489 490 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv); 491 492 if(pUnkOuter) { 493 *ppv = NULL; 494 return CLASS_E_NOAGGREGATION; 495 } 496 497 hres = AtlCreateRegistrar(®istrar); 498 if(FAILED(hres)) 499 return hres; 500 501 hres = IRegistrar_QueryInterface(registrar, riid, ppv); 502 IRegistrar_Release(registrar); 503 return hres; 504 } 505 506 static HRESULT WINAPI RegistrarCF_LockServer(IClassFactory *iface, BOOL lock) 507 { 508 TRACE("(%p)->(%x)\n", iface, lock); 509 return S_OK; 510 } 511 512 static const IClassFactoryVtbl IRegistrarCFVtbl = { 513 RegistrarCF_QueryInterface, 514 RegistrarCF_AddRef, 515 RegistrarCF_Release, 516 RegistrarCF_CreateInstance, 517 RegistrarCF_LockServer 518 }; 519 520 static IClassFactory RegistrarCF = { &IRegistrarCFVtbl }; 521 522 #ifdef __REACTOS__ 523 static HRESULT do_register_dll_server(IRegistrar *pRegistrar, LPCOLESTR wszDll, 524 LPCOLESTR wszId, BOOL do_register, 525 const struct _ATL_REGMAP_ENTRY* pMapEntries) 526 { 527 IRegistrar *registrar; 528 HRESULT hres; 529 const struct _ATL_REGMAP_ENTRY *pMapEntry; 530 531 static const WCHAR wszModule[] = {'M','O','D','U','L','E',0}; 532 static const WCHAR wszRegistry[] = {'R','E','G','I','S','T','R','Y',0}; 533 534 if(pRegistrar) { 535 registrar = pRegistrar; 536 }else { 537 hres = AtlCreateRegistrar(®istrar); 538 if(FAILED(hres)) 539 return hres; 540 } 541 542 IRegistrar_AddReplacement(registrar, wszModule, wszDll); 543 544 for (pMapEntry = pMapEntries; pMapEntry && pMapEntry->szKey; pMapEntry++) 545 IRegistrar_AddReplacement(registrar, pMapEntry->szKey, pMapEntry->szData); 546 547 if(do_register) 548 hres = IRegistrar_ResourceRegisterSz(registrar, wszDll, wszId, wszRegistry); 549 else 550 hres = IRegistrar_ResourceUnregisterSz(registrar, wszDll, wszId, wszRegistry); 551 552 if(registrar != pRegistrar) 553 IRegistrar_Release(registrar); 554 return hres; 555 } 556 557 static HRESULT do_register_server(BOOL do_register) 558 { 559 static const WCHAR CLSID_RegistrarW[] = 560 {'C','L','S','I','D','_','R','e','g','i','s','t','r','a','r',0}; 561 static const WCHAR atl_dllW[] = {'a','t','l','.','d','l','l',0}; 562 563 WCHAR clsid_str[40]; 564 const struct _ATL_REGMAP_ENTRY reg_map[] = {{CLSID_RegistrarW, clsid_str}, {NULL,NULL}}; 565 566 StringFromGUID2(&CLSID_Registrar, clsid_str, sizeof(clsid_str)/sizeof(WCHAR)); 567 return do_register_dll_server(NULL, atl_dllW, MAKEINTRESOURCEW(101), do_register, reg_map); 568 } 569 #endif 570 571 /************************************************************** 572 * DllGetClassObject (ATL.2) 573 */ 574 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, LPVOID *ppvObject) 575 { 576 TRACE("(%s %s %p)\n", debugstr_guid(clsid), debugstr_guid(riid), ppvObject); 577 578 if(IsEqualGUID(&CLSID_Registrar, clsid)) 579 return IClassFactory_QueryInterface( &RegistrarCF, riid, ppvObject ); 580 581 FIXME("Not supported class %s\n", debugstr_guid(clsid)); 582 return CLASS_E_CLASSNOTAVAILABLE; 583 } 584 585 /*********************************************************************** 586 * DllRegisterServer (ATL.@) 587 */ 588 HRESULT WINAPI DllRegisterServer(void) 589 { 590 #ifdef __REACTOS__ 591 /* Note: we can't use __wine_register_server here because it uses CLSID_Registrar which isn't registred yet */ 592 return do_register_server(TRUE); 593 #else 594 return __wine_register_resources( atl_instance ); 595 #endif 596 } 597 598 /*********************************************************************** 599 * DllUnRegisterServer (ATL.@) 600 */ 601 HRESULT WINAPI DllUnregisterServer(void) 602 { 603 #ifdef __REACTOS__ 604 return do_register_server(FALSE); 605 #else 606 return __wine_unregister_resources( atl_instance ); 607 #endif 608 } 609 610 /*********************************************************************** 611 * DllCanUnloadNow (ATL.@) 612 */ 613 HRESULT WINAPI DllCanUnloadNow(void) 614 { 615 return S_FALSE; 616 } 617