/* * Implementation of Active Template Library (atl.dll) * * Copyright 2004 Aric Stewart for CodeWeavers * * 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 #include #define COBJMACROS #include "windef.h" #include "winbase.h" #include "winerror.h" #include "wingdi.h" #include "winuser.h" #include "wine/debug.h" #include "objbase.h" #include "objidl.h" #include "ole2.h" #include "atlbase.h" #include "atliface.h" #include "atlwin.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(atl); DECLSPEC_HIDDEN HINSTANCE hInst; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved); if (fdwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hinstDLL); hInst = hinstDLL; } return TRUE; } #define ATLVer1Size FIELD_OFFSET(_ATL_MODULEW, dwAtlBuildVer) HRESULT WINAPI AtlModuleInit(_ATL_MODULEW* pM, _ATL_OBJMAP_ENTRYW* p, HINSTANCE h) { INT i; UINT size; FIXME("SEMI-STUB (%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) { HRESULT hRes; OLECHAR path[MAX_PATH+8]; /* leave some space for index */ TRACE("(%p, %s, %p, %p)\n", pM, debugstr_w(lpszIndex), pbstrPath, ppTypeLib); if (!pM) return E_INVALIDARG; GetModuleFileNameW(pM->m_hInstTypeLib, path, MAX_PATH); if (lpszIndex) lstrcatW(path, lpszIndex); hRes = LoadTypeLib(path, ppTypeLib); if (FAILED(hRes)) return hRes; *pbstrPath = SysAllocString(path); return S_OK; } HRESULT WINAPI AtlModuleTerm(_ATL_MODULEW* pM) { _ATL_TERMFUNC_ELEM *iter = pM->m_pTermFuncs, *tmp; TRACE("(%p)\n", pM); while(iter) { iter->pFunc(iter->dw); tmp = iter; iter = iter->pNext; HeapFree(GetProcessHeap(), 0, tmp); } HeapFree(GetProcessHeap(), 0, pM); return S_OK; } HRESULT WINAPI AtlModuleAddTermFunc(_ATL_MODULEW *pM, _ATL_TERMFUNC *pFunc, DWORD_PTR dw) { _ATL_TERMFUNC_ELEM *termfunc_elem; TRACE("(%p %p %ld)\n", pM, pFunc, dw); termfunc_elem = HeapAlloc(GetProcessHeap(), 0, sizeof(_ATL_TERMFUNC_ELEM)); termfunc_elem->pFunc = pFunc; termfunc_elem->dw = dw; termfunc_elem->pNext = pM->m_pTermFuncs; pM->m_pTermFuncs = termfunc_elem; return S_OK; } HRESULT WINAPI AtlModuleRegisterClassObjects(_ATL_MODULEW *pM, DWORD dwClsContext, DWORD dwFlags) { _ATL_OBJMAP_ENTRYW_V1 *obj; HRESULT hRes = S_OK; 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) ) { CoRegisterClassObject(obj->pclsid, pUnknown, dwClsContext, dwFlags, &obj->dwRegister); if (pUnknown) IUnknown_Release(pUnknown); } } } return hRes; } HRESULT WINAPI AtlModuleUnregisterServerEx(_ATL_MODULEW* pM, BOOL bUnRegTypeLib, const CLSID* pCLSID) { FIXME("(%p, %i, %p) stub\n", pM, bUnRegTypeLib, pCLSID); return S_OK; } IUnknown* WINAPI AtlComPtrAssign(IUnknown** pp, IUnknown *p) { TRACE("(%p %p)\n", pp, p); if (p) IUnknown_AddRef(p); if (*pp) IUnknown_Release(*pp); *pp = p; return p; } IUnknown* WINAPI AtlComQIPtrAssign(IUnknown** pp, IUnknown *p, REFIID riid) { IUnknown *new_p = NULL; TRACE("(%p %p %s)\n", pp, p, debugstr_guid(riid)); if (p) IUnknown_QueryInterface(p, riid, (void **)&new_p); if (*pp) IUnknown_Release(*pp); *pp = new_p; return new_p; } HRESULT WINAPI AtlInternalQueryInterface(void* this, const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject) { int i = 0; HRESULT rc = E_NOINTERFACE; TRACE("(%p, %p, %s, %p)\n",this, pEntries, debugstr_guid(iid), ppvObject); if (IsEqualGUID(iid,&IID_IUnknown)) { TRACE("Returning IUnknown\n"); *ppvObject = ((LPSTR)this+pEntries[0].dw); IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } while (pEntries[i].pFunc != 0) { TRACE("Trying entry %i (%s %i %p)\n",i,debugstr_guid(pEntries[i].piid), pEntries[i].dw, pEntries[i].pFunc); if (!pEntries[i].piid || IsEqualGUID(iid,pEntries[i].piid)) { TRACE("MATCH\n"); if (pEntries[i].pFunc == (_ATL_CREATORARGFUNC*)1) { TRACE("Offset\n"); *ppvObject = ((LPSTR)this+pEntries[i].dw); IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } else { TRACE("Function\n"); rc = pEntries[i].pFunc(this, iid, ppvObject, pEntries[i].dw); if(rc==S_OK || pEntries[i].piid) return rc; } } i++; } TRACE("Done returning (0x%x)\n",rc); return rc; } /*********************************************************************** * 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 (bRegTypeLib) { hRes = AtlModuleRegisterTypeLib(pM, NULL); if (FAILED(hRes)) return hRes; } return S_OK; } /*********************************************************************** * AtlAdvise [ATL.@] */ HRESULT WINAPI AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID *iid, LPDWORD pdw) { FIXME("%p %p %p %p\n", pUnkCP, pUnk, iid, pdw); return E_FAIL; } /*********************************************************************** * AtlUnadvise [ATL.@] */ HRESULT WINAPI AtlUnadvise(IUnknown *pUnkCP, const IID *iid, DWORD dw) { FIXME("%p %p %d\n", pUnkCP, iid, dw); return S_OK; } /*********************************************************************** * AtlFreeMarshalStream [ATL.@] */ HRESULT WINAPI AtlFreeMarshalStream(IStream *stm) { FIXME("%p\n", stm); return S_OK; } /*********************************************************************** * AtlMarshalPtrInProc [ATL.@] */ HRESULT WINAPI AtlMarshalPtrInProc(IUnknown *pUnk, const IID *iid, IStream **pstm) { FIXME("%p %p %p\n", pUnk, iid, pstm); return E_FAIL; } /*********************************************************************** * AtlUnmarshalPtr [ATL.@] */ HRESULT WINAPI AtlUnmarshalPtr(IStream *stm, const IID *iid, IUnknown **ppUnk) { FIXME("%p %p %p\n", stm, iid, ppUnk); return E_FAIL; } /*********************************************************************** * 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) { HRESULT hRes; BSTR path; ITypeLib *typelib; TRACE("%p %s\n", pm, debugstr_w(lpszIndex)); if (!pm) return E_INVALIDARG; hRes = AtlModuleLoadTypeLib(pm, lpszIndex, &path, &typelib); if (SUCCEEDED(hRes)) { hRes = RegisterTypeLib(typelib, path, NULL); /* FIXME: pass help directory */ ITypeLib_Release(typelib); SysFreeString(path); } return hRes; } /*********************************************************************** * 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; } void WINAPI AtlHiMetricToPixel(const SIZEL* lpHiMetric, SIZEL* lpPix) { HDC dc = GetDC(NULL); lpPix->cx = lpHiMetric->cx * GetDeviceCaps( dc, LOGPIXELSX ) / 100; lpPix->cy = lpHiMetric->cy * GetDeviceCaps( dc, LOGPIXELSY ) / 100; ReleaseDC( NULL, dc ); } void WINAPI AtlPixelToHiMetric(const SIZEL* lpPix, SIZEL* lpHiMetric) { HDC dc = GetDC(NULL); lpHiMetric->cx = 100 * lpPix->cx / GetDeviceCaps( dc, LOGPIXELSX ); lpHiMetric->cy = 100 * lpPix->cy / GetDeviceCaps( dc, LOGPIXELSY ); ReleaseDC( NULL, dc ); } /*********************************************************************** * AtlCreateTargetDC [ATL.@] */ HDC WINAPI AtlCreateTargetDC( HDC hdc, DVTARGETDEVICE *dv ) { static const WCHAR displayW[] = {'d','i','s','p','l','a','y',0}; const WCHAR *driver = NULL, *device = NULL, *port = NULL; DEVMODEW *devmode = NULL; TRACE( "(%p, %p)\n", hdc, dv ); if (dv) { if (dv->tdDriverNameOffset) driver = (WCHAR *)((char *)dv + dv->tdDriverNameOffset); if (dv->tdDeviceNameOffset) device = (WCHAR *)((char *)dv + dv->tdDeviceNameOffset); if (dv->tdPortNameOffset) port = (WCHAR *)((char *)dv + dv->tdPortNameOffset); if (dv->tdExtDevmodeOffset) devmode = (DEVMODEW *)((char *)dv + dv->tdExtDevmodeOffset); } else { if (hdc) return hdc; driver = displayW; } return CreateDCW( driver, device, port, devmode ); } /*********************************************************************** * 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(); pData->m_pNext = pM->m_pCreateWndList; pM->m_pCreateWndList = pData; } /*********************************************************************** * AtlModuleExtractCreateWndData [ATL.@] * * NOTE: I failed to find any good description of this function. * 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; TRACE("(%p)\n", pM); for(ppData = &pM->m_pCreateWndList; *ppData!=NULL; ppData = &(*ppData)->m_pNext) { if ((*ppData)->m_dwThreadID == GetCurrentThreadId()) { _AtlCreateWndData *pData = *ppData; *ppData = pData->m_pNext; return pData->m_pThis; } } return NULL; } /* FIXME: should be in a header file */ typedef struct ATL_PROPMAP_ENTRY { LPCOLESTR szDesc; DISPID dispid; const CLSID* pclsidPropPage; const IID* piidDispatch; DWORD dwOffsetData; DWORD dwSizeData; VARTYPE vt; } ATL_PROPMAP_ENTRY; /*********************************************************************** * AtlIPersistStreamInit_Load [ATL.@] */ HRESULT WINAPI AtlIPersistStreamInit_Load( LPSTREAM pStm, ATL_PROPMAP_ENTRY *pMap, void *pThis, IUnknown *pUnk) { FIXME("(%p, %p, %p, %p)\n", pStm, pMap, pThis, pUnk); return S_OK; } HRESULT WINAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY *pMap, void *pThis, IUnknown *pUnk) { FIXME("(%p, %d, %p, %p, %p)\n", pStm, fClearDirty, pMap, pThis, pUnk); return S_OK; }