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.

519 lines
11 KiB

  1. /*
  2. * clsfact.cpp - IClassFactory implementation.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.hpp"
  7. #pragma hdrstop
  8. #include "clsfact.h"
  9. #include "ftps.hpp"
  10. #include "inetcpl.h"
  11. #include "inetps.hpp"
  12. /* Types
  13. ********/
  14. // callback function used by ClassFactory::ClassFactory()
  15. typedef PIUnknown (*NEWOBJECTPROC)(OBJECTDESTROYEDPROC);
  16. DECLARE_STANDARD_TYPES(NEWOBJECTPROC);
  17. // description of class supported by DllGetClassObject()
  18. typedef struct classconstructor
  19. {
  20. PCCLSID pcclsid;
  21. NEWOBJECTPROC NewObject;
  22. }
  23. CLASSCONSTRUCTOR;
  24. DECLARE_STANDARD_TYPES(CLASSCONSTRUCTOR);
  25. /* Classes
  26. **********/
  27. // object class factory
  28. class ClassFactory : public RefCount,
  29. public IClassFactory
  30. {
  31. private:
  32. NEWOBJECTPROC m_NewObject;
  33. public:
  34. ClassFactory(NEWOBJECTPROC NewObject, OBJECTDESTROYEDPROC ObjectDestroyed);
  35. ~ClassFactory(void);
  36. // IClassFactory methods
  37. HRESULT STDMETHODCALLTYPE CreateInstance(PIUnknown piunkOuter, REFIID riid, PVOID *ppvObject);
  38. HRESULT STDMETHODCALLTYPE LockServer(BOOL bLock);
  39. // IUnknown methods
  40. ULONG STDMETHODCALLTYPE AddRef(void);
  41. ULONG STDMETHODCALLTYPE Release(void);
  42. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObj);
  43. // friends
  44. #ifdef DEBUG
  45. friend BOOL IsValidPCClassFactory(const ClassFactory *pcurlcf);
  46. #endif
  47. };
  48. DECLARE_STANDARD_TYPES(ClassFactory);
  49. /* Module Prototypes
  50. ********************/
  51. PRIVATE_CODE PIUnknown NewInternetShortcut(OBJECTDESTROYEDPROC ObjectDestroyed);
  52. PRIVATE_CODE PIUnknown NewMIMEHook(OBJECTDESTROYEDPROC ObjectDestroyed);
  53. PRIVATE_CODE PIUnknown NewInternet(OBJECTDESTROYEDPROC ObjectDestroyed);
  54. /* Module Constants
  55. *******************/
  56. #pragma data_seg(DATA_SEG_READ_ONLY)
  57. PRIVATE_DATA CCLASSCONSTRUCTOR s_cclscnstr[] =
  58. {
  59. { &CLSID_InternetShortcut, &NewInternetShortcut },
  60. { &CLSID_MIMEFileTypesPropSheetHook, &NewMIMEHook },
  61. { &CLSID_Internet, &NewInternet },
  62. };
  63. #pragma data_seg()
  64. /* Module Variables
  65. *******************/
  66. #pragma data_seg(DATA_SEG_PER_INSTANCE)
  67. // DLL reference count == number of class factories +
  68. // number of URLs +
  69. // LockServer() count
  70. PRIVATE_DATA ULONG s_ulcDLLRef = 0;
  71. #pragma data_seg()
  72. /***************************** Private Functions *****************************/
  73. PRIVATE_CODE HRESULT GetClassConstructor(REFCLSID rclsid,
  74. PNEWOBJECTPROC pNewObject)
  75. {
  76. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  77. UINT u;
  78. ASSERT(IsValidREFCLSID(rclsid));
  79. ASSERT(IS_VALID_WRITE_PTR(pNewObject, NEWOBJECTPROC));
  80. *pNewObject = NULL;
  81. for (u = 0; u < ARRAY_ELEMENTS(s_cclscnstr); u++)
  82. {
  83. if (rclsid == *(s_cclscnstr[u].pcclsid))
  84. {
  85. *pNewObject = s_cclscnstr[u].NewObject;
  86. hr = S_OK;
  87. }
  88. }
  89. ASSERT((hr == S_OK &&
  90. IS_VALID_CODE_PTR(*pNewObject, NEWOBJECTPROC)) ||
  91. (hr == CLASS_E_CLASSNOTAVAILABLE &&
  92. ! *pNewObject));
  93. return(hr);
  94. }
  95. PRIVATE_CODE void STDMETHODCALLTYPE DLLObjectDestroyed(void)
  96. {
  97. TRACE_OUT(("DLLObjectDestroyed(): Object destroyed."));
  98. DLLRelease();
  99. }
  100. PRIVATE_CODE PIUnknown NewInternetShortcut(OBJECTDESTROYEDPROC ObjectDestroyed)
  101. {
  102. ASSERT(! ObjectDestroyed ||
  103. IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC));
  104. TRACE_OUT(("NewInternetShortcut(): Creating a new InternetShortcut."));
  105. return((PIUnknown)(PIUniformResourceLocator)new(InternetShortcut(ObjectDestroyed)));
  106. }
  107. PRIVATE_CODE PIUnknown NewMIMEHook(OBJECTDESTROYEDPROC ObjectDestroyed)
  108. {
  109. ASSERT(! ObjectDestroyed ||
  110. IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC));
  111. TRACE_OUT(("NewMIMEHook(): Creating a new MIMEHook."));
  112. return((PIUnknown)(PIShellPropSheetExt)new(MIMEHook(ObjectDestroyed)));
  113. }
  114. PRIVATE_CODE PIUnknown NewInternet(OBJECTDESTROYEDPROC ObjectDestroyed)
  115. {
  116. ASSERT(! ObjectDestroyed ||
  117. IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC));
  118. TRACE_OUT(("NewInternet(): Creating a new Internet."));
  119. return((PIUnknown)(PIShellPropSheetExt)new(Internet(ObjectDestroyed)));
  120. }
  121. #ifdef DEBUG
  122. PRIVATE_CODE BOOL IsValidPCClassFactory(PCClassFactory pccf)
  123. {
  124. return(IS_VALID_READ_PTR(pccf, CClassFactory) &&
  125. IS_VALID_CODE_PTR(pccf->m_NewObject, NEWOBJECTPROC) &&
  126. IS_VALID_STRUCT_PTR((PCRefCount)pccf, CRefCount) &&
  127. IS_VALID_INTERFACE_PTR((PCIClassFactory)pccf, IClassFactory));
  128. }
  129. #endif
  130. /****************************** Public Functions *****************************/
  131. PUBLIC_CODE ULONG DLLAddRef(void)
  132. {
  133. ULONG ulcRef;
  134. ASSERT(s_ulcDLLRef < ULONG_MAX);
  135. ulcRef = ++s_ulcDLLRef;
  136. TRACE_OUT(("DLLAddRef(): DLL reference count is now %lu.",
  137. ulcRef));
  138. return(ulcRef);
  139. }
  140. PUBLIC_CODE ULONG DLLRelease(void)
  141. {
  142. ULONG ulcRef;
  143. if (EVAL(s_ulcDLLRef > 0))
  144. s_ulcDLLRef--;
  145. ulcRef = s_ulcDLLRef;
  146. TRACE_OUT(("DLLRelease(): DLL reference count is now %lu.",
  147. ulcRef));
  148. return(ulcRef);
  149. }
  150. PUBLIC_CODE PULONG GetDLLRefCountPtr(void)
  151. {
  152. return(&s_ulcDLLRef);
  153. }
  154. /********************************** Methods **********************************/
  155. ClassFactory::ClassFactory(NEWOBJECTPROC NewObject,
  156. OBJECTDESTROYEDPROC ObjectDestroyed) :
  157. RefCount(ObjectDestroyed)
  158. {
  159. DebugEntry(ClassFactory::ClassFactory);
  160. // Don't validate this until after construction.
  161. ASSERT(IS_VALID_CODE_PTR(NewObject, NEWOBJECTPROC));
  162. m_NewObject = NewObject;
  163. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  164. DebugExitVOID(ClassFactory::ClassFactory);
  165. return;
  166. }
  167. ClassFactory::~ClassFactory(void)
  168. {
  169. DebugEntry(ClassFactory::~ClassFactory);
  170. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  171. m_NewObject = NULL;
  172. // Don't validate this after destruction.
  173. DebugExitVOID(ClassFactory::~ClassFactory);
  174. return;
  175. }
  176. ULONG STDMETHODCALLTYPE ClassFactory::AddRef(void)
  177. {
  178. ULONG ulcRef;
  179. DebugEntry(ClassFactory::AddRef);
  180. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  181. ulcRef = RefCount::AddRef();
  182. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  183. DebugExitULONG(ClassFactory::AddRef, ulcRef);
  184. return(ulcRef);
  185. }
  186. ULONG STDMETHODCALLTYPE ClassFactory::Release(void)
  187. {
  188. ULONG ulcRef;
  189. DebugEntry(ClassFactory::Release);
  190. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  191. ulcRef = RefCount::Release();
  192. DebugExitULONG(ClassFactory::Release, ulcRef);
  193. return(ulcRef);
  194. }
  195. HRESULT STDMETHODCALLTYPE ClassFactory::QueryInterface(REFIID riid,
  196. PVOID *ppvObject)
  197. {
  198. HRESULT hr = S_OK;
  199. DebugEntry(ClassFactory::QueryInterface);
  200. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  201. ASSERT(IsValidREFIID(riid));
  202. ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
  203. if (riid == IID_IClassFactory)
  204. {
  205. *ppvObject = (PIClassFactory)this;
  206. ASSERT(IS_VALID_INTERFACE_PTR((PIClassFactory)*ppvObject, IClassFactory));
  207. TRACE_OUT(("ClassFactory::QueryInterface(): Returning IClassFactory."));
  208. }
  209. else if (riid == IID_IUnknown)
  210. {
  211. *ppvObject = (PIUnknown)this;
  212. ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown));
  213. TRACE_OUT(("ClassFactory::QueryInterface(): Returning IUnknown."));
  214. }
  215. else
  216. {
  217. *ppvObject = NULL;
  218. hr = E_NOINTERFACE;
  219. TRACE_OUT(("ClassFactory::QueryInterface(): Called on unknown interface."));
  220. }
  221. if (hr == S_OK)
  222. AddRef();
  223. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  224. ASSERT(FAILED(hr) ||
  225. IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE));
  226. DebugExitHRESULT(ClassFactory::QueryInterface, hr);
  227. return(hr);
  228. }
  229. HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(PIUnknown piunkOuter,
  230. REFIID riid,
  231. PVOID *ppvObject)
  232. {
  233. HRESULT hr;
  234. DebugEntry(ClassFactory::CreateInstance);
  235. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  236. ASSERT(! piunkOuter ||
  237. IS_VALID_INTERFACE_PTR(piunkOuter, IUnknown));
  238. ASSERT(IsValidREFIID(riid));
  239. ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
  240. *ppvObject = NULL;
  241. if (! piunkOuter)
  242. {
  243. PIUnknown piunk;
  244. piunk = (*m_NewObject)(&DLLObjectDestroyed);
  245. if (piunk)
  246. {
  247. DLLAddRef();
  248. hr = piunk->QueryInterface(riid, ppvObject);
  249. // N.b., the Release() method will destroy the object if the
  250. // QueryInterface() method failed.
  251. piunk->Release();
  252. }
  253. else
  254. hr = E_OUTOFMEMORY;
  255. }
  256. else
  257. {
  258. hr = CLASS_E_NOAGGREGATION;
  259. WARNING_OUT(("ClassFactory::CreateInstance(): Aggregation not supported."));
  260. }
  261. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  262. ASSERT(FAILED(hr) ||
  263. IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE));
  264. DebugExitHRESULT(ClassFactory::CreateInstance, hr);
  265. return(hr);
  266. }
  267. HRESULT STDMETHODCALLTYPE ClassFactory::LockServer(BOOL bLock)
  268. {
  269. HRESULT hr;
  270. DebugEntry(ClassFactory::LockServer);
  271. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  272. // bLock may be any value.
  273. if (bLock)
  274. DLLAddRef();
  275. else
  276. DLLRelease();
  277. hr = S_OK;
  278. ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
  279. DebugExitHRESULT(ClassFactory::LockServer, hr);
  280. return(hr);
  281. }
  282. /***************************** Exported Functions ****************************/
  283. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PVOID *ppvObject)
  284. {
  285. HRESULT hr = S_OK;
  286. NEWOBJECTPROC NewObject;
  287. DebugEntry(DllGetClassObject);
  288. ASSERT(IsValidREFCLSID(rclsid));
  289. ASSERT(IsValidREFIID(riid));
  290. ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
  291. *ppvObject = NULL;
  292. hr = GetClassConstructor(rclsid, &NewObject);
  293. if (hr == S_OK)
  294. {
  295. if (riid == IID_IUnknown ||
  296. riid == IID_IClassFactory)
  297. {
  298. PClassFactory pcf;
  299. pcf = new(ClassFactory(NewObject, &DLLObjectDestroyed));
  300. if (pcf)
  301. {
  302. if (riid == IID_IClassFactory)
  303. {
  304. *ppvObject = (PIClassFactory)pcf;
  305. ASSERT(IS_VALID_INTERFACE_PTR((PIClassFactory)*ppvObject, IClassFactory));
  306. TRACE_OUT(("DllGetClassObject(): Returning IClassFactory."));
  307. }
  308. else
  309. {
  310. ASSERT(riid == IID_IUnknown);
  311. *ppvObject = (PIUnknown)pcf;
  312. ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown));
  313. TRACE_OUT(("DllGetClassObject(): Returning IUnknown."));
  314. }
  315. DLLAddRef();
  316. hr = S_OK;
  317. TRACE_OUT(("DllGetClassObject(): Created a new class factory."));
  318. }
  319. else
  320. hr = E_OUTOFMEMORY;
  321. }
  322. else
  323. {
  324. WARNING_OUT(("DllGetClassObject(): Called on unknown interface."));
  325. hr = E_NOINTERFACE;
  326. }
  327. }
  328. else
  329. WARNING_OUT(("DllGetClassObject(): Called on unknown class."));
  330. ASSERT(FAILED(hr) ||
  331. IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE));
  332. DebugExitHRESULT(DllGetClassObject, hr);
  333. return(hr);
  334. }
  335. STDAPI DllCanUnloadNow(void)
  336. {
  337. HRESULT hr;
  338. DebugEntry(DllCanUnloadNow);
  339. hr = (s_ulcDLLRef > 0) ? S_FALSE : S_OK;
  340. if (hr == S_OK)
  341. hr = InternetCPLCanUnloadNow();
  342. TRACE_OUT(("DllCanUnloadNow(): DLL reference count is %lu.",
  343. s_ulcDLLRef));
  344. DebugExitHRESULT(DllCanUnloadNow, hr);
  345. return(hr);
  346. }