星期五, 9月 17, 2021

[C#] 字型安裝

把字型加入專案內,並在程式啟動時把安裝至 Windows Fonts 內

把字型加入 Resource.resx 內

[C#] 字型安裝-4

把字型加入後,在 Resource 資料夾內可以找到檔案,並把該檔案屬性建置動作,設定為內嵌資源

[C#] 字型安裝-5

在程式執行時,偵測字型是否安裝,沒有就進行字型安裝
using System;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Windows.Forms;

namespace InstallFont
{
    public partial class Form1 : Form
    {
        [DllImport("gdi32")]
        public static extern int AddFontResource(string lpFileName);

        private const int WM_FONTCHANGE = 0x001D;
        private const int HWND_BROADCAST = 0xffff;

        [DllImport("user32.dll")]
        public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int WriteProfileString(string lpszSection, string lpszKeyName, string lpszString);

        public Form1()
        {
            InitializeComponent();

            string FontName = "Gulim.ttf";
            string FontFullName = Path.Combine(Path.GetTempPath(), FontName);

            GetFontFromResource(FontFullName);

            InstallFont(FontFullName);
            
            SetFont();
        }

        /// <summary>
        /// 把內嵌字型檔案抓出來存放在本機暫存區
        /// </summary>
        /// <param name="FontFullName">字型檔案完整路徑</param>
        private void GetFontFromResource(string FontFullName)
        {
            if (File.Exists(FontFullName)) return;

            byte[] FontData = Properties.Resources.gulim;
            File.WriteAllBytes(FontFullName, FontData);
        }

        /// <summary>
        /// 安裝字型
        /// </summary>
        /// <param name="FontFullName">字型檔案完整路徑</param>
        private void InstallFont(string FontFullName)
        {
            string FontNameWithoutExtension = Path.GetFileNameWithoutExtension(FontFullName);
            string FontName = Path.GetFileName(FontFullName);

            if (IsFontInstalled(FontNameWithoutExtension))
            {
                MessageBox.Show("字型已存在");
                return;
            }

            if (IsAdminstrator() == false)
            {
                MessageBox.Show("當前使用者無管理員許可權,無法安裝字型");
                return;
            }

            string WindowsFontFullName = Path.Combine(SystemPath_Fonts(), FontName);

            // 將字型檔案複製到系統字型資料夾
            File.Copy(FontFullName, WindowsFontFullName);

            // 把字型加入 System Font Table 內
            AddFontResource(WindowsFontFullName);

            // 廣播告知字型有所變更
            SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);

            // 安裝字型,寫進機碼內就是
            string Section = "Fonts"; // 不區分大小寫
            string KeyName = FontNameWithoutExtension + " (TrueType)";
            WriteProfileString(Section, KeyName, FontName);
        }

        private string SystemPath_Fonts()
        {
            return Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
        }

        private bool IsFontInstalled(string FontNameWithoutExtension)
        {
            InstalledFontCollection installedFontCollection = new InstalledFontCollection();
            return installedFontCollection.Families.Any(font => font.Name == FontNameWithoutExtension);
        }

        private bool IsAdminstrator()
        {
            WindowsIdentity identity = WindowsIdentity.GetCurrent();
            WindowsPrincipal principal = new WindowsPrincipal(identity);
            return principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
        
        private void SetFont()
        {
            lblGulim.Font = new Font(this.FontName, 20);
        }        
    }
}
AddFontResource 重點:要完成機碼註冊才算是完成字型安裝
This function installs the font only for the current session. When the system restarts, the font will not be present. To have the font installed even after restarting the system, the font must be listed in the registry.

A font listed in the registry and installed to a location other than the %windir%\fonts\ folder cannot be modified, deleted, or replaced as long as it is loaded in any session. In order to change one of these fonts, it must first be removed by calling RemoveFontResource, removed from the font registry (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts), and the system restarted. After restarting the system, the font will no longer be loaded and can be changed.

SendMessageWM_FONTCHANGE 重點

An application that adds or removes fonts from the system (for example, by using the AddFontResource or RemoveFontResource function) should send this message to all top-level windows.

To send the WM_FONTCHANGE message to all top-level windows, an application can call the SendMessage function with the hwnd parameter set to HWND_BROADCAST.
WriteProfileStringA function (winbase.h) 重點:參數和機碼的顏色對應

[C#] 字型安裝-1

字型名稱確認方式,要以字型檔案內名稱為主,以下圖來看,檔案總管內顯示的是 [Guilm 標準],但是字型檔案內是 [Guilm]

   [C#] 字型安裝-2

程式執行結果

     [C#] 字型安裝-3

沒有留言:

張貼留言