WHEA-Logger(Event ID: 18)が発生しWindows 11が異常終了する問題に対処したときのメモ
症状
Windows 11環境で、突然画面が真っ黒になりフリーズする事象が発生。
- 画面ブラックアウト
- 音声停止
- PC本体のLEDは点灯したまま
- Ctrl+Alt+Del反応なし
フリーズではなく再起動の場合もあった。
また、「デバイスに問題が発生したため、再起動する必要があります」「DPC_WATCHDOG_VIOLATION(0x33)」と表示されるのも1回だけ発生。 ダンプを解析すると「FAILURE_BUCKET_ID: 0x133_DPC_nvlddmkm!unknown_function」だった。
ハードウェア構成
- CPU: Ryzen 5 5600X
- GPU: GeForce RTX 4060
- マザーボード: ASRock B550 Phantom Gaming 4 (BIOS:P2.80I)
- メモリ:合計96GB構成
- 16GB×2
- 32GB×2(後から自分で増設)
イベントログ
イベントビューアには以下のエラーが記録されていた。
WHEA-Logger Event ID: 18 コンポーネント: プロセッサ コア エラー ソース: Machine Check Exception エラーの種類: Cache Hierarchy Error MCABank: 5 ErrorType: 9
信頼性モニターにも以下が記録されていた。
LiveKernelEvent 124 AuthenticAMD_PROCESSOR Cache BANK5
実施した対処の内容
ChatGPTに相談してみると、メモリの容量やメーカーが統一されておらずメモリコントローラに高負荷がかかっているせいかもしれないと返ってきたので、32GB×2のみの64GB構成に変更した。
その後問題は再発せず、64GBでも困らなかったのでその状態で解決とした。
(96GBに戻したくなったら、BIOSのファームウェアアップデートを試すかもしれない。)
あと、CPUヒートシンクに埃がかなり蓄積していたので掃除した。
調査の過程でGPUのドライバのバージョンアップもしたけど、それでは改善しなかったので多分無関係。
半年ほど前にメモリを増設してからしばらくは問題なかったが、6月になって気温があがってから起きるようになったので、PC内の温度も要因かもしれない。
マウスジェスチャと右クリック+ホイールでタブ切り替えができるChromeのアドオンを作った
作ったアドオンのストアページは以下。
作った理由
既存のどのマウスジェスチャアドオンにも不満点があったので欲しい機能を持つものを自作した。
既存のものに対する主な不満点は以下。
ちなみに、自分も開発中にツイッター上で動作しない問題に直面したが、理由はホイールイベントを非標準のmousewheelで拾っていたことだった。正しくはwheel。
ただ、なぜそれでツイッターでだけ動かなくなるのかは不明。
Chromeアドオンの作り方
公式ドキュメントは https://developer.chrome.com/docs/extensions/
作成するものは大まかに分けると以下のとおり。
- manifest.json
- https://developer.chrome.com/docs/extensions/mv3/intro/
- アドオンの名前や必要な権限などの情報を書くファイル。
- 作成が必須。これ以外は省略可能。
- コンテンツスクリプト(JavaScript)
- https://developer.chrome.com/docs/extensions/mv3/service_workers/
- ブラウザで表示されているWEBページ内に挿入されるスクリプト。
- サービスワーカー(JavaScript)
- https://developer.chrome.com/docs/extensions/mv3/content_scripts/
- 表示されているWEBページではなくバックグラウンドで動き、ブラウザ全体にかかわる処理を行うスクリプト。
- message.json
- https://developer.chrome.com/docs/extensions/reference/i18n/
- 国際化(i18n = internationalization)を行う場合に作成する。
- オプションページ(HTML, JavaScript)
- https://developer.chrome.com/docs/extensions/mv3/options/
- アドオンに関する設定変更用のページ。
コンテンツスクリプトとサービスワーカーそれぞれで、できることとできないことが違うので役割分担をする。
双方のあいだで情報をやり取りしたい場合、chrome APIを使用する。
コンテンツスクリプトからサービスワーカーに送る場合はchrome.runtime.sendMessage()
サービスワーカーからコンテンツスクリプトに送る場合はchrome.tabs.sendMessage()
受け取るときはどちらでもchrome.runtime.onMessage.addListener()。
マウスジェスチャの実装
ソース
https://github.com/shining-corn/MouseGestureAndWheelAction
全部は説明しきれないので要所だけ。
マニフェスト
今回つくったマウスジェスチャの場合、マニフェストは以下の通り。
{ "name": "Mouse Gesture and Wheel Action", "version": "1.0.0",
アドオンの名前とバージョン。
"manifest_version": 3,
マニフェストファイルのバージョン。
"description": "__MSG_extensionDescription__",
アドオンの説明。
__MSG_メッセージID__形式の値を指定すると、message.jsonで定義したメッセージIDの値に置き換えられる。
__MSG_extensionDescription__ならmessage.jsonの"extensionDescription"の"message"の値に置き換えられる。
"default_locale": "en",
デフォルトロケール。 このアドオンは日本語と英語に対応しており、日本以外では英語で表示するので英語を指定。
"icons": { "16": "icon/16.png", "48": "icon/48.png", "128": "icon/128.png" },
アイコン用のpngファイル。
それぞれ16x16、48x48、128x128のサイズのファイルを、アドオン用フォルダ直下から見た相対パスで指定する。
"content_scripts": [ { "matches": [ "http://*/*", "https://*/*", "file://*/*" ],
アドオンを動作させるWEBページのURLを指定。
あらゆるページでマウスジェスチャを動作させるため、*ですべてのURLに一致するようにする。
なお、こうするとChrome Web Storeにアドオンを登録するときの審査期間が長くなると、申請時に警告される。
*を使わなくても、permissionsにactiveTabを指定すると、全URLでユーザがブラウザで特定の操作を行ったときにアドオンが動作するようにできる。しかし、マウスジェスチャは特定の操作を行う前から動作させる必要があるのでactiveTabは使えなかった。
"js": [ "common.js", "content.js" ],
コンテンツスクリプトのパス。
配列に書いた順に読み込まれるので、こう書いた場合はcontent.jsからcommon.jsのスクリプトを参照できる。
"run_at": "document_start",
コンテンツスクリプトをWEBページに挿入するタイミング。
このアドオンでは、マウスの右ボタン+ホイールで別タブに移動した後にマウスの右ボタンを離したときにコンテキストメニューが表示されるのを抑制している。しかし、コンテンツスクリプトの挿入が遅いと、別タブでページを開いてすぐにそのタブに移動したときにコンテキストメニューの抑制が間に合わない。コンテンツスクリプトの挿入を速くするためにdocument_startを指定。
これでも操作が早すぎる場合は間に合わないが、それはどうしようもない。
"all_frames": true, "match_about_blank": true } ],
IFRAME内でもアドオンを動作させるため、"all_frames": trueを指定。
about:blankのIFRAMEでも動作させるため、"match_about_blank": trueを指定。
参考: https://developer.chrome.com/docs/extensions/mv3/manifest/content_scripts/#frames
実は「about:blankでも動作させる」ということの意味を理解していないが、これを指定しないと動かないIFRAMEがあるので指定している。
"background": { "service_worker": "service-worker.js" },
サービスワーカーのパス。
"permissions": [ "storage", "sessions", "bookmarks" ],
アドオンに付与する権限。
https://developer.chrome.com/docs/extensions/mv3/declare_permissions/
オプションページでカスタマイズされた設定情報を保存するためにchrome.storage.localを使用するのでstorage権限を付与。
閉じたタブを開く機能のためにchrome.sessionsを使用するのでsessions権限を付与。
ブックマークの追加、削除機能のためにchrome.bookmarksを使用するのでbookmarks権限を付与。
なお、タブ切り替え等のためにchrome.tabsを使用するが、特定のフィールドにアクセスするのでなければtabs権限は不要。
WEBページのURLやタイトルをクリップボードにコピーする機能も実装しているが、clipboard権限は不要。この権限はchrome.clipboardのために必要だが、このアドオンで使用しているのはnavigator.clipboardなので。
"options_ui": { "page": "options.html",
オプションページ用のHTMLファイルのパス。
このHTMLから読み込む他のjavascriptファイルは、<script>タグで読み込めば使える。
"open_in_tab": true } }
オプションページを独立したタブで開くようにするため、trueを指定。
マウスの移動方向の判定
マウスジェスチャでマウスを上下左右のどの方向に動かしたのかを判定するためにMath.atan2()を使用。
学校以外で初めて三角関数が役に立った。
斜め45°付近で動かされたときに、↑→↑→↑→↑→のような入力が大量に連続しないようにするため、斜め方向の角度は無視するようにした。
また、同じ方向の連続した入力は一個分としてカウントする。つまり→→のようなマウスジェスチャは認めない。
WEBページ上のマウスイベントを拾って判定するので、コンテンツスクリプト側に実装。
マウスジェスチャの軌跡の描画
マウスジェスチャ中、マウス移動の軌跡を画面上に描画するため、document.createElement('canvas')で<canvas>タグを作成し、parentElement.appendChild(element)でWEB画面に挿入。
領域を画面いっぱいにし、背景を透明にするために以下のようなスタイルを指定。
element.style.width = '100vw'; element.style.height = '100vh'; element.style.position = 'fixed'; element.style.left = '0px'; element.style.top = '0px'; element.style.margin = '0px'; element.style.padding = '0px'; element.style.border = 'none'; element.style.backgroundColor = 'transparent';
また、画面の最前面に表示するためにstyle.zIndex = 16777271を指定。
window.addEventListener()でmousemoveイベントを拾い、(event.buttons & 2) === 2で右ボタンを押しながらの移動かどうかを判定してから、以下で線を描画。
const ctx = this.canvasElement.getContext('2d'); ctx.lineWidth = 4; ctx.strokeStyle = '#408040'; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.closePath();
この時にマウスの移動距離も取得して、移動方向を判定する。
mouseupイベントが来て、event.button === 2だったらマウスジェスチャが完了したとみなす。
mouseupのときはevent.buttonsではなくevent.buttonを見る点に注意。mouseupのとき、event.buttonには離されたボタンが、event.buttonsにはそのときにまだ押されているボタンの情報が入っている。
WEBページにタブを挿入し、そこに描画する処理なのでコンテンツスクリプト側に実装。
IFRAMEとの通信
このアドオンは、IFRAME内でマウスジェスチャを行った場合、その情報を親windowに伝えて、親window側で処理を行うという仕組みにしている。
これは、IFRAME内で「一番下にスクロール」を行った場合、IFRAME内をスクロールするのではなく親ウィンドウをスクロールするため。これは広告のIFRAME内でスクロールしてもうれしくないのでそれを防ぐための仕様。だが、逆に意図的に配置されている長い縦スクロールを持つIFRAME(例えばはてなブログの記事の編集ページ)に対しては使えないので一長一短の仕様である。広告が邪魔なケースの方が多いだろうと判断してこの仕様にした。
それで、この仕様を実現するためには親windowとIFRAME内のスクリプトが情報のやりとりを行う必要がある。
Cross-Origin Resource Policyがあるので直接やりとりすることはできない。IFRAME内でもコンテンツスクリプトを動作させ、window.postMessage()で親windowと情報をやりとりする必要がある。
IFRAME内からはwindow.parentで上位のフレームのwindowオブジェクトが得られる。最上位のウィンドウではwindow.parent === windowになるので、そうなるまで再帰的にさかのぼって最上位のウィンドウを探す。
受け取るときはwindow.addEventListener()でmessageイベントをハンドリングする。ここで受け取ったeventのsourceフィールドに送信元のwindowオブジェクトが入っている。
WEBページにもとからあるスクリプトもwindow.postMessage()を使用している可能性があるので、アドオン自身から送信されたメッセージかどうかを識別するために、送信するメッセージの中にアドオンのIDchrome.runtime.idを埋め込んでおく。
WEBページに関する処理なのでコンテンツスクリプト側に実装。
他のスクリプトによるstopImmediatePropagation()への対処
マウス関連のイベントを拾うため、個別のHTML Elementではなくwindowに対してaddEventListener()している。
その場合に、ページ内の要素上で他のスクリプト(WEBページの本来のスクリプトや他のアドオン)にイベントをstopImmediatePropagation()されると、自分のイベントハンドラまでイベントが来なくなる。
これに対処するため、addEventListener()の第二引数に{ capture: true }を指定。
captureの説明はhttps://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListenerにあるが、以下のほうがわかりやすい。
{ capture: true }を指定しないと、例えばgithubのtextareaタグ上でマウスジェスチャが動作しない。
解決できなかった問題
右クリック+ホイールでのタブ切り替えがスムーズに動かない場合がある
新しいタブで開くで複数のタブを開いた後、右クリック+ホイールでそれらのタブを連続で切り替えようとしても、一つ移動するたびにいったん操作を止めて、再度右クリック+ホイールをやり直さないと次のタブに切り替えられない。 あるいは、途中で反対方向にホイール回転させてからやり直すと次のタブに移動できる。
スクリプトの処理が重いせいかとも思ったが、最小限のシンプルな実装で実験しても結果は変わらなかった。
対処不可能なので放置。
IFRAMEをまたぐマウスジェスチャの完全なサポート
ほとんどのIFRAMEでは問題なくマウスジェスチャが動作する(IFRAME内からジェスチャを始めた場合、マウスの軌跡がIFRAME内にしか描画されないが、動きはする)。
しかし、他のスクリプトの影響次第では、動かなくはないが使いにくくなる。
例えば、特定のブラウザゲームのサイトでは、ゲーム画面上でマウスジェスチャを始めた場合、ゲーム画面の外側に出るとマウスジェスチャ機能が反応しなくなる(ゲーム画面内に戻ってそこでマウスの右ボタンを離せば動作させることは可能)。
通常、IFRAMEと親windowの両方にaddEventListener('mousemove')をしている場合、IFRAME内からマウスのドラッグを始めて外にでても、IFRAME内のイベントハンドラがmousemoveイベントを拾い続ける。
しかし、mousedownイベントをpreventDefault()しているCANVASタグがIFRAME内にある場合、そのCANVASから始めたドラッグは上記のようにならない。IFRAMEの外にでると親windowのイベントハンドラがイベントを拾うようになることがある。さらに他の条件が絡むとこうならないこともあるようだが、その条件は不明。
また、CANVASではなくDIVタグの場合はこの現象が起こらない。
これらの挙動を把握してIFRAMEの内外で通信してうまく処理すれば対処できそうではあるが、そこまでして対処する価値を感じないので放置。
なお、chromeのアドオンの話なので、上記はすべてchromeの場合での話。
Chrome Web Storeでの公開方法
以下を読んで実施。
最初に開発者アカウントの取得のために$5払う必要がある。
連絡用メールアドレスの登録も必要。登録したメールアドレスはWeb Storeで公開されるので普段使いのものとは別のものを使ったほうが良い。アドオンについての要望メールが届くこともあるが、「あなたのアドオンをもっと有名にしますよ」という胡散臭い詐欺っぽいメールも届く。
ストアページの説明文やスクリーンショットの登録、個人情報に関する宣言等も実施。
そこそこめんどくさかった。特に、手続き内容や何を入力しろと言われているのかを理解するところが。
人におすすめできるもの - ゲーム編
ブログ作成したときの趣旨から外れるけど、とりあえず何か更新するためにゲームの紹介をしてみる。
※有料のものも無料のものも含みます
Factorio
神ゲー。全人類やるべき。 機械やベルトコンベアを設置し、資源の採掘、アイテムの製造を行いテクノロジーを発展させ、ロケットを打ち上げるゲーム。 いかに効率よくものを配置して採掘から製造の流れを最適化するかが醍醐味。
Hades
ギリシャ神話世界を舞台にしたアクションローグライト。
ゲーム性、シナリオ、キャラクターの作りこみ、音楽、操作のストレスのなさ等あらゆる面で高水準。
Nintendo Switch版もある。
このゲームを取り扱っている以下の動画も良い。めちゃくちゃ楽しそうにギリシャ神話について語っていて、見ているこちらも楽しくなってくる。
Slay the Spire
カードゲーム型ローグライクといえばこれ。
グラフィックはインディーズゲームらしいクオリティだがゲーム性は抜群。
カードゲームとローグライクの組み合わせというアイデアが秀逸。
飢えた子羊
飢饉やら何やらで荒れていた時代の中国が舞台のノベルゲーム。
日本語音声のヒロインの声優に釘宮理恵が起用されたということで話題になっていた。
小さい女の子がいきなり刃物で襲い掛かってくる展開とか、侠客になりたかったけど乱世のせいで盗賊になるしかなくて落ちぶれたおっさんが再び立ち上がる話とか、強いけど不器用なおっさんを妙に利発なガキが手玉に取る関係性が好きな人とかは好きな人は買って後悔しないと思う。
残酷な描写があるので注意。
片道勇者
ローグライクと横スクロールの組み合わせというアイデアが秀逸。
有料版の片道勇者プラスもあり、steamで購入できる。
洞窟物語
フリーソフトなのに、かなりクオリティの高い2Dアクションゲーム。
アクションゲームとしてのゲーム性、シナリオ、キャラクターの作りこみがフリーソフトとは思えないクオリティ。
「Cave Story+」という名前でNintendo Switch版でも売られている。
Human Resource Machine
パズルゲームの皮をかぶった低レベルプログラミングゲーム(ここでいう低レベルというのは「ハードウェア側に近い」という意味)。
本職なら攻略サイトを見ずに全問余裕で溶けますよね?^^
私は解けませんでした。
ドラゴンクエストXI 過ぎ去りし時を求めて S
過去のドラゴンクエストシリーズの集大成的ゲーム。
過去作を知っている必要はないが、知っているとにやりとできたりシリーズ全体の関係性の考察がはかどる作りになっている。
ゲームシステムはいかにもドラクエという感じ。
RPGはめんどくさくなってやらなくなっていたが、ひさしぶりにコテコテのJRPGをやりたくなって評判がいい本作に手を出してみたら、期待以上に楽しめた。
MarkdownをブラウザでWebページっぽく表示するツールを作った
MDWikiを使っていたが、不満があったので似たようなものを自作した。
https://github.com/shining-corn/markdown-viewer-html
使い方
MarkdownファイルとWebサーバは事前に用意しておく。
- 上記リポジトリのdistフォルダにある
index.htmlとmdvh.jsを任意のWebサーバに置く - MarkdownファイルもWebサーバに置く
- ブラウザで
index.html?mdpath={Markdownファイル}を開く
クエリーパラメータmdpathを指定しなかった場合はデフォルトで、同じディレクトリにあるindex.mdを表示する。
動作例
https://shining-corn.github.io/markdown-viewer-html/?mdpath=./index.md
なぜ作ったか
MDWikiの以下の点に不満があったから。
- Markdownの解釈が普段使っているほかのツールと少し違う
- 例えばVSCodeのプレビューと細かいところでずれがある
- gimmicksの書式が独特なので、mermaidで書いたUML図をVSCodeでプレビューできない
作り方
ほぼnpmで公開されているライブラリを利用するだけで済んだ。
MarkdownからHTMLへの変換はmarkdown-itがすべてやってくれる。
markdown-itのプラグインもgithubに公開されているので、Markdownの拡張書式も追加できる。以下のプラグインを取り込んだ。
| 機能 | プラグイン |
|---|---|
| UML図 | GitHub - iamcco/md-it-mermaid: markdown-it plugin for mermaid |
| 注釈 | GitHub - markdown-it/markdown-it-footnote: Footnotes plugin for markdown-it markdown parser |
| 目次 | markdown-it-table-of-contents - npm |
| BootstrapのAlerts | GitHub - nunof07/markdown-it-alerts: Markdown-it plugin to create Bootstrap alerts (readmeには明記されていないが、BootstrapのAlertsのうち success、info、warning、dangerしか使えないようである。) |
| 数式 | GitHub - runarberg/markdown-it-math: Markdown-it plugin to include math in your document |
| 動画埋め込み | markdown-it-block-embed - npm |
スタイルシートは、githubと同じものがMITライセンスで公開されていたので利用させてもらった。
以下の部分は自分で作る必要があった。
- 他ファイルへのリンクの書き換え
- クエリーパラメータで指定されたMarkdownファイルの読み込み
- ちなみに最初は
mdpathではなくpという名前にしていたが、一部のWebサーバは独自にクエリーパラメータをサポートしている場合があり、それとパラメータ名が重複してしまった結果、ファイル読み込みが常に404 Not Foundエラーになってしまった。
- ちなみに最初は
- ハッシュつきURLで開かれた場合の画面スクロール
- htmlがブラウザにロードされた後でMarkdownファイルを読み込んで変換とレンダリングをしているので、タイミングの関係上、ハッシュへの移動はブラウザ任せにできない。レンダリングが終わったあとでwindow.scroll()する必要がある。
- その他細かい処理
M5Stackで赤外線リモコン
赤外線リモコンの信号を受信してダンプするプログラムと、それを送信するプログラムを作成した。
結論から言うとプログラムは動作したが、M5GO IoTスターターキットに入っていた赤外線送受信ユニットは射程が2mほどしかなくて、エアコンや照明の制御には使えなかった。
目次
- 赤外線リモコンの信号を受信
- 送信
- その他参考