Newsgroup: it.comp.programmare.win32
Titolo: CreateProcess dentro servizio su Win2k

Ciao,
è un po' di tempo che mi stò rompendo la testa su un servizio nt che ho
scritto.
Questo servizio semplicemente lancia un altro programma con CreateProcess
Tutto funziona a meraviglia.
Il problema è che quando faccio il logoff termina il processo figlio, ma il
servizio rimane attivo.
Come posso fare per far sopravvivere il processo figlio?
Ho provato di tutto, o quasi, penso che però una soluzione esista...
Ho anche guardato sui sorgenti di apache e ho visto che lì si fa uso della
funzione SetConsoleCtrlHandler per intercettare il logoff nel servizio.
Ho provato, lo intercetto, ma poi il processo figlio muore lo stesso.
Non posso modificare il programma figlio, altrimenti avrei unito servizio e
prog figlio...
Grazie a chi mi saprà dare una soluzione.

 figlio, ma il servizio rimane attivo.
il tuo servizio è interattivo? se sì, è normale. O lo rendi non 
interattivo, o avvii il processo figlio in una window station non 
interattiva
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.20. C, C++ and ASM developers
                              and beta testers are welcome!


Se ti riferisci al flag SERVICE_INTERACTIVE_PROCESS
allora il mio servizio non è interattivo, perché non l'ho usato.

 interattiva
Ho capito  una cosa. Il prog figlio viene chiuso perché riceve
WM_QUERYENDSESSION.
Vorrei provare a bloccare il messaggio con un hook di sistema visto che non
posso modificare l'applicazione. è una soluzione fattibile?

 fattibile? 
no, è una soluzione sbagliata. Che ne dici di dirmi di più su cosa fa 
questo programma che avvii?



il prog č il tnameserv.exe, sono un programmatore java.. e per questo non ci
capisco nulla di win32.
se vuoi ti mando il codice in pvt

 win32. se vuoi ti mando il codice in pvt
preferirei sul newsgroup, cosě possono beneficiarne tutti


ecco i sorgenti del mio servizio. Ho inserito anche l'hook di sistema, ma
non funziona bene.
nella voce di registro che leggo c'è semplicemente il path assoluto del
programma
g:\jbuilder6\jdk1.3.1\bin\tnameserv.exe
il codice è un po' incasinato per le prove... mi scuso.
#include <windows.h>
#include <tchar.h>
#include <iostream.h>
#include <fstream.h>
#define SERVICE_TYPE  SERVICE_WIN32_OWN_PROCESS
// chiavi di registro da cui legge il nome del programma da lanciare
#define REG_KEY       "SOFTWARE\\Cartotecnica"
#define REG_PROPERTY  "nameserver"
// file di log usato per il debug
ofstream *mioFile;
// puntatore a funzione callback usata per l'hook di sistema
typedef LRESULT (CALLBACK* LPFNDLLFUNC1)(INT, WPARAM, LPARAM);
TCHAR* serviceName = TEXT("Corba Name Server");
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE stopServiceEvent = 0;
HHOOK hhook;
/*
// callback consolectrl per intercettare messaggi a console
// NB: viene usata solo per prova
static BOOL CALLBACK ap_control_handler(DWORD ctrl_type)
{
    switch (ctrl_type)
    {
        case CTRL_C_EVENT:
        case CTRL_BREAK_EVENT:
        case CTRL_LOGOFF_EVENT:
//                MessageBeep(MB_OK);
                (*mioFile) << "Logoff" << endl;
        case CTRL_CLOSE_EVENT:
        case CTRL_SHUTDOWN_EVENT:
                return TRUE;
        default:
                return FALSE;
    }
}
*/
void WINAPI ServiceControlHandler( DWORD controlCode )
{
 switch ( controlCode )
 {
  case SERVICE_CONTROL_INTERROGATE:
   break;
  case SERVICE_CONTROL_SHUTDOWN:
  case SERVICE_CONTROL_STOP:
   serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
   SetServiceStatus( serviceStatusHandle, &serviceStatus );
   SetEvent( stopServiceEvent );
   return;
  case SERVICE_CONTROL_PAUSE:
   break;
  case SERVICE_CONTROL_CONTINUE:
   break;
  default:
   if ( controlCode >= 128 && controlCode <= 255 )
    // user defined control code
    break;
   else
    // unrecognised control code
    break;
 }
 SetServiceStatus( serviceStatusHandle, &serviceStatus );
}
void WINAPI ServiceMain( DWORD /*argc*/, TCHAR* /*argv*/[] )
{
 // initialise service status
 serviceStatus.dwServiceType = SERVICE_TYPE;
 serviceStatus.dwCurrentState = SERVICE_STOPPED;
 serviceStatus.dwControlsAccepted = 0;
 serviceStatus.dwWin32ExitCode = NO_ERROR;
 serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
 serviceStatus.dwCheckPoint = 0;
 serviceStatus.dwWaitHint = 0;
 serviceStatusHandle = RegisterServiceCtrlHandler( serviceName,
ServiceControlHandler );
 if ( serviceStatusHandle )
 {
  // service is starting
  serviceStatus.dwCurrentState = SERVICE_START_PENDING;
  SetServiceStatus( serviceStatusHandle, &serviceStatus );
  // do initialisation here
  stopServiceEvent = CreateEvent( 0, FALSE, FALSE, 0 );
  // running
  serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
  serviceStatus.dwCurrentState = SERVICE_RUNNING;
  SetServiceStatus( serviceStatusHandle, &serviceStatus );
  STARTUPINFO si = {
sizeof(STARTUPINFO),NULL,NULL,NULL,0,0,0,0,0,0,0,STARTF_USESTDHANDLES,SW_HID
E,0,NULL,0,0,0};
  PROCESS_INFORMATION pi;
                // leggo il nome del file eseguibile dal registro di sistema
                DWORD   rc;
                DWORD   MaxData;
                HKEY    hKeyCartotecnica;
                char    szAppName[MAX_PATH];
                rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                        REG_KEY,
                        0,
                        KEY_READ | KEY_QUERY_VALUE ,
                        &hKeyCartotecnica);
                if (rc != ERROR_SUCCESS) {
   DWORD lastError = GetLastError();
   (*mioFile) << "Error Reading registry " << lastError << endl;
   LPVOID lpMsgBuf;
   FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER |
     FORMAT_MESSAGE_FROM_SYSTEM |
     FORMAT_MESSAGE_IGNORE_INSERTS,
     NULL,
     lastError,
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
     (LPTSTR) &lpMsgBuf,
     0,
     NULL
     );
   (*mioFile) << "     " << (LPCTSTR)lpMsgBuf << endl;
   // Free the buffer.
   LocalFree( lpMsgBuf );
                        exit(1);
                }else{
                        RegQueryValueEx( hKeyCartotecnica,
                                (LPTSTR) REG_PROPERTY,
                                NULL,
                                NULL,
                                (LPBYTE) szAppName,
                                &MaxData );
                        RegCloseKey(hKeyCartotecnica);
                }
                // prendo l'indirizzo della funzione per l'hook di sistema
                HINSTANCE hDLL;               // Handle to DLL
                LPFNDLLFUNC1 SpyCallWndProc;    // Function pointer
                hDLL = LoadLibrary("TNHook.dll");
                if (hDLL != NULL)
                {
                   SpyCallWndProc = (LPFNDLLFUNC1)GetProcAddress(hDLL,
                                           "SpyCallWndProc");
                   if (!SpyCallWndProc)
                   {
                      // handle the error
                      FreeLibrary(hDLL);
   DWORD lastError = GetLastError();
   (*mioFile) << "Error loading SpyCallWndProc  " << lastError << endl;
   LPVOID lpMsgBuf;
   FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER |
     FORMAT_MESSAGE_FROM_SYSTEM |
     FORMAT_MESSAGE_IGNORE_INSERTS,
     NULL,
     lastError,
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
     (LPTSTR) &lpMsgBuf,
     0,
     NULL
     );
   (*mioFile) << "     " << (LPCTSTR)lpMsgBuf << endl;
   // Free the buffer.
   LocalFree( lpMsgBuf );
                      exit(1);
                   }
                }
                else
                {
                 (*mioFile) << "Error loading TNHook.dll "  << endl;
                }
                // aggancio l'hook sulla GetMessage
                hhook = SetWindowsHookEx(
                        WH_CALLWNDPROC,
                        //WH_GETMESSAGE ,
                        SpyCallWndProc,
                        hDLL,
                        0   // threadId 0 for all sys procedures
                        );
                 if (hhook == NULL)
                 {
                      // handle the error
                      FreeLibrary(hDLL);
   DWORD lastError = GetLastError();
   (*mioFile) << "Error SetWindowsHookEx  " << lastError << endl;
   LPVOID lpMsgBuf;
   FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER |
     FORMAT_MESSAGE_FROM_SYSTEM |
     FORMAT_MESSAGE_IGNORE_INSERTS,
     NULL,
     lastError,
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
     (LPTSTR) &lpMsgBuf,
     0,
     NULL
     );
   (*mioFile) << "     " << (LPCTSTR)lpMsgBuf << endl;
   // Free the buffer.
   LocalFree( lpMsgBuf );
                      exit(1);
                   }
                // setto il filtro per i messaggi a console
//                SetConsoleCtrlHandler(ap_control_handler, TRUE);
                SECURITY_ATTRIBUTES saAttr;
                saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
                saAttr.bInheritHandle = TRUE;
                saAttr.lpSecurityDescriptor = NULL;
                // creo il processo figlio
  if( NULL != CreateProcess( NULL,
     szAppName,
     &saAttr,
     &saAttr,
     TRUE,
     NORMAL_PRIORITY_CLASS,
     NULL,    // Use parent's environment block.
     NULL,           // Use parent's starting directory.
     &si,              // Pointer to STARTUPINFO structure.
     &pi )             // Pointer to PROCESS_INFORMATION structure.
   )
  {
   (*mioFile) << "Started "  << endl;
   while ( WaitForSingleObject( stopServiceEvent, 5000 ) == WAIT_TIMEOUT );
   // Terminate the process
   TerminateProcess(pi.hProcess, 1);
  }
  else
  {
   DWORD lastError = GetLastError();
   (*mioFile) << "Error Starting the service " << lastError << endl;
   LPVOID lpMsgBuf;
   FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER |
     FORMAT_MESSAGE_FROM_SYSTEM |
     FORMAT_MESSAGE_IGNORE_INSERTS,
     NULL,
     lastError,
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
     (LPTSTR) &lpMsgBuf,
     0,
     NULL
     );
   (*mioFile) << "     " << (LPCTSTR)lpMsgBuf << endl;
   // Free the buffer.
   LocalFree( lpMsgBuf );
  }
                // elimino il filtro per i messaggi a console
//                SetConsoleCtrlHandler(ap_control_handler, FALSE);
                // rimuovo l'hook di sistema
                UnhookWindowsHookEx(hhook);
                // disalloco la dll
                FreeLibrary(hDLL);
  // service was stopped
  serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  SetServiceStatus( serviceStatusHandle, &serviceStatus );
  // do cleanup here
  CloseHandle( stopServiceEvent );
  stopServiceEvent = 0;
  // service is now stopped
  serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
  serviceStatus.dwCurrentState = SERVICE_STOPPED;
  SetServiceStatus( serviceStatusHandle, &serviceStatus );
 }
}
void RunService()
{
 SERVICE_TABLE_ENTRY serviceTable[] =
 {
  { serviceName, ServiceMain },
  { 0, 0 }
 };
 StartServiceCtrlDispatcher( serviceTable );
}
void InstallService()
{
 (*mioFile) << "Installing TNmaeserv Service" << endl;
 SC_HANDLE serviceControlManager = OpenSCManager( 0, 0,
SC_MANAGER_CREATE_SERVICE );
 if ( serviceControlManager )
 {
  char path[ _MAX_PATH ];
  if ( GetModuleFileName( 0, path, sizeof(path) ) > 0 )
  {
   SC_HANDLE service = CreateService( serviceControlManager,
       serviceName, serviceName,
       SERVICE_ALL_ACCESS, SERVICE_TYPE/*SERVICE_WIN32_OWN_PROCESS
*//*SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS*/,
       SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, path,
       0, 0, 0, 0, 0 );
   if ( service )
    CloseServiceHandle( service );
  }
  CloseServiceHandle( serviceControlManager );
 }
}
void UninstallService()
{
 (*mioFile) << "Uninstalling TNmaeserv Service" << endl;
 SC_HANDLE serviceControlManager = OpenSCManager( 0, 0,
SC_MANAGER_CONNECT );
 if ( serviceControlManager )
 {
  SC_HANDLE service = OpenService( serviceControlManager,
   serviceName, SERVICE_QUERY_STATUS | DELETE );
  if ( service )
  {
   SERVICE_STATUS serviceStatus;
   if ( QueryServiceStatus( service, &serviceStatus ) )
   {
    if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
     DeleteService( service );
   }
   CloseServiceHandle( service );
  }
  CloseServiceHandle( serviceControlManager );
 }
}
int WINAPI WinMain(
    HINSTANCE /*hInstance*/,
    HINSTANCE /*hPrevInstance*/,
    LPSTR /*lpCmdLine*/,
    int /*nCmdShow*/){
 mioFile = new ofstream("tname_srv.log" ,ios::out);
 (*mioFile) << "---- DEBUG FILE FOR TNAMESERVER SERVICE ----" << endl <<
endl;
 if ( __argc > 1 && lstrcmpi( __argv[1], TEXT("install") ) == 0 )
 {
  InstallService();
 }
 else if ( __argc > 1 && lstrcmpi( __argv[1], TEXT("uninstall") ) == 0 )
 {
  UninstallService();
 }
 else
 {
  RunService();
 }
 return 0;
}


il mio programma usa CORBA, tnameserv č semplicemente un server ORB.

Non sono un esperto (anzi....) ma non potresti intercettare, anzichè il
messaggio di Logoff, quello di logon, in modo da riavviare il processo
figlio?
Ciao!
M

 figlio?
No, perché essendo un server ha delle connessioni aperte che cadrebbero e
degli oggetti registrati che andrebbero persi