この記事はF# Advent Calendar 2022参加記事です
Summary
cmdコンソールで起動時にカラーテーブルを変更して常に意図したカラーを出力する
カラーテーブルの変更期間はプログラム実行時中のみとする
背景
実行するパソコンによっては出力した文字色と背景色が同じになる場合がありcmdコンソールの色調を固定する必要があった
方策
実行している間、cmdコンソールのカラーテーブルを意図したものにする
実施策
SetConsoleScreenBufferInfoEx 関数を使用してカラーテーブル情報を書き換えればよい
// SetConsoleScreenBufferInfoEx 関数
// https://learn.microsoft.com/ja-jp/windows/console/setconsolescreenbufferinfoex
// 指定したコンソール画面バッファーに関する拡張情報を設定します
BOOL WINAPI SetConsoleScreenBufferInfoEx(
_In_ HANDLE hConsoleOutput,
_In_ PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx
);
// CONSOLE_SCREEN_BUFFER_INFOEX 構造体
// https://learn.microsoft.com/ja-jp/windows/console/console-screen-buffer-infoex
// コンソール画面バッファーに関する拡張情報が含まれます。
typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX {
ULONG cbSize;
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
WORD wPopupAttributes;
BOOL bFullscreenSupported;
COLORREF ColorTable[16]; // <---------- ★ここがcmdコンソールのカラーテーブル情報
} CONSOLE_SCREEN_BUFFER_INFOEX, *PCONSOLE_SCREEN_BUFFER_INFOEX;
実際のコード
メインコード
(*
サンプルプログラム
------------------
cmdコンソールの色調をどんな環境でも同じ色調にするように固定する
背景色:白色(rgb = 255,255,255)
前景色:黒色(rgb = 0 ,0 ,0 )
*)
open System
open System.Runtime.InteropServices
open DllImported
[<Literal>]
let STD_OUTPUT_HANDLE = -11
// 1. コンソール画面バッファーの容器を作成
let mutable screenBuffer = new CONSOLE_SCREEN_BUFFER_INFOEX(
cbSize = Marshal.SizeOf(typeof<CONSOLE_SCREEN_BUFFER_INFOEX>)
)
// 2. 現状のコンソール画面バッファーの拡張情報を取得
GetConsoleScreenBufferInfoEx(GetStdHandle(STD_OUTPUT_HANDLE), &screenBuffer ) |> ignore
// 3. 変更したい拡張情報を作成
// カラーテーブル番号0 に白色を設定
screenBuffer.colorScheme.black <- {Red=byte 255;Green=byte 255;Blue=byte 255}
// カラーテーブル番号15 に黒色を設定
screenBuffer.colorScheme.white <- {Red=byte 0 ;Green=byte 0 ;Blue=byte 0 }
// 4. コンソール画面バッファーの拡張情報を変更する
SetConsoleScreenBufferInfoEx(GetStdHandle(STD_OUTPUT_HANDLE), &screenBuffer ) |> ignore
// 5. コンソールの背景色・前景色を設定
// ここでは背景色をカラーテーブル番号0 に設定
// ここでは前景色をカラーテーブル番号15に設定
Console.BackgroundColor <- ConsoleColor.Black
Console.ForegroundColor <- ConsoleColor.White
"""
(。・ω・。)ノ hello world!
""" |> printfn "%s"
DLL取込み部分
ColorScheme
部分で@haxe
さんよりアドバイス頂き改善しました。ありがとうございます!
module DllImported =
open System
open System.Runtime.InteropServices
[<Struct; StructLayout(LayoutKind.Sequential, Size = 4)>]
type RGB = {
Red : byte
Green : byte
Blue : byte
}
[<Struct; StructLayout(LayoutKind.Sequential)>]
type ColorScheme = {
mutable black : RGB
mutable darkBlue : RGB
mutable darkGreen : RGB
mutable darkCyan : RGB
mutable darkRed : RGB
mutable darkMagenta : RGB
mutable darkYellow : RGB
mutable gray : RGB
mutable darkGray : RGB
mutable blue : RGB
mutable green : RGB
mutable cyan : RGB
mutable red : RGB
mutable magenta : RGB
mutable yellow : RGB
mutable white : RGB
}
[<Struct; StructLayout(LayoutKind.Sequential)>]
type COORD = { X : int16; Y : int16 }
[<Struct; StructLayoutAttribute(LayoutKind.Sequential)>]
type SMALL_RECT = { Left : int16; Top : int16; Right : int16; Bottom : int16 }
[<Struct; StructLayoutAttribute(LayoutKind.Sequential)>]
type CONSOLE_SCREEN_BUFFER_INFOEX =
val mutable cbSize : int
val mutable dwSize : COORD
val mutable dwCursorPosition : COORD
val mutable wAttributes : int16
val mutable srWindow : SMALL_RECT
val mutable dwMaximumWindowSize : COORD
val mutable wPopupAttributes : int16
val mutable bFullscreenSupported : bool
val mutable colorScheme : ColorScheme
[<DllImportAttribute("kernel32.dll",SetLastError=true)>]
extern IntPtr GetStdHandle(int nStdHndle)
[<DllImportAttribute("kernel32.dll",SetLastError=true)>]
extern IntPtr GetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFOEX& ConsoleScreenBufferInfo)
[<DllImportAttribute("kernel32.dll",SetLastError=true)>]
extern IntPtr SetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFOEX& ConsoleScreenBufferInfo)
その他
下記にサンプルプログラム置いてます
(。・ω・。)ノヨカッタラミテネ
それでは!よいクリスマスを🎄