blob: 130aad6ac56b3e852ae2ee835bfb51eed9373961 [file] [log] [blame]
Sauw Ming93ba7fe2012-04-18 02:38:42 +00001//------------------------------------------------------------------------------
2// File: DlleEntry.cpp
3//
4// Desc: DirectShow base classes - implements classes used to support dll
5// entry points for COM objects.
6//
7// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8//------------------------------------------------------------------------------
9
10
11#include <streams.h>
12#include <initguid.h>
13
14#ifdef DEBUG
15#ifdef UNICODE
16#ifndef _UNICODE
17#define _UNICODE
18#endif // _UNICODE
19#endif // UNICODE
20
21#include <tchar.h>
22#endif // DEBUG
23#include <strsafe.h>
24
25extern CFactoryTemplate g_Templates[];
26extern int g_cTemplates;
27
28HINSTANCE g_hInst;
29DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
30OSVERSIONINFO g_osInfo;
31
32//
33// an instance of this is created by the DLLGetClassObject entrypoint
34// it uses the CFactoryTemplate object it is given to support the
35// IClassFactory interface
36
37class CClassFactory : public IClassFactory, public CBaseObject
38{
39
40private:
41 const CFactoryTemplate *const m_pTemplate;
42
43 ULONG m_cRef;
44
45 static int m_cLocked;
46public:
47 CClassFactory(const CFactoryTemplate *);
48
49 // IUnknown
50 STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv);
51 STDMETHODIMP_(ULONG)AddRef();
52 STDMETHODIMP_(ULONG)Release();
53
54 // IClassFactory
55 STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv);
56 STDMETHODIMP LockServer(BOOL fLock);
57
58 // allow DLLGetClassObject to know about global server lock status
59 static BOOL IsLocked() {
60 return (m_cLocked > 0);
61 };
62};
63
64// process-wide dll locked state
65int CClassFactory::m_cLocked = 0;
66
67CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
68: CBaseObject(NAME("Class Factory"))
69, m_cRef(0)
70, m_pTemplate(pTemplate)
71{
72}
73
74
75STDMETHODIMP
76CClassFactory::QueryInterface(REFIID riid,__deref_out void **ppv)
77{
78 CheckPointer(ppv,E_POINTER)
79 ValidateReadWritePtr(ppv,sizeof(PVOID));
80 *ppv = NULL;
81
82 // any interface on this object is the object pointer.
83 if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
84 *ppv = (LPVOID) this;
85 // AddRef returned interface pointer
86 ((LPUNKNOWN) *ppv)->AddRef();
87 return NOERROR;
88 }
89
90 return ResultFromScode(E_NOINTERFACE);
91}
92
93
94STDMETHODIMP_(ULONG)
95CClassFactory::AddRef()
96{
97 return ++m_cRef;
98}
99
100STDMETHODIMP_(ULONG)
101CClassFactory::Release()
102{
103 LONG lRef = InterlockedDecrement((volatile LONG *)&m_cRef);
104 if (lRef == 0) {
105 delete this;
106 return 0;
107 } else {
108 return lRef;
109 }
110}
111
112STDMETHODIMP
113CClassFactory::CreateInstance(
114 LPUNKNOWN pUnkOuter,
115 REFIID riid,
116 __deref_out void **pv)
117{
118 CheckPointer(pv,E_POINTER)
119 ValidateReadWritePtr(pv,sizeof(void *));
120 *pv = NULL;
121
122 /* Enforce the normal OLE rules regarding interfaces and delegation */
123
124 if (pUnkOuter != NULL) {
125 if (IsEqualIID(riid,IID_IUnknown) == FALSE) {
126 *pv = NULL;
127 return ResultFromScode(E_NOINTERFACE);
128 }
129 }
130
131 /* Create the new object through the derived class's create function */
132
133 HRESULT hr = NOERROR;
134 CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
135
136 if (pObj == NULL) {
137 *pv = NULL;
138 if (SUCCEEDED(hr)) {
139 hr = E_OUTOFMEMORY;
140 }
141 return hr;
142 }
143
144 /* Delete the object if we got a construction error */
145
146 if (FAILED(hr)) {
147 delete pObj;
148 *pv = NULL;
149 return hr;
150 }
151
152 /* Get a reference counted interface on the object */
153
154 /* We wrap the non-delegating QI with NDAddRef & NDRelease. */
155 /* This protects any outer object from being prematurely */
156 /* released by an inner object that may have to be created */
157 /* in order to supply the requested interface. */
158 pObj->NonDelegatingAddRef();
159 hr = pObj->NonDelegatingQueryInterface(riid, pv);
160 pObj->NonDelegatingRelease();
161 /* Note that if NonDelegatingQueryInterface fails, it will */
162 /* not increment the ref count, so the NonDelegatingRelease */
163 /* will drop the ref back to zero and the object will "self-*/
164 /* destruct". Hence we don't need additional tidy-up code */
165 /* to cope with NonDelegatingQueryInterface failing. */
166
167 if (SUCCEEDED(hr)) {
168 ASSERT(*pv);
169 }
170
171 return hr;
172}
173
174STDMETHODIMP
175CClassFactory::LockServer(BOOL fLock)
176{
177 if (fLock) {
178 m_cLocked++;
179 } else {
180 m_cLocked--;
181 }
182 return NOERROR;
183}
184
185
186// --- COM entrypoints -----------------------------------------
187
188//called by COM to get the class factory object for a given class
189__control_entrypoint(DllExport) STDAPI
190DllGetClassObject(
191 __in REFCLSID rClsID,
192 __in REFIID riid,
193 __deref_out void **pv)
194{
195 *pv = NULL;
196 if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
197 return E_NOINTERFACE;
198 }
199
200 // traverse the array of templates looking for one with this
201 // class id
202 for (int i = 0; i < g_cTemplates; i++) {
203 const CFactoryTemplate * pT = &g_Templates[i];
204 if (pT->IsClassID(rClsID)) {
205
206 // found a template - make a class factory based on this
207 // template
208
209 *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
210 if (*pv == NULL) {
211 return E_OUTOFMEMORY;
212 }
213 ((LPUNKNOWN)*pv)->AddRef();
214 return NOERROR;
215 }
216 }
217 return CLASS_E_CLASSNOTAVAILABLE;
218}
219
220//
221// Call any initialization routines
222//
223void
224DllInitClasses(BOOL bLoading)
225{
226 int i;
227
228 // traverse the array of templates calling the init routine
229 // if they have one
230 for (i = 0; i < g_cTemplates; i++) {
231 const CFactoryTemplate * pT = &g_Templates[i];
232 if (pT->m_lpfnInit != NULL) {
233 (*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
234 }
235 }
236
237}
238
239// called by COM to determine if this dll can be unloaded
240// return ok unless there are outstanding objects or a lock requested
241// by IClassFactory::LockServer
242//
243// CClassFactory has a static function that can tell us about the locks,
244// and CCOMObject has a static function that can tell us about the active
245// object count
246STDAPI
247DllCanUnloadNow()
248{
249 DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
250 CClassFactory::IsLocked(),
251 CBaseObject::ObjectsActive()));
252
253 if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
254 return S_FALSE;
255 } else {
256 return S_OK;
257 }
258}
259
260
261// --- standard WIN32 entrypoints --------------------------------------
262
263
264extern "C" void __cdecl __security_init_cookie(void);
265extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID);
266#pragma comment(linker, "/merge:.CRT=.rdata")
267
268extern "C"
269DECLSPEC_NOINLINE
270BOOL
271WINAPI
272DllEntryPoint(
273 HINSTANCE hInstance,
274 ULONG ulReason,
275 __inout_opt LPVOID pv
276 )
277{
278 if ( ulReason == DLL_PROCESS_ATTACH ) {
279 // Must happen before any other code is executed. Thankfully - it's re-entrant
280 __security_init_cookie();
281 }
282 return _DllEntryPoint(hInstance, ulReason, pv);
283}
284
285
286DECLSPEC_NOINLINE
287BOOL
288WINAPI
289_DllEntryPoint(
290 HINSTANCE hInstance,
291 ULONG ulReason,
292 __inout_opt LPVOID pv
293 )
294{
295#ifdef DEBUG
296 extern bool g_fDbgInDllEntryPoint;
297 g_fDbgInDllEntryPoint = true;
298#endif
299
300 switch (ulReason)
301 {
302
303 case DLL_PROCESS_ATTACH:
304 DisableThreadLibraryCalls(hInstance);
305 DbgInitialise(hInstance);
306
307 {
308 // The platform identifier is used to work out whether
309 // full unicode support is available or not. Hence the
310 // default will be the lowest common denominator - i.e. N/A
311 g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
312
313 g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
314 if (GetVersionEx(&g_osInfo)) {
315 g_amPlatform = g_osInfo.dwPlatformId;
316 } else {
317 DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
318 }
319 }
320
321 g_hInst = hInstance;
322 DllInitClasses(TRUE);
323 break;
324
325 case DLL_PROCESS_DETACH:
326 DllInitClasses(FALSE);
327
328#ifdef DEBUG
329 if (CBaseObject::ObjectsActive()) {
330 DbgSetModuleLevel(LOG_MEMORY, 2);
331 TCHAR szInfo[512];
332 extern TCHAR m_ModuleName[]; // Cut down module name
333
334 TCHAR FullName[_MAX_PATH]; // Load the full path and module name
335 TCHAR *pName; // Searches from the end for a backslash
336
337 GetModuleFileName(NULL,FullName,_MAX_PATH);
338 pName = _tcsrchr(FullName,'\\');
339 if (pName == NULL) {
340 pName = FullName;
341 } else {
342 pName++;
343 }
344
345 (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "),
346 pName, GetCurrentProcessId(), GetCurrentThreadId());
347
348 (void)StringCchPrintf(szInfo+lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), TEXT("Module %s, %d objects left active!"),
349 m_ModuleName, CBaseObject::ObjectsActive());
350 DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
351
352 // If running remotely wait for the Assert to be acknowledged
353 // before dumping out the object register
354 DbgDumpObjectRegister();
355 }
356 DbgTerminate();
357#endif
358 break;
359 }
360
361#ifdef DEBUG
362 g_fDbgInDllEntryPoint = false;
363#endif
364 return TRUE;
365}
366
367