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