util.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 20k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include <lm.h>
  3. #include <dnsapi.h>
  4. #include <dsgetdc.h>
  5. #include <netcfgx.h>
  6. #include <netcfgn.h>
  7. #include <netcfgp.h>
  8. #include <netcon.h>
  9. #include <setupapi.h>
  10. #include <devguid.h>
  11. #include <tchar.h>
  12. #include <iphlpapi.h>
  13. #include <mprapi.h>
  14. #include <debug.h>
  15. #include "resource.h"
  16. #define SZ_REGKEY_SRVWIZ        TEXT("SOFTWARE\Microsoft\Windows NT\CurrentVersion\SrvWiz")
  17. // dcpromo stuff, copied from \kernelrazzle2srvadminburnslib and \kernelrazzle2srvadmindcpromo    
  18. // the number of bytes in a full DNS name to reserve for stuff
  19. // netlogon pre-/appends to DNS names when registering them
  20. #define SRV_RECORD_RESERVE      100
  21. // the max lengths, in bytes, of strings when represented in the UTF-8
  22. // character set.  These are the limits we expose to the user
  23. #define MAX_NAME_LENGTH         DNS_MAX_NAME_LENGTH - SRV_RECORD_RESERVE
  24. #define MAX_LABEL_LENGTH        DNS_MAX_LABEL_LENGTH
  25. // TCP/IP interface prefix, copied from ipconfig.c
  26. #define TCPIP_DEVICE_PREFIX "\Device\Tcpip_"
  27. // utility function: 
  28. // remove the leading and trailing spaces then return the modified string
  29. LPWSTR TrimString(LPWSTR pszIn)
  30. {
  31.     LPWSTR pstr;
  32.     if (!pszIn || !*pszIn)
  33.         return pszIn;
  34.     // strip leading spaces
  35.     for (pstr = pszIn; *pstr && *pstr == L' '; pstr++);
  36.     if (pstr != pszIn)
  37.         lstrcpyW(pszIn, pstr);
  38.     // strip trailing spaces
  39.     pstr = pszIn + lstrlen(pszIn) - 1; 
  40.     for (; pstr >= pszIn && *pstr == L' '; pstr--);
  41.     *(pstr + 1) = 0;
  42.     return pszIn;
  43. }
  44. BOOL ValidateDomainDNSName(LPWSTR pszDomainDNSName)
  45. {
  46.     // trim the name
  47.     pszDomainDNSName = TrimString(pszDomainDNSName);
  48.     if (!pszDomainDNSName || !*pszDomainDNSName)
  49.         return FALSE;
  50.     // validate DNS name syntax: length and characters
  51.     size_t cbUTF8 = WideCharToMultiByte(CP_UTF8, 0, pszDomainDNSName, -1, 0, 0, 0, 0);
  52.     if (cbUTF8 > MAX_NAME_LENGTH)
  53.         return FALSE;   // name is too long
  54.     if (ERROR_SUCCESS != DnsValidateName_W(pszDomainDNSName, DnsNameDomain))
  55.         return FALSE;
  56.     // check whether this name is already in use
  57.     DOMAIN_CONTROLLER_INFO* info = 0;
  58.     if (NO_ERROR == DsGetDcName(0, pszDomainDNSName, 0, 0, 0, &info))
  59.     {
  60.         NetApiBufferFree(info);
  61.         return FALSE;
  62.     }
  63.     if (ERROR_DUP_NAME == NetValidateName(0, pszDomainDNSName, 0, 0, NetSetupNonExistentDomain))
  64.         return FALSE;   // duplicate domain name
  65.     return TRUE;
  66. }
  67. BOOL ValidateDomainNetBiosName(LPWSTR pszDomainNetBiosName)
  68. {
  69.     // trim the name
  70.     pszDomainNetBiosName = TrimString(pszDomainNetBiosName);
  71.     if (!pszDomainNetBiosName || !*pszDomainNetBiosName)
  72.         return FALSE;
  73.     // check for "."
  74.     if (StrChrW(pszDomainNetBiosName, L'.'))
  75.         return FALSE;
  76.     WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  77.     DWORD ch = ARRAYSIZE(szComputerName);
  78.     *szComputerName = 0;
  79.     if (!DnsHostnameToComputerNameW(pszDomainNetBiosName, szComputerName, &ch))
  80.         return FALSE;
  81.     if (lstrlenW(szComputerName) < lstrlenW(pszDomainNetBiosName))
  82.         return FALSE;   // name was truncated
  83.     // check the name is not longer than the max bytes in te oem character set
  84.     if (WideCharToMultiByte(CP_OEMCP, 0, szComputerName, ch - 1, 0, 0, 0, 0) > DNLEN)
  85.         return FALSE; 
  86.     // check whether the domain name is in use
  87.     if (ERROR_DUP_NAME == NetValidateName(0, pszDomainNetBiosName, 0, 0, NetSetupNonExistentDomain))
  88.         return FALSE;
  89.     return TRUE;
  90. }
  91. BOOL IsTerminalServicesRunning(void)
  92. {
  93.     OSVERSIONINFOEX osVersionInfo;
  94.     DWORDLONG dwlConditionMask = 0;
  95.     ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  96.     osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  97.     osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL;
  98.     VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  99.     return VerifyVersionInfo(
  100.         &osVersionInfo,
  101.         VER_SUITENAME,
  102.         dwlConditionMask
  103.         );
  104. }
  105. // copied from ntprivateclustersetupcommonVerifyClusteros.cpp
  106. /////////////////////////////////////////////////////////////////////////////
  107. //++
  108. //
  109. // VerifyClusterOS
  110. //
  111. // Routine Description:
  112. //    This function determines whether the OS is correct for installing Clusteringi
  113. //    Service. The current requirements are that the OS be NT 5.0 and the product
  114. //    Suite be Enterprise and not Terminal Server.
  115. //
  116. // Arguments:
  117. //    None
  118. //
  119. // Return Value:
  120. //    TRUE - indicates that the OS is correct and Clustering Service may be installed.
  121. //
  122. //--
  123. /////////////////////////////////////////////////////////////////////////////
  124. BOOL VerifyClusterOS( void )
  125. {
  126.    BOOL              fReturnValue;
  127.    OSVERSIONINFOEX   osiv;
  128.    ZeroMemory( &osiv, sizeof( OSVERSIONINFOEX ) );
  129.    osiv.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
  130.    // The first call to VerifyVersionInfo will test the OS level and that the
  131.    // product suite is Enterprise.
  132.    
  133.    osiv.dwMajorVersion = 5;
  134.    osiv.dwMinorVersion = 0;
  135.    osiv.wServicePackMajor = 0;
  136.    osiv.wSuiteMask = VER_SUITE_ENTERPRISE;
  137.    DWORDLONG   dwlConditionMask;
  138.    dwlConditionMask = (DWORDLONG) 0L;
  139.    VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
  140.    VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
  141.    VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
  142.    VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  143.    fReturnValue = VerifyVersionInfo( &osiv,
  144.                                      VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR |
  145.                                      VER_SUITENAME,
  146.                                      dwlConditionMask );
  147.    
  148.    return ( fReturnValue );
  149. }
  150. // copied from ntprivateclustersetupcommonIsterminalServiceInstalled.cpp
  151. /////////////////////////////////////////////////////////////////////////////
  152. //++
  153. //
  154. // IsTerminalServicesInstalled
  155. //
  156. // Routine Description:
  157. //    This function determines whether Terminal Services is installed.
  158. //
  159. // Arguments:
  160. //    None
  161. //
  162. // Return Value:
  163. //    TRUE - indicates that Terminal Services is installed.
  164. //
  165. //--
  166. /////////////////////////////////////////////////////////////////////////////
  167. BOOL IsTerminalServicesInstalled( void )
  168. {
  169.    BOOL              fReturnValue;
  170.    OSVERSIONINFOEX   osiv;
  171.    ZeroMemory( &osiv, sizeof( OSVERSIONINFOEX ) );
  172.    osiv.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
  173.    osiv.wSuiteMask = VER_SUITE_TERMINAL;
  174.    DWORDLONG   dwlConditionMask;
  175.    dwlConditionMask = (DWORDLONG) 0L;
  176.    VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  177.    fReturnValue = VerifyVersionInfo( &osiv,
  178.                                      VER_SUITENAME,
  179.                                      dwlConditionMask );
  180.    
  181.    return ( fReturnValue );
  182. }
  183. LPTSTR WINAPI MyFormatString(UINT resId, ...)
  184. {
  185.     TCHAR szFormat[4096];
  186.     LPTSTR pszRet = NULL;
  187.     va_list ArgList;
  188.     // load the format string from resource
  189.     if (!LoadString(HINST_THISDLL, resId, szFormat, ARRAYSIZE(szFormat)))
  190.         return NULL;
  191.     // generate the string from format and arguments
  192.     va_start(ArgList, resId);
  193.     FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, szFormat, 0, 0, (LPTSTR)&pszRet, 0, &ArgList);
  194.     va_end(ArgList);
  195.     return pszRet;
  196. }
  197. LPSTR WINAPI MyFormatStringAnsi(UINT resId, ...)
  198. {
  199.     TCHAR szFormat[1024];
  200.     LPTSTR pszRet = NULL;
  201.     va_list ArgList;
  202.     // load the format string from resource
  203.     if (!LoadString(HINST_THISDLL, resId, szFormat, ARRAYSIZE(szFormat)))
  204.         return NULL;
  205.     // generate the string from format and arguments
  206.     va_start(ArgList, resId);
  207.     FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, szFormat, 0, 0, (LPTSTR)&pszRet, 0, &ArgList);
  208.     va_end(ArgList);
  209. #ifdef UNICODE
  210.     // turn pseRet to an Ansi string
  211.     int cch = lstrlenW(pszRet) + 1;
  212.     LPSTR pszTemp = (LPSTR)LocalAlloc(LPTR, cch * sizeof(CHAR));
  213.     if ( pszTemp )
  214.     {
  215.         WideCharToMultiByte(CP_ACP, 0, pszRet, -1, pszTemp, cch, NULL, NULL);
  216.         LocalFree(pszRet);
  217.     }
  218.     return pszTemp;
  219. #else
  220.     return pszRet;
  221. #endif // UNICODE
  222. }
  223. HRESULT CreateTempFile(LPCTSTR szPath, LPSTR szText)
  224. {
  225.    HRESULT hr = S_OK;
  226.    DWORD cbText = lstrlenA(szText) + 1;
  227.    DWORD cbWritten = 0;
  228.    HANDLE h = CreateFile(szPath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  229.    if (!h || h == INVALID_HANDLE_VALUE)
  230.       return HRESULT_FROM_WIN32(GetLastError());
  231.    // write eof to file
  232.    szText[cbText-1] = '32';
  233.    if (!WriteFile(h, szText, cbText, &cbWritten, NULL) || cbText != cbWritten)
  234.       hr = HRESULT_FROM_WIN32(GetLastError());
  235.    szText[cbText-1] = 0;
  236.    CloseHandle(h);
  237.    return hr;
  238. }
  239. BOOL InstallDNS(BOOL bWait)
  240. {
  241.     TCHAR szSysDir[MAX_PATH];
  242.     TCHAR szInfFile[MAX_PATH], szUnattendFile[MAX_PATH];
  243.     LPSTR pszText = NULL;
  244.     LPTSTR pszCmdLine = NULL;
  245.     DWORD dwRet = 0;
  246.     PROCESS_INFORMATION pi = { 0 };
  247.     STARTUPINFO si = { 0 };
  248.     si.cb = sizeof(si);
  249.     
  250.     // initialize directories and file paths
  251.     GetSystemDirectory(szSysDir, ARRAYSIZE(szSysDir));
  252.     GetWindowsDirectory(szInfFile, ARRAYSIZE(szInfFile));
  253.     StrCatN(szInfFile, TEXT("\inf"), ARRAYSIZE(szInfFile));
  254.     StrCpy(szUnattendFile, szInfFile);
  255.     // create inf file
  256.     StrCatN(szInfFile, TEXT("\cysdnsi.inf"), ARRAYSIZE(szInfFile));
  257.     pszText = MyFormatStringAnsi(IDS_INSTALL_DNS_INF_TEXT);
  258.     if (!pszText)
  259.         goto ERROR_RETURN;
  260.     if (S_OK != CreateTempFile(szInfFile, pszText))
  261.         goto ERROR_RETURN;
  262.         
  263.     LocalFree(pszText);
  264.     pszText = NULL;
  265.     // create unattend file
  266.     StrCatN(szUnattendFile, TEXT("\cysdnsu.inf"), 
  267.             ARRAYSIZE(szUnattendFile));
  268.     pszText = MyFormatStringAnsi(IDS_INSTALL_DNS_UNATTEND_TEXT);
  269.     if (!pszText)
  270.         goto ERROR_RETURN;
  271.     if (S_OK != CreateTempFile(szUnattendFile, pszText))
  272.         goto ERROR_RETURN;
  273.     LocalFree(pszText);
  274.     pszText = NULL;
  275.     // create command line
  276.     pszCmdLine = MyFormatString(IDS_INSTALL_DNS_COMMAND_LINE, 
  277.                                 szSysDir, szInfFile, szUnattendFile);
  278.     if (!pszCmdLine)
  279.         goto ERROR_RETURN;
  280.     // execute the command 
  281.     if (!CreateProcess(NULL, pszCmdLine, NULL, NULL, 
  282.                        FALSE, 0, NULL, NULL, &si, &pi))
  283.         goto ERROR_RETURN;
  284.     if (bWait)
  285.     {
  286.         dwRet = SHWaitForSendMessageThread(pi.hProcess, INFINITE);
  287.         ASSERT(dwRet == WAIT_OBJECT_0);
  288.         // get the process's return value
  289.         GetExitCodeProcess(pi.hProcess, &dwRet);
  290.     }
  291.     CloseHandle(pi.hThread);
  292.     CloseHandle(pi.hProcess);
  293.     LocalFree(pszCmdLine);
  294.     pszCmdLine = NULL;
  295.     // return dwRet != 0;    // sysocmgr returns non zero on success   
  296.     return TRUE;
  297. ERROR_RETURN:
  298.     if (pszText)
  299.         LocalFree(pszText);
  300.     if (pszCmdLine)
  301.         LocalFree(pszCmdLine);
  302.     return FALSE;
  303. }
  304. BOOL InstallDHCP(BOOL bWait)
  305. {
  306.     TCHAR szSysDir[MAX_PATH];
  307.     TCHAR szInfFile[MAX_PATH], szUnattendFile[MAX_PATH];
  308.     LPSTR pszText = NULL;
  309.     LPTSTR pszCmdLine = NULL;
  310.     TCHAR szDomainName[MAX_PATH];
  311.     DWORD cbSize;
  312.     DWORD dwRet;
  313.     PROCESS_INFORMATION pi = { 0 };
  314.     STARTUPINFO si = { 0 };
  315.     si.cb = sizeof(si);
  316.     
  317.     // initialize directories and file paths
  318.     GetSystemDirectory(szSysDir, ARRAYSIZE(szSysDir));
  319.     GetWindowsDirectory(szInfFile, ARRAYSIZE(szInfFile));
  320.     StrCatN(szInfFile, TEXT("\inf"), ARRAYSIZE(szInfFile));
  321.     StrCpy(szUnattendFile, szInfFile);
  322.     // get domain name from registry
  323.     cbSize = sizeof(szDomainName);
  324.     dwRet = SHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_SRVWIZ, 
  325.                        TEXT("DomainDNSName"), NULL, 
  326.                        (LPVOID)szDomainName, &cbSize);
  327.     if (NO_ERROR != dwRet || cbSize <= sizeof(TCHAR))
  328.         goto ERROR_RETURN;
  329.     // get inf file
  330.     StrCatN(szInfFile, TEXT("\sysoc.inf"), ARRAYSIZE(szInfFile));
  331.     // create unattend file
  332.     StrCatN(szUnattendFile, TEXT("\cysdhcpu.inf"), 
  333.             ARRAYSIZE(szUnattendFile));
  334.     pszText = MyFormatStringAnsi(IDS_INSTALL_DHCP_UNATTEND_TEXT,
  335.                                  szDomainName);
  336.     if (!pszText)
  337.         goto ERROR_RETURN;
  338.     if (S_OK != CreateTempFile(szUnattendFile, pszText))
  339.         goto ERROR_RETURN;
  340.     LocalFree(pszText);
  341.     pszText = NULL;
  342.     // create command line
  343.     pszCmdLine = MyFormatString(IDS_INSTALL_DHCP_COMMAND_LINE, 
  344.                                 szSysDir, szInfFile, szUnattendFile);
  345.     if (!pszCmdLine)
  346.         goto ERROR_RETURN;
  347.     // execute the command 
  348.     if (!CreateProcess(NULL, pszCmdLine, NULL, NULL, 
  349.                        FALSE, 0, NULL, NULL, &si, &pi))
  350.         goto ERROR_RETURN;
  351.     if (bWait)
  352.     {
  353.         dwRet = SHWaitForSendMessageThread(pi.hProcess, INFINITE);
  354.         ASSERT(dwRet == WAIT_OBJECT_0);
  355.         // get the process's return value
  356.         GetExitCodeProcess(pi.hProcess, &dwRet);
  357.     }
  358.         
  359.     CloseHandle(pi.hThread);
  360.     CloseHandle(pi.hProcess);
  361.     LocalFree(pszCmdLine);
  362.     pszCmdLine = NULL;
  363.     // return dwRet != 0;    // sysocmgr returns non zero on success   
  364.     return TRUE;
  365. ERROR_RETURN:
  366.     if (pszText)
  367.         LocalFree(pszText);
  368.     if (pszCmdLine)
  369.         LocalFree(pszCmdLine);
  370.     return FALSE;
  371. }
  372. BOOL InstallAD(BOOL bWait)
  373. {
  374.     TCHAR szSysDir[MAX_PATH];
  375.     TCHAR szAnswerFile[MAX_PATH];
  376.     LPSTR pszText = NULL;
  377.     LPTSTR pszCmdLine = NULL;
  378.     TCHAR szDomainNetBiosName[MAX_PATH], szDomainDNSName[MAX_PATH];
  379.     DWORD cbSize;
  380.     DWORD dwRet;
  381.     PROCESS_INFORMATION pi = { 0 };
  382.     STARTUPINFO si = { 0 };
  383.     si.cb = sizeof(si);
  384.     
  385.     // initialize directories and file paths
  386.     GetSystemDirectory(szSysDir, ARRAYSIZE(szSysDir));
  387.     GetWindowsDirectory(szAnswerFile, ARRAYSIZE(szAnswerFile));
  388.     StrCatN(szAnswerFile, TEXT("\inf"), ARRAYSIZE(szAnswerFile));
  389.     // get NetBios name from registry
  390.     cbSize = sizeof(szDomainNetBiosName);
  391.     dwRet = SHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_SRVWIZ,
  392.                        TEXT("DomainNetBiosName"), NULL, 
  393.                        (LPVOID)szDomainNetBiosName, &cbSize);
  394.     if (NO_ERROR != dwRet || cbSize <= sizeof(TCHAR))
  395.         goto ERROR_RETURN;
  396.     // get domain DNS name from registry
  397.     cbSize = sizeof(szDomainDNSName);
  398.     dwRet = SHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_SRVWIZ,
  399.                        TEXT("DomainDNSName"), NULL,
  400.                        (LPVOID)szDomainDNSName, &cbSize);
  401.     if (NO_ERROR != dwRet || cbSize <= sizeof(TCHAR))
  402.         goto ERROR_RETURN;
  403.     // create answer file
  404.     StrCatN(szAnswerFile, TEXT("\cysad.inf"), ARRAYSIZE(szAnswerFile));
  405.     pszText = MyFormatStringAnsi(IDS_INSTALL_AD_ANSWER_TEXT, 
  406.                                  szDomainNetBiosName, szDomainDNSName);
  407.     if (!pszText)
  408.         goto  ERROR_RETURN;
  409.     if (ERROR_SUCCESS != CreateTempFile(szAnswerFile, pszText))
  410.         goto ERROR_RETURN;
  411.     LocalFree(pszText);
  412.     pszText = NULL;
  413.     // create command line
  414.     pszCmdLine = MyFormatString(IDS_INSTALL_AD_COMMAND_LINE, 
  415.                                 szSysDir, szAnswerFile);
  416.     if (!pszCmdLine)
  417.         goto ERROR_RETURN;
  418.     // execute the command 
  419.     if (!CreateProcess(NULL, pszCmdLine, NULL, NULL, 
  420.                        FALSE, 0, NULL, NULL, &si, &pi))
  421.         goto ERROR_RETURN;
  422.     if (bWait)
  423.     {
  424.         dwRet = SHWaitForSendMessageThread(pi.hProcess, INFINITE);
  425.         ASSERT(dwRet == WAIT_OBJECT_0);
  426.         // get the process's return value
  427.         GetExitCodeProcess(pi.hProcess, &dwRet);
  428.     }
  429.     CloseHandle(pi.hThread);
  430.     CloseHandle(pi.hProcess);
  431.     LocalFree(pszCmdLine);
  432.     pszCmdLine = NULL;
  433.     // return dwRet != 0;    // dcpromo returns non zero on success   
  434.     return TRUE;
  435. ERROR_RETURN:
  436.     if (pszText)
  437.         LocalFree(pszText);
  438.     if (pszCmdLine)
  439.         LocalFree(pszCmdLine);
  440.     return FALSE;
  441. }
  442. // get guid name of the first tcp/ip interface we enum
  443. HRESULT GetTcpIpInterfaceGuidName(LPWSTR wszGuidName, DWORD cchSize)
  444. {
  445.     GUID guid;
  446.     DWORD dwError;
  447.     TCHAR szGuid[128];
  448.     ULONG ulSize = 0;
  449.     PIP_INTERFACE_INFO pInfo = NULL;
  450.     ASSERT(wszGuidName && cchSize);
  451.     
  452.     while( 1 ) {
  453.         dwError = GetInterfaceInfo( pInfo, &ulSize );
  454.         if( ERROR_INSUFFICIENT_BUFFER != dwError ) break;
  455.         if( NULL != pInfo ) LocalFree(pInfo);
  456.         if( 0 == ulSize ) return E_FAIL;
  457.         pInfo = (PIP_INTERFACE_INFO)LocalAlloc(LPTR, ulSize);
  458.         if( NULL == pInfo ) return E_OUTOFMEMORY;
  459.     }
  460.     if( ERROR_SUCCESS != dwError || 0 == pInfo->NumAdapters ) {
  461.         if( NULL != pInfo ) LocalFree(pInfo);
  462.         return E_FAIL;
  463.     }
  464.     StrCpyNW(wszGuidName, pInfo->Adapter[0].Name + strlen(TCPIP_DEVICE_PREFIX), cchSize);
  465.     // check whether this is a valid GUID
  466.     SHUnicodeToTChar(wszGuidName, szGuid, ARRAYSIZE(szGuid));
  467.     if (!GUIDFromString(szGuid, &guid))
  468.     {
  469.         // we failed to get a valid tcp/ip interface
  470.         *wszGuidName = 0;
  471.         LocalFree(pInfo);
  472.         return E_FAIL;
  473.     }
  474.     LocalFree(pInfo);
  475.     return NOERROR;
  476. }
  477. // get friendly name of the first tcp/ip interface we enum
  478. VOID GetTcpIpInterfaceFriendlyName(LPWSTR wszFriendlyName, DWORD cchSize)
  479. {
  480.     DWORD dwRet;
  481.     HRESULT hr;
  482.     WCHAR wszGuidName[128];
  483.     HANDLE hMprConfig;
  484.     *wszFriendlyName = 0;
  485.     
  486.     hr = GetTcpIpInterfaceGuidName(wszGuidName, ARRAYSIZE(wszGuidName));
  487.     if (NOERROR == hr)
  488.     {
  489.         dwRet = MprConfigServerConnect(NULL, &hMprConfig);
  490.         if (NO_ERROR == dwRet)
  491.         {
  492.             dwRet = MprConfigGetFriendlyName(hMprConfig, wszGuidName, 
  493.                             wszFriendlyName, sizeof(WCHAR) * cchSize);
  494.             if (NO_ERROR != dwRet)
  495.             {
  496.                 *wszFriendlyName = 0;
  497.             }
  498.         }
  499.     }
  500.     if (!*wszFriendlyName)
  501.     {
  502.         // BUGBUG: we failed to get a friendly name, so use the default one
  503.         StrCpyNW(wszFriendlyName, L"Local Area Connection", cchSize);
  504.     }
  505. }
  506.     
  507. VOID SetStaticIPAddressAndSubnetMask()
  508. {
  509.     DWORD dwRet;
  510.     
  511.     WCHAR wszFriendlyName[128];
  512.     TCHAR szFriendlyName[128];
  513.     TCHAR szCmdLine[256];
  514.     
  515.     PROCESS_INFORMATION pi = { 0 };
  516.     STARTUPINFO si = { 0 };
  517.     si.cb = sizeof(si);
  518.     // get friendly name of tcp/ip interface
  519.     GetTcpIpInterfaceFriendlyName(wszFriendlyName, ARRAYSIZE(wszFriendlyName));
  520.     ASSERT(*wszFriendlyName);
  521.     SHUnicodeToTChar(wszFriendlyName, szFriendlyName, ARRAYSIZE(szFriendlyName));
  522.     // set static IP address and subnet mask
  523.     wsprintf(szCmdLine, TEXT("netsh interface ip set address "%s" static 10.10.1.1 255.0.0.0 NONE"), szFriendlyName);
  524.     if (CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  525.     {
  526.         dwRet = SHWaitForSendMessageThread(pi.hProcess, INFINITE);
  527.         ASSERT(dwRet == WAIT_OBJECT_0);
  528.         CloseHandle(pi.hThread);
  529.         CloseHandle(pi.hProcess);
  530.     }
  531.     // set DNS server address for safety
  532.     ZeroMemory(&pi, sizeof(pi));
  533.     ZeroMemory(&si, sizeof(si));
  534.     si.cb = sizeof(si);
  535.     wsprintf(szCmdLine, TEXT("netsh interface ip set dns "%s" 10.10.1.1"), szFriendlyName);
  536.     if (CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  537.     {
  538.         dwRet = SHWaitForSendMessageThread(pi.hProcess, INFINITE);
  539.         ASSERT(dwRet == WAIT_OBJECT_0);
  540.         CloseHandle(pi.hThread);
  541.         CloseHandle(pi.hProcess);
  542.     }
  543. }