風柳メモ

ソフトウェア・プログラミング関連の覚書が中心

Twitter(X)関連拡張機能の開発中止と公開停止について/Discontinuation of Development and Publication of Twitter(X)-related Extensions

2024/02/15追記 / Added on February 15, 2024

Edge アドオンやChrome ウェブストアで「X メディアダウンローダ」といった名前で配布されているアドオンや拡張機能が存在するようです。
どうやら中身は自分がかつて配布していたものとほぼ同じもののようですが、当然ながら自分はこれらの配布にはまったく関わっておりませんので、ご留意願います。
なお、オリジナルはオープンソースソフトウェア(MIT License)として配布していたものですので、流用を止めることはできません。
It seems that there are add-ons and extensions available on the Edge Add-ons and Chrome Web Store named "X Media Downloader" that closely resemble something I once distributed.
However, I must clarify that I am in no way involved in the distribution of these current versions. Please be aware of this.
Additionally, the original was distributed as open-source software under the MIT License, so I have no means to prevent its reuse.

2023/09/26追記 / Added on September 26, 2023

Twitter(X)関連の拡張機能等の開発に関するメールやDM等での個別のご相談(開発継続・リポジトリ公開・買い取り等のご要望、他)には応じかねますので、ご了承願います。
Please note that I cannot accommodate individual inquiries via email or DM etc regarding the development of extensions related to Twitter(X), including requests for continued development, repository publication, or acquisition. I appreciate your understanding.


2023/09/16追記 / Added on September 16, 2023

拙作Twitter(X)関連のブラウザ拡張機能(ユーザースクリプト含む)を、各ストアおよびGitHubリポジトリにて非公開にしました。
My Twitter(X)-related browser extensions (including userscripts) are now private on the respective stores and GitHub repository.


残念なお知らせUnfortunate Announcement

諸般の事情により

をはじめとした、拙作Twitter(X)関連のブラウザ拡張機能(ユーザースクリプト含む)の開発および公開を中止致します。

各ストアやGitHubリポジトリ等は2023年9月16日を目処に順次非公開(配信停止)とする予定です。

ご愛顧ありがとうございました。

Due to various circumstances, I will be discontinuing the development and release of my Twitter(X)-related browser extensions, including:

I plan to gradually make them unavailable (stop distribution) on stores and GitHub repositories around September 16th, 2023.

Thank you for your patronage!

ひとりごと

2014年に近傍ツイート検索を作成して以来、断続的とはいえ9年以上に渡って続けてきたTwitter(X)系のブラウザ拡張機能の開発を中止とするというのは自分でも大変残念ではありますが……まぁいろいろな意味で無理になってきたので、潮時かなと。

……察して頂けると幸いです。

「有料でもいいから」というお気持ちはわかるのですが……


正規のAPIはこちらのページによると、

コース Basic Pro
月額 100ドル 5000ドル
取得ツイート数上限 1万 100万

これは1プロジェクトあたりにかかる制限なので、ユーザー毎に煩雑なプロジェクトの設定と、料金の(X社への)支払いが発生してしまうことになります。
しかし…Basicの月1万ツイートなんて、拡張機能のヘビーユーザーだった方なら確実に足りなくなる分量ですよねぇ……。
で、そこまでしても

  • 正規のAPIではWeb版やアプリでは使用できる機能が使えないことが往々にしてあるため、拡張機能のために必要な情報が取得できない可能性がある
  • サードパーティ製のTwitterクライアントが否定されたように、そもそも不特定多数のエンドユーザーが使用するような使い方はおそらくもはや想定されていない(開発者規約上も、拙作拡張機能のようなものは認められそうにない)

などなど、どうしても無理があるのですよね……。

AES-GCMでの暗号化/復号の例(JavaScript(Web Crypto API)←→Python(PyCryptodome)相互変換可)

JavaScript(Web Crypto API)で記述されたAES-GCMを用いた暗号化/復号処理をPython(PyCryptodome)にデータ互換性をもたせながら移植しようとしたところ、いくつかハマりどころがあったのでメモしておく。




ハマりどころ

Pythonに入れたPyCryptodomeが動作しない!?

Windows 10 Pro上にインストールしてあるPython 3.11に普通に

$ pip install pycryptodome

で入れているのに、

from Crypto.Cipher import AES

とかしても

ModuleNotFoundError: No module named 'Crypto'

となってしまう現象に悩まされてしまった。

結論としては、PyCryptodomeが入ったフォルダ名が

C:\Python311\Lib\site-packages\crypto

になっていたという……これを手動でcrypto→Cryptoに変更したら、無事に動くようになった。
どうも、ときどき発生する現象である模様……以前に入れたり削除したりしたモジュールの中に小文字でフォルダを作ったものがあったからか?

MAC tagはどこ?

PyCryptodomeではcipher.encrypt_and_digest()で暗号化したときの戻り値としてciphertextの他にMAC tagが存在する
ところが、JavaScriptのcrypto.subtle.encrypt()では、戻り値はciphertext(を含むArrayBuffer)のみで、MAC tagが見当たらない。
でも、AesGcmParamsではtagLengthを指定できる(未指定の場合は128ビット)ので、MAC tagの作成自体はしているはず……(実際、得られたciphertextをそのままMAC Tagを指定しないでdecryptしようとしてもうまくいかない)。

いろいろと調べてみた結果、crypto.subtle.encrypt()の戻り値の最終16オクテット(tagLength(128)ビット)がMAC tagに相当し、正味のciphertextはこれを除いたものであるらしい
PyCryptodomeでcipher.decrypt_and_digest()にわたす際にはこの点を留意する必要がある。

nonceはどこ?

PyCryptodomeだと、AES-GCMの場合にはAES.new()でnonceパラメータを指定する必要があるが、JavaScriptのコードを一見したところ、nonceが見当たらない。
どうも、JavaScriptのcrypto.subtle.encrypt()の第1引数(AesGcmParams)にある「iv」というパラメータ(初期化ベクトル(IV=Initialization Vector))が、nonceに相当するらしい。
AES.new()ではivとnonceは別パラメータとして存在し、MODEによってどちらを設定するか決まっている模様(MODE_GCMではnonceを設定)

additionalDataってどう扱えば?

JavaScriptのcrypto.subtle.encrypt()の第1引数(AesGcmParams)にはadditionalDataというパラメータがあるが、これはPyCryptodomeでどう扱えばよいのか?
そもそもadditionalDataは、それ自体は暗号化されないAAD(additional authenticated data、追加認証データ)であるらしい。
こちらも調べてみると、どうやらcipher.update()で指定すればよいらしいことが判明。

その他

今回調査した実装だけの話だけれど、cipher.decrypt_and_verify()を呼び出した際に、"ValueError: MAC check failed"が出たり出なかったり不安定という謎の現象が発生。
かなり悩んだけれど……実はpasswordを複数の候補からタイムスタンプを元に選択するような仕組みになっており、かつ、一連のシーケンス中で得られるデータ中に微妙に異なるタイムスタンプが複数箇所にあるけれど(仕様書もないために)どれを使えばよいのか不明で、間違ったものを使うと誤ったpasswordを選択してしまうことがある(たまたま一致していて通ることもある)というややこしい状況だった(その後、正しいものを特定するのにもかなり時間を要した……仕様書は大事)。

実装例

JavaScriptとPythonの具体的な実装例を掲載しておく。
それぞれで定義しているaes_gcm_encrypt()で暗号化したデータは、お互いのaes_gcm_decrypt()でも復号することが可能となっている(はず)。

JavaScript(Web Crypto API)用

関数仕様

ソースコード

Python(PyCryptodome)用

関数仕様

ソースコード

Surface Book 2は4K・60Hz・10ビット・HDRの夢を見るか?

PCを買い替えるような余裕が無いのもあって、いまだに2019年10月に購入したSurface Book 2 (15")をメインマシンとして愛用しているわけなんですが。
自宅ではいただきものの27インチ4Kモニタ(Dell U2720QM)に接続しているのですけれど、実はこれまでその性能を活かしきれていなかった……という衝撃の事実が発覚しました。

試行錯誤した結果、(限定的な条件ですが)Surface Book 2でも、4Kモニタに60Hz・色深度10ビット・HDR(High Dynamic Range)で出力可能、ということがわかり、現在は安定して使えております。

Surface Book 2を4Kモニタに60Hz・色深度10ビット・HDRで接続した状態

いまさらという話ですけれど、備忘のために記録しておきます。




結論

Surface Book 2から4Kモニタへの、60Hz・色深度10ビット・HDRでの出力は、

  • 本体のUSB-C端子から、DP Alt Mode(DisplayPort over alternate mode)対応のケーブル(DP1.4以上対応なら安心)でモニタのUSB-CもしくはDP端子に接続
  • その他の機器も接続したい場合、Surface Dock 2を使う(Surface Dock(無印)の方では、繋ぐだけで、本体側USB-C端子のDP Alt Modeが使えなくなってしまうので不可)
  • Surface Dock 2背面のUSB-C端子(ビデオディスプレイ対応)には、モニタを接続しないこと(接続してしまうと、モニタの方で入力信号として選択しなくても、本体側USB-C端子からモニタに出力されなくなる模様)

という条件でならば可能です。
当然ながらモニタやケーブルの方もそれぞれの規格に対応している必要があります
自分はWindows 10 Pro環境で下記のような機器で試しましたが、環境や設定が違うなどの要因で、実はDock/Dock2からでもできるよといった情報があれば、ご教示ください

経緯

最近になって、Surface Dockに直接接続しているものの動作が不安定(特にイーサネットが突然落ちてしまい、再起動するまで繋がらなくなる不具合発生)なため、やむを得ずSurface Dock 2を購入して入れ替えました

その際、Surface Dock 2のUSB-C端子(DP Alt Mode対応)からモニタに繋いだら30Hzでしか繋がらないから絶望しかけたけど、色々と試しているといつの間にか60Hzで繋がるようになった……とツイートしたのですが、


ここでとあるリプライを受けたのが調査するきっかけとなりました。

具体的には、モニタ(Dell U2720QM)の方はリフレッシュレート:60Hz/色深度(ビット深度):10ビット(10.7億色)/色空間:HDR 400に対応しているのに、8ビット/SDRになっているね、というご指摘でした。

せっかくモニタが対応しているのにそのモードで利用していないのはもったいないので、利用可能な条件を探してみた次第です。

試行

使用機器類

試行の際に使用した機器類は以下のようなものです。

略称 機器
PC Surface Book 2
モニタ Dell U2720QM
Dock Microsoft Surface Dock
Dock2 Microsoft Surface Dock 2
USB-Cケーブル モニタ付属のUSB Type-C(CーC)ケーブル
HDMIケーブル モニタ付属のHDMIーHDMIケーブル
DPケーブル iVANKY Mini DisplayPortーDisplayPortケーブル
DP変換ケーブル Silkland USB Type-CーDisplayPort 変換ケーブル
HDMIアダプタ・SANWA SUPPLY サンワサプライ Mini DisplayPortーHDMI 変換アダプタ
HDMIアダプタ・Dockteck Dockteck USB Type-CーHDMI アダプタ
HDMIアダプタ・Freesun Freesun Steam Deck(Nintendo Switch対応ドック・USB Type-CーHDMI変換機能を含む)
試行前の注意点

Dell U2720QMの場合、モニタ側の設定でディスプレイ>Smart HDRを「オフ」(初期値)以外にしておかないと、HDRが有効になってくれないようです。

また、ディスプレイ キャッシュをクリアするためのレジストリファイルを予めダウンロードしておき、接続方法を変更する際には(特にSurface Dock(無印)で試す場合や試した後には)随時クリアするようにしたほうがよいと思われます(クリアしないでやると、ときどき問題ないはずの条件でうまくいかない場合があるようです)。

試行結果
PC側端子 モニタ側 4K表示 60Hz 10ビット HDR 備考
本体USB-C(USB-Cケーブル) USB-C [^1][^2]
本体USB-C(DP変換ケーブル) DP [^1]
本体USB-C(HDMIアダプタ・DockteckーHDMIケーブル) HDMI × × [^1][^3]
本体USB-C(HDMIアダプタ・FreesunーHDMIケーブル) HDMI × × × [^1]
Dock Mini DP(DPケーブル) DP × ×
Dock Mini DP(HDMIアダプタ・SANWA SUPPLYーHDMIケーブル) HDMI × ×
Dock2 USB-C(DP)(USB-Cケーブル) USB-C × [^2][^3]
Dock2 USB-C(DP)(DP変換ケーブル) DP × [^3]
Dock2 USB-C(DP)(HDMIアダプタ・DockteckーHDMIケーブル) HDMI × × × × [^4]
Dock2 USB-C(DP)(HDMIアダプタ・FreesunーHDMIケーブル) HDMI × × ×

[^1] Surface Dock接続時や、Surface Dock 2接続時でかつ裏面USB-Cポート(ビデオディスプレイ対応)にモニタを接続した場合には(モニタ側で入力信号として選ぶ/選ばないにかかわらず)、本体USB-Cからの映像出力は無効化されてしまう
[^2] USBとしては2.0の機能しか使えなくなる(=モニタ側のUSBハブとしての機能も実質使えなくなってしまう・ただしPower Delivery機能の方はどうなるかは未検証)
[^3] HDR使用時、色深度が「ディザリング使用時、8ビット」となってしまう
[^4] 本体側は認識しているが、モニタ側で「接続されていません」となってしまい、画面が表示できない

結果として、実質「本体側のUSB-C端子にモニタを接続する」しか選択肢がありませんでした。
本当はSurface Dock 2の背面USB-Cで使いたかったのですが、どうやっても色深度を10ビットにする方法がわからず、断念しました

また、モニタのUSB-C端子につなげてしまうと、USBとしての機能は2.0に制限されてしまうので、USB-CーDisplayPort 変換ケーブルを用いてDisplayPort端子の方に繋げるようにしています。
別途、Surface Dock 2の前面USB-C端子(ビデオディスプレイに対応していない方)をモニタのUSB-C端子に繋ぐことにより、モニタのUSBハブとしての機能も確保しています。
なお、背面USB-C端子に繋いでしまうと、本体USB-C側のDP Alt Modeが使えなくなってしまってハマります……
ちなみにこの構成だとモニタのUSB Power Delivery機能は活かすことはできませんが、まぁ問題ないでしょう……

付録

Surface Book 2|3・Surface Dock・Surface Dock 2のUSB-C(DisplayPort over alternate mode)/Mini DisplayPort仕様
機器 DPバージョン 伝送速度(名称) 伝送速度 DSC(圧縮) モニターx1 モニターx2
Surface Book 2 1.2 HBR2 17.28 Gbps - 4096x2304@60Hz 4096x2304@30Hz
2560x1600@60Hz
Surface Book 3 1.4a HBR3 25.92 Gbps 1.2 4096x2304@120Hz 4096x2304@60Hz
Surface Dock 1.2 HBR2 17.28 Gbps - 4096x2304@60Hz 4096x2304@30Hz
2560x1600@60Hz
Surface Dock 2 1.4a HBR3 25.92 Gbps 1.2 7680x4320@30Hz
3840x2160@120Hz
3840x2160@60Hz

当然ながら、BookとDockとを組み合わせて使う場合、低い方の性能に合わされてしまうことになります。
いろいろなページを参考にまとめましたが、推測で書いているところもあるため、不正確な情報があるかもしれません。
また、公式ページにおいては色深度10ビット対応やHDR対応等の情報は見つけられず、Surface Connect端子に関する仕様も見当たらないという……なんともユーザーに対して不親切だと思うのは自分だけですかね……

DPの伝送速度の規格そのものはUSB-Cのもの(3.0/3.1 Gen1/3.2 Gen1x1は5Gbps・3.1 Gen2/3.2 Gen2x1は10Gbps等)とは別物ですが、同じ信号線(SuperSpeed信号線)を利用しているため、無関係というわけではありません

たとえばDP1.2ではHBR2(最大17.28Gbps)まで使えますが、これは4レーン(SuperSpeed信号線4本)全てを使った場合であり、USB 3.1 Gen1用にSuperSpeed信号線2本を確保する場合には2レーンしか使えず伝送速度は半分となるため、4K表示だと30Hzまでしか使えなくなることになります。
逆に、4K・60Hz・色深度10ビットだと15.68Gbps必要となるため、4レーン全てが必要となり、USB 3.1用にSuperSpeed線が確保できない結果、USBの機能としては2.0までしか使えない、ということになります。

ちなみにSurface Book 3はDP1.4aで4K・120Hzにも対応となっていますが、色深度10ビットにすると32.27Gbps必要となるため、HBR3(25.92 Gbps)だと足りなくなってしまいますね。実際はどうなっているのでしょうね?
色深度10ビットは不可だったりするのか、それともDSC(Display Stream Compression)で対応しているのか……Surface Book 3をお持ちの方、情報をお待ちしております(笑)→ここを見る限り、Windows 11で4K・120Hz・10ビット・HDRで表示できているようですね(DSCが使われているかはわかりませんが)

セルの右横にユーザーフォームを出したかっただけなのに……

軽い気持ちというかほとんどネタでVBAのユーザーフォームを用いたなんちゃってモダンなDatePickerを作ってみたのですが、その際に「セルの右横にユーザーフォームを表示する」という一見簡単そうなことが一筋縄ではいきませんでした。

試行錯誤の結果、ひとまずは実用にできそうな手法がわかったので、備忘として記事にしておきます。

セルの右横にユーザーフォームを表示したかっただけなのに……




せっかちな方へ

「能書きはいいから具体例を出せ」という向きは、

[Excel][VBA] ユーザーフォームをアクティブセルの右横に表示する実装例 · GitHub

こちらに実装例(マクロ有効ワークシート(*.xlsm))とソースコードを置いてあるので、ご自分で読み解いてください。

ちなみにこれを利用して作ったDatePicker(カレンダー)はこちら。

[Excel][VBA] Excel用DatePicker · GitHub

前提知識

  • エクセルVBAでは、オブジェクト(Window、Range、UserForm等)の位置や大きさは、基本的に「ポイント」という単位で管理されている(Top/Left/Width/Height等のプロパティの数値は全てポイント単位)
  • 位置を表す座標系には、大きく分けて、画面*1の左上を原点とする「画面座標系」(WindowオブジェクトやUserFormオブジェクト等はこちらで考える)と、ワークシートの左上*2を原点とする「ドキュメント座標系」(Rangeオブジェクト等はこちらで考える)とが存在する*3
  • 「画面座標系」と「ドキュメント座標系」とでは、同じ1ポイントであっても、画面上における大きさは異なる場合がある(例えばウィンドウの拡大率などに左右される)
  • ポイントとピクセル(ドット・画素)との比率も、環境によって異なる場合がある(画面解像度や拡大率に左右される)*4

アクティブセルの右側にユーザーフォームを表示したいときの座標計算方法の具体例

ユーザーフォームをアクティブセルの右側に表示する場合の座標の求め方

アクティブウィンドウ上にあるアクティブなセルのすぐ右側にユーザーフォームを表示する際の、ユーザーフォームに指定する座標(Top/Leftプロパティ)の値(ポイント)の具体的な求め方を記します。

なお、ここでは例として、

画面 横3840ピクセル✕縦2160ピクセル(4K)・拡大率150%
アクティブウィンドウ Top:84.0・Left:221.5・Width:1379.0・Height:822.0・拡大率200%
ウィンドウ枠の固定 有り(B3の位置)
アクティブセル アドレス:BR118・Top:2106.0・Left:3726.0・Width:54.0・Height:18.0

のようになっているものとします。

アクティブセルの位置を画面座標系に変換

アクティブセルのプロパティ(Top/Left)は、ドキュメント座標系上のポイント単位の数値です。
ひとまずこれを、画面座標系へと変換します。

これには、ペイン(Pane)オブジェクトのPointsToScreenPixelsY()PointsToScreenPixelsX()メソッドを使用します。

このとき注意するのが、アクティブセルが属しているPaneオブジェクトを指定する必要があることです。
ウィンドウ枠の固定をしている場合、ActiveWindow.Panes.Countは最大4まで存在するため、アクティブセルがPanes(1)~Panes(4)のいずれの下にあるかを調べる必要があります。
もっとも、アクティブセルが前提なので、この場合は、PaneオブジェクトとしてActiveWindow.ActivePaneオブジェクトを指定するのが簡単でしょう。

これで、Top: 2106.0ポイント→1003ピクセル、Left: 3726.0ポイント→1399ピクセルのように、アクティブセルの左上の、画面座標上の位置をピクセル単位で求めることができます。

画面座標系上の位置をピクセル単位からポイント単位に変換

求まった値はピクセル単位ですが、ユーザーフォームのプロパティ(Top/Left)に設定しようと思うと、ポイント単位への変換が必要になります。

画面座標系におけるピクセル→ポイントの変換方法として、自分は、ActiveWindowのHeight・Widthプロパティ(ポイント単位)と、WinAPIであるGetWindowRect()により得られるActiveWindowの座標(Top/Bottom/Left/Right・ピクセル単位)から求まる高さ・幅との比率を求めて使う、という方法を思いつきました。
もっと簡便な方法があればご教示願います。

これにより、上記の例では1ポイント=2.0ピクセルと出ましたので、Top:1003ピクセル→501.5ポイント、Left:1399ピクセル→699.5ポイントのように、アクティブセルの左上の、画面座標上の位置をポイント単位に変換できました。

セル幅を画面座標上のポイント単位に変換

セルの「右」に表示するので、横方向の座標にはセル幅(Widthプロパティ)分を加える必要があります。

Widthプロパティはポイント単位なので、これを足せばいいのか……と思いきや、ドキュメント座標上のポイントと画面座標上のポイントでは実サイズが異なってきます。
具体的には、ウィンドウの拡大率に左右されます。
アクティブウィンドウの拡大率は、ActiveWindow.Zoom÷100で求まり、上記の例(200%)だと2.0となります。

よって、ドキュメント座標上のWidth:54.0ポイントは、画面座標上では108.0ポイントとなります。

ユーザーフォームのプロパティを設定

以上により、ユーザーフォームの設定すべき画面座標上の位置は計算上(ポイント値で)Top:501.5、Left:699.5+108.0=807.5となります。
あとは、ユーザーフォームのStartUpPositionプロパティを0(Manual)にして、TopとLeftプロパティに値を設定すればいいわけですが……さらにいくつかハマりどころがあるのが困ったところですね。

ハマりどころ

第3の座標系が存在!?(ユーザーフォームの位置が想定よりも右下にずれていく問題)

環境によっては(画面解像度や拡大率、マルチモニタ等が影響?)上記のようにして計算した値をユーザーフォームのプロパティにセットしても、想定位置からずれてしまう場合があります。

計算値と実際の表示位置がずれる

しかも、画面の右下に行くに連れてズレも広がっていくようです。

この現象に最初に遭遇したときにいろいろと試してみたところ、上記の計算値に一定の係数(試したケースでは14/15=0.93…)を掛けたものをTop/Leftプロパティに設定すると、想定位置に表示されることがわかりました。
いわば、画面座標系と原点は共通ですが、目盛(1ポイント当たりの大きさ)の大きい座標系(ユーザーフォーム座標系?)が存在するようなイメージです。

この係数は環境により異なってくるため、定数にすることはできません。
そこで、

  1. GetWindowRect()でユーザーフォームのピクセル単位での座標を取得し、これから高さと幅を求める(実測値)
  2. ユーザーフォームのHeight/Widthプロパティに、ActiveWindowから求めたピクセル/ポイント比をかけて、ピクセル単位の高さと幅を求める(想定値)

のように二種の方法で高さと幅を求め、想定値と実測値の比を割り出し、これを係数として使用することで、対応することにしました。

とりあえず、この補正を行うことで、状況は改善されたようです。

計算値と実際の表示位置のズレを補正
画面の右の方にいくと、突然ユーザーフォームが左側にずれるようになる

環境によっては(おそらくマルチモニタ環境でかつ特定の解像度や拡大率の場合に)、画面の左側だと問題なく表示されているのに、あるところから突然ユーザーフォームが想定位置よりも左に大きくずれ始める、という現象が発生することがあります。

画面の右の方でいきなりずれだす

調べてみると、Pane.PointsToScreenPixelsX()が返す値が、ある列より右側では明らかにおかしくなっていました

PoinstsToScreenPixelsXテスト(4K・150%)

しばらく原因がわからず途方にくれていたのですが、その後、たまたま気がついたエクセルの設定を変更することで改善されることがわかりました。

ファイル>オプション>設定>全般>ユーザー インターフェイスのオプション>複数ディスプレイを使用する場合
で、

◉ 表示を優先した最適化 (アプリケーションの再起動が必要)

にしていると発生することがあるようで、試しに

◉ 互換性に対応した最適化

に変更(これもエクセルの再起動は必要)すると、

全般>複数ディスプレイを使用する場合は「互換性に対応した最適化」を選択

正常動作するようになったようです。

PoinstsToScreenPixelsXテスト(4K・150%)・「互換性に対応した最適化」設定後
その他注意点・制限事項など

処理を簡便化するモジュール

上記の処理の一部を簡便化するためのプロシージャ群を標準モジュールとしてまとめてあります

ConvertToScreenPosition()
Type ScreenPosition
    x As Double
    y As Double
End Type

Function ConvertToScreenPosition(TargetTop As Double, TargetLeft As Double, Optional TargetWindow As Window) As ScreenPosition

ドキュメント座標系の座標(TargetTop/TargetLeft・ポイント)を、画面座標上の座標(ピクセル単位)に変換して返します(変換不可な場合にはx=0・y=0が返ります)。
TargetWindowで対象となるWindowオブジェクトを指定可能です(省略時はActiveWindowになります)。
例えば対象となるセルのTop/Leftを指定するだけでよく、Panesのどれに属しているかは意識しなくても済むようにひと工夫してあります。

GetDisplayDotsPerPoint()
Type DotsPerPoint
    x As Double
    y As Double
End Type

Function GetDisplayDotsPerPoint(Optional TargetWindow As Window) As DotsPerPoint

画面座標系上の1ポイントあたりのドット(ピクセル)数を返します。
TargetWindowで対象となるWindowオブジェクトを指定可能です(省略時はActiveWindowになります)。

SetUserFormPosition()
Type CoordinateFactor
    x As Double
    y As Double
End Type

Function SetUserFormPosition(TargetForm, Top As Double, Left As Double, Optional Calibration As Boolean = True) As CoordinateFactor

TargetFormで指定したユーザーフォームを、画面座標系上の指定位置(Top/Left・ポイント)に移動します(このプロシージャでは表示は行わないことに注意してください。別途、TargetForm.Showプロシージャで表示する必要があります)。
このとき、位置ずれ補正(画面の右下に行くほどにずれる現象に対する補正)も自動で行います(Calibration:=Falseで補正を無効化することもできます)。
戻り値として、適用した補正係数を返します(Calibration:=False時はx=1・y=1が返ります)。

具体的な使用方法は、実装例を参照してください

ひとりごと

ユーザーフォームってあまり使った経験がないのですけれど、まさかセルの右横にユーザーフォームを表示するだけでこんなに苦労することになろうとは思いもよりませんでした……。
よりよい方法があれば、ご教示願います。


*1:マルチモニタ環境における「画面」は、すべての有効なモニタ画面を包括するような仮想的な矩形となると思われる

*2:セルの設定で非表示になっているものは含まないため、必ずしもA1ではないことに注意

*3:座標系の名前は便宜上のもので、自分のソースコード内では「ディスプレイ座標系」「ワークシート座標系」などと書いてある場合もある(統一が取れていなくてすみません……)

*4:ネットではDPI(Dots Per Inch)を96として決め打ちしている実装をよくみかけるが、あまり望ましくないと考えられる(ポイント(DTPポイント)の方は1インチあたり72ポイントがもともとの定義。なお、これもPoints Per Inchを略してPPIと書いてしまうと、Pixels Per Inchと混同してしまうため(こちらがより一般的なPPI)混乱の元なので避けたほうがよさそう)

私のSurface Book 2が不安定なのはどう考えてもグラフィック・ドライバーが悪い!?

Surface Book 2をメインPCとして愛用しているのですが作業中に突然ディスプレイがブラックアウトして、ひどいときにはそのまま復帰せずに手の施しようがなくなる……という現象に悩まされてきました(なんどかブルースクリーンにもなった覚えがあります)。

その際に調べたところでは、「デスクトップ ウィンドウ マネージャー(dwm.exe)」がメモリを数GB~数十GB程も占有している、という状況でした(通常は数十MB程度のはず)。

どうやらこれは、Surface Book 2(自分のは15")のIntel(R) UHD Graphics 620用のドライバーが原因だったようです

「それなら、Intel® Graphics – Windows* DCH Driversを更新すればよいんでしょ?」となるわけですが……(少なくとも自分のところでは)一筋縄ではいかなかったので、試行錯誤の内容を備忘録として記しておきます。




せっかちな人向けの手順

デスクトップ ウィンドウ マネージャー(dwm.exe)のメモリリーク対策として、Surface Book 2のIntel® Graphics – Windows* DCH Driversを更新する手順を示す。
自分のところは「Surface Book 2 15"(8th Gen Intel® Core™ i7-8650U クアッドコア プロセッサ, 4.2GHz Max Turbo)」なので、ドライバー名等は自身の環境にあわせて適宜読み替えのこと

  1. デバイスマネージャーを起動して、
    ディスプレイ アダプター>Intel(R) UHD Graphics 620のプロパティ>ドライバー
    を確認。
    これのバージョンが「30.0.101.1191」以降(例:「30.0.101.1339」)に既になっている場合、対策済みのはず
  2. 上記よりも前のバージョンになっている場合(自分のところでは「27.20.100.8682」「26.20.100.8141」が存在)、同じくデバイスマネージャーから、
    ディスプレイアダプター>Intel(R) UHD Graphics 620
    の「デバイスのアンインストール」(「☑ このデバイスのドライバーソフトェアを削除します」にチェックの上で)を実施(必要に応じて再起動)し、
    ディスプレイアダプター>Intel(R) UHD Graphics 620
    が存在しなくなるまで繰り返す
    自分のところだとディスプレイアダプター下には「NVDIC GeForce GTX 1060」のみが残った
  3. MicrosoftのSurface 用のドライバーとファームウェアをダウンロードするページより、Surface のドライバーとファームウェアの手動更新から「Surface デバイス モデルを選択する」で自分のモデルにあったリンクに遷移した上で(Surface Book 2の場合はこちら)最新のドライバーとファームウェアをダウンロードの上、実行してインストールを実施
    Surface Book 2の場合、ダウンロードされたのは「SurfaceBook2_Win10_19041_22.080.2839.0.msi」だった(2022/10/11現在)
  4. 再起動後、Intel(R) UHD Graphics 620のドライバーのバージョンが「30.0.101.1339」(もしくは「30.0.101.1191」以降)になっていることを確認

不具合(dwm.exeのメモリリーク)の原因

www.intel.co.jp
に書かれている通り、デスクトップ ウィンドウ マネージャー(dwm.exe)がいつの間にか理不尽なほどにメモリを占有してしまう不具合は、Intel製ドライバーに起因するメモリリークが原因だった模様。
対象となるドライバー(Intel® Graphics – Windows* DCH Drivers)は、

  • 「27.20.100.8587」以降で不具合発生
  • 「30.0.101.1191」以降であれば対策済み

とのこと。

試行錯誤

とくになにもせずとも通常のWindows Updateのみでいつのまにか「30.0.101.1339」に更新された……というケースもあるようなので(Surfaceかどうかは不明)、あくまで参考まで……。
自分の場合、過去にも試行錯誤していたため、その際に余分なことをしてしまった可能性も大いにある

ドライバーのバージョンを確認してみる

自分の環境で確認してみると、「Intel(R) UHD Graphics 620」のドライバーは

  • 日付:2020/09/06
  • バージョン: 27.20.100.8682

となっており、見事に不具合発生するバージョンであった。
これは……なんとかしてバージョンアップをしなければ……!
なお、試しにデバイスマネージャーの「ドライバーの更新(P)」を行ってみたところ……バージョン「26.20.100.8141」(日付: 2020/04/11)になってしまった……待って……なんで下がるの……(その後、「ドライバーを元に戻す(R)」でとりあえず「27.20.100.8682」に戻しておいた)

Intel公式ページよりダウンロードしたドライバーはインストール不可

最初は単純に「Intel公式ページから最新のをダウンロードしてインストールすればいいんでしょ?」と思ったが、実際にやってみると「お使いのシステムには製造元の仕様にロックされたドライバーがあります」なる無慈悲なメッセージが表示されてしまい、インストールできない。
なお、そのあたりを配慮して更新してくれそうな「Automatic Driver and Software Updates」なるものもあるが、自分の環境だとインストールはできたものの、その後のダウンロードができない(インジケータが20数パーセントくらいまで進むと0になるを繰り返す→そのうちダウンロードがキャンセルされる)現象が発生し、うまくいかなかった

ドライバー/ファームウェアの最新版を入れてみたが……

Surface Book 2 更新履歴を見てみると、「2022 年 6 月の更新プログラム(6 月 17 日リリース)」のところに、

Windows Update の名前 デバイス マネージャー
Surface - システム – 6.134.139.0 Surface Integration Service Device – システム デバイス
Intel Corporation - ディスプレイ – 30.0.101.1339 Intel(R) UHD Graphics 620 (15") – ディスプレイ アダプター
Intel Corporation - ディスプレイ – 30.0.101.1339 Intel(R) HD Graphics 620 (13") – ディスプレイ アダプター
Surface Book 2 更新履歴 - Microsoft サポート

という記述が……! これこそ自分が求めていたものではあるまいかっ!

喜び勇んでダウンロードセンターから最新版(SurfaceBook2_Win10_19041_22.080.2839.0.msi(Date Published:8/26/2022))をダウンロードし、インストール&再起動したところ……ドライバーのバージョンは「27.20.100.8682」のままだった……いや、なんでよ……?

ドライバーはアンインストールした上でのクリーンインストールが必要だった……!

なんどか入れ直したり再起動したりを繰り返すも、状況は変わらず。
さすがに諦めかけた頃に、もう一度このページを見直してみたところ、解決方法のところにしっかりと

dwm.exe の漏洩の修正プログラムを含むドライバー 30.0.101.1191 をインストールする前に、 ドライバーのクリーン・インストール を実行する必要があります。

dwm.exe (デスクトップ PC ウィンドウマネージャー) は、27.20.100.8587...

と書かれていることに気づく。

ダメ元だと、

  1. 念のため、インストールしてあったSurface Book 2 のドライバー/ファームウェア(Surface Book 2 Update 22.080.2839.0 (64 bit))をアンインストール
  2. デバイスマネージャーから、
    ディスプレイアダプター>Intel(R) UHD Graphics 620
    の「デバイスのアンインストール」を、
    ☑ このデバイスのドライバーソフトェアを削除します
    にチェックした状態で実施(必要に応じて再起動)
    ディスプレイアダプター>Intel(R) UHD Graphics 620の項目がなくなる(自分の場合、「NVDIC GeForce GTX 1060」のみが残る)まで繰り返し(「27.20.100.8682」「26.20.100.8141」の2つの削除が必要だった)
  3. Surface Book 2のドライバー/ファームウェア(SurfaceBook2_Win10_19041_22.080.2839.0.msi)を再インストール

とやってみると……なんとっ!

Intel(R) UHD Graphics 620のドライバーのバージョンを確認

見事に、バージョン: 30.0.101.1339(日付: 2022/01/22)のドライバーへと更新されていた……!

Windows Helloが使えなくなっちゃった!

無事更新されたと喜んだものの、なぜかWindows Helloによる顔認証が効かなくなってしまった……。
ログイン画面で「カメラをオンにできませんでした。PINを使ってサインインしてください。」とか言われる

自分の場合には幸いにして、
設定>アカウント>サインインオプション>Windows Hello 顔認証
より[認識精度を高める]を再度実施することによって、使えるようになった模様。
うまくいかない場合、こちらの記事などを参照のこと



とりあえず、この状態で様子見中。

この記事を書くきっかけ

2022/10/11に発生し、Windowsの動作が重くなったことで気がついたdwm.exeのメモリリークはこんな感じ。

デスクトップウィンドウマネージャーのメモリリーク

2GB弱なので、まだまだ序の口という印象だが……。
過去にもいろいろと調べてみたものの抜本的な対策が見つからずにあきらめていたのだが、なんとか対応する方法はないものか……と再度調べてみると、Surface Book 2 更新履歴に対策されたらしき履歴があったので、試してみた次第。

過去のツイート等