// main.cpp : Implementation of DLL Exports. #include "StdAfx.h" #include "resource.h" #include "main.h" #include "PromptForPathDlg.h" #include "cmdline.h" #include #include "stdio.h" CComModule _Module; VOID DisableBalloons( BOOL bDisable ); ///////////////////////////////////////////////////////////////////////////// // VOID AddBS( TCHAR* psz ) { if( !_tcslen(psz) ) { return; } const TCHAR *szTemp = psz; const UINT iSize = _tcslen(psz); // MBCS-safe walk thru string to last char for (UINT ui = 0; ui < iSize; ui++) szTemp = CharNext(szTemp); // See if the last char is a "\" if (_tcsncmp( szTemp, _T("\\"), 1)) { // Append a backslash _tcscat( psz, _T("\\") ); } } int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/) { USES_CONVERSION; CoInitialize(NULL); _Module.Init(NULL, hInstance); TCHAR* pszLocation = NULL; // Necessary to grab argv[0] too so we can successfully parse argv[1] flag later... (_FindOption) lpCmdLine = GetCommandLine(); if ( _tcsstr(lpCmdLine, _T("winsb")) ) { g_bWinSB = TRUE; } else { g_bWinSB = FALSE; } INT iRetVal = 0; TCHAR szPath[MAX_PATH * 2]; g_bSBS = FALSE; OSVERSIONINFO cInfo; cInfo.dwOSVersionInfoSize = sizeof( cInfo ); if (!GetVersionEx( &cInfo )) goto CLEAN_UP; if( cInfo.dwMajorVersion >= 5 ) { OSVERSIONINFOEX cInfoEx; cInfoEx.dwOSVersionInfoSize = sizeof( cInfoEx ); GetVersionEx( (OSVERSIONINFO*)&cInfoEx ); if( (cInfoEx.wSuiteMask & VER_SUITE_SMALLBUSINESS) || (cInfoEx.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED) ) { g_bSBS = TRUE; } } // Supress the balloons!! DisableBalloons(TRUE); // look for the /suppresscys switch if( SUCCEEDED(CheckSuppressCYS(lpCmdLine)) ) { goto CLEAN_UP; } // look for the /dcpromo switch on the command line. if it's there, setup to re-startup // with the rest of the command line, and then launch dcpromo.exe if( SUCCEEDED(CheckDCPromoSwitch(lpCmdLine)) ) { // can check here for needing to show a message (i.e. if hr == S_FALSE) goto CLEAN_UP; } // if we didn't find /dcpromo, look for /bossetup and /bosunattend if( SUCCEEDED(CheckBOSSwitch(lpCmdLine)) ) { // can check here for needing to show a message (i.e. if hr == S_FALSE) goto CLEAN_UP; } // Parse the cmdLine arguments to find out if we are setting up for BOS/SBS 5.0 Setup. INT iRunSetup = ParseCmdLine( lpCmdLine ); // ------------------------------------------------------------------------ // Parse command line the "real" way to look for the /l // parameter. // ------------------------------------------------------------------------ pszLocation = new TCHAR[_tcslen(lpCmdLine)+1]; if ( !pszLocation ) { goto CLEAN_UP; } _tcscpy( pszLocation, _T("") ); if( pszLocation != NULL ) { LPCTSTR lpszToken; LPTSTR pszCurrentPos; for ( lpszToken = _FindOption(lpCmdLine) ; // Init to no bad usage and get the first param. (lpszToken != NULL) && (pszCurrentPos = const_cast(lpszToken)) ; // While no bad usage and we still have a param... lpszToken = _FindOption(pszCurrentPos) ) // Get the next parameter. { switch(*pszCurrentPos) { case _T('l'): // /l case _T('L'): { _ReadParam(pszCurrentPos, pszLocation); break; } } } } if ( iRunSetup ) { // safely construct path from commandline if it exists. AddBS(pszLocation); INT iLaunchSetup = 1; CComBSTR bszPath = pszLocation ? pszLocation : _T(""); CComBSTR bszFilename = _T("setup.exe"); CComBSTR bszSetupFile = _T(""); bszSetupFile += bszPath; bszSetupFile += bszFilename; // First try out the path we got from the command line if( !VerifyPath((TCHAR*)OLE2T(bszSetupFile)) ) { // If not, try getting one from the registry. TCHAR * szSourcePath = new TCHAR[MAX_PATH]; if (szSourcePath) { if ( !GetSourcePath( szSourcePath, MAX_PATH ) ) { // Error reading the registry. szSourcePath[0] = 0; } else { AddBS(szSourcePath); } bszPath = szSourcePath; delete [] szSourcePath; } // Launch BO Setup bszSetupFile = _T(""); bszSetupFile += bszPath; bszSetupFile += bszFilename; // Try the default directory. if ( !VerifyPath((TCHAR*)OLE2T(bszSetupFile)) ) { // If BOS/SBS setup.exe isn't there, prompt them for it. iLaunchSetup = PromptForPath( &bszPath ); } } else { // clean off trailing backslash from bszPath so that the append of \setup.exe works. // the conditional logic here is a little ugly, but it works. WCHAR wszPath[MAX_PATH]; int cbPathSize; wcscpy( wszPath, (WCHAR *)OLE2W(bszPath) ); cbPathSize = wcslen( wszPath ); wszPath[cbPathSize-1] = '\0'; bszPath = wszPath; } // If the user wants to run setup... if ( iLaunchSetup ) { CComBSTR bstrEXE = bszPath; // NOTE: No longer branching here because both WinSB and SBS have the same CD layout now. // if ( _tcsstr(lpCmdLine, _T("winsb")) ) // In the WinSB SKU, setup.exe is in a different dir. // { bstrEXE += _T("\\setup\\i386\\setup.exe"); // } // else // { // bstrEXE += _T("\\sbs\\i386\\setup.exe"); // } CComBSTR bstrRun = _T("setup.exe /chain"); // CreateProcess. STARTUPINFO suinfo; memset( &suinfo, 0, sizeof(STARTUPINFO) ); suinfo.cb = sizeof( STARTUPINFO ); PROCESS_INFORMATION pinfo; if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &suinfo, &pinfo) ) { CloseHandle(pinfo.hProcess); CloseHandle(pinfo.hThread); } } else { // Nothing I guess.. let's just continue on with the cleanup. } // Clean up (remove BOSPrep.exe). TCHAR szSBS[MAX_PATH]; LoadString( _Module.m_hInst, IDS_SBSSwitch, szSBS, sizeof(szSBS) / sizeof(TCHAR) ); if( _tcsstr(lpCmdLine, szSBS) ) { TCHAR szExe[MAX_PATH]; LoadString( _Module.m_hInst, IDS_EXEName, szExe, sizeof(szExe) / sizeof(TCHAR) ); SHGetSpecialFolderPath( NULL, szPath, CSIDL_SYSTEM, FALSE ); AddBS( szPath ); _tcscat( szPath, szExe ); } else { TCHAR* szDrive = NULL; GetSystemDrive(&szDrive); lstrcpyn( szPath, szDrive, MAX_PATH ); delete [] szDrive; AddBS( szPath ); _tcscat( szPath, _T("bosprep.exe")); } MoveFileEx( szPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT ); // Clean up (remove the shortcut from the StartUp folder). TCHAR szLinkPath[MAX_PATH + 64]; if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) ) { TCHAR szTmp[64]; LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) ); _tcscat( szLinkPath, szTmp ); DeleteFile( szLinkPath ); } } else { // Fix up the userinit regkey to make sure that DCPromo.exe is not in there. RemoveFromUserinit( _T("DCPromo") ); // Suppress the Configure Your Server page. SuppressCfgSrvPage(); // Add ourself to the StartUp with the /setup option so that we can // begin BackOffice setup. TCHAR szLinkPath[MAX_PATH]; // JeffZi: bosprep.exe will be copied to %PROGFILESDIR%\Microsoft BackOffice\Setup, except for // SBS clean install cases, where it will be in %windir%\system32 if( _tcsstr(lpCmdLine, _T("sbs")) || _tcsstr(lpCmdLine, _T("winsb")) ) { TCHAR szExe[MAX_PATH]; LoadString( _Module.m_hInst, IDS_EXEName, szExe, sizeof(szExe) / sizeof(TCHAR) ); SHGetSpecialFolderPath( NULL, szPath, CSIDL_SYSTEM, FALSE ); AddBS( szPath ); _tcscat( szPath, szExe ); } else { TCHAR* szDrive = NULL; GetSystemDrive(&szDrive); _tcsncpy( szPath, szDrive, sizeof(szPath) / sizeof(TCHAR) ); delete [] szDrive; AddBS( szPath ); _tcscat( szPath, _T("bosprep.exe")); } if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) ) { TCHAR szArgs[128]; // Used for IDS_IDS_SetupSwitch ("/setup") TCHAR szTmp[64]; // Used for IDS_BOlnk ("\\boinst.lnk") LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) ); _tcscat( szLinkPath, szTmp); LoadString( _Module.m_hInst, IDS_SetupSwitch, szArgs, sizeof(szArgs)/sizeof(TCHAR) ); if ( _tcsstr(lpCmdLine, _T("winsb")) ) { _tcscat( szArgs, _T(" /winsb") ); } // Create the shortcut. MakeLink(szPath, szLinkPath, szArgs); } // Set the AppCompatibility\store.exe regkeys for SBS only. if ( g_bSBS ) { HKEY hk = NULL; CRegKey cKey; DWORD dwSize = 0; DWORD dwDisp = 0; BYTE byTmp; BYTE byArray[1024]; TCHAR szKeyName[1024]; TCHAR szTmpKey[1024]; TCHAR szTmpVal[4096]; TCHAR *pszToken = NULL; memset(byArray, 0, 1024); _tcscpy(szKeyName, _T("")); _tcscpy(szTmpKey, _T("")); _tcscpy(szTmpVal, _T("")); LoadString( _Module.m_hInst, IDS_StoreExeKey, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, &dwDisp) == ERROR_SUCCESS ) { // "DllPatch-SBSUpgrade" = "_sbsw2ku.dll" /* LoadString( _Module.m_hInst, IDS_DllPatchSBSUpgrade, szTmpKey, sizeof(szTmpKey)/sizeof(TCHAR) ); LoadString( _Module.m_hInst, IDS_DllPatchVal, szTmpVal, sizeof(szTmpVal)/sizeof(TCHAR) ); RegSetValueEx( hk, szTmpKey, NULL, REG_SZ, (LPBYTE)szTmpVal, (_tcslen(szTmpVal)+1)*sizeof(TCHAR) ); */ // "SBSUpgrade"=hex:0C,00,00,00, ... etc LoadString( _Module.m_hInst, IDS_SBSUpgrade, szTmpKey, sizeof(szTmpKey)/sizeof(TCHAR) ); LoadString( _Module.m_hInst, IDS_SBSUpgradeVal, szTmpVal, sizeof(szTmpVal)/sizeof(TCHAR) ); dwSize = 0; pszToken = _tcstok(szTmpVal, ","); while ( pszToken ) { byTmp = 0; if(1==_stscanf( pszToken, _T("%x"), &byTmp )) { byArray[dwSize++] = byTmp; } else { byArray[dwSize++]= 0; } pszToken = _tcstok(NULL, ","); } RegSetValueEx( hk, szTmpKey, NULL, REG_BINARY, byArray, dwSize ); cKey.Close(); } } } CLEAN_UP: // Exit. if (pszLocation) delete [] pszLocation; CoUninitialize(); _Module.Term(); return iRetVal; } // ---------------------------------------------------------------------------- // parseCmdLine() // // Goes through the command line and checks if the "/setup" option is // present. Since this program isn't really meant to be interactively // launched by the user, we will be a little sloppy with the way we look // at the commandline arguments. That is, instead of making sure that there // is only one commandline argument, and that it "/setup"... we will instead // just try to find "/setup" somewhere in the commandline. // // Return: // 0 if the setup switch string was NOT found in the cmd line. // 1 if the setup switch string WAS found in the cmd line. // ---------------------------------------------------------------------------- INT ParseCmdLine( LPTSTR lpCmdLine ) { TCHAR szSetup[MAX_PATH]; LoadString( _Module.m_hInst, IDS_SetupSwitch, szSetup, sizeof(szSetup)/sizeof(TCHAR) ); // If we find the setup switch string (/setup) in the cmd line, then we are setting // up to run BackOffice setup, so we'll return 1. if ( _tcsstr( lpCmdLine, szSetup ) ) return(1); return(0); } // ---------------------------------------------------------------------------- // promptForPath() // // Displays UI to the user asking for the location of the BackOffice 5 CD1 // so that we can launch setup. // // Return: // 0 if the user pressed cancel when prompted for the path. // 1 if we're ready to launch setup! // ---------------------------------------------------------------------------- INT PromptForPath( BSTR* pbszPath ) { USES_CONVERSION; INT_PTR iRet = 0; CPromptForPathDlg* pPromptDlg = NULL; TCHAR szTmpMsg[MAX_PATH]; if( !pbszPath ) return (0); CComBSTR bszDefault = *pbszPath; if (!bszDefault) return 0; SysFreeString( *pbszPath ); HWND hWndParent = GetActiveWindow(); pPromptDlg = new CPromptForPathDlg( bszDefault, _Module.m_hInst, g_bWinSB ); if ( !pPromptDlg ) return(0); bool bNotDone = true; while (bNotDone == true) { iRet = pPromptDlg->DoModal( hWndParent ); pPromptDlg->m_hWnd = NULL; if( iRet == IDOK ) { // leave this as a SysAllocString *pbszPath = SysAllocString( pPromptDlg->m_bszDef ); if (*pbszPath == NULL) goto CLEAN_UP; CComBSTR bszTmp = *pbszPath; bszTmp += _T("\\setup.exe"); // Check if the path they chose was correct. if ( VerifyPath((TCHAR*)OLE2T(bszTmp)) ) { bNotDone = false; // If so, let's just move on. } else { bNotDone = true; // If not, ask again. SysFreeString( *pbszPath ); LoadString( _Module.m_hInst, IDS_CantFindMsg, szTmpMsg, sizeof(szTmpMsg)/sizeof(TCHAR) ); TCHAR szTmpTitle[128]; LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBTitle : IDS_SBSTitle, szTmpTitle, sizeof(szTmpTitle)/sizeof(TCHAR) ); ::MessageBox( hWndParent, szTmpMsg, szTmpTitle, MB_OK | MB_ICONEXCLAMATION ); } } else if ( iRet == IDCANCEL ) { INT iDoCancel = 0; // note we do NOT use iRet here LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBCancelCDPrompt : IDS_SBSCancelCDPrompt, szTmpMsg, sizeof(szTmpMsg)/sizeof(TCHAR) ); TCHAR szTmpTitle[MAX_PATH]; LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBTitle : IDS_SBSTitle, szTmpTitle, sizeof(szTmpTitle)/sizeof(TCHAR) ); iDoCancel = ::MessageBox( hWndParent, szTmpMsg, szTmpTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 ); if ( iDoCancel == IDYES ) { bNotDone = false; } // else we will reprompt them for the CD } else { // we don't know how to handle any other return values //::MessageBox(::GetForegroundWindow(), _T("AHhhhhhhhhhh"), _T("DEBUG"), MB_OK); } } CLEAN_UP: if (pPromptDlg) { delete pPromptDlg; pPromptDlg = NULL; } return( iRet==IDOK ? 1 : 0 ); } // ---------------------------------------------------------------------------- // removeFromUserinit() // // Opens the Userinit registry key and searches for the 'szToRemove' string. // If it finds the string, it removes that entry from the string. // (i.e. it removes the string and also the following comma and spaces). // // NOTE: This function only removes the first occurance of the szToRemove. // If you want to remove all occurances, simply loop around this // function until the returned value is 0. // // Return: // 0 if an error of any kind occured. // 1 if everything went as planned. // ---------------------------------------------------------------------------- INT RemoveFromUserinit(const TCHAR * szToRemove) { TCHAR szToRemCpy[MAX_PATH]; TCHAR szKeyName[MAX_PATH]; TCHAR * szBuffer = NULL; TCHAR * szTmpBuf = NULL; TCHAR * ptc = NULL; TCHAR * p = NULL; TCHAR * q = NULL; DWORD dwOffset = 0; DWORD dwLen = 0; BOOL bAlreadyFixed = FALSE; CRegKey cKey; // Check to make sure a valid string was passed in. // ASSERT(szToRemove); if (!szToRemove) return(0); // If error, return 0. // Copy the passed in string to our "szToRemCpy" _tcsncpy(szToRemCpy, szToRemove, MAX_PATH); szToRemCpy[MAX_PATH-1] = 0; // Try to open the regkey. LoadString( _Module.m_hInst, IDS_UserInitKeyLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( cKey.Open(HKEY_LOCAL_MACHINE, szKeyName) != ERROR_SUCCESS ) return(0); // If error, return 0. if ( !(szBuffer = new TCHAR[MAX_PATH]) ) // Malloc and check... { // ASSERT(FALSE); cKey.Close(); // Close the regkey. return(0); // If error, return 0. } // Try to get the value of "userinit" dwLen = MAX_PATH; LoadString( _Module.m_hInst, IDS_UserInitKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( cKey.QueryValue(szBuffer, szKeyName, &dwLen) != ERROR_SUCCESS ) { delete[] szBuffer; // Free up that memory. cKey.Close(); // Close the regkey. return(0); // If error, return 0. } _tcslwr(szBuffer); // Convert to lowercase. _tcslwr(szToRemCpy); // Convert to lowercase. // See if the 'szToRemCpy' string is in the userinit string. if ( (ptc = _tcsstr(szBuffer, szToRemCpy)) == NULL ) { delete[] szBuffer; cKey.Close(); // Close the regkey. return(0); } dwOffset = _tcslen(szToRemCpy); for ( ; (ptc != szBuffer) && (*ptc != _T(',')); ptc--, dwOffset++ ); // Find the comma before this if it exists. // AHHHHHHHHHHHHHHHHH.. fix that char (','). if ( ptc != szBuffer ) // If we found a comma, bAlreadyFixed = true; // then signal that we already removed a comma. // Now that we know that the string to remove is indeed in the userinit regkey (and 'ptc' points to // the beginning of that sub string), we can copy all of the old buffer into the new buffer and // just omit the szToRemove part. if ( !(szTmpBuf = new TCHAR[dwLen]) ) { // ASSERT(FALSE); delete[] szBuffer; cKey.Close(); return(0); } // p = Source string // q = Target string for ( p = szBuffer, q = szTmpBuf; (*p != 0) && (p != ptc); *q++ = *p++ ); // Copy until we hit the beginning of what we want to remove. if ( *p != 0 ) p += dwOffset; // Move our source pointer forward. for ( ; (*p != 0) && (*p != _T(',')); p++ ); // AHHHHHHHHHHHHHHHHH.. fix that char (','). if ( !bAlreadyFixed ) { // If we haven't already removed a comma, if (*p != 0) p++; // then let's remove this one. } for ( ; (*p != 0) && (_istspace(*p)); p++ ); // Find the beginning of the next program. for ( ; *p != 0; *q++ = *p++ ); // Now copy until the end. *q = 0; // Now right the new and improved string to the registry. LoadString( _Module.m_hInst, IDS_UserInitKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); cKey.SetValue( szTmpBuf, szKeyName ); delete[] szTmpBuf; // Free up that memory. delete[] szBuffer; // Free up that memory. cKey.Close(); // Close the regkey. return(1); // Return success. } // ---------------------------------------------------------------------------- // suppressCfgSrvPage() // // Opens the "show" registry key and changes it's value to 0 to turn off the // "Configure Your Server" screen. // // Return: // 0 if an error of any kind occured. // 1 if everything went as planned. // ---------------------------------------------------------------------------- INT SuppressCfgSrvPage(void) { TCHAR szKeyName[MAX_PATH]; DWORD dwTmp=0; CRegKey cKey; // Try to open the regkey. LoadString( _Module.m_hInst, IDS_CfgSrvKeyLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( cKey.Open(HKEY_CURRENT_USER, szKeyName) != ERROR_SUCCESS ) return(0); // If error, return 0. // Try to set the value. LoadString( _Module.m_hInst, IDS_CfgSrvKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( cKey.SetValue(dwTmp, szKeyName) != ERROR_SUCCESS ) { cKey.Close(); // Close the regkey. return(0); // If error, return 0. } cKey.Close(); return(1); } INT GetSourcePath( TCHAR * szPath, DWORD dwCount ) { TCHAR szKeyName[MAX_PATH]; CRegKey cKey; DWORD dw = dwCount; // Try to open the regkey. LoadString( _Module.m_hInst, IDS_SourcePathLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( cKey.Open(HKEY_LOCAL_MACHINE, szKeyName) != ERROR_SUCCESS ) return(0); // Try to get the value LoadString( _Module.m_hInst, IDS_SourcePathName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) ); if ( cKey.QueryValue( szPath, szKeyName, &dw ) != ERROR_SUCCESS ) { cKey.Close(); return(0); } cKey.Close(); return(1); } // ---------------------------------------------------------------------------- // verifyPath() // // Checks to make sure that the BOS/SBS setup.exe exists at the given location. // // Returns: // 0 if BOS/SBS setup was not found at that location // 1 if setup WAS found at the location. // ---------------------------------------------------------------------------- INT VerifyPath( const TCHAR *szPath ) { if( !szPath ) return (0); return (INVALID_FILE_ATTRIBUTES != GetFileAttributes(szPath)); } // ---------------------------------------------------------------------------- // makeLink() // // This function creates a shortcut, "sourcePath," that points to "linkPath" // with the commandline arguments of "args." // // Return: // S_OK if the shortcut was successfully created. // Some sort of error (FAILED(hr)) if any error occured. // ---------------------------------------------------------------------------- HRESULT MakeLink(const TCHAR* const sourcePath, const TCHAR* const linkPath, const TCHAR* const args) { if ( !sourcePath || !linkPath || !args ) return(E_FAIL); IShellLink* pShellLink = NULL; HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast(&pShellLink)); if (FAILED(hr)) goto CLEAN_UP; hr = pShellLink->SetPath(sourcePath); if (FAILED(hr)) goto CLEAN_UP; hr = pShellLink->SetArguments(args); if (FAILED(hr)) goto CLEAN_UP; IPersistFile* pPersistFile = NULL; hr = pShellLink->QueryInterface(IID_IPersistFile, reinterpret_cast(&pPersistFile)); if (FAILED(hr)) goto CLEAN_UP; USES_CONVERSION; hr = pPersistFile->Save(T2OLE(linkPath), TRUE); if (FAILED(hr)) return hr; CLEAN_UP: if (pPersistFile) pPersistFile->Release(); if (pShellLink) pShellLink->Release(); return hr; } HRESULT CheckDCPromoSwitch( TCHAR* pszCmdLine ) { HRESULT hr = S_OK; CComBSTR bstrRun; CComBSTR bstrEXE; TCHAR* pszDCPromo = NULL; TCHAR* pszBOSUnattend = NULL; TCHAR* pszBOSSetup = NULL; TCHAR* pszNewCmd = NULL; if (!pszCmdLine) return E_INVALIDARG; pszDCPromo = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!pszDCPromo) return E_OUTOFMEMORY; GetParameter( pszCmdLine, _T("/dcpromo"), pszDCPromo ); if( !_tcslen(pszDCPromo) ) { hr = E_FAIL; goto CLEAN_UP; } // make sure that /bosunattend and /bossetup are on the cmd line as well pszBOSUnattend = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!pszBOSUnattend) { hr = E_OUTOFMEMORY; goto CLEAN_UP; } GetParameter( pszCmdLine, _T("/bosunattend"), pszBOSUnattend ); pszBOSSetup = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!pszBOSSetup) { hr = E_OUTOFMEMORY; goto CLEAN_UP; } GetParameter( pszCmdLine, _T("/bossetup"), pszBOSSetup ); if( !_tcslen(pszBOSSetup) || !_tcslen(pszBOSUnattend) ) { hr = S_FALSE; goto CLEAN_UP; } // build the new command line (basically remove the dcpromo switch) pszNewCmd = new TCHAR[_tcslen(pszBOSSetup) + _tcslen(pszBOSUnattend) + MAX_PATH]; if (!pszNewCmd) { hr = E_OUTOFMEMORY; goto CLEAN_UP; } _tcscpy( pszNewCmd, _T("/bosunattend ") ); _tcscat( pszNewCmd, pszBOSUnattend ); _tcscat( pszNewCmd, _T(" /bossetup ") ); _tcscat( pszNewCmd, pszBOSSetup ); // get the path to our exe TCHAR szOurPath[MAX_PATH * 2]; if (!GetModuleFileName( NULL, szOurPath, MAX_PATH * 2 )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto CLEAN_UP; } // make the path to the .lnk TCHAR szTmp[64]; // Used for IDS_BOlnk ("\\boinst.lnk") if (0 == LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto CLEAN_UP; } TCHAR szLinkPath[MAX_PATH + 64]; if (!SHGetSpecialFolderPath( NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE )) { // MSDN doesn't indicate that SHGetSpecialFolderPath sets GetLastError hr = E_FAIL; goto CLEAN_UP; } _tcscat( szLinkPath, szTmp ); // create the startup link if (FAILED(hr = MakeLink( szOurPath, szLinkPath, pszNewCmd ))) goto CLEAN_UP; // run dcpromo.exe with the command line // Ensure path is enclosed in quotes bstrEXE = _T("\""); TCHAR szPath[MAX_PATH] = {0}; if (0 == GetSystemDirectory(szPath, sizeof(szPath) / sizeof(TCHAR))) { hr = HRESULT_FROM_WIN32(GetLastError()); goto CLEAN_UP; } bstrEXE += szPath; bstrEXE += _T("dcpromo.exe\""); bstrRun = _T("dcpromo.exe /answer:"); bstrRun += pszDCPromo; USES_CONVERSION; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD dwRet; memset( &si, 0, sizeof(STARTUPINFO) ); si.cb = sizeof( STARTUPINFO ); if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi) ) { do { dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 100, QS_ALLINPUT); if (dwRet == WAIT_OBJECT_0 + 1) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } while (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } CLEAN_UP: if (pszDCPromo) delete [] pszDCPromo; if (pszBOSUnattend) delete [] pszBOSUnattend; if (pszBOSSetup) delete [] pszBOSSetup; if (pszNewCmd) delete [] pszNewCmd; return hr; } HRESULT CheckBOSSwitch( TCHAR* pszCmdLine ) { HRESULT hr = S_OK; CComBSTR bstrEXE; CComBSTR bstrRun; TCHAR* pszBOSUnattend = NULL; TCHAR* pszBOSSetup = NULL; // remove the old .lnk file TCHAR szLinkPath[MAX_PATH + 64]; if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) ) { TCHAR szTmp[64]; LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) ); _tcscat( szLinkPath, szTmp ); DeleteFile( szLinkPath ); } // look for the switches pszBOSUnattend = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!pszCmdLine) { hr = E_OUTOFMEMORY; goto CLEAN_UP; } GetParameter( pszCmdLine, _T("/bosunattend"), pszBOSUnattend ); pszBOSSetup = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!pszBOSSetup) { hr = E_OUTOFMEMORY; goto CLEAN_UP; } GetParameter( pszCmdLine, _T("/bossetup"), pszBOSSetup ); if( !_tcslen(pszBOSSetup) || !_tcslen(pszBOSUnattend) ) { hr = E_FAIL; goto CLEAN_UP; } USES_CONVERSION; // build the path via the bossetup, the unattend switch, then the unattend file bstrEXE = _T("\""); // Ensure path is in quotes bstrEXE += T2OLE(pszBOSSetup); bstrEXE += _T("\""); bstrRun = _T("/unattendfile "); bstrRun += T2OLE(pszBOSUnattend); STARTUPINFO si; PROCESS_INFORMATION pi; DWORD dwRet; memset( &si, 0, sizeof(STARTUPINFO) ); si.cb = sizeof( STARTUPINFO ); if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi) ) { do { dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 100, QS_ALLINPUT); if (dwRet == WAIT_OBJECT_0 + 1) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } while (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } CLEAN_UP: if (pszBOSUnattend) delete [] pszBOSUnattend; if (pszBOSSetup) delete [] pszBOSSetup; return hr; } VOID GetParameter( TCHAR* pszCmdLine, TCHAR* pszFindSwitch, TCHAR* pszOut ) { HRESULT hr = S_OK; if ( pszOut ) _tcscpy( pszOut, _T("") ); if (!pszCmdLine || !pszFindSwitch || !pszOut) return; TCHAR* psz = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!psz) { hr = E_OUTOFMEMORY; goto CLEAN_UP; } _tcscpy( psz, pszCmdLine ); _tcslwr( psz ); // look for the switch TCHAR* pszSwitch = NULL; if( !(pszSwitch = _tcsstr(psz, pszFindSwitch)) ) { goto CLEAN_UP; } // find the space for( ; *pszSwitch && !_istspace(*pszSwitch); ++pszSwitch ); if( !(*pszSwitch) || !(*(++pszSwitch)) ) { goto CLEAN_UP; } // if we have a ", we'll look for the next ", else look for a space bool bQuote = false; TCHAR* pszStart = pszSwitch; if( *pszSwitch == _T('"') ) { bQuote = true; ++pszSwitch; } // inc the pointer until we get either a " or a space for( ; *pszSwitch && (bQuote ? (*pszSwitch != _T('"')) : (!_istspace(*pszSwitch))); ++pszSwitch ); // if we're at the end and were looking for a quote, fail. if( !(*pszSwitch) && bQuote ) { goto CLEAN_UP; } // if we have a ", inc past it else if( bQuote ) { ++pszSwitch; } *pszSwitch = 0; _tcscpy( pszOut, pszStart ); CLEAN_UP: if (psz) delete [] psz; return; } HRESULT CheckSuppressCYS( TCHAR* pszCmdLine ) { HRESULT hr = S_OK; if (!pszCmdLine) return E_INVALIDARG; TCHAR* psz = new TCHAR[_tcslen(pszCmdLine) + 1]; if (!psz) return E_OUTOFMEMORY; _tcscpy( psz, pszCmdLine ); _tcslwr( psz ); if( _tcsstr(psz, "/suppresscys") ) { SuppressCfgSrvPage(); } else { hr = E_FAIL; } if (psz) delete [] psz; return hr; } // ---------------------------------------------------------------------------- // DisableBalloons() // // This function uses the following regkey to disable all balloon messages: // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced // EnableBalloonTips = 0x0 or 0x1 // // If bDisable = TRUE, then we disable the balloons (0x0) // if bDisable = FALSE, then we enable the balloons (0x1) // ---------------------------------------------------------------------------- VOID DisableBalloons( BOOL bDisable ) { HKEY hk = NULL; DWORD dwVal = bDisable ? 0x0 : 0x1; RegCreateKeyEx( HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), NULL, NULL, NULL, KEY_ALL_ACCESS, NULL, &hk, NULL); if ( hk ) { if ( RegSetValueEx(hk, _T("EnableBalloonTips"), NULL, REG_DWORD, (BYTE*)&dwVal, sizeof(dwVal)) != ERROR_SUCCESS ) { // ASSERT(FALSE); } RegCloseKey(hk); } } VOID GetSystemDrive(TCHAR** ppszDrive) { if (!ppszDrive) return; *ppszDrive = NULL; TCHAR szWindows[MAX_PATH + 1] = {0}; if (0 != GetWindowsDirectory(szWindows, sizeof(szWindows) / sizeof(TCHAR))) { *ppszDrive = new TCHAR[MAX_PATH]; _tsplitpath(szWindows, *ppszDrive, NULL, NULL, NULL); } }