SMRAH1
دوشنبه 20 آبان 1387, 20:21 عصر
قطعا تاکنون در برنامه هايتان،از فونت خاصي استفاده کرده ايد که از نصب بودن آن روي سيسم هدف،اطمينان نداشته ايد.چه راهکاري را در پيش گرفته ايد؟آيا با ساختن يک Installer اقدام به نصب فونت کرده ايد!آيا از کاربر در خواسته کرده ايد که فونت مورد نياز را نصب کند! يا ...
در اين نوشتار به دنبال آن هستيم که اطلاعاتي راجع به موارد زير بدست آوريم:
1) آيا فونت هاي مورد نظر در سيستم موجود است؟
2) چگونه از فونت هاي سفارشي خود استفاده کنيم؟
آيا فونت هاي مورد نظر در سيستم موجود است؟
همانگونه که اطلاع داريد،به محض بارگذاري ويندوز،سيستم عامل فهرستي از فونت هايي که آماده به کار هستند در اختيار کاربر قرار مي دهد.براي تشخيص وجود يا عدم وجود فونت مورد نظر ما (که نام آن را مي دانيم)،يکي از دو راه کار زير توصيه مي شود:
1) در System.Drawing.Text کلاس InstalledFontCollection مي تواند فهرستي از فونت هاي موجود روي سيستم (البته فقط فونت هاي TrueType) بر گرداند.براي استفاده از اين ساختار ،ابتدا يک نمونه از اين کلاس ايجاد کرده و سيس خصوصيت Families آن که يک آرايه از FontFamily ها را ارائه مي کند،مورد استفاده قرار دهيد.هر عضو اين آرايه (FontFamily) داراي خصوصياتي براي دريافت اطلاعات فونت از جمله خصوصيت Name که نام فونت را بر مي گرداند، مي باشد.در نتيجه با متدي شبيه متد زير مي توان از وجود فونت مورد نظر خود (البته با داشتن نام آن) اطمينان حاصل کرد.
public bool FontIsAvailable(string strFontName)
{
InstalledFontCollection AllFonts = new InstalledFontCollection();
foreach (FontFamily ff in AllFonts.Families)
if (ff.Name == strFontName)
return true;
return false;
}2) راه ديگر تست وجود فونت مورد نظر (تکرار مي شود که فقط فونت هاي TrueType)،ساختن يک نمونه از آن نوع فونت است.يعني خط زير
Font f = new Font("Name", Size);که در آن Name ،نام فونت بوده (مثلا Tahama) و size نيز اندازه مورد نظر به point (يک نوع واحد اندازه گيري) مي باشد.براي تست، بهتر است مقدار يک داده شود، چون فقط مي خواهيم تست وجود انجام دهيم و اندازه آن مهم نيست.البته به size نبايد مقدار صفر يا منفي اختصاص داد چون باعث ايجاد يک استثناي ArgumentException مي شود.با رعايت اين نکات،يکي از سه اتفاق زير رخ خواهد داد:
الف) يک استثنا رخ مي دهد (در اين رابطه مطلبي نديده ام و فقط تجربه است) : اين در حالتي است که فونت مورد نظر موجود است ولي نمي تواند يک نمونه از آن بسازد! مثلا فونت Aharoni باعث ايجاد يک چنين استثنايي مي شود.اين استثنا از آنجا ناشي مي شود که اين فونت داراي Regular style نيست و چون ساخت يک فونت توسط خط بالا،در نظر دارد که يک فونت با حالت Regular بسازد،اين استثنا رخ مي دهد.در نتيجه اين فونت موجود است!
ب) فونتي مي سازد که داراي نامي هماهنگ با نام درخواستي ماست : در اين حالت ساخت يک نمونه با موفقيت همراه بوده و قطعا فونت مورد نظر ما موجود است.
ج) فونتي مخالف فونت مورد نظر ما ساخته مي شود : پس از ساخت ،چنانچه Name فونت ساخته شده مخالف نام درخواستي ما باشد،به اين معني است که فونت مود نظر ما موجود نيست.به عبارت ديگر هنگامي که درخواست ساخت فونتي با نام دلخواه (مثلا MyFont) داشته باشيم و سيستم نتواند آن را توليد کند،فونت پيشفرض (معمولا Microsift Sans sherif) را توليد مي کند.در نتيجه فونت مورد نظر ما موجود نيست!
چگونه از فونت هاي سفارشي خود استفاده کنيم؟
براي استفاده از فونت مورد نظر خود در برنامه، دو راهکار وجود دارد:
1) نصب فونت در سيستم: در اين راهکار پس از اجراي برنامه،و تست وجود يا عدم وجود فونت مورد نظر،پس از اطمينان از عدم وجود فونت مورد نظر،مي توان آن را درسيستم هدف نصب کرد! در اين روش بايد از تابع API ويندوز به نام AddFontResource که در gdi32.dll موجود است،استفاده کنيم.همانطور که مي دانيد براي استفاده از توابع API ويندوز در برنامه هاي NET. ،ابتدا بايد آنها را Import کنيم،چيزي شبيه به اين:
[DllImport("gdi32")]
private static extern int AddFontResource(string strFontFilePath);که در آن تابع AddFontResource که يک رشته حاوي مسير فايل فونت مورد نظر است،دريافت و مقدار int بر ميگرداند را معرفي کرده ايم.عبارت الزامي extern ،تاکيد بر اين موضوع است که متد مذبور از خارج از برنامه (يک API ويندوز يا يک اسمبلي دات نت) فراخواني مي شود.همچنين دسترسي به اين متد بايد حتما static نيز باشد (چون موجود است و از خارج فراخواني مي شود) و در هنگام بارگذاري برنامه يک نمونه دسترسي به آن به حالت استاتيک،ايجاد مي شود.براي Import متد،نيازي نيست که حتما Private باشند بلکه مي توانند public يا .. هم باشند.مقدار بازگشتي AddFontResource نيز ،در صورت موفقيت غير صفر بوده و در صورت عدم موفقيت صفر است.
در رابطه با اين تابع، پنج نکته وجود دارد که عبارتند از :
الف) اطلاعات هر فونت با توجه به مسير آن ذخيره مي شود به عبارت ديگر اگر فونتي با نام MY_Font که در مسير C:\MyFontPath\MyFont.ttf موجود است را به وسيله AddFontResource در سيستم ثبت کنيم،و سپس فايل C:\MyFontPath\MyFont.ttf را حذف نماييم،با آنکه سيستم عامل نام فونت MY_Font را در فهرست فونت ها دارد،اما به دليل حذف فايل حاوي آن،نمي تواند آن را ايجاد نمايد! براي رفع اين مشکل پيشنهاد مي شود که فونت مورد نظر را ابتدا در پوشه فونتها در مسير windir\Fonts کپي کرده و سپس اقدام به نصب آن با توجه به همان مسير windir\Fonts نماييد.
ب) نصب فونت با استفاده از AddFontResource ،باعث ثبت فونت و نصب آن در ويندوز فعال جاري شده و با Restart ويندوز،در دسترس نخواهد بود.براي ثبت فونت به شکلي که در Restart ويندوز نيز در دسترسي باشد،بايد آن را در رجيستري،به شکل دستي،ثبت نمود.اين اطلاعات در مسير
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fontsدر رجيستري ثبت مي شود.در اين مسير،بايد ابتدا يک مقدار از نوع REG_SZ ايجاد کنيم.Name يا نام اين مقدار مهم نيست (هرچه مي تواند باشد) ولي Data يا اطلاعات آن براي يافتن فونت هاي در دسترس، مهم است.Data هر کليد شامل نام فايل فونت مورد نظر است.چنانچه اين فايل در windir\Fonts،موجود باشد،کافيست نام فايل آن را وارد کنيد (TAHOMA.TTF) و اگر در مسير ديگري قرار دارد،بايد حتما مسير کامل آن را درج کنيد (C:\MyFontPath\MyFont.ttf).تاکيد مي شود که اطلاعات اين کليد رجيستري فقط در هر بار Restart بازخواني شده تا اطلاعات فونت در درسترس ،بازيابي شود و پس از بارگذاري کامل ويندوز،براي افزودن يک فونت به فهرست فونت هاي جاري سيستم حتما بايد AddFontResource را فراخواني کرد.
ج) چنانچه بخواهيم فونت نصب شده را Uninsatll کنيم،بايد از تابع RemoveFontResource استفاده کنيم.براي اطلاعات بيشتر مي توان به MSDN مراجعه کرد.توجه به اين موضوع که حتما رد پاي فونت را از رجيستري نيز پاک شود،ضروريست (به قسمت ب مراجعه شود).
د) تابع AddFontResource ،فقط فونت را در سيستم نصب مي کند،ولي بايد به نرم افزارهاي باز ديگر اطلاع دهيد که فونت جديد نصب شده و خود را به روز کنند!براي اينکار بايد توسط متد SendMessage (از API هاي ويندوز) پيغام WM_FONTCHANGE را به تمام پنجره هاي سطح بالا ارسال کند.براي پارامتر دست انداز پنجره (HWND) مي توان از HWND_BROADCAST استفاده کرد.
ه) مطابق نکته د ،با آنکه تمام پنجره هاي ويندوز،از اين تغيير مطلع مي شوند،ولي برنامه هاي دات نت نمي توانند از اين تغيير اطلاع يابند.دليل آن وجود يک باگ در +GDI است که مطابق يک جستجو که انجام دادم،از سال 2004 مطرح شده و تا 2006 (http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic42273.aspx)به عنوان يک باگ ،به شکل غير رسمي،منتشر شده است.البته از وجود آن در vista بي خبرم (هر چند که از عدم وجود آن نيز بي اطلاع هستم!).اثر آن در دات نت به اين شکل است که با وجود ثبت فونت در سيستم،شي InstalledFontCollection ،فقط اطلاعات فونت هايي را در دسترس دارد که قبل از اجراي برنامه در سيستم ثبت شده بودند.در نتيجه چنانچه در برنامه دات نتي خود،اقدام به نصب فونت کرديم،حتما بايد برنامه خود را Resatrt کنيم.همچنين براي اطلاع تمام برنامه هاي دات نتي ديگر آنها هم بايد دوباره اجرا شوند ،در غير اينصورت از وجود فونت جديد بي اطلاع خواند بود.
با توجه به نکات مطرح شده قطعه برنامه زير براي نصب قونت در سيستم پيشنهاد مي شود :
public static bool InstallFontInWindows(string strFontFilePath)
{
string strFileName = Path.GetFileName(strFontFilePath);
try
{
//1)Step 1 : Copy font file to Fonts directory
string strFontsPathFile = Environment.GetEnvironmentVariable("windir")
+ @"\Fonts\" + strFileName;
File.Copy(strFontFilePath, strFontsPathFile, true);
//2)Step 2 : Install font in resource of MS-Windows
if (AddFontResource(strFontsPathFile) == 0)
return false;
//3)Step 3 : Set registry information of new installed font for use
RegistryKey reg = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", true);
reg.SetValue(strFileName.Split('.')[0] + " (TrueType)", strFileName);
reg.Close();
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
}
catch (Exception exc)
{
return false;
}
return true;
}البته تاکيد مي شود که بعد از نصب فونت،حتما برنامه خود را (و نه ويندوز را) Restart کنيد (يا از کاربر بخواهيد که اين کار را انجام دهد).توجه به اين نکته ضروريست که کدهاي بالا داراي خصوصياتي است که نياز به دسترسي هاي سطح Admin دارد (مثلا باز کردن کليد رجيستري در LocalMechine براي نوشتن!).در اين صورت (عدم اجازه کاربر جاري براي اجراي اين فرآيند ها)،سيستم يک استثنا از نوع SecurityException ايجاد مي کند.
2) شما مي توانيد بدون نصب يک فونت در سيستم آن را استفاده کنيد!در واقع +GDI و NET. به شما اين اجازه را مي دهند.در دات نت کلاسي به نام PrivateFontCollection به همين منظور تدارک ديده شده است.ابتدا يک نمونه از اين کلاس ايجاد کنيد.حالا متد AddFontFile اين نمونه را به همراه نام فايل فونت مورد نظر فراخواني کنيد.در اين صورت فونت مورد نظر براي اين نمونه از PrivateFontCollection بار گذاري مي شود.به هر دليل،PrivateFontCollection نتواند فونت را بارگذاري کند يک استثنا از نوع FileNotFoundException روي خواهد داد(حتي اگر فرمت فايل صحيح نباشد!).تا هنگامي که اين نمونه موجود است،مي توان از فونت بار گذاري شده در آن استفاده کرد.براي اين منظور از خصوصيتي Families آن استفاده کنيد.توجه کنيد که در اين حالت فقط فونت براي برنامه،آن هم تا هنگامي که نمونه اي از PrivateFontCollection که در آن فونت را بارگذاري نموده ايد در دسترس باشد،قابل دسترسي است و درسيستم اين فونت در دسترس نخواهد بود.در ضمن تاکيد مي شود که اين کلاس فقط براي فونتهاي TrueType کاربر دارد.
پي نوشت :
* فونت TrueType : در سيستم عامل هاي امروزي ،فونت ها را بر اساس ساختار ترسيم و همچنين فايل محتويات آن، تقسيم بندي مي شوند.بر اساس ساختار، فونت هاي به سه دسته MonoSpace و Serif و Sans Serif تقسيم بندي مي شوند.فونت هاي بر اساس فايل هايشان نيز به دسته هاي متعددي تقسيم مي گردند که با پسوند هاي فايل محتويات آنها شناسايي مي گردند که از جمله آنها مي توان به fon ، fnt ، ttf ، ttc ، fot ، pfb ، pfm و ... اشاره کرد.برخي از فونت هاي ساختاري با يک پسوند مشخص مي شوند.مثلا پسوند fon براي فونتهاي MonoSpace (اينگونه فونت ها، نظير فونت هاي تحت داس ،داراي فضاي کاراکتري يکساني براي تمام کاراکتر ها هستند در نتيجه زيبايي کمتري دارند - نمونه اين فونت،فونت Terminal مي باشد).اما برخي ساختارها داراي پسوند هاي متعدد هستند.مثلا فونت TrueType که بهترين زيبايي را در فرايند رسم خود دارد،مي تواند داراي پسوند هاي ttf (مشهورترين پسوند) يا ttc يا ... باشد.
* نام فونت در داخل فايل حاوي فونت معرفي و معمولا با نام فايل محتوي فونت متفاوت است.
* مي توان به جاي AddFontResource از AddFontResourceEx هم استفاده کرد که البته تنظيمات پيشرفته تري در اختيار برنامه نويس خواهد گذارد.
* windir عبارت است از آدرس پوشه ويندوز،مثلا C:\WINDOWS .
* لطفا اگر دوستان از وجود يا عدم وجود باگ مطرح شده در قسمت ه بخش 'نصب فونت در سيستم' در ويندوز هاي XP SP3 يا Vista اطلاع دارند ما را هم بي خبر نگذارند.
* دوستاني که در WPF کار مي کنند حتما کلاس System.Windows.Media.Fonts را ملاحظه کنند.متد GetFontFamilies اين کلاس مي تواند فهرستي از فونت هاي موجود در يک پوشه را بار گذاري کند.
*اگر ايرادي در اين نوشتار ملاحظه مي کنيد،حتما اينجانب را باخبر سازيد.
موفق و پيروز باشيد
در اين نوشتار به دنبال آن هستيم که اطلاعاتي راجع به موارد زير بدست آوريم:
1) آيا فونت هاي مورد نظر در سيستم موجود است؟
2) چگونه از فونت هاي سفارشي خود استفاده کنيم؟
آيا فونت هاي مورد نظر در سيستم موجود است؟
همانگونه که اطلاع داريد،به محض بارگذاري ويندوز،سيستم عامل فهرستي از فونت هايي که آماده به کار هستند در اختيار کاربر قرار مي دهد.براي تشخيص وجود يا عدم وجود فونت مورد نظر ما (که نام آن را مي دانيم)،يکي از دو راه کار زير توصيه مي شود:
1) در System.Drawing.Text کلاس InstalledFontCollection مي تواند فهرستي از فونت هاي موجود روي سيستم (البته فقط فونت هاي TrueType) بر گرداند.براي استفاده از اين ساختار ،ابتدا يک نمونه از اين کلاس ايجاد کرده و سيس خصوصيت Families آن که يک آرايه از FontFamily ها را ارائه مي کند،مورد استفاده قرار دهيد.هر عضو اين آرايه (FontFamily) داراي خصوصياتي براي دريافت اطلاعات فونت از جمله خصوصيت Name که نام فونت را بر مي گرداند، مي باشد.در نتيجه با متدي شبيه متد زير مي توان از وجود فونت مورد نظر خود (البته با داشتن نام آن) اطمينان حاصل کرد.
public bool FontIsAvailable(string strFontName)
{
InstalledFontCollection AllFonts = new InstalledFontCollection();
foreach (FontFamily ff in AllFonts.Families)
if (ff.Name == strFontName)
return true;
return false;
}2) راه ديگر تست وجود فونت مورد نظر (تکرار مي شود که فقط فونت هاي TrueType)،ساختن يک نمونه از آن نوع فونت است.يعني خط زير
Font f = new Font("Name", Size);که در آن Name ،نام فونت بوده (مثلا Tahama) و size نيز اندازه مورد نظر به point (يک نوع واحد اندازه گيري) مي باشد.براي تست، بهتر است مقدار يک داده شود، چون فقط مي خواهيم تست وجود انجام دهيم و اندازه آن مهم نيست.البته به size نبايد مقدار صفر يا منفي اختصاص داد چون باعث ايجاد يک استثناي ArgumentException مي شود.با رعايت اين نکات،يکي از سه اتفاق زير رخ خواهد داد:
الف) يک استثنا رخ مي دهد (در اين رابطه مطلبي نديده ام و فقط تجربه است) : اين در حالتي است که فونت مورد نظر موجود است ولي نمي تواند يک نمونه از آن بسازد! مثلا فونت Aharoni باعث ايجاد يک چنين استثنايي مي شود.اين استثنا از آنجا ناشي مي شود که اين فونت داراي Regular style نيست و چون ساخت يک فونت توسط خط بالا،در نظر دارد که يک فونت با حالت Regular بسازد،اين استثنا رخ مي دهد.در نتيجه اين فونت موجود است!
ب) فونتي مي سازد که داراي نامي هماهنگ با نام درخواستي ماست : در اين حالت ساخت يک نمونه با موفقيت همراه بوده و قطعا فونت مورد نظر ما موجود است.
ج) فونتي مخالف فونت مورد نظر ما ساخته مي شود : پس از ساخت ،چنانچه Name فونت ساخته شده مخالف نام درخواستي ما باشد،به اين معني است که فونت مود نظر ما موجود نيست.به عبارت ديگر هنگامي که درخواست ساخت فونتي با نام دلخواه (مثلا MyFont) داشته باشيم و سيستم نتواند آن را توليد کند،فونت پيشفرض (معمولا Microsift Sans sherif) را توليد مي کند.در نتيجه فونت مورد نظر ما موجود نيست!
چگونه از فونت هاي سفارشي خود استفاده کنيم؟
براي استفاده از فونت مورد نظر خود در برنامه، دو راهکار وجود دارد:
1) نصب فونت در سيستم: در اين راهکار پس از اجراي برنامه،و تست وجود يا عدم وجود فونت مورد نظر،پس از اطمينان از عدم وجود فونت مورد نظر،مي توان آن را درسيستم هدف نصب کرد! در اين روش بايد از تابع API ويندوز به نام AddFontResource که در gdi32.dll موجود است،استفاده کنيم.همانطور که مي دانيد براي استفاده از توابع API ويندوز در برنامه هاي NET. ،ابتدا بايد آنها را Import کنيم،چيزي شبيه به اين:
[DllImport("gdi32")]
private static extern int AddFontResource(string strFontFilePath);که در آن تابع AddFontResource که يک رشته حاوي مسير فايل فونت مورد نظر است،دريافت و مقدار int بر ميگرداند را معرفي کرده ايم.عبارت الزامي extern ،تاکيد بر اين موضوع است که متد مذبور از خارج از برنامه (يک API ويندوز يا يک اسمبلي دات نت) فراخواني مي شود.همچنين دسترسي به اين متد بايد حتما static نيز باشد (چون موجود است و از خارج فراخواني مي شود) و در هنگام بارگذاري برنامه يک نمونه دسترسي به آن به حالت استاتيک،ايجاد مي شود.براي Import متد،نيازي نيست که حتما Private باشند بلکه مي توانند public يا .. هم باشند.مقدار بازگشتي AddFontResource نيز ،در صورت موفقيت غير صفر بوده و در صورت عدم موفقيت صفر است.
در رابطه با اين تابع، پنج نکته وجود دارد که عبارتند از :
الف) اطلاعات هر فونت با توجه به مسير آن ذخيره مي شود به عبارت ديگر اگر فونتي با نام MY_Font که در مسير C:\MyFontPath\MyFont.ttf موجود است را به وسيله AddFontResource در سيستم ثبت کنيم،و سپس فايل C:\MyFontPath\MyFont.ttf را حذف نماييم،با آنکه سيستم عامل نام فونت MY_Font را در فهرست فونت ها دارد،اما به دليل حذف فايل حاوي آن،نمي تواند آن را ايجاد نمايد! براي رفع اين مشکل پيشنهاد مي شود که فونت مورد نظر را ابتدا در پوشه فونتها در مسير windir\Fonts کپي کرده و سپس اقدام به نصب آن با توجه به همان مسير windir\Fonts نماييد.
ب) نصب فونت با استفاده از AddFontResource ،باعث ثبت فونت و نصب آن در ويندوز فعال جاري شده و با Restart ويندوز،در دسترس نخواهد بود.براي ثبت فونت به شکلي که در Restart ويندوز نيز در دسترسي باشد،بايد آن را در رجيستري،به شکل دستي،ثبت نمود.اين اطلاعات در مسير
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fontsدر رجيستري ثبت مي شود.در اين مسير،بايد ابتدا يک مقدار از نوع REG_SZ ايجاد کنيم.Name يا نام اين مقدار مهم نيست (هرچه مي تواند باشد) ولي Data يا اطلاعات آن براي يافتن فونت هاي در دسترس، مهم است.Data هر کليد شامل نام فايل فونت مورد نظر است.چنانچه اين فايل در windir\Fonts،موجود باشد،کافيست نام فايل آن را وارد کنيد (TAHOMA.TTF) و اگر در مسير ديگري قرار دارد،بايد حتما مسير کامل آن را درج کنيد (C:\MyFontPath\MyFont.ttf).تاکيد مي شود که اطلاعات اين کليد رجيستري فقط در هر بار Restart بازخواني شده تا اطلاعات فونت در درسترس ،بازيابي شود و پس از بارگذاري کامل ويندوز،براي افزودن يک فونت به فهرست فونت هاي جاري سيستم حتما بايد AddFontResource را فراخواني کرد.
ج) چنانچه بخواهيم فونت نصب شده را Uninsatll کنيم،بايد از تابع RemoveFontResource استفاده کنيم.براي اطلاعات بيشتر مي توان به MSDN مراجعه کرد.توجه به اين موضوع که حتما رد پاي فونت را از رجيستري نيز پاک شود،ضروريست (به قسمت ب مراجعه شود).
د) تابع AddFontResource ،فقط فونت را در سيستم نصب مي کند،ولي بايد به نرم افزارهاي باز ديگر اطلاع دهيد که فونت جديد نصب شده و خود را به روز کنند!براي اينکار بايد توسط متد SendMessage (از API هاي ويندوز) پيغام WM_FONTCHANGE را به تمام پنجره هاي سطح بالا ارسال کند.براي پارامتر دست انداز پنجره (HWND) مي توان از HWND_BROADCAST استفاده کرد.
ه) مطابق نکته د ،با آنکه تمام پنجره هاي ويندوز،از اين تغيير مطلع مي شوند،ولي برنامه هاي دات نت نمي توانند از اين تغيير اطلاع يابند.دليل آن وجود يک باگ در +GDI است که مطابق يک جستجو که انجام دادم،از سال 2004 مطرح شده و تا 2006 (http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic42273.aspx)به عنوان يک باگ ،به شکل غير رسمي،منتشر شده است.البته از وجود آن در vista بي خبرم (هر چند که از عدم وجود آن نيز بي اطلاع هستم!).اثر آن در دات نت به اين شکل است که با وجود ثبت فونت در سيستم،شي InstalledFontCollection ،فقط اطلاعات فونت هايي را در دسترس دارد که قبل از اجراي برنامه در سيستم ثبت شده بودند.در نتيجه چنانچه در برنامه دات نتي خود،اقدام به نصب فونت کرديم،حتما بايد برنامه خود را Resatrt کنيم.همچنين براي اطلاع تمام برنامه هاي دات نتي ديگر آنها هم بايد دوباره اجرا شوند ،در غير اينصورت از وجود فونت جديد بي اطلاع خواند بود.
با توجه به نکات مطرح شده قطعه برنامه زير براي نصب قونت در سيستم پيشنهاد مي شود :
public static bool InstallFontInWindows(string strFontFilePath)
{
string strFileName = Path.GetFileName(strFontFilePath);
try
{
//1)Step 1 : Copy font file to Fonts directory
string strFontsPathFile = Environment.GetEnvironmentVariable("windir")
+ @"\Fonts\" + strFileName;
File.Copy(strFontFilePath, strFontsPathFile, true);
//2)Step 2 : Install font in resource of MS-Windows
if (AddFontResource(strFontsPathFile) == 0)
return false;
//3)Step 3 : Set registry information of new installed font for use
RegistryKey reg = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", true);
reg.SetValue(strFileName.Split('.')[0] + " (TrueType)", strFileName);
reg.Close();
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
}
catch (Exception exc)
{
return false;
}
return true;
}البته تاکيد مي شود که بعد از نصب فونت،حتما برنامه خود را (و نه ويندوز را) Restart کنيد (يا از کاربر بخواهيد که اين کار را انجام دهد).توجه به اين نکته ضروريست که کدهاي بالا داراي خصوصياتي است که نياز به دسترسي هاي سطح Admin دارد (مثلا باز کردن کليد رجيستري در LocalMechine براي نوشتن!).در اين صورت (عدم اجازه کاربر جاري براي اجراي اين فرآيند ها)،سيستم يک استثنا از نوع SecurityException ايجاد مي کند.
2) شما مي توانيد بدون نصب يک فونت در سيستم آن را استفاده کنيد!در واقع +GDI و NET. به شما اين اجازه را مي دهند.در دات نت کلاسي به نام PrivateFontCollection به همين منظور تدارک ديده شده است.ابتدا يک نمونه از اين کلاس ايجاد کنيد.حالا متد AddFontFile اين نمونه را به همراه نام فايل فونت مورد نظر فراخواني کنيد.در اين صورت فونت مورد نظر براي اين نمونه از PrivateFontCollection بار گذاري مي شود.به هر دليل،PrivateFontCollection نتواند فونت را بارگذاري کند يک استثنا از نوع FileNotFoundException روي خواهد داد(حتي اگر فرمت فايل صحيح نباشد!).تا هنگامي که اين نمونه موجود است،مي توان از فونت بار گذاري شده در آن استفاده کرد.براي اين منظور از خصوصيتي Families آن استفاده کنيد.توجه کنيد که در اين حالت فقط فونت براي برنامه،آن هم تا هنگامي که نمونه اي از PrivateFontCollection که در آن فونت را بارگذاري نموده ايد در دسترس باشد،قابل دسترسي است و درسيستم اين فونت در دسترس نخواهد بود.در ضمن تاکيد مي شود که اين کلاس فقط براي فونتهاي TrueType کاربر دارد.
پي نوشت :
* فونت TrueType : در سيستم عامل هاي امروزي ،فونت ها را بر اساس ساختار ترسيم و همچنين فايل محتويات آن، تقسيم بندي مي شوند.بر اساس ساختار، فونت هاي به سه دسته MonoSpace و Serif و Sans Serif تقسيم بندي مي شوند.فونت هاي بر اساس فايل هايشان نيز به دسته هاي متعددي تقسيم مي گردند که با پسوند هاي فايل محتويات آنها شناسايي مي گردند که از جمله آنها مي توان به fon ، fnt ، ttf ، ttc ، fot ، pfb ، pfm و ... اشاره کرد.برخي از فونت هاي ساختاري با يک پسوند مشخص مي شوند.مثلا پسوند fon براي فونتهاي MonoSpace (اينگونه فونت ها، نظير فونت هاي تحت داس ،داراي فضاي کاراکتري يکساني براي تمام کاراکتر ها هستند در نتيجه زيبايي کمتري دارند - نمونه اين فونت،فونت Terminal مي باشد).اما برخي ساختارها داراي پسوند هاي متعدد هستند.مثلا فونت TrueType که بهترين زيبايي را در فرايند رسم خود دارد،مي تواند داراي پسوند هاي ttf (مشهورترين پسوند) يا ttc يا ... باشد.
* نام فونت در داخل فايل حاوي فونت معرفي و معمولا با نام فايل محتوي فونت متفاوت است.
* مي توان به جاي AddFontResource از AddFontResourceEx هم استفاده کرد که البته تنظيمات پيشرفته تري در اختيار برنامه نويس خواهد گذارد.
* windir عبارت است از آدرس پوشه ويندوز،مثلا C:\WINDOWS .
* لطفا اگر دوستان از وجود يا عدم وجود باگ مطرح شده در قسمت ه بخش 'نصب فونت در سيستم' در ويندوز هاي XP SP3 يا Vista اطلاع دارند ما را هم بي خبر نگذارند.
* دوستاني که در WPF کار مي کنند حتما کلاس System.Windows.Media.Fonts را ملاحظه کنند.متد GetFontFamilies اين کلاس مي تواند فهرستي از فونت هاي موجود در يک پوشه را بار گذاري کند.
*اگر ايرادي در اين نوشتار ملاحظه مي کنيد،حتما اينجانب را باخبر سازيد.
موفق و پيروز باشيد