xref: /reactos/dll/win32/atl/atl.c (revision bae2bac6)
1 /*
2  * Copyright 2012 Stefan Leichter
3  * Copyright 2012 Jacek Caban for CodeWeavers
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #define COBJMACROS
21 
22 #include "wine/atlbase.h"
23 #include "wine/atlcom.h"
24 
25 #include "wine/debug.h"
26 #include "wine/heap.h"
27 #include "wine/unicode.h"
28 
29 #ifdef __REACTOS__
30 #include <wingdi.h>
31 #endif
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(atl);
34 
35 #define ATLVer1Size FIELD_OFFSET(_ATL_MODULEW, dwAtlBuildVer)
36 
37 HINSTANCE atl_instance;
38 
39 typedef unsigned char cpp_bool;
40 
41 static ICatRegister *catreg;
42 
43 /***********************************************************************
44  *           AtlAdvise         [atl100.@]
45  */
46 HRESULT WINAPI AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID *iid, DWORD *pdw)
47 {
48     IConnectionPointContainer *container;
49     IConnectionPoint *cp;
50     HRESULT hres;
51 
52     TRACE("%p %p %p %p\n", pUnkCP, pUnk, iid, pdw);
53 
54     if(!pUnkCP)
55         return E_INVALIDARG;
56 
57     hres = IUnknown_QueryInterface(pUnkCP, &IID_IConnectionPointContainer, (void**)&container);
58     if(FAILED(hres))
59         return hres;
60 
61     hres = IConnectionPointContainer_FindConnectionPoint(container, iid, &cp);
62     IConnectionPointContainer_Release(container);
63     if(FAILED(hres))
64         return hres;
65 
66     hres = IConnectionPoint_Advise(cp, pUnk, pdw);
67     IConnectionPoint_Release(cp);
68     return hres;
69 }
70 
71 /***********************************************************************
72  *           AtlUnadvise         [atl100.@]
73  */
74 HRESULT WINAPI AtlUnadvise(IUnknown *pUnkCP, const IID *iid, DWORD dw)
75 {
76     IConnectionPointContainer *container;
77     IConnectionPoint *cp;
78     HRESULT hres;
79 
80     TRACE("%p %p %d\n", pUnkCP, iid, dw);
81 
82     if(!pUnkCP)
83         return E_INVALIDARG;
84 
85     hres = IUnknown_QueryInterface(pUnkCP, &IID_IConnectionPointContainer, (void**)&container);
86     if(FAILED(hres))
87         return hres;
88 
89     hres = IConnectionPointContainer_FindConnectionPoint(container, iid, &cp);
90     IConnectionPointContainer_Release(container);
91     if(FAILED(hres))
92         return hres;
93 
94     hres = IConnectionPoint_Unadvise(cp, dw);
95     IConnectionPoint_Release(cp);
96     return hres;
97 }
98 
99 /***********************************************************************
100  *           AtlFreeMarshalStream         [atl100.@]
101  */
102 HRESULT WINAPI AtlFreeMarshalStream(IStream *stm)
103 {
104     FIXME("%p\n", stm);
105     return S_OK;
106 }
107 
108 /***********************************************************************
109  *           AtlMarshalPtrInProc         [atl100.@]
110  */
111 HRESULT WINAPI AtlMarshalPtrInProc(IUnknown *pUnk, const IID *iid, IStream **pstm)
112 {
113     FIXME("%p %p %p\n", pUnk, iid, pstm);
114     return E_FAIL;
115 }
116 
117 /***********************************************************************
118  *           AtlUnmarshalPtr              [atl100.@]
119  */
120 HRESULT WINAPI AtlUnmarshalPtr(IStream *stm, const IID *iid, IUnknown **ppUnk)
121 {
122     FIXME("%p %p %p\n", stm, iid, ppUnk);
123     return E_FAIL;
124 }
125 
126 /***********************************************************************
127  *           AtlCreateTargetDC         [atl100.@]
128  */
129 HDC WINAPI AtlCreateTargetDC( HDC hdc, DVTARGETDEVICE *dv )
130 {
131     static const WCHAR displayW[] = {'d','i','s','p','l','a','y',0};
132     const WCHAR *driver = NULL, *device = NULL, *port = NULL;
133     DEVMODEW *devmode = NULL;
134 
135     TRACE( "(%p, %p)\n", hdc, dv );
136 
137     if (dv)
138     {
139         if (dv->tdDriverNameOffset) driver  = (WCHAR *)((char *)dv + dv->tdDriverNameOffset);
140         if (dv->tdDeviceNameOffset) device  = (WCHAR *)((char *)dv + dv->tdDeviceNameOffset);
141         if (dv->tdPortNameOffset)   port    = (WCHAR *)((char *)dv + dv->tdPortNameOffset);
142         if (dv->tdExtDevmodeOffset) devmode = (DEVMODEW *)((char *)dv + dv->tdExtDevmodeOffset);
143     }
144     else
145     {
146         if (hdc) return hdc;
147         driver = displayW;
148     }
149     return CreateDCW( driver, device, port, devmode );
150 }
151 
152 /***********************************************************************
153  *           AtlHiMetricToPixel              [atl100.@]
154  */
155 void WINAPI AtlHiMetricToPixel(const SIZEL* lpHiMetric, SIZEL* lpPix)
156 {
157     HDC dc = GetDC(NULL);
158     lpPix->cx = lpHiMetric->cx * GetDeviceCaps( dc, LOGPIXELSX ) / 100;
159     lpPix->cy = lpHiMetric->cy * GetDeviceCaps( dc, LOGPIXELSY ) / 100;
160     ReleaseDC( NULL, dc );
161 }
162 
163 /***********************************************************************
164  *           AtlPixelToHiMetric              [atl100.@]
165  */
166 void WINAPI AtlPixelToHiMetric(const SIZEL* lpPix, SIZEL* lpHiMetric)
167 {
168     HDC dc = GetDC(NULL);
169     lpHiMetric->cx = 100 * lpPix->cx / GetDeviceCaps( dc, LOGPIXELSX );
170     lpHiMetric->cy = 100 * lpPix->cy / GetDeviceCaps( dc, LOGPIXELSY );
171     ReleaseDC( NULL, dc );
172 }
173 
174 /***********************************************************************
175  *           AtlComPtrAssign              [atl100.@]
176  */
177 IUnknown* WINAPI AtlComPtrAssign(IUnknown** pp, IUnknown *p)
178 {
179     TRACE("(%p %p)\n", pp, p);
180 
181     if (p) IUnknown_AddRef(p);
182     if (*pp) IUnknown_Release(*pp);
183     *pp = p;
184     return p;
185 }
186 
187 /***********************************************************************
188  *           AtlComQIPtrAssign              [atl100.@]
189  */
190 IUnknown* WINAPI AtlComQIPtrAssign(IUnknown** pp, IUnknown *p, REFIID riid)
191 {
192     IUnknown *new_p = NULL;
193 
194     TRACE("(%p %p %s)\n", pp, p, debugstr_guid(riid));
195 
196     if (p) IUnknown_QueryInterface(p, riid, (void **)&new_p);
197     if (*pp) IUnknown_Release(*pp);
198     *pp = new_p;
199     return new_p;
200 }
201 
202 /***********************************************************************
203  *           AtlInternalQueryInterface     [atl100.@]
204  */
205 HRESULT WINAPI AtlInternalQueryInterface(void* this, const _ATL_INTMAP_ENTRY* pEntries,  REFIID iid, void** ppvObject)
206 {
207     int i = 0;
208     HRESULT rc = E_NOINTERFACE;
209     TRACE("(%p, %p, %s, %p)\n",this, pEntries, debugstr_guid(iid), ppvObject);
210 
211     if (IsEqualGUID(iid,&IID_IUnknown))
212     {
213         TRACE("Returning IUnknown\n");
214         *ppvObject = ((LPSTR)this+pEntries[0].dw);
215         IUnknown_AddRef((IUnknown*)*ppvObject);
216         return S_OK;
217     }
218 
219     while (pEntries[i].pFunc != 0)
220     {
221         TRACE("Trying entry %i (%s %i %p)\n",i,debugstr_guid(pEntries[i].piid),
222               pEntries[i].dw, pEntries[i].pFunc);
223 
224         if (!pEntries[i].piid || IsEqualGUID(iid,pEntries[i].piid))
225         {
226             TRACE("MATCH\n");
227             if (pEntries[i].pFunc == (_ATL_CREATORARGFUNC*)1)
228             {
229                 TRACE("Offset\n");
230                 *ppvObject = ((LPSTR)this+pEntries[i].dw);
231                 IUnknown_AddRef((IUnknown*)*ppvObject);
232                 return S_OK;
233             }
234             else
235             {
236                 TRACE("Function\n");
237                 rc = pEntries[i].pFunc(this, iid, ppvObject, pEntries[i].dw);
238                 if(rc==S_OK || pEntries[i].piid)
239                     return rc;
240             }
241         }
242         i++;
243     }
244     TRACE("Done returning (0x%x)\n",rc);
245     return rc;
246 }
247 
248 /***********************************************************************
249  *           AtlIPersistStreamInit_Load      [atl100.@]
250  */
251 HRESULT WINAPI AtlIPersistStreamInit_Load( LPSTREAM pStm, ATL_PROPMAP_ENTRY *pMap,
252                                            void *pThis, IUnknown *pUnk)
253 {
254     FIXME("(%p, %p, %p, %p)\n", pStm, pMap, pThis, pUnk);
255 
256     return S_OK;
257 }
258 
259 /***********************************************************************
260  *           AtlIPersistStreamInit_Save      [atl100.@]
261  */
262 HRESULT WINAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty,
263                                           ATL_PROPMAP_ENTRY *pMap, void *pThis,
264                                           IUnknown *pUnk)
265 {
266     FIXME("(%p, %d, %p, %p, %p)\n", pStm, fClearDirty, pMap, pThis, pUnk);
267 
268     return S_OK;
269 }
270 
271 /***********************************************************************
272  *           AtlIPersistPropertyBag_Load      [atl100.@]
273  */
274 HRESULT WINAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog,
275                                            ATL_PROPMAP_ENTRY *pMap, void *pThis,
276                                            IUnknown *pUnk)
277 {
278     FIXME("(%p, %p, %p, %p, %p)\n", pPropBag, pErrorLog, pMap, pThis, pUnk);
279 
280     return S_OK;
281 }
282 
283 /***********************************************************************
284  *           AtlIPersistPropertyBag_Save     [atl100.@]
285  */
286 HRESULT WINAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty,
287                                            BOOL fSaveAll, ATL_PROPMAP_ENTRY *pMap,
288                                            void *pThis, IUnknown *pUnk)
289 {
290     FIXME("(%p, %d, %d, %p, %p, %p)\n", pPropBag, fClearDirty, fSaveAll, pMap, pThis, pUnk);
291 
292     return S_OK;
293 }
294 
295 /***********************************************************************
296  *           AtlModuleAddTermFunc            [atl100.@]
297  */
298 HRESULT WINAPI AtlModuleAddTermFunc(_ATL_MODULE *pM, _ATL_TERMFUNC *pFunc, DWORD_PTR dw)
299 {
300     _ATL_TERMFUNC_ELEM *termfunc_elem;
301 
302     TRACE("version %04x (%p %p %ld)\n", _ATL_VER, pM, pFunc, dw);
303 
304     if (_ATL_VER > _ATL_VER_30 || pM->cbSize > ATLVer1Size) {
305         termfunc_elem = HeapAlloc(GetProcessHeap(), 0, sizeof(_ATL_TERMFUNC_ELEM));
306         termfunc_elem->pFunc = pFunc;
307         termfunc_elem->dw = dw;
308         termfunc_elem->pNext = pM->m_pTermFuncs;
309 
310         pM->m_pTermFuncs = termfunc_elem;
311     }
312 
313     return S_OK;
314 }
315 
316 #if _ATL_VER > _ATL_VER_30
317 
318 /***********************************************************************
319  *           AtlCallTermFunc              [atl100.@]
320  */
321 void WINAPI AtlCallTermFunc(_ATL_MODULE *pM)
322 {
323     _ATL_TERMFUNC_ELEM *iter = pM->m_pTermFuncs, *tmp;
324 
325     TRACE("(%p)\n", pM);
326 
327     while(iter) {
328         iter->pFunc(iter->dw);
329         tmp = iter;
330         iter = iter->pNext;
331         HeapFree(GetProcessHeap(), 0, tmp);
332     }
333 
334     pM->m_pTermFuncs = NULL;
335 }
336 
337 #endif
338 
339 /***********************************************************************
340  *           AtlLoadTypeLib             [atl100.56]
341  */
342 HRESULT WINAPI AtlLoadTypeLib(HINSTANCE inst, LPCOLESTR lpszIndex,
343         BSTR *pbstrPath, ITypeLib **ppTypeLib)
344 {
345     size_t path_len, index_len;
346     ITypeLib *typelib = NULL;
347     WCHAR *path;
348     HRESULT hres;
349 
350     static const WCHAR tlb_extW[] = {'.','t','l','b',0};
351 
352     TRACE("(%p %s %p %p)\n", inst, debugstr_w(lpszIndex), pbstrPath, ppTypeLib);
353 
354     index_len = lpszIndex ? strlenW(lpszIndex) : 0;
355     path = heap_alloc((MAX_PATH+index_len)*sizeof(WCHAR) + sizeof(tlb_extW));
356     if(!path)
357         return E_OUTOFMEMORY;
358 
359     path_len = GetModuleFileNameW(inst, path, MAX_PATH);
360     if(!path_len) {
361         heap_free(path);
362         return HRESULT_FROM_WIN32(GetLastError());
363     }
364 
365     if(index_len)
366         memcpy(path+path_len, lpszIndex, (index_len+1)*sizeof(WCHAR));
367 
368     hres = LoadTypeLib(path, &typelib);
369     if(FAILED(hres)) {
370         WCHAR *ptr;
371 
372         for(ptr = path+path_len-1; ptr > path && *ptr != '\\' && *ptr != '.'; ptr--);
373         if(*ptr != '.')
374             ptr = path+path_len;
375         memcpy(ptr, tlb_extW, sizeof(tlb_extW));
376         hres = LoadTypeLib(path, &typelib);
377     }
378 
379     if(SUCCEEDED(hres)) {
380         *pbstrPath = SysAllocString(path);
381         if(!*pbstrPath) {
382             ITypeLib_Release(typelib);
383             hres = E_OUTOFMEMORY;
384         }
385     }
386 
387     heap_free(path);
388     if(FAILED(hres))
389         return hres;
390 
391     *ppTypeLib = typelib;
392     return S_OK;
393 }
394 
395 #if _ATL_VER <= _ATL_VER_80
396 
397 /***********************************************************************
398  *           AtlRegisterTypeLib         [atl80.19]
399  */
400 HRESULT WINAPI AtlRegisterTypeLib(HINSTANCE inst, const WCHAR *index)
401 {
402     ITypeLib *typelib;
403     BSTR path;
404     HRESULT hres;
405 
406     TRACE("(%p %s)\n", inst, debugstr_w(index));
407 
408     hres = AtlLoadTypeLib(inst, index, &path, &typelib);
409     if(FAILED(hres))
410         return hres;
411 
412     hres = RegisterTypeLib(typelib, path, NULL); /* FIXME: pass help directory */
413     ITypeLib_Release(typelib);
414     SysFreeString(path);
415     return hres;
416 }
417 
418 #endif
419 
420 #if _ATL_VER > _ATL_VER_30
421 
422 /***********************************************************************
423  *           AtlWinModuleInit                          [atl100.65]
424  */
425 HRESULT WINAPI AtlWinModuleInit(_ATL_WIN_MODULE *winmod)
426 {
427     TRACE("(%p)\n", winmod);
428 
429     if(winmod->cbSize != sizeof(*winmod))
430         return E_INVALIDARG;
431 
432     InitializeCriticalSection(&winmod->m_csWindowCreate);
433     winmod->m_pCreateWndList = NULL;
434     return S_OK;
435 }
436 
437 /***********************************************************************
438  *           AtlWinModuleAddCreateWndData              [atl100.43]
439  */
440 void WINAPI AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pM, _AtlCreateWndData *pData, void *pvObject)
441 {
442     TRACE("(%p, %p, %p)\n", pM, pData, pvObject);
443 
444     pData->m_pThis = pvObject;
445     pData->m_dwThreadID = GetCurrentThreadId();
446 
447     EnterCriticalSection(&pM->m_csWindowCreate);
448     pData->m_pNext = pM->m_pCreateWndList;
449     pM->m_pCreateWndList = pData;
450     LeaveCriticalSection(&pM->m_csWindowCreate);
451 }
452 
453 /***********************************************************************
454  *           AtlWinModuleExtractCreateWndData          [atl100.44]
455  */
456 void* WINAPI AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *winmod)
457 {
458     _AtlCreateWndData *iter, *prev = NULL;
459     DWORD thread_id;
460 
461     TRACE("(%p)\n", winmod);
462 
463     thread_id = GetCurrentThreadId();
464 
465     EnterCriticalSection(&winmod->m_csWindowCreate);
466 
467     for(iter = winmod->m_pCreateWndList; iter && iter->m_dwThreadID != thread_id; iter = iter->m_pNext)
468         prev = iter;
469     if(iter) {
470         if(prev)
471             prev->m_pNext = iter->m_pNext;
472         else
473             winmod->m_pCreateWndList = iter->m_pNext;
474     }
475 
476     LeaveCriticalSection(&winmod->m_csWindowCreate);
477 
478     return iter ? iter->m_pThis : NULL;
479 }
480 
481 /***********************************************************************
482  *           AtlComModuleGetClassObject                [atl100.15]
483  */
484 #if _ATL_VER < _ATL_VER_110
485 HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pm, REFCLSID rclsid, REFIID riid, void **ppv)
486 {
487     _ATL_OBJMAP_ENTRY **iter;
488     HRESULT hres;
489 
490     TRACE("(%p %s %s %p)\n", pm, debugstr_guid(rclsid), debugstr_guid(riid), ppv);
491 
492     if(!pm)
493         return E_INVALIDARG;
494 
495     for(iter = pm->m_ppAutoObjMapFirst; iter < pm->m_ppAutoObjMapLast; iter++) {
496         if(IsEqualCLSID((*iter)->pclsid, rclsid) && (*iter)->pfnGetClassObject) {
497             if(!(*iter)->pCF)
498                 hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&(*iter)->pCF);
499             if((*iter)->pCF)
500                 hres = IUnknown_QueryInterface((*iter)->pCF, riid, ppv);
501             TRACE("returning %p (%08x)\n", *ppv, hres);
502             return hres;
503         }
504     }
505 
506     WARN("Class %s not found\n", debugstr_guid(rclsid));
507     return CLASS_E_CLASSNOTAVAILABLE;
508 }
509 #else
510 HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pm, REFCLSID rclsid, REFIID riid, void **ppv)
511 {
512     _ATL_OBJMAP_ENTRY_EX **iter;
513     HRESULT hres;
514 
515     TRACE("(%p %s %s %p)\n", pm, debugstr_guid(rclsid), debugstr_guid(riid), ppv);
516 
517     if(!pm)
518         return E_INVALIDARG;
519 
520     for(iter = pm->m_ppAutoObjMapFirst; iter < pm->m_ppAutoObjMapLast; iter++) {
521         if(IsEqualCLSID((*iter)->pclsid, rclsid) && (*iter)->pfnGetClassObject) {
522             if(!(*iter)->pCache->pCF)
523                 hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&(*iter)->pCache->pCF);
524             if((*iter)->pCache->pCF)
525                 hres = IUnknown_QueryInterface((*iter)->pCache->pCF, riid, ppv);
526             TRACE("returning %p (%08x)\n", *ppv, hres);
527             return hres;
528         }
529     }
530 
531     WARN("Class %s not found\n", debugstr_guid(rclsid));
532     return CLASS_E_CLASSNOTAVAILABLE;
533 }
534 #endif
535 
536 /***********************************************************************
537  *           AtlComModuleRegisterClassObjects   [atl100.17]
538  */
539 #if _ATL_VER < _ATL_VER_110
540 HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags)
541 {
542     _ATL_OBJMAP_ENTRY **iter;
543     IUnknown *unk;
544     HRESULT hres;
545 
546     TRACE("(%p %x %x)\n", module, context, flags);
547 
548     if(!module)
549         return E_INVALIDARG;
550 
551     for(iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) {
552         if(!(*iter)->pfnGetClassObject)
553             continue;
554 
555         hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&unk);
556         if(FAILED(hres))
557             return hres;
558 
559         hres = CoRegisterClassObject((*iter)->pclsid, unk, context, flags, &(*iter)->dwRegister);
560         IUnknown_Release(unk);
561         if(FAILED(hres))
562             return hres;
563     }
564 
565    return S_OK;
566 }
567 #else
568 HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags)
569 {
570     _ATL_OBJMAP_ENTRY_EX **iter;
571     IUnknown *unk;
572     HRESULT hres;
573 
574     TRACE("(%p %x %x)\n", module, context, flags);
575 
576     if(!module)
577         return E_INVALIDARG;
578 
579     for(iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) {
580         if(!(*iter)->pfnGetClassObject)
581             continue;
582 
583         hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&unk);
584         if(FAILED(hres))
585             return hres;
586 
587         hres = CoRegisterClassObject((*iter)->pclsid, unk, context, flags, &(*iter)->pCache->dwRegister);
588         IUnknown_Release(unk);
589         if(FAILED(hres))
590             return hres;
591     }
592 
593    return S_OK;
594 }
595 #endif
596 
597 /***********************************************************************
598  *           AtlComModuleRevokeClassObjects   [atl100.20]
599  */
600 #if _ATL_VER < _ATL_VER_110
601 HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module)
602 {
603     _ATL_OBJMAP_ENTRY **iter;
604     HRESULT hres;
605 
606     TRACE("(%p)\n", module);
607 
608     if(!module)
609         return E_INVALIDARG;
610 
611     for(iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) {
612         hres = CoRevokeClassObject((*iter)->dwRegister);
613         if(FAILED(hres))
614             return hres;
615     }
616 
617     return S_OK;
618 }
619 #else
620 HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module)
621 {
622     _ATL_OBJMAP_ENTRY_EX **iter;
623     HRESULT hres;
624 
625     TRACE("(%p)\n", module);
626 
627     if(!module)
628         return E_INVALIDARG;
629 
630     for(iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) {
631         hres = CoRevokeClassObject((*iter)->pCache->dwRegister);
632         if(FAILED(hres))
633             return hres;
634     }
635 
636     return S_OK;
637 }
638 #endif
639 
640 /***********************************************************************
641  *           AtlComModuleUnregisterServer       [atl100.22]
642  */
643 #if _ATL_VER < _ATL_VER_110
644 HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid)
645 {
646     const struct _ATL_CATMAP_ENTRY *catmap;
647     _ATL_OBJMAP_ENTRY **iter;
648     HRESULT hres;
649 
650     TRACE("(%p %x %s)\n", mod, bRegTypeLib, debugstr_guid(clsid));
651 
652     for(iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++) {
653         if(!*iter || (clsid && !IsEqualCLSID((*iter)->pclsid, clsid)))
654             continue;
655 
656         TRACE("Unregistering clsid %s\n", debugstr_guid((*iter)->pclsid));
657 
658         catmap = (*iter)->pfnGetCategoryMap();
659         if(catmap) {
660             hres = AtlRegisterClassCategoriesHelper((*iter)->pclsid, catmap, FALSE);
661             if(FAILED(hres))
662                 return hres;
663         }
664 
665         hres = (*iter)->pfnUpdateRegistry(FALSE);
666         if(FAILED(hres))
667             return hres;
668     }
669 
670     if(bRegTypeLib) {
671         ITypeLib *typelib;
672         TLIBATTR *attr;
673         BSTR path;
674 
675         hres = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib);
676         if(FAILED(hres))
677             return hres;
678 
679         SysFreeString(path);
680         hres = ITypeLib_GetLibAttr(typelib, &attr);
681         if(SUCCEEDED(hres)) {
682             hres = UnRegisterTypeLib(&attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind);
683             ITypeLib_ReleaseTLibAttr(typelib, attr);
684         }
685         ITypeLib_Release(typelib);
686         if(FAILED(hres))
687             return hres;
688     }
689 
690     return S_OK;
691 }
692 #else
693 HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid)
694 {
695     const struct _ATL_CATMAP_ENTRY *catmap;
696     _ATL_OBJMAP_ENTRY_EX **iter;
697     HRESULT hres;
698 
699     TRACE("(%p %x %s)\n", mod, bRegTypeLib, debugstr_guid(clsid));
700 
701     for(iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++) {
702         if(!*iter || (clsid && !IsEqualCLSID((*iter)->pclsid, clsid)))
703             continue;
704 
705         TRACE("Unregistering clsid %s\n", debugstr_guid((*iter)->pclsid));
706 
707         catmap = (*iter)->pfnGetCategoryMap();
708         if(catmap) {
709             hres = AtlRegisterClassCategoriesHelper((*iter)->pclsid, catmap, FALSE);
710             if(FAILED(hres))
711                 return hres;
712         }
713 
714         hres = (*iter)->pfnUpdateRegistry(FALSE);
715         if(FAILED(hres))
716             return hres;
717     }
718 
719     if(bRegTypeLib) {
720         ITypeLib *typelib;
721         TLIBATTR *attr;
722         BSTR path;
723 
724         hres = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib);
725         if(FAILED(hres))
726             return hres;
727 
728         SysFreeString(path);
729         hres = ITypeLib_GetLibAttr(typelib, &attr);
730         if(SUCCEEDED(hres)) {
731             hres = UnRegisterTypeLib(&attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind);
732             ITypeLib_ReleaseTLibAttr(typelib, attr);
733         }
734         ITypeLib_Release(typelib);
735         if(FAILED(hres))
736             return hres;
737     }
738 
739     return S_OK;
740 }
741 #endif
742 
743 #endif
744 
745 /***********************************************************************
746  *           AtlRegisterClassCategoriesHelper          [atl100.49]
747  */
748 HRESULT WINAPI AtlRegisterClassCategoriesHelper(REFCLSID clsid, const struct _ATL_CATMAP_ENTRY *catmap, BOOL reg)
749 {
750     const struct _ATL_CATMAP_ENTRY *iter;
751     HRESULT hres;
752 
753     TRACE("(%s %p %x)\n", debugstr_guid(clsid), catmap, reg);
754 
755     if(!catmap)
756         return S_OK;
757 
758     if(!catreg) {
759         ICatRegister *new_catreg;
760 
761         hres = CoCreateInstance(&CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER,
762                 &IID_ICatRegister, (void**)&new_catreg);
763         if(FAILED(hres))
764             return hres;
765 
766         if(InterlockedCompareExchangePointer((void**)&catreg, new_catreg, NULL))
767             ICatRegister_Release(new_catreg);
768     }
769 
770     for(iter = catmap; iter->iType != _ATL_CATMAP_ENTRY_END; iter++) {
771         CATID catid = *iter->pcatid; /* For stupid lack of const in ICatRegister declaration. */
772 
773         if(iter->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED) {
774             if(reg)
775                 hres = ICatRegister_RegisterClassImplCategories(catreg, clsid, 1, &catid);
776             else
777                 hres = ICatRegister_UnRegisterClassImplCategories(catreg, clsid, 1, &catid);
778         }else {
779             if(reg)
780                 hres = ICatRegister_RegisterClassReqCategories(catreg, clsid, 1, &catid);
781             else
782                 hres = ICatRegister_UnRegisterClassReqCategories(catreg, clsid, 1, &catid);
783         }
784         if(FAILED(hres))
785             return hres;
786     }
787 
788     if(!reg) {
789         WCHAR reg_path[256] = {'C','L','S','I','D','\\'}, *ptr = reg_path+6;
790 
791         static const WCHAR implemented_catW[] =
792             {'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0};
793         static const WCHAR required_catW[] =
794             {'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0};
795 
796         ptr += StringFromGUID2(clsid, ptr, 64)-1;
797         *ptr++ = '\\';
798 
799         memcpy(ptr, implemented_catW, sizeof(implemented_catW));
800         RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
801 
802         memcpy(ptr, required_catW, sizeof(required_catW));
803         RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
804     }
805 
806     return S_OK;
807 }
808 
809 /***********************************************************************
810  *           AtlWaitWithMessageLoop     [atl100.24]
811  */
812 BOOL WINAPI AtlWaitWithMessageLoop(HANDLE handle)
813 {
814     MSG msg;
815     DWORD res;
816 
817     TRACE("(%p)\n", handle);
818 
819     while(1) {
820         res = MsgWaitForMultipleObjects(1, &handle, FALSE, INFINITE, QS_ALLINPUT);
821         switch(res) {
822         case WAIT_OBJECT_0:
823             return TRUE;
824         case WAIT_OBJECT_0+1:
825             if(GetMessageW(&msg, NULL, 0, 0) < 0)
826                 return FALSE;
827 
828             TranslateMessage(&msg);
829             DispatchMessageW(&msg);
830             break;
831         default:
832             return FALSE;
833         }
834     }
835 }
836 
837 static HRESULT get_default_source(ITypeLib *typelib, const CLSID *clsid, IID *iid)
838 {
839     ITypeInfo *typeinfo, *src_typeinfo = NULL;
840     TYPEATTR *attr;
841     int type_flags;
842     unsigned i;
843     HRESULT hres;
844 
845     hres = ITypeLib_GetTypeInfoOfGuid(typelib, clsid, &typeinfo);
846     if(FAILED(hres))
847         return hres;
848 
849     hres = ITypeInfo_GetTypeAttr(typeinfo, &attr);
850     if(FAILED(hres)) {
851         ITypeInfo_Release(typeinfo);
852         return hres;
853     }
854 
855     for(i=0; i < attr->cImplTypes; i++) {
856         hres = ITypeInfo_GetImplTypeFlags(typeinfo, i, &type_flags);
857         if(SUCCEEDED(hres) && type_flags == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) {
858             HREFTYPE ref;
859 
860             hres = ITypeInfo_GetRefTypeOfImplType(typeinfo, i, &ref);
861             if(SUCCEEDED(hres))
862                 hres = ITypeInfo_GetRefTypeInfo(typeinfo, ref, &src_typeinfo);
863             break;
864         }
865     }
866 
867     ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
868     ITypeInfo_Release(typeinfo);
869     if(FAILED(hres))
870         return hres;
871 
872     if(!src_typeinfo) {
873         *iid = IID_NULL;
874         return S_OK;
875     }
876 
877     hres = ITypeInfo_GetTypeAttr(src_typeinfo, &attr);
878     if(SUCCEEDED(hres)) {
879         *iid = attr->guid;
880         ITypeInfo_ReleaseTypeAttr(src_typeinfo, attr);
881     }
882     ITypeInfo_Release(src_typeinfo);
883     return hres;
884 }
885 
886 /***********************************************************************
887  *           AtlGetObjectSourceInterface    [atl100.54]
888  */
889 HRESULT WINAPI AtlGetObjectSourceInterface(IUnknown *unk, GUID *libid, IID *iid, unsigned short *major, unsigned short *minor)
890 {
891     IProvideClassInfo2 *classinfo;
892     ITypeInfo *typeinfo;
893     ITypeLib *typelib;
894     IPersist *persist;
895     IDispatch *disp;
896     HRESULT hres;
897 
898     TRACE("(%p %p %p %p %p)\n", unk, libid, iid, major, minor);
899 
900     hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
901     if(FAILED(hres))
902         return hres;
903 
904     hres = IDispatch_GetTypeInfo(disp, 0, 0, &typeinfo);
905     IDispatch_Release(disp);
906     if(FAILED(hres))
907         return hres;
908 
909     hres = ITypeInfo_GetContainingTypeLib(typeinfo, &typelib, 0);
910     ITypeInfo_Release(typeinfo);
911     if(SUCCEEDED(hres)) {
912         TLIBATTR *attr;
913 
914         hres = ITypeLib_GetLibAttr(typelib, &attr);
915         if(SUCCEEDED(hres)) {
916             *libid = attr->guid;
917             *major = attr->wMajorVerNum;
918             *minor = attr->wMinorVerNum;
919             ITypeLib_ReleaseTLibAttr(typelib, attr);
920         }else {
921             ITypeLib_Release(typelib);
922         }
923     }
924     if(FAILED(hres))
925         return hres;
926 
927     hres = IUnknown_QueryInterface(unk, &IID_IProvideClassInfo2, (void**)&classinfo);
928     if(SUCCEEDED(hres)) {
929         hres = IProvideClassInfo2_GetGUID(classinfo, GUIDKIND_DEFAULT_SOURCE_DISP_IID, iid);
930         IProvideClassInfo2_Release(classinfo);
931         ITypeLib_Release(typelib);
932         return hres;
933     }
934 
935     hres = IUnknown_QueryInterface(unk, &IID_IPersist, (void**)&persist);
936     if(SUCCEEDED(hres)) {
937         CLSID clsid;
938 
939         hres = IPersist_GetClassID(persist, &clsid);
940         if(SUCCEEDED(hres))
941             hres = get_default_source(typelib, &clsid, iid);
942         IPersist_Release(persist);
943     }
944 
945     return hres;
946 }
947 
948 #if _ATL_VER >= _ATL_VER90
949 
950 /***********************************************************************
951  *           AtlSetPerUserRegistration [atl100.67]
952  */
953 HRESULT WINAPI AtlSetPerUserRegistration(cpp_bool bEnable)
954 {
955     FIXME("stub: bEnable: %d\n", bEnable);
956     return E_NOTIMPL;
957 }
958 
959 /***********************************************************************
960  *           AtlGetPerUserRegistration  [atl100.68]
961  */
962 HRESULT WINAPI AtlGetPerUserRegistration(cpp_bool *pbEnabled)
963 {
964     FIXME("stub: returning false\n");
965     *pbEnabled = 0;
966     return S_OK;
967 }
968 
969 #endif
970 
971 /***********************************************************************
972  *           AtlGetVersion              [atl100.@]
973  */
974 DWORD WINAPI AtlGetVersion(void *pReserved)
975 {
976     TRACE("version %04x (%p)\n", _ATL_VER, pReserved);
977     return _ATL_VER;
978 }
979 
980 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
981 {
982     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
983 
984     switch(fdwReason) {
985     case DLL_PROCESS_ATTACH:
986         atl_instance = hinstDLL;
987         DisableThreadLibraryCalls(hinstDLL);
988         break;
989     case DLL_PROCESS_DETACH:
990         if (lpvReserved) break;
991         if(catreg)
992             ICatRegister_Release(catreg);
993     }
994 
995     return TRUE;
996 }
997