C#やVB .NETでExcelを使わずにExcelのファイルを読み込むときの定番NPOIを使用せずExcelDataReaderで文字化けなくファイルを読み込むための方法です。

ExcelDataReaderを用いて.xlsファイルを読み込み、文字化けを起こした例

Read More

タミヤの『楽しい工作シリーズ No.227 カムロボット工作セット』と『IchigoJam』の組み合わせで動くサンプルプログラムを作ってみました。

プログラムを実行するとIchigoJamにつながっているキーボードがリモコンになり、キー入力をするとカムロボット(カムロボ)が動きます。

IMG_1215

Read More

KB4497934を適用するとレイアウトが崩れる?」の続きです。

検索キーワードが絞り込めたので、改めてインターネットを検索してみるとQiita@tfukumoriさんの記事が見つかりました。

2019/4/26のWindows 新元号(令和)対応パッチでのフォント変更?での不具合調査(Windows 7, 10 1803, .NET, Excel)』 (https://qiita.com/tfukumori/items/a1fb3984a3488875515e)

@tfukumoriさんの記事を読んでいくと自分が遭遇している現象と同じようです。

自分の場合、KB4497934で現象が起きましたが、俗に「令和対応」と呼ばれるパッチがリリースされたあたりから発生しているようです。

さらに読み進めていくと、この現象を解決するための修正パッチが配布されているようです。

Windows Updateでの修正(5/15追記)

Windows Update 定例パッチ(Bリリース、アメリカ第2火曜日の翌日、日本では5/15)で修正されたようです。

えっ、自分の環境では解決できていない…

ページに書いてあった情報をヒントに試してみたところ、解決ができたので修正方法を以下に記載します。

Read More

KB4497934を適用するとフォントの大きさが変わる?」でアップデートを適用するとフォントの大きさが変わるようだと記事を書きましたが、それ以外にも違いがあるようです。

差異を確認したのはVB .NETのSystem.Windows.Forms.Formクラスを継承したクラスでインスタンス生成時に発生するフォームのResizeイベントです。
具体的には、フォームのコンストラクタから呼び出されるInitializeComponentメソッドの実行中に発生するResizeイベントの発生回数が変わります。

  • 確認した環境

Windows 10 Pro Version 1809 Build 17753.475
Visual Studio Professional 2017 Version 15.9.11
VB .NETを用いたWindows Formsアプリ

  • アップデート適用前にResizeイベントが発生するタイミング

  1. Me.ClientSizeプロパティ設定時
  2. Me.Locationプロパティ設定時
  3. フォーム内のコントロール(コンテナ)に対するEndInitメソッド実行時
  • アップデート適用後にResizeイベントが発生するタイミング

  1. Me.ClientSizeプロパティ設定時
  2. Me.Locationプロパティ設定時
  3. フォーム内のコントロール(コンテナ)に対するEndInitメソッド実行時
  4. Me.ResumeLayoutメソッド実行時

比べてみると、アップデート適用後の4回目のResizeイベントが発生したタイミングでフォームのレイアウトが崩れてしまっています。
調査のために使用したフォームでは145ピクセル相当の横ずれが生じているようです。
全体の幅が1000ピクセル強の中で145ピクセルのずれなので見た目的にはかなりの違和感があります。

4回目のResizeイベント発生自体はInitializeComponentメソッドのMe.ResumeLayoutメソッドを呼び出している部分をコメントアウトすることで抑制できます。
(かなり乱暴な方法ですが、ResumeLayoutの引数を変えるなどでは抑制できませんでした。)
しかし、Resizeイベントの発生を抑制した状態でも生成されたフォームを確認するとフォントの大きさが異なるためか、やはりレイアウトが崩れています。
全体的にフォントの横幅が狭まっているのか前詰め状態になっています。

Windows Updateで改善されるのを待つのが無難かもしれません。

InitializeComponentメソッドの変更ですが、ソースを確認すると以下のように変更をするなとコメントされている部分なので危険性を理解したうえで変更するようにしてください。

‘メモ: 以下のプロシージャは Windows フォーム デザイナで必要です。
‘Windows フォーム デザイナを使って変更できます。
‘コード エディタを使用して、変更しないでください。

※2019/05/30 14:00 「KB4497934を適用するとレイアウトが崩れる? [とりあえず解決]」にこの記事の続きを書きました。

Windows 10のWindows UpdateでKB4497934
(2019年5月21日リリース)を適用するとフォントの大きさが変わってしまうケースがあるようです。

この現象を確認しているのは、MS UIゴシックとMS Pゴシックの2種類です。
(Visual Studio Professional 2017 Version 15.9.11上でVB .NETを用いてWindows Formsアプリを開発しているときに発生)

掲載したサンプルはSystem.Windows.Forms.LabelとSystem.Windows.Forms.TextBoxを用いてフォントにMS UI ゴシックを指定して表示してみました。
このサンプルではわずか数ピクセル程度のずれですが、String.Drawing.GraphicsクラスのMeasureStringメソッドなどを用いて描画サイズを測りながら描画位置を調整するような処理を行うと、かなり大きくずれて表示されます。
守秘義務の都合上公開はできないのですが作業中のプロジェクトではドン引きするくらいに画面が崩れています。

2019-05-29

KB4497934のリリース文でフォントや描画に関する言及はありませんが、KB4494441 (2019年5月14日リリース)のリリース文に以下のような説明があります。

Microsoft Excel で、MS UI Gothic または MS PGothic フォントを使用しているときに、テキスト、レイアウト、またはセルのサイズの幅が予想よりも狭く、または広くなることがある問題を修正します。

また、インターネットの情報を検索すると令和対応のあたりから表示崩れの報告が散見されるようです。KB4497934でもなんらかの影響を受けているのかもしれないですね。

とりあえずKB4497934をアンインストールすると、見た目上は以前の描画に戻るようです。

※2019/05/30 0:40 「KB4497934を適用するとレイアウトが崩れる?」にこの記事の続きを書きました。

  • KB4497934適用前
    KB4497934適用前
  • KB4497934適用後
    KB4497934適用後

VB6のUpDownコントロールのように、Valueプロパティの値がMinimumプロパティの値より小さい値になったらMaximumプロパティの値に、Valueプロパティの値がMaximumプロパティの値より大きい値になったらMinimumプロパティの値に折り返すNumericUpDownコントロールです。

UpDownコントロールのWarpプロパティをONにした際の挙動のみを拡張しているので、それ以外の部分は必要に応じて実装してください。

  • 確認した環境
    Windows 10 Ver. 1809 (ビルド  17763)
    Visual Studio Professional 2017 Ver. 15.9.11
  • ライセンス
    NYSL ( http://www.kmonos.net/nysl/ )
  • 折り返し(Wrap)に対応したNumericUpDownコントロール

' This software is distributed under the license of NYSL.
' ( http://www.kmonos.net/nysl/ )

''' <summary>
''' VB6のUpDownのように値の折り返しに対応したNumericUpDown
''' </summary>
Public Class WrapNumericUpDown
    Inherits NumericUpDown

    Private _wrap As Boolean = False
    Private _minimum As Decimal
    Private _maximum As Decimal

    ''' <summary>
    ''' 最小値
    ''' </summary>
    ''' <returns></returns>
    Public Shadows Property Minimum As Decimal
        Get
            Return _minimum
        End Get
        Set(value As Decimal)
            _minimum = value
            MyBase.Minimum = value - 1
        End Set
    End Property

    ''' <summary>
    ''' 最大値
    ''' </summary>
    ''' <returns></returns>
    Public Shadows Property Maximum As Decimal
        Get
            Return _maximum
        End Get
        Set(value As Decimal)
            _maximum = value
            MyBase.Maximum = value + 1
        End Set
    End Property

    ''' <summary>
    ''' 折り返しフラグ
    ''' Trueの場合、Valueプロパティの値がMinimumプロパティの値より小さい値になったらMaximumプロパティの値に、Valueプロパティの値がMaximumプロパティの値より大きい値になったらMinimumプロパティの値に調整
    ''' </summary>
    ''' <returns></returns>
    Public Property Wrap As Boolean
        Get
            Return _wrap
        End Get
        Set(value As Boolean)
            _wrap = value
        End Set
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overrides Sub OnValueChanged(e As EventArgs)

        If _wrap Then
            If Me.Value <= MyBase.Minimum Then
                Me.Value = Me.Maximum
            ElseIf Me.Value >= MyBase.Maximum Then
                Me.Value = Me.Minimum
            End If
        Else
            If Me.Value < Me.Minimum Then
                Me.Value = Me.Minimum
            ElseIf Me.Value > Me.Maximum Then
                Me.Value = Me.Maximum
            End If
        End If

        MyBase.OnValueChanged(e)

    End Sub
End Class

VB6を起動したところ、『Visual Studio 2005 Premier Partner Edition』のセットアップディスクを求められました。
自分で明示的にインストールした記憶がないので、何かに付帯してインストールされてしまったのではないかと考え、手元に該当するメディアも無いことだし、とりあえずセットアップ要求をスキップしようとしたのですが、キャンセルボタンを押しても「取消中」と表示されたまま先に進まなくなってしまいました。
そのような現象が発生したときに取った解決手順です。

※Visual Studio 2005 Premier Partner Editionは、SQL Serverの関連製品をインストールすると入ってしまうという情報が検索で引っかかりました。たしかに動作確認用にSQL Server 2005と関連ツールがインストールされています。
でも、最近までセットアップディスクの要求はなかったはずなんですよね、謎です。

Read More

VB .NETからWSL(Windows Subsystem for Linux)を起動しLinuxコマンドを実行、標準出力に出力された内容を.NET側で受け取りコンソールに出力するサンプルプログラムです。

サンプルプログラムはLinuxのPSコマンドを実行し、標準出力の内容を逐次読み込むパターンとイベントハンドラを用いて非同期に読み込むパターンの2つを用意しました。

BackgroundWorkerなどと組み合わせると長時間実行するLinuxコマンドから出力される内容を.NET側で受け取りGUIに進行状況を表示しながら実行することもできます。

  1. Linuxコマンドから標準出力に出力出力された内容を逐次読み込むサンプル

' This software is distributed under the license of NYSL.
' ( http://www.kmonos.net/nysl/ )

''' 
''' <summary>
''' WSL上でLinuxコマンドを実行し、標準出力に出力された内容をコンソールへ出力
''' </summary>
Public Shared Sub InvokeWslCommand()

    Dim psi As New ProcessStartInfo()

    ' WSLのディストリビューション(ubuntu、ubuntu1804など)
    psi.FileName = "ubuntu1804"
    ' WSL上で実行するコマンド(実行したい部分をダブルクオーテーションで囲む)
    psi.Arguments = "run ""ps -aux"""

    ' リダイレクト設定(標準出力のみをリダイレクト)
    psi.RedirectStandardInput = False
    psi.RedirectStandardOutput = True
    psi.RedirectStandardError = False

    ' シェル使用せず、ウィンドウ表示なし
    psi.UseShellExecute = False
    psi.CreateNoWindow = True

    ' WSLプロセスを起動
    Using p = Process.Start(psi)

        ' 標準出力に出力される内容を読み取り
        Dim reader = p.StandardOutput
        Do Until reader.EndOfStream
            Dim line = reader.ReadLine
            Console.WriteLine(line)
        Loop

        ' プロセスの終了待ち
        p.WaitForExit()

	' 終了コードを出力
        Console.WriteLine("exit-code=" & p.ExitCode)

    End Using

End Sub
  1. Linuxコマンドから標準出力に出力された内容をイベントで受け取り非同期で読み込むサンプル

' This software is distributed under the license of NYSL.
' ( http://www.kmonos.net/nysl/ )

''' 

''' <summary>
''' WSL上でLinuxコマンドを実行し、標準出力に出力された内容をコンソールへ出力(非同期版)
''' </summary>
Public Shared InvokeWslCommandAsync()

    Dim psi As New ProcessStartInfo()

    ' WSLのディストリビューション(ubuntu、ubuntu1804など)
    psi.FileName = "ubuntu1804"
    ' WSL上で実行するコマンド(実行したい部分をダブルクオーテーションで囲む)
    psi.Arguments = "run ""ps -aux"""

    ' リダイレクト設定(標準出力のみをリダイレクト)
    psi.RedirectStandardInput = False
    psi.RedirectStandardOutput = True
    psi.RedirectStandardError = False

    ' シェル使用せず、ウィンドウ表示なし
    psi.UseShellExecute = False
    psi.CreateNoWindow = True

    ' WSLプロセスを起動
    Using p = Process.Start(psi)

        ' 出力を受け取った時のハンドラを設定
        AddHandler p.OutputDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
                                                Console.WriteLine(e.Data)
                                            End Sub

        ' 非同期読み込み開始
        p.BeginOutputReadLine()

        ' プロセスの終了待ち
        p.WaitForExit()

        ' 非同期読み込みをキャンセル
        p.CancelOutputRead()

	' 終了コードを出力
        Console.WriteLine("exit-code=" & p.ExitCode)

    End Using


End Sub

Windowsのパス表現(例: C:\data\ )とWSLのパス表現(例: /mnt/c/data )を変換するための方法として、WSL側にはwslpathコマンドがサポートされていますがWindows側 .NETのライブラリでは簡単に変換できる方法がないようです。

WSL環境のwslpathコマンドを呼び出しパス表現の変換を行うための関数を作成しました。

' This software is distributed under the license of NYSL.
' ( http://www.kmonos.net/nysl/ )

''' <summary>
''' Windowsのパス表現からWSLのパス表現に変換する
''' </summary>
''' <param name="distro">ディストリビューションの起動コマンド(ubuntu、ubuntu1804など)</param>
''' <param name="windowsPath">Windowsのパス</param>
''' <returns>WSLのパス</returns>
Public Shared Function ToWslPath(distro As String, windowsPath As String) As String

    Dim psi As New ProcessStartInfo()
    psi.FileName = distro
    psi.Arguments = "run ""wslpath '" & windowsPath.Replace("\", "/") & "'"""
    psi.RedirectStandardOutput = True
    psi.UseShellExecute = False
    psi.CreateNoWindow = True

    Dim p = Process.Start(psi)
    Dim wslPath = p.StandardOutput.ReadLine
    p.WaitForExit()

    Return wslPath

End Function

''' <summary>
''' WSLのパス表現からWindowsのパス表現に変換する
''' </summary>
''' <param name="distro">ディストリビューションの起動コマンド(ubuntu、ubuntu1804など)</param>
''' <param name="wslPath">WSLのパス</param>
''' <param name="slash">Trueの場合セパレータが"/"、Falseの場合セパレータが"\"</param>
''' <returns>Windowsのパス</returns>
Public Shared Function ToWindowsPath(distro As String, wslPath As String, Optional slash As Boolean = False) As String

    Dim psi As New ProcessStartInfo()
    psi.FileName = distro
    psi.Arguments = "run ""wslpath " & If(slash, "-m", "-w") & " '" & wslPath & "'"""
    psi.RedirectStandardOutput = True
    psi.UseShellExecute = False
    psi.CreateNoWindow = False

    Dim p = Process.Start(psi)
    Dim windowsPath = p.StandardOutput.ReadLine
    p.WaitForExit()

    Return windowsPath

End Function



PowerBuilderのソースファイル(.SRWファイルなど)からコントロールの定義とイベントハンドラを抽出するための正規表現です。

コントロールの定義を抽出する正規表現

type\s{1,}(\S{1,})?([\s\S]*?)end\s{1,}type

イベントハンドラを抽出する正規表現

event\s{1,}(\S{1,})?;([\s\S]*?)end\s{1,}event

$1にコントロール名またはハンドラ名、$2に本体部分が設定されます。

PowerBuilderライブラリファイル(.PBLファイル)から.SRW形式のソースファイルの作り方については、『PowerBuilderのソースファイルをテキスト形式で一括エクスポートするツール』をご覧ください。