14

So quite simply, the question is how to get the system boot up time in windows with c/c++.

Searching for this hasn't got me any answer, I have only found a really hacky approach which is reading a file timestamp ( needless to say, I abandoned reading that halfway ).

Another approach that I found was actually reading windows diagnostics logged events? Supposedly that has last boot up time.

Does anyone know how to do this (with hopefully not too many ugly hacks)?

4

5 に答える 5

22

GetTickCount64「システムが起動してから経過したミリ秒数を取得します。」

システムが実行されている期間がわかれば、現在の時刻からこの期間を差し引いて、いつ起動されたかを判断するだけです。たとえば、C ++ 11クロノライブラリ(Visual C ++ 2012でサポート)を使用すると、次のようになります。

auto uptime = std::chrono::milliseconds(GetTickCount64());
auto boot_time = std::chrono::system_clock::now() - uptime;
于 2012-06-01T16:26:10.197 に答える
8

WMIを使用して、正確な起動時間を取得することもできます。WMIは気弱な人向けではありませんが、探しているものを取得できます。

問題の情報は、プロパティWin32_OperatingSystemの下のオブジェクトにありLastBootUpTimeます。WMIツールを使用して他のプロパティを調べることができます。

プロパティインスタンスを表示するWMIエクスプローラー

編集: 必要に応じて、コマンドラインからこの情報を取得することもできます。

wmic OS Get LastBootUpTime

C#の例として、次のようになります(C ++を使用するとかなり冗長になります)。

static void Main(string[] args)
{      
    // Create a query for OS objects
    SelectQuery query = new SelectQuery("Win32_OperatingSystem", "Status=\"OK\"");

    // Initialize an object searcher with this query
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

    string dtString;
    // Get the resulting collection and loop through it
    foreach (ManagementObject envVar in searcher.Get())
        dtString = envVar["LastBootUpTime"].ToString();
}
于 2012-06-01T16:49:15.727 に答える
4

「System」オブジェクトの「SystemUpTime」パフォーマンスカウンターは別のソースです。PDHHelperメソッドを使用してプログラムで利用できます。ただし、スリープ/休止状態のサイクルに対して堅牢ではないため、おそらくGetTickCount()/よりもはるかに優れているわけではありませんGetTickCount64()

カウンターを読み取ると、64ビットFILETIME値(Windowsエポック(1601-01-01 00:00:00 UTC)以降の100-NSティック数)が返されます。また、これを計算するために使用される生の値を公開するWMIテーブルを読み取ることにより、カウンターが返す値を確認できます。(COMを使用してプログラムで読み取るか、wmicからコマンドラインを取得します:)

wmic path Win32_PerfRawData_PerfOS_System  get systemuptime

そのクエリは、2021年1月23日土曜日午後6時14分36秒UTCに対応する132558992761256000を生成します。

PerfFormattedDataこれに相当するものを使用して、浮動小数点の秒数を取得するか、PowerShellのコマンドラインから読み取るかwmic、PowerShellのカウンターにクエリを実行できます。

Get-Counter -Counter '\system\system up time'

これにより、427.0152秒の稼働時間が返されます。

また、他の3つの回答のそれぞれを実装し、方法を選択しようとしている人に役立つ可能性のあるいくつかの観察結果があります。

現在の時刻の使用GetTickCount64と減算

  • 0.112ミリ秒でクロックインする最速の方法。
  • クロックティックに依存するため、引数の100nsの解像度で一意の一貫した値を生成しません。戻り値はすべて、互いに1/64秒以内です。
  • Vista以降が必要です。アプリケーション/ライブラリが古いバージョンのWindowsをサポートする必要がある場合、XPの32ビットカウンターは最大49日でロールオーバーし、このアプローチには使用できません。

LastBootUpTimeのフィールドのWMIクエリを使用するWin32_OperatingSystem

  • COMを使用して84ミリ秒、wmicコマンドラインを使用して202ミリ秒かかりました。
  • CIM_DATETIME文字列として一貫した値を生成します
  • WMIクラスにはVista以降が必要です。

イベントログの読み取り

  • 最も遅い方法で、229ミリ秒かかります
  • 秒単位で一貫した値を生成します(Unix時間)
  • Windows2000以降で動作します。
  • コメントでジョナサン・ギルバートが指摘したように、結果が出るとは限りません。

これらのメソッドは、異なるタイムスタンプも生成しました。

  • 稼働時間:1558758098843 = 2019-05-25 04:21:38 UTC(場合によっては:37)
  • WMI:20190524222528.665400-420 = 2019-05-25 05:25:28 UTC
  • イベントログ:1558693023 = 2019-05-24 10:17:03 UTC

結論:

イベントログメソッドは、古いバージョンのWindowsと互換性があり、UNIX時間で一貫したタイムスタンプを生成します。これは、スリープ/休止状態のサイクルの影響を受けませんが、最も低速です。これがループで実行される可能性が低いことを考えると、これは許容できるパフォーマンスへの影響である可能性があります。ただし、このアプローチを使用するには、イベントログが容量に達し、古いメッセージを削除する状況を処理する必要があります。バックアップとして他のオプションの1つを使用する可能性があります。

于 2019-06-10T00:52:19.217 に答える
2

C ++ Boostは以前はWMIを使用してLastBootUpTimeいましたが、バージョン1.54では、システムイベントログのチェックに切り替えました。これには明らかに理由があります。

ABIの中断:Windowsのブートスタンプ機能を変更して、EventLogサービスの開始時刻をシステムの起動時刻として使用するようにしました。以前LastBootupTimeにWMIから使用されていたものは、時刻の同期と休止状態によって不安定であり、実際には使用できませんでした。Boost 1.54より前の動作を本当に取得する必要がある場合はBOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME、コマンドラインまたはdetail/workaround.hppから定義してください。

inline bool get_last_bootup_time(std::string &stamp)例として、関数の実装である2201行目あたりのboost / interprocess / detail/win32_api.hppを確認してください。(行番号を一致させたい場合は、バージョン1.60を見ています。)

Boostがなんらかの理由で死んで、Boostを指さしても役に立たない場合に備えて(そうです)、必要な機能は主ReadEventLogAに、検索するイベントID(Boostのコメントによると「イベントログ開始」)は明らかにです。6005

于 2019-01-18T18:02:33.947 に答える
1

私はこれほど遊んだことはありませんが、個人的には、「システム」プロセスの開始時刻を照会するのがおそらく最善の方法だと思います。Windowsでは、カーネルは起動時に独自の目的でプロセスを割り当てます(驚くべきことに、Googleですばやく検索しても、実際の目的が何であるかは簡単にはわかりませんが、情報はそこにあると確信しています)。このプロセスは、タスクマネージャでは単に「システム」と呼ばれ、現在のWindowsバージョンでは常にPID 4が使用されます(NT4およびWindows2000ではPID8が使用されている可能性があります)。このプロセスは、システムが実行されている限り終了することはなく、私のテストでは、メタデータに関する限り、本格的なプロセスのように動作します。私のテストから、昇格していないユーザーでもPID 4のハンドルを開いて、を要求できるようPROCESS_QUERY_LIMITED_INFORMATIONです。GetProcessTimeslpCreationTimeプロセスが開始された時刻のUTCタイムスタンプを入力します。私の知る限り、システムプロセスが実行される前にWindowsが実行される意味のある方法はないため、このタイムスタンプはWindowsの起動時とほぼ同じです。

#include <iostream>
#include <iomanip>

#include <windows.h>

using namespace std;

int main()
{
    unique_ptr<remove_pointer<HANDLE>::type, decltype(&::CloseHandle)> hProcess(
        ::OpenProcess(
            PROCESS_QUERY_LIMITED_INFORMATION,
            FALSE, // bInheritHandle
            4), // dwProcessId
        ::CloseHandle);

    FILETIME creationTimeStamp, exitTimeStamp, kernelTimeUsed, userTimeUsed;
    FILETIME creationTimeStampLocal;
    SYSTEMTIME creationTimeStampSystem;

    if (::GetProcessTimes(hProcess.get(), &creationTimeStamp, &exitTimeStamp, &kernelTimeUsed, &userTimeUsed)
     && ::FileTimeToLocalFileTime(&creationTimeStamp, &creationTimeStampLocal)
     && ::FileTimeToSystemTime(&creationTimeStampLocal, &creationTimeStampSystem))
    {
        __int64 ticks =
            ((__int64)creationTimeStampLocal.dwHighDateTime) << 32 |
            creationTimeStampLocal.dwLowDateTime;

        wios saved(NULL);

        saved.copyfmt(wcout);

        wcout << setfill(L'0')
            << setw(4)
            << creationTimeStampSystem.wYear << L'-'
            << setw(2)
            << creationTimeStampSystem.wMonth << L'-'
            << creationTimeStampSystem.wDay
            << L' '
            << creationTimeStampSystem.wHour << L':'
            << creationTimeStampSystem.wMinute << L':'
            << creationTimeStampSystem.wSecond << L'.'
            << setw(7)
            << (ticks % 10000000)
            << endl;

        wcout.copyfmt(saved);
    }
}

私の現在のブートの比較:

  • system_clock::now() - milliseconds(GetTickCount64())

2020-07-18 17:36:41.3284297
2020-07-18 17:36:41.3209437
2020-07-18 17:36:41.3134106
2020-07-18 17:36:41.3225148
2020-07-18 17:36:41.3145312

(結果は呼び出しごとに異なります。これはsystem_clock::now()::GetTickCount64()がまったく同時に実行されず、同じ精度がないためです)

  • wmic OS Get LastBootUpTime

2020-07-18 17:36:41.512344

  • イベントログ

現在、私のシステムにはイベントログエントリが存在しないため、結果はありません(最も早いイベントは7月23日からです)

  • GetProcessTimesPID 4:

2020-07-18 17:36:48.0424863

他の方法とは数秒異なりますが、システムプロセスがまだ実行されていない場合、システムは実際に起動されたので、それ自体が間違っているとは考えられません。

于 2020-07-23T10:11:37.067 に答える