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.

721 lines
20 KiB

  1. /****************************************************************************
  2. *
  3. * icfg32.cpp
  4. *
  5. * Microsoft Confidential
  6. * Copyright (c) 1992-1999 Microsoft Corporation
  7. * All rights reserved
  8. *
  9. * This module provides the implementation of the methods for
  10. * the NT specific functionality of inetcfg
  11. *
  12. * 6/5/97 ChrisK Inherited from AmnonH
  13. * 7/3/97 ShaunCo Modfied for NT5
  14. *
  15. ***************************************************************************/
  16. #define UNICODE
  17. #define _UNICODE
  18. #include <wtypes.h>
  19. #include <cfgapi.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <tchar.h>
  24. #include <setupapi.h>
  25. #include <basetyps.h>
  26. #include <devguid.h>
  27. #include <lmsname.h>
  28. #include "debug.h"
  29. #include <netcfgx.h>
  30. const LPTSTR gc_szIsdnSigature = TEXT("\\NET\\");
  31. #define REG_DATA_EXTRA_SPACE 255
  32. #define DEVICE_INSTANCE_SIZE 128
  33. extern DWORD g_dwLastError;
  34. typedef BOOL (WINAPI *PFNINSTALLNEWDEVICE) (HWND hwndParent,
  35. LPGUID ClassGuid,
  36. PDWORD pReboot);
  37. /*++
  38. Routine Description:
  39. Exported Entry point from newdev.cpl. Installs a new device. A new Devnode is
  40. created and the user is prompted to select the device. If the class guid
  41. is not specified then then the user begins at class selection.
  42. Arguments:
  43. hwndParent - Window handle of the top-level window to use for any UI related
  44. to installing the device.
  45. LPGUID ClassGuid - Optional class of the new device to install.
  46. If ClassGuid is NULL we start at detection choice page.
  47. If ClassGuid == GUID_NULL or GUID_DEVCLASS_UNKNOWN
  48. we start at class selection page.
  49. pReboot - Optional address of variable to receive reboot flags (DI_NEEDRESTART,DI_NEEDREBOOT)
  50. Return Value:
  51. BOOL TRUE for success (does not mean device was installed or updated),
  52. FALSE unexpected error. GetLastError returns the winerror code.
  53. */
  54. // For the code that was copied from netcfg, make the TraceError stuff
  55. // go away. Likewise for existing debug statements.
  56. //
  57. #define TraceError
  58. #define Dprintf
  59. ULONG
  60. ReleaseObj (
  61. IUnknown* punk)
  62. {
  63. return (punk) ? punk->Release () : 0;
  64. }
  65. //+---------------------------------------------------------------------------
  66. //
  67. // Function: HrCreateAndInitializeINetCfg
  68. //
  69. // Purpose: Cocreate and initialize the root INetCfg object. This will
  70. // optionally initialize COM for the caller too.
  71. //
  72. // Arguments:
  73. // pfInitCom [in,out] TRUE to call CoInitialize before creating.
  74. // returns TRUE if COM was successfully
  75. // initialized FALSE if not. If NULL, means
  76. // don't initialize COM.
  77. // ppnc [out] The returned INetCfg object.
  78. // fGetWriteLock [in] TRUE if a writable INetCfg is needed
  79. // cmsTimeout [in] See INetCfg::AcquireWriteLock
  80. // szwClientDesc [in] See INetCfg::AcquireWriteLock
  81. // pbstrClientDesc [in] See INetCfg::AcquireWriteLock
  82. //
  83. // Returns: S_OK or an error code.
  84. //
  85. // Author: shaunco 7 May 1997
  86. //
  87. // Notes:
  88. //
  89. HRESULT
  90. HrCreateAndInitializeINetCfg (
  91. BOOL* pfInitCom,
  92. INetCfg** ppnc,
  93. BOOL fGetWriteLock,
  94. DWORD cmsTimeout,
  95. LPCWSTR szwClientDesc,
  96. BSTR* pbstrClientDesc)
  97. {
  98. Assert (ppnc);
  99. // Initialize the output parameter.
  100. *ppnc = NULL;
  101. // Initialize COM if the caller requested.
  102. HRESULT hr = S_OK;
  103. if (pfInitCom && *pfInitCom)
  104. {
  105. hr = CoInitializeEx( NULL,
  106. COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
  107. if (RPC_E_CHANGED_MODE == hr)
  108. {
  109. hr = S_OK;
  110. if (pfInitCom)
  111. {
  112. *pfInitCom = FALSE;
  113. }
  114. }
  115. }
  116. if (SUCCEEDED(hr))
  117. {
  118. // Create the object implementing INetCfg.
  119. //
  120. INetCfg* pnc;
  121. hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER,
  122. IID_INetCfg, reinterpret_cast<void**>(&pnc));
  123. if (SUCCEEDED(hr))
  124. {
  125. INetCfgLock * pnclock = NULL;
  126. if (fGetWriteLock)
  127. {
  128. // Get the locking interface
  129. hr = pnc->QueryInterface(IID_INetCfgLock,
  130. reinterpret_cast<LPVOID *>(&pnclock));
  131. if (SUCCEEDED(hr))
  132. {
  133. // Attempt to lock the INetCfg for read/write
  134. hr = pnclock->AcquireWriteLock(cmsTimeout, szwClientDesc,
  135. pbstrClientDesc);
  136. if (S_FALSE == hr)
  137. {
  138. // Couldn't acquire the lock
  139. hr = NETCFG_E_NO_WRITE_LOCK;
  140. }
  141. }
  142. }
  143. if (SUCCEEDED(hr))
  144. {
  145. // Initialize the INetCfg object.
  146. //
  147. hr = pnc->Initialize (NULL);
  148. if (SUCCEEDED(hr))
  149. {
  150. *ppnc = pnc;
  151. pnc->AddRef ();
  152. }
  153. else
  154. {
  155. if (pnclock)
  156. {
  157. pnclock->ReleaseWriteLock();
  158. }
  159. }
  160. // Transfer reference to caller.
  161. }
  162. ReleaseObj(pnclock);
  163. ReleaseObj(pnc);
  164. }
  165. // If we failed anything above, and we've initialized COM,
  166. // be sure an uninitialize it.
  167. //
  168. if (FAILED(hr) && pfInitCom && *pfInitCom)
  169. {
  170. CoUninitialize ();
  171. }
  172. }
  173. TraceError("HrCreateAndInitializeINetCfg", hr);
  174. return hr;
  175. }
  176. //+---------------------------------------------------------------------------
  177. //
  178. // Function: HrUninitializeAndUnlockINetCfg
  179. //
  180. // Purpose: Uninitializes and unlocks the INetCfg object
  181. //
  182. // Arguments:
  183. // pnc [in] INetCfg to uninitialize and unlock
  184. //
  185. // Returns: S_OK if success, OLE or Win32 error otherwise
  186. //
  187. // Author: danielwe 13 Nov 1997
  188. //
  189. // Notes:
  190. //
  191. HRESULT
  192. HrUninitializeAndUnlockINetCfg (
  193. INetCfg* pnc)
  194. {
  195. HRESULT hr = S_OK;
  196. hr = pnc->Uninitialize();
  197. if (SUCCEEDED(hr))
  198. {
  199. INetCfgLock * pnclock;
  200. // Get the locking interface
  201. hr = pnc->QueryInterface(IID_INetCfgLock,
  202. reinterpret_cast<LPVOID *>(&pnclock));
  203. if (SUCCEEDED(hr))
  204. {
  205. // Attempt to lock the INetCfg for read/write
  206. hr = pnclock->ReleaseWriteLock();
  207. ReleaseObj(pnclock);
  208. }
  209. }
  210. TraceError("HrUninitializeAndUnlockINetCfg", hr);
  211. return hr;
  212. }
  213. //+---------------------------------------------------------------------------
  214. //
  215. // Function: HrUninitializeAndReleaseINetCfg
  216. //
  217. // Purpose: Unintialize and release an INetCfg object. This will
  218. // optionally uninitialize COM for the caller too.
  219. //
  220. // Arguments:
  221. // fUninitCom [in] TRUE to uninitialize COM after the INetCfg is
  222. // uninitialized and released.
  223. // pnc [in] The INetCfg object.
  224. // fHasLock [in] TRUE if the INetCfg was locked for write and
  225. // must be unlocked.
  226. //
  227. // Returns: S_OK or an error code.
  228. //
  229. // Author: shaunco 7 May 1997
  230. //
  231. // Notes: The return value is the value returned from
  232. // INetCfg::Uninitialize. Even if this fails, the INetCfg
  233. // is still released. Therefore, the return value is for
  234. // informational purposes only. You can't touch the INetCfg
  235. // object after this call returns.
  236. //
  237. HRESULT
  238. HrUninitializeAndReleaseINetCfg (
  239. BOOL fUninitCom,
  240. INetCfg* pnc,
  241. BOOL fHasLock)
  242. {
  243. Assert (pnc);
  244. HRESULT hr = S_OK;
  245. if (fHasLock)
  246. {
  247. hr = HrUninitializeAndUnlockINetCfg(pnc);
  248. }
  249. else
  250. {
  251. hr = pnc->Uninitialize ();
  252. }
  253. ReleaseObj (pnc);
  254. if (fUninitCom)
  255. {
  256. CoUninitialize ();
  257. }
  258. TraceError("HrUninitializeAndReleaseINetCfg", hr);
  259. return hr;
  260. }
  261. //+---------------------------------------------------------------------------
  262. //
  263. // Function: HrInstallComponent
  264. //
  265. // Purpose: Install the component with a specified id.
  266. //
  267. // Arguments:
  268. // pnc [in] INetCfg pointer.
  269. // pguidClass [in] Class guid of the component to install.
  270. // pszwComponentId [in] Component id to install.
  271. // ppncc [out] (Optional) Returned component that was
  272. // installed.
  273. //
  274. // Returns: S_OK or an error code.
  275. //
  276. // Author: shaunco 4 Jan 1998
  277. //
  278. // Notes: nickball 7 May 1999 - Removed unused pszwOboToken parameter
  279. //
  280. HRESULT
  281. HrInstallComponent (
  282. INetCfg* pnc,
  283. const GUID* pguidClass,
  284. LPCWSTR pszwComponentId,
  285. INetCfgComponent** ppncc)
  286. {
  287. OBO_TOKEN oboToken;
  288. Assert (pnc);
  289. Assert (pszwComponentId);
  290. // Initialize output parameter.
  291. //
  292. if (ppncc)
  293. {
  294. *ppncc = NULL;
  295. }
  296. // Get the class setup object.
  297. //
  298. INetCfgClassSetup* pncclasssetup;
  299. ZeroMemory((PVOID)&oboToken, sizeof(oboToken));
  300. oboToken.Type = OBO_USER;
  301. //NT #330252
  302. //oboToken.pncc = *ppncc;
  303. //oboToken. fRegistered = TRUE;
  304. HRESULT hr = pnc->QueryNetCfgClass (pguidClass, IID_INetCfgClassSetup,
  305. reinterpret_cast<void**>(&pncclasssetup));
  306. if (SUCCEEDED(hr))
  307. {
  308. hr = pncclasssetup->Install (pszwComponentId,
  309. &oboToken, 0, 0, NULL, NULL, ppncc);
  310. ReleaseObj (pncclasssetup);
  311. }
  312. TraceError("HrInstallComponent", hr);
  313. return hr;
  314. }
  315. //+----------------------------------------------------------------------------
  316. //
  317. // Function: CallModemInstallWizard
  318. //
  319. // Synopsis: Invoke modem install wizard via SetupDi interfaces
  320. //
  321. // Arguments: hwnd - handle to parent window
  322. //
  323. // Returns: TRUE - success, FALSE - failed
  324. //
  325. // History: 6/5/97 ChrisK Inherited
  326. //
  327. //-----------------------------------------------------------------------------
  328. //
  329. // The following code was stolen from RAS
  330. //
  331. BOOL
  332. CallModemInstallWizardNT5(HWND hwnd)
  333. {
  334. BOOL fReturn = FALSE;
  335. PFNINSTALLNEWDEVICE pfn;
  336. HINSTANCE hInst;
  337. Dprintf("ICFGNT: CallModemInstallWizard\n");
  338. //
  339. // Load newdev.dll can call the InstallNewDevice method with Modem device class
  340. //
  341. hInst = LoadLibrary((LPCTSTR) L"newdev.dll");
  342. if (NULL == hInst)
  343. {
  344. goto CleanupAndExit;
  345. }
  346. pfn = (PFNINSTALLNEWDEVICE) GetProcAddress(hInst, (LPCSTR)"InstallNewDevice");
  347. if (NULL == pfn)
  348. {
  349. goto CleanupAndExit;
  350. }
  351. //
  352. // Call the function - on NT5 modem installation should not require
  353. // reboot; so that last parameter, which is used to return if restart/reboot
  354. // is required can be NULL
  355. //
  356. fReturn = pfn(hwnd, (LPGUID) &GUID_DEVCLASS_MODEM, NULL);
  357. CleanupAndExit:
  358. if (NULL != hInst)
  359. {
  360. FreeLibrary(hInst);
  361. }
  362. return fReturn;
  363. }
  364. //+----------------------------------------------------------------------------
  365. //
  366. // Function: IcfgNeedModem
  367. //
  368. // Synopsis: Check system configuration to determine if there is at least
  369. // one physical modem installed
  370. //
  371. // Arguments: dwfOptions - currently not used
  372. //
  373. // Returns: HRESULT - S_OK if successfull
  374. // lpfNeedModem - TRUE if no modems are available
  375. //
  376. // History: 6/5/97 ChrisK Inherited
  377. //
  378. //-----------------------------------------------------------------------------
  379. HRESULT WINAPI
  380. IcfgNeedModemNT5(DWORD dwfOptions, LPBOOL lpfNeedModem)
  381. {
  382. //
  383. // Ras is installed, and ICW wants to know if it needs to
  384. // install a modem.
  385. //
  386. *lpfNeedModem = TRUE;
  387. // Get the device info set for modems.
  388. //
  389. HDEVINFO hdevinfo = SetupDiGetClassDevs((GUID*)&GUID_DEVCLASS_MODEM,
  390. NULL,
  391. NULL,
  392. DIGCF_PRESENT);
  393. if (hdevinfo)
  394. {
  395. SP_DEVINFO_DATA diData;
  396. diData.cbSize = sizeof(diData);
  397. // Look for at least one modem.
  398. //
  399. if (SetupDiEnumDeviceInfo(hdevinfo, 0, &diData))
  400. {
  401. *lpfNeedModem = FALSE;
  402. }
  403. SetupDiDestroyDeviceInfoList (hdevinfo);
  404. }
  405. if (*lpfNeedModem)
  406. {
  407. //
  408. // check for ISDN adaptors
  409. //
  410. // Get the device info set for modems.
  411. //
  412. hdevinfo = SetupDiGetClassDevs((GUID*)&GUID_DEVCLASS_NET,
  413. NULL,
  414. NULL,
  415. DIGCF_PRESENT);
  416. if (hdevinfo)
  417. {
  418. TCHAR szDevInstanceId[DEVICE_INSTANCE_SIZE];
  419. DWORD dwIndex = 0;
  420. DWORD dwRequiredSize;
  421. SP_DEVINFO_DATA diData;
  422. diData.cbSize = sizeof(diData);
  423. //
  424. // look for an ISDN device
  425. //
  426. while (SetupDiEnumDeviceInfo(hdevinfo, dwIndex, &diData))
  427. {
  428. if (SetupDiGetDeviceInstanceId(hdevinfo,
  429. &diData,
  430. szDevInstanceId,
  431. sizeof(szDevInstanceId) / sizeof(szDevInstanceId[0]),
  432. &dwRequiredSize))
  433. {
  434. HKEY hReg, hInterface;
  435. TCHAR szLowerRange[MAX_PATH + 1];
  436. DWORD cb = sizeof(szLowerRange);
  437. hReg = SetupDiOpenDevRegKey(hdevinfo, &diData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
  438. if (hReg != INVALID_HANDLE_VALUE)
  439. {
  440. if (RegOpenKey(hReg, TEXT("Ndi\\Interfaces"), &hInterface) == ERROR_SUCCESS)
  441. {
  442. if (RegQueryValueEx(hInterface, TEXT("LowerRange"), 0, NULL, (PBYTE) szLowerRange, &cb) == ERROR_SUCCESS)
  443. {
  444. if (lstrcmpi(szLowerRange, TEXT("isdn")) == 0)
  445. {
  446. *lpfNeedModem = FALSE;
  447. break;
  448. }
  449. }
  450. RegCloseKey(hInterface);
  451. }
  452. RegCloseKey(hReg);
  453. }
  454. //
  455. // ISDN adaptors are in the form XXX\NET\XXX
  456. //
  457. if (_tcsstr(szDevInstanceId, gc_szIsdnSigature))
  458. {
  459. *lpfNeedModem = FALSE;
  460. break;
  461. }
  462. }
  463. dwIndex++;
  464. }
  465. SetupDiDestroyDeviceInfoList (hdevinfo);
  466. }
  467. }
  468. return(ERROR_SUCCESS);
  469. }
  470. //+----------------------------------------------------------------------------
  471. //
  472. // Function: IcfgInstallModem
  473. //
  474. // Synopsis:
  475. // This function is called when ICW verified that RAS is installed,
  476. // but no modems are avilable. It needs to make sure a modem is availble.
  477. // There are two possible scenarios:
  478. //
  479. // a. There are no modems installed. This happens when someone deleted
  480. // a modem after installing RAS. In this case we need to run the modem
  481. // install wizard, and configure the newly installed modem to be a RAS
  482. // dialout device.
  483. //
  484. // b. There are modems installed, but non of them is configured as a dial out
  485. // device. In this case, we silently convert them to be DialInOut devices,
  486. // so ICW can use them.
  487. //
  488. // Arguments: hwndParent - handle to parent window
  489. // dwfOptions - not used
  490. //
  491. // Returns: lpfNeedsStart - not used
  492. //
  493. // History: 6/5/97 ChrisK Inherited
  494. //
  495. //-----------------------------------------------------------------------------
  496. HRESULT WINAPI
  497. IcfgInstallModemNT5(HWND hwndParent, DWORD dwfOptions, LPBOOL lpfNeedsStart)
  498. {
  499. //
  500. // Fire up the modem install wizard
  501. //
  502. if (!CallModemInstallWizardNT5(hwndParent))
  503. {
  504. return(g_dwLastError = GetLastError());
  505. }
  506. return(ERROR_SUCCESS);
  507. }
  508. //+----------------------------------------------------------------------------
  509. //
  510. // Function: IcfgNeedInetComponets
  511. //
  512. // Synopsis: Check to see if the components marked in the options are
  513. // installed on the system
  514. //
  515. // Arguements: dwfOptions - set of bit flag indicating which components to
  516. // check for
  517. //
  518. // Returns; HRESULT - S_OK if successfull
  519. // lpfNeedComponents - TRUE is some components are not installed
  520. //
  521. // History: 6/5/97 ChrisK Inherited
  522. //
  523. //-----------------------------------------------------------------------------
  524. HRESULT WINAPI
  525. IcfgNeedInetComponentsNT5(DWORD dwfOptions, LPBOOL lpfNeedComponents)
  526. {
  527. Dprintf("ICFGNT: IcfgNeedInetComponents\n");
  528. //
  529. // Assume we have what we need.
  530. //
  531. *lpfNeedComponents = FALSE;
  532. HRESULT hr = S_OK;
  533. INetCfg* pnc = NULL;
  534. BOOL fInitCom = TRUE;
  535. // If the optiona are such that we need an INetCfg interface pointer,
  536. // get one.
  537. //
  538. if ((dwfOptions & ICFG_INSTALLTCP) ||
  539. (dwfOptions & ICFG_INSTALLRAS))
  540. {
  541. hr = HrCreateAndInitializeINetCfg (&fInitCom, &pnc,
  542. FALSE, 0, NULL, NULL);
  543. }
  544. // Look for TCP/IP using the INetCfg interface.
  545. //
  546. if (SUCCEEDED(hr) && (dwfOptions & ICFG_INSTALLTCP))
  547. {
  548. Assert (pnc);
  549. hr = pnc->FindComponent (NETCFG_TRANS_CID_MS_TCPIP, NULL);
  550. if (S_FALSE == hr)
  551. {
  552. *lpfNeedComponents = TRUE;
  553. }
  554. }
  555. // We no longer need the INetCfg interface pointer, so release it.
  556. //
  557. if (pnc)
  558. {
  559. (void) HrUninitializeAndReleaseINetCfg (fInitCom, pnc, FALSE);
  560. }
  561. // Normalize the HRESULT.
  562. if (SUCCEEDED(hr))
  563. {
  564. hr = S_OK;
  565. }
  566. return hr;
  567. }
  568. //+----------------------------------------------------------------------------
  569. //
  570. // Function: IcfgInstallInetComponentsNT5
  571. //
  572. // Synopsis: Install the components as specified by the dwfOptions values
  573. //
  574. // Arguments hwndParent - handle to parent window
  575. // dwfOptions - set of bit flags indicating which components to
  576. // install
  577. //
  578. // Returns: HRESULT - S_OK if success
  579. // lpfNeedsReboot - TRUE if reboot is required
  580. //
  581. // History: 6/5/97 ChrisK Inherited
  582. //
  583. //-----------------------------------------------------------------------------
  584. HRESULT WINAPI
  585. IcfgInstallInetComponentsNT5(HWND hwndParent, DWORD dwfOptions, LPBOOL lpfNeedsRestart)
  586. {
  587. Dprintf("ICFGNT: IcfgInstallInetComponents\n");
  588. //
  589. // Assume don't need restart
  590. //
  591. *lpfNeedsRestart = FALSE;
  592. HRESULT hr = S_OK;
  593. INetCfg* pnc = NULL;
  594. BOOL fInitCom = TRUE;
  595. // If the optiona are such that we need an INetCfg interface pointer,
  596. // get one.
  597. //
  598. if ((dwfOptions & ICFG_INSTALLTCP) ||
  599. (dwfOptions & ICFG_INSTALLRAS))
  600. {
  601. BSTR bstrClient;
  602. hr = HrCreateAndInitializeINetCfg (&fInitCom, &pnc, TRUE,
  603. 0, L"", &bstrClient);
  604. }
  605. // Install TCP/IP on behalf of the user.
  606. //
  607. if (SUCCEEDED(hr) && (dwfOptions & ICFG_INSTALLTCP))
  608. {
  609. hr = HrInstallComponent (pnc, &GUID_DEVCLASS_NETTRANS,
  610. NETCFG_TRANS_CID_MS_TCPIP, NULL);
  611. }
  612. // We no longer need the INetCfg interface pointer, so release it.
  613. //
  614. if (pnc)
  615. {
  616. // Apply the changes if everything was successful.
  617. //
  618. if (SUCCEEDED(hr))
  619. {
  620. hr = pnc->Apply();
  621. if (NETCFG_S_REBOOT == hr)
  622. {
  623. *lpfNeedsRestart = TRUE;
  624. }
  625. }
  626. (void) HrUninitializeAndReleaseINetCfg (fInitCom, pnc, TRUE);
  627. }
  628. // Normalize the HRESULT.
  629. if (SUCCEEDED(hr))
  630. {
  631. hr = S_OK;
  632. }
  633. return(hr);
  634. }