プレゼントに当選しました

日本ギガバイトが運営しているファンサイトAORUS4Uで応募したプレゼントに当選しました。
Chibiちゃんが来てくれるのを期待していたけど、帽子というのも要所で目立ちそうで良いなw

Aorus mouse pad, baseball cap and Gigabyte motherboard

一緒に撮影しているのは、約10年前のギガバイト製のG1.Sniper 5というマザーボード
このころはAorusというブランドはまだ存在せず、G1-Killerシリーズを展開していました。
Z270くらいまでの時代は、フラッグシップモデルのMoboは4-way SLIをするためにx16スロットを4つ備えているのが常でした。

しかしGTX1xxxで2-wayのみのサポートとなり、RTX2xxxではSLI→劣化NV-Linkになり、
RTX4xxxではとうとうNV-Linkもサポート対象外になりました。
NV-Linkもフルスペックなら素晴らしいのですが、革ジャンCEOはAI-GPU(旧Tesla)しか興味がないのか・・・

x16をフル装備したマザーボードというのは、ゲームでいうと強化ソケットが上限の武器のようなもので、胸が躍るものがありました。
メインストリームで発売されなくなってさみしい限りです・・・
え、Xeon-WとTRがあるって??
さすがに予算3桁万円は・・・😅

【C#】端末が操作されていない時間を取得する

Windows端末がどのくらいの間AFKであるかを知りたかったので調査結果をノートします。

参考サイト
csharp.hotexamples.com

C#の場合】

internal struct LASTINPUTINFO
{
    public uint cbSize;
    public uint dwTime;
}

class Program
{
    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

    static void Main(string[] args)
    {
        LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
        lastInputInfo.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInputInfo);

        while (true)
        {
            Console.WriteLine(GetAfkSecond(lastInputInfo));

            System.Threading.Thread.Sleep(1000);
        }
    }

    /// <summary>
    /// 端末が入力されていない時間を取得する
    /// </summary>
    /// <returns>AFK秒数</returns>
    public static long GetAfkSecond(LASTINPUTINFO lastInputInfo)
    {
        GetLastInputInfo(ref lastInputInfo);
        return ((Environment.TickCount - lastInputInfo.dwTime) / 1000);
    }
}

【実行結果】
f:id:ktts:20210414002720p:plain

【VisualBasic】PrinterオブジェクトでUTF8文字を印字する

VB6のPrinterでUTF8を印字する方法を調べたのでノートします。

PrinterでUTF8文字を出力すると、通常は’?’と出力されるけど、
TextOutW関数(gdi32.dll)を利用することで出力できました。


参考サイト
stackoverflow.com

' TextOutW関数の宣言
Private Declare Function TextOutW Lib "gdi32" ( _
    ByVal hdc As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal lpStringU As Long, _
    ByVal nCount As Long) As Long  


' ScaleModeをミリメートルにする
Printer.ScaleMode = vbMillimeters

' 通常のPrintメソッドによるテキスト出力
Printer.CurrentX = 100
Printer.CurrentY = 200
Printer.Print strText

' TextOutW関数によるテキスト出力
TextOutW Printer.hdc, _
    Printer.ScaleX(100, vbMillimeters, vbPixels), _
    Printer.ScaleY(200, vbMillimeters, vbPixels), _
    StrPtr(strText), _
    Len(strText)

【C#】【VB.NET】文字列の中にList<string>が含まれるかを判定する

ある文字列の中に、ある文字列リストの一部/全部が含まれるかを判定する手法を調べたのでノートします

参考サイト
stackoverflow.com

C#の場合】

List<string> words = new List<string>() { "bar", "baz" };
string chat1 = "What is foo?";
string chat2 = "What is bar doing?";
string chat3 = "What is bar doing in baz?";

// or
Console.WriteLine("chat 1 is {0}.", words.Any(x => chat1.Contains(x)));
Console.WriteLine("chat 2 is {0}.", words.Any(x => chat2.Contains(x)));
Console.WriteLine("chat 3 is {0}.", words.Any(x => chat3.Contains(x)));

// and
Console.WriteLine("chat 1 is {0}.", words.All(x => chat1.Contains(x)));
Console.WriteLine("chat 2 is {0}.", words.All(x => chat2.Contains(x)));
Console.WriteLine("chat 3 is {0}.", words.All(x => chat3.Contains(x)));

VB.NETの場合】

Dim words As New List(Of String)(New String() {"bar", "baz"})
Dim chat1 As String = "What is foo?"
Dim chat2 As String = "What is bar doing?"
Dim chat3 As String = "What is bar doing in baz?"

' or
Console.WriteLine("chat 1 is {0}.", words.Any(Function(x) chat1.Contains(x)))
Console.WriteLine("chat 2 is {0}.", words.Any(Function(x) chat2.Contains(x)))
Console.WriteLine("chat 3 is {0}.", words.Any(Function(x) chat3.Contains(x)))

' and
Console.WriteLine("chat 1 is {0}.", words.All(Function(x) chat1.Contains(x)))
Console.WriteLine("chat 2 is {0}.", words.All(Function(x) chat2.Contains(x)))
Console.WriteLine("chat 3 is {0}.", words.All(Function(x) chat3.Contains(x)))

【結果】
f:id:ktts:20200719155951p:plain

VB.NETでdefault(T)に相当するモノ

VB.NETでdefault(T)に相当するモノが使いたかったのでノートします

参考サイト
stackoverflow.com

【使用例】

' 構造体オブジェクトが初期値かどうか判定する
If obj.Equals(CType(Nothing, MyStructure)) Then
    Console.WriteLine("構造体オブジェクトは初期値です")
End If

【C#】DataGridViewで行コピーペーストを実装する

f:id:ktts:20200331234605p:plain

C#のDataGridViewで行コピペ機能が欲しかったので調査結果をノートします。

参考サイト
stackoverflow.com

C#の場合】
下記クラスを作成します

using System.Windows.Forms;

public class ClipboardUtils
{
    public static void OnDataGridViewPaste(object grid, KeyEventArgs e)
    {
        if ((e.Shift && e.KeyCode == Keys.Insert) || (e.Control && e.KeyCode == Keys.V))
        {
            PasteTSV((DataGridView)grid);
        }
    }

    public static void PasteTSV(DataGridView grid)
    {
        char[] rowSplitter = { '\r', '\n' };
        char[] columnSplitter = { '\t' };

        // クリップボードからテキストを取得する
        IDataObject dataInClipboard = Clipboard.GetDataObject();
        string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);

        // グリッドで分割する
        string[] rowsInClipboard = stringInClipboard.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);

        // ペースト先のセル番地を取得する
        int r = grid.SelectedCells[0].RowIndex;
        int c = grid.SelectedCells[0].ColumnIndex;

        // コピペで行数が不足している場合は、行追加する
        if (grid.Rows.Count - (grid.AllowUserToAddRows ? 1 : 0) < (r + rowsInClipboard.Length))
        {
            grid.Rows.Add(r + rowsInClipboard.Length - grid.Rows.Count + (grid.AllowUserToAddRows ? 1 : 0));
        }

        // コピー行を列挙する
        for (int iRow = 0; iRow < rowsInClipboard.Length; iRow++)
        {
            // Split row into cell values
            List<string> valuesInRow = rowsInClipboard[iRow].Split(columnSplitter).ToList();

            // コピーしている列数がグリッドの列数を超える場合は、先頭から削除する(RowHeadersVisible表示時)
            while (valuesInRow.Count > grid.ColumnCount)
            {
                valuesInRow.RemoveAt(0);
            }

            // コピーセルを列挙する
            for (int iCol = 0; iCol < valuesInRow.Count; iCol++)
            {
                // グリッドの列数を超えない場合に、対応するセルに値を入力する
                if (grid.ColumnCount - 1 >= c + iCol)
                {
                    DataGridViewCell cell = grid.Rows[r + iRow].Cells[c + iCol];

                    if (!cell.ReadOnly)
                    {
                        cell.Value = valuesInRow[iCol];
                    }
                }
            }
        }
    }
}

DataGridViewには下記イベントを追加します

private void DataGridView1_KeyUp(object sender, KeyEventArgs e)
{
    ClipboardUtils.OnDataGridViewPaste(sender, e);
}

【C#】【VB.NET】WinFormsのTreeViewで全ての葉ノード(末端)がチェックされているか判定する

TreeViewにおいて、あるノードの持つ全部の葉ノード(末端)がチェックされているか知りたいことがあります。

f:id:ktts:20200204233155p:plain
↑のような3値のチェック状態を持たせられれば、true(✓)かnull(■)かで判定できるのですが、
WinFormsのTreeViewでは不可です。

【参考サイト】
clikington-saito.com
上記サイトのように親がチェック状態なら子のチェックを外せないとする手法もありますが、
ユーザーからすると不便ですね。
そこで、簡易なメソッドを考えたのでここにノートします。

C#の場合】

public static class ExtensionMethods
{
    /// <summary>
    /// 全ての葉ノードがチェックされているか判定する拡張メソッド
    /// </summary>
    /// <param name="treeNode">TreeNode</param>
    /// <returns>チェック状態</returns>
    public static bool AllLeavesChecked(this TreeNode treeNode)
    {
        if (treeNode.Nodes.Count == 0)
        {
            return treeNode.Checked;
        }
        else
        {
            bool returns = true;
            foreach (TreeNode node in treeNode.Nodes)
            {
                returns &= node.AllLeavesChecked();
            }

            return returns;
        }
    }
}

VB.NETの場合】

Module ExtensionMethods
    ''' <summary>
    ''' 全ての葉ノードがチェックされているか判定する拡張メソッド
    ''' </summary>
    ''' <param name="treeNode">TreeNode</param>
    ''' <returns>チェック状態</returns>
    <System.Runtime.CompilerServices.Extension()>
    Public Function AllLeavesChecked(treeNode As TreeNode) As Boolean
        If treeNode.Nodes.Count = 0 Then
            Return treeNode.Checked
        Else
            Dim returns As Boolean = True
            For Each node As TreeNode In treeNode.Nodes
                returns = returns And node.AllLeavesChecked()
            Next

            Return returns
        End If
    End Function
End Module