potisanのプログラミングメモ

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

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

C#&MSVS 17.5.0 Preview 3.0 ユーザーコントロールのobject、nint、nuint型プロパティはプロパティウィンドウで読み取り専用

ユーザーコントロールのobject、nint、nuint型プロパティはプロパティウィンドウで読み取り専用になります。

// UserControl1.Designer.csとUserControl1.resxは既定値なので省略します。
namespace UserControlTest1;

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    public object? ObjectProp { get; set; } = null;
    public sbyte Int8Prop { get; set; }
    public byte UInt8Prop { get; set; }
    public short Int16Prop { get; set; }
    public ushort UInt16Prop { get; set; }
    public int Int32Prop { get; set; }
    public uint UInt32Prop { get; set; }
    public long Int64Prop { get; set; }
    public ulong UInt64Prop { get; set; }
    public nint NIntProp { get; set; }
    public nuint NUIntProp { get; set; }
    public char CharProp { get; set; }
    public string StringProp { get; set; } = "123";
    public float FloatProp { get; set; }
    public double DoubleProp { get; set; }
    public bool BoolProp { get; set; }
    public int[] IntArrayProp { get; set; } = new[] { 1, 2, 3 };
    public char[] CharArrayProp { get; set; } = new[] { 'A', 'B', 'C' };
    public byte[] ByteArrayProp { get; set; } = new byte[] { 1, 2, 3 };
    public string[] StringArrayProp { get; set; } = new[] { "A", "B", "C" };
    public bool[] BoolArrayProp { get; set; } = new[] { false, true };
}

nint、nuint型プロパティはTypeConverterを適用すると別の型として編集できます。

    [TypeConverter(typeof(Int32Converter))]
    public nint NIntProp { get; set; }
    [TypeConverter(typeof(UInt32Converter))]
    public nuint NUIntProp { get; set; }