Smith5727
Smith5727

Reputation: 785

Last Boot Time in .NET Standard 2.0

In .NET 8.0 I can do the following to fetch the last boot time of the PC:

 public static DateTime? GetLastBootTime()
 {
     DateTime? dtBootTime = null;
     SelectQuery query = new SelectQuery(@"SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary='true'");

     ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
     foreach (ManagementObject mo in searcher.Get())
     {
         dtBootTime = ManagementDateTimeConverter.ToDateTime(mo.Properties["LastBootUpTime"].Value.ToString());
     }

     return dtBootTime;
 }

This works great but I want to have this code in a shared class which is using netstandard2.0.

Is it possible to somehow do the same thing but in .NET Standard 2.0? I though TickCount64 could work but its not available in net standard.

Upvotes: 1

Views: 87

Answers (3)

Matthew Watson
Matthew Watson

Reputation: 109782

If you don't want to use a NuGet package, and you are ONLY ever going to be using the library on Windows applications, you can use P/Invoke to call the operating system's GetTickCount64() function.

IMPORTANT: .NET Standard 2.0 supports P/Invoke calls, but as soon as you do that the assembly doing so will only work on Windows.

The P/Invoke for this would look like:

public static class PInvokes
{
    [DllImport("kernel32")]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    public static extern long GetTickCount64();
}

Then you can just call PInvokes.GetTickCount64() to get the number of ticks since the operating system was booted.

Note that you should use [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] for security - it ensures that the system DLL being loaded will ONLY be loaded from System32. Without that, it's possible that some other DLL could be loaded.

Also note that if you do use the "System.Management" NuGet package instead to provide this functionality, that will also mean that the assembly is dependent on Windows.


As an alternative approach which works for all supported operating systems, you can use Stopwatch.GetTimestamp(), which is available in .NET Standard 2.0:

public static long TickCount64()
{
    return Stopwatch.GetTimestamp() / (Stopwatch.Frequency/1000);
}

This does seem to return a value a few seconds different from GetTickCount64(), but perhaps a few seconds here and there won't matter for your purposes.

Upvotes: 0

nastaran dehghan
nastaran dehghan

Reputation: 1

Two ways:

1- Use higher versions of .NET Standard, because .NET Standard 2.0 cannot use WMI classes directly. Additionally, as stated in the question, TickCount64 is not available in .NET Standard and cannot be used.

2- In .NET Standard 2.0, instead of TickCount64, use Environment.TickCount to get the last boot time of the system.

Upvotes: -2

Jeroen Landheer
Jeroen Landheer

Reputation: 9943

You will need to put this function in a library if you want to use it in .Net Standard. I've tried it and it works both from a console app written in .Net 8 and another app in .Net Framework.

The trick is in the class library's project to include the following:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Management" Version="8.0.0" />
  </ItemGroup>

</Project>

That way the library can be referenced easily from both .Net 8 and older versions of .Net.

As others have stated in the comments, you can only use this functionality on Windows so you might want to target a windows variant of .Net 8 for your app or decorate this function with a [SupportedOsPlatform] attribute.

Upvotes: 3

Related Questions