Jump to content

Determining the active user profile


Zaxon
 Share

Recommended Posts

I'm writing a script that will run in every profile that is started. So in Windows XP, if two users logon, then there will be an instance of the script running for each user.

I want the script running under the active user profile to execute a task.

So the script goes:

. Is my user profile currently active?

. If so, then do something

How can I detect whether the current user profile is active or not under Windows XP?

Link to comment
Share on other sites

First install it under the All User profile c:\documents and settings\all users\start menu\programs\startup\

This will run it no matter who logs in.

Next use the @username to determine who is logged in and now you can assign a var:

$curprofile = "C:\Documents and settings\" & @UserName

I am not sure what you mean though by detect the current user profile is active or not under Windows XP. Do you mean has a particular profile been used recently? If so then check the date of the ntuser.dat file under the profile in question.

Link to comment
Share on other sites

I am not sure what you mean though by detect the current user profile is active or not under Windows XP. Do you mean has a particular profile been used recently? If so then check the date of the ntuser.dat file under the profile in question.

<{POST_SNAPBACK}>

I've written a scheduling program that will file programs off at specific date/times. Think of it as an advanced version of the scheduler that comes with XP.

An instance of the scheduler starts up with each person who logs on, and access the some scheduler database.

Some fired off programs may require a user input. Take a backup program, for example, that displays prompts such as "please insert the next disk", "that disk isn't blank", etc.

Under Windows Task Manager > [users], it will list all usernames along with their status

. active - meaning you're currently using that profile

. disconnected - meaning the profile is only running in the background

If you windows-L between the two profiles/users, the status of which profile is currently active can be seen reflected in the list of users and their associated statuses.

So, I want my scheduling program to fire off tasks in the instance of the scheduler which is currently running as the active profile.

Link to comment
Share on other sites

If @Username = "James" Then
  ;...
ElseIf @Username = "Administrator" Then
  ;...
EndIf

<{POST_SNAPBACK}>

That's right. But let's assume that everyone is eligible to run this program. And all we need to determine is which user is "active" at that moment in time.
Link to comment
Share on other sites

I've found some relevant information at http://msdn.microsoft.com/library/default....ml/winxpfus.asp

BOOL WINAPI

WTSRegisterSessionNotification(

    HWND hWnd,        // Window handle

    DWORD dwFlags        // Flags

    );

The registered HWND receives the message WM_WTSSESSION_CHANGE.

In dwFlags you can specify:

NOTIFY_FOR_THIS_SESSION. A window is notified only about the session change events that affect the session to which window belongs.

NOTIFY_FOR_ALL_SESSIONS. A window is notified for all session change events.

Essentially, your process can register to be informed if its session becomes active or loses the active status.

So obviously there's some sort of message sending going on, but I'll need someone more familiar with interfacing to the operating system to give me a hand.

Link to comment
Share on other sites

I don't use fast user switching, but it looks like WTSRegisterSessionNotification() is defined in Wtsapi32.dll, so if you:

- Learn what the value of the NOTIFY_FOR_ALL_SESSIONS flag is

- Likewise learn the value of the WM_WTSSESSION_CHANGE message

- and WTS_CONSOLE_CONNECT

- and WTS_CONSOLE_DISCONNECT

...then you could make a AutoIt3 GUI script that registered itself for session change notification using DllCall() and monitored the changes in its GUI message loop.

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

OK. I've found some more places that talk about this functionality. The best I can do is find discussions about it, but I'll need someone with some skills in calling DLLs to help decipher this.

See http://dev.remotenetworktechnology.com/api/wtsapi.htm

See http://support.microsoft.com/kb/310153/EN-US/

Although I have no idea on how to even begin with this, I can put forward an attempted bumbly framework. Shows I'm trying.

#include <GuiConstants.au3>
const $NOTIFY_FOR_THIS_SESSION=1; not really sure of this value

$main=guicreate("main")
guisetstate()

$dll=DllOpen ("Wtsapi32.dll")
$result=dllcall($dll,"int","WTSRegisterSessionNotification","hwnd",$main,"int",$NOTIFY_FOR_THIS_SESSION)
if @error then
    msgbox(0,"","Dll call failed")
; currently not returning an error - a good start
endif
msgbox(0,"",$result)
; this should return 1, but currently returning an empty string.  Not good

do
    use either GUICtrlRecvMsg ($main,???) or GUIGetMsg (); not sure which 
until 0
Link to comment
Share on other sites

From the Windows Server 2003 SDK

From WtsAPI32.h:

#define NOTIFY_FOR_ALL_SESSIONS  1
#define NOTIFY_FOR_THIS_SESSION  0

From WinUser.h:

#define WTS_CONSOLE_CONNECT             0x1
#define WTS_CONSOLE_DISCONNECT           0x2
#define WTS_REMOTE_CONNECT               0x3
#define WTS_REMOTE_DISCONNECT             0x4
#define WTS_SESSION_LOGON                 0x5
#define WTS_SESSION_LOGOFF               0x6
#define WTS_SESSION_LOCK                   0x7
#define WTS_SESSION_UNLOCK               0x8
#define WTS_SESSION_REMOTE_CONTROL       0x9
// ...
#define WM_WTSSESSION_CHANGE            0x02B1

Tried this this morning, DllCall() returns success, but WM_WTSSESSION_CHANGE is never a recognizable message at the message loop; as always this may be due to my imperfect understanding...

GUI code by CyberSlug's splendid AutoBuilder

; Script generated by AutoBuilder 0.5 Prototype

#include <GuiConstants.au3>

If Not IsDeclared('WS_CLIPSIBLINGS') Then Global $WS_CLIPSIBLINGS = 0x04000000

$main = GuiCreate("Session Info", 277, 81,(@DesktopWidth-277)/2, (@DesktopHeight-81)/2 , $WS_OVERLAPPEDWINDOW + $WS_VISIBLE + $WS_CLIPSIBLINGS)

$Label_1 = GuiCtrlCreateLabel("Last time we left this window session was: ", 10, 10, 200, 20)
$Label_2 = GuiCtrlCreateLabel("Never", 220, 10, 40, 20)
$Button_3 = GuiCtrlCreateButton("OK", 90, 40, 90, 30)
$NOTIFY_FOR_THIS_SESSION = 0
$WM_WTSSESSION_CHANGE = 0x02B1

GuiSetState()
Sleep(1000)

$ourCall = DllCall(@SystemDir & "\Wtsapi32.dll", "int", "WTSRegisterSessionNotification", "hwnd", $main, "int", $NOTIFY_FOR_THIS_SESSION)
MsgBox(0, "Debug", "DllCall returned: " & $ourCall[0])

While 1
    $msg = GuiGetMsg(1)
    Select
    Case $msg[0] = $GUI_EVENT_CLOSE
        ExitLoop
    Case $msg[0] = $Button_3
        ExitLoop
   Case $msg[0] = $WM_WTSSESSION_CHANGE
     ; If we're here we got the message
      Sleep(2000)
      MsgBox(0, "Debug", "Array[1] = " & $msg[1] & @CRLF & "Array[2] = " & $msg[2] & @CRLF & "Array[3] = " & $msg[3])
      GUICtrlSetData($Label_2, @HOUR & ":" & @MIN)
    Case Else
    ;;;
    EndSelect
WEnd
Exit

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

I can confirm we're not getting back any notification. Even with a modified loop doing "show me virtually anything", we're definately not going anything back.

While 1
    $msg = GuiGetMsg(1)
    Select
    Case $msg[0] = $GUI_EVENT_CLOSE
        ExitLoop
    Case $msg[0] = $Button_3
        ExitLoop
   Case $msg[0] = $WM_WTSSESSION_CHANGE
    ; If we're here we got the message
      Sleep(2000)
      MsgBox(0, "Debug", "Array[1] = " & $msg[1] & @CRLF & "Array[2] = " & $msg[2] & @CRLF & "Array[3] = " & $msg[3])
      GUICtrlSetData($Label_2, @HOUR & ":" & @MIN)
    case $msg[0] = -11
    ; do nothing
    case $msg[0] = 0
    ; do nothing
    Case Else
        msgbox(0,"case else",$msg[0])
    EndSelect
WEnd

The other thing I noticed is that the line: MsgBox(0, "Debug", "DllCall returned: " & $ourCall[0]) lets us know the number of parameters, not the parameter returned itself.

If I look at $ourCall[1] I get something like '001507AE', which is weird, considering that the function we're calling is supposed to return a boolean:

BOOL WTSRegisterSessionNotification(

HWND hWnd,

DWORD dwFlags

);

What's happening with the registration return value?

Link to comment
Share on other sites

The other thing I noticed is that the line: MsgBox(0, "Debug", "DllCall returned: " & $ourCall[0]) lets us know the number of parameters, not the parameter returned itself.

Are you using the most recent release version of AutoIt? DllCall() returns an array, and index zero of the array is the DLL function return value. Check your version, check your docs...

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

Are you using the most recent release version of AutoIt? DllCall() returns an array, and index zero of the array is the DLL function return value. Check your version, check your docs...

<{POST_SNAPBACK}>

Well, back to school for me! I'm so used to AutoIt filling $array[0] with the number of elements in the array, that I automatically read "$return[1] = function return value" in my mind from the docs.
Link to comment
Share on other sites

GUIGetMsg() isn't going to return the message. All you're doing is showing the messages that are allowed through. Search the Support forum for "PeekMessage" by me for a potential work-around to actually see the message.

Link to comment
Share on other sites

GUIGetMsg() isn't going to return the message.  All you're doing is showing the messages that are allowed through.  Search the Support forum for "PeekMessage" by me for a potential work-around to actually see the message.

<{POST_SNAPBACK}>

Has anyone got PeekMessage to work and give useful results? According to the messages I was reading on PeekMessage, people understood it was a necessary function, but they didn't appear to be getting useful results with it.

Nevertheless, I've whipped up a PeekMessage based on the examples in the messages so far, and with some minor tailorings:

#include <GUIConstants.au3>
#Include <date.au3>

Const $PM_NOREMOVE = 0
Const $PM_REMOVE = 1
Const $WM_QUERYENDSESSION = 17
const $NOTIFY_FOR_THIS_SESSION = 0

Dim $dummy[200], $ret[200]

$handle=DllOpen("user32.dll")
if @error then msgbox(64,"Error!","Didn't open DLL!",2)

$window = GUICreate("Main window", 400, 400)
$ourCall = DllCall(@SystemDir & "\Wtsapi32.dll", "int", "WTSRegisterSessionNotification", "hwnd", $window, "int", $NOTIFY_FOR_THIS_SESSION)
if @error then msgbox(64,"Error!","Didn't open DLL!",2)
$edit = GUICtrlCreateEdit("", 10, 10, 380, 380, $ES_READONLY + $ES_AUTOVSCROLL)
GUISetState()

while 1
; (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    $ret=DllCall($handle, "long", "PeekMessage", "str", $dummy, "long" , $window, "long" , 0, "long", 1000, "long", $PM_REMOVE)
    if @error = 1 Then 
        msgbox(64, "Error!","Error in DllCall",2)
    else
    ; If the function succeeds, the return value is nonzero. 
        if $ret[0] <> 0 Then
            GUICtrlSetData($edit, _NowTime() & ": " & $ret[0]& $ret[1]& $ret[2]& $ret[3]& $ret[4]& $ret[5] & @crlf, 1)
        EndIf
    endif
WEnd

Currently it doesn't produce anything too useful. Valik, can you help refine this? Or anyone?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...