8cc8eda1983b3d894e03b4fefeb118d5272be943
[reactos.git] / reactos / dll / win32 / atl / 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 #include <precomp.h>
21
22 #include <wingdi.h>
23
24 #define ATLVer1Size FIELD_OFFSET(_ATL_MODULEW, dwAtlBuildVer)
25
26 HINSTANCE atl_instance;
27
28 typedef unsigned char cpp_bool;
29
30 static inline void *heap_alloc(size_t len)
31 {
32 return HeapAlloc(GetProcessHeap(), 0, len);
33 }
34
35 static inline BOOL heap_free(void *mem)
36 {
37 return HeapFree(GetProcessHeap(), 0, mem);
38 }
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 %i %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 /* FIXME: should be in a header file */
248 typedef struct ATL_PROPMAP_ENTRY
249 {
250 LPCOLESTR szDesc;
251 DISPID dispid;
252 const CLSID* pclsidPropPage;
253 const IID* piidDispatch;
254 DWORD dwOffsetData;
255 DWORD dwSizeData;
256 VARTYPE vt;
257 } ATL_PROPMAP_ENTRY;
258
259 /***********************************************************************
260 * AtlIPersistStreamInit_Load [atl100.@]
261 */
262 HRESULT WINAPI AtlIPersistStreamInit_Load( LPSTREAM pStm, ATL_PROPMAP_ENTRY *pMap,
263 void *pThis, IUnknown *pUnk)
264 {
265 FIXME("(%p, %p, %p, %p)\n", pStm, pMap, pThis, pUnk);
266
267 return S_OK;
268 }
269
270 /***********************************************************************
271 * AtlIPersistStreamInit_Save [atl100.@]
272 */
273 HRESULT WINAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty,
274 ATL_PROPMAP_ENTRY *pMap, void *pThis,
275 IUnknown *pUnk)
276 {
277 FIXME("(%p, %d, %p, %p, %p)\n", pStm, fClearDirty, pMap, pThis, pUnk);
278
279 return S_OK;
280 }
281
282 /***********************************************************************
283 * AtlIPersistPropertyBag_Load [atl100.@]
284 */
285 HRESULT WINAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog,
286 ATL_PROPMAP_ENTRY *pMap, void *pThis,
287 IUnknown *pUnk)
288 {
289 FIXME("(%p, %p, %p, %p, %p)\n", pPropBag, pErrorLog, 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 ? strlenW(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 HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pm, REFCLSID rclsid, REFIID riid, void **ppv)
484 {
485 _ATL_OBJMAP_ENTRY **iter;
486 HRESULT hres;
487
488 TRACE("(%p %s %s %p)\n", pm, debugstr_guid(rclsid), debugstr_guid(riid), ppv);
489
490 if(!pm)
491 return E_INVALIDARG;
492
493 for(iter = pm->m_ppAutoObjMapFirst; iter < pm->m_ppAutoObjMapLast; iter++) {
494 if(IsEqualCLSID((*iter)->pclsid, rclsid) && (*iter)->pfnGetClassObject) {
495 if(!(*iter)->pCF)
496 hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&(*iter)->pCF);
497 if((*iter)->pCF)
498 hres = IUnknown_QueryInterface((*iter)->pCF, riid, ppv);
499 TRACE("returning %p (%08x)\n", *ppv, hres);
500 return hres;
501 }
502 }
503
504 WARN("Class %s not found\n", debugstr_guid(rclsid));
505 return CLASS_E_CLASSNOTAVAILABLE;
506 }
507
508 /***********************************************************************
509 * AtlComModuleRegisterClassObjects [atl100.17]
510 */
511 HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags)
512 {
513 _ATL_OBJMAP_ENTRY **iter;
514 IUnknown *unk;
515 HRESULT hres;
516
517 TRACE("(%p %x %x)\n", module, context, flags);
518
519 if(!module)
520 return E_INVALIDARG;
521
522 for(iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) {
523 if(!(*iter)->pfnGetClassObject)
524 continue;
525
526 hres = (*iter)->pfnGetClassObject((*iter)->pfnCreateInstance, &IID_IUnknown, (void**)&unk);
527 if(FAILED(hres))
528 return hres;
529
530 hres = CoRegisterClassObject((*iter)->pclsid, unk, context, flags, &(*iter)->dwRegister);
531 IUnknown_Release(unk);
532 if(FAILED(hres))
533 return hres;
534 }
535
536 return S_OK;
537 }
538
539 /***********************************************************************
540 * AtlComModuleRevokeClassObjects [atl100.20]
541 */
542 HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module)
543 {
544 _ATL_OBJMAP_ENTRY **iter;
545 HRESULT hres;
546
547 TRACE("(%p)\n", module);
548
549 if(!module)
550 return E_INVALIDARG;
551
552 for(iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) {
553 hres = CoRevokeClassObject((*iter)->dwRegister);
554 if(FAILED(hres))
555 return hres;
556 }
557
558 return S_OK;
559 }
560
561 /***********************************************************************
562 * AtlComModuleUnregisterServer [atl100.22]
563 */
564 HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid)
565 {
566 const struct _ATL_CATMAP_ENTRY *catmap;
567 _ATL_OBJMAP_ENTRY **iter;
568 HRESULT hres;
569
570 TRACE("(%p %x %s)\n", mod, bRegTypeLib, debugstr_guid(clsid));
571
572 for(iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++) {
573 if(!*iter || (clsid && !IsEqualCLSID((*iter)->pclsid, clsid)))
574 continue;
575
576 TRACE("Unregistering clsid %s\n", debugstr_guid((*iter)->pclsid));
577
578 catmap = (*iter)->pfnGetCategoryMap();
579 if(catmap) {
580 hres = AtlRegisterClassCategoriesHelper((*iter)->pclsid, catmap, FALSE);
581 if(FAILED(hres))
582 return hres;
583 }
584
585 hres = (*iter)->pfnUpdateRegistry(FALSE);
586 if(FAILED(hres))
587 return hres;
588 }
589
590 if(bRegTypeLib) {
591 ITypeLib *typelib;
592 TLIBATTR *attr;
593 BSTR path;
594
595 hres = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib);
596 if(FAILED(hres))
597 return hres;
598
599 SysFreeString(path);
600 hres = ITypeLib_GetLibAttr(typelib, &attr);
601 if(SUCCEEDED(hres)) {
602 hres = UnRegisterTypeLib(&attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind);
603 ITypeLib_ReleaseTLibAttr(typelib, attr);
604 }
605 ITypeLib_Release(typelib);
606 if(FAILED(hres))
607 return hres;
608 }
609
610 return S_OK;
611 }
612
613 #endif
614
615 /***********************************************************************
616 * AtlRegisterClassCategoriesHelper [atl100.49]
617 */
618 HRESULT WINAPI AtlRegisterClassCategoriesHelper(REFCLSID clsid, const struct _ATL_CATMAP_ENTRY *catmap, BOOL reg)
619 {
620 const struct _ATL_CATMAP_ENTRY *iter;
621 HRESULT hres;
622
623 TRACE("(%s %p %x)\n", debugstr_guid(clsid), catmap, reg);
624
625 if(!catmap)
626 return S_OK;
627
628 if(!catreg) {
629 ICatRegister *new_catreg;
630
631 hres = CoCreateInstance(&CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER,
632 &IID_ICatRegister, (void**)&new_catreg);
633 if(FAILED(hres))
634 return hres;
635
636 if(InterlockedCompareExchangePointer((void**)&catreg, new_catreg, NULL))
637 ICatRegister_Release(new_catreg);
638 }
639
640 for(iter = catmap; iter->iType != _ATL_CATMAP_ENTRY_END; iter++) {
641 CATID catid = *iter->pcatid; /* For stupid lack of const in ICatRegister declaration. */
642
643 if(iter->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED) {
644 if(reg)
645 hres = ICatRegister_RegisterClassImplCategories(catreg, clsid, 1, &catid);
646 else
647 hres = ICatRegister_UnRegisterClassImplCategories(catreg, clsid, 1, &catid);
648 }else {
649 if(reg)
650 hres = ICatRegister_RegisterClassReqCategories(catreg, clsid, 1, &catid);
651 else
652 hres = ICatRegister_UnRegisterClassReqCategories(catreg, clsid, 1, &catid);
653 }
654 if(FAILED(hres))
655 return hres;
656 }
657
658 if(!reg) {
659 WCHAR reg_path[256] = {'C','L','S','I','D','\\'}, *ptr = reg_path+6;
660
661 static const WCHAR implemented_catW[] =
662 {'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0};
663 static const WCHAR required_catW[] =
664 {'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0};
665
666 ptr += StringFromGUID2(clsid, ptr, 64)-1;
667 *ptr++ = '\\';
668
669 memcpy(ptr, implemented_catW, sizeof(implemented_catW));
670 RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
671
672 memcpy(ptr, required_catW, sizeof(required_catW));
673 RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
674 }
675
676 return S_OK;
677 }
678
679 /***********************************************************************
680 * AtlWaitWithMessageLoop [atl100.24]
681 */
682 BOOL WINAPI AtlWaitWithMessageLoop(HANDLE handle)
683 {
684 MSG msg;
685 DWORD res;
686
687 TRACE("(%p)\n", handle);
688
689 while(1) {
690 res = MsgWaitForMultipleObjects(1, &handle, FALSE, INFINITE, QS_ALLINPUT);
691 switch(res) {
692 case WAIT_OBJECT_0:
693 return TRUE;
694 case WAIT_OBJECT_0+1:
695 if(GetMessageW(&msg, NULL, 0, 0) < 0)
696 return FALSE;
697
698 TranslateMessage(&msg);
699 DispatchMessageW(&msg);
700 break;
701 default:
702 return FALSE;
703 }
704 }
705 }
706
707 static HRESULT get_default_source(ITypeLib *typelib, const CLSID *clsid, IID *iid)
708 {
709 ITypeInfo *typeinfo, *src_typeinfo = NULL;
710 TYPEATTR *attr;
711 int type_flags;
712 unsigned i;
713 HRESULT hres;
714
715 hres = ITypeLib_GetTypeInfoOfGuid(typelib, clsid, &typeinfo);
716 if(FAILED(hres))
717 return hres;
718
719 hres = ITypeInfo_GetTypeAttr(typeinfo, &attr);
720 if(FAILED(hres)) {
721 ITypeInfo_Release(typeinfo);
722 return hres;
723 }
724
725 for(i=0; i < attr->cImplTypes; i++) {
726 hres = ITypeInfo_GetImplTypeFlags(typeinfo, i, &type_flags);
727 if(SUCCEEDED(hres) && type_flags == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) {
728 HREFTYPE ref;
729
730 hres = ITypeInfo_GetRefTypeOfImplType(typeinfo, i, &ref);
731 if(SUCCEEDED(hres))
732 hres = ITypeInfo_GetRefTypeInfo(typeinfo, ref, &src_typeinfo);
733 break;
734 }
735 }
736
737 ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
738 ITypeInfo_Release(typeinfo);
739 if(FAILED(hres))
740 return hres;
741
742 if(!src_typeinfo) {
743 *iid = IID_NULL;
744 return S_OK;
745 }
746
747 hres = ITypeInfo_GetTypeAttr(src_typeinfo, &attr);
748 if(SUCCEEDED(hres)) {
749 *iid = attr->guid;
750 ITypeInfo_ReleaseTypeAttr(src_typeinfo, attr);
751 }
752 ITypeInfo_Release(src_typeinfo);
753 return hres;
754 }
755
756 /***********************************************************************
757 * AtlGetObjectSourceInterface [atl100.54]
758 */
759 HRESULT WINAPI AtlGetObjectSourceInterface(IUnknown *unk, GUID *libid, IID *iid, unsigned short *major, unsigned short *minor)
760 {
761 IProvideClassInfo2 *classinfo;
762 ITypeInfo *typeinfo;
763 ITypeLib *typelib;
764 IPersist *persist;
765 IDispatch *disp;
766 HRESULT hres;
767
768 TRACE("(%p %p %p %p %p)\n", unk, libid, iid, major, minor);
769
770 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
771 if(FAILED(hres))
772 return hres;
773
774 hres = IDispatch_GetTypeInfo(disp, 0, 0, &typeinfo);
775 IDispatch_Release(disp);
776 if(FAILED(hres))
777 return hres;
778
779 hres = ITypeInfo_GetContainingTypeLib(typeinfo, &typelib, 0);
780 ITypeInfo_Release(typeinfo);
781 if(SUCCEEDED(hres)) {
782 TLIBATTR *attr;
783
784 hres = ITypeLib_GetLibAttr(typelib, &attr);
785 if(SUCCEEDED(hres)) {
786 *libid = attr->guid;
787 *major = attr->wMajorVerNum;
788 *minor = attr->wMinorVerNum;
789 ITypeLib_ReleaseTLibAttr(typelib, attr);
790 }else {
791 ITypeLib_Release(typelib);
792 }
793 }
794 if(FAILED(hres))
795 return hres;
796
797 hres = IUnknown_QueryInterface(unk, &IID_IProvideClassInfo2, (void**)&classinfo);
798 if(SUCCEEDED(hres)) {
799 hres = IProvideClassInfo2_GetGUID(classinfo, GUIDKIND_DEFAULT_SOURCE_DISP_IID, iid);
800 IProvideClassInfo2_Release(classinfo);
801 ITypeLib_Release(typelib);
802 return hres;
803 }
804
805 hres = IUnknown_QueryInterface(unk, &IID_IPersist, (void**)&persist);
806 if(SUCCEEDED(hres)) {
807 CLSID clsid;
808
809 hres = IPersist_GetClassID(persist, &clsid);
810 if(SUCCEEDED(hres))
811 hres = get_default_source(typelib, &clsid, iid);
812 IPersist_Release(persist);
813 }
814
815 return hres;
816 }
817
818 #if _ATL_VER >= _ATL_VER90
819
820 /***********************************************************************
821 * AtlSetPerUserRegistration [atl100.67]
822 */
823 HRESULT WINAPI AtlSetPerUserRegistration(cpp_bool bEnable)
824 {
825 FIXME("stub: bEnable: %d\n", bEnable);
826 return E_NOTIMPL;
827 }
828
829 /***********************************************************************
830 * AtlGetPerUserRegistration [atl100.68]
831 */
832 HRESULT WINAPI AtlGetPerUserRegistration(cpp_bool *pbEnabled)
833 {
834 FIXME("stub: returning false\n");
835 *pbEnabled = 0;
836 return S_OK;
837 }
838
839 #endif
840
841 /***********************************************************************
842 * AtlGetVersion [atl100.@]
843 */
844 DWORD WINAPI AtlGetVersion(void *pReserved)
845 {
846 TRACE("version %04x (%p)\n", _ATL_VER, pReserved);
847 return _ATL_VER;
848 }
849
850 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
851 {
852 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
853
854 switch(fdwReason) {
855 case DLL_PROCESS_ATTACH:
856 atl_instance = hinstDLL;
857 DisableThreadLibraryCalls(hinstDLL);
858 break;
859 case DLL_PROCESS_DETACH:
860 if (lpvReserved) break;
861 if(catreg)
862 ICatRegister_Release(catreg);
863 }
864
865 return TRUE;
866 }