Sauw Ming | 93ba7fe | 2012-04-18 02:38:42 +0000 | [diff] [blame^] | 1 | //------------------------------------------------------------------------------
|
| 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 |
|
| 25 | extern CFactoryTemplate g_Templates[];
|
| 26 | extern int g_cTemplates;
|
| 27 |
|
| 28 | HINSTANCE g_hInst;
|
| 29 | DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
|
| 30 | OSVERSIONINFO 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 |
|
| 37 | class CClassFactory : public IClassFactory, public CBaseObject
|
| 38 | {
|
| 39 |
|
| 40 | private:
|
| 41 | const CFactoryTemplate *const m_pTemplate;
|
| 42 |
|
| 43 | ULONG m_cRef;
|
| 44 |
|
| 45 | static int m_cLocked;
|
| 46 | public:
|
| 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
|
| 65 | int CClassFactory::m_cLocked = 0;
|
| 66 |
|
| 67 | CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
|
| 68 | : CBaseObject(NAME("Class Factory"))
|
| 69 | , m_cRef(0)
|
| 70 | , m_pTemplate(pTemplate)
|
| 71 | {
|
| 72 | }
|
| 73 |
|
| 74 |
|
| 75 | STDMETHODIMP
|
| 76 | CClassFactory::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 |
|
| 94 | STDMETHODIMP_(ULONG)
|
| 95 | CClassFactory::AddRef()
|
| 96 | {
|
| 97 | return ++m_cRef;
|
| 98 | }
|
| 99 |
|
| 100 | STDMETHODIMP_(ULONG)
|
| 101 | CClassFactory::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 |
|
| 112 | STDMETHODIMP
|
| 113 | CClassFactory::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 |
|
| 174 | STDMETHODIMP
|
| 175 | CClassFactory::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
|
| 190 | DllGetClassObject(
|
| 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 | //
|
| 223 | void
|
| 224 | DllInitClasses(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
|
| 246 | STDAPI
|
| 247 | DllCanUnloadNow()
|
| 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 |
|
| 264 | extern "C" void __cdecl __security_init_cookie(void);
|
| 265 | extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID);
|
| 266 | #pragma comment(linker, "/merge:.CRT=.rdata")
|
| 267 |
|
| 268 | extern "C"
|
| 269 | DECLSPEC_NOINLINE
|
| 270 | BOOL
|
| 271 | WINAPI
|
| 272 | DllEntryPoint(
|
| 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 |
|
| 286 | DECLSPEC_NOINLINE
|
| 287 | BOOL
|
| 288 | WINAPI
|
| 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 |
|