// StartUp by Sebastian Roll // 2010-09-15 // This program reads a config file line by line (filename = "StartUpConfig.txt"). // If a line begins with "wait", StartUp delays specified seconds (example: "wait 5"). // All other lines are interpreted as fully qualified paths to a program to start (example: "C:\WINDOWS\notepad.exe"). // Empty lines are ignored. #define WIN32_LEAN_AND_MEAN // exclude rarely-used services from Windows headers #define NOGDI // exclude GDI services from Windows headers #include <windows.h> // Sleep() #include <shellapi.h> // ShellExecute() #include <stdio.h> // FILE, fopen(), fgets(), fclose(), frpintf(), sprintf() #include <stdlib.h> // EXIT_SUCCESS, atoi(), malloc(), free() #include <string.h> // strlen(), strncmp() #include <limits.h> // INT_MAX // the file to read the config from #define FILE_NAME "StartUpConfig.txt" // config file: the max size of one line to read AND the max amount of all lines #define LINES_SIZE (1024) // the text to interpret as "delay command" within the config file #define WAIT_STRING "wait" // the max "delay" we allow (4294967 seconds = 1193 hours) #define WAIT_SECONDS_MAX (INT_MAX/1000) // CarrierReturn ASCII code #define CHAR_CODE_CARRIER_RETURN (0x0D) // LineFeed ASCII code #define CHAR_CODE_LINE_FEED (0x0A) // the config file is stored to this 2D array // each line (first[]) holds a command to execute (second[]) // e.g. config[2][0] is the first char of the 3rd command line // e.g. &(config[2][0]) is the C-string of the 3rd command line static char config[LINES_SIZE][LINES_SIZE]; // funtion prototypes int getConfig(); int formatLine(int line, int lineLength); char* getLine(int line); void startProcess(int line); void wait(int seconds); void printShellExecuteError(int error); // application entry point int main(void) { int i = 0; int numOfLines = getConfig(); int waitStringSize = strlen(WAIT_STRING); for (i = 0; i < numOfLines; i++) { // check if we have a "delay command" if (!strncmp(WAIT_STRING, getLine(i), waitStringSize)) { wait(atoi(&(config[i][waitStringSize + 1]))); } else { startProcess(i); } } return EXIT_SUCCESS; } // reads file "FILE_NAME" and stores its content to config[][]. // skips empty lines in the file. // removes LF/CR chars at the end of each line. int getConfig() { int lineCount = 0; int lineLength = 0; int errorFlag = 0; char* status = 0; FILE* file = fopen(FILE_NAME, "r"); printf("getConfig() reading file %s \n", FILE_NAME); if (NULL != file) { while (!feof(file)) { // read a line from file and write to config[][] status = fgets(getLine(lineCount), LINES_SIZE, file); if ( (lineCount == 0) && (status == 0) ) { errorFlag = 1; printf("getConfig() read file error (empty file?): line %d \n", lineCount); // exit while() break; } // check size of the line lineLength = strlen(getLine(lineCount)); if (lineLength >= LINES_SIZE - 1) { errorFlag = 1; printf("getConfig() read file error: string too long: line %d \n", lineCount); // exit while() break; } // check if line is empty and // check line for CarrierReturn/LineFeed chars lineCount += formatLine(lineCount, lineLength); if (lineCount >= LINES_SIZE) { errorFlag = 1; printf("getConfig() file too long (max %d lines allowed) \n", LINES_SIZE); // exit while() break; } } fclose(file); if (errorFlag == 0) { printf("getConfig() found %d commands \n", lineCount); } } else { printf("getConfig() cannot open file \n"); } if (errorFlag == 1) { lineCount = 0; } return lineCount; } // overwrites last CR/LF char of given line with 0 (zero) // returns 1 if given line is a valid command // returns 0 if given line is emtpy // returns 0 if given line consists of only one CR/LF char int formatLine(int line, int lineLength) { int result = 0; if (lineLength == 0) { // line is empty } else if (lineLength == 1) { // this line has either one LF/CR char or a valid filename with only one char // suppress LF/CR char if ( (config[line][lineLength - 1] == CHAR_CODE_CARRIER_RETURN) || (config[line][lineLength - 1] == CHAR_CODE_LINE_FEED) ) { config[line][lineLength - 1] = 0; } else { // it is a valid filename with only one char result = 1; } } else { // suppress LF/CR char if ( (config[line][lineLength - 1] == CHAR_CODE_CARRIER_RETURN) || (config[line][lineLength - 1] == CHAR_CODE_LINE_FEED) ) { config[line][lineLength - 1] = 0; } // it is a valid filename with some chars result = 1; } return result; } // returns the pointer to the first char of given line char* getLine(int line) { return &(config[line][0]); } // executes the given line of the config file void startProcess(int line) { HINSTANCE hInst; printf("startProcess() \"%s\" \n", getLine(line)); hInst = ShellExecute(0, "open", // operation to perform getLine(line), // application name 0, // additional parameters 0, // default directory SW_SHOW); // MSDN says: return code > 31 is "no error" if ((int)hInst < 32) { printShellExecuteError((int)hInst); } } // delays execution for given seconds void wait(int seconds) { if ( (seconds > 0) && (seconds < WAIT_SECONDS_MAX) ) { printf("wait() %d seconds ", seconds); Sleep(seconds * 1000); printf("end \n"); } else { printf("wait() warning: cannot wait for %d seconds (invalid number?)\n", seconds); } } // maps ShellExecute() error codes to text void printShellExecuteError(int error) { char* standardText = "startProcess() error"; char* detailText = (char*)malloc(64); switch (error) { case ERROR_FILE_NOT_FOUND: detailText = "file not found"; break; case ERROR_PATH_NOT_FOUND: detailText = "path not found"; break; case ERROR_BAD_FORMAT: detailText = "not an executable"; break; case SE_ERR_NOASSOC: detailText = "filetype unknown"; break; case SE_ERR_ACCESSDENIED: detailText = "access denied"; break; case SE_ERR_SHARE: detailText = "sharing violation"; break; default: sprintf(detailText, "%d", error); break; } printf("%s: %s \n", standardText, detailText); free(detailText); }