?
Solved

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

Posted on 2003-11-11
8
Medium Priority
?
1,281 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
8 Comments
 
LVL 11

Assisted Solution

by:robert_marquardt
robert_marquardt earned 80 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 200 total points
ID: 9778026
You may find some info here

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

hth, pritaeas
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 6

Assisted Solution

by:GloomyFriar
GloomyFriar earned 200 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
 
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 520 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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses

752 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