{"id":105232,"date":"2021-05-20T07:00:00","date_gmt":"2021-05-20T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105232"},"modified":"2021-05-20T06:20:43","modified_gmt":"2021-05-20T13:20:43","slug":"20210520-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210520-00\/?p=105232","title":{"rendered":"Obtaining network usage information from the Windows Runtime"},"content":{"rendered":"<p>Network usage information on Windows can be obtained from classes in the <code>Windows.<wbr \/>Networking.<wbr \/>Connectivity<\/code> namespace. The <code>Network\u00adInformation<\/code> class is your starting point.<\/p>\n<p>We&#8217;ll start with C# and translate to C++\/WinRT when we&#8217;re done.<\/p>\n<p>Prepare a C# console application to use Windows Runtime asynchronous operations as described <a title=\"Awaiting Windows Runtime asynchronous operations from C# desktop apps\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210519-00\/?p=105229\"> last time<\/a>, and start typing.<\/p>\n<pre>using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Threading.Tasks;\r\nusing Windows.Networking.Connectivity;\r\n\r\nclass Program\r\n{\r\n    static async Task DoIt()\r\n    {\r\n        var now = DateTime.Now;\r\n        var states = new NetworkUsageStates\r\n        { Roaming = TriStates.DoNotCare, Shared = TriStates.DoNotCare };\r\n\r\n        var profiles = NetworkInformation.GetConnectionProfiles();\r\n        foreach (var profile in profiles)\r\n        {\r\n            var usages = await profile.GetNetworkUsageAsync(\r\n                now.AddDays(-1), now, DataUsageGranularity.PerDay,\r\n                states);\r\n            var usage = usages[0];\r\n            if (usage.ConnectionDuration &gt; TimeSpan.Zero)\r\n            {\r\n                Console.WriteLine(profile.ProfileName);\r\n                Console.WriteLine($\"BytesReceived = {usage.BytesReceived}\");\r\n                Console.WriteLine($\"BytesSent = {usage.BytesSent}\");\r\n                Console.WriteLine($\"ConnectionDuration = {usage.ConnectionDuration}\");\r\n                Console.WriteLine($\"------------------\");\r\n            }\r\n        }\r\n\r\n    }\r\n    static void Main()\r\n    {\r\n        DoIt().GetAwaiter().GetResult();\r\n    }\r\n}\r\n<\/pre>\n<p>All of the work happens in the creatively-named <code>DoIt<\/code> method. The main function just calls <code>DoIt()<\/code> and waits for the task to complete. If you can upgrade to C# 7.1 or better, you can take advantage of <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-7-1#async-main\"> async main<\/a> support.<\/p>\n<p>Okay, so back to the <code>DoIt()<\/code> method.<\/p>\n<p>We first capture the current time into a local variable <code>now<\/code>. This ensures that our time queries are consistent through the loop.<\/p>\n<p>We also create a local <code>Network\u00adUsage\u00adStates<\/code> object which says that we don&#8217;t care about distinguishing whether you were Roaming or Shared.<\/p>\n<p>We then ask the <code>Network\u00adInformation<\/code> object for all the connection profiles. For each profile, we ask for usage in the last 24 hours, aggregated by day. Given those parameters, there will be exactly one usage report.\u00b9<\/p>\n<p>For any connection that was used for a nonzero amount of time, we report the various properties of that daily usage.<\/p>\n<p>Note that generating these reports is time-consuming, so if you already know which connections you want, you can filter on their name. If you are interested only in the connection that is currently being used for Internet access, you can use <code>Get\u00adInternet\u00adConnection\u00adProfile<\/code> instead of enumerating through all of the connections.<\/p>\n<p>And here&#8217;s the C++\/WinRT version.<\/p>\n<pre>#include &lt;winrt\/Windows.Foundation.h&gt;\r\n#include &lt;winrt\/Windows.Foundation.Collections.h&gt;\r\n#include &lt;winrt\/Windows.Networking.Connectivity.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nusing namespace std::literals::chrono_literals;\r\nusing namespace winrt;\r\nusing namespace winrt::Windows::Foundation;\r\nusing namespace winrt::Windows::Networking::Connectivity;\r\n\r\nIAsyncAction DoIt()\r\n{\r\n    auto now = clock::now();\r\n    NetworkUsageStates states{ TriStates::DoNotCare, TriStates::DoNotCare };\r\n\r\n    auto profiles = NetworkInformation::GetConnectionProfiles();\r\n    for (auto profile : profiles)\r\n    {\r\n        auto usages = co_await profile.GetNetworkUsageAsync(\r\n            now - 24h, now, DataUsageGranularity::PerDay, states);\r\n        auto usage = usages.GetAt(0);\r\n        auto seconds = static_cast&lt;int&gt;(std::chrono::duration_cast&lt;\r\n            std::chrono::seconds&gt;(usage.ConnectionDuration()).count());\r\n        if (seconds &gt; 0)\r\n        {\r\n            printf(\"%ls\\n\", profile.ProfileName().c_str());\r\n            printf(\"BytesReceived = %I64u\\n\", usage.BytesReceived());\r\n            printf(\"BytesSent = %I64u\\n\", usage.BytesSent());\r\n            printf(\"ConnectionDuration = %d seconds\\n\", seconds);\r\n            printf(\"------------------\\n\");\r\n        }\r\n\r\n    }\r\n}\r\n\r\nint main()\r\n{\r\n    init_apartment();\r\n    DoIt().get();\r\n}\r\n<\/pre>\n<p>Next time, we&#8217;ll look at usage attribution.<\/p>\n<p>\u00b9 If we had asked for multiple days, then there would be one report per day, in chronological order. Note that the definition of &#8220;day&#8221; is not &#8220;calendar day&#8221; but &#8220;24-hour period starting at the provided start time.&#8221; If the time range is not an exact multiple of the granularity, then the last report will cover only part of the granularity interval.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Getting your foot in the door with the NetworkInformation class.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-105232","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Getting your foot in the door with the NetworkInformation class.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105232","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=105232"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105232\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=105232"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105232"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105232"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}