potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

Windows11 ファイルの新規作成登録の注意点

メモ帳をアンインストールしたらファイルの新規作成からテキストファイルが消えました。修復過程で気付いた注意点を共有します。

  • 「新規作成」項目の実体は拡張子単位のレジストリキーShellNewHKCR直下の拡張子キーまたは拡張子キー直下のファイル型キーに作成する。
  • ファイル型キーは拡張子キーの既定の値と同名のレジストリキーで通常はHKCR直下だが、新規作成で参照されるShellNewキーは特別扱い。ShellNewキーは拡張子キー直下のファイル型キーに登録できるが、新規作成時の項目名はHKCR直下のファイル型キーの既定値が使われる。
  • 拡張子キーまたはその直下のファイル型キーにShellNewキーを作成しても、HKCR直下のファイル型キーの既定値が空白だと新規作成に表示されない。
    • ShellNewキーにItemName値を登録すれば表示されるかもしれない。ただし、ItemName値はPEファイルのリソース位置のみ。

Windows11でストアアプリ版のメモ帳をアンインストールすると「.txt」は「txtfilelegacy」に関連付けられました。HKCR\txtfilelegacyキーは既定値が空白なので、HKCR\.txtキーまたはHKCR\.txt\txtfilelegacyキーにShellNewキーを作成しても上記の理由から新規作成に追加されません。HKCR\.txt\txtfilelegacyキーの既定値を「テキストファイル」に変更すれば解決しました。

C++&Win API _bstr_tとwil::make_bstr

Windows環境でLPWSTRからスマートポインタ的なBSTRを作成する方法には次の2通りあります。

  1. _bstr_t(...) <comutil.h>
  2. wil::make_bstr(...) "wil/com.h"

前者の_bstr_t(...)コンパイラ付属なので追加インストールが不要ですが、ムーブセマンティクス非対応で独自の参照カウンタを使用しています。作成する度に参照カウント管理用にクラスがnewされます。また、LPWSTR/LPSTR等からの作成に対応しています。

後者のwil::make_bstr(...)Microsoftのパッケージですが追加インストールが必要です。ムーブセマンティクス対応でメモリ消費は少ないですが、コピー時は新しいBSTRが作成されます。LPWSTRからの作成しか対応しません。 各種エラーパターン(エラーコード、フェイルファスト、例外)に対応した関数が存在します。

結局は用途に合わせて使い分けですが、それぞれの存在は知っておいて損はないと思いました。

Googleのログアウト時の広告用検索アクティビティ記録

Googleはログアウト状態だと履歴の記録を止めると思い込んでいましたが、Google検索の「検索でのデータ」と「広告設定」の管理画面を見る限り記録していたようです。

  • Google 検索でのデータ
    • 日本語版ではGoogle検索トップページ右下の設定をクリック→検索におけるデータのクリックで表示できます。
  • Google広告設定
    • 初期表示は「検索」ですが、ページ中に「YouTube」と「ウェブ」のタブもあります。

使用ブラウザはFirefoxなので追跡用にGoogle謹製の機能は使えないはずです。CookieIPアドレス、ブラウザバージョンなどを組み合わせていると思うのですが、さすが広告企業だと思いました。

参考までに、Cookie以外のブラウザフィンガープリント情報は電子フロンティア財団Cover Your Tracksなどで確認できます。IPアドレス自体の情報は日本語で検索すればいくつかのサイトが見つかります。

coveryourtracks.eff.org

Python 3.11でパッケージのグローバル変数やインポートを隠す

パッケージで使いまわしたいグローバル変数やインポートは__init__.pyと別ファイルの組み合わせで隠せます(見えにくくできます)。具体的には次の手順です。

  1. パッケージ名のディレクトリと__init__.pyを作成する。
  2. グローバル変数やインポートを使いたいスコープをfile1.pyなどに移動する。
  3. __init__.pyで公開したいオブジェクトだけfile1.pyなどからimportする。

上記の手順でパッケージ外からimport パッケージ名したときに__init__.py以外のファイルで使っているグローバル変数やインポートが非表示になります。厳密にはimport パッケージ名.file1で表示されますが、そこは使用者の使い方次第です。変数名やインポートエイリアス先頭の_で内部使用を示す方法も組み合わせられます。

この方法はcomtypesパッケージで知りました。このパッケージにはcomtypes.GUIDクラス(__init__.pyimportされたcomtypes.GUID.GUIDの別名)とcomtypes.GUIDファイルが存在していて、comtypes.GUIDファイルのグローバル変数_CLSIDFromString__init__.pyimportしないことで隠されています。

C#11 配列の入ったobject型をstring.Joinで結合する

配列の入ったobject型をstring.Join()で結合するにはIEnumerableにキャストしてからOfType<T>()を使います。キャストせず渡すと可変長引数の最初の引数として素直にToString()されます。ちなみにIEnumerableへキャストすると文字列(char[]配列)も分割されるので適宜x.GetType().IsArrayで分岐します。

// global using有効時
using System.Collections;

object o = new int[5];

Console.WriteLine(string.Join(", ", o));
Console.WriteLine(string.Join(", ", (o as IEnumerable)!.OfType<object>()));
// 出力
// System.Int32[]
// 0, 0, 0, 0, 0

OfType<T>()の類似メソッドにCast<T>()がありますが、object型を使う場合はOfType<T>()で十分だと思います。

using System.Collections;

object o = new int[5];

Console.WriteLine(string.Join(", ", (o as IEnumerable)!.Cast<object>()));
// 0, 0, 0, 0, 0