/*++ Filename : setuplog.c Description: This is the main file for the setuplog.c Created by: Wally Ho History: Created on 03/30/99. Contains these functions: 1. GetTargetFile (LPTSTR szOutPath, LPTSTR szBld) 2. GetNTSoundInfo (VOID) 3. ConnectAndWrite (LPTSTR MachineName, LPTSTR Buffer) 4. GetBuildNumber (LPTSTR szBld) 5. RandomMachineID (VOID) 6. WriteMinimalData (LPTSTR szFileName) 7. DeleteDatafile (LPTSTR szDatafile) 8. GlobalInit (VOID) --*/ #include "setuplogEXE.h" VOID GetTargetFile (LPTSTR szOutPath, LPTSTR szBld) /*++ Routine Description: The file name is generated based on the calling machine's name and the build number being installed. In the "before" case, the generated name is saved to c:\setuplog.ini, and this name is in turn read in "after" case. Arguments: Where to write the file. The build. Return Value: NONE --*/ { HANDLE hFile; DWORD dwLen = MAX_PATH; TCHAR szParam [ MAX_PATH ]; TCHAR szComputerName [20]; TCHAR szComputerNameBld[30]; g_pfnWriteDataToFile = (fnWriteData)GetProcAddress (LoadLibrary ("setuplog.dll"), "WriteDataToFile"); GetComputerName (szComputerName, &dwLen); // // Build the new filename.Consisting of // 1. The Computername // 2. The build number. // _stprintf (szOutPath,TEXT("%s"), szComputerName); _tcscat (szOutPath, szBld); _tcscat (szOutPath, TEXT(".1")); // // Combine Computername and the build // To keep DavidShi code from breaking. // _stprintf(szComputerNameBld,TEXT("%s%s"),szComputerName,szBld); if (!lpCmdFrom.b_Cancel ){ hFile = CreateFile (SAVE_FILE, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ); if (hFile == INVALID_HANDLE_VALUE){ OutputDebugString ("Unable to write setuplog.ini\n"); return; } // Check for Upgrade. _stprintf (szParam, TEXT("%s"), lpCmdFrom.b_Upgrade? TEXT("U"): TEXT("I")); WriteFile (hFile, (LPCVOID) szParam, 1, &dwLen, NULL); // Check for CD install. _stprintf (szParam, TEXT("%s\""), lpCmdFrom.b_CDrom? TEXT("C"): TEXT("N")); WriteFile (hFile, (LPCVOID) szParam, 2, &dwLen, NULL); // Write out the platform. // I think this get ignored so i may delete it. Its DavidShi code. WriteFile (hFile, (LPCVOID) szPlatform, _tcsclen(szPlatform), &dwLen, NULL); // Write out the drive. WriteFile (hFile, (LPCVOID) "\"C:", 3, &dwLen, NULL); // Write out the computer name and build WriteFile (hFile, (LPCVOID) szComputerNameBld, _tcsclen(szComputerNameBld)+1, &dwLen, NULL); // Write the RandomID. _stprintf (szParam, TEXT("\r\nMachineID %lu"), lpCmdFrom.dwRandomID); WriteFile (hFile, (LPCVOID) szParam,_tcsclen(szParam)+1 , &dwLen, NULL); // Check for MSI install _stprintf (szParam, TEXT("\r\nMSI %s"), lpCmdFrom.b_MsiInstall? TEXT("Y"): TEXT("N")); WriteFile (hFile, (LPCVOID) szParam,_tcsclen(szParam)+1 , &dwLen, NULL); CloseHandle (hFile); } } VOID GetNTSoundInfo() { HKEY hKey; DWORD dwCbData; ULONG ulType; LPTSTR sSubKey=TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"); INT i; TCHAR szSubKeyName[ MAX_PATH ]; TCHAR szTempString[ MAX_PATH ]; // Get Sound Card Info m.nNumWaveOutDevices = 0; hKey = 0; if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, sSubKey, 0, KEY_READ, &hKey)){ // Loop through the key to see how many wave devices we have, but skip mmdrv.dll. for (i = 0; i <= 1; i++){ if (i != 0) _stprintf(szSubKeyName, TEXT("wave%d"),i); else _tcscpy(szSubKeyName, TEXT("wave")); dwCbData = sizeof (szTempString); if (RegQueryValueEx(hKey, szSubKeyName, 0, &ulType, (LPBYTE)szTempString, &dwCbData)) break; else{ // We want to skip mmdrv.dll - not relevant. if (szTempString[0] && _tcscmp(szTempString, TEXT("mmdrv.dll"))) { _tcscpy(&m.szWaveDriverName[m.nNumWaveOutDevices][0], szTempString); m.nNumWaveOutDevices++; } } } } if (hKey){ RegCloseKey(hKey); hKey = 0; } sSubKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\drivers.desc"); hKey = 0; if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, sSubKey, 0, KEY_READ, &hKey)){ // Now grab the sound device string for each wave device for (i = 0; i < m.nNumWaveOutDevices; i++){ dwCbData = sizeof szTempString; if (RegQueryValueEx(hKey, m.szWaveDriverName[i], 0, &ulType, (LPBYTE)szTempString, &dwCbData)) _tcscpy(m.szWaveOutDesc[i], TEXT("Unknown")); else _tcscpy(m.szWaveOutDesc[i], szTempString); } } if (hKey){ RegCloseKey(hKey); hKey = 0; } return; } VOID ConnectAndWrite(LPTSTR MachineName, LPTSTR Buffer) /*++ Routine Description: Cconnect to the data share and write the buffer to a file named MachineNamebuild.1 Arguments: The MachineName The buffer with the data to put in. Return Value: NONE --*/ { TCHAR szLogName[ MAX_PATH ]; HANDLE hWrite ; DWORD Size, Actual ; TCHAR szWriteFile[2000]; _tcscpy(szWriteFile,Buffer); // // Blow through the list of servers. // and change the g_szServerShare to match. // if (TRUE == IsServerOnline(MachineName, NULL)){ // // Set the server name now as we now have it // into the outputbuffer // _stprintf (Buffer+_tcsclen(Buffer), TEXT("IdwlogServer:%s\r\n"), g_szServerShare); _stprintf (szLogName, TEXT("%s\\%s"),g_szServerShare,MachineName ); hWrite = CreateFile( szLogName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL ); if ( hWrite != INVALID_HANDLE_VALUE ){ SetFilePointer( hWrite, 0, NULL, FILE_END ); Size = _tcsclen( Buffer ); WriteFile( hWrite, szWriteFile, Size, &Actual, NULL ); CloseHandle( hWrite ); } } } VOID GetBuildNumber (LPTSTR szBld) /*++ Routine Description: Acquires the Build number from imagehlp.dll Arguments: Return Value: True upon sucessful completion. --*/ { VS_FIXEDFILEINFO* pvsFileInfo; WIN32_FIND_DATA fd; HANDLE hFind; TCHAR szCurDir [MAX_PATH]; TCHAR szFullPath[ MAX_PATH ]; LPTSTR ptstr; DWORD dwTemp; DWORD dwLen; INT iBuild; LPVOID lpData; _tcscpy (szBld, TEXT("latest")); // // Use this to get the location // setuplog.exe is run from. this tool // will always assume imagehlp.dll is in its // current path or one up. // GetModuleFileName (NULL, szCurDir, MAX_PATH); // // This will cull off the setuplog.exe part // leaving us with the full path to where // setuplog.exe was on the CD or netshare. // ptstr = szCurDir + strlen(szCurDir); while (*ptstr-- != TEXT('\\')); ptstr++; *ptstr = ('\0'); _stprintf (szFullPath, TEXT("%s\\imagehlp.dll"),szCurDir); // // On a network share the Imagehlp.dll is one up from where // setuplog.exe is located. We will look in both places. // hFind = FindFirstFile (szFullPath, &fd); if (INVALID_HANDLE_VALUE == hFind){ // // Now we know the file in not in the // immediate directory. Move up one by // culling off one more directory. // ptstr = szCurDir + _tcsclen(szCurDir); while (*ptstr-- != '\\'); ptstr++; *ptstr = '\0'; _stprintf (szFullPath, TEXT("%s\\imagehlp.dll"),szCurDir); hFind = FindFirstFile (szFullPath,&fd); if (INVALID_HANDLE_VALUE == hFind){ // // In case we cannot find it we will exit. // _tcscpy (szBld, TEXT("latest")); return; } } // // Get the buffer info size // dwLen = GetFileVersionInfoSize (szFullPath, &dwTemp); if ( 0 == dwLen ) { // // We have a problem. // _tcscpy (szBld, TEXT("latest")); return; } lpData = LocalAlloc (LPTR, dwLen); if ( lpData == NULL ) { // // We have a problem. // _tcscpy (szBld, TEXT("latest")); return; } // // Get the File Version Info // if(0 == GetFileVersionInfo(szFullPath,0,MAX_PATH,lpData)){ // // We have a problem. // _tcscpy (szBld, TEXT("latest")); return; } if (0 == VerQueryValue (lpData, "\\", &pvsFileInfo, &dwTemp)) { // // We have a problem. // _tcscpy (szBld, TEXT("latest")); return; } // // The HIWORD() of this is the build // The LOWORD() of this is some garbage? :-) // iBuild = HIWORD(pvsFileInfo->dwFileVersionLS); LocalFree (lpData); // // Write it back to the buffer. // _stprintf(szBld, TEXT("%d"),iBuild); } DWORD RandomMachineID(VOID) /*++ Author: Wallyho. Routine Description: Generates a DWORD Random MachineID for each machine Arguments: NONE Return Value: The DWORD random ID. --*/ { INT i; TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1]; DWORD dwSize; INT iLenCName; INT iNameTotal = 0; DWORD dwMachineID; CHAR szRandomID[ 4 ]; // need 4 bytes to contain the DWORD. struct _timeb tm; // // This will get us the milliseconds // _ftime(&tm); // // Seed the random number generator. // We will seed with the seconds + milliseconds at // at that time. I was getting the same number // if I pressed the keyboard too fast in testing this. // The milli seconds should decrease the expectancy of // duplication. // srand ( (unsigned) time (NULL) + tm.millitm); // // This will guarantee a mostly random identifier. // Even with no computer name. We will tally the // ascii decimal value of the computer name and // add that to the randomly generated number. // The possibility of a dup is greatly decreased // since we switched to a dword system. // This computername tweak should be unnecessary. // dwSize = sizeof(szComputerName); if (0 == GetComputerName(szComputerName,&dwSize) ){ // // This algorithm will limit the random number to // uppercase ascii alphabet. // szComputerName[0] = 65 + (rand() % 25); szComputerName[1] = 65 + (rand() % 25); szComputerName[2] = 65 + (rand() % 25); szComputerName[3] = 65 + (rand() % 25); szComputerName[4] = 65 + (rand() % 25); szComputerName[5] = 65 + (rand() % 25); szComputerName[6] = 65 + (rand() % 25); szComputerName[7] = TEXT('\0'); } iLenCName = _tcslen (szComputerName); // // Tally up the individual elements in the file // for (i = 0; i < iLenCName; i++) iNameTotal += szComputerName[i]; // // Generate four 8 bit numbers. // Add the some random number based on the // computername mod'ed to 0-100. // Limit the 8 bit number to 0-155 to make room // for the 100 from the computer name tweak. // Total per 8 bit is 256. // Do this tweak to only 2. // We will then cast and shift to combine it // into a DWORD. // szRandomID[0] = (rand() % 155) + (iNameTotal % 100); szRandomID[1] = rand() % 255; szRandomID[2] = (rand() % 155) + (iNameTotal % 100); szRandomID[3] = rand() % 255; // // This will combine the 4 8bit CHAR into one DWORD // dwMachineID = (DWORD)szRandomID[0] * 0x00000001 + (DWORD)szRandomID[1] * 0x00000100 + (DWORD)szRandomID[2] * 0x00010000 + (DWORD)szRandomID[3] * 0x01000000; return dwMachineID; } VOID WriteMinimalData (LPTSTR szFileName) /*++ For machines on which setuplog.dll fails to load, just write the platform,a time stamp, upgrade, and cpu count. --*/ { TCHAR szOutBuffer[4096]; _tcscpy (szCPU ,TEXT("1")); _stprintf (szOutBuffer, TEXT("MachineID:%lu\r\n") TEXT("Source Media:%s\r\n") TEXT("Type:%s\r\n") TEXT("FromBld:%s\r\n") TEXT("Arch:%s\r\n") TEXT("Sound:%s\r\n") TEXT("NumProcs:%s\r\n") TEXT("MSI:%s\r\n"), lpCmdFrom.dwRandomID, lpCmdFrom.b_CDrom? TEXT("C"): TEXT("N"), lpCmdFrom.b_Upgrade? TEXT("U"): TEXT("I"), szPlatform, szArch, m.nNumWaveOutDevices? m.szWaveDriverName[m.nNumWaveOutDevices-1]: TEXT("None"), szCPU, lpCmdFrom.b_MsiInstall? TEXT("Y"): TEXT("N") ); ConnectAndWrite (szFileName, szOutBuffer); } VOID DeleteDatafile (LPTSTR szDatafile) /*++ Author: Routine Description: Deletes the file from the server if the user cancels it. Arguments: The name of the datafile. Return Value: NONE --*/ { TCHAR szPath[MAX_PATH]; _stprintf (szPath,TEXT("%s\\%s"), g_szServerShare,szDatafile); DeleteFile (szPath); } INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE h, LPTSTR szCmdLine, INT nCmdShow) { BOOL bAfter = FALSE; TCHAR szBld[10]; TCHAR szFileToSave[MAX_PATH]; OSVERSIONINFO osVer; // // Initialize Global Variables. // // GlobalInit(); // Spray up a simple help screen for /? if ( 0 == _tcscmp(szCmdLine, TEXT("/?")) || 0 == _tcscmp(szCmdLine, TEXT("-?")) ){ MessageBox(NULL,TEXT("setuplog upgrade cancel cdrom MSI "),TEXT("Help!"),MB_ICONQUESTION | MB_OK); return FALSE; } SetErrorMode (SEM_FAILCRITICALERRORS); // // See if Drive C is a HD. // if (DRIVE_FIXED != GetDriveType (TEXT("C:\\")) ){ return 0; } osVer.dwOSVersionInfoSize= sizeof( osVer ); GetVersionEx( &osVer ); switch (osVer.dwPlatformId){ case VER_PLATFORM_WIN32_NT: szPlatform = TEXT("Windows NT"); switch (osVer.dwMajorVersion){ case 3: szPlatform = TEXT("Windows NT 3.51"); break; case 4: szPlatform = TEXT("Windows NT 4.0"); break; case 5: szPlatform = szCurBld; break; } GetEnvironmentVariable ( TEXT("NUMBER_OF_PROCESSORS"), szCPU, 6); GetEnvironmentVariable ( TEXT("PROCESSOR_ARCHITECTURE"), szArch, 20); break; case VER_PLATFORM_WIN32_WINDOWS: szPlatform = TEXT("Windows 9x"); _tcscpy (szArch, "X86"); break; default: szPlatform = TEXT("Unknown"); _tcscpy (szArch, TEXT("Unknown")); break; } // // This is a very primitive command line processor // I'll add to it now to get this working soon. // I'll flesh this out to a full parser soon. // Wallyho. // lpCmdFrom.b_Upgrade = _tcsstr (szCmdLine, TEXT("upgrade")) ? TRUE : FALSE; lpCmdFrom.b_Cancel = _tcsstr (szCmdLine, TEXT("cancel")) ? TRUE : FALSE; lpCmdFrom.b_CDrom = _tcsstr (szCmdLine, TEXT("cdrom")) ? TRUE : FALSE; lpCmdFrom.b_MsiInstall= _tcsstr (szCmdLine, TEXT("MSI")) ? TRUE : FALSE; if (osVer.dwMajorVersion >= 5){ _itoa (osVer.dwBuildNumber, szCurBld, sizeof(szCurBld)); } // // Load the build number in the szBld // Variable. // GetBuildNumber (szBld); // // Generate a MachineID upfront to use later. // lpCmdFrom.dwRandomID = RandomMachineID(); GetTargetFile (szFileToSave, szBld); if (!lpCmdFrom.b_Cancel){ GetNTSoundInfo (); if (g_pfnWriteDataToFile) g_pfnWriteDataToFile(szFileToSave, NULL, &lpCmdFrom); else WriteMinimalData (szFileToSave); } else DeleteDatafile (szFileToSave); return 0; } VOID GlobalInit(VOID) /*++ Author: Wallyho. Routine Description: Initializes global Values. Arguments: NONE Return Value: NONE --*/ { // // Do some global initializations. // }