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.

737 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N E T A F X . C P P
  7. //
  8. // Contents: Tool for applying answerfile
  9. //
  10. // Author: kumarp 10-December-97
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "pch.h"
  14. #pragma hdrstop
  15. #include "getopt.h"
  16. #include "ncstring.h"
  17. #include "kkutils.h"
  18. #include "ncnetcfg.h"
  19. #include "ncerror.h"
  20. #include "nceh.h"
  21. #include "nsexports.h"
  22. class CNetAfxOptions
  23. {
  24. public:
  25. tstring m_strAFileName;
  26. BOOL m_fVerbose;
  27. BOOL m_fShowComponents;
  28. CNetAfxOptions()
  29. {
  30. m_fVerbose = FALSE;
  31. m_fShowComponents = FALSE;
  32. }
  33. };
  34. // ----------------------------------------------------------------------
  35. // Global vars
  36. //
  37. BOOL g_fVerbose=FALSE;
  38. INetCfg* g_pINetCfg=NULL;
  39. BOOL g_fInitCom=TRUE;
  40. // ----------------------------------------------------------------------
  41. BOOL FParseCmdLine(IN int argc,
  42. IN WCHAR* argv[],
  43. OUT CNetAfxOptions* pnaOptions);
  44. void ShowUsage();
  45. HRESULT HrApplyAnswerFile(IN INetCfg* pnc,
  46. IN PCWSTR szAnswerFileName,
  47. IN BOOL fVerbose);
  48. void ShowAnswerFileErrors(IN TStringList* pslErrors);
  49. void ShowMsgIfVerbose(IN BOOL fVerbose, IN PCWSTR szMsg, ...);
  50. void ShowMsgIfGlobalVerboseV(IN PCWSTR szMsg, IN va_list arglist);
  51. void ShowMsgIfVerboseV(IN BOOL fVerbose, IN PCWSTR szMsg, IN va_list arglist);
  52. HRESULT HrGetInstalledComponentList(IN INetCfg* pnc,
  53. IN const GUID* pguidClass,
  54. OUT TStringList* pslComponents,
  55. OUT TStringList* pslDescriptions);
  56. HRESULT HrShowInstalledComponentList(IN INetCfg* pnc,
  57. IN const GUID* pguidClass);
  58. HRESULT HrDoNetAfx(IN CNetAfxOptions* pnaOptions);
  59. BOOL WINAPI NetAfxConsoleCrtlHandler(IN DWORD dwCtrlType);
  60. // ----------------------------------------------------------------------
  61. //
  62. // Function: wmain
  63. //
  64. // Purpose: The main function
  65. //
  66. // Arguments: standard main args
  67. //
  68. // Returns: 0 on success, non-zero otherwise
  69. //
  70. // Author: kumarp 25-December-97
  71. //
  72. // Notes:
  73. //
  74. EXTERN_C int __cdecl wmain(int argc, WCHAR* argv[])
  75. {
  76. tstring strAFileName;
  77. BOOL fVerbose;
  78. HRESULT hr=S_OK;
  79. CNetAfxOptions naOptions;
  80. InitializeDebugging();
  81. if (FParseCmdLine(argc, argv, &naOptions))
  82. {
  83. SetConsoleCtrlHandler(NetAfxConsoleCrtlHandler, TRUE);
  84. hr = HrDoNetAfx(&naOptions);
  85. }
  86. else
  87. {
  88. ShowUsage();
  89. }
  90. UnInitializeDebugging();
  91. return hr;
  92. }
  93. // ----------------------------------------------------------------------
  94. //
  95. // Function: HrDoNetAfx
  96. //
  97. // Purpose: Perform actions specified by pnaOptions
  98. //
  99. // Arguments:
  100. // pnaOptions [in] pointer to CNetAfxOptions object
  101. //
  102. // Returns: S_OK on success, otherwise an error code
  103. //
  104. // Author: kumarp 19-February-98
  105. //
  106. // Notes:
  107. //
  108. HRESULT HrDoNetAfx(IN CNetAfxOptions* pnaOptions)
  109. {
  110. AssertValidReadPtr(pnaOptions);
  111. DefineFunctionName("HrDoNetAfx");
  112. static const WCHAR c_szNetAfxName[] = L"netafx.exe";
  113. HRESULT hr=S_OK;
  114. PCWSTR szAnswerFileName;
  115. g_fVerbose = pnaOptions->m_fVerbose;
  116. szAnswerFileName = pnaOptions->m_strAFileName.c_str();
  117. PWSTR pszwClientDesc = NULL;
  118. const UINT c_cmsWaitForINetCfgWrite = 120000;
  119. BOOL fNeedWriteLock=FALSE;
  120. ShowMsgIfVerbose(pnaOptions->m_fVerbose, L"Trying to get INetCfg...");
  121. fNeedWriteLock = !pnaOptions->m_strAFileName.empty();
  122. hr = HrCreateAndInitializeINetCfg(&g_fInitCom, &g_pINetCfg, fNeedWriteLock,
  123. c_cmsWaitForINetCfgWrite,
  124. c_szNetAfxName,
  125. &pszwClientDesc);
  126. if (S_OK == hr)
  127. {
  128. Assert(!pszwClientDesc);
  129. ShowMsgIfVerbose(pnaOptions->m_fVerbose, L"...got it");
  130. if (pnaOptions->m_fShowComponents)
  131. {
  132. (void) HrShowInstalledComponentList(g_pINetCfg,
  133. &GUID_DEVCLASS_NET);
  134. (void) HrShowInstalledComponentList(g_pINetCfg,
  135. &GUID_DEVCLASS_NETTRANS);
  136. (void) HrShowInstalledComponentList(g_pINetCfg,
  137. &GUID_DEVCLASS_NETCLIENT);
  138. (void) HrShowInstalledComponentList(g_pINetCfg,
  139. &GUID_DEVCLASS_NETSERVICE);
  140. }
  141. if (!pnaOptions->m_strAFileName.empty())
  142. {
  143. hr = HrApplyAnswerFile(g_pINetCfg, szAnswerFileName,
  144. pnaOptions->m_fVerbose);
  145. }
  146. TraceTag(ttidNetAfx, "%s: releasing INetCfg...", __FUNCNAME__);
  147. (void) HrUninitializeAndReleaseINetCfg(g_fInitCom, g_pINetCfg, TRUE);
  148. g_pINetCfg = NULL;
  149. }
  150. else if (NETCFG_E_NO_WRITE_LOCK == hr)
  151. {
  152. Assert (pszwClientDesc);
  153. ShowMsgIfVerbose(pnaOptions->m_fVerbose,
  154. L"... failed to lock INetCfg. "
  155. L"It is already locked by '%s'", pszwClientDesc);
  156. CoTaskMemFree(pszwClientDesc);
  157. }
  158. else
  159. {
  160. Assert(!pszwClientDesc);
  161. ShowMsgIfVerbose(pnaOptions->m_fVerbose,
  162. L"...error getting INetCfg, "
  163. L"error code: 0x%x", hr);
  164. }
  165. TraceError(__FUNCNAME__, hr);
  166. return hr;
  167. }
  168. // ----------------------------------------------------------------------
  169. //
  170. // Function: HrApplyAnswerFile
  171. //
  172. // Purpose: Run & apply the specified answerfile
  173. //
  174. // Arguments:
  175. // szAnswerFileName [in] name of answerfile
  176. // fVerbose [in] display verbose messages when TRUE
  177. //
  178. // Returns: S_OK on success, otherwise an error code
  179. //
  180. // Author: kumarp 24-December-97
  181. //
  182. // Notes:
  183. //
  184. HRESULT HrApplyAnswerFile(IN INetCfg* pnc,
  185. IN PCWSTR szAnswerFileName,
  186. IN BOOL fVerbose)
  187. {
  188. DefineFunctionName("HrApplyAnswerFile");
  189. static const WCHAR c_szAFileDll[] =
  190. L"netshell.dll";
  191. static const CHAR c_szNetSetupSetProgressCallback[] =
  192. "NetSetupSetProgressCallback";
  193. static const CHAR c_szNetSetupApplyAnswerFile[] =
  194. "HrNetSetupApplyAnswerFile";
  195. ShowMsgIfVerbose(fVerbose, L"Applying answerfile: %s",
  196. szAnswerFileName);
  197. BOOL fRebootRequired=FALSE;
  198. HRESULT hr=S_OK;
  199. HMODULE hDll;
  200. NetSetupSetProgressCallbackFn pfNetSetupSetProgressCallback;
  201. HrNetSetupApplyAnswerFileFn pfHrNetSetupApplyAnswerFileFn;
  202. TStringList* pslErrors;
  203. hr = HrLoadLibAndGetProcsV(c_szAFileDll,
  204. &hDll,
  205. c_szNetSetupSetProgressCallback,
  206. (FARPROC*) &pfNetSetupSetProgressCallback,
  207. c_szNetSetupApplyAnswerFile,
  208. (FARPROC*) &pfHrNetSetupApplyAnswerFileFn,
  209. NULL);
  210. if (S_OK == hr)
  211. {
  212. NC_TRY
  213. {
  214. pfNetSetupSetProgressCallback(ShowMsgIfGlobalVerboseV);
  215. hr = pfHrNetSetupApplyAnswerFileFn(pnc,
  216. szAnswerFileName,
  217. &pslErrors);
  218. fRebootRequired = NETCFG_S_REBOOT == hr;
  219. }
  220. NC_CATCH_ALL
  221. {
  222. hr = E_FAIL;
  223. ShowMsgIfVerbose(fVerbose,
  224. L"...unhandled exception in netshell.dll");
  225. }
  226. FreeLibrary(hDll);
  227. }
  228. if (SUCCEEDED(hr))
  229. {
  230. ShowMsgIfVerbose(fVerbose,
  231. L"answerfile '%s' successfully applied",
  232. szAnswerFileName);
  233. }
  234. else
  235. {
  236. if (NETSETUP_E_ANS_FILE_ERROR == hr)
  237. {
  238. ShowAnswerFileErrors(pslErrors);
  239. }
  240. else
  241. {
  242. ShowMsgIfVerbose(fVerbose,
  243. L"answerfile '%s' could not be "
  244. L"successfully applied. error code: 0x%x",
  245. szAnswerFileName, hr);
  246. }
  247. }
  248. if (fRebootRequired)
  249. {
  250. ShowMsgIfVerbose(TRUE,
  251. L"You must shut down and restart your computer "
  252. L"before the new settings will take effect.");
  253. }
  254. TraceError(__FUNCNAME__, hr);
  255. return hr;
  256. }
  257. // ----------------------------------------------------------------------
  258. //
  259. // Function: ShowAnswerFileErrors
  260. //
  261. // Purpose: Display errors in the answerfile
  262. //
  263. // Arguments:
  264. // pslErrors [in] pointer to list of
  265. //
  266. // Returns: None
  267. //
  268. // Author: kumarp 24-December-97
  269. //
  270. // Notes:
  271. //
  272. void ShowAnswerFileErrors(IN TStringList* pslErrors)
  273. {
  274. TStringListIter pos;
  275. PCWSTR szError;
  276. wprintf(L"Answerfile has the following errors. Cannot continue...");
  277. for (pos = pslErrors->begin(); pos != pslErrors->end(); pos++)
  278. {
  279. szError = (*pos)->c_str();
  280. wprintf(L"%s\n", szError);
  281. }
  282. }
  283. // ----------------------------------------------------------------------
  284. //
  285. // Function: ShowMsgIfVerboseV
  286. //
  287. // Purpose: Show the passed message if we are in verbose mode
  288. // otherwise do nothing.
  289. //
  290. // Arguments:
  291. // szMsg [in] message
  292. // arglist [in] list of arguments
  293. //
  294. // Returns: None
  295. //
  296. // Author: kumarp 15-April-98
  297. //
  298. // Notes:
  299. //
  300. void ShowMsgIfGlobalVerboseV(IN PCWSTR szMsg, IN va_list arglist)
  301. {
  302. ShowMsgIfVerboseV(g_fVerbose, szMsg, arglist);
  303. }
  304. // ----------------------------------------------------------------------
  305. //
  306. // Function: ShowMsgIfVerboseV
  307. //
  308. // Purpose: Show the passed message if we are in verbose mode
  309. // otherwise do nothing.
  310. //
  311. // Arguments:
  312. // fVerbose [in] flag indicating verbose mode
  313. // szMsg [in] message
  314. // arglist [in] list of arguments
  315. //
  316. // Returns: None
  317. //
  318. // Author: kumarp 15-April-98
  319. //
  320. // Notes:
  321. //
  322. void ShowMsgIfVerboseV(IN BOOL fVerbose, IN PCWSTR szMsg, IN va_list arglist)
  323. {
  324. static WCHAR szTempBuf[1024];
  325. vswprintf(szTempBuf, szMsg, arglist);
  326. if (fVerbose)
  327. {
  328. wprintf(L"%s\n", szTempBuf);
  329. fflush(stdout);
  330. }
  331. TraceTag(ttidNetAfx, "%S", szTempBuf);
  332. }
  333. // ----------------------------------------------------------------------
  334. //
  335. // Function: ShowMsgIfVerbose
  336. //
  337. // Purpose: Show the passed message only if Verbose mode is on
  338. //
  339. // Arguments:
  340. // szMsg [in] message to be displayed
  341. // fVerbose [in] flag controlling the verbose mode
  342. //
  343. // Returns: None
  344. //
  345. // Author: kumarp 24-December-97
  346. //
  347. // Notes:
  348. //
  349. void ShowMsgIfVerbose(IN BOOL fVerbose, IN PCWSTR szMsg, ...)
  350. {
  351. va_list arglist;
  352. va_start(arglist, szMsg);
  353. ShowMsgIfVerboseV(fVerbose, szMsg, arglist);
  354. va_end(arglist);
  355. }
  356. // ----------------------------------------------------------------------
  357. //
  358. // Function: FParseCmdLine
  359. //
  360. // Purpose: Parse command line arguments
  361. //
  362. // Arguments:
  363. // argc [in] number of arguments
  364. // argv [in] pointer to array of command line arguments
  365. // pstrAFileName [out] name of answerfile
  366. // pfVerbose [out] flag controlling the verbose mode
  367. //
  368. // Returns: TRUE if all cmd line arguments correct, FALSE otherwise
  369. //
  370. // Author: kumarp 24-December-97
  371. //
  372. // Notes:
  373. //
  374. BOOL FParseCmdLine(IN int argc,
  375. IN WCHAR* argv[],
  376. OUT CNetAfxOptions* pnaOptions)
  377. {
  378. DefineFunctionName("FParseCmdLine");
  379. AssertValidReadPtr(argv);
  380. AssertValidWritePtr(pnaOptions);
  381. BOOL fStatus=FALSE;
  382. CHAR ch;
  383. static const WCHAR c_szValidOptions[] = L"f:vVlLhH?";
  384. WCHAR szFileFullPath[MAX_PATH+1];
  385. PWSTR szFileComponent;
  386. while ((ch = getopt(argc, argv, (WCHAR*) c_szValidOptions)) != EOF)
  387. {
  388. switch (ch)
  389. {
  390. case 'f':
  391. int nChars;
  392. nChars = GetFullPathName(optarg, MAX_PATH,
  393. szFileFullPath, &szFileComponent);
  394. if (nChars)
  395. {
  396. pnaOptions->m_strAFileName = szFileFullPath;
  397. }
  398. fStatus = TRUE;
  399. break;
  400. case 'v':
  401. case 'V':
  402. pnaOptions->m_fVerbose = TRUE;
  403. break;
  404. case 'l':
  405. case 'L':
  406. pnaOptions->m_fShowComponents = TRUE;
  407. fStatus = TRUE;
  408. break;
  409. default:
  410. case 'h':
  411. case 'H':
  412. case '?':
  413. case 0:
  414. fStatus = FALSE;
  415. break;
  416. }
  417. }
  418. return fStatus;
  419. }
  420. // ----------------------------------------------------------------------
  421. //
  422. // Function: ShowUsage
  423. //
  424. // Purpose: Display program usage help
  425. //
  426. // Arguments: None
  427. //
  428. // Returns: None
  429. //
  430. // Author: kumarp 24-December-97
  431. //
  432. // Notes:
  433. //
  434. void ShowUsage()
  435. {
  436. static const WCHAR c_szUsage[] =
  437. L"Command syntax\n"
  438. L"--------------\n"
  439. L"netafx [/f [drive:][path]filename ] [/v] [/l]\n"
  440. L" or\n"
  441. L"netafx /?\n"
  442. L"\n"
  443. L" /f [drive:][path]filename\n"
  444. L"\t Specifies the answerfile name.\n"
  445. L"\n"
  446. L" /V\t Turns on the verbose mode that dumps what is being applied and\n"
  447. L" \t what result is returned. The default is off.\n"
  448. L" /l\t Displays list of installed networking components\n"
  449. L" /?\t Displays this help\n"
  450. L"\n"
  451. L"\n"
  452. L"General Overview\n"
  453. L"----------------\n"
  454. L"netafx is a tool that you can use for listing, installing, "
  455. L"configuring and uninstalling networking components. To list "
  456. L"installed components use the /l option. For other operations you "
  457. L"need to provide a text file (also called AnswerFile) that describes "
  458. L"the actions that you want to perform. "
  459. L"For more information on the syntax of the AnswerFile, please refer "
  460. L"to the document 'Unattended Setup Parameters'"
  461. L"\n";
  462. wprintf(c_szUsage);
  463. }
  464. // ----------------------------------------------------------------------
  465. //
  466. // Function: HrGetInstalledComponentList
  467. //
  468. // Purpose: Get list of installed networking components
  469. //
  470. // Arguments:
  471. // pnc [in] pointer to INetCfg object
  472. // pguidClass [in] pointer to class whose components are requested
  473. // pslComponents [out] pointer to list of components
  474. // pslDescriptions [out] pointer to list of descriptions
  475. //
  476. // Returns: S_OK on success, otherwise an error code
  477. //
  478. // Author: kumarp 15-April-98
  479. //
  480. // Notes:
  481. //
  482. HRESULT HrGetInstalledComponentList(IN INetCfg* pnc,
  483. IN const GUID* pguidClass,
  484. OUT TStringList* pslComponents,
  485. OUT TStringList* pslDescriptions)
  486. {
  487. DefineFunctionName("HrGetInstalledComponentList");
  488. AssertValidReadPtr(pnc);
  489. AssertValidReadPtr(pguidClass);
  490. AssertValidWritePtr(pslComponents);
  491. AssertValidWritePtr(pslDescriptions);
  492. static const WCHAR c_szErrorGettingDisplayName[] =
  493. L"<Error getting display name>";
  494. HRESULT hr=S_OK;
  495. CIterNetCfgComponent nccIter(pnc, pguidClass);
  496. PWSTR pszwInfId;
  497. DWORD dwcc;
  498. INetCfgComponent* pINetCfgComponent;
  499. while (SUCCEEDED(hr) && (S_OK == (hr = nccIter.HrNext(&pINetCfgComponent))))
  500. {
  501. if (pguidClass == &GUID_DEVCLASS_NET)
  502. {
  503. // we are interested only in physical netcards
  504. //
  505. hr = pINetCfgComponent->GetCharacteristics(&dwcc);
  506. if (FAILED(hr) || !(dwcc & NCF_PHYSICAL))
  507. {
  508. hr = S_OK;
  509. ReleaseObj(pINetCfgComponent);
  510. continue;
  511. }
  512. }
  513. hr = pINetCfgComponent->GetId(&pszwInfId);
  514. if (S_OK == hr)
  515. {
  516. pslComponents->push_back(new tstring(pszwInfId));
  517. PWSTR pszwDisplayName;
  518. hr = pINetCfgComponent->GetDisplayName(&pszwDisplayName);
  519. if (SUCCEEDED(hr))
  520. {
  521. pslDescriptions->push_back(new tstring(pszwDisplayName));
  522. CoTaskMemFree(pszwDisplayName);
  523. }
  524. else
  525. {
  526. pslDescriptions->push_back(new tstring(c_szErrorGettingDisplayName));
  527. }
  528. CoTaskMemFree(pszwInfId);
  529. }
  530. // we dont want to quit upgrade just because 1 component
  531. // failed OsUpgrade, therefore reset hr to S_OK
  532. hr = S_OK;
  533. ReleaseObj(pINetCfgComponent);
  534. }
  535. if (S_FALSE == hr)
  536. {
  537. hr = S_OK;
  538. }
  539. TraceError(__FUNCNAME__, hr);
  540. return hr;
  541. }
  542. // ----------------------------------------------------------------------
  543. //
  544. // Function: HrShowInstalledComponentList
  545. //
  546. // Purpose: Display list of installed networking componetns
  547. //
  548. // Arguments:
  549. // pnc [in] pointer to INetCfg object
  550. // pguidClass [in] class whose components are to be listed
  551. //
  552. // Returns: S_OK on success, otherwise an error code
  553. //
  554. // Author: kumarp 15-April-98
  555. //
  556. // Notes:
  557. //
  558. HRESULT HrShowInstalledComponentList(IN INetCfg* pnc,
  559. IN const GUID* pguidClass)
  560. {
  561. DefineFunctionName("HrShowInstalledComponentList");
  562. HRESULT hr=S_OK;
  563. PCWSTR szClassName;
  564. static const WCHAR c_szNetCards[] = L"Network Adapters";
  565. static const WCHAR c_szNetProtocols[] = L"Network Protocols";
  566. static const WCHAR c_szNetServices[] = L"Network Services";
  567. static const WCHAR c_szNetClients[] = L"Network Clients";
  568. if (pguidClass == &GUID_DEVCLASS_NET)
  569. {
  570. szClassName = c_szNetCards;
  571. }
  572. else if (pguidClass == &GUID_DEVCLASS_NETTRANS)
  573. {
  574. szClassName = c_szNetProtocols;
  575. }
  576. else if (pguidClass == &GUID_DEVCLASS_NETSERVICE)
  577. {
  578. szClassName = c_szNetServices;
  579. }
  580. else if (pguidClass == &GUID_DEVCLASS_NETCLIENT)
  581. {
  582. szClassName = c_szNetClients;
  583. }
  584. else
  585. {
  586. szClassName = NULL;
  587. }
  588. Assert(szClassName);
  589. wprintf(L"\n%s\n-----------------\n", szClassName);
  590. TStringList slComponents;
  591. TStringList slDisplayNames;
  592. hr = HrGetInstalledComponentList(pnc, pguidClass, &slComponents,
  593. &slDisplayNames);
  594. if (S_OK == hr)
  595. {
  596. TStringListIter pos1, pos2;
  597. PCWSTR szComponentId;
  598. PCWSTR szDisplayName;
  599. pos1 = slComponents.begin();
  600. pos2 = slDisplayNames.begin();
  601. while (pos1 != slComponents.end())
  602. {
  603. Assert(pos2 != slDisplayNames.end());
  604. szComponentId = (*pos1++)->c_str();
  605. szDisplayName = (*pos2++)->c_str();
  606. wprintf(L"%-26s %s\n", szComponentId, szDisplayName);
  607. }
  608. }
  609. TraceError(__FUNCNAME__, hr);
  610. return hr;
  611. }
  612. // ----------------------------------------------------------------------
  613. //
  614. // Function: NetAfxConsoleCrtlHandler
  615. //
  616. // Purpose: Release resources on abnormal exit
  617. //
  618. // Arguments:
  619. // dwCtrlType [in] reason of abnormal exit
  620. //
  621. // Returns: FALSE --> so that netafx will be terminated
  622. //
  623. // Author: kumarp 15-April-98
  624. //
  625. // Notes:
  626. //
  627. BOOL WINAPI NetAfxConsoleCrtlHandler(IN DWORD dwCtrlType)
  628. {
  629. DefineFunctionName("NetAfxConsoleCrtlHandler");
  630. // Handles all dwCtrlType i.e. ignore the passed type
  631. if (g_pINetCfg)
  632. {
  633. TraceTag(ttidNetAfx, "%s: abnormal exit, releasing INetCfg...",
  634. __FUNCNAME__);
  635. (void) HrUninitializeAndReleaseINetCfg(g_fInitCom, g_pINetCfg, TRUE);
  636. g_pINetCfg = NULL;
  637. }
  638. return FALSE;
  639. }