Skip to content

Instantly share code, notes, and snippets.

@KOZ60
Last active October 25, 2024 02:11
Show Gist options
  • Save KOZ60/7fcdcb1a067fa2a1194b447d37e58494 to your computer and use it in GitHub Desktop.
Save KOZ60/7fcdcb1a067fa2a1194b447d37e58494 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[DesignerCategory("code")]
public class FontDialogEx : FontDialog
{
public FontDialogEx() { }
// スタイル名
private enum WeightStyles
{
THIN = 100,
EXTRALIGHT = 200,
ULTRALIGHT = 200,
LIGHT = 300,
SEMILIGHT = 350,
NORMAL = 400,
REGULAR = 400,
MEDIUM = 500,
SEMIBOLD = 600,
DEMIBOLD = 600,
BOLD = 700,
EXTRABOLD = 800,
ULTRABOLD = 800,
HEAVY = 900,
BLACK = 900
}
// ダイアログで選択したとき フォント名と lfWeight の組み合わせを登録して次回から使用する。
// 既知のフォントはあらかじめ登録しておく
private static readonly Dictionary<string, int> dicWeight
= new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) {
{ "Nirmala UI Semilight", 350 },
{ "Microsoft JhengHei Light", 290 },
{ "Microsoft JhengHei UI Light", 290 },
{ "Segoe UI Light", 300 },
{ "Segoe UI Semibold", 600 },
{ "Segoe UI Black", 900 }
};
private static NativeMethods.LOGFONT GetLogFont(Font font) {
// 既知のフォント名から lfWeight を設定する
var logFont = new NativeMethods.LOGFONT();
font.ToLogFont(logFont);
lock (dicWeight) {
if (dicWeight.TryGetValue(logFont.lfFaceName, out int weight)) {
logFont.lfWeight = weight;
return logFont;
}
}
// フォント名からスタイルを検索して lfWeight を設定する
var faceName = logFont.lfFaceName.ToUpper();
foreach (WeightStyles style in Enum.GetValues(typeof(WeightStyles))) {
if (faceName.IndexOf(" " + style.ToString()) >= 0) {
logFont.lfWeight = (int)style;
break;
}
}
return logFont;
}
protected override bool RunDialog(IntPtr hWndOwner) {
var hookProcPtr = new NativeMethods.WndProc(HookProc);
var cf = new NativeMethods.CHOOSEFONT();
var logFontPtr = IntPtr.Zero;
try {
logFontPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NativeMethods.LOGFONT)));
var logFont = GetLogFont(Font);
Marshal.StructureToPtr(logFont, logFontPtr, false);
cf.hwndOwner = hWndOwner;
cf.hDC = IntPtr.Zero;
cf.lpLogFont = logFontPtr;
cf.Flags = Options | NativeMethods.CF_INITTOLOGFONTSTRUCT | NativeMethods.CF_ENABLEHOOK;
if (MinSize > 0 || MaxSize > 0) {
cf.Flags |= NativeMethods.CF_LIMITSIZE;
}
if (ShowColor || ShowEffects) {
cf.rgbColors = ColorTranslator.ToWin32(Color);
} else {
cf.rgbColors = ColorTranslator.ToWin32(SystemColors.ControlText);
}
cf.lpfnHook = hookProcPtr;
cf.hInstance = NativeMethods.GetModuleHandle(null);
cf.nSizeMin = MinSize;
if (MaxSize == 0) {
cf.nSizeMax = int.MaxValue;
} else {
cf.nSizeMax = MaxSize;
}
if (!NativeMethods.ChooseFont(cf)) return false;
logFont = Marshal.PtrToStructure<NativeMethods.LOGFONT>(logFontPtr);
if (logFont.lfFaceName != null && logFont.lfFaceName.Length > 0) {
UpdateFont(logFont);
UpdateColor(cf.rgbColors);
}
return true;
} finally {
if (logFontPtr != IntPtr.Zero) {
Marshal.FreeCoTaskMem(logFontPtr);
}
}
}
protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) {
switch (msg) {
case NativeMethods.WM_COMMAND:
if ((int)wparam == 0x402) {
NativeMethods.LOGFONT lf = new NativeMethods.LOGFONT();
NativeMethods.SendMessage(hWnd, NativeMethods.WM_CHOOSEFONT_GETLOGFONT, 0, lf);
UpdateFont(lf);
}
break;
}
return base.HookProc(hWnd, msg, wparam, lparam);
}
private void UpdateFont(NativeMethods.LOGFONT logFont) {
// LOGFONT から Font を作成する
Font = Font.FromLogFont(logFont);
// Font から LOGFONT を取り出す
var gdipLogFont = GetLogFont(Font);
Debug.Print($"{logFont.lfFaceName} {logFont.lfWeight}:{gdipLogFont.lfWeight}");
// lfWeight が違う場合は保存する
if (gdipLogFont.lfWeight != logFont.lfWeight) {
lock (dicWeight) {
dicWeight[logFont.lfFaceName] = logFont.lfWeight;
}
}
}
private void UpdateColor(int rgb) {
if (ColorTranslator.ToWin32(Color) != rgb) {
Color = ColorTranslator.FromOle(rgb);
}
}
}
internal static class NativeMethods
{
public const int
WM_COMMAND = 0x0111,
WM_USER = 0x0400,
WM_CHOOSEFONT_GETLOGFONT = WM_USER + 1;
public const int
CF_INITTOLOGFONTSTRUCT = 0x00000040,
CF_ENABLEHOOK = 0x00000008,
CF_LIMITSIZE = 0x00002000;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class LOGFONT
{
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string lfFaceName;
public LOGFONT() { }
public LOGFONT(LOGFONT lf) {
lfHeight = lf.lfHeight;
lfWidth = lf.lfWidth;
lfEscapement = lf.lfEscapement;
lfOrientation = lf.lfOrientation;
lfWeight = lf.lfWeight;
lfItalic = lf.lfItalic;
lfUnderline = lf.lfUnderline;
lfStrikeOut = lf.lfStrikeOut;
lfCharSet = lf.lfCharSet;
lfOutPrecision = lf.lfOutPrecision;
lfClipPrecision = lf.lfClipPrecision;
lfQuality = lf.lfQuality;
lfPitchAndFamily = lf.lfPitchAndFamily;
lfFaceName = lf.lfFaceName;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class CHOOSEFONT
{
public int lStructSize = Marshal.SizeOf(typeof(CHOOSEFONT));
public IntPtr hwndOwner;
public IntPtr hDC;
public IntPtr lpLogFont;
public int iPointSize = 0;
public int Flags;
public int rgbColors;
public IntPtr lCustData = IntPtr.Zero;
public WndProc lpfnHook;
public string lpTemplateName = null;
public IntPtr hInstance;
public string lpszStyle = null;
public short nFontType = 0;
public short ___MISSING_ALIGNMENT__ = 0;
public int nSizeMin;
public int nSizeMax;
}
[DllImport("comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool ChooseFont([In, Out] CHOOSEFONT cf);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string modName);
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, [In, Out] LOGFONT lParam);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment