| /* |
| * Implementation of Active Template Library (atl.dll) |
| * |
| * Copyright 2004 Aric Stewart for CodeWeavers |
| * Copyright 2005 Jacek Caban |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdio.h> |
| |
| #define COBJMACROS |
| |
| #include "objidl.h" |
| #include "rpcproxy.h" |
| #include "atlbase.h" |
| #include "atlwin.h" |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(atl); |
| |
| extern HINSTANCE atl_instance; |
| |
| #define ATLVer1Size FIELD_OFFSET(_ATL_MODULEW, dwAtlBuildVer) |
| |
| HRESULT WINAPI AtlModuleInit(_ATL_MODULEW* pM, _ATL_OBJMAP_ENTRYW* p, HINSTANCE h) |
| { |
| INT i; |
| UINT size; |
| |
| TRACE("(%p %p %p)\n", pM, p, h); |
| |
| size = pM->cbSize; |
| switch (size) |
| { |
| case ATLVer1Size: |
| case sizeof(_ATL_MODULEW): |
| #ifdef _WIN64 |
| case sizeof(_ATL_MODULEW) + sizeof(void *): |
| #endif |
| break; |
| default: |
| WARN("Unknown structure version (size %i)\n",size); |
| return E_INVALIDARG; |
| } |
| |
| memset(pM,0,pM->cbSize); |
| pM->cbSize = size; |
| pM->m_hInst = h; |
| pM->m_hInstResource = h; |
| pM->m_hInstTypeLib = h; |
| pM->m_pObjMap = p; |
| pM->m_hHeap = GetProcessHeap(); |
| |
| InitializeCriticalSection(&pM->u.m_csTypeInfoHolder); |
| InitializeCriticalSection(&pM->m_csWindowCreate); |
| InitializeCriticalSection(&pM->m_csObjMap); |
| |
| /* call mains */ |
| i = 0; |
| if (pM->m_pObjMap != NULL && size > ATLVer1Size) |
| { |
| while (pM->m_pObjMap[i].pclsid != NULL) |
| { |
| TRACE("Initializing object %i %p\n",i,p[i].pfnObjectMain); |
| if (p[i].pfnObjectMain) |
| p[i].pfnObjectMain(TRUE); |
| i++; |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| static _ATL_OBJMAP_ENTRYW_V1 *get_objmap_entry( _ATL_MODULEW *mod, unsigned int index ) |
| { |
| _ATL_OBJMAP_ENTRYW_V1 *ret; |
| |
| if (mod->cbSize == ATLVer1Size) |
| ret = (_ATL_OBJMAP_ENTRYW_V1 *)mod->m_pObjMap + index; |
| else |
| ret = (_ATL_OBJMAP_ENTRYW_V1 *)(mod->m_pObjMap + index); |
| |
| if (!ret->pclsid) ret = NULL; |
| return ret; |
| } |
| |
| HRESULT WINAPI AtlModuleLoadTypeLib(_ATL_MODULEW *pM, LPCOLESTR lpszIndex, |
| BSTR *pbstrPath, ITypeLib **ppTypeLib) |
| { |
| TRACE("(%p, %s, %p, %p)\n", pM, debugstr_w(lpszIndex), pbstrPath, ppTypeLib); |
| |
| if (!pM) |
| return E_INVALIDARG; |
| |
| return AtlLoadTypeLib(pM->m_hInstTypeLib, lpszIndex, pbstrPath, ppTypeLib); |
| } |
| |
| HRESULT WINAPI AtlModuleTerm(_ATL_MODULE *pM) |
| { |
| _ATL_TERMFUNC_ELEM *iter, *tmp; |
| |
| TRACE("(%p)\n", pM); |
| |
| if (pM->cbSize > ATLVer1Size) |
| { |
| iter = pM->m_pTermFuncs; |
| |
| while(iter) { |
| iter->pFunc(iter->dw); |
| tmp = iter; |
| iter = iter->pNext; |
| HeapFree(GetProcessHeap(), 0, tmp); |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT WINAPI AtlModuleRegisterClassObjects(_ATL_MODULEW *pM, DWORD dwClsContext, |
| DWORD dwFlags) |
| { |
| _ATL_OBJMAP_ENTRYW_V1 *obj; |
| int i=0; |
| |
| TRACE("(%p %i %i)\n",pM, dwClsContext, dwFlags); |
| |
| if (pM == NULL) |
| return E_INVALIDARG; |
| |
| while ((obj = get_objmap_entry( pM, i++ ))) |
| { |
| IUnknown* pUnknown; |
| HRESULT rc; |
| |
| TRACE("Registering object %i\n",i); |
| if (obj->pfnGetClassObject) |
| { |
| rc = obj->pfnGetClassObject(obj->pfnCreateInstance, &IID_IUnknown, |
| (LPVOID*)&pUnknown); |
| if (SUCCEEDED (rc) ) |
| { |
| rc = CoRegisterClassObject(obj->pclsid, pUnknown, dwClsContext, |
| dwFlags, &obj->dwRegister); |
| |
| if (FAILED (rc) ) |
| WARN("Failed to register object %i: 0x%08x\n", i, rc); |
| |
| if (pUnknown) |
| IUnknown_Release(pUnknown); |
| } |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT WINAPI AtlModuleUnregisterServerEx(_ATL_MODULEW* pM, BOOL bUnRegTypeLib, const CLSID* pCLSID) |
| { |
| FIXME("(%p, %i, %p) stub\n", pM, bUnRegTypeLib, pCLSID); |
| return S_OK; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleRegisterServer [ATL.@] |
| * |
| */ |
| HRESULT WINAPI AtlModuleRegisterServer(_ATL_MODULEW* pM, BOOL bRegTypeLib, const CLSID* clsid) |
| { |
| const _ATL_OBJMAP_ENTRYW_V1 *obj; |
| int i; |
| HRESULT hRes; |
| |
| TRACE("%p %d %s\n", pM, bRegTypeLib, debugstr_guid(clsid)); |
| |
| if (pM == NULL) |
| return E_INVALIDARG; |
| |
| for (i = 0; (obj = get_objmap_entry( pM, i )) != NULL; i++) /* register CLSIDs */ |
| { |
| if (!clsid || IsEqualCLSID(obj->pclsid, clsid)) |
| { |
| TRACE("Registering clsid %s\n", debugstr_guid(obj->pclsid)); |
| hRes = obj->pfnUpdateRegistry(TRUE); /* register */ |
| if (FAILED(hRes)) |
| return hRes; |
| |
| if(pM->cbSize > ATLVer1Size) { |
| const struct _ATL_CATMAP_ENTRY *catmap; |
| |
| catmap = ((const _ATL_OBJMAP_ENTRYW*)obj)->pfnGetCategoryMap(); |
| if(catmap) { |
| hRes = AtlRegisterClassCategoriesHelper(obj->pclsid, catmap, TRUE); |
| if(FAILED(hRes)) |
| return hRes; |
| } |
| } |
| } |
| } |
| |
| if (bRegTypeLib) |
| { |
| hRes = AtlRegisterTypeLib(pM->m_hInstTypeLib, NULL); |
| if (FAILED(hRes)) |
| return hRes; |
| } |
| |
| return S_OK; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleGetClassObject [ATL.@] |
| */ |
| HRESULT WINAPI AtlModuleGetClassObject(_ATL_MODULEW *pm, REFCLSID rclsid, |
| REFIID riid, LPVOID *ppv) |
| { |
| _ATL_OBJMAP_ENTRYW_V1 *obj; |
| int i; |
| HRESULT hres = CLASS_E_CLASSNOTAVAILABLE; |
| |
| TRACE("%p %s %s %p\n", pm, debugstr_guid(rclsid), debugstr_guid(riid), ppv); |
| |
| if (pm == NULL) |
| return E_INVALIDARG; |
| |
| for (i = 0; (obj = get_objmap_entry( pm, i )) != NULL; i++) |
| { |
| if (IsEqualCLSID(obj->pclsid, rclsid)) |
| { |
| TRACE("found object %i\n", i); |
| if (obj->pfnGetClassObject) |
| { |
| if (!obj->pCF) |
| hres = obj->pfnGetClassObject(obj->pfnCreateInstance, |
| &IID_IUnknown, |
| (void **)&obj->pCF); |
| if (obj->pCF) |
| hres = IUnknown_QueryInterface(obj->pCF, riid, ppv); |
| break; |
| } |
| } |
| } |
| |
| WARN("no class object found for %s\n", debugstr_guid(rclsid)); |
| |
| return hres; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleGetClassObject [ATL.@] |
| */ |
| HRESULT WINAPI AtlModuleRegisterTypeLib(_ATL_MODULEW *pm, LPCOLESTR lpszIndex) |
| { |
| TRACE("%p %s\n", pm, debugstr_w(lpszIndex)); |
| |
| if (!pm) |
| return E_INVALIDARG; |
| |
| return AtlRegisterTypeLib(pm->m_hInstTypeLib, lpszIndex); |
| } |
| |
| /*********************************************************************** |
| * AtlModuleRevokeClassObjects [ATL.@] |
| */ |
| HRESULT WINAPI AtlModuleRevokeClassObjects(_ATL_MODULEW *pm) |
| { |
| FIXME("%p\n", pm); |
| return E_FAIL; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleUnregisterServer [ATL.@] |
| */ |
| HRESULT WINAPI AtlModuleUnregisterServer(_ATL_MODULEW *pm, const CLSID *clsid) |
| { |
| FIXME("%p %s\n", pm, debugstr_guid(clsid)); |
| return E_FAIL; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleRegisterWndClassInfoA [ATL.@] |
| * |
| * See AtlModuleRegisterWndClassInfoW. |
| */ |
| ATOM WINAPI AtlModuleRegisterWndClassInfoA(_ATL_MODULEA *pm, _ATL_WNDCLASSINFOA *wci, WNDPROC *pProc) |
| { |
| ATOM atom; |
| |
| FIXME("%p %p %p semi-stub\n", pm, wci, pProc); |
| |
| atom = wci->m_atom; |
| if (!atom) |
| { |
| WNDCLASSEXA wc; |
| |
| TRACE("wci->m_wc.lpszClassName = %s\n", wci->m_wc.lpszClassName); |
| |
| if (wci->m_lpszOrigName) |
| FIXME( "subclassing %s not implemented\n", debugstr_a(wci->m_lpszOrigName)); |
| |
| if (!wci->m_wc.lpszClassName) |
| { |
| snprintf(wci->m_szAutoName, sizeof(wci->m_szAutoName), "ATL%08lx", (UINT_PTR)wci); |
| TRACE("auto-generated class name %s\n", wci->m_szAutoName); |
| wci->m_wc.lpszClassName = wci->m_szAutoName; |
| } |
| |
| atom = GetClassInfoExA(pm->m_hInst, wci->m_wc.lpszClassName, &wc); |
| if (!atom) |
| { |
| wci->m_wc.hInstance = pm->m_hInst; |
| wci->m_wc.hCursor = LoadCursorA( wci->m_bSystemCursor ? NULL : pm->m_hInst, |
| wci->m_lpszCursorID ); |
| atom = RegisterClassExA(&wci->m_wc); |
| } |
| wci->pWndProc = wci->m_wc.lpfnWndProc; |
| wci->m_atom = atom; |
| } |
| |
| if (wci->m_lpszOrigName) *pProc = wci->pWndProc; |
| |
| TRACE("returning 0x%04x\n", atom); |
| return atom; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleRegisterWndClassInfoW [ATL.@] |
| * |
| * PARAMS |
| * pm [IO] Information about the module registering the window. |
| * wci [IO] Information about the window being registered. |
| * pProc [O] Window procedure of the registered class. |
| * |
| * RETURNS |
| * Atom representing the registered class. |
| * |
| * NOTES |
| * Can be called multiple times without error, unlike RegisterClassEx(). |
| * |
| * If the class name is NULL, then a class with a name of "ATLxxxxxxxx" is |
| * registered, where the 'x's represent a unique value. |
| * |
| */ |
| ATOM WINAPI AtlModuleRegisterWndClassInfoW(_ATL_MODULEW *pm, _ATL_WNDCLASSINFOW *wci, WNDPROC *pProc) |
| { |
| ATOM atom; |
| |
| FIXME("%p %p %p semi-stub\n", pm, wci, pProc); |
| |
| atom = wci->m_atom; |
| if (!atom) |
| { |
| WNDCLASSEXW wc; |
| |
| TRACE("wci->m_wc.lpszClassName = %s\n", debugstr_w(wci->m_wc.lpszClassName)); |
| |
| if (wci->m_lpszOrigName) |
| FIXME( "subclassing %s not implemented\n", debugstr_w(wci->m_lpszOrigName)); |
| |
| if (!wci->m_wc.lpszClassName) |
| { |
| static const WCHAR szFormat[] = {'A','T','L','%','0','8','l','x',0}; |
| snprintfW(wci->m_szAutoName, sizeof(wci->m_szAutoName)/sizeof(WCHAR), szFormat, (UINT_PTR)wci); |
| TRACE("auto-generated class name %s\n", debugstr_w(wci->m_szAutoName)); |
| wci->m_wc.lpszClassName = wci->m_szAutoName; |
| } |
| |
| atom = GetClassInfoExW(pm->m_hInst, wci->m_wc.lpszClassName, &wc); |
| if (!atom) |
| { |
| wci->m_wc.hInstance = pm->m_hInst; |
| wci->m_wc.hCursor = LoadCursorW( wci->m_bSystemCursor ? NULL : pm->m_hInst, |
| wci->m_lpszCursorID ); |
| atom = RegisterClassExW(&wci->m_wc); |
| } |
| wci->pWndProc = wci->m_wc.lpfnWndProc; |
| wci->m_atom = atom; |
| } |
| |
| if (wci->m_lpszOrigName) *pProc = wci->pWndProc; |
| |
| TRACE("returning 0x%04x\n", atom); |
| return atom; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleAddCreateWndData [ATL.@] |
| */ |
| void WINAPI AtlModuleAddCreateWndData(_ATL_MODULEW *pM, _AtlCreateWndData *pData, void* pvObject) |
| { |
| TRACE("(%p, %p, %p)\n", pM, pData, pvObject); |
| |
| pData->m_pThis = pvObject; |
| pData->m_dwThreadID = GetCurrentThreadId(); |
| |
| EnterCriticalSection(&pM->m_csWindowCreate); |
| pData->m_pNext = pM->m_pCreateWndList; |
| pM->m_pCreateWndList = pData; |
| LeaveCriticalSection(&pM->m_csWindowCreate); |
| } |
| |
| /*********************************************************************** |
| * AtlModuleExtractCreateWndData [ATL.@] |
| * |
| * NOTE: Tests show that this function extracts one of _AtlCreateWndData |
| * records from the current thread from a list |
| * |
| */ |
| void* WINAPI AtlModuleExtractCreateWndData(_ATL_MODULEW *pM) |
| { |
| _AtlCreateWndData **ppData; |
| void *ret = NULL; |
| |
| TRACE("(%p)\n", pM); |
| |
| EnterCriticalSection(&pM->m_csWindowCreate); |
| |
| for(ppData = &pM->m_pCreateWndList; *ppData!=NULL; ppData = &(*ppData)->m_pNext) |
| { |
| if ((*ppData)->m_dwThreadID == GetCurrentThreadId()) |
| { |
| _AtlCreateWndData *pData = *ppData; |
| *ppData = pData->m_pNext; |
| ret = pData->m_pThis; |
| break; |
| } |
| } |
| |
| LeaveCriticalSection(&pM->m_csWindowCreate); |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * AtlModuleUpdateRegistryFromResourceD [ATL.@] |
| * |
| */ |
| HRESULT WINAPI AtlModuleUpdateRegistryFromResourceD(_ATL_MODULEW* pM, LPCOLESTR lpszRes, |
| BOOL bRegister, struct _ATL_REGMAP_ENTRY* pMapEntries, IRegistrar* pReg) |
| { |
| TRACE("(%p %s %d %p %p)\n", pM, debugstr_w(lpszRes), bRegister, pMapEntries, pReg); |
| |
| return AtlUpdateRegistryFromResourceD(pM->m_hInst, lpszRes, bRegister, pMapEntries, pReg); |
| } |
| |
| static HRESULT WINAPI RegistrarCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppvObject) |
| { |
| TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject); |
| |
| if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) { |
| *ppvObject = iface; |
| IClassFactory_AddRef( iface ); |
| return S_OK; |
| } |
| |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI RegistrarCF_AddRef(IClassFactory *iface) |
| { |
| return 2; |
| } |
| |
| static ULONG WINAPI RegistrarCF_Release(IClassFactory *iface) |
| { |
| return 1; |
| } |
| |
| static HRESULT WINAPI RegistrarCF_CreateInstance(IClassFactory *iface, LPUNKNOWN pUnkOuter, |
| REFIID riid, void **ppv) |
| { |
| IRegistrar *registrar; |
| HRESULT hres; |
| |
| TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if(pUnkOuter) { |
| *ppv = NULL; |
| return CLASS_E_NOAGGREGATION; |
| } |
| |
| hres = AtlCreateRegistrar(®istrar); |
| if(FAILED(hres)) |
| return hres; |
| |
| hres = IRegistrar_QueryInterface(registrar, riid, ppv); |
| IRegistrar_Release(registrar); |
| return hres; |
| } |
| |
| static HRESULT WINAPI RegistrarCF_LockServer(IClassFactory *iface, BOOL lock) |
| { |
| TRACE("(%p)->(%x)\n", iface, lock); |
| return S_OK; |
| } |
| |
| static const IClassFactoryVtbl IRegistrarCFVtbl = { |
| RegistrarCF_QueryInterface, |
| RegistrarCF_AddRef, |
| RegistrarCF_Release, |
| RegistrarCF_CreateInstance, |
| RegistrarCF_LockServer |
| }; |
| |
| static IClassFactory RegistrarCF = { &IRegistrarCFVtbl }; |
| |
| /************************************************************** |
| * DllGetClassObject (ATL.2) |
| */ |
| HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, LPVOID *ppvObject) |
| { |
| TRACE("(%s %s %p)\n", debugstr_guid(clsid), debugstr_guid(riid), ppvObject); |
| |
| if(IsEqualGUID(&CLSID_Registrar, clsid)) |
| return IClassFactory_QueryInterface( &RegistrarCF, riid, ppvObject ); |
| |
| FIXME("Not supported class %s\n", debugstr_guid(clsid)); |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| |
| /*********************************************************************** |
| * DllRegisterServer (ATL.@) |
| */ |
| HRESULT WINAPI DllRegisterServer(void) |
| { |
| return __wine_register_resources( atl_instance ); |
| } |
| |
| /*********************************************************************** |
| * DllUnRegisterServer (ATL.@) |
| */ |
| HRESULT WINAPI DllUnregisterServer(void) |
| { |
| return __wine_unregister_resources( atl_instance ); |
| } |
| |
| /*********************************************************************** |
| * DllCanUnloadNow (ATL.@) |
| */ |
| HRESULT WINAPI DllCanUnloadNow(void) |
| { |
| return S_FALSE; |
| } |