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.

1109 lines
36 KiB

  1. // main.cpp : Implementation of DLL Exports.
  2. #include "StdAfx.h"
  3. #include "resource.h"
  4. #include "main.h"
  5. #include "PromptForPathDlg.h"
  6. #include "cmdline.h"
  7. #include <shlobj.h>
  8. #include "stdio.h"
  9. CComModule _Module;
  10. VOID DisableBalloons( BOOL bDisable );
  11. /////////////////////////////////////////////////////////////////////////////
  12. //
  13. VOID AddBS( TCHAR* psz )
  14. {
  15. if( !_tcslen(psz) )
  16. {
  17. return;
  18. }
  19. const TCHAR *szTemp = psz;
  20. const UINT iSize = _tcslen(psz);
  21. // MBCS-safe walk thru string to last char
  22. for (UINT ui = 0; ui < iSize; ui++)
  23. szTemp = CharNext(szTemp);
  24. // See if the last char is a "\"
  25. if (_tcsncmp( szTemp, _T("\\"), 1))
  26. {
  27. // Append a backslash
  28. _tcscat( psz, _T("\\") );
  29. }
  30. }
  31. int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
  32. {
  33. USES_CONVERSION;
  34. CoInitialize(NULL);
  35. _Module.Init(NULL, hInstance);
  36. TCHAR* pszLocation = NULL;
  37. // Necessary to grab argv[0] too so we can successfully parse argv[1] flag later... (_FindOption)
  38. lpCmdLine = GetCommandLine();
  39. if ( _tcsstr(lpCmdLine, _T("winsb")) )
  40. {
  41. g_bWinSB = TRUE;
  42. }
  43. else
  44. {
  45. g_bWinSB = FALSE;
  46. }
  47. INT iRetVal = 0;
  48. TCHAR szPath[MAX_PATH * 2];
  49. g_bSBS = FALSE;
  50. OSVERSIONINFO cInfo;
  51. cInfo.dwOSVersionInfoSize = sizeof( cInfo );
  52. if (!GetVersionEx( &cInfo ))
  53. goto CLEAN_UP;
  54. if( cInfo.dwMajorVersion >= 5 )
  55. {
  56. OSVERSIONINFOEX cInfoEx;
  57. cInfoEx.dwOSVersionInfoSize = sizeof( cInfoEx );
  58. GetVersionEx( (OSVERSIONINFO*)&cInfoEx );
  59. if( (cInfoEx.wSuiteMask & VER_SUITE_SMALLBUSINESS) || (cInfoEx.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED) )
  60. {
  61. g_bSBS = TRUE;
  62. }
  63. }
  64. // Supress the balloons!!
  65. DisableBalloons(TRUE);
  66. // look for the /suppresscys switch
  67. if( SUCCEEDED(CheckSuppressCYS(lpCmdLine)) )
  68. {
  69. goto CLEAN_UP;
  70. }
  71. // look for the /dcpromo switch on the command line. if it's there, setup to re-startup
  72. // with the rest of the command line, and then launch dcpromo.exe
  73. if( SUCCEEDED(CheckDCPromoSwitch(lpCmdLine)) )
  74. {
  75. // can check here for needing to show a message (i.e. if hr == S_FALSE)
  76. goto CLEAN_UP;
  77. }
  78. // if we didn't find /dcpromo, look for /bossetup and /bosunattend
  79. if( SUCCEEDED(CheckBOSSwitch(lpCmdLine)) )
  80. {
  81. // can check here for needing to show a message (i.e. if hr == S_FALSE)
  82. goto CLEAN_UP;
  83. }
  84. // Parse the cmdLine arguments to find out if we are setting up for BOS/SBS 5.0 Setup.
  85. INT iRunSetup = ParseCmdLine( lpCmdLine );
  86. // ------------------------------------------------------------------------
  87. // Parse command line the "real" way to look for the /l <setup location>
  88. // parameter.
  89. // ------------------------------------------------------------------------
  90. pszLocation = new TCHAR[_tcslen(lpCmdLine)+1];
  91. if ( !pszLocation )
  92. {
  93. goto CLEAN_UP;
  94. }
  95. _tcscpy( pszLocation, _T("") );
  96. if( pszLocation != NULL )
  97. {
  98. LPCTSTR lpszToken;
  99. LPTSTR pszCurrentPos;
  100. for ( lpszToken = _FindOption(lpCmdLine) ; // Init to no bad usage and get the first param.
  101. (lpszToken != NULL) && (pszCurrentPos = const_cast<LPTSTR>(lpszToken)) ; // While no bad usage and we still have a param...
  102. lpszToken = _FindOption(pszCurrentPos) ) // Get the next parameter.
  103. {
  104. switch(*pszCurrentPos)
  105. {
  106. case _T('l'): // /l <setup location>
  107. case _T('L'):
  108. {
  109. _ReadParam(pszCurrentPos, pszLocation);
  110. break;
  111. }
  112. }
  113. }
  114. }
  115. if ( iRunSetup )
  116. {
  117. // safely construct path from commandline if it exists.
  118. AddBS(pszLocation);
  119. INT iLaunchSetup = 1;
  120. CComBSTR bszPath = pszLocation ? pszLocation : _T("");
  121. CComBSTR bszFilename = _T("setup.exe");
  122. CComBSTR bszSetupFile = _T("");
  123. bszSetupFile += bszPath;
  124. bszSetupFile += bszFilename;
  125. // First try out the path we got from the command line
  126. if( !VerifyPath((TCHAR*)OLE2T(bszSetupFile)) )
  127. {
  128. // If not, try getting one from the registry.
  129. TCHAR * szSourcePath = new TCHAR[MAX_PATH];
  130. if (szSourcePath)
  131. {
  132. if ( !GetSourcePath( szSourcePath, MAX_PATH ) )
  133. {
  134. // Error reading the registry.
  135. szSourcePath[0] = 0;
  136. }
  137. else
  138. {
  139. AddBS(szSourcePath);
  140. }
  141. bszPath = szSourcePath;
  142. delete [] szSourcePath;
  143. }
  144. // Launch BO Setup
  145. bszSetupFile = _T("");
  146. bszSetupFile += bszPath;
  147. bszSetupFile += bszFilename;
  148. // Try the default directory.
  149. if ( !VerifyPath((TCHAR*)OLE2T(bszSetupFile)) )
  150. {
  151. // If BOS/SBS setup.exe isn't there, prompt them for it.
  152. iLaunchSetup = PromptForPath( &bszPath );
  153. }
  154. }
  155. else
  156. {
  157. // clean off trailing backslash from bszPath so that the append of \setup.exe works.
  158. // the conditional logic here is a little ugly, but it works.
  159. WCHAR wszPath[MAX_PATH];
  160. int cbPathSize;
  161. wcscpy( wszPath, (WCHAR *)OLE2W(bszPath) );
  162. cbPathSize = wcslen( wszPath );
  163. wszPath[cbPathSize-1] = '\0';
  164. bszPath = wszPath;
  165. }
  166. // If the user wants to run setup...
  167. if ( iLaunchSetup )
  168. {
  169. CComBSTR bstrEXE = bszPath;
  170. // NOTE: No longer branching here because both WinSB and SBS have the same CD layout now.
  171. // if ( _tcsstr(lpCmdLine, _T("winsb")) ) // In the WinSB SKU, setup.exe is in a different dir.
  172. // {
  173. bstrEXE += _T("\\setup\\i386\\setup.exe");
  174. // }
  175. // else
  176. // {
  177. // bstrEXE += _T("\\sbs\\i386\\setup.exe");
  178. // }
  179. CComBSTR bstrRun = _T("setup.exe /chain");
  180. // CreateProcess.
  181. STARTUPINFO suinfo;
  182. memset( &suinfo, 0, sizeof(STARTUPINFO) );
  183. suinfo.cb = sizeof( STARTUPINFO );
  184. PROCESS_INFORMATION pinfo;
  185. if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &suinfo, &pinfo) )
  186. {
  187. CloseHandle(pinfo.hProcess);
  188. CloseHandle(pinfo.hThread);
  189. }
  190. }
  191. else
  192. {
  193. // Nothing I guess.. let's just continue on with the cleanup.
  194. }
  195. // Clean up (remove BOSPrep.exe).
  196. TCHAR szSBS[MAX_PATH];
  197. LoadString( _Module.m_hInst, IDS_SBSSwitch, szSBS, sizeof(szSBS) / sizeof(TCHAR) );
  198. if( _tcsstr(lpCmdLine, szSBS) )
  199. {
  200. TCHAR szExe[MAX_PATH];
  201. LoadString( _Module.m_hInst, IDS_EXEName, szExe, sizeof(szExe) / sizeof(TCHAR) );
  202. SHGetSpecialFolderPath( NULL, szPath, CSIDL_SYSTEM, FALSE );
  203. AddBS( szPath );
  204. _tcscat( szPath, szExe );
  205. }
  206. else
  207. {
  208. TCHAR* szDrive = NULL;
  209. GetSystemDrive(&szDrive);
  210. lstrcpyn( szPath, szDrive, MAX_PATH );
  211. delete [] szDrive;
  212. AddBS( szPath );
  213. _tcscat( szPath, _T("bosprep.exe"));
  214. }
  215. MoveFileEx( szPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
  216. // Clean up (remove the shortcut from the StartUp folder).
  217. TCHAR szLinkPath[MAX_PATH + 64];
  218. if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) )
  219. {
  220. TCHAR szTmp[64];
  221. LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) );
  222. _tcscat( szLinkPath, szTmp );
  223. DeleteFile( szLinkPath );
  224. }
  225. }
  226. else
  227. {
  228. // Fix up the userinit regkey to make sure that DCPromo.exe is not in there.
  229. RemoveFromUserinit( _T("DCPromo") );
  230. // Suppress the Configure Your Server page.
  231. SuppressCfgSrvPage();
  232. // Add ourself to the StartUp with the /setup option so that we can
  233. // begin BackOffice setup.
  234. TCHAR szLinkPath[MAX_PATH];
  235. // JeffZi: bosprep.exe will be copied to %PROGFILESDIR%\Microsoft BackOffice\Setup, except for
  236. // SBS clean install cases, where it will be in %windir%\system32
  237. if( _tcsstr(lpCmdLine, _T("sbs")) || _tcsstr(lpCmdLine, _T("winsb")) )
  238. {
  239. TCHAR szExe[MAX_PATH];
  240. LoadString( _Module.m_hInst, IDS_EXEName, szExe, sizeof(szExe) / sizeof(TCHAR) );
  241. SHGetSpecialFolderPath( NULL, szPath, CSIDL_SYSTEM, FALSE );
  242. AddBS( szPath );
  243. _tcscat( szPath, szExe );
  244. }
  245. else
  246. {
  247. TCHAR* szDrive = NULL;
  248. GetSystemDrive(&szDrive);
  249. _tcsncpy( szPath, szDrive, sizeof(szPath) / sizeof(TCHAR) );
  250. delete [] szDrive;
  251. AddBS( szPath );
  252. _tcscat( szPath, _T("bosprep.exe"));
  253. }
  254. if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) )
  255. {
  256. TCHAR szArgs[128]; // Used for IDS_IDS_SetupSwitch ("/setup")
  257. TCHAR szTmp[64]; // Used for IDS_BOlnk ("\\boinst.lnk")
  258. LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) );
  259. _tcscat( szLinkPath, szTmp);
  260. LoadString( _Module.m_hInst, IDS_SetupSwitch, szArgs, sizeof(szArgs)/sizeof(TCHAR) );
  261. if ( _tcsstr(lpCmdLine, _T("winsb")) )
  262. {
  263. _tcscat( szArgs, _T(" /winsb") );
  264. }
  265. // Create the shortcut.
  266. MakeLink(szPath, szLinkPath, szArgs);
  267. }
  268. // Set the AppCompatibility\store.exe regkeys for SBS only.
  269. if ( g_bSBS )
  270. {
  271. HKEY hk = NULL;
  272. CRegKey cKey;
  273. DWORD dwSize = 0;
  274. DWORD dwDisp = 0;
  275. BYTE byTmp;
  276. BYTE byArray[1024];
  277. TCHAR szKeyName[1024];
  278. TCHAR szTmpKey[1024];
  279. TCHAR szTmpVal[4096];
  280. TCHAR *pszToken = NULL;
  281. memset(byArray, 0, 1024);
  282. _tcscpy(szKeyName, _T(""));
  283. _tcscpy(szTmpKey, _T(""));
  284. _tcscpy(szTmpVal, _T(""));
  285. LoadString( _Module.m_hInst, IDS_StoreExeKey, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  286. if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, &dwDisp) == ERROR_SUCCESS )
  287. {
  288. // "DllPatch-SBSUpgrade" = "_sbsw2ku.dll"
  289. /* LoadString( _Module.m_hInst, IDS_DllPatchSBSUpgrade, szTmpKey, sizeof(szTmpKey)/sizeof(TCHAR) );
  290. LoadString( _Module.m_hInst, IDS_DllPatchVal, szTmpVal, sizeof(szTmpVal)/sizeof(TCHAR) );
  291. RegSetValueEx( hk, szTmpKey, NULL, REG_SZ, (LPBYTE)szTmpVal, (_tcslen(szTmpVal)+1)*sizeof(TCHAR) );
  292. */
  293. // "SBSUpgrade"=hex:0C,00,00,00, ... etc
  294. LoadString( _Module.m_hInst, IDS_SBSUpgrade, szTmpKey, sizeof(szTmpKey)/sizeof(TCHAR) );
  295. LoadString( _Module.m_hInst, IDS_SBSUpgradeVal, szTmpVal, sizeof(szTmpVal)/sizeof(TCHAR) );
  296. dwSize = 0;
  297. pszToken = _tcstok(szTmpVal, ",");
  298. while ( pszToken )
  299. {
  300. byTmp = 0;
  301. if(1==_stscanf( pszToken, _T("%x"), &byTmp ))
  302. {
  303. byArray[dwSize++] = byTmp;
  304. }
  305. else
  306. {
  307. byArray[dwSize++]= 0;
  308. }
  309. pszToken = _tcstok(NULL, ",");
  310. }
  311. RegSetValueEx( hk, szTmpKey, NULL, REG_BINARY, byArray, dwSize );
  312. cKey.Close();
  313. }
  314. }
  315. }
  316. CLEAN_UP:
  317. // Exit.
  318. if (pszLocation)
  319. delete [] pszLocation;
  320. CoUninitialize();
  321. _Module.Term();
  322. return iRetVal;
  323. }
  324. // ----------------------------------------------------------------------------
  325. // parseCmdLine()
  326. //
  327. // Goes through the command line and checks if the "/setup" option is
  328. // present. Since this program isn't really meant to be interactively
  329. // launched by the user, we will be a little sloppy with the way we look
  330. // at the commandline arguments. That is, instead of making sure that there
  331. // is only one commandline argument, and that it "/setup"... we will instead
  332. // just try to find "/setup" somewhere in the commandline.
  333. //
  334. // Return:
  335. // 0 if the setup switch string was NOT found in the cmd line.
  336. // 1 if the setup switch string WAS found in the cmd line.
  337. // ----------------------------------------------------------------------------
  338. INT ParseCmdLine( LPTSTR lpCmdLine )
  339. {
  340. TCHAR szSetup[MAX_PATH];
  341. LoadString( _Module.m_hInst, IDS_SetupSwitch, szSetup, sizeof(szSetup)/sizeof(TCHAR) );
  342. // If we find the setup switch string (/setup) in the cmd line, then we are setting
  343. // up to run BackOffice setup, so we'll return 1.
  344. if ( _tcsstr( lpCmdLine, szSetup ) )
  345. return(1);
  346. return(0);
  347. }
  348. // ----------------------------------------------------------------------------
  349. // promptForPath()
  350. //
  351. // Displays UI to the user asking for the location of the BackOffice 5 CD1
  352. // so that we can launch setup.
  353. //
  354. // Return:
  355. // 0 if the user pressed cancel when prompted for the path.
  356. // 1 if we're ready to launch setup!
  357. // ----------------------------------------------------------------------------
  358. INT PromptForPath( BSTR* pbszPath )
  359. {
  360. USES_CONVERSION;
  361. INT_PTR iRet = 0;
  362. CPromptForPathDlg* pPromptDlg = NULL;
  363. TCHAR szTmpMsg[MAX_PATH];
  364. if( !pbszPath )
  365. return (0);
  366. CComBSTR bszDefault = *pbszPath;
  367. if (!bszDefault)
  368. return 0;
  369. SysFreeString( *pbszPath );
  370. HWND hWndParent = GetActiveWindow();
  371. pPromptDlg = new CPromptForPathDlg( bszDefault, _Module.m_hInst, g_bWinSB );
  372. if ( !pPromptDlg ) return(0);
  373. bool bNotDone = true;
  374. while (bNotDone == true)
  375. {
  376. iRet = pPromptDlg->DoModal( hWndParent );
  377. pPromptDlg->m_hWnd = NULL;
  378. if( iRet == IDOK )
  379. {
  380. // leave this as a SysAllocString
  381. *pbszPath = SysAllocString( pPromptDlg->m_bszDef );
  382. if (*pbszPath == NULL)
  383. goto CLEAN_UP;
  384. CComBSTR bszTmp = *pbszPath;
  385. bszTmp += _T("\\setup.exe");
  386. // Check if the path they chose was correct.
  387. if ( VerifyPath((TCHAR*)OLE2T(bszTmp)) )
  388. {
  389. bNotDone = false; // If so, let's just move on.
  390. }
  391. else
  392. {
  393. bNotDone = true; // If not, ask again.
  394. SysFreeString( *pbszPath );
  395. LoadString( _Module.m_hInst, IDS_CantFindMsg, szTmpMsg, sizeof(szTmpMsg)/sizeof(TCHAR) );
  396. TCHAR szTmpTitle[128];
  397. LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBTitle : IDS_SBSTitle, szTmpTitle, sizeof(szTmpTitle)/sizeof(TCHAR) );
  398. ::MessageBox( hWndParent, szTmpMsg, szTmpTitle, MB_OK | MB_ICONEXCLAMATION );
  399. }
  400. }
  401. else if ( iRet == IDCANCEL )
  402. {
  403. INT iDoCancel = 0; // note we do NOT use iRet here
  404. LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBCancelCDPrompt : IDS_SBSCancelCDPrompt, szTmpMsg, sizeof(szTmpMsg)/sizeof(TCHAR) );
  405. TCHAR szTmpTitle[MAX_PATH];
  406. LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBTitle : IDS_SBSTitle, szTmpTitle, sizeof(szTmpTitle)/sizeof(TCHAR) );
  407. iDoCancel = ::MessageBox( hWndParent, szTmpMsg, szTmpTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 );
  408. if ( iDoCancel == IDYES )
  409. {
  410. bNotDone = false;
  411. }
  412. // else we will reprompt them for the CD
  413. }
  414. else
  415. {
  416. // we don't know how to handle any other return values
  417. //::MessageBox(::GetForegroundWindow(), _T("AHhhhhhhhhhh"), _T("DEBUG"), MB_OK);
  418. }
  419. }
  420. CLEAN_UP:
  421. if (pPromptDlg)
  422. {
  423. delete pPromptDlg;
  424. pPromptDlg = NULL;
  425. }
  426. return( iRet==IDOK ? 1 : 0 );
  427. }
  428. // ----------------------------------------------------------------------------
  429. // removeFromUserinit()
  430. //
  431. // Opens the Userinit registry key and searches for the 'szToRemove' string.
  432. // If it finds the string, it removes that entry from the string.
  433. // (i.e. it removes the string and also the following comma and spaces).
  434. //
  435. // NOTE: This function only removes the first occurance of the szToRemove.
  436. // If you want to remove all occurances, simply loop around this
  437. // function until the returned value is 0.
  438. //
  439. // Return:
  440. // 0 if an error of any kind occured.
  441. // 1 if everything went as planned.
  442. // ----------------------------------------------------------------------------
  443. INT RemoveFromUserinit(const TCHAR * szToRemove)
  444. {
  445. TCHAR szToRemCpy[MAX_PATH];
  446. TCHAR szKeyName[MAX_PATH];
  447. TCHAR * szBuffer = NULL;
  448. TCHAR * szTmpBuf = NULL;
  449. TCHAR * ptc = NULL;
  450. TCHAR * p = NULL;
  451. TCHAR * q = NULL;
  452. DWORD dwOffset = 0;
  453. DWORD dwLen = 0;
  454. BOOL bAlreadyFixed = FALSE;
  455. CRegKey cKey;
  456. // Check to make sure a valid string was passed in.
  457. // ASSERT(szToRemove);
  458. if (!szToRemove)
  459. return(0); // If error, return 0.
  460. // Copy the passed in string to our "szToRemCpy"
  461. _tcsncpy(szToRemCpy, szToRemove, MAX_PATH);
  462. szToRemCpy[MAX_PATH-1] = 0;
  463. // Try to open the regkey.
  464. LoadString( _Module.m_hInst, IDS_UserInitKeyLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  465. if ( cKey.Open(HKEY_LOCAL_MACHINE, szKeyName) != ERROR_SUCCESS )
  466. return(0); // If error, return 0.
  467. if ( !(szBuffer = new TCHAR[MAX_PATH]) ) // Malloc and check...
  468. {
  469. // ASSERT(FALSE);
  470. cKey.Close(); // Close the regkey.
  471. return(0); // If error, return 0.
  472. }
  473. // Try to get the value of "userinit"
  474. dwLen = MAX_PATH;
  475. LoadString( _Module.m_hInst, IDS_UserInitKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  476. if ( cKey.QueryValue(szBuffer, szKeyName, &dwLen) != ERROR_SUCCESS )
  477. {
  478. delete[] szBuffer; // Free up that memory.
  479. cKey.Close(); // Close the regkey.
  480. return(0); // If error, return 0.
  481. }
  482. _tcslwr(szBuffer); // Convert to lowercase.
  483. _tcslwr(szToRemCpy); // Convert to lowercase.
  484. // See if the 'szToRemCpy' string is in the userinit string.
  485. if ( (ptc = _tcsstr(szBuffer, szToRemCpy)) == NULL )
  486. {
  487. delete[] szBuffer;
  488. cKey.Close(); // Close the regkey.
  489. return(0);
  490. }
  491. dwOffset = _tcslen(szToRemCpy);
  492. for ( ; (ptc != szBuffer) && (*ptc != _T(',')); ptc--, dwOffset++ ); // Find the comma before this if it exists.
  493. // AHHHHHHHHHHHHHHHHH.. fix that char (',').
  494. if ( ptc != szBuffer ) // If we found a comma,
  495. bAlreadyFixed = true; // then signal that we already removed a comma.
  496. // Now that we know that the string to remove is indeed in the userinit regkey (and 'ptc' points to
  497. // the beginning of that sub string), we can copy all of the old buffer into the new buffer and
  498. // just omit the szToRemove part.
  499. if ( !(szTmpBuf = new TCHAR[dwLen]) )
  500. {
  501. // ASSERT(FALSE);
  502. delete[] szBuffer;
  503. cKey.Close();
  504. return(0);
  505. }
  506. // p = Source string
  507. // q = Target string
  508. for ( p = szBuffer, q = szTmpBuf; (*p != 0) && (p != ptc); *q++ = *p++ ); // Copy until we hit the beginning of what we want to remove.
  509. if ( *p != 0 )
  510. p += dwOffset; // Move our source pointer forward.
  511. for ( ; (*p != 0) && (*p != _T(',')); p++ ); // AHHHHHHHHHHHHHHHHH.. fix that char (',').
  512. if ( !bAlreadyFixed )
  513. { // If we haven't already removed a comma,
  514. if (*p != 0)
  515. p++; // then let's remove this one.
  516. }
  517. for ( ; (*p != 0) && (_istspace(*p)); p++ ); // Find the beginning of the next program.
  518. for ( ; *p != 0; *q++ = *p++ ); // Now copy until the end.
  519. *q = 0;
  520. // Now right the new and improved string to the registry.
  521. LoadString( _Module.m_hInst, IDS_UserInitKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  522. cKey.SetValue( szTmpBuf, szKeyName );
  523. delete[] szTmpBuf; // Free up that memory.
  524. delete[] szBuffer; // Free up that memory.
  525. cKey.Close(); // Close the regkey.
  526. return(1); // Return success.
  527. }
  528. // ----------------------------------------------------------------------------
  529. // suppressCfgSrvPage()
  530. //
  531. // Opens the "show" registry key and changes it's value to 0 to turn off the
  532. // "Configure Your Server" screen.
  533. //
  534. // Return:
  535. // 0 if an error of any kind occured.
  536. // 1 if everything went as planned.
  537. // ----------------------------------------------------------------------------
  538. INT SuppressCfgSrvPage(void)
  539. {
  540. TCHAR szKeyName[MAX_PATH];
  541. DWORD dwTmp=0;
  542. CRegKey cKey;
  543. // Try to open the regkey.
  544. LoadString( _Module.m_hInst, IDS_CfgSrvKeyLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  545. if ( cKey.Open(HKEY_CURRENT_USER, szKeyName) != ERROR_SUCCESS )
  546. return(0); // If error, return 0.
  547. // Try to set the value.
  548. LoadString( _Module.m_hInst, IDS_CfgSrvKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  549. if ( cKey.SetValue(dwTmp, szKeyName) != ERROR_SUCCESS )
  550. {
  551. cKey.Close(); // Close the regkey.
  552. return(0); // If error, return 0.
  553. }
  554. cKey.Close();
  555. return(1);
  556. }
  557. INT GetSourcePath( TCHAR * szPath, DWORD dwCount )
  558. {
  559. TCHAR szKeyName[MAX_PATH];
  560. CRegKey cKey;
  561. DWORD dw = dwCount;
  562. // Try to open the regkey.
  563. LoadString( _Module.m_hInst, IDS_SourcePathLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  564. if ( cKey.Open(HKEY_LOCAL_MACHINE, szKeyName) != ERROR_SUCCESS )
  565. return(0);
  566. // Try to get the value
  567. LoadString( _Module.m_hInst, IDS_SourcePathName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
  568. if ( cKey.QueryValue( szPath, szKeyName, &dw ) != ERROR_SUCCESS )
  569. {
  570. cKey.Close();
  571. return(0);
  572. }
  573. cKey.Close();
  574. return(1);
  575. }
  576. // ----------------------------------------------------------------------------
  577. // verifyPath()
  578. //
  579. // Checks to make sure that the BOS/SBS setup.exe exists at the given location.
  580. //
  581. // Returns:
  582. // 0 if BOS/SBS setup was not found at that location
  583. // 1 if setup WAS found at the location.
  584. // ----------------------------------------------------------------------------
  585. INT VerifyPath( const TCHAR *szPath )
  586. {
  587. if( !szPath )
  588. return (0);
  589. return (INVALID_FILE_ATTRIBUTES != GetFileAttributes(szPath));
  590. }
  591. // ----------------------------------------------------------------------------
  592. // makeLink()
  593. //
  594. // This function creates a shortcut, "sourcePath," that points to "linkPath"
  595. // with the commandline arguments of "args."
  596. //
  597. // Return:
  598. // S_OK if the shortcut was successfully created.
  599. // Some sort of error (FAILED(hr)) if any error occured.
  600. // ----------------------------------------------------------------------------
  601. HRESULT MakeLink(const TCHAR* const sourcePath, const TCHAR* const linkPath, const TCHAR* const args)
  602. {
  603. if ( !sourcePath || !linkPath || !args )
  604. return(E_FAIL);
  605. IShellLink* pShellLink = NULL;
  606. HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  607. IID_IShellLink, reinterpret_cast<void**>(&pShellLink));
  608. if (FAILED(hr))
  609. goto CLEAN_UP;
  610. hr = pShellLink->SetPath(sourcePath);
  611. if (FAILED(hr))
  612. goto CLEAN_UP;
  613. hr = pShellLink->SetArguments(args);
  614. if (FAILED(hr))
  615. goto CLEAN_UP;
  616. IPersistFile* pPersistFile = NULL;
  617. hr = pShellLink->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&pPersistFile));
  618. if (FAILED(hr))
  619. goto CLEAN_UP;
  620. USES_CONVERSION;
  621. hr = pPersistFile->Save(T2OLE(linkPath), TRUE);
  622. if (FAILED(hr))
  623. return hr;
  624. CLEAN_UP:
  625. if (pPersistFile)
  626. pPersistFile->Release();
  627. if (pShellLink)
  628. pShellLink->Release();
  629. return hr;
  630. }
  631. HRESULT CheckDCPromoSwitch( TCHAR* pszCmdLine )
  632. {
  633. HRESULT hr = S_OK;
  634. CComBSTR bstrRun;
  635. CComBSTR bstrEXE;
  636. TCHAR* pszDCPromo = NULL;
  637. TCHAR* pszBOSUnattend = NULL;
  638. TCHAR* pszBOSSetup = NULL;
  639. TCHAR* pszNewCmd = NULL;
  640. if (!pszCmdLine)
  641. return E_INVALIDARG;
  642. pszDCPromo = new TCHAR[_tcslen(pszCmdLine) + 1];
  643. if (!pszDCPromo)
  644. return E_OUTOFMEMORY;
  645. GetParameter( pszCmdLine, _T("/dcpromo"), pszDCPromo );
  646. if( !_tcslen(pszDCPromo) )
  647. {
  648. hr = E_FAIL;
  649. goto CLEAN_UP;
  650. }
  651. // make sure that /bosunattend and /bossetup are on the cmd line as well
  652. pszBOSUnattend = new TCHAR[_tcslen(pszCmdLine) + 1];
  653. if (!pszBOSUnattend)
  654. {
  655. hr = E_OUTOFMEMORY;
  656. goto CLEAN_UP;
  657. }
  658. GetParameter( pszCmdLine, _T("/bosunattend"), pszBOSUnattend );
  659. pszBOSSetup = new TCHAR[_tcslen(pszCmdLine) + 1];
  660. if (!pszBOSSetup)
  661. {
  662. hr = E_OUTOFMEMORY;
  663. goto CLEAN_UP;
  664. }
  665. GetParameter( pszCmdLine, _T("/bossetup"), pszBOSSetup );
  666. if( !_tcslen(pszBOSSetup) || !_tcslen(pszBOSUnattend) )
  667. {
  668. hr = S_FALSE;
  669. goto CLEAN_UP;
  670. }
  671. // build the new command line (basically remove the dcpromo switch)
  672. pszNewCmd = new TCHAR[_tcslen(pszBOSSetup) + _tcslen(pszBOSUnattend) + MAX_PATH];
  673. if (!pszNewCmd)
  674. {
  675. hr = E_OUTOFMEMORY;
  676. goto CLEAN_UP;
  677. }
  678. _tcscpy( pszNewCmd, _T("/bosunattend ") );
  679. _tcscat( pszNewCmd, pszBOSUnattend );
  680. _tcscat( pszNewCmd, _T(" /bossetup ") );
  681. _tcscat( pszNewCmd, pszBOSSetup );
  682. // get the path to our exe
  683. TCHAR szOurPath[MAX_PATH * 2];
  684. if (!GetModuleFileName( NULL, szOurPath, MAX_PATH * 2 ))
  685. {
  686. hr = HRESULT_FROM_WIN32(GetLastError());
  687. goto CLEAN_UP;
  688. }
  689. // make the path to the .lnk
  690. TCHAR szTmp[64]; // Used for IDS_BOlnk ("\\boinst.lnk")
  691. if (0 == LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) ))
  692. {
  693. hr = HRESULT_FROM_WIN32(GetLastError());
  694. goto CLEAN_UP;
  695. }
  696. TCHAR szLinkPath[MAX_PATH + 64];
  697. if (!SHGetSpecialFolderPath( NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE ))
  698. {
  699. // MSDN doesn't indicate that SHGetSpecialFolderPath sets GetLastError
  700. hr = E_FAIL;
  701. goto CLEAN_UP;
  702. }
  703. _tcscat( szLinkPath, szTmp );
  704. // create the startup link
  705. if (FAILED(hr = MakeLink( szOurPath, szLinkPath, pszNewCmd )))
  706. goto CLEAN_UP;
  707. // run dcpromo.exe with the command line
  708. // Ensure path is enclosed in quotes
  709. bstrEXE = _T("\"");
  710. TCHAR szPath[MAX_PATH] = {0};
  711. if (0 == GetSystemDirectory(szPath, sizeof(szPath) / sizeof(TCHAR)))
  712. {
  713. hr = HRESULT_FROM_WIN32(GetLastError());
  714. goto CLEAN_UP;
  715. }
  716. bstrEXE += szPath;
  717. bstrEXE += _T("dcpromo.exe\"");
  718. bstrRun = _T("dcpromo.exe /answer:");
  719. bstrRun += pszDCPromo;
  720. USES_CONVERSION;
  721. STARTUPINFO si;
  722. PROCESS_INFORMATION pi;
  723. DWORD dwRet;
  724. memset( &si, 0, sizeof(STARTUPINFO) );
  725. si.cb = sizeof( STARTUPINFO );
  726. if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi) )
  727. {
  728. do
  729. {
  730. dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 100, QS_ALLINPUT);
  731. if (dwRet == WAIT_OBJECT_0 + 1)
  732. {
  733. MSG msg;
  734. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  735. {
  736. TranslateMessage(&msg);
  737. DispatchMessage(&msg);
  738. }
  739. }
  740. }
  741. while (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED);
  742. CloseHandle(pi.hProcess);
  743. CloseHandle(pi.hThread);
  744. }
  745. CLEAN_UP:
  746. if (pszDCPromo)
  747. delete [] pszDCPromo;
  748. if (pszBOSUnattend)
  749. delete [] pszBOSUnattend;
  750. if (pszBOSSetup)
  751. delete [] pszBOSSetup;
  752. if (pszNewCmd)
  753. delete [] pszNewCmd;
  754. return hr;
  755. }
  756. HRESULT CheckBOSSwitch( TCHAR* pszCmdLine )
  757. {
  758. HRESULT hr = S_OK;
  759. CComBSTR bstrEXE;
  760. CComBSTR bstrRun;
  761. TCHAR* pszBOSUnattend = NULL;
  762. TCHAR* pszBOSSetup = NULL;
  763. // remove the old .lnk file
  764. TCHAR szLinkPath[MAX_PATH + 64];
  765. if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) )
  766. {
  767. TCHAR szTmp[64];
  768. LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) );
  769. _tcscat( szLinkPath, szTmp );
  770. DeleteFile( szLinkPath );
  771. }
  772. // look for the switches
  773. pszBOSUnattend = new TCHAR[_tcslen(pszCmdLine) + 1];
  774. if (!pszCmdLine)
  775. {
  776. hr = E_OUTOFMEMORY;
  777. goto CLEAN_UP;
  778. }
  779. GetParameter( pszCmdLine, _T("/bosunattend"), pszBOSUnattend );
  780. pszBOSSetup = new TCHAR[_tcslen(pszCmdLine) + 1];
  781. if (!pszBOSSetup)
  782. {
  783. hr = E_OUTOFMEMORY;
  784. goto CLEAN_UP;
  785. }
  786. GetParameter( pszCmdLine, _T("/bossetup"), pszBOSSetup );
  787. if( !_tcslen(pszBOSSetup) || !_tcslen(pszBOSUnattend) )
  788. {
  789. hr = E_FAIL;
  790. goto CLEAN_UP;
  791. }
  792. USES_CONVERSION;
  793. // build the path via the bossetup, the unattend switch, then the unattend file
  794. bstrEXE = _T("\""); // Ensure path is in quotes
  795. bstrEXE += T2OLE(pszBOSSetup);
  796. bstrEXE += _T("\"");
  797. bstrRun = _T("/unattendfile ");
  798. bstrRun += T2OLE(pszBOSUnattend);
  799. STARTUPINFO si;
  800. PROCESS_INFORMATION pi;
  801. DWORD dwRet;
  802. memset( &si, 0, sizeof(STARTUPINFO) );
  803. si.cb = sizeof( STARTUPINFO );
  804. if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi) )
  805. {
  806. do
  807. {
  808. dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 100, QS_ALLINPUT);
  809. if (dwRet == WAIT_OBJECT_0 + 1)
  810. {
  811. MSG msg;
  812. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  813. {
  814. TranslateMessage(&msg);
  815. DispatchMessage(&msg);
  816. }
  817. }
  818. }
  819. while (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED);
  820. CloseHandle(pi.hProcess);
  821. CloseHandle(pi.hThread);
  822. }
  823. CLEAN_UP:
  824. if (pszBOSUnattend)
  825. delete [] pszBOSUnattend;
  826. if (pszBOSSetup)
  827. delete [] pszBOSSetup;
  828. return hr;
  829. }
  830. VOID GetParameter( TCHAR* pszCmdLine, TCHAR* pszFindSwitch, TCHAR* pszOut )
  831. {
  832. HRESULT hr = S_OK;
  833. if ( pszOut )
  834. _tcscpy( pszOut, _T("") );
  835. if (!pszCmdLine || !pszFindSwitch || !pszOut)
  836. return;
  837. TCHAR* psz = new TCHAR[_tcslen(pszCmdLine) + 1];
  838. if (!psz)
  839. {
  840. hr = E_OUTOFMEMORY;
  841. goto CLEAN_UP;
  842. }
  843. _tcscpy( psz, pszCmdLine );
  844. _tcslwr( psz );
  845. // look for the switch
  846. TCHAR* pszSwitch = NULL;
  847. if( !(pszSwitch = _tcsstr(psz, pszFindSwitch)) )
  848. {
  849. goto CLEAN_UP;
  850. }
  851. // find the space
  852. for( ; *pszSwitch && !_istspace(*pszSwitch); ++pszSwitch );
  853. if( !(*pszSwitch) || !(*(++pszSwitch)) )
  854. {
  855. goto CLEAN_UP;
  856. }
  857. // if we have a ", we'll look for the next ", else look for a space
  858. bool bQuote = false;
  859. TCHAR* pszStart = pszSwitch;
  860. if( *pszSwitch == _T('"') )
  861. {
  862. bQuote = true;
  863. ++pszSwitch;
  864. }
  865. // inc the pointer until we get either a " or a space
  866. for( ; *pszSwitch && (bQuote ? (*pszSwitch != _T('"')) : (!_istspace(*pszSwitch))); ++pszSwitch );
  867. // if we're at the end and were looking for a quote, fail.
  868. if( !(*pszSwitch) && bQuote )
  869. {
  870. goto CLEAN_UP;
  871. }
  872. // if we have a ", inc past it
  873. else if( bQuote )
  874. {
  875. ++pszSwitch;
  876. }
  877. *pszSwitch = 0;
  878. _tcscpy( pszOut, pszStart );
  879. CLEAN_UP:
  880. if (psz)
  881. delete [] psz;
  882. return;
  883. }
  884. HRESULT CheckSuppressCYS( TCHAR* pszCmdLine )
  885. {
  886. HRESULT hr = S_OK;
  887. if (!pszCmdLine)
  888. return E_INVALIDARG;
  889. TCHAR* psz = new TCHAR[_tcslen(pszCmdLine) + 1];
  890. if (!psz)
  891. return E_OUTOFMEMORY;
  892. _tcscpy( psz, pszCmdLine );
  893. _tcslwr( psz );
  894. if( _tcsstr(psz, "/suppresscys") )
  895. {
  896. SuppressCfgSrvPage();
  897. }
  898. else
  899. {
  900. hr = E_FAIL;
  901. }
  902. if (psz)
  903. delete [] psz;
  904. return hr;
  905. }
  906. // ----------------------------------------------------------------------------
  907. // DisableBalloons()
  908. //
  909. // This function uses the following regkey to disable all balloon messages:
  910. // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
  911. // EnableBalloonTips = 0x0 or 0x1
  912. //
  913. // If bDisable = TRUE, then we disable the balloons (0x0)
  914. // if bDisable = FALSE, then we enable the balloons (0x1)
  915. // ----------------------------------------------------------------------------
  916. VOID DisableBalloons( BOOL bDisable )
  917. {
  918. HKEY hk = NULL;
  919. DWORD dwVal = bDisable ? 0x0 : 0x1;
  920. RegCreateKeyEx( HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), NULL, NULL, NULL, KEY_ALL_ACCESS, NULL, &hk, NULL);
  921. if ( hk )
  922. {
  923. if ( RegSetValueEx(hk, _T("EnableBalloonTips"), NULL, REG_DWORD, (BYTE*)&dwVal, sizeof(dwVal)) != ERROR_SUCCESS )
  924. {
  925. // ASSERT(FALSE);
  926. }
  927. RegCloseKey(hk);
  928. }
  929. }
  930. VOID GetSystemDrive(TCHAR** ppszDrive)
  931. {
  932. if (!ppszDrive)
  933. return;
  934. *ppszDrive = NULL;
  935. TCHAR szWindows[MAX_PATH + 1] = {0};
  936. if (0 != GetWindowsDirectory(szWindows, sizeof(szWindows) / sizeof(TCHAR)))
  937. {
  938. *ppszDrive = new TCHAR[MAX_PATH];
  939. _tsplitpath(szWindows, *ppszDrive, NULL, NULL, NULL);
  940. }
  941. }