msvcp90: Added complex<{float, double, long double}> constructors implementation.
[wine] / dlls / atl100 / atl.c
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 "atlbase.h"
23
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(atl100);
28
29 static inline void *heap_alloc(size_t len)
30 {
31     return HeapAlloc(GetProcessHeap(), 0, len);
32 }
33
34 static inline BOOL heap_free(void *mem)
35 {
36     return HeapFree(GetProcessHeap(), 0, mem);
37 }
38
39 static ICatRegister *catreg;
40
41 /***********************************************************************
42  *           AtlAdvise         [atl100.@]
43  */
44 HRESULT WINAPI AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID *iid, DWORD *pdw)
45 {
46     IConnectionPointContainer *container;
47     IConnectionPoint *cp;
48     HRESULT hres;
49
50     TRACE("%p %p %p %p\n", pUnkCP, pUnk, iid, pdw);
51
52     hres = IUnknown_QueryInterface(pUnkCP, &IID_IConnectionPointContainer, (void**)&container);
53     if(FAILED(hres))
54         return hres;
55
56     hres = IConnectionPointContainer_FindConnectionPoint(container, iid, &cp);
57     IConnectionPointContainer_Release(container);
58     if(FAILED(hres))
59         return hres;
60
61     hres = IConnectionPoint_Advise(cp, pUnk, pdw);
62     IConnectionPoint_Release(cp);
63     return hres;
64 }
65
66 /***********************************************************************
67  *           AtlUnadvise         [atl100.@]
68  */
69 HRESULT WINAPI AtlUnadvise(IUnknown *pUnkCP, const IID *iid, DWORD dw)
70 {
71     IConnectionPointContainer *container;
72     IConnectionPoint *cp;
73     HRESULT hres;
74
75     TRACE("%p %p %d\n", pUnkCP, iid, dw);
76
77     hres = IUnknown_QueryInterface(pUnkCP, &IID_IConnectionPointContainer, (void**)&container);
78     if(FAILED(hres))
79         return hres;
80
81     hres = IConnectionPointContainer_FindConnectionPoint(container, iid, &cp);
82     IConnectionPointContainer_Release(container);
83     if(FAILED(hres))
84         return hres;
85
86     hres = IConnectionPoint_Unadvise(cp, dw);
87     IConnectionPoint_Release(cp);
88     return hres;
89 }
90
91 /***********************************************************************
92  *           AtlFreeMarshalStream         [atl100.@]
93  */
94 HRESULT WINAPI AtlFreeMarshalStream(IStream *stm)
95 {
96     FIXME("%p\n", stm);
97     return S_OK;
98 }
99
100 /***********************************************************************
101  *           AtlMarshalPtrInProc         [atl100.@]
102  */
103 HRESULT WINAPI AtlMarshalPtrInProc(IUnknown *pUnk, const IID *iid, IStream **pstm)
104 {
105     FIXME("%p %p %p\n", pUnk, iid, pstm);
106     return E_FAIL;
107 }
108
109 /***********************************************************************
110  *           AtlUnmarshalPtr              [atl100.@]
111  */
112 HRESULT WINAPI AtlUnmarshalPtr(IStream *stm, const IID *iid, IUnknown **ppUnk)
113 {
114     FIXME("%p %p %p\n", stm, iid, ppUnk);
115     return E_FAIL;
116 }
117
118 /***********************************************************************
119  *           AtlCreateTargetDC         [atl100.@]
120  */
121 HDC WINAPI AtlCreateTargetDC( HDC hdc, DVTARGETDEVICE *dv )
122 {
123     static const WCHAR displayW[] = {'d','i','s','p','l','a','y',0};
124     const WCHAR *driver = NULL, *device = NULL, *port = NULL;
125     DEVMODEW *devmode = NULL;
126
127     TRACE( "(%p, %p)\n", hdc, dv );
128
129     if (dv)
130     {
131         if (dv->tdDriverNameOffset) driver  = (WCHAR *)((char *)dv + dv->tdDriverNameOffset);
132         if (dv->tdDeviceNameOffset) device  = (WCHAR *)((char *)dv + dv->tdDeviceNameOffset);
133         if (dv->tdPortNameOffset)   port    = (WCHAR *)((char *)dv + dv->tdPortNameOffset);
134         if (dv->tdExtDevmodeOffset) devmode = (DEVMODEW *)((char *)dv + dv->tdExtDevmodeOffset);
135     }
136     else
137     {
138         if (hdc) return hdc;
139         driver = displayW;
140     }
141     return CreateDCW( driver, device, port, devmode );
142 }
143
144 /***********************************************************************
145  *           AtlHiMetricToPixel              [atl100.@]
146  */
147 void WINAPI AtlHiMetricToPixel(const SIZEL* lpHiMetric, SIZEL* lpPix)
148 {
149     HDC dc = GetDC(NULL);
150     lpPix->cx = lpHiMetric->cx * GetDeviceCaps( dc, LOGPIXELSX ) / 100;
151     lpPix->cy = lpHiMetric->cy * GetDeviceCaps( dc, LOGPIXELSY ) / 100;
152     ReleaseDC( NULL, dc );
153 }
154
155 /***********************************************************************
156  *           AtlPixelToHiMetric              [atl100.@]
157  */
158 void WINAPI AtlPixelToHiMetric(const SIZEL* lpPix, SIZEL* lpHiMetric)
159 {
160     HDC dc = GetDC(NULL);
161     lpHiMetric->cx = 100 * lpPix->cx / GetDeviceCaps( dc, LOGPIXELSX );
162     lpHiMetric->cy = 100 * lpPix->cy / GetDeviceCaps( dc, LOGPIXELSY );
163     ReleaseDC( NULL, dc );
164 }
165
166 /***********************************************************************
167  *           AtlComPtrAssign              [atl100.@]
168  */
169 IUnknown* WINAPI AtlComPtrAssign(IUnknown** pp, IUnknown *p)
170 {
171     TRACE("(%p %p)\n", pp, p);
172
173     if (p) IUnknown_AddRef(p);
174     if (*pp) IUnknown_Release(*pp);
175     *pp = p;
176     return p;
177 }
178
179 /***********************************************************************
180  *           AtlComQIPtrAssign              [atl100.@]
181  */
182 IUnknown* WINAPI AtlComQIPtrAssign(IUnknown** pp, IUnknown *p, REFIID riid)
183 {
184     IUnknown *new_p = NULL;
185
186     TRACE("(%p %p %s)\n", pp, p, debugstr_guid(riid));
187
188     if (p) IUnknown_QueryInterface(p, riid, (void **)&new_p);
189     if (*pp) IUnknown_Release(*pp);
190     *pp = new_p;
191     return new_p;
192 }
193
194 /***********************************************************************
195  *           AtlInternalQueryInterface     [atl100.@]
196  */
197 HRESULT WINAPI AtlInternalQueryInterface(void* this, const _ATL_INTMAP_ENTRY* pEntries,  REFIID iid, void** ppvObject)
198 {
199     int i = 0;
200     HRESULT rc = E_NOINTERFACE;
201     TRACE("(%p, %p, %s, %p)\n",this, pEntries, debugstr_guid(iid), ppvObject);
202
203     if (IsEqualGUID(iid,&IID_IUnknown))
204     {
205         TRACE("Returning IUnknown\n");
206         *ppvObject = ((LPSTR)this+pEntries[0].dw);
207         IUnknown_AddRef((IUnknown*)*ppvObject);
208         return S_OK;
209     }
210
211     while (pEntries[i].pFunc != 0)
212     {
213         TRACE("Trying entry %i (%s %i %p)\n",i,debugstr_guid(pEntries[i].piid),
214               pEntries[i].dw, pEntries[i].pFunc);
215
216         if (!pEntries[i].piid || IsEqualGUID(iid,pEntries[i].piid))
217         {
218             TRACE("MATCH\n");
219             if (pEntries[i].pFunc == (_ATL_CREATORARGFUNC*)1)
220             {
221                 TRACE("Offset\n");
222                 *ppvObject = ((LPSTR)this+pEntries[i].dw);
223                 IUnknown_AddRef((IUnknown*)*ppvObject);
224                 return S_OK;
225             }
226             else
227             {
228                 TRACE("Function\n");
229                 rc = pEntries[i].pFunc(this, iid, ppvObject, pEntries[i].dw);
230                 if(rc==S_OK || pEntries[i].piid)
231                     return rc;
232             }
233         }
234         i++;
235     }
236     TRACE("Done returning (0x%x)\n",rc);
237     return rc;
238 }
239
240 /* FIXME: should be in a header file */
241 typedef struct ATL_PROPMAP_ENTRY
242 {
243     LPCOLESTR szDesc;
244     DISPID dispid;
245     const CLSID* pclsidPropPage;
246     const IID* piidDispatch;
247     DWORD dwOffsetData;
248     DWORD dwSizeData;
249     VARTYPE vt;
250 } ATL_PROPMAP_ENTRY;
251
252 /***********************************************************************
253  *           AtlIPersistStreamInit_Load      [atl100.@]
254  */
255 HRESULT WINAPI AtlIPersistStreamInit_Load( LPSTREAM pStm, ATL_PROPMAP_ENTRY *pMap,
256                                            void *pThis, IUnknown *pUnk)
257 {
258     FIXME("(%p, %p, %p, %p)\n", pStm, pMap, pThis, pUnk);
259
260     return S_OK;
261 }
262
263 /***********************************************************************
264  *           AtlIPersistStreamInit_Save      [atl100.@]
265  */
266 HRESULT WINAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty,
267                                           ATL_PROPMAP_ENTRY *pMap, void *pThis,
268                                           IUnknown *pUnk)
269 {
270     FIXME("(%p, %d, %p, %p, %p)\n", pStm, fClearDirty, pMap, pThis, pUnk);
271
272     return S_OK;
273 }
274
275 /***********************************************************************
276  *           AtlModuleAddTermFunc            [atl100.@]
277  */
278 HRESULT WINAPI AtlModuleAddTermFunc(_ATL_MODULE *pM, _ATL_TERMFUNC *pFunc, DWORD_PTR dw)
279 {
280     _ATL_TERMFUNC_ELEM *termfunc_elem;
281
282     TRACE("(%p %p %ld)\n", pM, pFunc, dw);
283
284     termfunc_elem = HeapAlloc(GetProcessHeap(), 0, sizeof(_ATL_TERMFUNC_ELEM));
285     termfunc_elem->pFunc = pFunc;
286     termfunc_elem->dw = dw;
287     termfunc_elem->pNext = pM->m_pTermFuncs;
288
289     pM->m_pTermFuncs = termfunc_elem;
290
291     return S_OK;
292 }
293
294 /***********************************************************************
295  *           AtlCallTermFunc              [atl100.@]
296  */
297 void WINAPI AtlCallTermFunc(_ATL_MODULE *pM)
298 {
299     _ATL_TERMFUNC_ELEM *iter = pM->m_pTermFuncs, *tmp;
300
301     TRACE("(%p)\n", pM);
302
303     while(iter) {
304         iter->pFunc(iter->dw);
305         tmp = iter;
306         iter = iter->pNext;
307         HeapFree(GetProcessHeap(), 0, tmp);
308     }
309
310     pM->m_pTermFuncs = NULL;
311 }
312
313 /***********************************************************************
314  *           AtlLoadTypeLib             [atl100.56]
315  */
316 HRESULT WINAPI AtlLoadTypeLib(HINSTANCE inst, LPCOLESTR lpszIndex,
317         BSTR *pbstrPath, ITypeLib **ppTypeLib)
318 {
319     size_t path_len, index_len;
320     ITypeLib *typelib = NULL;
321     WCHAR *path;
322     HRESULT hres;
323
324     static const WCHAR tlb_extW[] = {'.','t','l','b',0};
325
326     TRACE("(%p %s %p %p)\n", inst, debugstr_w(lpszIndex), pbstrPath, ppTypeLib);
327
328     index_len = lpszIndex ? strlenW(lpszIndex) : 0;
329     path = heap_alloc((MAX_PATH+index_len)*sizeof(WCHAR) + sizeof(tlb_extW));
330     if(!path)
331         return E_OUTOFMEMORY;
332
333     path_len = GetModuleFileNameW(inst, path, MAX_PATH);
334     if(!path_len) {
335         heap_free(path);
336         return HRESULT_FROM_WIN32(GetLastError());
337     }
338
339     if(index_len)
340         memcpy(path+path_len, lpszIndex, (index_len+1)*sizeof(WCHAR));
341
342     hres = LoadTypeLib(path, &typelib);
343     if(FAILED(hres)) {
344         WCHAR *ptr;
345
346         for(ptr = path+path_len-1; ptr > path && *ptr != '\\' && *ptr != '.'; ptr--);
347         if(*ptr != '.')
348             ptr = path+path_len;
349         memcpy(ptr, tlb_extW, sizeof(tlb_extW));
350         hres = LoadTypeLib(path, &typelib);
351     }
352
353     if(SUCCEEDED(hres)) {
354         *pbstrPath = SysAllocString(path);
355         if(!*pbstrPath) {
356             ITypeLib_Release(typelib);
357             hres = E_OUTOFMEMORY;
358         }
359     }
360
361     heap_free(path);
362     if(FAILED(hres))
363         return hres;
364
365     *ppTypeLib = typelib;
366     return S_OK;
367 }
368
369 /***********************************************************************
370  *           AtlWinModuleInit                          [atl100.65]
371  */
372 HRESULT WINAPI AtlWinModuleInit(_ATL_WIN_MODULE *winmod)
373 {
374     TRACE("(%p\n", winmod);
375
376     if(winmod->cbSize != sizeof(*winmod))
377         return E_INVALIDARG;
378
379     InitializeCriticalSection(&winmod->m_csWindowCreate);
380     winmod->m_pCreateWndList = NULL;
381     return S_OK;
382 }
383
384 /***********************************************************************
385  *           AtlWinModuleAddCreateWndData              [atl100.43]
386  */
387 void WINAPI AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pM, _AtlCreateWndData *pData, void *pvObject)
388 {
389     TRACE("(%p, %p, %p)\n", pM, pData, pvObject);
390
391     pData->m_pThis = pvObject;
392     pData->m_dwThreadID = GetCurrentThreadId();
393
394     EnterCriticalSection(&pM->m_csWindowCreate);
395     pData->m_pNext = pM->m_pCreateWndList;
396     pM->m_pCreateWndList = pData;
397     LeaveCriticalSection(&pM->m_csWindowCreate);
398 }
399
400 /***********************************************************************
401  *           AtlWinModuleExtractCreateWndData          [atl100.44]
402  */
403 void* WINAPI AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *winmod)
404 {
405     _AtlCreateWndData *iter, *prev = NULL;
406     DWORD thread_id;
407
408     TRACE("(%p)\n", winmod);
409
410     thread_id = GetCurrentThreadId();
411
412     EnterCriticalSection(&winmod->m_csWindowCreate);
413
414     for(iter = winmod->m_pCreateWndList; iter && iter->m_dwThreadID != thread_id; iter = iter->m_pNext)
415         prev = iter;
416     if(iter) {
417         if(prev)
418             prev->m_pNext = iter->m_pNext;
419         else
420             winmod->m_pCreateWndList = iter->m_pNext;
421     }
422
423     LeaveCriticalSection(&winmod->m_csWindowCreate);
424
425     return iter ? iter->m_pThis : NULL;
426 }
427
428 /***********************************************************************
429  *           AtlComModuleGetClassObject                [atl100.15]
430  */
431 HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pm, REFCLSID rclsid, REFIID riid, void **ppv)
432 {
433     _ATL_OBJMAP_ENTRY **iter;
434     HRESULT hres;
435
436     TRACE("(%p %s %s %p)\n", pm, debugstr_guid(rclsid), debugstr_guid(riid), ppv);
437
438     if(!pm)
439         return E_INVALIDARG;
440
441     for(iter = pm->m_ppAutoObjMapFirst; iter < pm->m_ppAutoObjMapLast; iter++) {
442         if(IsEqualCLSID((*iter)->pclsid, rclsid) && (*iter)->pfnGetClassObject) {
443             if(!(*iter)->pCF)
444                 hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&(*iter)->pCF);
445             if((*iter)->pCF)
446                 hres = IUnknown_QueryInterface((*iter)->pCF, riid, ppv);
447             TRACE("returning %p (%08x)\n", *ppv, hres);
448             return hres;
449         }
450     }
451
452     WARN("Class %s not found\n", debugstr_guid(rclsid));
453     return CLASS_E_CLASSNOTAVAILABLE;
454 }
455
456 /***********************************************************************
457  *           AtlComModuleUnregisterServer       [atl100.22]
458  */
459 HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid)
460 {
461     const struct _ATL_CATMAP_ENTRY *catmap;
462     _ATL_OBJMAP_ENTRY **iter;
463     HRESULT hres;
464
465     TRACE("(%p %x %s)\n", mod, bRegTypeLib, debugstr_guid(clsid));
466
467     for(iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++) {
468         if(!*iter || (clsid && !IsEqualCLSID((*iter)->pclsid, clsid)))
469             continue;
470
471         TRACE("Unregistering clsid %s\n", debugstr_guid((*iter)->pclsid));
472
473         catmap = (*iter)->pfnGetCategoryMap();
474         if(catmap) {
475             hres = AtlRegisterClassCategoriesHelper((*iter)->pclsid, catmap, FALSE);
476             if(FAILED(hres))
477                 return hres;
478         }
479
480         hres = (*iter)->pfnUpdateRegistry(FALSE);
481         if(FAILED(hres))
482             return hres;
483     }
484
485     if(bRegTypeLib) {
486         ITypeLib *typelib;
487         TLIBATTR *attr;
488         BSTR path;
489
490         hres = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib);
491         if(FAILED(hres))
492             return hres;
493
494         SysFreeString(path);
495         hres = ITypeLib_GetLibAttr(typelib, &attr);
496         if(SUCCEEDED(hres)) {
497             hres = UnRegisterTypeLib(&attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind);
498             ITypeLib_ReleaseTLibAttr(typelib, attr);
499         }
500         ITypeLib_Release(typelib);
501         if(FAILED(hres))
502             return hres;
503     }
504
505     return S_OK;
506 }
507
508 /***********************************************************************
509  *           AtlRegisterClassCategoriesHelper          [atl100.49]
510  */
511 HRESULT WINAPI AtlRegisterClassCategoriesHelper(REFCLSID clsid, const struct _ATL_CATMAP_ENTRY *catmap, BOOL reg)
512 {
513     const struct _ATL_CATMAP_ENTRY *iter;
514     HRESULT hres;
515
516     TRACE("(%s %p %x)\n", debugstr_guid(clsid), catmap, reg);
517
518     if(!catmap)
519         return S_OK;
520
521     if(!catreg) {
522         ICatRegister *new_catreg;
523
524         hres = CoCreateInstance(&CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER,
525                 &IID_ICatRegister, (void**)&new_catreg);
526         if(FAILED(hres))
527             return hres;
528
529         if(InterlockedCompareExchangePointer((void**)&catreg, new_catreg, NULL))
530             ICatRegister_Release(new_catreg);
531     }
532
533     for(iter = catmap; iter->iType != _ATL_CATMAP_ENTRY_END; iter++) {
534         CATID catid = *iter->pcatid; /* For stupid lack of const in ICatRegister declaration. */
535
536         if(iter->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED) {
537             if(reg)
538                 hres = ICatRegister_RegisterClassImplCategories(catreg, clsid, 1, &catid);
539             else
540                 hres = ICatRegister_UnRegisterClassImplCategories(catreg, clsid, 1, &catid);
541         }else {
542             if(reg)
543                 hres = ICatRegister_RegisterClassReqCategories(catreg, clsid, 1, &catid);
544             else
545                 hres = ICatRegister_UnRegisterClassReqCategories(catreg, clsid, 1, &catid);
546         }
547         if(FAILED(hres))
548             return hres;
549     }
550
551     if(!reg) {
552         WCHAR reg_path[256] = {'C','L','S','I','D','\\'}, *ptr = reg_path+6;
553
554         static const WCHAR implemented_catW[] =
555             {'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0};
556         static const WCHAR required_catW[] =
557             {'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0};
558
559         ptr += StringFromGUID2(clsid, ptr, 64)-1;
560         *ptr++ = '\\';
561
562         memcpy(ptr, implemented_catW, sizeof(implemented_catW));
563         RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
564
565         memcpy(ptr, required_catW, sizeof(required_catW));
566         RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
567     }
568
569     return S_OK;
570 }
571
572 /***********************************************************************
573  *           AtlWaitWithMessageLoop     [atl100.24]
574  */
575 BOOL WINAPI AtlWaitWithMessageLoop(HANDLE handle)
576 {
577     MSG msg;
578     DWORD res;
579
580     TRACE("(%p)\n", handle);
581
582     while(1) {
583         res = MsgWaitForMultipleObjects(1, &handle, FALSE, INFINITE, QS_ALLINPUT);
584         switch(res) {
585         case WAIT_OBJECT_0:
586             return TRUE;
587         case WAIT_OBJECT_0+1:
588             if(GetMessageW(&msg, NULL, 0, 0) < 0)
589                 return FALSE;
590
591             TranslateMessage(&msg);
592             DispatchMessageW(&msg);
593             break;
594         default:
595             return FALSE;
596         }
597     }
598 }
599
600 static HRESULT get_default_source(ITypeLib *typelib, const CLSID *clsid, IID *iid)
601 {
602     ITypeInfo *typeinfo, *src_typeinfo = NULL;
603     TYPEATTR *attr;
604     int type_flags;
605     unsigned i;
606     HRESULT hres;
607
608     hres = ITypeLib_GetTypeInfoOfGuid(typelib, clsid, &typeinfo);
609     if(FAILED(hres))
610         return hres;
611
612     hres = ITypeInfo_GetTypeAttr(typeinfo, &attr);
613     if(FAILED(hres)) {
614         ITypeInfo_Release(typeinfo);
615         return hres;
616     }
617
618     for(i=0; i < attr->cImplTypes; i++) {
619         hres = ITypeInfo_GetImplTypeFlags(typeinfo, i, &type_flags);
620         if(SUCCEEDED(hres) && type_flags == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) {
621             HREFTYPE ref;
622
623             hres = ITypeInfo_GetRefTypeOfImplType(typeinfo, i, &ref);
624             if(SUCCEEDED(hres))
625                 hres = ITypeInfo_GetRefTypeInfo(typeinfo, ref, &src_typeinfo);
626             break;
627         }
628     }
629
630     ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
631     ITypeInfo_Release(typeinfo);
632     if(FAILED(hres))
633         return hres;
634
635     if(!src_typeinfo) {
636         *iid = IID_NULL;
637         return S_OK;
638     }
639
640     hres = ITypeInfo_GetTypeAttr(src_typeinfo, &attr);
641     if(SUCCEEDED(hres)) {
642         *iid = attr->guid;
643         ITypeInfo_ReleaseTypeAttr(src_typeinfo, attr);
644     }
645     ITypeInfo_Release(src_typeinfo);
646     return hres;
647 }
648
649 /***********************************************************************
650  *           AtlGetObjectSourceInterface    [atl100.54]
651  */
652 HRESULT WINAPI AtlGetObjectSourceInterface(IUnknown *unk, GUID *libid, IID *iid, unsigned short *major, unsigned short *minor)
653 {
654     IProvideClassInfo2 *classinfo;
655     ITypeInfo *typeinfo;
656     ITypeLib *typelib;
657     IPersist *persist;
658     IDispatch *disp;
659     HRESULT hres;
660
661     TRACE("(%p %p %p %p %p)\n", unk, libid, iid, major, minor);
662
663     hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
664     if(FAILED(hres))
665         return hres;
666
667     hres = IDispatch_GetTypeInfo(disp, 0, 0, &typeinfo);
668     IDispatch_Release(disp);
669     if(FAILED(hres))
670         return hres;
671
672     hres = ITypeInfo_GetContainingTypeLib(typeinfo, &typelib, 0);
673     ITypeInfo_Release(typeinfo);
674     if(SUCCEEDED(hres)) {
675         TLIBATTR *attr;
676
677         hres = ITypeLib_GetLibAttr(typelib, &attr);
678         if(SUCCEEDED(hres)) {
679             *libid = attr->guid;
680             *major = attr->wMajorVerNum;
681             *minor = attr->wMinorVerNum;
682             ITypeLib_ReleaseTLibAttr(typelib, attr);
683         }else {
684             ITypeLib_Release(typelib);
685         }
686     }
687     if(FAILED(hres))
688         return hres;
689
690     hres = IUnknown_QueryInterface(unk, &IID_IProvideClassInfo2, (void**)&classinfo);
691     if(SUCCEEDED(hres)) {
692         hres = IProvideClassInfo2_GetGUID(classinfo, GUIDKIND_DEFAULT_SOURCE_DISP_IID, iid);
693         IProvideClassInfo2_Release(classinfo);
694         ITypeLib_Release(typelib);
695         return hres;
696     }
697
698     hres = IUnknown_QueryInterface(unk, &IID_IPersist, (void**)&persist);
699     if(SUCCEEDED(hres)) {
700         CLSID clsid;
701
702         hres = IPersist_GetClassID(persist, &clsid);
703         if(SUCCEEDED(hres))
704             hres = get_default_source(typelib, &clsid, iid);
705         IPersist_Release(persist);
706     }
707
708     return hres;
709 }
710
711 /***********************************************************************
712  *           AtlGetVersion              [atl100.@]
713  */
714 DWORD WINAPI AtlGetVersion(void *pReserved)
715 {
716    return _ATL_VER;
717 }
718
719 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
720 {
721     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
722
723     switch(fdwReason) {
724     case DLL_PROCESS_ATTACH:
725         DisableThreadLibraryCalls(hinstDLL);
726         break;
727     case DLL_PROCESS_DETACH:
728         if(catreg)
729             ICatRegister_Release(catreg);
730     }
731
732     return TRUE;
733 }