//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: N E T A F X . C P P // // Contents: Tool for applying answerfile // // Author: kumarp 10-December-97 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "getopt.h" #include "ncstring.h" #include "kkutils.h" #include "ncnetcfg.h" #include "ncerror.h" #include "nceh.h" #include "nsexports.h" class CNetAfxOptions { public: tstring m_strAFileName; BOOL m_fVerbose; BOOL m_fShowComponents; CNetAfxOptions() { m_fVerbose = FALSE; m_fShowComponents = FALSE; } }; // ---------------------------------------------------------------------- // Global vars // BOOL g_fVerbose=FALSE; INetCfg* g_pINetCfg=NULL; BOOL g_fInitCom=TRUE; // ---------------------------------------------------------------------- BOOL FParseCmdLine(IN int argc, IN WCHAR* argv[], OUT CNetAfxOptions* pnaOptions); void ShowUsage(); HRESULT HrApplyAnswerFile(IN INetCfg* pnc, IN PCWSTR szAnswerFileName, IN BOOL fVerbose); void ShowAnswerFileErrors(IN TStringList* pslErrors); void ShowMsgIfVerbose(IN BOOL fVerbose, IN PCWSTR szMsg, ...); void ShowMsgIfGlobalVerboseV(IN PCWSTR szMsg, IN va_list arglist); void ShowMsgIfVerboseV(IN BOOL fVerbose, IN PCWSTR szMsg, IN va_list arglist); HRESULT HrGetInstalledComponentList(IN INetCfg* pnc, IN const GUID* pguidClass, OUT TStringList* pslComponents, OUT TStringList* pslDescriptions); HRESULT HrShowInstalledComponentList(IN INetCfg* pnc, IN const GUID* pguidClass); HRESULT HrDoNetAfx(IN CNetAfxOptions* pnaOptions); BOOL WINAPI NetAfxConsoleCrtlHandler(IN DWORD dwCtrlType); // ---------------------------------------------------------------------- // // Function: wmain // // Purpose: The main function // // Arguments: standard main args // // Returns: 0 on success, non-zero otherwise // // Author: kumarp 25-December-97 // // Notes: // EXTERN_C int __cdecl wmain(int argc, WCHAR* argv[]) { tstring strAFileName; BOOL fVerbose; HRESULT hr=S_OK; CNetAfxOptions naOptions; InitializeDebugging(); if (FParseCmdLine(argc, argv, &naOptions)) { SetConsoleCtrlHandler(NetAfxConsoleCrtlHandler, TRUE); hr = HrDoNetAfx(&naOptions); } else { ShowUsage(); } UnInitializeDebugging(); return hr; } // ---------------------------------------------------------------------- // // Function: HrDoNetAfx // // Purpose: Perform actions specified by pnaOptions // // Arguments: // pnaOptions [in] pointer to CNetAfxOptions object // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 19-February-98 // // Notes: // HRESULT HrDoNetAfx(IN CNetAfxOptions* pnaOptions) { AssertValidReadPtr(pnaOptions); DefineFunctionName("HrDoNetAfx"); static const WCHAR c_szNetAfxName[] = L"netafx.exe"; HRESULT hr=S_OK; PCWSTR szAnswerFileName; g_fVerbose = pnaOptions->m_fVerbose; szAnswerFileName = pnaOptions->m_strAFileName.c_str(); PWSTR pszwClientDesc = NULL; const UINT c_cmsWaitForINetCfgWrite = 120000; BOOL fNeedWriteLock=FALSE; ShowMsgIfVerbose(pnaOptions->m_fVerbose, L"Trying to get INetCfg..."); fNeedWriteLock = !pnaOptions->m_strAFileName.empty(); hr = HrCreateAndInitializeINetCfg(&g_fInitCom, &g_pINetCfg, fNeedWriteLock, c_cmsWaitForINetCfgWrite, c_szNetAfxName, &pszwClientDesc); if (S_OK == hr) { Assert(!pszwClientDesc); ShowMsgIfVerbose(pnaOptions->m_fVerbose, L"...got it"); if (pnaOptions->m_fShowComponents) { (void) HrShowInstalledComponentList(g_pINetCfg, &GUID_DEVCLASS_NET); (void) HrShowInstalledComponentList(g_pINetCfg, &GUID_DEVCLASS_NETTRANS); (void) HrShowInstalledComponentList(g_pINetCfg, &GUID_DEVCLASS_NETCLIENT); (void) HrShowInstalledComponentList(g_pINetCfg, &GUID_DEVCLASS_NETSERVICE); } if (!pnaOptions->m_strAFileName.empty()) { hr = HrApplyAnswerFile(g_pINetCfg, szAnswerFileName, pnaOptions->m_fVerbose); } TraceTag(ttidNetAfx, "%s: releasing INetCfg...", __FUNCNAME__); (void) HrUninitializeAndReleaseINetCfg(g_fInitCom, g_pINetCfg, TRUE); g_pINetCfg = NULL; } else if (NETCFG_E_NO_WRITE_LOCK == hr) { Assert (pszwClientDesc); ShowMsgIfVerbose(pnaOptions->m_fVerbose, L"... failed to lock INetCfg. " L"It is already locked by '%s'", pszwClientDesc); CoTaskMemFree(pszwClientDesc); } else { Assert(!pszwClientDesc); ShowMsgIfVerbose(pnaOptions->m_fVerbose, L"...error getting INetCfg, " L"error code: 0x%x", hr); } TraceError(__FUNCNAME__, hr); return hr; } // ---------------------------------------------------------------------- // // Function: HrApplyAnswerFile // // Purpose: Run & apply the specified answerfile // // Arguments: // szAnswerFileName [in] name of answerfile // fVerbose [in] display verbose messages when TRUE // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 24-December-97 // // Notes: // HRESULT HrApplyAnswerFile(IN INetCfg* pnc, IN PCWSTR szAnswerFileName, IN BOOL fVerbose) { DefineFunctionName("HrApplyAnswerFile"); static const WCHAR c_szAFileDll[] = L"netshell.dll"; static const CHAR c_szNetSetupSetProgressCallback[] = "NetSetupSetProgressCallback"; static const CHAR c_szNetSetupApplyAnswerFile[] = "HrNetSetupApplyAnswerFile"; ShowMsgIfVerbose(fVerbose, L"Applying answerfile: %s", szAnswerFileName); BOOL fRebootRequired=FALSE; HRESULT hr=S_OK; HMODULE hDll; NetSetupSetProgressCallbackFn pfNetSetupSetProgressCallback; HrNetSetupApplyAnswerFileFn pfHrNetSetupApplyAnswerFileFn; TStringList* pslErrors; hr = HrLoadLibAndGetProcsV(c_szAFileDll, &hDll, c_szNetSetupSetProgressCallback, (FARPROC*) &pfNetSetupSetProgressCallback, c_szNetSetupApplyAnswerFile, (FARPROC*) &pfHrNetSetupApplyAnswerFileFn, NULL); if (S_OK == hr) { NC_TRY { pfNetSetupSetProgressCallback(ShowMsgIfGlobalVerboseV); hr = pfHrNetSetupApplyAnswerFileFn(pnc, szAnswerFileName, &pslErrors); fRebootRequired = NETCFG_S_REBOOT == hr; } NC_CATCH_ALL { hr = E_FAIL; ShowMsgIfVerbose(fVerbose, L"...unhandled exception in netshell.dll"); } FreeLibrary(hDll); } if (SUCCEEDED(hr)) { ShowMsgIfVerbose(fVerbose, L"answerfile '%s' successfully applied", szAnswerFileName); } else { if (NETSETUP_E_ANS_FILE_ERROR == hr) { ShowAnswerFileErrors(pslErrors); } else { ShowMsgIfVerbose(fVerbose, L"answerfile '%s' could not be " L"successfully applied. error code: 0x%x", szAnswerFileName, hr); } } if (fRebootRequired) { ShowMsgIfVerbose(TRUE, L"You must shut down and restart your computer " L"before the new settings will take effect."); } TraceError(__FUNCNAME__, hr); return hr; } // ---------------------------------------------------------------------- // // Function: ShowAnswerFileErrors // // Purpose: Display errors in the answerfile // // Arguments: // pslErrors [in] pointer to list of // // Returns: None // // Author: kumarp 24-December-97 // // Notes: // void ShowAnswerFileErrors(IN TStringList* pslErrors) { TStringListIter pos; PCWSTR szError; wprintf(L"Answerfile has the following errors. Cannot continue..."); for (pos = pslErrors->begin(); pos != pslErrors->end(); pos++) { szError = (*pos)->c_str(); wprintf(L"%s\n", szError); } } // ---------------------------------------------------------------------- // // Function: ShowMsgIfVerboseV // // Purpose: Show the passed message if we are in verbose mode // otherwise do nothing. // // Arguments: // szMsg [in] message // arglist [in] list of arguments // // Returns: None // // Author: kumarp 15-April-98 // // Notes: // void ShowMsgIfGlobalVerboseV(IN PCWSTR szMsg, IN va_list arglist) { ShowMsgIfVerboseV(g_fVerbose, szMsg, arglist); } // ---------------------------------------------------------------------- // // Function: ShowMsgIfVerboseV // // Purpose: Show the passed message if we are in verbose mode // otherwise do nothing. // // Arguments: // fVerbose [in] flag indicating verbose mode // szMsg [in] message // arglist [in] list of arguments // // Returns: None // // Author: kumarp 15-April-98 // // Notes: // void ShowMsgIfVerboseV(IN BOOL fVerbose, IN PCWSTR szMsg, IN va_list arglist) { static WCHAR szTempBuf[1024]; vswprintf(szTempBuf, szMsg, arglist); if (fVerbose) { wprintf(L"%s\n", szTempBuf); fflush(stdout); } TraceTag(ttidNetAfx, "%S", szTempBuf); } // ---------------------------------------------------------------------- // // Function: ShowMsgIfVerbose // // Purpose: Show the passed message only if Verbose mode is on // // Arguments: // szMsg [in] message to be displayed // fVerbose [in] flag controlling the verbose mode // // Returns: None // // Author: kumarp 24-December-97 // // Notes: // void ShowMsgIfVerbose(IN BOOL fVerbose, IN PCWSTR szMsg, ...) { va_list arglist; va_start(arglist, szMsg); ShowMsgIfVerboseV(fVerbose, szMsg, arglist); va_end(arglist); } // ---------------------------------------------------------------------- // // Function: FParseCmdLine // // Purpose: Parse command line arguments // // Arguments: // argc [in] number of arguments // argv [in] pointer to array of command line arguments // pstrAFileName [out] name of answerfile // pfVerbose [out] flag controlling the verbose mode // // Returns: TRUE if all cmd line arguments correct, FALSE otherwise // // Author: kumarp 24-December-97 // // Notes: // BOOL FParseCmdLine(IN int argc, IN WCHAR* argv[], OUT CNetAfxOptions* pnaOptions) { DefineFunctionName("FParseCmdLine"); AssertValidReadPtr(argv); AssertValidWritePtr(pnaOptions); BOOL fStatus=FALSE; CHAR ch; static const WCHAR c_szValidOptions[] = L"f:vVlLhH?"; WCHAR szFileFullPath[MAX_PATH+1]; PWSTR szFileComponent; while ((ch = getopt(argc, argv, (WCHAR*) c_szValidOptions)) != EOF) { switch (ch) { case 'f': int nChars; nChars = GetFullPathName(optarg, MAX_PATH, szFileFullPath, &szFileComponent); if (nChars) { pnaOptions->m_strAFileName = szFileFullPath; } fStatus = TRUE; break; case 'v': case 'V': pnaOptions->m_fVerbose = TRUE; break; case 'l': case 'L': pnaOptions->m_fShowComponents = TRUE; fStatus = TRUE; break; default: case 'h': case 'H': case '?': case 0: fStatus = FALSE; break; } } return fStatus; } // ---------------------------------------------------------------------- // // Function: ShowUsage // // Purpose: Display program usage help // // Arguments: None // // Returns: None // // Author: kumarp 24-December-97 // // Notes: // void ShowUsage() { static const WCHAR c_szUsage[] = L"Command syntax\n" L"--------------\n" L"netafx [/f [drive:][path]filename ] [/v] [/l]\n" L" or\n" L"netafx /?\n" L"\n" L" /f [drive:][path]filename\n" L"\t Specifies the answerfile name.\n" L"\n" L" /V\t Turns on the verbose mode that dumps what is being applied and\n" L" \t what result is returned. The default is off.\n" L" /l\t Displays list of installed networking components\n" L" /?\t Displays this help\n" L"\n" L"\n" L"General Overview\n" L"----------------\n" L"netafx is a tool that you can use for listing, installing, " L"configuring and uninstalling networking components. To list " L"installed components use the /l option. For other operations you " L"need to provide a text file (also called AnswerFile) that describes " L"the actions that you want to perform. " L"For more information on the syntax of the AnswerFile, please refer " L"to the document 'Unattended Setup Parameters'" L"\n"; wprintf(c_szUsage); } // ---------------------------------------------------------------------- // // Function: HrGetInstalledComponentList // // Purpose: Get list of installed networking components // // Arguments: // pnc [in] pointer to INetCfg object // pguidClass [in] pointer to class whose components are requested // pslComponents [out] pointer to list of components // pslDescriptions [out] pointer to list of descriptions // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 15-April-98 // // Notes: // HRESULT HrGetInstalledComponentList(IN INetCfg* pnc, IN const GUID* pguidClass, OUT TStringList* pslComponents, OUT TStringList* pslDescriptions) { DefineFunctionName("HrGetInstalledComponentList"); AssertValidReadPtr(pnc); AssertValidReadPtr(pguidClass); AssertValidWritePtr(pslComponents); AssertValidWritePtr(pslDescriptions); static const WCHAR c_szErrorGettingDisplayName[] = L""; HRESULT hr=S_OK; CIterNetCfgComponent nccIter(pnc, pguidClass); PWSTR pszwInfId; DWORD dwcc; INetCfgComponent* pINetCfgComponent; while (SUCCEEDED(hr) && (S_OK == (hr = nccIter.HrNext(&pINetCfgComponent)))) { if (pguidClass == &GUID_DEVCLASS_NET) { // we are interested only in physical netcards // hr = pINetCfgComponent->GetCharacteristics(&dwcc); if (FAILED(hr) || !(dwcc & NCF_PHYSICAL)) { hr = S_OK; ReleaseObj(pINetCfgComponent); continue; } } hr = pINetCfgComponent->GetId(&pszwInfId); if (S_OK == hr) { pslComponents->push_back(new tstring(pszwInfId)); PWSTR pszwDisplayName; hr = pINetCfgComponent->GetDisplayName(&pszwDisplayName); if (SUCCEEDED(hr)) { pslDescriptions->push_back(new tstring(pszwDisplayName)); CoTaskMemFree(pszwDisplayName); } else { pslDescriptions->push_back(new tstring(c_szErrorGettingDisplayName)); } CoTaskMemFree(pszwInfId); } // we dont want to quit upgrade just because 1 component // failed OsUpgrade, therefore reset hr to S_OK hr = S_OK; ReleaseObj(pINetCfgComponent); } if (S_FALSE == hr) { hr = S_OK; } TraceError(__FUNCNAME__, hr); return hr; } // ---------------------------------------------------------------------- // // Function: HrShowInstalledComponentList // // Purpose: Display list of installed networking componetns // // Arguments: // pnc [in] pointer to INetCfg object // pguidClass [in] class whose components are to be listed // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 15-April-98 // // Notes: // HRESULT HrShowInstalledComponentList(IN INetCfg* pnc, IN const GUID* pguidClass) { DefineFunctionName("HrShowInstalledComponentList"); HRESULT hr=S_OK; PCWSTR szClassName; static const WCHAR c_szNetCards[] = L"Network Adapters"; static const WCHAR c_szNetProtocols[] = L"Network Protocols"; static const WCHAR c_szNetServices[] = L"Network Services"; static const WCHAR c_szNetClients[] = L"Network Clients"; if (pguidClass == &GUID_DEVCLASS_NET) { szClassName = c_szNetCards; } else if (pguidClass == &GUID_DEVCLASS_NETTRANS) { szClassName = c_szNetProtocols; } else if (pguidClass == &GUID_DEVCLASS_NETSERVICE) { szClassName = c_szNetServices; } else if (pguidClass == &GUID_DEVCLASS_NETCLIENT) { szClassName = c_szNetClients; } else { szClassName = NULL; } Assert(szClassName); wprintf(L"\n%s\n-----------------\n", szClassName); TStringList slComponents; TStringList slDisplayNames; hr = HrGetInstalledComponentList(pnc, pguidClass, &slComponents, &slDisplayNames); if (S_OK == hr) { TStringListIter pos1, pos2; PCWSTR szComponentId; PCWSTR szDisplayName; pos1 = slComponents.begin(); pos2 = slDisplayNames.begin(); while (pos1 != slComponents.end()) { Assert(pos2 != slDisplayNames.end()); szComponentId = (*pos1++)->c_str(); szDisplayName = (*pos2++)->c_str(); wprintf(L"%-26s %s\n", szComponentId, szDisplayName); } } TraceError(__FUNCNAME__, hr); return hr; } // ---------------------------------------------------------------------- // // Function: NetAfxConsoleCrtlHandler // // Purpose: Release resources on abnormal exit // // Arguments: // dwCtrlType [in] reason of abnormal exit // // Returns: FALSE --> so that netafx will be terminated // // Author: kumarp 15-April-98 // // Notes: // BOOL WINAPI NetAfxConsoleCrtlHandler(IN DWORD dwCtrlType) { DefineFunctionName("NetAfxConsoleCrtlHandler"); // Handles all dwCtrlType i.e. ignore the passed type if (g_pINetCfg) { TraceTag(ttidNetAfx, "%s: abnormal exit, releasing INetCfg...", __FUNCNAME__); (void) HrUninitializeAndReleaseINetCfg(g_fInitCom, g_pINetCfg, TRUE); g_pINetCfg = NULL; } return FALSE; }