Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Windows 10 - find last logon time in C++ ??

Windows 10 - find last logon time in C++ ??

Scheduled Pinned Locked Moved C / C++ / MFC
c++visual-studiotutorialquestion
13 Posts 4 Posters 18 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D David Crow

    Derell Licht wrote:

    wprintf(L"Password age (seconds): %d\n", pBuf2->usri2_password_age); wprintf(L"Last logon (seconds since January 1, 1970 GMT): %d\n", pBuf2->usri2_last_logon);

    Not sure if it's related or not, but the two members that are being printed here are DWORDs so you might want to use %lu instead. Other than that, are you running into a timezone issue? I tried your code on my Windows 10 system and it reported the correct numbers.

    "One man's wage rise is another man's price increase." - Harold Wilson

    "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

    "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

    D Offline
    D Offline
    Derell Licht
    wrote on last edited by
    #3

    Okay, I changed them to %u, which made no difference. I'm using a 32-bit compiler, so I don't need to specify %lu to get 32-bit values. This is definitely *not* a timezone issue, since the logon time is off by 77 days, not by 8 hours!!

    1 Reply Last reply
    0
    • D Derell Licht

      I'm trying to determine this value for a system-status program that I maintain. In the past, I've just shown Uptime, but now that I'm forced to Windows 10, that isn't entirely informative!! If I log out of my machine (shutdown -l) and then log back in, Uptime doesn't get reset. So I want to add an option to show logon time vs reboot time (Uptime)... but I'm not having much success with this... I have found several articles which recommend NetUserGetInfo(), but this is returning invalid data for me... for example, I just logged out, and back in, to my machine... here is the code, followed by the results that I get:

      // Call the NetUserGetInfo function.
      dwLevel = 2;
      wchar_t username[UNLEN+1];
      DWORD username_len = UNLEN+1;
      GetUserNameW(username, &username_len);
      nStatus = NetUserGetInfo(NULL, username, dwLevel, (LPBYTE *) & pBuf);
      // skipping result checking
      pBuf2 = (LPUSER_INFO_2) pBuf;
      wprintf(L"User account name: %s\n", pBuf2->usri2_name);
      wprintf(L"Password age (seconds): %d\n", pBuf2->usri2_password_age);
      wprintf(L"Last logon (seconds since January 1, 1970 GMT): %d\n", pBuf2->usri2_last_logon);
      time_t logon_time = pBuf2->usri2_last_logon ;
      char buff[20];
      strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&logon_time));
      printf("logon time: %s\n", buff);

      The results that I get are:

      User account name: dan7m
      Password age (seconds): 10221317
      Last logon (seconds since January 1, 1970 GMT): 1616249786
      logon time: 2021-03-20 07:16:26

      Note that the logon time *actually* around 1920 on 06/05/21... So I have two questions, I guess... 1. is there some way to make this function actually work?? 2. if not, how else can I programmatically access the login time on Windows 10 64bit??

      D Offline
      D Offline
      Derell Licht
      wrote on last edited by
      #4

      BTW, I found another site which suggested a console command to display last logon: > net user dan7m | findstr /B /C:"Last logon" Last logon 03/20/21 07:16:26 Interestingly, that is showing exactly the same logon time as NetUserGetInfo(2) is showing... But that is *not* when I last logged on; it's not even when I last rebooted - Uptime is showing 4.5 days, which is correct... I think, maybe, this suggests that the 'logon' time that I'm actually looking for - which is the time since I last logged out of this session and logged in again... is maybe called something else entirely in Windows 10?? I am very confused by all this...

      1 Reply Last reply
      0
      • D Derell Licht

        I'm trying to determine this value for a system-status program that I maintain. In the past, I've just shown Uptime, but now that I'm forced to Windows 10, that isn't entirely informative!! If I log out of my machine (shutdown -l) and then log back in, Uptime doesn't get reset. So I want to add an option to show logon time vs reboot time (Uptime)... but I'm not having much success with this... I have found several articles which recommend NetUserGetInfo(), but this is returning invalid data for me... for example, I just logged out, and back in, to my machine... here is the code, followed by the results that I get:

        // Call the NetUserGetInfo function.
        dwLevel = 2;
        wchar_t username[UNLEN+1];
        DWORD username_len = UNLEN+1;
        GetUserNameW(username, &username_len);
        nStatus = NetUserGetInfo(NULL, username, dwLevel, (LPBYTE *) & pBuf);
        // skipping result checking
        pBuf2 = (LPUSER_INFO_2) pBuf;
        wprintf(L"User account name: %s\n", pBuf2->usri2_name);
        wprintf(L"Password age (seconds): %d\n", pBuf2->usri2_password_age);
        wprintf(L"Last logon (seconds since January 1, 1970 GMT): %d\n", pBuf2->usri2_last_logon);
        time_t logon_time = pBuf2->usri2_last_logon ;
        char buff[20];
        strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&logon_time));
        printf("logon time: %s\n", buff);

        The results that I get are:

        User account name: dan7m
        Password age (seconds): 10221317
        Last logon (seconds since January 1, 1970 GMT): 1616249786
        logon time: 2021-03-20 07:16:26

        Note that the logon time *actually* around 1920 on 06/05/21... So I have two questions, I guess... 1. is there some way to make this function actually work?? 2. if not, how else can I programmatically access the login time on Windows 10 64bit??

        L Offline
        L Offline
        Lost User
        wrote on last edited by
        #5

        Hi, The NetUserGetInfo function is an old derelict function. (pun intentional) Maybe you could use the Security and Identity[^] framework to get session information. Disclaimer: This is a code sample, it doesn't handle dynamic daylight saving time. Also, the pointer arithmetic could be refactored.

        #pragma comment(lib, "Secur32.lib")

        #include #include #include INT main()
        {
        DWORD lc = 0;
        DWORD status = 0;
        PLUID list = nullptr;

        LsaEnumerateLogonSessions(&lc, &list);
        for (DWORD i = 0; i < lc; i++)
        {
            PSECURITY\_LOGON\_SESSION\_DATA pData;
        
            status = LsaGetLogonSessionData((PLUID)((INT\_PTR)list + sizeof(LUID) \* i), &pData);
            if (0 == status)
            {
                if (Interactive == pData->LogonType)
                {
                    FILETIME ft;
                    SYSTEMTIME st\_utc, st\_local;
                    TIME\_ZONE\_INFORMATION tzi;
        
                    ft.dwHighDateTime = pData->LogonTime.HighPart;
                    ft.dwLowDateTime = pData->LogonTime.LowPart;
        
                    GetTimeZoneInformation(&tzi);
                    FileTimeToSystemTime(&ft, &st\_utc);
                    SystemTimeToTzSpecificLocalTime(&tzi, &st\_utc, &st\_local);
        
                    wprintf(L"UserName: %s\\n", pData->UserName.Buffer);
                    wprintf(L"Last logon %s: %d/%d/%d-%d:%d:%d:%d\\n", tzi.StandardName, st\_local.wMonth, st\_local.wDay, st\_local.wYear, st\_local.wHour, st\_local.wMinute, st\_local.wSecond, st\_local.wMilliseconds);
                }
        
                LsaFreeReturnBuffer(pData);
            }
        }
        

        }

        I noticed that the C# guys have much better time zone tools[^]. For some reason nobody invested any time into doing this for the public native API. So I whipped up something real quick for converting to an arbitrary time zone:

        //The registry 'Olson TZ structure' is partially documented here https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time\_zone\_information --David Delaune
        typedef struct _REG_TZI_FORMAT
        {

        D 1 Reply Last reply
        0
        • L Lost User

          Hi, The NetUserGetInfo function is an old derelict function. (pun intentional) Maybe you could use the Security and Identity[^] framework to get session information. Disclaimer: This is a code sample, it doesn't handle dynamic daylight saving time. Also, the pointer arithmetic could be refactored.

          #pragma comment(lib, "Secur32.lib")

          #include #include #include INT main()
          {
          DWORD lc = 0;
          DWORD status = 0;
          PLUID list = nullptr;

          LsaEnumerateLogonSessions(&lc, &list);
          for (DWORD i = 0; i < lc; i++)
          {
              PSECURITY\_LOGON\_SESSION\_DATA pData;
          
              status = LsaGetLogonSessionData((PLUID)((INT\_PTR)list + sizeof(LUID) \* i), &pData);
              if (0 == status)
              {
                  if (Interactive == pData->LogonType)
                  {
                      FILETIME ft;
                      SYSTEMTIME st\_utc, st\_local;
                      TIME\_ZONE\_INFORMATION tzi;
          
                      ft.dwHighDateTime = pData->LogonTime.HighPart;
                      ft.dwLowDateTime = pData->LogonTime.LowPart;
          
                      GetTimeZoneInformation(&tzi);
                      FileTimeToSystemTime(&ft, &st\_utc);
                      SystemTimeToTzSpecificLocalTime(&tzi, &st\_utc, &st\_local);
          
                      wprintf(L"UserName: %s\\n", pData->UserName.Buffer);
                      wprintf(L"Last logon %s: %d/%d/%d-%d:%d:%d:%d\\n", tzi.StandardName, st\_local.wMonth, st\_local.wDay, st\_local.wYear, st\_local.wHour, st\_local.wMinute, st\_local.wSecond, st\_local.wMilliseconds);
                  }
          
                  LsaFreeReturnBuffer(pData);
              }
          }
          

          }

          I noticed that the C# guys have much better time zone tools[^]. For some reason nobody invested any time into doing this for the public native API. So I whipped up something real quick for converting to an arbitrary time zone:

          //The registry 'Olson TZ structure' is partially documented here https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time\_zone\_information --David Delaune
          typedef struct _REG_TZI_FORMAT
          {

          D Offline
          D Offline
          Derell Licht
          wrote on last edited by
          #6

          Hey, @Randor, that works *great* !!!!!!!!!!! Thank you so much!! I do have *one* minor issue with it, though... Is this intended to be a 64-bit-only operation?? I use MinGW, not Visual C++, for all of my app development, and at this point, I still use a 32-bit compiler... However, I cannot build this with 32-bit MinGW: > g++ -Wall -O2 login_lsa.cpp -o login_lsa.exe -lsecur32 login_lsa.cpp: In function 'INT main()': login_lsa.cpp:14: error: 'LsaEnumerateLogonSessions' was not declared in this scope login_lsa.cpp:17: error: 'PSECURITY_LOGON_SESSION_DATA' was not declared in this scope login_lsa.cpp:17: error: expected ';' before 'pData' login_lsa.cpp:19: error: 'pData' was not declared in this scope login_lsa.cpp:19: error: 'LsaGetLogonSessionData' was not declared in this scope I searched through *all* .h and .hpp files in c:\mingw, and these functions were not declared anywhere... Mind ye, it *does* build and run just fine with 64-bit MinGW. (in case anyone is not familiar with MinGW, it stands for Minimal Gnu for Windows, and is a port of the GNU toolchain to Windows, using Windows libraries for most services.) My MinGW 32-bit toolchain *does* have netsecapi.h and secur32.lib (in its format), but these LSA functions appear to not be included... I also tried current TDM build of MinGW, which is gcc 10.3.0, but it does not contain these functions either...

          L 1 Reply Last reply
          0
          • D Derell Licht

            Hey, @Randor, that works *great* !!!!!!!!!!! Thank you so much!! I do have *one* minor issue with it, though... Is this intended to be a 64-bit-only operation?? I use MinGW, not Visual C++, for all of my app development, and at this point, I still use a 32-bit compiler... However, I cannot build this with 32-bit MinGW: > g++ -Wall -O2 login_lsa.cpp -o login_lsa.exe -lsecur32 login_lsa.cpp: In function 'INT main()': login_lsa.cpp:14: error: 'LsaEnumerateLogonSessions' was not declared in this scope login_lsa.cpp:17: error: 'PSECURITY_LOGON_SESSION_DATA' was not declared in this scope login_lsa.cpp:17: error: expected ';' before 'pData' login_lsa.cpp:19: error: 'pData' was not declared in this scope login_lsa.cpp:19: error: 'LsaGetLogonSessionData' was not declared in this scope I searched through *all* .h and .hpp files in c:\mingw, and these functions were not declared anywhere... Mind ye, it *does* build and run just fine with 64-bit MinGW. (in case anyone is not familiar with MinGW, it stands for Minimal Gnu for Windows, and is a port of the GNU toolchain to Windows, using Windows libraries for most services.) My MinGW 32-bit toolchain *does* have netsecapi.h and secur32.lib (in its format), but these LSA functions appear to not be included... I also tried current TDM build of MinGW, which is gcc 10.3.0, but it does not contain these functions either...

            L Offline
            L Offline
            Lost User
            wrote on last edited by
            #7

            Derell Licht wrote:

            Is this intended to be a 64-bit-only operation??

            Not sure what gave you that idea. That code will build and function correctly on both 32/64 bit platforms. The library 'Secur32.lib' was named a really long time ago and just like the path'C:\Windows\System32' the decision was made to keep the old name.

            Derell Licht wrote:

            I searched through *all* .h and .hpp files in c:\mingw, and these functions were not declared anywhere...

            I very rarely use the MinGW compiler tools. The errors you are getting are simple #include errors. I checked the msys2 source code repository and found mingw-w64/ntsecapi.h which is dated Dec 13, 2013 has all of the required function declarations. Sounds like you just need to update your development environment. Best Wishes, -David Delaune

            D 1 Reply Last reply
            0
            • L Lost User

              Derell Licht wrote:

              Is this intended to be a 64-bit-only operation??

              Not sure what gave you that idea. That code will build and function correctly on both 32/64 bit platforms. The library 'Secur32.lib' was named a really long time ago and just like the path'C:\Windows\System32' the decision was made to keep the old name.

              Derell Licht wrote:

              I searched through *all* .h and .hpp files in c:\mingw, and these functions were not declared anywhere...

              I very rarely use the MinGW compiler tools. The errors you are getting are simple #include errors. I checked the msys2 source code repository and found mingw-w64/ntsecapi.h which is dated Dec 13, 2013 has all of the required function declarations. Sounds like you just need to update your development environment. Best Wishes, -David Delaune

              D Offline
              D Offline
              Derell Licht
              wrote on last edited by
              #8

              Ahhh!! So you *are using 64-bit compiler then ?!?! mingw-w64 is the 64-bit compiler... and in my 64-bit compiler, they are also present, but not in the 32-bit compiler... Actually, though, I found a way to make this work with Mingw32... I found the clue in a page for gkrellm application, which has a support file to add support for system functions which are missing in default MinGW-32 package... What he did is use LoadLibrary() to load and obtain a handle for secur32.dll, then used GetProcAddress() to get pointers to the required functions:

              hSecur32 = LoadLibraryW(L"secur32.dll");
              if (hSecur32 != NULL)
              {
              pfLELS = (pfLsaEnumerateLogonSessions)GetProcAddress(hSecur32, "LsaEnumerateLogonSessions");
              if (pfLELS == NULL)
              {
              wprintf(L"Could not get address for LsaEnumerateLogonSessions() in secur32.dll\n");
              }

              That worked beautifully for me!! And yes, your code *does* in fact return the login times that I was looking for; Thank You again!!

              L 1 Reply Last reply
              0
              • D Derell Licht

                Ahhh!! So you *are using 64-bit compiler then ?!?! mingw-w64 is the 64-bit compiler... and in my 64-bit compiler, they are also present, but not in the 32-bit compiler... Actually, though, I found a way to make this work with Mingw32... I found the clue in a page for gkrellm application, which has a support file to add support for system functions which are missing in default MinGW-32 package... What he did is use LoadLibrary() to load and obtain a handle for secur32.dll, then used GetProcAddress() to get pointers to the required functions:

                hSecur32 = LoadLibraryW(L"secur32.dll");
                if (hSecur32 != NULL)
                {
                pfLELS = (pfLsaEnumerateLogonSessions)GetProcAddress(hSecur32, "LsaEnumerateLogonSessions");
                if (pfLELS == NULL)
                {
                wprintf(L"Could not get address for LsaEnumerateLogonSessions() in secur32.dll\n");
                }

                That worked beautifully for me!! And yes, your code *does* in fact return the login times that I was looking for; Thank You again!!

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #9

                Derell Licht wrote:

                That worked beautifully for me!! And yes, your code *does* in fact return the login times that I was looking for; Thank You again!!

                You are welcome. Best Wishes, -David Delaune

                1 Reply Last reply
                0
                • D Derell Licht

                  I'm trying to determine this value for a system-status program that I maintain. In the past, I've just shown Uptime, but now that I'm forced to Windows 10, that isn't entirely informative!! If I log out of my machine (shutdown -l) and then log back in, Uptime doesn't get reset. So I want to add an option to show logon time vs reboot time (Uptime)... but I'm not having much success with this... I have found several articles which recommend NetUserGetInfo(), but this is returning invalid data for me... for example, I just logged out, and back in, to my machine... here is the code, followed by the results that I get:

                  // Call the NetUserGetInfo function.
                  dwLevel = 2;
                  wchar_t username[UNLEN+1];
                  DWORD username_len = UNLEN+1;
                  GetUserNameW(username, &username_len);
                  nStatus = NetUserGetInfo(NULL, username, dwLevel, (LPBYTE *) & pBuf);
                  // skipping result checking
                  pBuf2 = (LPUSER_INFO_2) pBuf;
                  wprintf(L"User account name: %s\n", pBuf2->usri2_name);
                  wprintf(L"Password age (seconds): %d\n", pBuf2->usri2_password_age);
                  wprintf(L"Last logon (seconds since January 1, 1970 GMT): %d\n", pBuf2->usri2_last_logon);
                  time_t logon_time = pBuf2->usri2_last_logon ;
                  char buff[20];
                  strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&logon_time));
                  printf("logon time: %s\n", buff);

                  The results that I get are:

                  User account name: dan7m
                  Password age (seconds): 10221317
                  Last logon (seconds since January 1, 1970 GMT): 1616249786
                  logon time: 2021-03-20 07:16:26

                  Note that the logon time *actually* around 1920 on 06/05/21... So I have two questions, I guess... 1. is there some way to make this function actually work?? 2. if not, how else can I programmatically access the login time on Windows 10 64bit??

                  D Offline
                  D Offline
                  Derell Licht
                  wrote on last edited by
                  #10

                  Well, since this works so nicely, I thought I would include the complete, working demo function here... however, apparently, I cannot actually attach a file in a message, so I will just link to the file in my Github repository, in the program that it will be used in. derbar/login_lsa.cpp at master · DerellLicht/derbar · GitHub[^] Be sure to enable the STAND_ALONE macro to build stand-alone utility, either in the code, or by putting the macro on the command line, like this:

                  g++ -Wall -O2 -DSTAND_ALONE=1 login_lsa.cpp -o login_lsa.exe -lsecur32

                  It works very nicely!!

                  L M 2 Replies Last reply
                  0
                  • D Derell Licht

                    Well, since this works so nicely, I thought I would include the complete, working demo function here... however, apparently, I cannot actually attach a file in a message, so I will just link to the file in my Github repository, in the program that it will be used in. derbar/login_lsa.cpp at master · DerellLicht/derbar · GitHub[^] Be sure to enable the STAND_ALONE macro to build stand-alone utility, either in the code, or by putting the macro on the command line, like this:

                    g++ -Wall -O2 -DSTAND_ALONE=1 login_lsa.cpp -o login_lsa.exe -lsecur32

                    It works very nicely!!

                    L Offline
                    L Offline
                    Lost User
                    wrote on last edited by
                    #11

                    You could post it (including a write up) in the Tips and Tricks section of Submit a new Article[^].

                    D 1 Reply Last reply
                    0
                    • L Lost User

                      You could post it (including a write up) in the Tips and Tricks section of Submit a new Article[^].

                      D Offline
                      D Offline
                      Derell Licht
                      wrote on last edited by
                      #12

                      Actually, that's a good idea... I haven't created an article here in awhile... I did so... here is a link to the article: Determine Time Since Last Logon[^]

                      1 Reply Last reply
                      0
                      • D Derell Licht

                        Well, since this works so nicely, I thought I would include the complete, working demo function here... however, apparently, I cannot actually attach a file in a message, so I will just link to the file in my Github repository, in the program that it will be used in. derbar/login_lsa.cpp at master · DerellLicht/derbar · GitHub[^] Be sure to enable the STAND_ALONE macro to build stand-alone utility, either in the code, or by putting the macro on the command line, like this:

                        g++ -Wall -O2 -DSTAND_ALONE=1 login_lsa.cpp -o login_lsa.exe -lsecur32

                        It works very nicely!!

                        M Offline
                        M Offline
                        Maximilien
                        wrote on last edited by
                        #13

                        thanks for sharing that.

                        CI/CD = Continuous Impediment/Continuous Despair

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups