Link to home
Start Free TrialLog in
Avatar of PeterLarsen
PeterLarsen

asked on

Detect user login (like WM_USERCHANGED)

Hi Experts,

I'm doing a Service and this NT-service is interacting with the desktop.
I need to know when then user login to the system OR when the taskbar is created.

I know that WM_USERCHANGED wont work on Win2000 or XP - so how do i trap system login ??

I have read a lot about this issue on Google-Groups, but i didn't found anything there that really could help me out.

Peter
Avatar of smot
smot

You might want to look at the
WTSRegisterSessionNotification() API to receive session switch notification. (consult msdn)
Avatar of PeterLarsen

ASKER

But WTSRegisterSessionNotification/WM_WTSSESSION_CHANGE only works with XP right !?!
yes, right.
I dont get it.
Is it really necessary to use 3 different methods to detect system login - one for Win 95/98/NT4, one for Win2000 and one for XP ???
http://www.pcmag.com/article2/0,4149,93230,00.asp

this guy did it somehow, the source for the program he wrote is availble to download. not sure how much this will help but its worth a shot. (its in C++ but i followed your link in the c++ section to here)
SOLUTION
Avatar of Salte
Salte

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
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany 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
Think jkr's solution might work.

You might even have those functions send a WM_USERCHANGED event to yourself - i.e. to your server's message queue, that way you can have the same interface as in Win95 etc.

If WM_USERCHANGED isn't defined when building your service just #define  (or use an enum) and use a value that isn't used by windows or you already.

Probably not WM_USER since WM_USER area is used by windows own controls. It is ok if you are sure that none of those windows ever get the WM_USERCHANGED but if they do and WM_USERCHANGE is defined equal to WM_USER or something like that they are likely to misunderstand the message.

Alf
Thank you for your comments.

There are several ideas here and right now i'm working on a solution where i am using WM_USERCHANGED for Win95/98/ME and for WinNT/2000/XP i'm trying Winlogon Notification Packages.
I dont know whether Winlogin notification will work with XP Fast-User-Switching or not - i really hope i does.

Best regards
Peter
SOLUTION
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
Thanks smot,

I dont know yet, whether i have to use WTSRegisterSessionNotification/WM_WTSSESSION_CHANGE or not.

From what i hear, i must - because i have to recreate handles to the taskbar (and desktop) when fast-switching - and fast-switching dont act like a normal login/logout.

Peter
Hi all,

If i'm using Winlogon Notification Packages, the package must notify my running NT-service on login/logout.
How can it do that ??

Something like this : Sendmessage(aHandle, MessageIdentifier, xxxx, xxxx); ??
Regards
Peter
>>Something like this : Sendmessage(aHandle, MessageIdentifier, xxxx, xxxx); ??

'SendMessage()' will only work for GUI apps - and since most services lack a GUI... :o)

I'd use either a simple event or a service control request using 'ControlService()' with a user-defined control code.
Hi,
I may have misunderstood, but have you looked into GINA? Its a huge topic, but search on msdn. Be prepared for a few remote network registry adjustments though!

D.
SendMessage()' will only work for GUI apps - and since most services lack a GUI... :o)

This is actually wrong.

SendMessage() works for any process that has a message queue attached to it.

A process gets a message queue if it ever does a PeekMessage() or GetMessage call. First time this happens windows will create a message queue for the process.

If a server does GetMessage() you can do SendMessage() to send messages to it.

Of course, one problem is that SendMessage() takes a windows handle as argument and that means you must have a 'window'. This is actually quite silly and is the reason why full screen DirectX games have to create (an invisible) window at startup for the sole purpose so that they can receive windows messages.

A server can of course do the same thing. But most services do not and as such you can't use SendMessage() to send messages to a random server. But if you write your own server you can easily do so. Just have the server create an invisible window and do GetMessage() or PeekMessage() on that window at some early stage and there you got your message queue.

However, the regular way to interact with a service is to use ControlService() which is essentially exactly the same as SendMessage() wouldn't surprise me if it under the hood used exactly the same mechanism as SendMesage() and uses exactly the same message queue mechanism as SendMessage does. There is one important difference though, it won't use a window handle to identify the message queue but will instead use a handle returned by OpenService() to identify the message queue. Apart from that there's no reason why they should have a completely different type of message queue for servers compared to windows GUI programs.

In fact I believe it is a bad idea that they did it this way, since the difference between a service and a GUI program is - on the whole - very small, they're both event driven or request/response driven (some event or request comes and they need to respond to it), so I believe it is bad OS design to have two different worlds for something that is - on the whole - very much the same but then nobody ever claimed that Windows was good OS design? ;-)

Alf
Are we talking about MSGINA.DLL - and what can it do ??

salte :
Thanks for your comment.
Actually, i do have a question related to what you are writing about. Not that i dont know how to solve it, but i dont understand why it works :-). I will get back very soon.
Hi Salte,
You are talking about handles and the need of a window in order to obtain a handle.

In this NT-Service i have, i use the message "TaskBarCreated" - so i know when the taskbar is ready.
But it's not possible to receive messages within the Service - just like you said.

To get the message, i interrupt (override) a function. And this is what i dont understand :
       OldWinProc := TFNWndProc(SetWindowLong(Forms.Application.Handle, GWL_WNDPROC, Longint(@NewWndProc)));

How can this be a valid handle : Forms.Application.Handle ??
I dont have any forms yet and "Forms" is only in the uses clause.

Regards
Peter
well, for one thing this looks like Delphi code and not C++. In any case, let me see if I can decode it :-)

In C++ the equivalen code would be something like:

OldWinProc = TFNWndProc(SetWindowLong(Forms::Application->Handle, GWL_WNDPROC, static_cast<long>(NewWndProc)));

Well, the crucial point here is the 'Handle' and what value it return. Check your startup code where the application object is initialized. There's one such object per application so you should have only one such object and there should be a static pointer pointing to it.

This object is created during VCL startup. I am not sure if it sets a handle value there or what, if you - as you say - never create a window then I would believe the Handle returned from this should be some form of a NULL handle to no window.

Not sure how that works to get messages sent to such a handle though.

It is also possible that it is the application startup code that creates a window if you don't make one yourself. Handle is most likely a property and so there is a read function attached to it. If that function checks for a NULL handle and creates a window if it is NULL and then return the handle of the created window then the service will create a (presumably invisible) window that you can use to receive messages.

Alf
Hi salte,
Thanks for your comment - it didn't answer my question, but sometimes it helps to hear what others have to say about it - and this is what i found :

Delphi create a instance of TAppilation (Application) on program start. This is done automatically.
In the constructor of TApplication a window is created : "FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle), WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU or WS_MINIMIZEBOX, GetSystemMetrics(SM_CXSCREEN) div 2, GetSystemMetrics(SM_CYSCREEN) div 2, 0, 0, 0, 0, HInstance, nil);"
but only if the program isn't a DLL or a Console.

So you was right about this :-)  :
>>It is also possible that it is the application startup code that creates a window if you don't make one yourself. Handle is most likely a property and so there is a read function attached to it. If that function checks for a NULL handle and creates a window if it is NULL and then return the handle of the created window then the service will create a (presumably invisible) window that you can use to receive messages.

TApplication is located in unit Forms. Not the entire unit is created, only a instance of TApplication (and probably other stuff).
Thats why i could type Forms.Application.Handle. Application.handle is exactly the same.

>>Not sure how that works to get messages sent to such a handle though.
All messages are sent to the hidden window through a function called WndProc "procedure TApplication.WndProc(var Message: TMessage);"
By calling SetWindowLong the address to WndProc (in the hidden window) is changed so it point to my function (called NewWndProc) in the Service.

I guess you are an experienced programmer in C++ and since this is Delphi, you'll probably dont understand much about TApplication and similar. How does it feel not to understand anything and still be able to help ?? :-)

Best regards
Peter
Well, I do know about TApplication - it is used in C++ builder also and I must confess I have some but not detailed knowledge of object pascal or delphi. A couple of years ago I had a version of C++ builder installed on my computer with the source of the VCL library included and that source was all in pascal and was rather interesting reading :-)

Must admit that it is many years ago now though and I it is not my strongest field.

Alf