Vollständige Version anzeigen : [C/C++] ApplicationService


terraNova
26.04.2011, 17:14

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! ;)

#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:
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.

Hardware Preisvergleich | Amazon Blitzangebote!

Videos zum Thema
Video Loading...
Alex²
26.04.2011, 21:03

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.


terraNova
26.04.2011, 21:11

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.

sc funktioniert bei simplen Anwendungen nicht, deswegen wurde dieses Programm geschrieben.


Ähnliche Themen zu [C/C++] ApplicationService
  • [C/C++] 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 be [...]



raid-rush.ws | Imprint & Contact pr