Starten von Programmen aus einem Service ...



  • Hallo,

    nachdem ich nun einen Service erzeugen konnte,
    habe ich das Shellexecute ausprobiert und festgestellt, das
    dieses aus einem Service heraus keine Wirkung hat 😞
    Wie macht man es dann ?
    Es geht praktisch darum, das man OHNE eingeloggt zu sein
    ein Programm mit einem Benutzerkonto starten kann.
    Oder so ähnlich ...

    mfg
    thenoname



  • Teste mal eine der Beiden Funktionen aus folgender Datei (code in ne .h datei speichern un din Projekt einbilden) ... in meinen Service funktionierts so ...
    hab diese Funktionen mal von www.codeguru.com geloadet ... hab sie also nicht selbst geschrieben! (damit keiner denkt ich würd code stehlen und ihn für meinen ausgeben ) ...

    #include "windows.h"
    #include <process.h>
    
    BOOL RunProcessAndForget(CString sCmdLine,
                             CString sRunningDir,
                             int *nRetValue);
    
    BOOL RunProcessAndWait(CString sCmdLine, 
                           CString sRunningDir, 
                           int *nRetValue);
    
    //---------------------------------------------------------
    // Run a synchronized other command line EXE. Returns only 
    // after this exits. The process is runned as a console window.
    // Returns Values : TRUE if the process was created
    //                  FALSE if not.
    // see *nRetValue for the LastError number
    BOOL RunProcessAndWait(CString sCmdLine, 
                           CString sRunningDir, 
                           int *nRetValue)
    {
     int nRetWait;
     int nError;
    
     // That means wait 300 s before returning an error
     // You can change it to the value you need.
     // If you want to wait for ever just use 'dwTimeout = INFINITE'>
     DWORD dwTimeout = 1000 *300; 
    
     STARTUPINFO stInfo;
     PROCESS_INFORMATION prInfo;
     BOOL bResult;
     ZeroMemory( &stInfo, sizeof(stInfo) );
     stInfo.cb = sizeof(stInfo);
     stInfo.dwFlags=STARTF_USESHOWWINDOW;
     stInfo.wShowWindow=SW_MINIMIZE;
    
     bResult = CreateProcess(NULL, 
                             (LPSTR)(LPCSTR)sCmdLine, 
                             NULL, 
                             NULL, 
                             TRUE,
                             CREATE_NEW_CONSOLE 
                             | NORMAL_PRIORITY_CLASS,
                             NULL,
                             (LPCSTR)sRunningDir,
                             &stInfo, 
                             &prInfo);
     *nRetValue = nError = GetLastError();
    
     if (!bResult) return FALSE;
      nRetWait =  WaitForSingleObject(prInfo.hProcess,dwTimeout);
    
     CloseHandle(prInfo.hThread); 
     CloseHandle(prInfo.hProcess); 
    
     if (nRetWait == WAIT_TIMEOUT) return FALSE;
      return TRUE;
    }
    //---------------------------------------------------------
    // This function call a command line process.
    // Returns Values : TRUE if the process was created
    //                  FALSE if not.
    // see *nRetValue for the LastError number
    BOOL RunAndForgetProcess(CString sCmdLine,
                             CString sRunningDir,
                             int *nRetValue)
    {
     int nRetWait;
     int nError;
     STARTUPINFO stInfo;
     PROCESS_INFORMATION prInfo;
     BOOL bResult;
     ZeroMemory( &stInfo, sizeof(stInfo) );
     stInfo.cb = sizeof(stInfo);
     stInfo.dwFlags=STARTF_USESHOWWINDOW;
     stInfo.wShowWindow=SW_MINIMIZE;
    
     bResult = CreateProcess(NULL, 
                             (LPSTR)(LPCSTR)sCmdLine, 
                             NULL, 
                             NULL, 
                             TRUE,
                             CREATE_NEW_CONSOLE 
                             | NORMAL_PRIORITY_CLASS ,
                             NULL,
                             (LPCSTR)sRunningDir ,
                             &stInfo, 
                             &prInfo);
     *nRetValue = nError = GetLastError();
    
     // Don't write these two lines if you need
     CloseHandle(prInfo.hThread); 
    
     class="codeComment">// to use these handles
     CloseHandle(prInfo.hProcess);
    
     if (!bResult) return FALSE;
      return TRUE;	
    }
    


  • Ja,
    die CreateProcess habe ich nun auch verwendet ...
    Klappt gut, auch ohne weitere Prameter. Die zwei letzten
    Strukturen sind bei mir mit zero gefüllt, dürfen aber nicht
    NULL sein.
    Habe allerdings festgestellt, das bei fehlender Datei es einen
    Crash des Services gibt ...
    Nun kann ich also ohne logon Programme starten, wenn ich eine
    Joysticktaste drücke. (naja, wers halt braucht)

    Desweiteren gibt es noch CreatProcessWithLogonW und CreateProcessAsUser.
    Die sind allerdings erst ein Studium wert, um Nutzen ziehen zu können.

    Danke für den Code ...
    thenoname



  • Freut mich, dass ich Dir helfen konnte,
    aber wollte mal fragen, ob Du auf folgendes Problem, was ich grad habe ne antwort hast:

    Ich bastle grad einen Service ... hat bis jetzt auch gut geklappt, wollte
    jetzt allerdings ein Client Programm schreiben was den Service Verwaltet (Einstellungen ändert usw.) deshalb hab ich eine CAsyncSocket klasse geschrieben. ich hab die Klasse in einer "normalen" Dialogfeld Anwendung getestet, sie funktioniert einwandfrei (is nur zum test, die sendet wenn man irgendwas an sie sendet einfach ein "hallo" zurück, dieser Send befehl steht inder überschriebenen OnReceive Funktion) , wenn ich diese Klasse aber in dem Service Einbinde kann man zwar connecten, aber die überschriebene OnAccept Funktion wird nie ausgeführt, wodurch man ja nich richtig connectet ist ... ich hab die Vermutung, dass in einen Service solche ereignisse, wie Connecting und Receive nicht augelöst werden, oder liege ich da falsch ?!? (hab bis jetzt mit Services keine Erfahrung, und mit Sockets nur nen bisschen *g* ) ...

    hab das schon allgemein als Thema gepostet, hat noch keiner geantwortet, aber ich dachte du hättest vielleich davon Ahnung ????!!!!??? 😕



  • post mal den code den du bis her hast!
    dann können wir besser analysieren!

    cu



  • ja ich poste erst mal nen Teil .. is nämlich viel .... ich glaub dass es daran liegt, dass so was wie die MessageMap von nen "normalen" Windows Programmen dort fehlt (is aber nur so ne Vermutung ... ich bin nich soo der Held, was WinAPI Programmierung angeht 🙄 ) ... aber hier erst mal der Code:

    erstmal die Socketklasse:

    #if !defined(AFX_MYSOCKET_H__72590960_C463_4A50_9FE6_B08F623A9D3D__INCLUDED_)
    #define AFX_MYSOCKET_H__72590960_C463_4A50_9FE6_B08F623A9D3D__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    // MySocket.h : header file
    
    class CMySocket : public CAsyncSocket
    {
    // Attributes
    public:
    
    // Operations
    public:
    	CMySocket();
    	virtual ~CMySocket();
    
    	//CListBox* Out;
    
    	CMySocket* So1;
    	CMySocket* So2;
    	CMySocket* So3;
    
    // Overrides
    public:
    	void SetParent(CDialog* pWnd);
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CMySocket)
    	//}}AFX_VIRTUAL
    
    	// Generated message map functions
    	//{{AFX_MSG(CMySocket)
    		// NOTE - the ClassWizard will add and remove member functions here.
    	//}}AFX_MSG
    
    // Implementation
    protected:
    	void OnReceive(int nErrorCode);
    	void OnSend(int nErrorCode);
    	void OnClose(int nErrorCode);
    	void OnConnect(int nErrorCode);
    	void OnAccept(int nErrorCode);
    private:
    	CDialog* m_pWnd;
    };
    /////////////////////////////////////////////////////////////////////////////
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_MYSOCKET_H__72590960_C463_4A50_9FE6_B08F623A9D3D__INCLUDED_)
    
    // MySocket.cpp : implementation file
    //
    
    #include "stdafx.h"
    //#include "sock.h"
    #include "MySocket.h"
    //#include "SockDlg.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CMySocket
    
    CMySocket::CMySocket()
    {
    //	Out = NULL;
    	So1 = NULL;
    	So2 = NULL;
    	So3 = NULL;
    }
    
    CMySocket::~CMySocket()
    {
    }
    
    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CMySocket, CAsyncSocket)
    	//{{AFX_MSG_MAP(CMySocket)
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif	// 0
    
    /////////////////////////////////////////////////////////////////////////////
    // CMySocket member functions
    
    void CMySocket::SetParent(CDialog *pWnd)
    {
    // Elementzeiger setzen
         m_pWnd = pWnd;
    }
    
    void CMySocket::OnAccept(int nErrorCode)
    {
     // Sind Fehler aufgetreten?
     //    if (nErrorCode == 0)
             // Nein, OnAccept-Funktion des Dialogfelds aufrufen
    //          ((CSockDlg*)m_pWnd)->OnAccept();
    	//So2 = new CMySocket;
    //	if(So1->Accept(*So2)) Out->AddString("Accept");
    	So1->Accept(*So2);
    
    }
    
    void CMySocket::OnConnect(int nErrorCode)
    {
    // Sind Fehler aufgetreten?
         if (nErrorCode == 0)
    	 {
    		 //Out->AddString("Connected");
    	 }
             // Nein, OnAccept-Funktion des Dialogfelds aufrufen
      //        ((CSockDlg*)m_pWnd)->OnConnect();
    }
    
    void CMySocket::OnClose(int nErrorCode)
    {
    // Sind Fehler aufgetreten?
         if (nErrorCode == 0)
    	 {
    	//	 Out->AddString("Disconnected");
    		 So2->Close();
    		 //So1->Listen();
    	 }
    }
    
    void CMySocket::OnSend(int nErrorCode)
    {
    // Sind Fehler aufgetreten?
    //     if (nErrorCode == 0)
             // Nein, OnAccept-Funktion des Dialogfelds aufrufen
    //          ((CSockDlg*)m_pWnd)->OnSend();
    }
    
    void CMySocket::OnReceive(int nErrorCode)
    {
    // Sind Fehler aufgetreten?
    //     if (nErrorCode == 0)
             // Nein, OnAccept-Funktion des Dialogfelds aufrufen
    //          ((CSockDlg*)m_pWnd)->OnReceive();
    
    	char Buff[1024];
    	int i;
    
    	if (nErrorCode == 0)
    	{
    		if(So2 == NULL)  return;
    		i = So2->Receive(Buff, 512);
    		Buff[i] = 0;
    		//Out->AddString(Buff);
    	}
    
    	strcpy(Buff, "Hallo Welt !!!");
    	So2->Send(Buff, strlen(Buff));
    
    	//Out->AddString("sdsssss");
    }
    


  • und jetzt noch die Endlosschleife, die mein Service ausführt:

    void EndlessLoop()
    {
    //	Output("EndlessLoop Start\n");
    
    	SYSTEMTIME Clock;
    	CString Out;
    	HANDLE hTimer;
    	bool StartSock = true;
    	CMySocket Sock;
    	CMySocket Sock2;
    
    	hTimer = ::CreateWaitableTimer(0, FALSE, "DemoService-Timer");
    
    	// This endlessloop is killed by Windows when the service is stopped or shutdown
    	while (1)
    	{
    		if (hTimer != 0)
    		{
    			LARGE_INTEGER Elapse;
    			Elapse.QuadPart = -10000000; // 1 Seconds in 100 Nanoseconds resolution (negative=relative)
    			BOOL Res = ::SetWaitableTimer(hTimer, &Elapse, 0, 0, 0, TRUE);
    
    			if (Res)
    			{
    				DWORD Event = WaitForSingleObject(hTimer, 300000); // 30 seconds timeout
    				// Event = (258=WAIT_TIMEOUT) (128=WAIT_ABANDONED) (0=WAIT_OBJECT_0) (0xFFFFFFFF=WAIT_FAILED)
    			}
    		}
    
    		::GetLocalTime(&Clock);
    //############################################################################		
    //############################################################################
    //############################################################################
    
    	CFtpGet ftp;
    	List Commands;
    	char LogBuff[3000];
    	char CTemp[512];
    //	char Time[16];
    //	CString CTime;
    //	CString CSetTime;
    	CString JobTime;
    	CString RealTime;
    	CString JobDate;
    	CString RealDate;
    	bool Run = false;
    	unsigned int JobCount;
    	unsigned int i = 0;
    	Job* JobSet;
    
    /*	_strtime(Time);
    	CTime = Time;
    	CSetTime = g_Service.Settings.StartTime;
    	CTime = CTime.Mid(0, 8);
    	CSetTime = CSetTime.Mid(0, 8);*/
    
    	if(StartSock == true)
    	{
    		Sock.So1 = &Sock;
    		Sock.So2 = &Sock2;
    
    		Sock2.So1 = &Sock;
    		Sock2.So2 = &Sock2;
    
    		Sock.Create(4000);
    		Sock.Listen();
    
    		StartSock = false;
    	}
    
    	JobCount = g_Service.JobList.GetCount();
    
    	char ww[16];
    	_itoa( JobCount, ww, 10 );// wandelt int in char um
    
    	while(i < JobCount)
    	{
    		JobSet = (Job*)g_Service.JobList.GetPoint(i, false);
    		JobDate = JobSet->StartDate;
    		JobTime = JobSet->StartTime;
    
    		//_strdate(CTemp);
    		GetDate(CTemp);
    		RealDate = CTemp;
    		_strtime(CTemp);
    		RealTime = CTemp;
    
    		Run = false;
    		if(DateABiggerDateB(RealDate, JobDate) == true)
    		{
    			if(TimeABiggerTimeB(RealTime, JobTime) == true) Run = true;
    		}
    
    		i++;
    		if(Run == true)
    		{
    			Commands.DelAll();
    			Commands.SetSize(2048);
    
    			if(FileExist(JobSet->ComFile) == false)
    			{
    				Log("ERROR!!! Command  - File do not exist or unable to open !!!", true);
    				return;
    			}
    
    			Log("\r\n", false);
    			Log("\r\n", false);
    			strcpy(LogBuff, "Job starting with Commandfile: ");
    			strcat(LogBuff, JobSet->ComFile);
    			Log(LogBuff, true);
    
    			ExecuteSkript(JobSet->ComFile, &Commands, &ftp);
    
    			Log("Job Finish", true);
    			DelOrReBuildJob(i-1, &g_Service.JobList);
    			i = 0;
    			JobCount = g_Service.JobList.GetCount();
    		}
    	}
    //############################################################################
    //############################################################################
    //############################################################################
    
    	};
    }
    


  • und noch die Service Klasse:

    // cService.h: interface for the cService class.
    //
    //////////////////////////////////////////////////////////////////////
    
    #if !defined(AFX_CSERVICE_H__FD1A6E41_AAFB_11D7_A8B4_000AE637F271__INCLUDED_)
    #define AFX_CSERVICE_H__FD1A6E41_AAFB_11D7_A8B4_000AE637F271__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #include "winsvc.h"
    
    class cService  
    {
    public:
    	cService();
    	virtual ~cService();
    
    	DWORD Start();
    	DWORD Stop();
    	DWORD Create();
    	DWORD Delete();
    
    	void Dispatch();
    	void MainStart   (DWORD argc, LPTSTR *argv);
    	void ControlHandler (DWORD Opcode);
    
    	Set Settings;
    	List JobList;
    	AppPathStr AppPathSt;
    	bool Running;
    private:
    
    	SERVICE_STATUS_HANDLE  hdlStat;
    
    };
    
    #endif // !defined(AFX_CSERVICE_H__FD1A6E41_AAFB_11D7_A8B4_000AE637F271__INCLUDED_)
    
    // cService.cpp: implementation of the cService class.
    //
    //////////////////////////////////////////////////////////////////////
    
    #include "stdafx.h"
    #include "Service.h"
    #include "cService.h"
    
    #ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #define new DEBUG_NEW
    #endif
    
    extern Set Settings;
    
    // global instance of Service
    cService g_Service;
    
    cService::cService()
    {
    	Running = false;
    }
    
    cService::~cService()
    {
    
    }
    // return Errorcode or 0
    // Install the service when user clicks the Create button
    DWORD cService::Create()
    {
    	SC_HANDLE hdlSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
    
    	CString Calling = ::GetCommandLine();
    	Calling += " /Service";
    
    	if (hdlSCM == 0) return ::GetLastError();
    
    	SC_HANDLE hdlServ = CreateService(
    		hdlSCM,                    // SCManager database 
    		ServiceName,               // name of service 
    		ServiceDisplayName,        // service name to display 
    		STANDARD_RIGHTS_REQUIRED,  // desired access 
    		SERVICE_WIN32_OWN_PROCESS, // service type 
    		SERVICE_DEMAND_START,      // start type 
    		SERVICE_ERROR_NORMAL,      // error control type 
    		Calling,                   // service's binary Path name
    		0,                      // no load ordering group 
    		0,                      // no tag identifier 
    		0,                      // no dependencies 
    		0,                      // LocalSystem account 
    		0);                     // no password 
    
    	DWORD Ret = 0;
    	if (!hdlServ) Ret = ::GetLastError();
        CloseServiceHandle(hdlServ);
    	return Ret;
    }
    
    // return Errorcode or 0
    // Uninstall the service when user clicks the Delete button
    DWORD cService::Delete()
    {
    	SC_HANDLE hdlSCM = OpenSCManager(0, 0, STANDARD_RIGHTS_REQUIRED);
    
    	if (!hdlSCM) return ::GetLastError();
    
    	SC_HANDLE hdlServ = OpenService(hdlSCM, ServiceName, DELETE);
    
    	DWORD Ret = 0;
    	if (!DeleteService(hdlServ)) Ret = ::GetLastError();
    	CloseServiceHandle(hdlServ);
    	return Ret;
    }
    
    // return Errorcode or 0
    // Start the service when user clicks the Start button
    DWORD cService::Start()
    {
    	SC_HANDLE hdlSCM = OpenSCManager(0, 0, STANDARD_RIGHTS_REQUIRED);
    
    	if (!hdlSCM) return ::GetLastError();
    
    	SC_HANDLE hdlServ = OpenService(hdlSCM, ServiceName, SERVICE_START);
    
    	DWORD Ret = 0;
    	if (!StartService(hdlServ, 0, 0)) Ret = ::GetLastError();
    	CloseServiceHandle(hdlServ);
    	Running = true;
    	return Ret;
    }
    
    // return Errorcode or 0
    // Stop the service when user clicks the Stop button
    DWORD cService::Stop()
    {
    	SC_HANDLE hdlSCM = OpenSCManager(0, 0, STANDARD_RIGHTS_REQUIRED);
    
    	if (!hdlSCM) return ::GetLastError();
    
    	SC_HANDLE hdlServ = OpenService(hdlSCM, ServiceName, SERVICE_STOP);
    
    	SERVICE_STATUS ServStat;
    	DWORD Ret = 0;
    	if (!ControlService(hdlServ, SERVICE_CONTROL_STOP, &ServStat)) Ret = ::GetLastError();
    	CloseServiceHandle(hdlServ);
    	Running = false;
    	return Ret;
    }
    
    // this function must be in global namespace (Windows API callback)
    void ApiServiceMainStarter(DWORD argc, LPTSTR *argv);
    
    void ApiServiceMainStarter(DWORD argc, LPTSTR *argv)
    {
    	g_Service.MainStart(argc, argv);
    } 
    
    // this function must be in global namespace (Windows API callback)
    void ApiServiceControlHandler(DWORD Opcode);
    
    void ApiServiceControlHandler(DWORD Opcode)
    {
    	g_Service.ControlHandler(Opcode);
    }
    
    // Service Main Function called by Windows
    void cService::MainStart(DWORD argc, LPTSTR *argv)
    {
    	CString Out = *argv;
    	//Output("Service Main -- Start with Arguments: \"" + Out + "\"");
    
    	if(!AfxSocketInit())
    {
    	AfxMessageBox("Could not initialize Windows Sockets!");
    	return ;
    }
    
        hdlStat = ::RegisterServiceCtrlHandler(ServiceName, (LPHANDLER_FUNCTION) ApiServiceControlHandler);
         if (!hdlStat) 
        { 
    		int Err = ::GetLastError();
    		Out.Format("Service Main -- RegisterServiceHandler Error : %d\n", Err);
    		//Output(Out);
            return; 
        } 
    	//else Output("Service Main -- RegisterServiceHandler");
    
    	ControlHandler (0); // Set status Running
    
    	LoadAppPath(&AppPathSt);
    
    	LoadSettings(&Settings);
    
    	LoadJobs(&JobList);
    
    	EndlessLoop(); // Do the service work (write to logfile every 5 seconds)
    
    	JobList.DelAll();
    }
    
    // Start the service (in the Exe which is running as Service!!)
    void cService::Dispatch()
    {
    	SERVICE_TABLE_ENTRY DispTbl[] = 
    	{
    		{ ServiceName, (LPSERVICE_MAIN_FUNCTION) ApiServiceMainStarter},
    		{ 0 , 0}
    	}; 
    
    	//Output("Dispatch -- Before calling StartServiceCtrlDispatcher\n");
    
    	if (!::StartServiceCtrlDispatcher(DispTbl)) // does not return until service stopped
    	{
    		int Err = ::GetLastError();
    		CString Out;
    		Out.Format("Dispatch -- StartServiceCtrlDispatcher Error : %d\n", Err);
    		//Output(Out);
    	}
    	//else Output("Dispatch -- Returning from StartServiceCtrlDispatcher\n");
    }
    
    // Control Handler handles Start / Stop events
    void cService::ControlHandler(DWORD Opcode)
    {
    	SERVICE_STATUS  strctStat;
        strctStat.dwServiceType        = SERVICE_WIN32; 
        strctStat.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
        strctStat.dwWin32ExitCode      = NO_ERROR;
        strctStat.dwServiceSpecificExitCode = 0; // returned Status code
        strctStat.dwCheckPoint         = 0;      // returned Error code
        strctStat.dwWaitHint           = 0;
    
    	CString Command, Status;
    	if (Opcode == SERVICE_CONTROL_STOP)
    	{
    		Command = "CONTROL_STOP";
    		strctStat.dwCurrentState = SERVICE_STOPPED;
    		Status  = "SERVICE_STOPPED";		
    	}
    	else if (Opcode == SERVICE_CONTROL_SHUTDOWN)
    	{
    		Command = "CONTROL_SHUTDOWN";
    		strctStat.dwCurrentState = SERVICE_STOPPED;
    		Status  = "SERVICE_STOPPED";		
    	}
    	else if (Opcode == SERVICE_CONTROL_INTERROGATE)
    	{
    		Command = "CONTROL_INTERROGATE";
    		strctStat.dwCurrentState = SERVICE_RUNNING; 
    		Status  = "SERVICE_RUNNING";		
    	}
    	else
    	{
    		Command.Format("Command Opcode Nr. %d ", Opcode);
    		strctStat.dwCurrentState = SERVICE_RUNNING; 	
    		Status  = "SERVICE_RUNNING";
    	}
    
    	//if (Opcode != 0) Output("Control Handler -- received Command "+Command);
    
        if (!SetServiceStatus (hdlStat, &strctStat)) 
        { 
    		int Err = ::GetLastError();
    		CString Out;
    		Out.Format("Control Handler -- Set Status Error : %d", Err);
    	//	Output(Out);
            return; 
        } 
    	//else Output("Control Handler -- SetStatus "+Status);
    }
    

Anmelden zum Antworten