1010 lines
32 KiB
C
1010 lines
32 KiB
C
/****************************************************************************
|
|
|
|
PROGRAM: mttf.c
|
|
|
|
AUTHOR: Lars Opstad (LarsOp) 3/16/93
|
|
|
|
PURPOSE: NT Mean-time-to-failure reporting tool.
|
|
|
|
FUNCTIONS:
|
|
|
|
WinMain() - check for local file, read ini file and display dialogs
|
|
SignonDlgProc() - processes messages for signon dialog
|
|
EventDlgProc() - processes messages for event (other problem) dialog
|
|
|
|
COMMENTS:
|
|
|
|
This program displays 2 dialog boxes to prompt the user for
|
|
what type of problem occurred.
|
|
|
|
Every polling period, the time in the mttf data file is updated
|
|
(as either busy or idle based on percent of cpu usage). If a machine
|
|
is idle for more than 4 hrs, the "gone" field is increased by the time
|
|
gone. Whenever the program starts, the user is prompted for why they
|
|
rebooted or logged off. Other problems should be logged as they happen.
|
|
|
|
If any machine can not access the server file for some reason, the
|
|
data is stored in c:\mttf.dat until the next time the server file is
|
|
opened. At such a time, the server file is updated and the local file
|
|
is deleted.
|
|
|
|
****************************************************************************/
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include "mttf.h" /* specific to this program */
|
|
|
|
//
|
|
// For internal use, include header for NetMessageBufferSend and set up
|
|
// alert name and unicode buffers for NetMessageBufferSend.
|
|
//
|
|
#ifndef CUSTOMER
|
|
|
|
#include <lm.h>
|
|
#define AlertName "DavidAn"
|
|
WCHAR UniAlertName[16];
|
|
WCHAR UnicodeBuffer[1024];
|
|
|
|
#endif
|
|
|
|
#define IniFileName "Mttf.ini"
|
|
#define LocalFileName "c:\\mttf.dat"
|
|
|
|
|
|
#define DEFAULT_IDLE_LIMIT 10
|
|
#define DEFAULT_POLLING_PERIOD 30
|
|
|
|
#define CONSEC_IDLE_LIMIT 4*60
|
|
#define POLLING_PRODUCT 60000
|
|
#define HUNDREDNS_TO_MS 10000
|
|
#define MAX_RETRIES 10
|
|
|
|
HANDLE hInst; // current instance
|
|
HWND hCopying; // handle to copying dialog box
|
|
DWORD PollingPeriod = DEFAULT_POLLING_PERIOD;
|
|
DWORD IdlePercentage = DEFAULT_IDLE_LIMIT;
|
|
char ResultsFile[MAX_DIR], NameFile[MAX_DIR];
|
|
BOOL Enabled=TRUE;
|
|
BOOL LocalExists=FALSE;
|
|
DWORD Version;
|
|
DWORD ConsecIdle=0;
|
|
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
|
|
SYSTEM_PERFORMANCE_INFORMATION PreviousPerfInfo;
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
|
|
|
|
PURPOSE: Check for local file, read ini file and display dialogs.
|
|
|
|
COMMENTS:
|
|
|
|
Check to see if local data file exists and set flag appropriately.
|
|
Initialize the performance information.
|
|
Read the IniFile.
|
|
Display signon dialog.
|
|
Display event dialog (minimized).
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI
|
|
WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
OFSTRUCT ofstruct;
|
|
|
|
hInst = hInstance;
|
|
|
|
//
|
|
// Check for local file (if exists, write it to server at next opportunity)
|
|
//
|
|
LocalExists=(HFILE_ERROR!=OpenFile(LocalFileName, &ofstruct, OF_EXIST));
|
|
|
|
//
|
|
// Initialize performance information
|
|
//
|
|
Version=GetVersion();
|
|
NtQuerySystemInformation(
|
|
SystemPerformanceInformation,
|
|
&PerfInfo,
|
|
sizeof(PerfInfo),
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Read ini file
|
|
//
|
|
ReadIniFile();
|
|
|
|
//
|
|
// For Internal use, convert alert name to unicode for NetMessageBufferSend.
|
|
//
|
|
#ifndef CUSTOMER
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, AlertName, sizeof(UniAlertName)/2, UniAlertName, sizeof(UniAlertName)/2);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Display signon dlg
|
|
//
|
|
DialogBox(hInstance, (LPCSTR)IDD_SIGNON, NULL, SignonDlgProc);
|
|
|
|
//
|
|
// Display event dialog
|
|
//
|
|
DialogBox(hInstance, (LPCSTR) IDD_EVENT, NULL, EventDlgProc);
|
|
|
|
return(0);
|
|
|
|
} // WinMain()
|
|
|
|
/*****************************************************************************
|
|
|
|
FUNCTION: ReadIniFile ( )
|
|
|
|
PURPOSE: Read values from INI file using GetPrivateProfileString/Int
|
|
|
|
COMMENTS:
|
|
|
|
This reads entries from the mttf.ini file (in windows nt directory)
|
|
for NameFile, ResultsFile, PollingPeriod and IdlePercent. Any non-
|
|
existent entry returns a default.
|
|
|
|
*****************************************************************************/
|
|
VOID
|
|
ReadIniFile (
|
|
)
|
|
{
|
|
GetPrivateProfileString("Mttf",
|
|
"NameFile",
|
|
"",
|
|
NameFile,
|
|
MAX_DIR,
|
|
IniFileName);
|
|
|
|
GetPrivateProfileString("Mttf",
|
|
"ResultsFile",
|
|
"",
|
|
ResultsFile,
|
|
MAX_DIR,
|
|
IniFileName);
|
|
|
|
PollingPeriod = GetPrivateProfileInt("Mttf",
|
|
"PollingPeriod",
|
|
DEFAULT_POLLING_PERIOD,
|
|
IniFileName);
|
|
|
|
IdlePercentage = GetPrivateProfileInt("Mttf",
|
|
"IdlePercent",
|
|
DEFAULT_IDLE_LIMIT,
|
|
IniFileName);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: DWORD CpuUsage ( )
|
|
|
|
PURPOSE: Returns percentage of cpu usage for last polling period.
|
|
|
|
COMMENTS:
|
|
|
|
Computes time spent in the idle thread.
|
|
|
|
Divides this number by the number of 100nanoseconds in a millisecond.
|
|
(This division is to prevent over-flows in later computations.)
|
|
|
|
Returns 100-PercentIdle to get percent busy.
|
|
|
|
****************************************************************************/
|
|
DWORD
|
|
CpuUsage(
|
|
)
|
|
{
|
|
LARGE_INTEGER EndTime, BeginTime, ElapsedTime;
|
|
DWORD PercentIdle, Remainder;
|
|
PreviousPerfInfo = PerfInfo;
|
|
|
|
//
|
|
// Get current perf info
|
|
//
|
|
NtQuerySystemInformation(
|
|
SystemPerformanceInformation,
|
|
&PerfInfo,
|
|
sizeof(PerfInfo),
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Get times from PerfInfo and PreviousPerfInfo
|
|
//
|
|
EndTime = *(PLARGE_INTEGER)&PerfInfo.IdleProcessTime;
|
|
BeginTime = *(PLARGE_INTEGER)&PreviousPerfInfo.IdleProcessTime;
|
|
|
|
//
|
|
// Convert from 100 NS to Milliseconds
|
|
//
|
|
EndTime = RtlExtendedLargeIntegerDivide(EndTime, HUNDREDNS_TO_MS, &Remainder);
|
|
BeginTime = RtlExtendedLargeIntegerDivide(BeginTime, HUNDREDNS_TO_MS, &Remainder);
|
|
|
|
//
|
|
// Compute elapsed time and percent idle
|
|
//
|
|
ElapsedTime = RtlLargeIntegerSubtract(EndTime,BeginTime);
|
|
PercentIdle = (ElapsedTime.LowPart) / ((POLLING_PRODUCT/100)*PollingPeriod);
|
|
|
|
//
|
|
// Sometimes it takes significantly longer than PollingPeriod
|
|
// to make a round trip.
|
|
//
|
|
|
|
if ( PercentIdle > 100 ) {
|
|
|
|
PercentIdle = 100;
|
|
}
|
|
|
|
//
|
|
// return cpuusage (100-PercentIdle)
|
|
//
|
|
return 100-PercentIdle;
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IncrementStats (StatType)
|
|
|
|
PURPOSE: Increments the specified stat and writes new data to mttf.dat.
|
|
|
|
COMMENTS:
|
|
|
|
Increment the specified stat. For MTTF_TIME, check if it is busy
|
|
or idle by comparing the CpuUsage to IdlePercentage. If a machine
|
|
is idle for 4 hrs consecutively, first time this is true set the
|
|
IdleConsec stat to the total ConsecIdle value, otherwise set to
|
|
polling period. (IdleConsec should never exceed Idle.)
|
|
|
|
Open mttf.dat. If opening the server fails (10 times), open the
|
|
local data file. If server opened and local file also exists,
|
|
open local file also for transfer.
|
|
|
|
Search through data file for matching build number, add all values
|
|
and write new record. (Continue until local file is gone if
|
|
transferring.)
|
|
|
|
****************************************************************************/
|
|
VOID
|
|
IncrementStats(
|
|
StatType stattype
|
|
)
|
|
{
|
|
HANDLE fhandle,localHandle;
|
|
StatFileRecord newRec, curRec;
|
|
DWORD numBytes;
|
|
BOOL localToServer=FALSE;
|
|
CHAR buffer[1024];
|
|
int i;
|
|
|
|
//
|
|
// Initialize all values to zero
|
|
//
|
|
memset(&newRec, 0, sizeof(newRec));
|
|
|
|
newRec.Version=Version;
|
|
|
|
//
|
|
// Increment the appropriate stat.
|
|
//
|
|
switch (stattype) {
|
|
|
|
//
|
|
// MTTF_TIME stat: Get cpu usage and set idle/busy and percent fields.
|
|
//
|
|
// If idle for more than CONSEC_IDLE_LIMIT, Set IdleConsec.
|
|
// If difference is less than polling period (first time), set to total
|
|
// ConsecIdle; otherwise, just PollingPeriod.
|
|
//
|
|
case MTTF_TIME:
|
|
//
|
|
// Has the CPU been "busy"?
|
|
//
|
|
if ((newRec.PercentTotal=CpuUsage()) > IdlePercentage) {
|
|
//
|
|
// Yes, set busy to polling period and clear ConsecIdle.
|
|
//
|
|
newRec.Busy = PollingPeriod;
|
|
ConsecIdle=0;
|
|
|
|
} else {
|
|
//
|
|
// No, not busy, increment consec idle by PollingPeriod.
|
|
// (Set value of idle to polling period.)
|
|
//
|
|
// If ConsecIdle is greater than IDLE_LIMIT, set IdleConsec.
|
|
// If first time, set IdleConsec to ConsecIdle, else PollingPer.
|
|
//
|
|
ConsecIdle+=(newRec.Idle = PollingPeriod);
|
|
if (ConsecIdle>=CONSEC_IDLE_LIMIT) {
|
|
if (ConsecIdle < CONSEC_IDLE_LIMIT + PollingPeriod) {
|
|
newRec.IdleConsec=ConsecIdle;
|
|
} else {
|
|
newRec.IdleConsec=PollingPeriod;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Weight PercentTotal by number of minutes in polling period.
|
|
//
|
|
newRec.PercentTotal *= PollingPeriod;
|
|
break;
|
|
|
|
//
|
|
// MTTF_COLD: Set cold boot count to 1
|
|
//
|
|
case MTTF_COLD:
|
|
newRec.Cold = 1;
|
|
break;
|
|
//
|
|
// MTTF_WARM: Set warm boot count to 1
|
|
//
|
|
case MTTF_WARM:
|
|
newRec.Warm = 1;
|
|
break;
|
|
//
|
|
// MTTF_OTHER: Set other problem count to 1
|
|
//
|
|
case MTTF_OTHER:
|
|
newRec.Other = 1;
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
//
|
|
// If there is a ResultsFile name entered in the INI file,
|
|
//
|
|
if (ResultsFile[0]) {
|
|
|
|
//
|
|
// Try to open the server file (MAX_RETRIES times).
|
|
//
|
|
for (i=0;i<MAX_RETRIES;i++) {
|
|
if (INVALID_HANDLE_VALUE!=(fhandle = CreateFile(ResultsFile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL))) {
|
|
break;
|
|
}
|
|
Sleep(500); // wait a half second if it failed.
|
|
}
|
|
} else {
|
|
//
|
|
// If ResultsFile name is blank, set i to MAX_RETRIES to force open
|
|
// of local data file.
|
|
//
|
|
i=MAX_RETRIES;
|
|
}
|
|
|
|
//
|
|
// If i is MAX_RETRIES, server file failed to open, so open local file.
|
|
//
|
|
if (i==MAX_RETRIES) {
|
|
if (INVALID_HANDLE_VALUE==(fhandle = CreateFile(LocalFileName,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL))) {
|
|
return;
|
|
}
|
|
LocalExists=TRUE; // Set flag to indicate local file exists
|
|
} else {
|
|
//
|
|
// If the server file opened and the local file exists, open local for
|
|
// transfer (indicated by localToServer).
|
|
//
|
|
if (LocalExists) {
|
|
localToServer=TRUE;
|
|
if (INVALID_HANDLE_VALUE==(localHandle = CreateFile(LocalFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL))) {
|
|
localToServer=FALSE;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Outer loop is to continue searching in case of transferring local
|
|
// file to server.
|
|
//
|
|
do {
|
|
//
|
|
// Loop through data file until versions match or end of file found.
|
|
//
|
|
while (1) {
|
|
|
|
//
|
|
// If ReadFile fails, close files (and send message if internal).
|
|
//
|
|
if (!ReadFile(fhandle, &curRec, sizeof(curRec), &numBytes, NULL)) {
|
|
|
|
CloseHandle(fhandle);
|
|
|
|
if (localToServer) {
|
|
CloseHandle(localHandle);
|
|
DeleteFile(LocalFileName);
|
|
LocalExists=FALSE;
|
|
}
|
|
|
|
#ifndef CUSTOMER
|
|
|
|
sprintf(buffer,
|
|
"Mttf error reading %s (error code %ld).\nPlease rename file.",
|
|
//
|
|
// If the local file exists and not transferring,
|
|
// local file is open; otherwise, server file.
|
|
//
|
|
(LocalExists & !localToServer ? LocalFileName : ResultsFile),
|
|
GetLastError());
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, buffer, sizeof(buffer), UnicodeBuffer, sizeof(UnicodeBuffer)/2);
|
|
|
|
NetMessageBufferSend(NULL, UniAlertName, NULL, (LPBYTE)UnicodeBuffer, 2 * strlen(buffer));
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If numBytes is 0, end of file reached; break out of while to
|
|
// add a new record.
|
|
//
|
|
if (numBytes==0) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If numBytes is not record size, report an error and close files.
|
|
//
|
|
// Reporting is a local message box for customers and a popup internally.
|
|
//
|
|
if (numBytes != sizeof(curRec)) {
|
|
|
|
#ifdef CUSTOMER
|
|
|
|
sprintf(buffer,
|
|
"Error reading %s (error code %ld).\n\nPlease have "
|
|
"your administrator rename the file and contact "
|
|
"Microsoft regarding the Mttf (mean time to failure) "
|
|
"reporting tool.",
|
|
//
|
|
// If the local file exists and not transferring,
|
|
// local file is open; otherwise, server file.
|
|
//
|
|
(LocalExists & !localToServer ? LocalFileName : ResultsFile),
|
|
GetLastError());
|
|
|
|
|
|
MessageBox(NULL, buffer, "Read File Error", MB_OK|MB_ICONHAND);
|
|
|
|
#else
|
|
|
|
sprintf(buffer,
|
|
"Mttf error reading %s (error code %ld).\n(Byte count wrong.) Please rename file.",
|
|
//
|
|
// If the local file exists and not transferring,
|
|
// local file is open; otherwise, server file.
|
|
//
|
|
(LocalExists & !localToServer ? LocalFileName : ResultsFile),
|
|
GetLastError());
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, buffer, sizeof(buffer), UnicodeBuffer, sizeof(UnicodeBuffer)/2);
|
|
|
|
NetMessageBufferSend(NULL, UniAlertName, NULL, (LPBYTE)UnicodeBuffer, 2 * strlen(buffer));
|
|
|
|
#endif
|
|
|
|
CloseHandle(fhandle);
|
|
|
|
if (localToServer) {
|
|
CloseHandle(localHandle);
|
|
DeleteFile(LocalFileName);
|
|
LocalExists=FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If Versions match, increment all other stats, rewind file and
|
|
// break out of while to do write.
|
|
//
|
|
if (curRec.Version==newRec.Version) {
|
|
newRec.Idle += curRec.Idle;
|
|
newRec.IdleConsec += curRec.IdleConsec;
|
|
newRec.Busy += curRec.Busy;
|
|
newRec.PercentTotal += curRec.PercentTotal;
|
|
newRec.Warm += curRec.Warm;
|
|
newRec.Cold += curRec.Cold;
|
|
newRec.Other += curRec.Other;
|
|
SetFilePointer(fhandle, -(LONG)sizeof(curRec), NULL, FILE_CURRENT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write newRec at current location (end of file for new record)
|
|
//
|
|
WriteFile(fhandle, &newRec, sizeof(newRec), &numBytes, NULL);
|
|
|
|
//
|
|
// if transferring from local to server, read the next record from
|
|
// the local file, rewind data file and loop again until end of
|
|
// (local) file.
|
|
//
|
|
if (localToServer) {
|
|
//
|
|
// If ReadFile fails, close files (and send popup internally)
|
|
//
|
|
if (!ReadFile(localHandle, &newRec, sizeof(curRec), &numBytes, NULL)) {
|
|
|
|
CloseHandle(fhandle);
|
|
CloseHandle(localHandle);
|
|
LocalExists=FALSE;
|
|
DeleteFile(LocalFileName);
|
|
|
|
#ifndef CUSTOMER
|
|
|
|
sprintf(buffer,
|
|
"Mttf error reading %s (error code %ld).\nLocal file access failed...data will be lost.",
|
|
LocalFileName,
|
|
GetLastError());
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, buffer, sizeof(buffer), UnicodeBuffer, sizeof(UnicodeBuffer)/2);
|
|
|
|
NetMessageBufferSend(NULL, UniAlertName, NULL, (LPBYTE)UnicodeBuffer, 2 * strlen(buffer));
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (numBytes==0) {
|
|
//
|
|
// Done transferring, close both files, delete local and set
|
|
// LocalExists and localToServer to FALSE.
|
|
//
|
|
CloseHandle(localHandle);
|
|
DeleteFile(LocalFileName);
|
|
LocalExists=localToServer=FALSE;
|
|
CloseHandle(fhandle);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if numBytes is not record size, close files (and send popup internally)
|
|
//
|
|
if (numBytes != sizeof(curRec)) {
|
|
|
|
#ifndef CUSTOMER
|
|
|
|
sprintf(buffer,
|
|
"Mttf error reading %s (error code %ld).\n(Byte count wrong.) Data will be lost.",
|
|
LocalFileName,
|
|
GetLastError());
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, buffer, sizeof(buffer), UnicodeBuffer, sizeof(UnicodeBuffer)/2);
|
|
|
|
NetMessageBufferSend(NULL, UniAlertName, NULL, (LPBYTE)UnicodeBuffer, 2 * strlen(buffer));
|
|
|
|
#endif
|
|
|
|
CloseHandle(fhandle);
|
|
CloseHandle(localHandle);
|
|
DeleteFile(LocalFileName);
|
|
LocalExists=FALSE;
|
|
return;
|
|
|
|
}
|
|
|
|
SetFilePointer(fhandle,0, NULL, FILE_BEGIN);
|
|
} else {
|
|
//
|
|
// If not transferring, close file and exit
|
|
//
|
|
CloseHandle(fhandle);
|
|
return;
|
|
}
|
|
} while (localToServer);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: CheckAndAddName ( )
|
|
|
|
PURPOSE: Checks name file for machine name and build number at startup.
|
|
|
|
COMMENTS:
|
|
|
|
Writes various system info to name file if the machine doesn't have
|
|
an entry for this build. This was an add-on to collect info on how
|
|
many machines were actually running NT.
|
|
|
|
****************************************************************************/
|
|
VOID
|
|
CheckAndAddName(
|
|
)
|
|
{
|
|
NameFileRecord newRec, curRec;
|
|
HANDLE fhandle;
|
|
DWORD numBytes,i,ulLength=MAX_NAME;
|
|
DWORD dwVersion;
|
|
SYSTEMTIME sysTime;
|
|
MEMORYSTATUS memstat;
|
|
SYSTEM_INFO sysinfo;
|
|
|
|
//
|
|
// If the NameFile name is blank, exit
|
|
//
|
|
if (0==NameFile[0]) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set record to zero.
|
|
//
|
|
memset(&newRec, 0, sizeof(newRec));
|
|
|
|
GetComputerName(newRec.MachineName, &ulLength);
|
|
|
|
GetSystemInfo(&sysinfo); // Get system info
|
|
|
|
switch(sysinfo.wProcessorArchitecture) {
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
newRec.MachineType=X86_CPU;
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
|
newRec.MachineType=MIP_CPU;
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
|
newRec.MachineType=AXP_CPU;
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_PPC:
|
|
newRec.MachineType=PPC_CPU;
|
|
break;
|
|
|
|
default:
|
|
newRec.MachineType=UNKNOWN_CPU;
|
|
break;
|
|
};
|
|
|
|
dwVersion=GetVersion();
|
|
sprintf(newRec.Build, "%3ld", dwVersion>>16);
|
|
|
|
memstat.dwLength=sizeof(memstat);
|
|
GlobalMemoryStatus(&memstat); // Get memory info
|
|
|
|
sprintf(newRec.Mem, "%5ldMB",memstat.dwTotalPhys/(1024*1024));
|
|
|
|
ulLength=MAX_NAME;
|
|
|
|
GetUserName(newRec.UserName, &ulLength);
|
|
|
|
GetLocalTime(&sysTime);
|
|
sprintf(newRec.DateAndTime, "%2d/%2d/%4d %2d:%02ld",
|
|
sysTime.wMonth, sysTime.wDay, sysTime.wYear,
|
|
sysTime.wHour, sysTime.wMinute);
|
|
|
|
newRec.Tab1=newRec.Tab2=newRec.Tab3=newRec.Tab4=newRec.Tab5=9;
|
|
newRec.CRLF[0]=13;
|
|
newRec.CRLF[1]=10;
|
|
|
|
//
|
|
// Try to open NameFile, for shared read access.
|
|
//
|
|
if (INVALID_HANDLE_VALUE==(fhandle = CreateFile(NameFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL))) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read each record until a match or end-of-file is encountered.
|
|
//
|
|
while (ReadFile(fhandle, &curRec, sizeof(curRec), &numBytes, NULL)) {
|
|
//
|
|
// At end of file, break out and write new record.
|
|
//
|
|
if (numBytes==0) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If there is a match, close the file and return.
|
|
//
|
|
if (0==strcmp(curRec.Build, newRec.Build) &&
|
|
0==strcmp(curRec.MachineName, newRec.MachineName)) {
|
|
CloseHandle(fhandle);
|
|
return;
|
|
}
|
|
}
|
|
//
|
|
// Close the name file and try to open it for ExclusiveWrite
|
|
//
|
|
CloseHandle(fhandle);
|
|
for (i=0;i<MAX_RETRIES;i++) {
|
|
if (INVALID_HANDLE_VALUE!=(fhandle = CreateFile(NameFile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL))) {
|
|
break;
|
|
}
|
|
Sleep(500); // wait if open failed.
|
|
}
|
|
|
|
//
|
|
// If open succeeded, go to the end of file and write newRec.
|
|
//
|
|
if (i<MAX_RETRIES) {
|
|
SetFilePointer(fhandle, 0, &numBytes, FILE_END);
|
|
WriteFile(fhandle, &newRec, sizeof(newRec), &numBytes, NULL);
|
|
CloseHandle(fhandle);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: SignonDlgProc(HWND, UINT, UINT, UINT)
|
|
|
|
PURPOSE: Dialog procedure for signon dialog.
|
|
|
|
COMMENTS: The signon dialog
|
|
|
|
WM_INITDIALOG: Checks machine name in name file and sets focus.
|
|
|
|
WM_COMMAND: Process the button press:
|
|
IDOK: Get input values and check for validity.
|
|
IDCANCEL: Kill the app.
|
|
IDB_HELP: Descriptive message box
|
|
|
|
****************************************************************************/
|
|
INT_PTR
|
|
SignonDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG: // Checks machinename in namefile and sets focus
|
|
|
|
CheckAndAddName();
|
|
|
|
CheckRadioButton(hDlg, IDS_NORMAL, IDS_COLD, IDS_NORMAL);
|
|
return (TRUE);
|
|
|
|
case WM_COMMAND: // command: button pressed
|
|
|
|
switch (wParam) // which button
|
|
{
|
|
//
|
|
// OK: Update the appropriate stat if not "Normal Boot"
|
|
//
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
|
|
if (IsDlgButtonChecked(hDlg, IDS_WARM)) {
|
|
IncrementStats(MTTF_WARM);
|
|
} else {
|
|
if (IsDlgButtonChecked(hDlg, IDS_COLD)) {
|
|
IncrementStats(MTTF_COLD);
|
|
}
|
|
}
|
|
EndDialog(hDlg, TRUE);
|
|
return (TRUE);
|
|
|
|
//
|
|
// HELP: Descriptive message box (.HLP file would be overkill)
|
|
//
|
|
case IDB_HELP:
|
|
MessageBox( NULL,
|
|
"Mttf tracks the amount of time your machine stays up, "
|
|
"the number of cold and warm boots, and "
|
|
"the number of other problems that occur on your machine. "
|
|
"All this information is written to a server that is "
|
|
"specified in mttf.ini (in your Windows NT directory).\n\n"
|
|
"The app should be placed in your start-up group and "
|
|
"you should respond accurately (if there was a problem) "
|
|
"on startup. When you encounter other problems -- where "
|
|
"the system did not require a reboot, but encountered "
|
|
"anything you consider a problem -- double-click on the "
|
|
"Mttf icon and press the Other Problem button.\n\n"
|
|
"When you are running some test that is outside of the "
|
|
"realm of normal usage (e.g. Stress), please disable Mttf "
|
|
"by double-clicking the icon and pressing disable. When "
|
|
"you are done with this test, please press the Enable "
|
|
"button to continue reporting.",
|
|
"Mean Time to Failure Help",
|
|
MB_OK
|
|
);
|
|
return (TRUE);
|
|
|
|
default:
|
|
break;
|
|
} // switch (wParam)
|
|
break;
|
|
default:
|
|
break;
|
|
} // switch (message)
|
|
return (FALSE); // Didn't process a message
|
|
} // SignonDlgProc()
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: EventDlgProc(HWND, UINT, UINT, UINT)
|
|
|
|
PURPOSE: Processes timer and button events (disable and other problems).
|
|
|
|
COMMENTS: Processes the following messages:
|
|
|
|
WM_INITDIALOG: Minimize dialog and start timer
|
|
WM_CLOSE...: End app
|
|
WM_TIMER: Update Time stat (busy or idle)
|
|
|
|
WM_COMMAND: Process the button press:
|
|
IDOK: Log Other problem (and minimize).
|
|
IDCANCEL: Minimize without action.
|
|
IDE_DISABLE: Disable or enable mttf reporting.
|
|
IDB_HELP: Descriptive message box.
|
|
|
|
|
|
****************************************************************************/
|
|
INT_PTR
|
|
EventDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG: // minimize and start timer
|
|
|
|
SetClassLongPtr(hDlg, GCLP_HICON, (LONG_PTR)LoadIcon(hInst,"mttf"));
|
|
SendMessage(hDlg, WM_SYSCOMMAND, SC_ICON, 0);
|
|
SetTimer(hDlg, 1, POLLING_PRODUCT*PollingPeriod, NULL);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
case WM_DESTROY:
|
|
case WM_ENDSESSION:
|
|
case WM_QUIT:
|
|
|
|
EndDialog(hDlg,0);
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
IncrementStats(MTTF_TIME);
|
|
break;
|
|
|
|
case WM_COMMAND: // button was pressed
|
|
switch(LOWORD(wParam)) // which one
|
|
{
|
|
//
|
|
// OK: Other problem encountered increment # of others.
|
|
//
|
|
case IDOK:
|
|
|
|
SendMessage(hDlg, WM_SYSCOMMAND, SC_ICON, 0);
|
|
|
|
IncrementStats(MTTF_OTHER);
|
|
break;
|
|
|
|
//
|
|
// DISABLE: Disable/Enable Mttf polling.
|
|
//
|
|
case IDE_DISABLE:
|
|
|
|
SendMessage(hDlg, WM_SYSCOMMAND, SC_ICON, 0);
|
|
|
|
//
|
|
// Based on whether enabling or disabling, change button and window title
|
|
//
|
|
if (Enabled) {
|
|
SetWindowText((HWND) lParam,"&Enable Mttf Reporting");
|
|
SetWindowText(hDlg, "Mttf (Disabled)");
|
|
KillTimer(hDlg, 1);
|
|
Enabled = FALSE;
|
|
} else {
|
|
SetWindowText((HWND) lParam,"&Disable Mttf Reporting");
|
|
SetWindowText(hDlg, "Mttf (Enabled)");
|
|
SetTimer(hDlg, 1, POLLING_PRODUCT*PollingPeriod, NULL);
|
|
NtQuerySystemInformation(
|
|
SystemPerformanceInformation,
|
|
&PerfInfo,
|
|
sizeof(PerfInfo),
|
|
NULL
|
|
);
|
|
Enabled = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// CANCEL: Minimize app (no problem)
|
|
//
|
|
case IDCANCEL:
|
|
|
|
SendMessage(hDlg, WM_SYSCOMMAND, SC_ICON, 0);
|
|
return (TRUE);
|
|
|
|
|
|
//
|
|
// HELP: Descriptive message box (.HLP file would be overkill)
|
|
//
|
|
case IDB_HELP:
|
|
MessageBox( NULL,
|
|
"Mttf tracks the amount of time your machine stays up, "
|
|
"the number of cold and warm boots, and "
|
|
"the number of other problems that occur on your machine. "
|
|
"All this information is written to a server that is "
|
|
"specified in mttf.ini (in your Windows NT directory).\n\n"
|
|
"The app should be placed in your start-up group and "
|
|
"you should respond accurately (if there was a problem) "
|
|
"on startup. When you encounter other problems -- where "
|
|
"the system did not require a reboot, but encountered "
|
|
"anything you consider a problem -- double-click on the "
|
|
"Mttf icon and press the Other Problem button.\n\n"
|
|
"When you are running some test that is outside of the "
|
|
"realm of normal usage (e.g. Stress), please disable Mttf "
|
|
"by double-clicking the icon and pressing disable. When "
|
|
"you are done with this test, please press the Enable "
|
|
"button to continue reporting.",
|
|
"Mean Time to Failure Help",
|
|
MB_OK
|
|
);
|
|
return (TRUE);
|
|
|
|
default:
|
|
;
|
|
} // switch (LOWORD(wParam))
|
|
|
|
break;
|
|
|
|
default:
|
|
;
|
|
} // switch (message)
|
|
return FALSE;
|
|
|
|
} // EventDlgProc()
|