Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
8.4 KiB

  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. #include <streams.h>
  10. #include <initguid.h>
  11. #ifdef DEBUG
  12. #ifdef UNICODE
  13. #ifndef _UNICODE
  14. #define _UNICODE
  15. #endif // _UNICODE
  16. #endif // UNICODE
  17. #include <tchar.h>
  18. #endif // DEBUG
  19. extern CFactoryTemplate g_Templates[];
  20. extern int g_cTemplates;
  21. HINSTANCE g_hInst;
  22. DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
  23. OSVERSIONINFO g_osInfo;
  24. //
  25. // an instance of this is created by the DLLGetClassObject entrypoint
  26. // it uses the CFactoryTemplate object it is given to support the
  27. // IClassFactory interface
  28. class CClassFactory : public IClassFactory, public CBaseObject
  29. {
  30. private:
  31. const CFactoryTemplate *const m_pTemplate;
  32. ULONG m_cRef;
  33. static int m_cLocked;
  34. public:
  35. CClassFactory(const CFactoryTemplate *);
  36. // IUnknown
  37. STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
  38. STDMETHODIMP_(ULONG)AddRef();
  39. STDMETHODIMP_(ULONG)Release();
  40. // IClassFactory
  41. STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
  42. STDMETHODIMP LockServer(BOOL fLock);
  43. // allow DLLGetClassObject to know about global server lock status
  44. static BOOL IsLocked() {
  45. return (m_cLocked > 0);
  46. };
  47. };
  48. // process-wide dll locked state
  49. int CClassFactory::m_cLocked = 0;
  50. CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
  51. : CBaseObject(NAME("Class Factory"))
  52. , m_cRef(0)
  53. , m_pTemplate(pTemplate)
  54. {
  55. }
  56. STDMETHODIMP
  57. CClassFactory::QueryInterface(REFIID riid,void **ppv)
  58. {
  59. CheckPointer(ppv,E_POINTER)
  60. ValidateReadWritePtr(ppv,sizeof(PVOID));
  61. *ppv = NULL;
  62. // any interface on this object is the object pointer.
  63. if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
  64. *ppv = (LPVOID) this;
  65. // AddRef returned interface pointer
  66. ((LPUNKNOWN) *ppv)->AddRef();
  67. return NOERROR;
  68. }
  69. return ResultFromScode(E_NOINTERFACE);
  70. }
  71. STDMETHODIMP_(ULONG)
  72. CClassFactory::AddRef()
  73. {
  74. return ++m_cRef;
  75. }
  76. STDMETHODIMP_(ULONG)
  77. CClassFactory::Release()
  78. {
  79. if (--m_cRef == 0) {
  80. delete this;
  81. return 0;
  82. } else {
  83. return m_cRef;
  84. }
  85. }
  86. STDMETHODIMP
  87. CClassFactory::CreateInstance(
  88. LPUNKNOWN pUnkOuter,
  89. REFIID riid,
  90. void **pv)
  91. {
  92. CheckPointer(pv,E_POINTER)
  93. ValidateReadWritePtr(pv,sizeof(void *));
  94. /* Enforce the normal OLE rules regarding interfaces and delegation */
  95. if (pUnkOuter != NULL) {
  96. if (IsEqualIID(riid,IID_IUnknown) == FALSE) {
  97. return ResultFromScode(E_NOINTERFACE);
  98. }
  99. }
  100. /* Create the new object through the derived class's create function */
  101. HRESULT hr = NOERROR;
  102. CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
  103. if (pObj == NULL) {
  104. if (SUCCEEDED(hr)) {
  105. hr = E_OUTOFMEMORY;
  106. }
  107. return hr;
  108. }
  109. /* Delete the object if we got a construction error */
  110. if (FAILED(hr)) {
  111. delete pObj;
  112. return hr;
  113. }
  114. /* Get a reference counted interface on the object */
  115. /* We wrap the non-delegating QI with NDAddRef & NDRelease. */
  116. /* This protects any outer object from being prematurely */
  117. /* released by an inner object that may have to be created */
  118. /* in order to supply the requested interface. */
  119. pObj->NonDelegatingAddRef();
  120. hr = pObj->NonDelegatingQueryInterface(riid, pv);
  121. pObj->NonDelegatingRelease();
  122. /* Note that if NonDelegatingQueryInterface fails, it will */
  123. /* not increment the ref count, so the NonDelegatingRelease */
  124. /* will drop the ref back to zero and the object will "self-*/
  125. /* destruct". Hence we don't need additional tidy-up code */
  126. /* to cope with NonDelegatingQueryInterface failing. */
  127. if (SUCCEEDED(hr)) {
  128. ASSERT(*pv);
  129. }
  130. return hr;
  131. }
  132. STDMETHODIMP
  133. CClassFactory::LockServer(BOOL fLock)
  134. {
  135. if (fLock) {
  136. m_cLocked++;
  137. } else {
  138. m_cLocked--;
  139. }
  140. return NOERROR;
  141. }
  142. // --- COM entrypoints -----------------------------------------
  143. //called by COM to get the class factory object for a given class
  144. STDAPI
  145. DllGetClassObject(
  146. REFCLSID rClsID,
  147. REFIID riid,
  148. void **pv)
  149. {
  150. if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
  151. return E_NOINTERFACE;
  152. }
  153. // traverse the array of templates looking for one with this
  154. // class id
  155. for (int i = 0; i < g_cTemplates; i++) {
  156. const CFactoryTemplate * pT = &g_Templates[i];
  157. if (pT->IsClassID(rClsID)) {
  158. // found a template - make a class factory based on this
  159. // template
  160. *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
  161. if (*pv == NULL) {
  162. return E_OUTOFMEMORY;
  163. }
  164. ((LPUNKNOWN)*pv)->AddRef();
  165. return NOERROR;
  166. }
  167. }
  168. return CLASS_E_CLASSNOTAVAILABLE;
  169. }
  170. //
  171. // Call any initialization routines
  172. //
  173. void
  174. DllInitClasses(BOOL bLoading)
  175. {
  176. int i;
  177. // traverse the array of templates calling the init routine
  178. // if they have one
  179. for (i = 0; i < g_cTemplates; i++) {
  180. const CFactoryTemplate * pT = &g_Templates[i];
  181. if (pT->m_lpfnInit != NULL) {
  182. (*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
  183. }
  184. }
  185. }
  186. // called by COM to determine if this dll can be unloaded
  187. // return ok unless there are outstanding objects or a lock requested
  188. // by IClassFactory::LockServer
  189. //
  190. // CClassFactory has a static function that can tell us about the locks,
  191. // and CCOMObject has a static function that can tell us about the active
  192. // object count
  193. STDAPI
  194. DllCanUnloadNow()
  195. {
  196. DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
  197. CClassFactory::IsLocked(),
  198. CBaseObject::ObjectsActive()));
  199. if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
  200. return S_FALSE;
  201. } else {
  202. return S_OK;
  203. }
  204. }
  205. // --- standard WIN32 entrypoints --------------------------------------
  206. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  207. BOOL WINAPI
  208. DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv)
  209. {
  210. #ifdef DEBUG
  211. extern bool g_fDbgInDllEntryPoint;
  212. g_fDbgInDllEntryPoint = true;
  213. #endif
  214. switch (ulReason)
  215. {
  216. case DLL_PROCESS_ATTACH:
  217. DisableThreadLibraryCalls(hInstance);
  218. DbgInitialise(hInstance);
  219. {
  220. // The platform identifier is used to work out whether
  221. // full unicode support is available or not. Hence the
  222. // default will be the lowest common denominator - i.e. N/A
  223. g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
  224. g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
  225. if (GetVersionEx(&g_osInfo)) {
  226. g_amPlatform = g_osInfo.dwPlatformId;
  227. } else {
  228. DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
  229. }
  230. }
  231. g_hInst = hInstance;
  232. DllInitClasses(TRUE);
  233. break;
  234. case DLL_PROCESS_DETACH:
  235. DllInitClasses(FALSE);
  236. #ifdef DEBUG
  237. if (CBaseObject::ObjectsActive()) {
  238. DbgSetModuleLevel(LOG_MEMORY, 2);
  239. TCHAR szInfo[512];
  240. extern TCHAR m_ModuleName[]; // Cut down module name
  241. TCHAR FullName[_MAX_PATH]; // Load the full path and module name
  242. TCHAR *pName; // Searches from the end for a backslash
  243. GetModuleFileName(NULL,FullName,_MAX_PATH);
  244. pName = _tcsrchr(FullName,'\\');
  245. if (pName == NULL) {
  246. pName = FullName;
  247. } else {
  248. pName++;
  249. }
  250. DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "),
  251. pName, GetCurrentProcessId(), GetCurrentThreadId());
  252. wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"),
  253. m_ModuleName, CBaseObject::ObjectsActive());
  254. DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
  255. // If running remotely wait for the Assert to be acknowledged
  256. // before dumping out the object register
  257. DbgDumpObjectRegister();
  258. }
  259. DbgTerminate();
  260. #endif
  261. break;
  262. }
  263. #ifdef DEBUG
  264. g_fDbgInDllEntryPoint = false;
  265. #endif
  266. return TRUE;
  267. }