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