Faster serial speed cases for non Linux systems.
[wine] / dlls / urlmon / comimpl.c
1 /*
2  * A basic implementation for COM DLL implementor.
3  *
4  * Copyright (C) 2002 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "windef.h"
24 #include "winerror.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "ole2.h"
30
31 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(comimpl);
33
34 #include "comimpl.h"
35
36 /*
37   - All threading model including Apartment and Both are supported.
38   - Aggregation is supported.
39   - CoFreeUnusedLibraries() is supported.
40   - DisableThreadLibraryCalls() is supported.
41  */
42
43 static CRITICAL_SECTION csComImpl;
44 static DWORD dwComImplRef;
45
46
47 static HRESULT WINAPI
48 IUnknown_fnQueryInterface(IUnknown* iface,REFIID riid,LPVOID *ppobj)
49 {
50         ICOM_THIS(COMIMPL_IUnkImpl,iface);
51         size_t  ofs;
52         DWORD   dwIndex;
53         COMIMPL_IFDelegation*   pDelegation;
54         HRESULT hr;
55
56         TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
57
58         if ( ppobj == NULL )
59                 return E_POINTER;
60         *ppobj = NULL;
61
62         ofs = 0;
63
64         if ( IsEqualGUID( &IID_IUnknown, riid ) )
65         {
66                 TRACE("IID_IUnknown - returns inner object.\n");
67         }
68         else
69         {
70                 for ( dwIndex = 0; dwIndex < This->dwEntries; dwIndex++ )
71                 {
72                         if ( IsEqualGUID( This->pEntries[dwIndex].piid, riid ) )
73                         {
74                                 ofs = This->pEntries[dwIndex].ofsVTPtr;
75                                 break;
76                         }
77                 }
78                 if ( dwIndex == This->dwEntries )
79                 {
80                         hr = E_NOINTERFACE;
81
82                         /* delegation */
83                         pDelegation = This->pDelegationFirst;
84                         while ( pDelegation != NULL )
85                         {
86                                 hr = (*pDelegation->pOnQueryInterface)( iface, riid, ppobj );
87                                 if ( hr != E_NOINTERFACE )
88                                         break;
89                                 pDelegation = pDelegation->pNext;
90                         }
91
92                         if ( hr == E_NOINTERFACE )
93                         {
94                                 FIXME("(%p) unknown interface: %s\n",This,debugstr_guid(riid));
95                         }
96
97                         return hr;
98                 }
99         }
100
101         *ppobj = (LPVOID)(((char*)This) + ofs);
102         IUnknown_AddRef((IUnknown*)(*ppobj));
103
104         return S_OK;
105 }
106
107 static ULONG WINAPI
108 IUnknown_fnAddRef(IUnknown* iface)
109 {
110         ICOM_THIS(COMIMPL_IUnkImpl,iface);
111
112         TRACE("(%p)->()\n",This);
113
114         return InterlockedExchangeAdd(&(This->ref),1) + 1;
115 }
116
117 static ULONG WINAPI
118 IUnknown_fnRelease(IUnknown* iface)
119 {
120         ICOM_THIS(COMIMPL_IUnkImpl,iface);
121         LONG    ref;
122
123         TRACE("(%p)->()\n",This);
124         ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
125         if ( ref > 0 )
126                 return (ULONG)ref;
127
128         This->ref ++;
129         if ( This->pOnFinalRelease != NULL )
130                 (*(This->pOnFinalRelease))(iface);
131         This->ref --;
132
133         COMIMPL_FreeObj(This);
134
135         return 0;
136 }
137
138
139 static ICOM_VTABLE(IUnknown) iunknown =
140 {
141         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
142         /* IUnknown fields */
143         IUnknown_fnQueryInterface,
144         IUnknown_fnAddRef,
145         IUnknown_fnRelease,
146 };
147
148
149 void COMIMPL_IUnkInit( COMIMPL_IUnkImpl* pImpl, IUnknown* punkOuter )
150 {
151         TRACE("(%p)\n",pImpl);
152
153         ICOM_VTBL(pImpl) = &iunknown;
154         pImpl->pEntries = NULL;
155         pImpl->dwEntries = 0;
156         pImpl->pDelegationFirst = NULL;
157         pImpl->pOnFinalRelease = NULL;
158         pImpl->ref = 1;
159         pImpl->punkControl = (IUnknown*)pImpl;
160
161         /* for implementing aggregation. */
162         if ( punkOuter != NULL )
163                 pImpl->punkControl = punkOuter;
164 }
165
166 void COMIMPL_IUnkAddDelegationHandler(
167         COMIMPL_IUnkImpl* pImpl, COMIMPL_IFDelegation* pDelegation )
168 {
169         pDelegation->pNext = pImpl->pDelegationFirst;
170         pImpl->pDelegationFirst = pDelegation;
171 }
172
173
174
175 /************************************************************************/
176
177
178 static HRESULT WINAPI
179 IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj);
180 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface);
181 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface);
182 static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj);
183 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock);
184
185 static ICOM_VTABLE(IClassFactory) iclassfact =
186 {
187         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
188         IClassFactory_fnQueryInterface,
189         IClassFactory_fnAddRef,
190         IClassFactory_fnRelease,
191         IClassFactory_fnCreateInstance,
192         IClassFactory_fnLockServer
193 };
194
195 typedef struct
196 {
197         /* IUnknown fields */
198         ICOM_VFIELD(IClassFactory);
199         LONG    ref;
200         /* IClassFactory fields */
201         const COMIMPL_CLASSENTRY* pEntry;
202 } IClassFactoryImpl;
203
204
205 static HRESULT WINAPI
206 IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
207 {
208         ICOM_THIS(IClassFactoryImpl,iface);
209
210         TRACE("(%p)->(%p,%p)\n",This,riid,ppobj);
211         if ( ( IsEqualGUID( &IID_IUnknown, riid ) ) ||
212              ( IsEqualGUID( &IID_IClassFactory, riid ) ) )
213         {
214                 *ppobj = iface;
215                 IClassFactory_AddRef(iface);
216                 return S_OK;
217         }
218
219         return E_NOINTERFACE;
220 }
221
222 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
223 {
224         ICOM_THIS(IClassFactoryImpl,iface);
225
226         TRACE("(%p)->()\n",This);
227
228         return InterlockedExchangeAdd(&(This->ref),1) + 1;
229 }
230
231 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
232 {
233         ICOM_THIS(IClassFactoryImpl,iface);
234         LONG    ref;
235
236         TRACE("(%p)->()\n",This);
237         ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
238         if ( ref > 0 )
239                 return (ULONG)ref;
240
241         COMIMPL_FreeObj(This);
242         return 0;
243 }
244
245 static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj)
246 {
247         ICOM_THIS(IClassFactoryImpl,iface);
248         HRESULT hr;
249         IUnknown*       punk;
250
251         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
252
253         if ( ppobj == NULL )
254                 return E_POINTER;
255         if ( pOuter != NULL && !IsEqualGUID( riid, &IID_IUnknown ) )
256                 return CLASS_E_NOAGGREGATION;
257
258         *ppobj = NULL;
259
260         hr = (*This->pEntry->pCreateIUnk)(pOuter,(void**)&punk);
261         if ( hr != S_OK )
262                 return hr;
263
264         hr = IUnknown_QueryInterface(punk,riid,ppobj);
265         IUnknown_Release(punk);
266
267         return hr;
268 }
269
270 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock)
271 {
272         ICOM_THIS(IClassFactoryImpl,iface);
273         HRESULT hr;
274
275         TRACE("(%p)->(%d)\n",This,dolock);
276         if (dolock)
277                 hr = IClassFactory_AddRef(iface);
278         else
279                 hr = IClassFactory_Release(iface);
280
281         return hr;
282 }
283
284
285
286 static HRESULT IClassFactory_Alloc( const CLSID* pclsid, void** ppobj )
287 {
288         const COMIMPL_CLASSENTRY*       pEntry;
289         IClassFactoryImpl*      pImpl;
290
291         TRACE( "(%s,%p)\n", debugstr_guid(pclsid), ppobj );
292
293         pEntry = COMIMPL_ClassList;
294         while ( pEntry->pclsid != NULL )
295         {
296                 if ( IsEqualGUID( pclsid, pEntry->pclsid ) )
297                         goto found;
298                 pEntry ++;
299         }
300
301         return CLASS_E_CLASSNOTAVAILABLE;
302 found:
303         pImpl = (IClassFactoryImpl*)COMIMPL_AllocObj( sizeof(IClassFactoryImpl) );
304         if ( pImpl == NULL )
305                 return E_OUTOFMEMORY;
306
307         TRACE( "allocated successfully.\n" );
308
309         ICOM_VTBL(pImpl) = &iclassfact;
310         pImpl->ref = 1;
311         pImpl->pEntry = pEntry;
312
313         *ppobj = (void*)pImpl;
314         return S_OK;
315 }
316
317
318
319
320 /***********************************************************************
321  *              COMIMPL_InitProcess (internal)
322  */
323 static BOOL COMIMPL_InitProcess( HINSTANCE hInstDLL )
324 {
325         TRACE("()\n");
326
327         dwComImplRef = 0;
328         InitializeCriticalSection( &csComImpl );
329
330 #ifndef COMIMPL_PERTHREAD_INIT
331         DisableThreadLibraryCalls((HMODULE)hInstDLL);
332 #endif  /* COMIMPL_PERTHREAD_INIT */
333
334         return TRUE;
335 }
336
337 /***********************************************************************
338  *              COMIMPL_UninitProcess (internal)
339  */
340 static void COMIMPL_UninitProcess( HINSTANCE hInstDLL )
341 {
342         CHAR    szThisDLL[ MAX_PATH ];
343
344         TRACE("()\n");
345
346         if ( dwComImplRef != 0 )
347         {
348                 szThisDLL[0] = '\0';
349                 if ( !GetModuleFileNameA( (HMODULE)hInstDLL, szThisDLL, MAX_PATH ) )
350                         szThisDLL[0] = '\0';
351                 ERR( "you must release some objects allocated from %s.\n", szThisDLL );
352         }
353         DeleteCriticalSection( &csComImpl );
354 }
355
356
357 /***********************************************************************
358  *              COMIMPL_DllMain
359  */
360 BOOL WINAPI COMIMPL_DllMain(
361         HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved )
362 {
363         TRACE("(%08x,%08lx,%p)\n",hInstDLL,fdwReason,lpvReserved);
364
365         switch ( fdwReason )
366         {
367         case DLL_PROCESS_ATTACH:
368                 if ( !COMIMPL_InitProcess( hInstDLL ) )
369                         return FALSE;
370                 break;
371         case DLL_PROCESS_DETACH:
372                 COMIMPL_UninitProcess( hInstDLL );
373                 break;
374         case DLL_THREAD_ATTACH:
375                 break;
376         case DLL_THREAD_DETACH:
377                 break;
378         }
379
380         return TRUE;
381 }
382
383 /***********************************************************************
384  *              COMIMPL_DllGetClassObject
385  */
386 HRESULT WINAPI COMIMPL_DllGetClassObject(
387                 const CLSID* pclsid,const IID* piid,void** ppv)
388 {
389         *ppv = NULL;
390         if ( IsEqualGUID( &IID_IUnknown, piid ) ||
391              IsEqualGUID( &IID_IClassFactory, piid ) )
392         {
393                 return IClassFactory_Alloc( pclsid, ppv );
394         }
395
396         return CLASS_E_CLASSNOTAVAILABLE;
397 }
398
399 /***********************************************************************
400  *              COMIMPL_DllCanUnloadNow
401  *
402  * RETURNS
403  *    Success: S_OK
404  *    Failure: S_FALSE
405  */
406 HRESULT WINAPI COMIMPL_DllCanUnloadNow(void)
407 {
408         HRESULT hr;
409
410         EnterCriticalSection( &csComImpl );
411         hr = ( dwComImplRef == 0 ) ? S_OK : S_FALSE;
412         LeaveCriticalSection( &csComImpl );
413
414         return hr;
415 }
416
417 /***********************************************************************
418  *              COMIMPL_AllocObj
419  */
420 void* COMIMPL_AllocObj( DWORD dwSize )
421 {
422         void*   pv;
423
424         EnterCriticalSection( &csComImpl );
425         dwComImplRef ++;
426         pv = HeapAlloc( COMIMPL_hHeap, 0, dwSize );
427         if ( pv == NULL )
428                 dwComImplRef --;
429         LeaveCriticalSection( &csComImpl );
430
431         return pv;
432 }
433
434 /***********************************************************************
435  *              COMIMPL_FreeObj
436  */
437 void COMIMPL_FreeObj( void* pobj )
438 {
439         EnterCriticalSection( &csComImpl );
440         HeapFree( COMIMPL_hHeap, 0, pobj );
441         dwComImplRef --;
442         LeaveCriticalSection( &csComImpl );
443 }
444