...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

PCを新調した

OSが入ったHDDをSSDにクローンしたけどブートができなくて焦った~。 ブートマネージャーが旧Dドライブ(Windows Vista入り)になってて、旧Cドライブと旧Dドライブにブートローダーがあって、デュアルブートしていたらしい。 一度全部のHDDを外してSSDだけにして、Windows10インストールディスクでコマンドプロンプトを開いてbcdbootコマンドを使ってSSDにブートファイルを構成しなおしたら起動してよかった。

  • OS: Windows 10 Pro 64bit (もうしばらく10で頑張る)
  • CPU: AMD Ryzen 7 5700X (これまでIntelだったので初めてのAMD)
  • CPUクーラー: DEEPCOOL AK400 WH R-AK400-WHNNMN-G-1
  • メモリ: crucial CT2K16G4DFRA32A DDR4 PC4-25600 16GB 2枚組
  • マザーボード: GIGABYTE B550 AORUS ELITE V2
  • グラフィックボード: ASUS Dual GeForce RTX 3060 Ti OC Edition 8GB GDDR6X DUAL-RTX3060TI-O8GD6X
  • SSD: WD BLACK SN770 NVMe SSD WDS100T3X0E 1TB (新C:)
  • HDD: SATA 6Gb/s 2TB WDC WD20EFRX 2TB (旧C:→新I:)
  • HDD: SATA 6Gb/s 3TB WDC WD30EZRX 3TB (旧D:)
  • HDD: SATA/300 500GB ST3500320AS 500GB (旧E:)
  • ディスプレイ: Acer VG280Kbmiipx (2台)
  • 電源: ANTEC NeoECO Gold NE750G
  • ケース: ANTEC SOLO black (流用)
  • USBフロントパネル: GRAUGEAR G-MP01CR

とりあえず以前に旧PCに使ったベンチマークを同じソフトで。 今時のベンチマークソフトで試さないと全然分からないだろうけど。

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
CrystalMark 2004R3 [0.9.126.451] (C) 2001-2008 hiyohiyo
                                  Crystal Dew World [http://crystalmark.info/]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

------------------------------------------------------------------------------
CrystalMark Result
------------------------------------------------------------------------------
   Display Mode : 2560 x 1440 32bit (ClearType)

    CrystalMark :  638529

[ ALU ]            164655
      Fibonacci :   33747
      Napierian :   45219
   Eratosthenes :   28807
      QuickSort :   56860
[ FPU ]             77169
        MikoFPU :    5739
     RandMeanSS :   44831
            FFT :   17901
     Mandelbrot :    8676
[ MEM ]            198714
           Read : 35241.00 MB/s ( 35241)
          Write : 70353.71 MB/s ( 70353)
     Read/Write : 64343.90 MB/s ( 64343)
          Cache : 287556.78 MB/s ( 28755)
[ HDD ]            107404
           Read : 3346.49 MB/s ( 22232)
          Write : 4074.46 MB/s ( 25872)
 RandomRead512K : 2655.20 MB/s ( 18776)
RandomWrite512K : 2779.68 MB/s ( 19398)
 RandomRead 64K :  692.22 MB/s (  8961)
RandomWrite 64K : 1333.05 MB/s ( 12165)
[ GDI ]             20956
           Text :   12130
         Square :     987
         Circle :    3297
         BitBlt :    4542
[ D2D ]             24434
   Sprite    10 :  690.86 FPS  (    69)
   Sprite   100 :  633.94 FPS  (   633)
   Sprite   500 :  436.31 FPS  (  2181)
   Sprite  1000 :  406.71 FPS  (  4067)
   Sprite  5000 :  162.16 FPS  (  8108)
   Sprite 10000 :   93.76 FPS  (  9376)
[ OGL ]             45197
  Scene 1 Score :   24599
  Lines (x1000) : (5721918)
  Scene 1  CPUs : (   1024)
  Scene 2 Score :   20598
Polygons(x1000) : (1447265)
  Scene 2  CPUs : (    512)

------------------------------------------------------------------------------
System Information
------------------------------------------------------------------------------
             OS : Windows NT6.2 Business  [6.2 Build 9200]
   Display Mode : 2560 x 1440 32bit 60Hz
         Memory : 32691 MB
        DirectX : 12.0
------------------------------------------------------------------------------
CPU
------------------------------------------------------------------------------
       CPU Name : AMD Unknown CPU
  Vendor String : AuthenticAMD
    Name String : AMD Ryzen 7 5700X 8-Core Processor             
       CPU Type : Original OEM processor
Number(Logical) : 16
         Family : F
       FamilyEx : 0A
     Generation : F
          Model : 1
       Stepping : 2
           APIC : 00
        Feature : MMX SSE SSE2 SSE3 SSSE3 SSE4.1 SSE4.2 SSE4A MMX+ NX AMD-V AMD64
          Clock : 3393.61 MHz
      Data Rate :    HT

     L1 I-Cache :   32 KB
     L1 D-Cache :   32 KB
       L2 Cache :  512 KB [Full:3393.61 MHz]
       L3 Cache : 32768 KB
------------------------------------------------------------------------------
Device
------------------------------------------------------------------------------
        ChipSet : AMD Unknown
          North : AMD Unknown
          South : AMD Unknown
          Video : NVIDIA Unknown
 IDE Controller : 
------------------------------------------------------------------------------
HDD
------------------------------------------------------------------------------
Type Size    Model                                  ( Buffer Mode )     
SATA 2000.3GB WDC WD20EFRX-68EUZN0                     
SATA 801.5GB WDC WD30EZRX-00D8PB0                     
SATA 500.1GB ST3500320AS                              

ビットマップのコピー・アンド・ペースト関連リンク集

ブックマーク整理のためここへ吐き出す。

ビットマップ関係

ビットマップファイルフォーマット

BMP(ビットマップ)のファイルフォーマット

ビットマップファイルフォーマット | イメージングソリューション

BMPファイルのフォーマット

ビットマップファイルの操作

クリップボードからビットマップの保存方法について - プログラマ専用SNS ミクプラ

DIB→DDB変換【Windowsプログラミング研究所】

DDB→DIB変換【Windowsプログラミング研究所】

DIBSectionを作る【Windowsプログラミング研究所】

DIBをBMPファイルに保存する【Windowsプログラミング研究所】

BMPファイルを32ビットDIBSectionとして読み込む【Windowsプログラミング研究所】

BMPファイルを32ビットDIBとして読み込む【Windowsプログラミング研究所】

32ビットDIBを作る【Windowsプログラミング研究所】

DIBをBMPファイルに保存する【Windowsプログラミング研究所】

CreateDIBSectionによる汎用ビットマップ

HBITMAPをビットマップファイルに保存

Microsoft

ビットマップ ヘッダーの種類 - Win32 apps | Microsoft Learn

デバイスに依存しないビットマップ - Win32 apps | Microsoft Learn

イメージの保存 - Win32 apps | Microsoft Learn

イメージのキャプチャ - Win32 apps | Microsoft Learn

BITMAPINFO (wingdi.h) - Win32 apps | Microsoft Learn

BITMAPINFOHEADER (wingdi.h) - Win32 apps | Microsoft Learn

BITMAP (wingdi.h) - Win32 apps | Microsoft Learn

GetDIBColorTable 関数 (wingdi.h) - Win32 apps | Microsoft Learn

GetObject 関数 (wingdi.h) - Win32 apps | Microsoft Learn

IDataObjectとクリップボード関係

Implementing IDataObject

Implementing IDataObject - Catch22

非実在ファイルのD&Dで複数ファイルを送り出す - イグトランスの頭の中

非同期ドロップ処理フリースレッドマーシャラー + CFSTR_FILEDESCRIPTORで複数ファイル (SHCreateMemStream) · GitHub

クリップボード | C# プログラミング解説

システム - .NET Tips (VB.NET,C#...)

Copying bitmap to the Clipboard

Qt 4.8: QOleDataObject Class Reference

RichEditコントロールからテキストを取得する

DFLのRichTextBox用にせっかく書いたけど不要だった・・・ここで供養する。

// この辺のインポートが必要だけど競合するので選択インポートする。
private import dfl.internal.winapi;
private import core.sys.windows.richedit : GETTEXTEX, GETTEXTLENGTHEX, GTL_CLOSE;
final @property Dstring getText() // getter
{
    GETTEXTLENGTHEX getLength;
    getLength.codepage = 1200; // Unicode
    getLength.flags = GTL_CLOSE;
    int textLength = cast(int)sendMessage(handle, EM_GETTEXTLENGTHEX, cast(WPARAM)&getLength, 0);

    GETTEXTEX getText;
    getText.cb = textLength + cast(uint)wchar.sizeof; // Add Utf16 null terminater.

    // dmd同梱のrichedit.dには定義されていなくて古いもよう。
    // Flags for the GETEXTEX data structure
    enum GT_DEFAULT = 0;
    enum GT_USECRLF = 1;
    enum GT_SELECTION = 2;
    enum GT_RAWTEXT = 4;
    enum GT_NOHIDDENTEXT = 8;
    getText.flags = GT_DEFAULT; // GT_RAWTEXT | GT_SELECTION;
    getText.codepage = 1200; // Unicode
    getText.lpDefaultChar = null;
    getText.lpUsedDefChar = null;

    ubyte[] buf = new ubyte[getText.cb];
    int copiedLength = cast(int)sendMessage(handle, EM_GETTEXTEX, cast(WPARAM)&getText, cast(LPARAM)buf.ptr);
    return fromUnicode(cast(wchar*)buf.ptr, copiedLength);
}

参考文献

DFL: ToolBarのサンプルコード

ツールバーのサンプルコードです。

長くなるのでソースコードはこちらにリンクを張っておきます。

下図の左から、普通のボタン、トグルボタン、セパレータ(区切り)、ドロップダウンボタン、矢印分離ドロップダウンボタン、セパレータ、ラジオボタン3つ(グループ1)、セパレータ、ラジオボタン(グループ2)です。

ビジュアルスタイルを有効にすると、3Dスタイルではなくなり、フラットスタイルしか選べなくなるので、サンプルコードではコメントアウトして無効にしています。

普通のボタンを押すとボーダースタイルが変化します(3種類)。 ボーダースタイルの設定機能は、WinFormsを参考にして今回実装しました。

トグルボタンを押すとフラットスタイルになると同時に、リストスタイルになります。 フラットスタイルとリストスタイルの表示形式は、今回実装しました。 サンプルコードでは同時に変更していますが、両スタイルは個別に設定可能です。

ドロップダウンボタンを押すとドロップダウンリスト風のコンテキストメニューが表示されます。 このメニューでmsgBox()を呼ぶと2回WM_COMMANDが飛んできてしまい、2回msgBox()が呼ばれてしまって困りましたが、そうならないように直しました。

矢印分離ドロップダウンボタンのボタン部を押すと、普通のボタンと同様の挙動をします。 矢印部を押すと、ドロップダウンリスト風のコンテキストメニューが表示されます。 こちらもおかしな挙動に悩まされましたが、違和感ない挙動に修正しました。 WM_COMMAND、WM_LBUTTONDOWN及びWM_LBUTTONUPメッセージを捉えて自力で動かしています。

ドロップダウン系ボタンは、普通、BN_CLICKED通知を捉えて、メニュー項目が選択されたことを取得するようですが、どうも奇妙な挙動をするので、使わないことにしました。

ラジオボタンは、セパレータでグループが自動的に区切られるようです。 ラジオボタンは、同一グループ内で1つのボタンしか押下状態になりません。 新たにボタンが押下状態になるときは、以前に押下状態であったボタンは勝手に解放状態になります。 また、グループが分かれていることがテストできるように、ダミーのラジオボタンを右端に付けています。

上図は、フラットスタイルかつリストスタイルにしたものです。 visibleプロパティの動作確認のため、トグルボタンを押した状態ではラジオボタン3つを非表示にしています。

上図は、ドロップダウンメニューを表示させた様子です。 元々書かれていたコードを活用しようとしている間は、変な挙動が直らず苦戦しましたが、これを諦めて自作のウィンドウプロシージャでoverrideして全部上書きしたら割とすぐにできました。

以前のリストボックスでもそうでしたが、コモンコントロールの挙動がイマイチのときは、自分でウィンドウメッセージとウィンドウ通知を捉えて、自力で挙動を精微にコントロールしてやる方がいいようです。

WinFormsとの違い

.NET Core 3.1以降はToolStripクラスに移行されたため、ToolBarクラスが使えません。 そうしてToolBarの実装が中止されたせいか、Windows APIに存在するツールバー関係の機能がWinFormsのToolBarクラスには一部実装されていないようです。 具体的には、矢印分離ドロップダウンボタンとラジオボタンは、ボタンのスタイルとして選択できないようですし、ツールバーをリストスタイルで表示する機能もないようです。 また、非ビジュアルスタイル下でのフラットスタイルも選択できないようです。 そのため、この辺りは本家WinFormsよりも高機能になりました。

まあ、本来であればToolStripクラスを実装したいところなのですが。

DFLのダウンロード

github.com

DFL: ContextMenuのサンプルコード

コンテキストメニューのサンプルです。

特に難しいことはないですね。

ただ、mouseDownイベントを使って右クリックを検出した方が、DFLらしいかもしれません。

import dfl;
import core.sys.windows.windows;

version(Have_dfl) // For DUB.
{
}
else
{
    pragma(lib, "dfl.lib");
}

class MainForm : Form
{
    private ContextMenu _contextMenu;
    
    this()
    {
        this.text = "ContextMenu example";
        this.size = Size(350, 200);
        
        _contextMenu = new ContextMenu();
        MenuItem contextMenuItem1 = new MenuItem("Kyoto");
        contextMenuItem1.click ~= (MenuItem mi, EventArgs e) {
            msgBox("Kyoto");
        };
        MenuItem contextMenuItem2 = new MenuItem("Tokyo");
        contextMenuItem2.click ~= (MenuItem mi, EventArgs e) {
            msgBox("Tokyo");
        };
        MenuItem contextMenuItem3 = new MenuItem("Osaka");
        contextMenuItem3.click ~= (MenuItem mi, EventArgs e) {
            msgBox("Osaka");
        };
        _contextMenu.menuItems.add(contextMenuItem1); // 1つだけでも
        _contextMenu.menuItems.addRange([contextMenuItem2, contextMenuItem3]); // 配列を渡すこともできる
    }

    // 右クリックした位置にメニューを表示するためにウィンドウプロシージャをoverrideする
    // Control.mouseDownイベントでもできそう?
    override void wndProc(ref Message msg)
    {
        switch (msg.msg)
        {
            case WM_RBUTTONDOWN:
            {
                if (_contextMenu)
                {
                    POINT pt;
                    GetCursorPos(&pt);
                    _contextMenu.show(this, Point(&pt));
                }
                return;
            }
         default:
            {
                super.wndProc(msg);
                return;
            }
        }
    }
}

static this()
{
    Application.enableVisualStyles();
}

void main()
{
    Application.run(new MainForm());
}

DFLのダウンロード

github.com

追記

GitHubのサンプルコードは、mouseDownイベントを使った方法に変更しました。

ひとつ注意事項があります。 MouseEventArgsで与えられるマウス座標はクライアント座標です。 コンテキストメニューを表示する座標はスクリーン座標で指定しなければならないので、クライアント座標からスクリーン座標に変換する必要があります。

this.mouseDown ~= (Control c, MouseEventArgs e) {
    if (e.button & MouseButtons.RIGHT)
    {
        if (_contextMenu)
        {
            Point pt = Point(e.x, e.y);
            ClientToScreen(handle, &pt.point);
            _contextMenu.show(this, pt);
        }
    }
};

DFL: Timerのサンプルコード

Timerクラスのサンプルコードです。

Startボタンでカウントアップ開始、Stopボタンで停止します。

import dfl;
import std.conv;

version(Have_dfl) // For DUB.
{
}
else
{
    pragma(lib, "dfl.lib");
}

class MainForm : Form
{
    private Label _label;
    private Timer _timer;
    private Button _start;
    private Button _stop;
    private uint _count;

    public this()
    {
        this.text = "Timer example";
        this.size = Size(300, 200);

        _label = new Label;
        _label.location = Point(100, 0);
        _label.font = new Font("Verdana", 50f);
        _label.autoSize = true;
        _label.text = to!string(_count);
        _label.parent = this;

        _timer = new Timer;
        _timer.interval = 1000; // 1秒周期に設定
        _timer.tick ~= (Timer t, EventArgs e) {
            _label.text = to!string(_count);
            _count++;
        };

        _start = new Button;
        _start.text = "Start";
        _start.location = Point(10, 10);
        _start.click ~= (Control c, EventArgs e) {
            _timer.start();
        };
        _start.parent = this;

        _stop = new Button;
        _stop.text = "Stop";
        _stop.location = Point(10, 50);
        _stop.click ~= (Control c, EventArgs e) {
            _timer.stop();
        };
        _stop.parent = this;
    }
}

static this()
{
    Application.enableVisualStyles();
}

void main()
{
    Application.run(new MainForm());
}

DFL: NotifyIconのサンプルコード

NotifyIconのサンプルコードです。

NotifyIconというのは、タスクバーに出るアイコンです。

上のスクリーンショットで右端にあるフェイスマークを表示しています。

import dfl;

class MainForm : Form
{
    private NotifyIcon _notifyIcon;

    public this()
    {
        this.text = "NotifyIcon example";
        this.size = Size(300, 200);
        
        MenuItem menuItem1 = new MenuItem("Show");
        menuItem1.click ~= (MenuItem mi, EventArgs e) { msgBox("Hi!"); };

        MenuItem menuItem2 = new MenuItem("Close");
        menuItem2.click ~= (MenuItem mi, EventArgs e) { this.close(); };
        
        _notifyIcon = new NotifyIcon;
        _notifyIcon.icon = new Icon(r".\image\icon.ico");
        _notifyIcon.text = "This is tooltip text";
        _notifyIcon.contextMenu = new ContextMenu;
        _notifyIcon.contextMenu.menuItems.add(menuItem1);
        _notifyIcon.contextMenu.menuItems.add(menuItem2);
        _notifyIcon.show();
    }
}

static this()
{
    Application.enableVisualStyles();
}

void main()
{
    Application.run(new MainForm());
}

DFLのダウンロード

github.com