#1 26. April 2011 ApplicationService Hey, ich hab spontan ein Programm geschrieben, dass Programme wie einen Service behandelt. D.h. es ist möglich normale Programme, die nicht als Service gedacht sind (z.B. Server wie Teamspeak3), zu starten und zu beenden. Es wird also nichts an Windows geändert und lässt sich einfach per CMD bedienen, was so manche Arbeit ersparen dürfte, wenn etwas schnell gehen soll. Wie gesagt, das Programm ist spontan geschrieben, sollten euch also Fehler auffallen dürft ihr mir gerne verraten wie diese auftreten (Genauer Befehl), damit ich diese sobald wie möglich beheben kann. Bedienung dürfte selbsterklärend sein, wenn nicht: Fragen! Code: #include <iostream> #include <string> #include <vector> #include <queue> #include <fstream> #include <cstdlib> #define WIN32_LEAN_AND_MEAN #include <windows.h> #define TAS_FILE_DEFAULT "tas.db" using namespace std; enum { SC_NONE = 0, SC_START = 0x01, SC_STOP = 0x10, SC_RESTART = 0x11, }; enum { SQ_NONE = 0, SQ_ADD, SQ_REMOVE, SQ_CONTROL, SQ_STATUS, }; enum { SDB_SKIP = -2, SDB_ADD = -1, SDB_FIRST = 0, }; struct tas_entry { char id[16]; char path[256]; char param[256]; unsigned pid; void set_id( char* _id ) { strncpy(id, _id, 16); } void set_path( char* _path ) { strncpy(path, _path, 256); } void set_param( char* _param ) { strncpy(param, _param, 256); } }; struct tas_task { int type; int action; tas_entry entry; tas_task(int _type = SQ_NONE) : type(_type), action(SC_NONE) { memset(&entry, 0, sizeof(tas_entry)); } }; struct tas_config { bool verbose; bool changes; char db[256]; queue< tas_task > tasks; vector< pair<tas_entry, long> > services; tas_config() : verbose(false), changes(false) { strncpy(db, TAS_FILE_DEFAULT, 16); } void set_db( char* _db ) { strncpy(db, _db, 256); } }; void tas_check_opt(tas_config& conf, char opt, int argc_left, char **argv); void tas_init(tas_config& conf); void tas_close(tas_config& conf); // writes db if tas_config::changes was set void tas_process_tasks(tas_config& conf); bool tas_process_task(tas_config& conf, tas_task& task); void tas_print_task(const tas_task& task, bool details = false); bool tas_service_exists(const tas_config& conf, const char* id, size_t& pos); bool tas_service_running(tas_entry& entry); int main( int argc, char *argv[] ) { tas_config conf; if(argc == 1) { tas_check_opt(conf, 'h', 0, 0); return EXIT_SUCCESS; } for(int i=1; i<argc; i++) { if(argv[i][0] == '-') { size_t len = strlen(argv[i]); for(size_t j=1; j<len; j++) { tas_check_opt(conf, argv[i][j], argc-i, argv+i); } } } tas_init(conf); tas_process_tasks(conf); tas_close(conf); return EXIT_SUCCESS; } void tas_check_opt(tas_config& conf, char opt, int argc_left, char **argv) { switch(opt) { case 'h': { cout << "tAppSvc <-hvarcds> [id|path] [[path|action] [param]]" << endl << endl << "OPTIONS: " << endl << "\t-h USAGE" << endl << "\t-v VERBOSE" << endl << "\t-a <id> <path> [param] ADD SERVICE" << endl << "\t-r <id> REMOVE SERVICE" << endl << "\t-c <id> <action> CONTROL SERVICE" << endl << "\t-d <path> ALT. DATABASE" << endl << "\t-s SHOW SERVICES" << endl << "\t-s <id> STATUS" << endl << endl << "ACTIONS: " << endl << "\tstart START SERVICE" << endl << "\tstop STOP SERVICE" << endl << "\trestart RESTART SERVICE" << endl << endl; exit(EXIT_SUCCESS); } break; case 'v': { conf.verbose = true; } break; case 'a': { tas_task task(SQ_ADD); if(argc_left < 2) { cout << "Too few parameter (-a)" << endl << endl; tas_check_opt(conf, 'h', 0, 0); exit(EXIT_FAILURE); } task.entry.set_id(argv[1]); task.entry.set_path(argv[2]); if(argc_left > 3 && argv[3][0] != '-') task.entry.set_param(argv[3]); conf.tasks.push(task); } break; case 'r': { tas_task task(SQ_REMOVE); if(argc_left < 1) { cout << "Too few parameter (-r)" << endl << endl; tas_check_opt(conf, 'h', 0, 0); exit(EXIT_FAILURE); } task.entry.set_id(argv[1]); conf.tasks.push(task); } break; case 'c': { tas_task task(SQ_CONTROL); if(argc_left < 3) { cout << "Too few parameter (-c)" << endl << endl; tas_check_opt(conf, 'h', 0, 0); exit(EXIT_FAILURE); } task.entry.set_id(argv[1]); if(!strcmp(argv[2], "start")) { task.action = SC_START; } else if(!strcmp(argv[2], "stop")) { task.action = SC_STOP; } else if(!strcmp(argv[2], "restart")) { task.action = SC_RESTART; } else { cout << "Unknown action '" << argv[2] << "' for '" << argv[1] << "'. Skipping" << endl << endl; break; } conf.tasks.push(task); } break; case 'd': { if(argc_left < 1) { cout << "Too few parameter (-d)" << endl << endl; tas_check_opt(conf, 'h', 0, 0); exit(EXIT_FAILURE); } conf.set_db(argv[1]); } break; case 's': { tas_task task(SQ_STATUS); if(argc_left > 1) task.entry.set_id(argv[1]); conf.tasks.push(task); } break; default: { cout << "Unknown parameter '" << opt << "'. Skipping" << endl << endl; } break; } } void tas_init(tas_config& conf) { fstream db(conf.db, ios::binary|ios::in); tas_entry ent; size_t pos = 0; if(db.is_open() == false) { cout << "Database does not exists (" << conf.db << "). Creating and Quitting." << endl << endl; db.open(conf.db, ios::binary|ios::app); db.close(); exit(EXIT_FAILURE); } if(db.rdbuf()->in_avail() > 1) { while(db.rdbuf()->in_avail() > 1) { // SURELY EOF db.read((char*)&ent, sizeof(tas_entry)); conf.services.push_back(pair<tas_entry, long>(ent, pos)); pos = db.tellg(); if(conf.verbose == true) { cout << "read service '" << ent.id << "'" << endl; } } } db.close(); } void tas_close(tas_config& conf) { if(conf.changes == false) return; fstream db(conf.db, ios::binary|ios::out); if(db.is_open() == false) { cout << "Fatal Error: Could not write Database. Quitting." << endl; exit(EXIT_FAILURE); } for(vector< pair<tas_entry, long> >::iterator ent=conf.services.begin(); ent != conf.services.end(); ent++) { if((*ent).second != SDB_SKIP) { db.write((char*)(&(*ent).first), sizeof(tas_entry)); } else if((*ent).second == SDB_SKIP && (ent+1) == conf.services.end()) { char eof = EOF; db.write(&eof, 1); } } db.close(); } void tas_process_tasks(tas_config& conf) { while(conf.tasks.empty() == false) { bool ret = tas_process_task(conf, conf.tasks.front()); if(ret == true) { cout << "Task succeeded: "; tas_print_task(conf.tasks.front()); } else { cout << "Task failed: "; tas_print_task(conf.tasks.front(), true); } conf.tasks.pop(); } } bool tas_process_task(tas_config& conf, tas_task& task) { size_t pos; switch(task.type) { case SQ_ADD: { if(tas_service_exists(conf, task.entry.id, pos) == true) { cout << "Service (" << task.entry.id << ") already exists. Skipping" << endl << endl; return false; } HANDLE hFile = CreateFileA(task.entry.path, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(FAILED(hFile)) { cout << "Path (" << task.entry.path << ") doesn\'t exist. Skipping" << endl << endl; return false; } CloseHandle(hFile); conf.services.push_back(pair<tas_entry, size_t>(task.entry, SDB_ADD)); conf.changes = true; } break; case SQ_REMOVE: { if(tas_service_exists(conf, task.entry.id, pos) == false) { cout << "Service (" << task.entry.id << ") doesn\'t exists. Skipping" << endl << endl; return false; } cout << (*(conf.services.begin()+pos)).first.id << endl; conf.services.at(pos).second = SDB_SKIP; conf.changes = true; } break; case SQ_CONTROL: { if(tas_service_exists(conf, task.entry.id, pos) == false) { cout << "Service (" << task.entry.id << ") doesn\'t exists. Skipping" << endl << endl; return false; } switch(task.action) { case SC_RESTART: { cout << "Restarting Service (" << task.entry.id << ")" << endl; } case SC_STOP: { cout << "Stopping Service (" << task.entry.id << ")" << endl; if(tas_service_running(conf.services.at(pos).first) == false) { cout << "Service (" << task.entry.id << ") already stopped" << endl; } else { HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, conf.services.at(pos).first.pid); if(SUCCEEDED(hProc)) { if(TerminateProcess(hProc, 0) == TRUE) { conf.services.at(pos).first.pid = 0; conf.changes = true; } CloseHandle(hProc); } else { cout << "Unable to stop Process." << endl; } } if(task.action != SC_RESTART) break; } case SC_START: { cout << "Starting Service (" << task.entry.id << ")" << endl; PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); string exec = string(conf.services.at(pos).first.path) + " " + string(conf.services.at(pos).first.param); if(CreateProcessA(0, (char*)exec.c_str(), 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0, &si, &pi) == TRUE) { conf.services.at(pos).first.pid = pi.dwProcessId; cout << "Service running under PID " << conf.services.at(pos).first.pid << endl; conf.changes = true; } else { cout << "Could not start Service " << conf.services.at(pos).first.id << endl; return false; } } break; case SQ_STATUS: { if(conf.services.empty() == true){ cout << "No Services in Database" << endl << endl; return false; } if(task.entry.id[0] == 0) { for(vector< pair<tas_entry, long> >::iterator ent=conf.services.begin(); ent != conf.services.end(); ent++, pos++) { cout << "SERVICE (" << (*ent).first.id << "): " << endl << "\tPath: " << (*ent).first.path << endl << "\tParam: " << (*ent).first.param << endl << "\tState: " << (tas_service_running((tas_entry&)conf.services.at(pos))?"Running":"Stopped") << endl << endl; } } else { if(tas_service_exists(conf, task.entry.id, pos) == false) { cout << "Service (" << task.entry.id << ") doesn\'t exists. Skipping" << endl << endl; return false; } vector< pair<tas_entry, long> >::iterator ent = conf.services.begin()+pos; cout << "SERVICE (" << (*ent).first.id << "): " << endl << "\tPath: " << (*ent).first.path << endl << "\tParam: " << (*ent).first.param << endl << "\tState: " << (tas_service_running((tas_entry&)conf.services.at(pos))?"Running":"Stopped") << endl << endl; } } break; } return true; } void tas_print_task(const tas_task& task, bool details) { switch(task.type) { case SQ_ADD: { cout << "SQ_ADD" << endl; cout << "\tID: " << task.entry.id << endl; if(details == true) { cout << "\tPath: " << task.entry.path << endl; cout << "\tParam: " << task.entry.param << endl; } } break; case SQ_REMOVE: { cout << "SQ_REMOVE" << endl; cout << "\tID: " << task.entry.id << endl; if(details == true) { cout << "\tPath: " << task.entry.path << endl; cout << "\tParam: " << task.entry.param << endl; } } break; case SQ_CONTROL: { cout << "SQ_CONTROL "; switch(task.action) { case SC_START: { cout << "(SC_START)" << endl; } break; case SC_STOP: { cout << "(SC_STOP)" << endl; } break; case SC_RESTART: { cout << "(SC_RESTART)" << endl; } break; } cout << "\tID: " << task.entry.id << endl; if(details == true) { cout << "\tPath: " << task.entry.path << endl; cout << "\tParam: " << task.entry.param << endl; } } break; case SQ_STATUS: { cout << "SQ_STATUS " << endl; } break; } cout << endl; } bool tas_service_exists(const tas_config& conf, const char* id, size_t& pos) { pos = 0; for(vector< pair<tas_entry, long> >::const_iterator ent=conf.services.begin(); ent != conf.services.end(); ent++, pos++) { if(!strcmp(id, (*ent).first.id) && (*ent).second >= SDB_FIRST) return true; } return false; } bool tas_service_running(tas_entry& entry) { if(entry.pid == 0) return false; HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, entry.pid); if(FAILED(hProc)) { return false; } CloseHandle(hProc); return true; } Ein Beispiel: Code: tAppSvc -a ts3_sv1 C:\Teamspeak3\ts3server_win32.exe "Parameter1 Parameter2" tAppSvc -c ts3_sv1 start Wie immer würde ich gerne - aus Anstand - voher informiert werden, bevor ihr etwas kopiert. Grüße. + Multi-Zitat Zitieren
#2 26. April 2011 AW: ApplicationService Wie sollte ich das der guten alten sc.exe vorziehen? Ich meine das ist im Prinzip nicht anderes als eine rudimentäre Kopie der Windows Service Implementierung. + Multi-Zitat Zitieren
#3 26. April 2011 AW: ApplicationService sc funktioniert bei simplen Anwendungen nicht, deswegen wurde dieses Programm geschrieben. + Multi-Zitat Zitieren