xref: /reactos/dll/win32/atl/atl30.c (revision 94a413ae)
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(&registrar);
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(&registrar);
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