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