PDA

Ver la Versión Completa : Sobre la función StartService y sus parámetros


dec
01-02-2007, 16:09:17
Hola,

Existe en la unidad "WinSvc" una función de nombre "StartService". De la documentación en la ayuda de Win32:


BOOL StartService(
SC_HANDLE hService, // handle of service
DWORD dwNumServiceArgs, // number of arguments
LPCTSTR *lpServiceArgVectors // address of array of argument string pointers
);


Es el caso que el segundo y tercer parámetros son opciones, puesto que acaso el Servicio a iniciar no los requiere. En este caso "dwNumServiceArgs" ha de valer "0" y "lpServiceArgVectors" ser "nulo". En Delphi el asunto quedaría de este modo, pues:


begin
{...}
StartService(hService, 0, nil);
end;


Ahora bien, suponiendo que un determinado Servicio requiera de algún parámetro... ¿cómo se los haríamos llegar? O sea, no entiendo cómo trabajar con el parámetro de tipo "lpServiceArgVectors" en la función "StartService".

Entiendo que es un "puntero" lo que hay que pasar a la función, y de hecho podemos hacer algo así:


var
{...}
args: PChar;
begin
{...}
args := 'unparametro';
StartService(hService, 0, args);
end;


O como mucho se me ocurre esto:


var
{...}
args: PChar;
begin
{...}
args := 'unparametro';
StartService(hService, 1, args);
end;


Que acaso sea algo más acercado que lo anterior, porque al menos aquí indicamos que se le envía un parámetro al Servicio... pero, haciendo esto no podemos enviar más de un parámetro al Servicio (si es que funciona siquiera el que intentamos enviar, porque aunque "compila" no he podido probarlo de veras), y además de no poder enviar más parámetros en realidad es que estamos obviando el tipo "lpServiceArgVectors"...

¿Qué se os ocurre? ¿Alguien utilizó alguna vez el tipo "lpServiceArgVectors"? Disculpad el royo... se ve que la síntesis (de cualquier tipo) no es lo mío... ¡y gracias de antemano pataliebres! :D :D :D

seoane
01-02-2007, 17:21:37
El argumento lpServiceArgVectors no es mas que un array de PChar. Así que no tenemos mas que declarar un array y pasarlo como parámetro. Para esto supongo que podremos declarar un array fijo, uno dinámico, o por las malas utilizando punteros ;)

Esta es la función que aparece en los trucos, pero modificada para admitir parámetros:

procedure StartSrv(Nombre: String; Params: TStringList);
var
ServiceControlManager: SC_HANDLE;
Service: SC_HANDLE;
ServiceStatus: SERVICE_STATUS;
Argv, P: ^PChar;
i: integer;
begin
ServiceControlManager:= OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if ServiceControlManager <> 0 then
begin
Service:= OpenService(ServiceControlManager,PChar(Nombre),
SERVICE_QUERY_STATUS or SERVICE_START);
if Service <> 0 then
begin
if QueryServiceStatus(Service, ServiceStatus) then
begin
if ServiceStatus.dwCurrentState <> SERVICE_RUNNING then
begin
if (Params <> nil) and (Params.Count > 0) then
begin
GetMem(Argv,Params.Count * Sizeof(PChar));
try
P:= Argv;
for i:= 0 to Params.Count - 1 do
begin
P^:= PChar(Params[i]);
inc(P);
end;
StartService(Service,Params.Count,Argv^);
finally
FreeMem(Argv);
end;
end else
begin
Argv:= nil;
StartService(Service,0,Argv^);
end;
end;
end;
CloseServiceHandle(Service);
end;
CloseServiceHandle(ServiceControlManager);
end;
end;

// Por ejemplo
var
Params: TStringList;
begin
Params:= TStringList.Create;
try
Params.Add('Uno');
Params.Add('Dos');
Params.Add('Tres');
StartSrv('Service1',Params);
finally
Params.Free;
end;
end;


Ahora si alguien se anima, que lo implemente con arrays dinámicos :p

dec
01-02-2007, 17:41:50
Hola,

Flipante. Sin palabras. Muchas gracias Seoane. :)

dec
01-02-2007, 17:56:53
Hola,

Seoane, seguro que estoy haciendo algo mal, porque en la línea:


P^:= PChar(Params[i]);


Me "dice" el compilador que no son compatibles ambos tipos...

Por otro lado, ¿esto otro funcionaría? Porque compilar compila y un Servicio sin argumentos lo inicia bien, pero, no he probado si funcionaría como se espera en un Servicio con parámetros...


{...}

var
argsv := array of PChar;
FArgumentos: TStringList;

{...}

if (FArgumentos.Count > 0) then begin
SetLength(argsv, FArgumentos.Count);
for i := 0 to FArgumentos.Count-1 do
argsv[i] := PChar(FArgumentos[i]);
end;
StartService(hServicio, FArgumentos.Count, PChar(argsv));
end;


¿O es una burrada? :D :D

EDITO: Je, je, je... bueno... no puedo probarlo "realmente", pero, sí puedo incluir un par de parámetros "a ver qué pasa"... y lo que pasa es que empiezan a salir ventanas de error a diestro y siniestro... una detrás de otra y sin parar... "Access violation"...

Neftali [Germán.Estévez]
01-02-2007, 17:58:44
Prueba algo así:


// El array de PChar y el puntero que lo apunta
type
PStrArray = ^TStrArray;
TStrArray = array[0..2] of PChar;


La variable para el parámetro


var
lpServiceArgVectors: PChar;


Rellenar los parámetros, la llamada y liberar


// proteccion para liberar
try
// Supongamos 3 parametros
GetMem(lpServiceArgVectors, SizeOf(PChar)* 3);
PStrArray(lpServiceArgVectors)^[0] := PChar('Lunes');
PStrArray(lpServiceArgVectors)^[1] := PChar('Martes');
PStrArray(lpServiceArgVectors)^[2] := PChar('Miercoles');
// Arrancar el servicio
StartService({Handle}123456, 3, lpServiceArgVectors);
finally
FreeMem(lpServiceArgVectors);
end;


Un saludo.

EDITO: Tarde, tarde, tarde,... pasé tres horas con el mensaje abierto y ya veo que lo tenéis encarrilado...

dec
01-02-2007, 18:02:27
Hola,

Vale... error mío... el código que pusiste es correcto Seoane, compila perfectamente, lo que ocurre es que estaba declarando las variables tal que así:


var
argv, p: PChar;


Cuando tú lo indicaste correctamente:


var
argv, p: ^PChar;


Todo correcto, pues. No puedo probar que funcionan los parámetros realmente, pero, sí puedo pasar parámetros "a ver qué pasa" sin que ahora se caiga el programa... ¡gracias otra vez, pues! :D

roman
01-02-2007, 18:04:17
Neftali, ¿no se puede declarar lpServiceArgVectors como PStrArray en lugar de PChar para evitar el moldeo en cada asignación y hacerlo sólo al pasarlo a la función?

// Saludos

seoane
01-02-2007, 18:09:12
No puedo probar que funcionan los parámetros realmente


Teniendo un delphi a mano no hay nada que no se pueda hacer :D Crea un proyecto nuevo un "Service Application" y en el evento OnExecute coloca esto:

procedure TService2.ServiceExecute(Sender: TService);
var
i: integer;
begin
for i:= 1 to Self.ParamCount - 1 do
OutputDebugString(PChar(Self.Param[i]));
end;


Compila e instala el servicio. Ahora te preguntaras como puedes ver el resultado, para eso utiliza este programa (http://www.microsoft.com/technet/sysinternals/utilities/debugview.mspx) de Mark Russinovich. Cuando ejecutes el servicio, en el DebugView aparecerán los parámetros con que lo has iniciado.

dec
01-02-2007, 18:09:28
Hola,


Neftali, ¿no se puede declarar lpServiceArgVectors como PStrArray en lugar de PChar para evitar el moldeo en cada asignación y hacerlo sólo al pasarlo a la función?


¡Abuela! ¡Que es Seoane no Neftalí! :D :D

Je, je, je... pero, fuera de bromas... tal vez lo que digas queda más curioso... si bien es cierto que a mí al menos me lo tendrías que traducir un poquitín por lo menos. :D :D

dec
01-02-2007, 18:12:25
Hola,


Teniendo un delphi a mano no hay nada que no se pueda hacer (...)


¡Y que lo tú lo digas! :D No; pero, no sé... es que creo que le estoy dando demasiadas vueltas al asunto... incluso diría que ya está bien, que esto de los parámetros es lo último que me preocupa de lo que traigo entre manos: una sencilla clase (de las tantas y tantas que hay, mucho mejores) que se encargue de controlar un Servicio: desde su instalación, puesta en marcha, detención, etc.

Pero, como digo, ya está bien, leñe, que a lo mejor no es para tanto... de hecho todo empezó para un programilla que uso personalmente para controlar los Servicios de Apache y MySQL. :)

PD. Adjunto la clase (o lo que sea), aunque no la considere terminada (ni lo estará nunca) y acaso en lugar de "TServicio" debería llamarse "TServicioWin32" o algo así... como poco. ;)

seoane
01-02-2007, 18:19:41
Pero, como digo, ya está bien, leñe, que a lo mejor no es para tanto...


De eso nada, el tema de los servicios, al menos a mi, me interesa bastante. Así que cualquier cosa que quieras hablar sobre el tema, por mi estupendo :)

No hace mucho que estoy por este club, pero veo que no es un tema que se toque mucho. Y se me ocurren muchas cosas de que hablar: el control de un servicio en una maquina remota, la comunicación de un servicio con una aplicación de usuario, interactuar con el usuario actual, es decir con su desktop, teniendo en cuenta que los servicios interactivos se acabaron con el nuevo Vista, etc ... Si señor, hay mucho de que hablar sobre el tema.

dec
01-02-2007, 18:27:11
Hola,

No, si eso es lo malo, precisamente, que habría que dedicarle a ello un tiempo considerable, además de un esfuerzo, una voluntad y demás... pero soy perfectamente consciente de ello. Bueno. Un poco. Cuando dije que no era para tanto me estaba refiriendo a mis necesidades únicamente.

Es decir, en el Monitor de los Servicios de Apache y MySQL que programé para mi uso precisaba de una serie de funciones típicas para controlar un determinado Servicio. Me dio fuerte y conseguí escribir siguiendo la ayuda y no pocos ejemplos las funciones que necesitaba.

Hace poco he retomado el Monitor de marras y he tratado de mejorarlo en algunos aspectos. Y lo he conseguido... pero ya empieza a ser demás, es decir, por ejemplo, la clase "TServicio" hace ya mucho más (independientemente ahora de si lo hace mejor o peor) de lo que necesita el programa Monitor.

Y como por otro lado no es algo que me apasione (como a ti, que me parece estupendo) el tema de los Servicios.... pues por eso decía que no era para tanto, pero no porque el tema de los Servicios no de para mucho... todo lo contrario. :)

Neftali [Germán.Estévez]
01-02-2007, 18:35:39
Neftali, ¿no se puede declarar lpServiceArgVectors como PStrArray en lugar de PChar para evitar el moldeo en cada asignación y hacerlo sólo al pasarlo a la función?


Supongo que sí (la verdad es que está así por comodidad, realmente no es lo más eficiente), y luego hacer la llamada como PChar.
No lo he probado, pero debe funcionar ¿no?

Neftali [Germán.Estévez]
01-02-2007, 18:41:10
..utiliza este programa (http://www.microsoft.com/technet/sysinternals/utilities/debugview.mspx) de Mark Russinovich.

Buen programa...
(SysInternals, como no... ;))

roman
01-02-2007, 20:12:02
¡Abuela! ¡Que es Seoane no Neftalí! :D :D


:confused: La pregunta sí era para Neftali.

// Saludos

dec
01-02-2007, 20:20:03
Hola,

Pues me equivoqué entonces. Aunque es un poco raro, ¿no? ;)

Neftali [Germán.Estévez]
02-02-2007, 12:04:12
Aunque es un poco raro, ¿no? ;)

:confused::confused::confused: Yo estoy igual que Román. No entiendo. ¿Donde está lo raro?

Alguien aquí se ha despistado... :p

dec
02-02-2007, 12:08:33
Hola,

El raro soy yo... es decir, que soy el despistado. No había tu mensaje Neftalí, y de ahí mi confusión. Lo que ya roza lo absurdo es que hize por mirarlo... es decir, cuando repliqué a Román como lo hize fue, precisamente, porque había "revisado" el Hilo y no ví tu mensaje y entendí que Román se había confundido.

Edito: Además de despistado no quiero ser maleducado: os pido disculpas a ambos Román y Neftalí. :)

roman
02-02-2007, 17:42:05
No te preocupes, supuse que era algo por el estilo pero ayer cuando lo ví ya no tuve tiempo de responder.

// Saludos

fide
01-03-2008, 04:17:02
Hola,



¡Y que lo tú lo digas! :D No; pero, no sé... es que creo que le estoy dando demasiadas vueltas al asunto... incluso diría que ya está bien, que esto de los parámetros es lo último que me preocupa de lo que traigo entre manos: una sencilla clase (de las tantas y tantas que hay, mucho mejores) que se encargue de controlar un Servicio: desde su instalación, puesta en marcha, detención, etc.

Pero, como digo, ya está bien, leñe, que a lo mejor no es para tanto... de hecho todo empezó para un programilla que uso personalmente para controlar los Servicios de Apache y MySQL. :)

PD. Adjunto la clase (o lo que sea), aunque no la considere terminada (ni lo estará nunca) y acaso en lugar de "TServicio" debería llamarse "TServicioWin32" o algo así... como poco. ;)

Dec, a la verdad que no se por que razon dices que esa clase no esta terminada, por que por lo que veo, hace todo lo que tiene que hacer y sobre todo de la manera correcta. Es algo bueno de verdad para el trabajo con los dichosos servicios esos. A mi me ha servido para lo que quiero perfectamente...

Gracias.....