Link to home
Start Free TrialLog in
Avatar of Dark_King
Dark_King

asked on

Check if user logout or shutdown

I am making a console program that writes some stuff to files when it starts up.
I want it do keep running and check if user logout or shutdown computer and
then write to file before it closes, how do I make that possibly.
ASKER CERTIFIED SOLUTION
Avatar of sun4sunday
sun4sunday
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Dark_King
Dark_King

ASKER

I’m not shore on that, not using any forms in my console program.
why not use a windows application and not console? you don't need a form, just make it without forms. it will then receive the windows messages and you can process them.
An alternative (not very recommended) is to install a system-wide hook for ExitWindows()

You should go with window messages though
Hello Sir,

  Check the following code if it is of any use. This is also not a console application.


{Detecting Windows Shutdown
To detect Windows Shutdown, you must trap WM_EndSession message. These steps should be taken: Declare a message handling procedure in your Form's Private section: }

Procedure WMEndSession(var Msg : TWMEndSession); message WM_ENDSESSION;
//Add the procedure to the implementation section of your Unit:  
 

          procedure TForm1.WMEndSession(var Msg : TWMEndSession);  
          begin
            if Msg.EndSession = TRUE then  
              ShowMessage('Windows is shutting down ' + #13 + 'at ' +  
                FormatDateTime('c', Now));  
            inherited;  
          end;

{Detecting Windows shutdown
When Windows is shutting down, it sends a WM_QueryEndSession to all open applications. To detect (and prevent shutdown), you must define a message handler to this message. Put this definition on the private section of the main form:}  

procedure WMQueryEndSession(var Msg : TWMQueryEndSession); message  
          WM_QueryEndSession;

//     And put this method in the implementation section of the unit:  

procedure TForm1.WMQueryEndSession(var Msg : TWMQueryEndSession);  
          begin  
            if MessageDlg('Close Windows ?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then  
              Msg.Result := 0  
            else  
              Msg.Result := 1;  
          end;

with regards,
padmaja.
You have to make your application a Service, then you can set a call back for logoff events.

this should work ok,

program Cleaner;

uses
  Windows, WinSvc;

var
  Stop:Boolean;

function CtrlHandler(CtrlType:DWORD):BOOL; stdcall;
begin
  Result:= False;
  case CtrlType of
    CTRL_LOGOFF_EVENT:
    begin
     
      Result:= True;
    end;
  end;
end;

procedure InitMain;
begin
  SetConsoleCtrlHandler(@CtrlHandler, True);
  while not Stop do
    Sleep(1);
end;

var
  DispatchTable:ARRAY[0..1] OF TServiceTableEntry;
  sshStatusHandle:Service_Status_Handle;
  ssStatus:Service_Status;

const
  Svc_Name = 'Svc';

procedure CreateSampleService;
var
  schSCManager, schService:DWORD;
begin
  schSCManager:= OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  schService:= CreateService(schSCManager, Svc_Name, 'Svc',
                             SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
                             SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
                             PChar(ParamStr(0)), nil, nil, nil, nil, nil);
  CloseServiceHandle(schService);
end;

procedure DeleteSampleService;
var
  schSCManager, schService:DWORD;
begin
  schSCManager:= OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  schService:= OpenService(schSCManager, Svc_Name, SERVICE_ALL_ACCESS);
  DeleteService(schService);
  CloseServiceHandle(schService);
end;

procedure ServiceHandler(dwControl:Integer); stdcall;
begin
  case dwControl of
    SERVICE_CONTROL_STOP:
      begin
        Stop:= True;
        ssStatus.dwCurrentState:= Service_Stop_Pending;
        SetServiceStatus(sshStatusHandle, ssStatus);
      end;
    SERVICE_CONTROL_PAUSE:
      begin
        ssStatus.dwCurrentState:= Service_Paused;
        SetServiceStatus(sshStatusHandle, ssStatus);
      end;
    SERVICE_CONTROL_CONTINUE:
      begin
        ssStatus.dwCurrentState:= Service_Running;
        SetServiceStatus(sshStatusHandle, ssStatus);
      end;
    SERVICE_CONTROL_INTERROGATE:
      SetServiceStatus(sshStatusHandle, ssStatus);
    SERVICE_CONTROL_SHUTDOWN:
      Stop:= True;
  end;
end;

procedure ServiceProc(dwArgc:Integer; var lpszArgv:PChar); stdcall;
begin
  sshStatusHandle:= RegisterServiceCtrlHandler((Svc_Name), @ServiceHandler);
  if sshStatusHandle <> 0 then begin
    ZeroMemory(@ssStatus, SizeOf(ssStatus));
    ssStatus.dwServiceType:= SERVICE_WIN32_OWN_PROCESS;
    ssStatus.dwCurrentState:= SERVICE_START_PENDING;
    ssStatus.dwControlsAccepted:= SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_PAUSE_CONTINUE;
    ssStatus.dwWaitHint:= 1000;
    SetServiceStatus(sshStatusHandle, ssStatus);
    ssStatus.dwCurrentState:= SERVICE_RUNNING;
    SetServiceStatus(sshStatusHandle, ssStatus);
    InitMain;
    ssStatus.dwCurrentState:= SERVICE_STOPPED;
    SetServiceStatus(sshStatusHandle, ssStatus);
  end;
end;

begin
  if ParamCount <> 0 then begin
    if ParamStr(1) = '/i' then
      CreateSampleService
    else if ParamStr(1) = '/u' then
      DeleteSampleService;
  end else begin
    DispatchTable[0].lpServiceName:= Svc_Name;
    DispatchTable[0].lpServiceProc:= @ServiceProc;
    DispatchTable[1].lpServiceName:= nil;
    DispatchTable[1].lpServiceProc:= nil;
    StartServiceCtrlDispatcher(DispatchTable[0]);
  end;
end.
 
heretoread

where do I call my procedure if user logoff, and is logoff trigger when user shutdown to?
In this function here,

function CtrlHandler(CtrlType:DWORD):BOOL; stdcall;
begin
  Result:= False;
  case CtrlType of
    CTRL_LOGOFF_EVENT:
    begin
      //USER LOG OFF, SAVE FILE
      Result:= True;
    end;
  end;
end;

And it works for shutdowns too as the user is logged off before shutdown.

As it's a service you need to install it like
MyService.exe /i
That will add it to the services and it will start every time with the computer, to uninstall do
MyService.exe /u
Is there a way to run this service as user, It has no network resources and can’t log to network file.
And I need to manual start this service
I mean the service is installed but it is not running, If I start it self it work almost


No answer, I now try the form app