简体   繁体   English

作为服务运行时,C ++中获取当前登录用户名不显示任何内容

[英]Get current logged in user name in C++ doesn't show anything when run as service

This is my code. 这是我的代码。 I compiled and run it in release mode. 我编译并在发布模式下运行它。 It prints the output. 打印输出。 I have added library in linker as wtsapi32.lib. 我已在链接器中将库添加为wtsapi32.lib。

 #include "stdafx.h"
        #include <windows.h>
        #include <conio.h>
        #include <iostream>
        #include <tchar.h>
        #include <wtsapi32.h>
        #include <atlstr.h>
        #include <string>

        #define INFO_BUFFER_SIZE 32767

        int _tmain(int argc, _TCHAR* argv[])
        {
            //bool pidToSessionId = ProcessIdToSessionId(GetCurrentProcessId(),_Out_ DWORD *pSessionId);
            DWORD*pSessionId = (DWORD*)malloc(sizeof(DWORD));
            bool pidToSessionId = ProcessIdToSessionId(GetCurrentProcessId(),pSessionId);
            std::cout << *pSessionId << std::endl;

            LPWSTR*infoBuf = (LPWSTR*)malloc(sizeof(LPWSTR));
            DWORD  bufCharCount = INFO_BUFFER_SIZE;

            WTSQuerySessionInformation(NULL, *pSessionId,/**_WTS_INFO_CLASS.*/WTSUserName, infoBuf, &bufCharCount);
            std::wcout << *infoBuf << std::endl;

            std::string st = CW2A(*infoBuf);
            std::cout << st << std::endl;

            _getch();
            return 0;
        }

I need to run it as service. 我需要将其作为服务运行。 Then I install it with nssm https://nssm.cc/ and set a file to print the output. 然后,我使用nssm https://nssm.cc/安装它,并设置一个文件以打印输出。 nssm lets you to print the output in file. nssm使您可以在文件中打印输出。 But it just prints pSessionId only. 但是它仅打印pSessionId。 What's wrong with my code? 我的代码有什么问题? Can anybody tell the reason? 有人能说出原因吗?

First, your use of malloc() to allocate pointer variables is wasteful and unnecessary, not to mention you are leaking the memory you are allocating. 首先,使用malloc()分配指针变量既浪费又不必要,更不用说泄漏正在分配的内存。 Just declare the pointers on the stack instead, it is much easier and safer. 只需在堆栈上声明指针即可,这更加容易和安全。

Second, in Vista and later, all services run in Session 0, and users login to Session 1 and higher. 其次,在Vista和更高版本中,所有服务都在会话0中运行,并且用户登录到会话1及更高版本。 This is known as Session 0 Isolation : 这称为会话0隔离

Services have always run in session 0. Before Windows Vista, the first user to log on was also assigned to session 0. Now, session 0 is reserved exclusively for services and other applications not associated with an interactive user session. 服务始终在会话0中运行。在Windows Vista之前,还将第一个登录的用户分配给会话0。现在,会话0专为与交互式用户会话无关的服务和其他应用程序保留。 (The first user to log on is connected to session 1, the second user to log on is connected to session 2, and so on.) Session 0 does not support processes that interact with the user. (第一个登录的用户已连接到会话1,第二个登录的用户已连接到会话2,依此类推。)会话0不支持与该用户交互的进程。

This change means that a service cannot post or send a message to an application and an application cannot send or post a message to a service. 此更改意味着服务无法向应用程序发布或发送消息,并且应用程序无法向服务发送或发布消息。 In addition, services cannot display a user interface item such as a dialog box directly. 另外,服务不能直接显示用户界面项,例如对话框。 A service can use the WTSSendMessage function to display a dialog box in another session. 服务可以使用WTSSendMessage函数在另一个会话中显示对话框。

Impact of Session 0 Isolation on Services and Drivers in Windows 会话0隔离对Windows中的服务和驱动程序的影响

Session 0 isolation: Where backward compatibility loses to security 会话0隔离:向后兼容性会降低安全性的地方

To find logged in users from inside a service, you have to enumerate the available sessions using WTSEnumerateSessions() , calling WTSQuerySessionInformation() on each one (you can also do this in Win2000 and XP, which allow users to login to Session 0). 要从服务内部查找登录的用户,您必须使用WTSEnumerateSessions()枚举可用的会话,并在每个服务上调用WTSQuerySessionInformation() (您也可以在Win2000和XP中这样做,允许用户登录到会话0)。 And don't forget to free all of the memory buffers that the WTS functions return to you. 并且不要忘记释放WTS函数返回给您的所有内存缓冲区。

And third, you are not doing any error handling at all. 第三,您根本不执行任何错误处理。

Try something more like this: 尝试更多类似这样的方法:

int _tmain(int argc, _TCHAR* argv[])
{
    PWTS_SESSION_INFO pSessions = NULL;
    DWORD dwCount = 0;
    DWORD dwError;

    if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessions, &dwCount))
    {
        dwError = GetLastError();
        std::cout << "Error enumerating sessions: " << dwError << std::endl;
    }
    else if (dwCount == 0)
    {
        std::cout << "No sessions available" << std::endl;
    }
    else
    {
        DWORD dwNumActive = 0;
        for (DWORD i = 0; i < dwCount; ++i)
        {
            if (pSessions[i].State == WTSActive) // has a logged in user
            {
                ++dwNumActive;

                std::cout << "Session: " << pSessions[i].SessionId << ", ";

                LPWSTR pUserName = NULL;
                DWORD dwBufSize = 0;

                if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, pSessions[i].SessionId, WTSUserName, &pUserName, &dwBufSize))
                {
                    dwError = GetLastError();
                    std::cout << "Error getting username: " << dwError;
                }
                else
                {
                    //std::wcout << pUserName << std::endl;
                    std::string st = CW2A(pUserName);
                    std::cout << "User: " << st;
                    WTSFreeMemory(pUserName);
                }

                std::cout << std::endl;
            }
        }

        if (!dwNumActive)
            std::cout << "No users are logged in" << std::endl;
    }

    WTSFreeMemory(pSessions);

    _getch();
    return 0;
}

With that said, in a non-service process, if you need the logged in username that is associated with the session that your app is running in, and you are not running your code as a different user than the one that is logged in (UAC elevation, impersonation, etc), then you can just use GetUserName() instead: 话虽如此,在非服务过程中,如果您需要与应用程序正在运行的会话相关联的登录用户名,并且您没有以与登录用户不同的用户身份运行代码( UAC标高,模拟等),则可以只使用GetUserName()代替:

int _tmain(int argc, _TCHAR* argv[])
{
    WCHAR szUserName[UNLEN+1];
    DWORD dwCount = UNLEN+1;

    if (!GetUserNameW(szUserName, &dwCount))
    {
        DWORD dwError = GetLastError();
        std::cout << "Error getting username: " << dwError << std::endl;
    }
    else
    {
        //std::wcout << szUserName << std::endl;
        std::string st = CW2A(szUserName);
        std::cout << "User: " << st << std::endl;
    }

    _getch();
    return 0;
}

Otherwise, you are back to WTSQuerySessionInformation() again: 否则,您将再次回到WTSQuerySessionInformation()

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwSessionId;
    DWORD dwError;

    if (!ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId))
    {
        dwError = GetLastError();
        std::cout << "Error getting Session ID: " << dwError << std::endl;
    }
    else
    {
        std::cout << "Session: " << dwSessionId << ", ";

        LPWSTR pUserName = NULL;
        DWORD dwBufSize = 0;

        if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, dwSessionId, WTSUserName, &pUserName, &dwBufSize))
        {
            dwError = GetLastError();
            std::cout << "Error getting username: " << dwError;
        }
        else
        {
            //std::wcout << pUserName << std::endl;
            std::string st = CW2A(pUserName);
            std::cout << "User: " << st;
            WTSFreeMemory(pUserName);
        }

        std::cout << std::endl;
    }

    _getch();
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM