NT Service Window Enumeration Question

I have a NT Service that is set to NOT interact with the desktop. This calls a program that I want to pass info to a window of a service process that CAN interact with the desktop. I tried  
EnumWindowStations(),
EnumDesktops(),
EnumDesktopWindows().

How can I get at all the windows on the system?  
AndrewRAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

chensuCommented:
I don't understand your question very well. Is EnumWindows what you are looking for?
0
jkrCommented:
You'll have to get access to the user's desktop. The easiest way to do this is to 'impersonate' the security context of the logged-on user using one of the user's process token. Some 'pseudocode' to illustrate it:


HANDLE GetTokenOfLoggedOnUser()
{
 HANDLE hToken;
 HANDLE hProcess;
 DWORD dwPID;
 // find PID of 'explorer.exe'
 // HOWTO: Enumerate Applications in Win32
 // http://support.microsoft.com/support/kb/articles/Q175/0/30.ASP 

    hProcess    =   OpenProcess (   PROCESS_ALL_ACCESS,
                                    TRUE,
                                    dwPID
                                );
  
    if  (   !OpenProcessToken   (   hProcess,
                                    TOKEN_QUERY,
                                    &hToken
                                )
        )   return  (   INVALID_HANDLE_VALUE);

 return ( hToken);
}

//Error checking & 'CloseHandle()' omitted for brevity ;-)


    DWORD dwThreadId;
    HWINSTA hwinstaSave;
    HDESK hdeskSave;
    HWINSTA hwinstaUser;
    HDESK hdeskUser;
    int result;
 
    /*
     * Ensure connection to service window station and desktop, and
     * save their handles.
     */
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation();
    dwThreadId = GetCurrentThreadId();
    hdeskSave = GetThreadDesktop(dwThreadId);
 
    /*
     * Impersonate the client and connect to the User's
     * window station and desktop.
     */
    InpersonateLoggedOnUser ( GetTokenOfLoggedOnUser();
    hwinstaUser = OpenWindowStation(lpszWindowStation, FALSE, MAXIMUM_ALLOWED);
    if (hwinstaUser == NULL) {
        RevertToSelf();
        return 0;
    }
    SetProcessWindowStation(hwinstaUser);
    hdeskUser = OpenDesktop(lpszDesktop, 0, FALSE, MAXIMUM_ALLOWED);
    RevertToSelf();
    if (hdeskUser == NULL) {
        SetProcessWindowStation(hwinstaSave);
        CloseWindowStation(hwinstaUser);
        return 0;
    }
    SetThreadDesktop(hdeskUser);
 
    /*
     * Display message box (for example's sakes) or enumerate the windows
     */
    dwGuiThreadId = dwThreadId;
    result = MessageBox(NULL, lpszText, lpszTitle, fuStyle);
    dwGuiThreadId = 0;
 
    /*
     * Restore window station and desktop.
     */
    SetThreadDesktop(hdeskSave);
    SetProcessWindowStation(hwinstaSave);
    CloseDesktop(hdeskUser);
    CloseWindowStation(hwinstaUser);
 
    RevertToSelf();
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jkrCommented:
To elaborate: You can't 'simply' acces the user's desktop, as it is a secured object. But 'ImpersonateLoggedOnUser()' provides a way to get the same credentials as the user that 'owns' the desktop, so you'll be able to access it. All you need is the access token of a process running in the context of the logged-on user, so 'OpenProcessToken()' will do the job for you...
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

jkrCommented:
Ooops, have overseen chensu's comment...

But anyway, you cannot 'EnumWindows()' before you aren't 'connected' to the user's desktop.
0
chensuCommented:
So, jkr, do you mean that AndrewR wants to enumerate all the windows NT Service that is set to NOT interact with the desktop? What is another service for?
0
jkrCommented:
>> do you mean that AndrewR wants to enumerate all the
>>windows NT Service that is set to NOT interact with the
>>desktop?

No, the problem is to enumerate the windows on the user's desktop from a service that is not allowed to interact with the desktop...
0
chensuCommented:
I see.
0
jkrCommented:
Ooops...


    if  (   !OpenProcessToken   (   hProcess,
                                    TOKEN_QUERY,
                                    &hToken
                                )
        )   return  (   INVALID_HANDLE_VALUE);


should read


    if  (   !OpenProcessToken   (   hProcess,
                                    TOKEN_QUERY | TOKEN_IMPERSONATE,
                                    &hToken
                                )
        )   return  (   INVALID_HANDLE_VALUE);
 
0
AndrewRAuthor Commented:
jkr,
I will try this out.
How about the case where no one is logged on? Will I still be able to find a handle to the window of my service?
0
jkrCommented:
>>How about the case where no one is
>>logged on?

In this special case, things are more difficult, as the 'Logon' desktop is secured in a special way (to disallow password sniffing)...
0
jkrCommented:
Err, 'more difficult' means that you should obtain a token of the service that shows the window...
0
AndrewRAuthor Commented:
Is there any way to get a handle to the main window of a process if we know the process id? I am looking at this as another way around my problem.
0
jkrCommented:
Yes, there is one:

// globals
HWND  g_hwnd;

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam) :


HWND GetWindowFromPID ( DWORD dwProcessId)
{
 g_hwnd = NULL;
 g_nFound = 0;

 EnumWindows (  FindHwndFromPID,    ( LPARAM) dwProcessId));

 if ( g_hwnd)  
     // we found one...
     return ( g_hwnd);

 // nothing found :-(

 return (NULL);
}

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam)
{
    DWORD   dwPID2Find  =   ( DWORD) lParam;
    DWORD   dwPID       =   0;

    if  (   GetWindowThreadProcessId    (   hwnd,   &dwPID))
        {
            if  (   dwPID   ==  dwPID2Find)
                {
                    g_hwnd  =   hwnd

                    return  (   FALSE);
                }
        }

    return  (   TRUE);
}
0
AndrewRAuthor Commented:
It seems to me that the EnumProcesses()
will get all the process on the machine, but the EnumWindows() only gets the windows on a particular desktop. I am still having trouble implementing the proposed solution. I will keep at it...
0
jkrCommented:
>>but the EnumWindows() only gets the
>>windows on a particular desktop

That's exactly the problem. Thus,
using 'SetThreadDesktop()' and 'SetProcessWindowStation()' is necessary...
0
AndrewRAuthor Commented:
Thanks.
I got it to work using your suggestions.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.