PCの起動時間を計測して、特定の時間が経過すると強制シャットダウンする

# 背景
暇つぶしのネタとして某クラウドソーシングの案件を勝手に（※）やってみる。
※：受注したわけではない
https://github.com/tagawa0525/prac_restart

# 仕様
## 仕様の確認
### Q:依頼
GithubではないCopilot君に公開用としてまとめなおしてもらう。
```
--- 依頼文のコピペ ---
上記の仕様を背景、目的、概要でまとめなおしてください。
```

### A
```
背景
多くのユーザーがPCをシャットダウンせずにスリープ状態のまま長期間放置するため、OSのアップデートやセキュリティ更新が滞ってしまう問題が発生しています。この状態では、システムの安全性とパフォーマンスが低下するリスクが高まります。

目的
PCの起動から特定の時間（例：72時間）経過後に強制シャットダウンを実行し、システムの更新とセキュリティ対策を促進することを目的としています。これにより、ユーザーが意図的または無意識にPCを長期間スリープ状態にし続けることを防ぎ、定期的なメンテナンスを確保します。

概要
時間計測：PCの起動からの時間を計測し、特定の時間（例：72時間）経過後に強制シャットダウンを実行します。

アラート表示：特定の時間が経過する前に、複数のタイミング（例：24時間前、6時間前、3時間前、1時間前、30分前、15分前、10分前、5分前）でアラートをポップアップ表示させ、ユーザーにシャットダウンが近づいていることを通知します。

強制シャットダウン：指定された時間が経過すると、保存されていないデータやソフトも含めて強制的にシャットダウンを実行します。シャットダウンの5分前にはカウントダウンが表示され、0になると即座にシャットダウンが行われます。

ユーザー操作：アラート表示時に「OK」ボタンをクリックすることでアラートが消えますが、シャットダウンのタイミングは変わりません。
```

## プロトタイプの実装
### Q:依頼
```
実装してください
```

### A
```
コードの実装について具体的な手順を説明します。このソリューションは、Python を用いたスクリプトを使って、PC の起動時間を計測し、指定された時間が経過すると強制的にシャットダウンを実行するものです。

以下はそのコードの一例です：
```
```python
import time
import ctypes
import os
import threading
from tkinter import messagebox, Tk

def show_alert(message):
    root = Tk()
    root.withdraw()  # メインウィンドウを表示しない
    messagebox.showwarning("警告", message)
    root.destroy()

def shutdown():
    os.system('shutdown /s /f /t 0')  # 強制シャットダウンコマンド

def start_shutdown_timer(total_time, alerts):
    start_time = time.time()

    for alert_time in alerts: # この辺バグっている。（以下参照）
        time.sleep(alert_time)
        threading.Thread(target=show_alert, args=(f"{total_time // 3600}時間後に強制シャットダウンします。",)).start()

    countdown_time = 300  # 5分前カウントダウン
    for i in range(countdown_time, 0, -1):
        print(f"強制シャットダウンまで {i} 秒")
        time.sleep(1)

    shutdown()

if __name__ == "__main__":
    total_time = 72 * 3600  # 72時間を秒に換算
    alerts = [total_time - 24 * 3600, total_time - 6 * 3600, total_time - 3 * 3600, total_time - 3600, total_time - 1800, total_time - 900, total_time - 600, total_time - 300]

    # シャットダウンタイマーを開始
    threading.Thread(target=start_shutdown_timer, args=(total_time, alerts)).start()
```
```
このスクリプトは、PCが起動してから72時間を計測し、その間に指定された時間にポップアップアラートを表示します。そして最終的には強制シャットダウンを実行します。

+ show_alert 関数：指定されたメッセージを含む警告ポップアップを表示します。
+ shutdown 関数：強制シャットダウンを実行するコマンドです。
+ start_shutdown_timer 関数：起動時間を計測し、指定された時間にアラートを表示し、最終的に強制シャットダウンを実行します。

このスクリプトを実行することで、目的通りにPCが強制的にシャットダウンされるようになります。

安全面を考慮し、実行前に他の重要なデータやタスクが失われないよう、十分に確認してください。
```


## バグ修正
経過時間の計算のところが明らかにおかしいので修正。
``` py
def start_shutdown_timer(total_time, alerts):
    start_time = time.time()

    for alert_time in alerts:
        elapsed_time = time.time() - start_time
        time.sleep(alert_time - elapsed_time)
        h = int((total_time - alert_time) // HOUR)
        m = int((total_time - alert_time) % HOUR / MIN)
        threading.Thread(
            target=show_alert,
            args=(f"後{h}時間{m}分後に強制シャットダウンします。",),
        ).start()

    countdown_time = 5 * MIN  # 5分前カウントダウン
    for i in range(countdown_time, 0, -1):
        print(f"強制シャットダウンまで {i} 秒")
        time.sleep(1)

    shutdown()
```

### Q:指摘
```
72時間黒い画面が出続けているのはユーザーに閉じられると思いますので、解決策を提案してください。
```

### A
```
確かに、長時間にわたり黒い画面が表示されるとユーザーにとって使いづらいですね。代わりに、バックグラウンドで時間を計測し、アラートを適切なタイミングで表示する方法を提案します。これにより、ユーザーの作業が中断されることなくシャットダウンの通知を受け取ることができます。

以下は改善されたコード例です：
```

``` python
# --- 略--- 
def start_shutdown_timer(total_time, alerts):
    start_time = time.time()

    def alert_worker():
        for alert_time in alerts:
            time.sleep(alert_time)
            threading.Thread(target=show_alert, args=(f"PC起動から {alert_time // 3600} 時間が経過しました。指定時間後にシャットダウンします。",)).start()
        
        countdown_time = 300  # 5分前カウントダウン
        for i in range(countdown_time, 0, -1):
            print(f"強制シャットダウンまで {i} 秒")
            time.sleep(1)

        shutdown()

    alert_thread = threading.Thread(target=alert_worker)
    alert_thread.start()

# --- 略 ---
```

```
この改善されたコードでは、以下のような変更を加えました：
+ バックグラウンド動作：計測はバックグラウンドで行われ、ユーザーの作業中に黒い画面が表示されることはありません。
+ アラートのポップアップ表示：各アラートタイミングで警告メッセージがポップアップ表示され、ユーザーに通知します。
+ カウントダウン表示：シャットダウン5分前からカウントダウンが始まり、ユーザーに対して強制シャットダウンのタイミングを知らせます。

この方法で、ユーザーがPCをスムーズに使用しながらも、適切なタイミングでシャットダウンの通知を受け取ることができます。
```

Pythonの黒い画面自体は消えないので、できていないわけだが！！！

# 課題
## バックグラウンド実行

### Q:質問
```
windowsにおいて何日も起動し続けるプログラムを開発しています。
黒い画面が出続けると邪魔なので、バックグラウンド実行したいです。
```

### A
```
なるほど、プログラムの実行中に黒い画面が出続けると確かに不便ですよね。バックグラウンドでプログラムを実行する方法はいくつかあります。以下にその方法をいくつかご紹介します。

1. Windowsサービスとして実行
プログラムをWindowsサービスとして登録することで、バックグラウンドで実行することが可能です。これにより、黒い画面が表示されることはありません。

2. タスクスケジューラを使用
タスクスケジューラを使ってプログラムを定期的に実行するように設定することもできます。これにより、指定した時間にプログラムがバックグラウンドで実行されます。

3. PowerShellを使用
以下のようにPowerShellを使用してプログラムをバックグラウンドで実行することもできます：

powershell
Start-Process -FilePath "C:\Path\To\YourProgram.exe" -WindowStyle Hidden
このコマンドは、指定したプログラムをウィンドウを隠した状態で起動します。

4. バッチファイルを使用
バッチファイルを作成し、それを実行することでプログラムをバックグラウンドで実行することもできます。以下はその例です：

batch
start /min C:\Path\To\YourProgram.exe
このバッチファイルは、プログラムを最小化して起動します。

これらの方法の中からご希望のものを試してみてください。必要に応じてさらに詳細な説明もお手伝いしますので、どうぞお知らせください。
```

batファイルには/bオプションもあるがうまくいかなかったので、PowerShellを使用することにする。


## クロスプラットフォーム
### Q:依頼
```
windowsとmacに対応したいです。また、pythonの環境を新たにインストールしたくないので、実行可能形式(.exe等)にしたいです。 ソースファイルをある程度共通化できる言語を複数挙げてそのメリットデメリットを教えてください。なお、クロスコンパイル可能だとありがたいです。
```

### A
```
ここでは、WindowsとmacOSに対応し、Python環境を新たにインストールする必要がなく、実行可能形式（.exeなど）にできるクロスコンパイル可能な言語をいくつか紹介します。それぞれのメリットとデメリットを説明します。

1. Go (Golang)
メリット:

クロスコンパイルが容易: 単一のコマンドで複数のプラットフォーム向けにバイナリを生成できます。

シンプルな構文: 学習コストが低く、迅速な開発が可能です。

標準ライブラリが豊富: 多くの機能が標準ライブラリに含まれており、追加の依存関係を最小限に抑えられます。

デメリット:

ガベージコレクション: リアルタイムシステムなどの性能が重要な場面ではガベージコレクションがネックになることがあります。

ジェネリクスの制約: 2022年のGo 1.18からジェネリクスが導入されていますが、他の言語に比べてまだ成熟していない部分もあります。

2. Rust
メリット:

高パフォーマンス: CやC++に匹敵する性能を持ち、メモリ安全性が高い。

クロスコンパイルが可能: 多くのプラットフォーム向けにコンパイルできます。

優れたエラーハンドリング: 強力な型システムと所有権システムにより、バグやエラーを防ぐ設計になっています。

デメリット:

学習曲線が急: 所有権システムやライフタイム管理など、他の言語にはない概念があり、初心者には難しいと感じることがあります。

コンパイル時間が長い: 他の言語に比べてコンパイル時間が長いことがある。

3. C#
メリット:

クロスプラットフォーム: .NET Coreや.NET 5+を使うことで、Windows、macOS、Linuxで動作するアプリケーションを作成可能。

強力な開発ツール: Visual Studioなどの強力なIDEと豊富なライブラリが利用可能。

商用利用可能: ライセンスに問題なく商用利用できます。

デメリット:

ランタイム依存: .NETランタイムのインストールが必要であり、完全なスタンドアロンの実行ファイルではない。

セットアップの複雑さ: 開発環境のセットアップが他の言語に比べて複雑になることがあります。

4. Kotlin
メリット:

クロスプラットフォーム: Kotlin/Nativeを使用して、Windows、macOS、Linux向けにネイティブバイナリを生成できます。

モダンな言語機能: Null安全性や拡張関数など、モダンなプログラミング言語機能が豊富。

豊富なエコシステム: Android開発での人気も高く、多くのライブラリやツールが利用可能です。

デメリット:

パフォーマンス: 非ネイティブな場合、特にJVM上で動作するため、ネイティブコードに比べてパフォーマンスが劣ることがあります。

サポートの成熟度: 特にKotlin/Nativeに関しては、他の言語に比べて成熟度が低い部分もあります。

まとめ
初心者や迅速な開発を求める場合：Goがおすすめです。学習コストが低く、クロスコンパイルが簡単です。

パフォーマンスやメモリ安全性が重要な場合：Rustが適しています。高パフォーマンスでメモリ安全性が高いですが、学習曲線は急です。

強力なツールと豊富なライブラリを利用したい場合：C#が良い選択肢です。特に.NET環境に慣れている場合に最適です。

モダンな言語機能とクロスプラットフォーム開発を求める場合：Kotlinも考慮すべきです。豊富なエコシステムとモダンな言語機能が魅力です。

どの言語が最適かはプロジェクトの具体的なニーズやチームのスキルセットに依存します。必要であれば、さらに詳細な情報や具体的な実装例を提供しますのでお知らせください。
```

C#, Kotlinは.NETフレームワークやJVMなどの追加のインストールが必要そうなので、却下。
GoとRustだと触った時間が長いRustとする。

# 実装
Github Copiot君で実装！