Last active
October 25, 2024 02:11
-
-
Save KOZ60/7fcdcb1a067fa2a1194b447d37e58494 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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