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