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