Thinkpadのアップデートかけたらタスクスケジューラにエラーが出てブルースクリーンになった
Thinkpadが提供するアップデートをかけたら逆に不具合が出たのでThinkpadVantage Rescur and Recoveryを使って少し前の状態に戻した.(直前にバックアップをとってた)
そしたらタスクスケジューラを起動すると「タスクイメージは破損しているか、または変更されています。」と表示されタスクスケジューラが使えない状態に.
ここを参考にして悪さをしてるタスクを調べると「SystemToolsDailyTest」というタスクだった.
これはどうも右下にぴょこっと出てきて異常がないか知らせるポップアップの起動に関するものらしい.
常日頃からあのポップアップがうざったらしいと思っていたので参考先に従って削除(正確には違うフォルダに隔離)した.
するとタスクスケジューラを起動してもエラーが出てこなくなったのでめでたしめでたし.
と思ったのだけど,そうすると今度は突如ブルースクリーンに見舞われることになってしまった.
始めは見当が付かなかったけれど,1:00になってWinSAT.exeが起動してwindows の評価をしてたらまたブルースクリーンになったのを見てタスクスケジューラ周りの悪さであると推測.(WinSATは日曜1:00に実行されるようにスケジュールされている)
調べたところ,SystemToolsDailyTestのタスクスケジューラに関するレジストリは残ったままだったので,ここを参考にして関係するレジストリを削除(正確には違うフォルダに隔離)した.
これが正解である保証はないけどしばらくこれで様子を見てみよう.
しかしこういうとこThinkpadダメだなぁ…
Linuxのライブラリ検索順番
Qtでコンパイルすると「libQtCore.so」や「libQtGui.so」などといった共有ライブラリを実行開始時に動的リンクして実行する.
私の環境では正規の(?)ライブラリディレクトリには古いQtライブラリが入っており,ホームディレクトリに自分でインストールした新しいQtライブラリをインストールしている.
自分のアカウント内ではパスとかを通してる(よく知らないけど通ってる,ってのが正しい)ので問題ないけれど,他アカウントから私の実行ファイルを実行しようとするとセグメンテーション違反になった.
調べてみるとどうも他のアカウントからでは私が自分でインストールしたQtライブラリをたどれずに,古いQtライブラリを動的リンクしてしまい,エラーになっているようだった.
共有ライブラリの依存状態を調べるには「ldd」コマンドで調べられた.
で,ライブラリを読んでくれるように試行錯誤した.
始めに実行ファイルと同じディレクトリに「ln」コマンドで私がインストールしたQtライブラリへシンボリックリンクを張ってみたがダメだった.
「cp」コマンドで.soファイルをそのままコピーして持ってきてもダメだった.
仕方ないので実行時のライブラリの検索順序を調べてみた.
それによると環境変数の「LD_LIBRARY_PATH」の順番で調べられるみたい.
だから「export LD_LIBRARY_PATH=○○:$LD_LIBRARY_PATH」みたいにLD_LIBRARY_PATHの最初に追記すればそちらの.soファイルをリンクしてくれる.
追記後にlddで調べると「libQtCore.so」などが自分のディレクトリのライブラリにリンクするように更新されているのが確認できた.(もちろん実行も可能になった)
windowsのdllだと同じフォルダに置いとけばよろしくリンクしてくれた気がしたので悩んでしまった.
あと/etc/ld.so.confに記述されたパスも検索するらしいけれど,そのあたりは検証してないから分からない.
環境変数「LD_LIBRARY_PATH」の順番で検索順番を指定したけれど,環境変数「LD_PRELOAD」にファイルを指定を指定する方法でもいいみたい.
pythonでWindows APIを実行する
pythonでWindows API(DLL)を実行するには「ctypes」というライブラリを使用すればよいみたい.
チュートリアルに書いてあることでほぼ事足りる感じ.
Windowsだと結構Cだとヘッダーファイルの#defineで「GetModuleHandle」が「GetModuleHandleA」「GetModuleHandleW」に自動的に書き換えられるけど,pythonみたいにDLLから直接実行する場合はAやWを付けて実行しないといけない.
(ホントはunicodeとかに応じて場合分けして実行すべきなんだろうけどめんどくさい)
ctypesでは,ほとんどCと同じことができる.ポインタ,構造体,配列からコールバックまで!
ctypes.sizeofで構造体のC言語での大きさとかも調べらる.
LASTINPUTINFOのcbSizeみたいに,Windows APIで使われる構造体では自分の構造体の大きさを指定しなきゃいけないことが多いので便利.
後はGetWindowTextのlpStringみたいに呼び出す側で文字列領域確保しといてね,ってケースもWindow APIには多い.
そうした場合にはこんな感じにすればいいみたい.
import ctypes
user = ctypes.windll.user32
def getWindowText(hwnd):
# 文字の長さ取得
length = user.GetWindowTextLengthW(hwnd) + 1
# 文字列領域確保
s = (ctypes.c_wchar * length)()
# 文字列領域に参照でテキスト取得
user.GetWindowTextW(hwnd, ctypes.byref(s), length)
return s.value
コードの見栄えを良くするのはどうしたらいいんだろう.
まぁおいおいね.
テスト
ひゅーん