Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   API de Windows (https://www.clubdelphi.com/foros/forumdisplay.php?f=7)
-   -   Sobre la función StartService y sus parámetros (https://www.clubdelphi.com/foros/showthread.php?t=39894)

dec 01-02-2007 16:09:17

Sobre la función StartService y sus parámetros
 
Hola,

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

Código:

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:

Código Delphi [-]
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í:

Código Delphi [-]
var
  {...}
  args: PChar;
begin
    {...}
   args := 'unparametro';
    StartService(hService, 0, args);
 end;

O como mucho se me ocurre esto:

Código Delphi [-]
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:
Código Delphi [-]
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:

Código Delphi [-]
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...

Código Delphi [-]
{...}

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í:

Código Delphi [-]
  // 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

Código Delphi [-]
var
  lpServiceArgVectors: PChar;

Rellenar los parámetros, la llamada y liberar

Código Delphi [-]
  // 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í:

Código Delphi [-]
var
  argv, p: PChar;

Cuando tú lo indicaste correctamente:

Código Delphi [-]
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

Cita:

Empezado por dec
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:
Código Delphi [-]
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 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,

Cita:

Empezado por Román
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

1 Archivos Adjunto(s)
Hola,

Cita:

Empezado por Seoane
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

Cita:

Empezado por dec
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

Cita:

Empezado por roman
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

Cita:

Empezado por seoane
..utiliza este programa de Mark Russinovich.

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

roman 01-02-2007 20:12:02

Cita:

Empezado por dec
¡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

Cita:

Empezado por dec
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

Clase marabillosa
 
Cita:

Empezado por dec (Mensaje 180237)
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.....


La franja horaria es GMT +2. Ahora son las 21:12:58.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi