Solved

Does JournalRecord hook from service require "Allow service to interact With Desktop"?

Posted on 2003-11-11
8
1,252 Views
Last Modified: 2012-05-04
Hello!
  I have restarted working on my work-monitoring utility :-)
  I was wprking with my Journal Record service and noticed that it worked only when I check the "Allow service to interact With Desktop" checkbox. If it is not checked, I get the message "No Journal Hook availible" in my file.
  The service monitors different mouse/keyboard events and logs them in a file "C:\IdlLog.Txt".
  I am running it under Win XP and have compiled it in Delphi 7.
  Can some body tell me why this could happen and what is the solution?
  Here's the unit:
unit WorkUnit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  ExtCtrls;

Const
  TimeToSec = 86400;

type
  TService1 = class(TService)
    Timer1: TTimer;
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceExecute(Sender: TService);
    procedure Timer1Timer(Sender: TObject);

  private
    { Private declarations }
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;

var
  Service1: TService1;
  MyHook, KHook: THandle;
  LastActivityTime, LastCheckTime, TheTotalIdleCount, TheCurrentIdleCount,
  TheIdleCutOff, TheCurrentWorkCount : TDateTime;
  FHookStarted : Boolean;
  MsgLog: TStringList;
  KbdLog: String;
implementation

{$R *.DFM}

Function SecondOfTheDay(CnvTime: TDateTime): Integer;
Begin
  Result := Round(CnvTime * TimeToSec);
End;

Function GetTimeDiff(CurTime, PreTime: TDateTime): TDateTime;
Begin


  If CurTime < PreTime Then
  Begin
    CurTime := 1 + CurTime;
  End;
  Result := CurTime - PreTime;

End;



Procedure UpdateIdleTime(KeyFlag:Boolean = True);
var
  TimeDiff, CurTime: TDateTime;

Begin

  CurTime := TIME;
  If KeyFlag Then
  Begin
    TimeDiff := GetTimeDiff(CurTime, LastActivityTime);
    If TimeDiff >= TheIdleCutOff Then
    Begin
      TheTotalIdleCount := TheTotalIdleCount + TimeDiff;
      TheCurrentIdleCount := TheCurrentIdleCount + (GetTimeDiff(CurTime, LastCheckTime));
    End
    Else
    Begin
      TheCurrentWorkCount := TheCurrentWorkCount + TimeDiff;
    end;

    LastCheckTime := CurTime;
    LastActivityTime := LastCheckTime;
  End
  Else
  Begin
    TimeDiff := GetTimeDiff(CurTime, LastCheckTime);
    If TimeDiff >= TheIdleCutOff Then
    Begin
      TheCurrentIdleCount := TheCurrentIdleCount + TimeDiff;
    End;
    LastCheckTime := CurTime;
  End;

End;



Function GetWorkStats: Word;

Begin

  Result := SecondOfTheDay(TheCurrentWorkCount);
  TheCurrentWorkCount := 0;

End;


procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service1.Controller(CtrlCode);
end;

function TService1.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

function JournalProc(Code, wParam: Integer; var EventStrut: TEventMsg): Integer; stdcall;
var
  s: string;
  KbdFlag: Boolean;
begin
  {this is the JournalRecordProc}
  Result := CallNextHookEx(MyHook, Code, wParam, Longint(@EventStrut));
  {the CallNextHookEX is not really needed for journal hook since it it not
  really in a hook chain, but it's standard for a Hook}
  if Code < 0 then Exit;

  {you should cancel operation if you get HC_SYSMODALON}
  if Code = HC_SYSMODALON then Exit;
  if Code = HC_ACTION then
  begin
    {
    The lParam parameter contains a pointer to a TEventMsg
    structure containing information on
    the message removed from the system message queue.
    }

    s := '';
    KbdFlag := False;
    if EventStrut.message = WM_LBUTTONUP then
      s := 'Left Mouse UP at X pos ' +
        IntToStr(EventStrut.paramL) + ' and Y pos ' + IntToStr(EventStrut.paramH);

    if (EventStrut.message = WM_RBUTTONUP) then
      s := 'Right Mouse Up at X pos ' +
        IntToStr(EventStrut.paramL) + ' and Y pos ' + IntToStr(EventStrut.paramH);

    if (EventStrut.message = WM_MOUSEWHEEL) then
      s := 'Mouse Wheel at X pos ' +
        IntToStr(EventStrut.paramL) + ' and Y pos ' + IntToStr(EventStrut.paramH);

    if (EventStrut.message = WM_KEYUP) then
    Begin
      KbdFlag := True;
      s := 'Keyboard';
      KbdLog := KbdLog + Format('<%d>',[EventStrut.paramL]);

      If wParam = VK_Return Then
      Begin
        KbdFlag := False;
        s := KbdLog;
        KbdLog := '';
      End;
    End;

    if s <> '' then
    Begin
      If not KbdFlag then
        MsgLog.Add(s);
      UpdateIdleTime;
    End;
  end;
end;

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
Var
  CutOffSec, CheckSec: Integer;
begin

  CutOffSec := 5;
  CheckSec := 10;
  MsgLog := TStringList.Create;
  KbdLog :='';
  if FHookStarted then
  begin
    MsgLog.Add('Mouse is already being Journaled, can not restart');
    Exit;
  end;

  LastActivityTime := TIME;
  LastCheckTime := LastActivityTime;
  TheIdleCutOff := CutOffSec / TimeToSec;
  TheTotalIdleCount := 0;
  TheCurrentIdleCount := 0;
  TheCurrentWorkCount := 0;

  MyHook := SetWindowsHookEx(WH_JOURNALRECORD, @JournalProc, hInstance, 0);
  Timer1.Interval := CheckSec * 1000;
  Timer1.Enabled := True;
  {SetWindowsHookEx starts the Hook}
  if MyHook > 0 then
  begin
    FHookStarted := True;
  end
  else
    MsgLog.Add('No Journal Hook availible');
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  FHookStarted := False;
  Timer1.Enabled := False;
  Timer1Timer(Timer1);
  UpdateIdleTime;
  UnhookWindowsHookEx(MyHook);
  MyHook := 0;
  MsgLog.Add(KbdLog);
  MsgLog.SaveToFile('C:\IdlLog.Txt');
  MsgLog.Free;
end;

procedure TService1.ServiceExecute(Sender: TService);
begin
 while not Terminated do
    ServiceThread.ProcessRequests(True);
end;

procedure TService1.Timer1Timer(Sender: TObject);
Var
  TotalIdl, CurIdl, CurWrk: Word;
begin
  CurWrk := GetWorkStats;
  MsgLog.Add(Format('Work = %d',[CurWrk]));
end;

end.

0
Comment
Question by:snehanshu
8 Comments
 
LVL 11

Assisted Solution

by:robert_marquardt
robert_marquardt earned 20 total points
ID: 9777128
Applying my common sense:
You want to access an application. An application runs on a desktop.
0
 
LVL 5

Author Comment

by:snehanshu
ID: 9777165
>>You want to access an application.
I thought I wanted to catch windows messages.
Does it mean that keyboard hooks also would not work if I haven't checked this thing? I haven't tried it, but want to know.
What classifies as "Desktop thing" and what does not?
...Snehanshu
0
 
LVL 6

Assisted Solution

by:pritaeas
pritaeas earned 50 total points
ID: 9778026
You may find some info here

http://www.geocities.com/macrotech_tr/API.html

hth, pritaeas
0
 
LVL 6

Assisted Solution

by:GloomyFriar
GloomyFriar earned 50 total points
ID: 9778365
When you have the "Allow service to interact With Desktop" checkbox unchecked your service run in a "black box" so it can't do what you want.
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 5

Author Comment

by:snehanshu
ID: 9778459
GloomyFriar,
>>your service run in a "black box"
  Is it true about JournalRecord or any hook?
  And is there some place where I can find information on what lies inside the black box and what lies outside?
:-)
Thanks,
...Snehanshu
0
 
LVL 12

Accepted Solution

by:
Lee_Nover earned 130 total points
ID: 9778955
imo mouse and kbd aren't accessible from a service
you can have different settings for them for each user
that's why you need to interact with the desktop

I also have a monitoring service and it needs to be interactive (I use the mouse and kbd hooks separately)

a simple rule of thumb .. anything that can be customized on a user level can't be accessed from a service unless it's interactive OR by using user Impersonation
0
 
LVL 5

Author Comment

by:snehanshu
ID: 9786853
Lee_Nover,
>>unless it's interactive
  I didn't know you could enable that check box on install just by changing the interactive property to true at design time!
  I have also got a few links from experts at Windows Programming TA and looks like I am all set to continue my task for now.
http://www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_20802669.html
  Thank you all your help.
...Snehanshu
0
 
LVL 5

Author Comment

by:snehanshu
ID: 9786855
>>Thank you all your help.
Thank you all for your help.
:-)
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now