Leaked source code of windows server 2003
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.

600 lines
18 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation
  3. Module Name:
  4. factory.cpp
  5. Abstract:
  6. This module implements CClassFactory class
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "devmgr.h"
  12. #include "factory.h"
  13. #include "about.h"
  14. const TCHAR* const REG_MMC_SNAPINS = TEXT("Software\\Microsoft\\MMC\\Snapins");
  15. const TCHAR* const REG_MMC_NODETYPE = TEXT("Software\\Microsoft\\MMC\\NodeTypes");
  16. const TCHAR* const MMC_NAMESTRING = TEXT("NameString");
  17. const TCHAR* const MMC_NAMESTRINGINDIRECT = TEXT("NameStringIndirect");
  18. const TCHAR* const MMC_PROVIDER = TEXT("Provider");
  19. const TCHAR* const MMC_VERSION = TEXT("Version");
  20. const TCHAR* const MMC_NODETYPES = TEXT("NodeTypes");
  21. const TCHAR* const MMC_STANDALONE = TEXT("StandAlone");
  22. const TCHAR* const MMC_EXTENSIONS = TEXT("Extensions");
  23. const TCHAR* const MMC_NAMESPACE = TEXT("NameSpace");
  24. const TCHAR* const MMC_ABOUT = TEXT("About");
  25. const TCHAR* const REG_INPROCSERVER32 = TEXT("InprocServer32");
  26. const TCHAR* const REG_THREADINGMODEL = TEXT("ThreadingModel");
  27. const TCHAR* const REG_CLSID = TEXT("CLSID");
  28. const TCHAR* const REG_PROGID = TEXT("ProgId");
  29. const TCHAR* const REG_VERSIONINDEPENDENTPROGID = TEXT("VersionIndependentProgId");
  30. const TCHAR* const APARTMENT = TEXT("Apartment");
  31. //
  32. // CClassFactory implmentation
  33. //
  34. LONG CClassFactory::s_Locks = 0;
  35. LONG CClassFactory::s_Objects = 0;
  36. ULONG
  37. CClassFactory::AddRef()
  38. {
  39. return ::InterlockedIncrement(&m_Ref);
  40. }
  41. ULONG
  42. CClassFactory::Release()
  43. {
  44. ASSERT( 0 != m_Ref );
  45. ULONG cRef = ::InterlockedDecrement(&m_Ref);
  46. if ( 0 == cRef )
  47. {
  48. delete this;
  49. }
  50. return cRef;
  51. }
  52. STDMETHODIMP
  53. CClassFactory::QueryInterface(
  54. REFIID riid,
  55. LPVOID* ppv
  56. )
  57. {
  58. if (!ppv)
  59. {
  60. return E_INVALIDARG;
  61. }
  62. HRESULT hr = S_OK;
  63. if (IsEqualIID(riid, IID_IUnknown))
  64. {
  65. *ppv = (IUnknown *)(IClassFactory *)this;
  66. }
  67. else if (IsEqualIID(riid, IID_IClassFactory))
  68. {
  69. *ppv = (IUnknown *)(IClassFactory *)this;
  70. }
  71. else
  72. {
  73. hr = E_NOINTERFACE;
  74. }
  75. if (SUCCEEDED(hr))
  76. {
  77. AddRef();
  78. }
  79. else
  80. {
  81. *ppv = NULL;
  82. }
  83. return hr;
  84. }
  85. STDMETHODIMP
  86. CClassFactory::CreateInstance(
  87. IUnknown *pUnkOuter,
  88. REFIID riid,
  89. LPVOID *ppv
  90. )
  91. {
  92. if (!ppv)
  93. {
  94. return E_INVALIDARG;
  95. }
  96. HRESULT hr = S_OK;
  97. *ppv = NULL;
  98. if (pUnkOuter != NULL)
  99. {
  100. hr = CLASS_E_NOAGGREGATION;
  101. }
  102. try
  103. {
  104. switch (m_ClassType)
  105. {
  106. case DM_CLASS_TYPE_SNAPIN:
  107. {
  108. // create the factory with the request class(class type).
  109. // When a new OLE object is created, it initializes its
  110. // ref count to 1. We do a release right after the QI
  111. // so that if the QI failed, the object will be self-destructed
  112. CComponentData* pCompData = new CComponentDataPrimary();
  113. hr = pCompData->QueryInterface(riid, ppv);
  114. pCompData->Release();
  115. break;
  116. }
  117. case DM_CLASS_TYPE_SNAPIN_EXTENSION:
  118. {
  119. // create the factory with the request class(class type).
  120. // When a new OLE object is created, it initializes its
  121. // ref count to 1. We do a release right after the QI
  122. // so that if the QI failed, the object will be self-destructed
  123. CComponentData* pCompData = new CComponentDataExtension();
  124. hr = pCompData->QueryInterface(riid, ppv);
  125. pCompData->Release();
  126. break;
  127. }
  128. case DM_CLASS_TYPE_SNAPIN_ABOUT:
  129. {
  130. // create the factory with the request class(class type).
  131. // When a new OLE object is created, it initializes its
  132. // ref count to 1. We do a release right after the QI
  133. // so that if the QI failed, the object will be self-destructed
  134. CDevMgrAbout* pAbout = new CDevMgrAbout;
  135. hr = pAbout->QueryInterface(riid, ppv);
  136. pAbout->Release();
  137. break;
  138. }
  139. default:
  140. {
  141. hr = E_NOINTERFACE;
  142. }
  143. }
  144. }
  145. catch (CMemoryException* e)
  146. {
  147. hr = E_OUTOFMEMORY;
  148. e->Delete();
  149. }
  150. return hr;
  151. }
  152. STDMETHODIMP
  153. CClassFactory::LockServer(
  154. BOOL fLock
  155. )
  156. {
  157. if (fLock)
  158. {
  159. ::InterlockedIncrement((LONG*)&s_Locks);
  160. }
  161. else
  162. {
  163. ASSERT( 0 != s_Locks );
  164. ::InterlockedDecrement((LONG*)&s_Locks);
  165. }
  166. return S_OK;
  167. }
  168. HRESULT
  169. CClassFactory::CanUnloadNow()
  170. {
  171. return (s_Objects || s_Locks) ? S_FALSE : S_OK;
  172. }
  173. //
  174. // This function create a CClassFactory. It is mainly called
  175. // by DllGetClassObject API
  176. // INPUT:
  177. // rclsid -- reference to the CLSID
  178. // riid -- reference to the interface IID
  179. // ppv -- interface pointer holder
  180. //
  181. // OUTPUT:
  182. // S_OK if succeeded else standard OLE error code
  183. //
  184. //
  185. HRESULT
  186. CClassFactory::GetClassObject(
  187. REFCLSID rclsid,
  188. REFIID riid,
  189. void** ppv
  190. )
  191. {
  192. if (!ppv)
  193. {
  194. return E_INVALIDARG;
  195. }
  196. *ppv = NULL;
  197. HRESULT hr = S_OK;
  198. DM_CLASS_TYPE ClassType;
  199. //
  200. // determine the class type so that CreateInstance will be
  201. // creating the right object. We use a single class factory
  202. // to create all the object types.
  203. //
  204. if (IsEqualCLSID(rclsid, CLSID_DEVMGR))
  205. {
  206. ClassType = DM_CLASS_TYPE_SNAPIN;
  207. }
  208. else if (IsEqualCLSID(rclsid, CLSID_DEVMGR_EXTENSION))
  209. {
  210. ClassType = DM_CLASS_TYPE_SNAPIN_EXTENSION;
  211. }
  212. else if (IsEqualCLSID(rclsid, CLSID_DEVMGR_ABOUT))
  213. {
  214. ClassType = DM_CLASS_TYPE_SNAPIN_ABOUT;
  215. }
  216. else
  217. {
  218. ClassType = DM_CLASS_TYPE_UNKNOWN;
  219. hr = E_NOINTERFACE;
  220. }
  221. if (SUCCEEDED(hr))
  222. {
  223. CClassFactory* pUnk;
  224. // guard memory allocation error because we do not want
  225. // to cause an execption here.
  226. try
  227. {
  228. // create the factory with the request class(class type).
  229. // When a new OLE object is created, it initializes its
  230. // ref count to 1. We do a release right after the QI
  231. // so that if the QI failed, the object will be self-destructed
  232. pUnk = new CClassFactory(ClassType);
  233. hr = pUnk->QueryInterface(riid, ppv);
  234. pUnk->Release();
  235. }
  236. catch (CMemoryException* e)
  237. {
  238. e->Delete();
  239. hr = E_OUTOFMEMORY;
  240. }
  241. }
  242. return hr;
  243. }
  244. //
  245. // This function registers the dll to MMC
  246. //
  247. HRESULT
  248. CClassFactory::RegisterAll()
  249. {
  250. BOOL Result;
  251. TCHAR szText[MAX_PATH];
  252. TCHAR ModuleName[MAX_PATH];
  253. GetModuleFileName(g_hInstance, ModuleName, ARRAYLEN(ModuleName));
  254. Result = FALSE;
  255. szText[0] = TEXT('\0');
  256. // first register standalone snapin CLSID
  257. CSafeRegistry regRootCLSID;
  258. if (regRootCLSID.Open(HKEY_CLASSES_ROOT, REG_CLSID))
  259. {
  260. CSafeRegistry regCLSID;
  261. // register our CLSID to HKEY_CLASS_ROOT\CLSID
  262. if (regCLSID.Create(regRootCLSID, CLSID_STRING_DEVMGR))
  263. {
  264. // write the description
  265. ::LoadString(g_hInstance, IDS_DESC_DEVMGR, szText, ARRAYLEN(szText));
  266. if (regCLSID.SetValue(NULL, szText))
  267. {
  268. CSafeRegistry regServer;
  269. if (regServer.Create(regCLSID, REG_INPROCSERVER32) &&
  270. regServer.SetValue(NULL, ModuleName) &&
  271. regServer.SetValue(REG_THREADINGMODEL, APARTMENT))
  272. {
  273. CSafeRegistry regProgId;
  274. if (regProgId.Create(regCLSID, REG_PROGID) &&
  275. regProgId.SetValue(NULL, PROGID_DEVMGR))
  276. {
  277. CSafeRegistry regVerIndProgId;
  278. if (regVerIndProgId.Create(regCLSID, REG_VERSIONINDEPENDENTPROGID))
  279. {
  280. Result = regVerIndProgId.SetValue(NULL, PROGID_DEVMGR);
  281. }
  282. }
  283. }
  284. }
  285. }
  286. if (Result)
  287. {
  288. regCLSID.Close();
  289. Result = FALSE;
  290. // register extension snapin CLSID
  291. if (regCLSID.Create(regRootCLSID, CLSID_STRING_DEVMGR_EXTENSION))
  292. {
  293. ::LoadString(g_hInstance, IDS_EXTENSION_DESC, szText, ARRAYLEN(szText));
  294. if (regCLSID.SetValue(NULL, szText))
  295. {
  296. CSafeRegistry regServer;
  297. if (regServer.Create(regCLSID, REG_INPROCSERVER32)&&
  298. regServer.SetValue(NULL, ModuleName) &&
  299. regServer.SetValue(REG_THREADINGMODEL, APARTMENT))
  300. {
  301. CSafeRegistry regProgId;
  302. if (regProgId.Create(regCLSID, REG_PROGID) &&
  303. regProgId.SetValue(NULL, PROGID_DEVMGREXT))
  304. {
  305. CSafeRegistry regVerIndProgId;
  306. if (regVerIndProgId.Create(regCLSID, REG_VERSIONINDEPENDENTPROGID))
  307. {
  308. Result = regVerIndProgId.SetValue(NULL, PROGID_DEVMGREXT);
  309. }
  310. }
  311. }
  312. }
  313. }
  314. }
  315. if (Result)
  316. {
  317. regCLSID.Close();
  318. Result = FALSE;
  319. // register snapin about CLSID
  320. if (regCLSID.Create(regRootCLSID, CLSID_STRING_DEVMGR_ABOUT))
  321. {
  322. ::LoadString(g_hInstance, IDS_ABOUT_DEVMGR, szText, ARRAYLEN(szText));
  323. if (regCLSID.SetValue(NULL, szText))
  324. {
  325. CSafeRegistry regServer;
  326. if (regServer.Create(regCLSID, REG_INPROCSERVER32)&&
  327. regServer.SetValue(NULL, ModuleName) &&
  328. regServer.SetValue(REG_THREADINGMODEL, APARTMENT))
  329. {
  330. CSafeRegistry regProgId;
  331. if (regProgId.Create(regCLSID, REG_PROGID) &&
  332. regProgId.SetValue(NULL, PROGID_DEVMGR_ABOUT))
  333. {
  334. CSafeRegistry regVerIndProgId;
  335. if (regVerIndProgId.Create(regCLSID, REG_VERSIONINDEPENDENTPROGID))
  336. {
  337. Result = regVerIndProgId.SetValue(NULL, PROGID_DEVMGR_ABOUT);
  338. }
  339. }
  340. }
  341. }
  342. }
  343. }
  344. }
  345. if (Result)
  346. {
  347. Result = FALSE;
  348. CSafeRegistry regSnapins;
  349. //
  350. // open mmc snapin subkey
  351. //
  352. if (regSnapins.Open(HKEY_LOCAL_MACHINE, REG_MMC_SNAPINS))
  353. {
  354. PNODEINFO pniDevMgr = (PNODEINFO)&NodeInfo[COOKIE_TYPE_SCOPEITEM_DEVMGR];
  355. CSafeRegistry regDevMgr;
  356. if (regDevMgr.Create(regSnapins, CLSID_STRING_DEVMGR))
  357. {
  358. StringCchPrintf(szText, ARRAYLEN(szText), TEXT("@%s,-%d"), ModuleName, IDS_DESC_DEVMGR);
  359. if (regDevMgr.SetValue(MMC_NAMESTRINGINDIRECT, szText))
  360. {
  361. ::LoadString(g_hInstance, pniDevMgr->idsName, szText, ARRAYLEN(szText));
  362. if (regDevMgr.SetValue(MMC_NAMESTRING, szText))
  363. {
  364. ::LoadString(g_hInstance, IDS_PROGRAM_PROVIDER, szText, ARRAYLEN(szText));
  365. if (regDevMgr.SetValue(MMC_PROVIDER, szText))
  366. {
  367. ::LoadString(g_hInstance, IDS_PROGRAM_VERSION, szText, ARRAYLEN(szText));
  368. if (regDevMgr.SetValue(MMC_VERSION, szText) &&
  369. regDevMgr.SetValue(MMC_ABOUT, CLSID_STRING_DEVMGR_ABOUT))
  370. {
  371. //
  372. // Let MMC knows that we are a standalone snapin --
  373. // meaning we do not need any extension snapins for us
  374. // to run.
  375. //
  376. CSafeRegistry regStandAlone;
  377. Result = regStandAlone.Create(regDevMgr, MMC_STANDALONE);
  378. }
  379. }
  380. }
  381. }
  382. }
  383. CSafeRegistry regMMCNodeTypes;
  384. if (Result)
  385. {
  386. // populate our nodes
  387. Result = regMMCNodeTypes.Open(HKEY_LOCAL_MACHINE, REG_MMC_NODETYPE);
  388. if (Result)
  389. {
  390. CSafeRegistry regTheNode;
  391. int i = NODETYPE_FIRST;
  392. do
  393. {
  394. PNODEINFO pni = (PNODEINFO) &NodeInfo[i];
  395. Result = regTheNode.Create(regMMCNodeTypes, pni->GuidString);
  396. regTheNode.Close();
  397. } while (Result && ++i <= NODETYPE_LAST);
  398. }
  399. }
  400. if (Result)
  401. {
  402. // register as an extension to Computer management snapin
  403. CSafeRegistry regDevMgrExt;
  404. if (regDevMgrExt.Create(regSnapins, CLSID_STRING_DEVMGR_EXTENSION))
  405. {
  406. ::LoadString(g_hInstance, IDS_EXTENSION_DESC, szText, ARRAYLEN(szText));
  407. if (regDevMgrExt.SetValue(MMC_NAMESTRING, szText))
  408. {
  409. ::LoadString(g_hInstance, IDS_PROGRAM_PROVIDER, szText, ARRAYLEN(szText));
  410. if (regDevMgrExt.SetValue(MMC_PROVIDER, szText))
  411. {
  412. ::LoadString(g_hInstance, IDS_PROGRAM_VERSION, szText, ARRAYLEN(szText));
  413. if (regDevMgrExt.SetValue(MMC_VERSION, szText) &&
  414. regDevMgrExt.SetValue(MMC_ABOUT, CLSID_STRING_DEVMGR_ABOUT))
  415. {
  416. CSafeRegistry regSysTools;
  417. if (regSysTools.Open(regMMCNodeTypes, CLSID_STRING_SYSTOOLS))
  418. {
  419. CSafeRegistry regExtensions;
  420. if (regExtensions.Open(regSysTools,MMC_EXTENSIONS))
  421. {
  422. CSafeRegistry regNameSpace;
  423. if (regNameSpace.Open(regExtensions, MMC_NAMESPACE))
  424. {
  425. // add our guid as a value of Name space
  426. Result = regNameSpace.SetValue(CLSID_STRING_DEVMGR_EXTENSION, szText);
  427. }
  428. }
  429. }
  430. }
  431. }
  432. }
  433. }
  434. }
  435. }
  436. }
  437. if (!Result)
  438. {
  439. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  440. UnregisterAll();
  441. return hr;
  442. }
  443. return S_OK;
  444. }
  445. //
  446. // This function unregisters the dll from MMC
  447. //
  448. HRESULT
  449. CClassFactory::UnregisterAll()
  450. {
  451. CSafeRegistry regSnapins;
  452. //
  453. // open mmc snapin subkey
  454. //
  455. if (regSnapins.Open(HKEY_LOCAL_MACHINE, REG_MMC_SNAPINS))
  456. {
  457. // remove devmgr subkey from MMC snapins main key
  458. // both primary and extension
  459. regSnapins.DeleteSubkey(CLSID_STRING_DEVMGR);
  460. regSnapins.DeleteSubkey(CLSID_STRING_DEVMGR_EXTENSION);
  461. // removed populated node types
  462. CSafeRegistry regMMCNodeTypes;
  463. if (regMMCNodeTypes.Open(HKEY_LOCAL_MACHINE, REG_MMC_NODETYPE))
  464. {
  465. for (int i = NODETYPE_FIRST; i <= NODETYPE_LAST; i++)
  466. {
  467. PNODEINFO pni = (PNODEINFO) &NodeInfo[i];
  468. regMMCNodeTypes.DeleteValue(pni->GuidString);
  469. }
  470. // remove from system tools
  471. CSafeRegistry regSysTools;
  472. if (regSysTools.Open(regMMCNodeTypes, CLSID_STRING_SYSTOOLS))
  473. {
  474. CSafeRegistry regExtensions;
  475. if (regExtensions.Open(regSysTools, MMC_EXTENSIONS))
  476. {
  477. CSafeRegistry regNameSpace;
  478. if (regNameSpace.Open(regExtensions, MMC_NAMESPACE))
  479. {
  480. regNameSpace.DeleteValue(CLSID_STRING_DEVMGR_EXTENSION);
  481. }
  482. }
  483. }
  484. }
  485. }
  486. // unregister from OLE
  487. CSafeRegistry regRootCLSID;
  488. if (regRootCLSID.Open(HKEY_CLASSES_ROOT, REG_CLSID))
  489. {
  490. regRootCLSID.DeleteSubkey(CLSID_STRING_DEVMGR);
  491. regRootCLSID.DeleteSubkey(CLSID_STRING_DEVMGR_EXTENSION);
  492. regRootCLSID.DeleteSubkey(CLSID_STRING_DEVMGR_ABOUT);
  493. }
  494. return S_OK;
  495. }