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.

670 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994-2000 Microsoft Corporation
  3. Module Name :
  4. inetmgrapp.cpp
  5. Abstract:
  6. Snapin object
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. --*/
  14. //
  15. // Include Files
  16. //
  17. #include "stdafx.h"
  18. #include "resource.h"
  19. #include "initguid.h"
  20. #include "inetmgr.h"
  21. #include "dlldatax.h"
  22. #include "common.h"
  23. #include "guids.h"
  24. #include <winsock2.h>
  25. #include "inetmgr_i.c"
  26. #include "inetmgrapp.h"
  27. #ifdef _DEBUG
  28. #undef THIS_FILE
  29. static char BASED_CODE THIS_FILE[] = __FILE__;
  30. #endif
  31. #define new DEBUG_NEW
  32. #ifdef _DEBUG
  33. //
  34. // Allocation tracker
  35. //
  36. BOOL
  37. TrackAllocHook(
  38. IN size_t nSize,
  39. IN BOOL bObject,
  40. IN LONG lRequestNumber
  41. )
  42. {
  43. //
  44. // Set breakpoint on specific allocation number
  45. // to track memory leak.
  46. //
  47. //TRACEEOLID("allocation # " << lRequestNumber);
  48. return TRUE;
  49. }
  50. #endif // _DEBUG
  51. // From stdafx.cpp
  52. #ifdef _ATL_STATIC_REGISTRY
  53. #include <statreg.h>
  54. #include <statreg.cpp>
  55. #endif
  56. #include <atlimpl.cpp>
  57. #include <atlwin.cpp>
  58. #ifdef _MERGE_PROXYSTUB
  59. extern "C" HINSTANCE hProxyDll;
  60. #endif
  61. const LPCTSTR g_cszCLSID = _T("CLSID");
  62. const LPCTSTR g_cszLS32 = _T("LocalServer32");
  63. const LPCTSTR g_cszIPS32 = _T("InprocServer32");
  64. const LPCTSTR g_cszMMCBasePath = _T("Software\\Microsoft\\MMC");
  65. const LPCTSTR g_cszSnapins = _T("Snapins");
  66. const LPCTSTR g_cszNameString = _T("NameString");
  67. const LPCTSTR g_cszNameStringInd = _T("NameStringIndirect");
  68. const LPCTSTR g_cszProvider = _T("Provider");
  69. const LPCTSTR g_cszVersion = _T("Version");
  70. const LPCTSTR g_cszStandAlone = _T("StandAlone");
  71. const LPCTSTR g_cszNodeTypes = _T("NodeTypes");
  72. const LPCTSTR g_cszAbout = _T("About");
  73. const LPCTSTR g_cszExtensions = _T("Extensions");
  74. const LPCTSTR g_cszExtensionsView = _T("Extensions\\View");
  75. const LPCTSTR g_cszNameSpace = _T("NameSpace");
  76. const LPCTSTR g_cszDynamicExt = _T("Dynamic Extensions");
  77. const LPCTSTR g_cszValProvider = _T("Microsoft");
  78. const LPCTSTR g_cszValVersion = _T("6.0");
  79. const LPCTSTR g_cszMyCompMsc = _T("%SystemRoot%\\system32\\compmgmt.msc");
  80. const LPCTSTR g_cszServerAppsLoc = _T("System\\CurrentControlSet\\Control\\Server Applications");
  81. const LPCTSTR g_cszInetMGRBasePath = _T("Software\\Microsoft\\InetMGR");
  82. const LPCTSTR g_cszInetSTPBasePath = _T("Software\\Microsoft\\InetStp");
  83. const LPCTSTR g_cszMinorVersion = _T("MinorVersion");
  84. const LPCTSTR g_cszMajorVersion = _T("MajorVersion");
  85. const LPCTSTR g_cszParameters = _T("Parameters");
  86. const LPCTSTR g_cszHelpPath = _T("HelpLocation");
  87. //const GUID cInternetRootNode = {0xa841b6c3, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  88. //const GUID cMachineNode = {0xa841b6c4, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  89. //const GUID cServiceCollectorNode = {0xa841b6c5, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  90. //const GUID cInstanceCollectorNode = {0xa841b6c6, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  91. //const GUID cInstanceNode = {0xa841b6c7, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  92. //const GUID cChildNode = {0xa841b6c8, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  93. //const GUID cFileNode = {0xa841b6c9, 0x7577, 0x11d0, { 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c}};
  94. #define lstruuidNodetypeServerApps L"{476e6449-aaff-11d0-b944-00c04fd8d5b0}"
  95. // needed for setting extension views for certain objects
  96. const LPCTSTR g_cszViewGUID = _T("{B708457E-DB61-4C55-A92F-0D4B5E9B1224}");
  97. const LPCTSTR g_cszViewDescript = _T("MMCViewExt 1.0 Object");
  98. CComModule _Module;
  99. BEGIN_OBJECT_MAP(ObjectMap)
  100. OBJECT_ENTRY(CLSID_InetMgr, CInetMgr)
  101. OBJECT_ENTRY(CLSID_InetMgrAbout, CInetMgrAbout)
  102. END_OBJECT_MAP()
  103. //
  104. // Message Map
  105. //
  106. BEGIN_MESSAGE_MAP(CInetmgrApp, CWinApp)
  107. //{{AFX_MSG_MAP(CInetmgrApp)
  108. //}}AFX_MSG_MAP
  109. //
  110. // Global help commands
  111. //
  112. ON_COMMAND(ID_HELP, CWinApp::OnHelp)
  113. ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp)
  114. END_MESSAGE_MAP()
  115. CInetmgrApp theApp;
  116. CInetmgrApp::CInetmgrApp()
  117. : CWinApp(),
  118. m_pfusionInit(NULL)
  119. {
  120. #ifdef _DEBUG
  121. afxMemDF |= checkAlwaysMemDF;
  122. AfxSetAllocHook(TrackAllocHook);
  123. #endif // _DEBUG
  124. }
  125. BOOL
  126. CInetmgrApp::InitInstance()
  127. {
  128. #ifdef _MERGE_PROXYSTUB
  129. hProxyDll = m_hInstance;
  130. #endif
  131. ::AfxEnableControlContainer();
  132. //InitErrorFunctionality();
  133. _Module.Init(ObjectMap, m_hInstance);
  134. //
  135. // Save a pointer to the old help file and app name.
  136. //
  137. m_lpOriginalHelpPath = m_pszHelpFilePath;
  138. m_lpOriginalAppName = m_pszAppName;
  139. //
  140. // Build up inetmgr help path, expanding
  141. // the help path if necessary.
  142. //
  143. CString strKey;
  144. strKey.Format(_T("%s\\%s"), g_cszInetMGRBasePath, g_cszParameters);
  145. CRegKey rk;
  146. rk.Create(HKEY_LOCAL_MACHINE, strKey);
  147. DWORD len = MAX_PATH;
  148. rk.QueryValue(m_strInetMgrHelpPath.GetBuffer(len), g_cszHelpPath, &len);
  149. m_strInetMgrHelpPath.ReleaseBuffer(-1);
  150. m_strInetMgrHelpPath += _T("\\inetmgr.hlp");
  151. TRACEEOLID("Initialized help file " << m_strInetMgrHelpPath);
  152. m_pszHelpFilePath = m_strInetMgrHelpPath;
  153. #ifdef _DEBUG
  154. afxMemDF |= checkAlwaysMemDF;
  155. #endif // _DEBUG
  156. InitCommonDll();
  157. WSADATA wsaData;
  158. BOOL WinSockInit = (::WSAStartup(MAKEWORD(1, 1), &wsaData) == 0);
  159. VERIFY(m_strInetMgrAppName.LoadString(IDS_APP_NAME));
  160. m_pszAppName = m_strInetMgrAppName;
  161. m_pfusionInit = new CAppFusionInit(m_hInstance, 2 /*SXS_MANIFEST_RESOURCE_ID*/);
  162. return CWinApp::InitInstance();
  163. }
  164. int
  165. CInetmgrApp::ExitInstance()
  166. {
  167. _Module.Term();
  168. //
  169. // Restore original help file path and app name, so
  170. // MFC can safely delete them.
  171. //
  172. ASSERT_PTR(m_lpOriginalHelpPath);
  173. m_pszHelpFilePath = m_lpOriginalHelpPath;
  174. ASSERT_PTR(m_lpOriginalAppName);
  175. m_pszAppName = m_lpOriginalAppName;
  176. if (m_pfusionInit)
  177. delete m_pfusionInit;
  178. return CWinApp::ExitInstance();
  179. }
  180. STDAPI
  181. DllCanUnloadNow()
  182. /*++
  183. Routine Description:
  184. Used to determine whether the DLL can be unloaded by OLE
  185. Arguments:
  186. None
  187. Return Value:
  188. HRESULT
  189. --*/
  190. {
  191. #ifdef _MERGE_PROXYSTUB
  192. if (PrxDllCanUnloadNow() != S_OK)
  193. {
  194. return S_FALSE;
  195. }
  196. #endif
  197. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  198. return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ? S_OK : S_FALSE;
  199. }
  200. STDAPI
  201. DllGetClassObject(
  202. IN REFCLSID rclsid,
  203. IN REFIID riid,
  204. IN LPVOID * ppv
  205. )
  206. /*++
  207. Routine Description:
  208. Returns a class factory to create an object of the requested type
  209. Arguments:
  210. REFCLSID rclsid
  211. REFIID riid
  212. LPVOID * ppv
  213. Return Value:
  214. HRESULT
  215. --*/
  216. {
  217. #ifdef _MERGE_PROXYSTUB
  218. if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
  219. {
  220. return S_OK;
  221. }
  222. #endif
  223. return _Module.GetClassObject(rclsid, riid, ppv);
  224. }
  225. STDAPI
  226. DllRegisterServer()
  227. /*++
  228. Routine Description:
  229. DllRegisterServer - Adds entries to the system registry
  230. Arguments:
  231. None.
  232. Return Value:
  233. HRESULT
  234. --*/
  235. {
  236. #ifdef _MERGE_PROXYSTUB
  237. HRESULT hRes = PrxDllRegisterServer();
  238. if (FAILED(hRes))
  239. {
  240. return hRes;
  241. }
  242. #endif
  243. CError err(_Module.RegisterServer(TRUE));
  244. if (err.Succeeded())
  245. {
  246. CString str, strKey, strExtKey;
  247. try
  248. {
  249. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  250. //
  251. // Create the primary snapin nodes
  252. //
  253. CString strNameString((LPCTSTR)IDS_ROOT_NODE);
  254. CString strNameStringInd;
  255. TCHAR path[MAX_PATH];
  256. GetModuleFileName(_Module.GetResourceInstance(), path, MAX_PATH - 1);
  257. strNameStringInd.Format(_T("@%s,-%d"), path, IDS_ROOT_NODE);
  258. TRACEEOLID("MUI-lized snapin name: " << strNameStringInd);
  259. CString strProvider(g_cszValProvider);
  260. CString strVersion(g_cszValVersion);
  261. strKey.Format(_T("%s\\%s\\%s"),
  262. g_cszMMCBasePath,
  263. g_cszSnapins,
  264. GUIDToCString(CLSID_InetMgr, str)
  265. );
  266. TRACEEOLID(strKey);
  267. CString strAbout;
  268. GUIDToCString(CLSID_InetMgrAbout, strAbout);
  269. CRegKey rkSnapins, rkStandAlone, rkNodeTypes;
  270. rkSnapins.Create(HKEY_LOCAL_MACHINE, strKey);
  271. if (NULL != (HKEY)rkSnapins)
  272. {
  273. rkSnapins.SetValue(strAbout, g_cszAbout);
  274. rkSnapins.SetValue(strNameString, g_cszNameString);
  275. rkSnapins.SetValue(strNameStringInd, g_cszNameStringInd);
  276. rkSnapins.SetValue(strProvider, g_cszProvider);
  277. rkSnapins.SetValue(strVersion, g_cszVersion);
  278. }
  279. rkStandAlone.Create(rkSnapins, g_cszStandAlone);
  280. rkNodeTypes.Create(rkSnapins, g_cszNodeTypes);
  281. //
  282. // Create the nodetype GUIDS
  283. //
  284. CRegKey rkN1;
  285. rkN1.Create(rkNodeTypes, GUIDToCString(cInternetRootNode, str));
  286. rkN1.Create(rkNodeTypes, GUIDToCString(cMachineNode, str));
  287. rkN1.Create(rkNodeTypes, GUIDToCString(cInstanceNode, str));
  288. rkN1.Create(rkNodeTypes, GUIDToCString(cChildNode, str));
  289. rkN1.Create(rkNodeTypes, GUIDToCString(cFileNode, str));
  290. rkN1.Create(rkNodeTypes, GUIDToCString(cServiceCollectorNode, str));
  291. rkN1.Create(rkNodeTypes, GUIDToCString(cAppPoolsNode, str));
  292. rkN1.Create(rkNodeTypes, GUIDToCString(cAppPoolNode, str));
  293. rkN1.Create(rkNodeTypes, GUIDToCString(cWebServiceExtensionContainer, str));
  294. rkN1.Create(rkNodeTypes, GUIDToCString(cWebServiceExtension, str));
  295. {
  296. //
  297. // Register certain objects to use the
  298. // Extension view
  299. //
  300. strExtKey.Format(
  301. _T("%s\\%s\\%s\\%s"),
  302. g_cszMMCBasePath,
  303. g_cszNodeTypes,
  304. GUIDToCString(cWebServiceExtensionContainer, str),
  305. g_cszExtensionsView
  306. );
  307. TRACEEOLID(strExtKey);
  308. CRegKey rkMMCNodeTypes0;
  309. rkMMCNodeTypes0.Create(HKEY_LOCAL_MACHINE, strExtKey);
  310. if (NULL != (HKEY)rkMMCNodeTypes0)
  311. {
  312. rkMMCNodeTypes0.SetValue(
  313. g_cszViewDescript,
  314. g_cszViewGUID
  315. );
  316. }
  317. }
  318. {
  319. //
  320. // Register as a dynamic extension to computer management
  321. //
  322. strExtKey.Format(
  323. _T("%s\\%s\\%s\\%s"),
  324. g_cszMMCBasePath,
  325. g_cszNodeTypes,
  326. lstruuidNodetypeServerApps,
  327. g_cszDynamicExt
  328. );
  329. TRACEEOLID(strExtKey);
  330. CRegKey rkMMCNodeTypes;
  331. rkMMCNodeTypes.Create(HKEY_LOCAL_MACHINE, strExtKey);
  332. if (NULL != (HKEY)rkMMCNodeTypes)
  333. {
  334. rkMMCNodeTypes.SetValue(
  335. strNameString,
  336. GUIDToCString(CLSID_InetMgr, str)
  337. );
  338. }
  339. }
  340. {
  341. //
  342. // Register as a namespace extension to computer management
  343. //
  344. strExtKey.Format(
  345. _T("%s\\%s\\%s\\%s\\%s"),
  346. g_cszMMCBasePath,
  347. g_cszNodeTypes,
  348. lstruuidNodetypeServerApps,
  349. g_cszExtensions,
  350. g_cszNameSpace
  351. );
  352. TRACEEOLID(strExtKey);
  353. CRegKey rkMMCNodeTypes;
  354. rkMMCNodeTypes.Create(HKEY_LOCAL_MACHINE, strExtKey);
  355. if (NULL != (HKEY)rkMMCNodeTypes)
  356. {
  357. rkMMCNodeTypes.SetValue(
  358. strNameString,
  359. GUIDToCString(CLSID_InetMgr, str)
  360. );
  361. }
  362. }
  363. //
  364. // This key indicates that the service in question is available
  365. // on the local machine
  366. //
  367. CRegKey rkCompMgmt;
  368. rkCompMgmt.Create(HKEY_LOCAL_MACHINE, g_cszServerAppsLoc);
  369. if (NULL != (HKEY)rkCompMgmt)
  370. {
  371. rkCompMgmt.SetValue(strNameString, GUIDToCString(CLSID_InetMgr, str));
  372. }
  373. }
  374. catch(CMemoryException * e)
  375. {
  376. e->Delete();
  377. err = ERROR_NOT_ENOUGH_MEMORY;
  378. }
  379. catch(COleException * e)
  380. {
  381. e->Delete();
  382. err = SELFREG_E_CLASS;
  383. }
  384. }
  385. return err;
  386. }
  387. STDAPI
  388. DllUnregisterServer()
  389. /*++
  390. Routine Description:
  391. DllUnregisterServer - Removes entries from the system registry
  392. Arguments:
  393. None.
  394. Return Value:
  395. HRESULT
  396. --*/
  397. {
  398. #ifdef _MERGE_PROXYSTUB
  399. PrxDllUnregisterServer();
  400. #endif
  401. CError err;
  402. try
  403. {
  404. CString strKey(g_cszMMCBasePath);
  405. strKey += _T("\\");
  406. strKey += g_cszSnapins;
  407. TRACEEOLID(strKey);
  408. CString str, strExtKey;
  409. CRegKey rkBase;
  410. rkBase.Create(HKEY_LOCAL_MACHINE, strKey);
  411. ASSERT(NULL != (HKEY)rkBase);
  412. if (NULL != (HKEY)rkBase)
  413. {
  414. CRegKey rkCLSID;
  415. rkCLSID.Create(rkBase, GUIDToCString(CLSID_InetMgr, str));
  416. ASSERT(NULL != (HKEY)rkCLSID);
  417. if (NULL != (HKEY)rkCLSID)
  418. {
  419. ::RegDeleteKey(rkCLSID, g_cszStandAlone);
  420. {
  421. CRegKey rkNodeTypes;
  422. rkNodeTypes.Create(rkCLSID, g_cszNodeTypes);
  423. ASSERT(NULL != (HKEY)rkNodeTypes);
  424. if (NULL != (HKEY)rkNodeTypes)
  425. {
  426. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cInternetRootNode, str));
  427. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cMachineNode, str));
  428. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cInstanceNode, str));
  429. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cChildNode, str));
  430. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cFileNode, str));
  431. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cServiceCollectorNode, str));
  432. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cAppPoolsNode, str));
  433. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cAppPoolNode, str));
  434. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cWebServiceExtensionContainer, str));
  435. ::RegDeleteKey(rkNodeTypes, GUIDToCString(cWebServiceExtension, str));
  436. }
  437. }
  438. ::RegDeleteKey(rkCLSID, g_cszNodeTypes);
  439. }
  440. ::RegDeleteKey(rkBase, GUIDToCString(CLSID_InetMgr, str));
  441. }
  442. {
  443. //
  444. // Delete a dynamic extension to computer management
  445. //
  446. strExtKey.Format(
  447. _T("%s\\%s\\%s\\%s"),
  448. g_cszMMCBasePath,
  449. g_cszNodeTypes,
  450. lstruuidNodetypeServerApps,
  451. g_cszDynamicExt
  452. );
  453. CRegKey rkMMCNodeTypes;
  454. rkMMCNodeTypes.Create(HKEY_LOCAL_MACHINE, strExtKey);
  455. if (NULL != (HKEY)rkMMCNodeTypes)
  456. {
  457. ::RegDeleteValue(rkMMCNodeTypes, GUIDToCString(CLSID_InetMgr, str));
  458. }
  459. }
  460. {
  461. //
  462. // Delete the namespace extension to computer management
  463. //
  464. strExtKey.Format(
  465. _T("%s\\%s\\%s\\%s\\%s"),
  466. g_cszMMCBasePath,
  467. g_cszNodeTypes,
  468. lstruuidNodetypeServerApps,
  469. g_cszExtensions,
  470. g_cszNameSpace
  471. );
  472. CRegKey rkMMCNodeTypes;
  473. rkMMCNodeTypes.Create(HKEY_LOCAL_MACHINE, strExtKey);
  474. if (NULL != (HKEY)rkMMCNodeTypes)
  475. {
  476. ::RegDeleteValue(rkMMCNodeTypes, GUIDToCString(CLSID_InetMgr, str));
  477. }
  478. }
  479. {
  480. //
  481. // Delete Extension view for certain objects
  482. //
  483. //
  484. strExtKey.Format(_T("%s\\%s"),g_cszMMCBasePath,g_cszNodeTypes);
  485. CRegKey rkMMCNodeTypes0;
  486. rkMMCNodeTypes0.Create(HKEY_LOCAL_MACHINE, strExtKey);
  487. if (NULL != (HKEY)rkMMCNodeTypes0)
  488. {
  489. CRegKey rkMMCNodeTypes1;
  490. rkMMCNodeTypes1.Create(rkMMCNodeTypes0, GUIDToCString(cWebServiceExtensionContainer, str));
  491. if (NULL != (HKEY)rkMMCNodeTypes1)
  492. {
  493. CRegKey rkMMCNodeTypes2;
  494. rkMMCNodeTypes2.Create(rkMMCNodeTypes1, g_cszExtensionsView);
  495. if (NULL != (HKEY)rkMMCNodeTypes2)
  496. {
  497. ::RegDeleteValue(rkMMCNodeTypes2,g_cszViewGUID);
  498. }
  499. ::RegDeleteKey(rkMMCNodeTypes1, g_cszExtensionsView);
  500. ::RegDeleteKey(rkMMCNodeTypes1, g_cszExtensions);
  501. }
  502. ::RegDeleteKey(rkMMCNodeTypes0, GUIDToCString(cWebServiceExtensionContainer, str));
  503. }
  504. }
  505. //
  506. // And the service itself no longer available on the local
  507. // computer
  508. //
  509. CRegKey rkCompMgmt;
  510. rkCompMgmt.Create(HKEY_LOCAL_MACHINE, g_cszServerAppsLoc);
  511. if (NULL != (HKEY)rkCompMgmt)
  512. {
  513. ::RegDeleteValue(rkCompMgmt, GUIDToCString(CLSID_InetMgr, str));
  514. }
  515. }
  516. catch(CException * e)
  517. {
  518. err.GetLastWinError();
  519. e->Delete();
  520. }
  521. if (err.Failed())
  522. {
  523. return err.Failed();
  524. }
  525. return _Module.UnregisterServer();
  526. }
  527. HRESULT CInetMgrAbout::GetSnapinVersion(LPOLESTR * lpVersion)
  528. {
  529. CRegKey rk;
  530. rk.Create(HKEY_LOCAL_MACHINE, g_cszInetSTPBasePath);
  531. DWORD minor, major;
  532. if ( ERROR_SUCCESS == rk.QueryValue(minor, g_cszMinorVersion)
  533. && ERROR_SUCCESS == rk.QueryValue(major, g_cszMajorVersion)
  534. )
  535. {
  536. CString buf;
  537. buf.Format(_T("%d.%d"), major, minor);
  538. *lpVersion = (LPOLESTR)::CoTaskMemAlloc((buf.GetLength() + 1) * sizeof(OLECHAR));
  539. if (*lpVersion == NULL)
  540. {
  541. return E_OUTOFMEMORY;
  542. }
  543. ::ocscpy(*lpVersion, T2OLE((LPTSTR)(LPCTSTR)buf));
  544. return S_OK;
  545. }
  546. return E_FAIL;
  547. }