Python .NETについて

以前作っていたモニタリングするアプリケーションについて

https://qiita.com/ppza53893/items/6bd3c5923376f348889b

このアプリでは、通知やメッセージボックスなどの.NET系、[OpenHardwareMonitor](https://openhardwaremonitor.org/)を[Python.NET](http://pythonnet.github.io/)を使って呼び出しています。
Python.NETというのは、公式docにもあるように

> Python.NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and provides a powerful application scripting tool for .NET developers. It allows Python code to interact with the CLR, and may also be used to embed Python into a .NET application.

約(DeepL):
> Python.NET は、Pythonプログラマに .NET Common Language Runtime (CLR) とのほぼシームレスな統合を提供し、.NET 開発者に強力なアプリケーションスクリプティングツールを提供するパッケージです。PythonのコードがCLRと対話することを可能にし、Pythonを.NETアプリケーションに組み込むために使用されることもあります。

要は、.NETの関数やクラスなどをpythonで使えるようにしたものです。
僕自身は大学での測定装置用ソフトウェアを作っていたときに出会いました。

# 使い方
最新版(2022/11/24時点)ではpython 3.7~3.11で対応しています。
以下のコマンドでインストールできます。
`pip install pythonnet`

使う際は、次のコードをはじめに書きます。Linux/Macではmonoが、Windowsでは.NET Frameworkが使えます。

```python
import clr
```

v3.0以降では環境変数を変えるか`pythonnet.load`を使うと、.NET Coreが使えるようになります。

```python
import pythonnet
pythonnet.load('coreclr')

# or

import os
os.environ['PYTHONNET_RUNTIME'] = 'coreclr'

# ________________________________________

import clr
```

使いたい関数などを使う場合は、そのアセンブリ名を追加する必要があります。例えば、`System.ComponentModel.Primitives`の`Container`を使いたい場合であれば、

```python
clr.AddReference('System.ComponentModel.Primitives')

from System.ComponentModel import Container
```

ちなみに公式ドキュメントとかにもないですが、アセンブリがどこにあるかを調べたいときは次で取れます。

```python
directory = clr.FindAssembly('System.ComponentModel.Primitives')
print(directory) # 'C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\\\System.ComponentModel.Primitives.dll'
```

# 例

とりあえずなんか呼び出してみましょう。
Windowsの通知センターにタイトルが`python`で`Hello World!`を出すプログラムを作ってみます。
c#などを触った方がいれば、それと同じことをしてるだけです。

```python
import os
import time
from typing import Optional

import clr

# reference追加
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.ComponentModel.Primitives')
clr.AddReference('System.Drawing')

# import
import System.Windows.Forms as Forms
from System.ComponentModel import Container
from System.Drawing import Icon, SystemIcons

container = Container()
notifyicon = Forms.NotifyIcon(container)

def show_notification(
    title: str,
    message: str,
    app_icon: Optional[str] = None) -> None:

    app_icon = app_icon
    if app_icon is not None and os.path.exists(app_icon):
        icon = Icon(app_icon)
    else:
        icon = SystemIcons.Application # なければ、デフォルトアイコン

    notifyicon.Icon = icon # アイコンをセット
    notifyicon.BalloonTipTitle = title # タイトルを決定
    notifyicon.BalloonTipText = message # 表示メッセージ
    notifyicon.Visible = True # 見えるように
    notifyicon.ShowBalloonTip(1) # 表示時間(osの中身で決まってるので、引数はあんまし意味がない)

if __name__ == '__main__':
    # icon(任意)
    icon = './shared.ico' # .icoファイルである必要あり
    show_notification(title = 'python', message='hello world!', app_icon=icon)
    time.sleep(7)
    container.Dispose() # 7s程度待たないとアイコンがバグる

```

結果:
![名称未設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/783413/eb46d614-6c4f-1dc1-84e5-15ff4c91493a.png)

こんな感じで通知もできるわけです(同じことはpythonの[plyer](https://github.com/kivy/plyer)でもできます)。
C#等で自分の作ったプログラムをPythonで使いたい場合は、こういうPython.NETを使ってみてはどうでしょうか。

最後に、今回は.NETをPythonで呼び出しましたが、逆もできます。こちらについては、以下の記事を参照してください。
[C#にpythonで作った処理を組み込む【pythonnet準備＋確認編 2021年2月最新](https://tpsxai.com/c%E3%81%ABpython%E3%81%A7%E4%BD%9C%E3%81%A3%E3%81%9F%E5%87%A6%E7%90%86%E3%82%92%E7%B5%84%E3%81%BF%E8%BE%BC%E3%82%80%E3%80%90pythonnet%E6%BA%96%E5%82%99%EF%BC%8B%E7%A2%BA%E8%AA%8D%E7%B7%A8-2021/)