none
How to tell by vba if a character is supported by its current font set or not? RRS feed

  • Question

  • We know that MS Word displays those characters (in my case, FarEast ones) not supported by its font as blanks or retangles. How could I use vba to quickly locate these improperly displayed characters? I googled and but could not find a successful solution, some useful information are (http://efreedom.com/Question/1-1439551/Get-Supported-Characters-Font-CSharp).

    TIA for any suggestions.
    Monday, January 3, 2011 8:12 AM

Answers

  • Hi Pkusogno,

    It seems that your project lack some assembly references, I use Visual Studio 2010:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Media;
    using System.Runtime.InteropServices;

    namespace CSFontLibForVBA
    {
        [ClassInterface(ClassInterfaceType.AutoDual)]
        [ComVisible(true)]
        public class DetectFont
        {
            public string GetSupportedCharacterOfAFont(string fontPath)
            {
                var families = Fonts.GetFontFamilies(fontPath);
                StringBuilder sb = new StringBuilder();
                foreach (FontFamily family in families)
                {
                    var typefaces = family.GetTypefaces();
                    foreach (Typeface typeface in typefaces)
                    {
                        GlyphTypeface glyph;
                        typeface.TryGetGlyphTypeface(out glyph);
                        IDictionary<intushort> characterMap = glyph.CharacterToGlyphMap;

                        foreach (KeyValuePair<intushort> kvp in characterMap)
                        {
                            //Console.WriteLine(String.Format("{0}:{1}", kvp.Key, kvp.Value));
                            sb.Append(kvp.Key.ToString());
                            sb.Append(":");
                            sb.Append(kvp.Value.ToString());
                            sb.Append("\n");
                        }

                    }
                }

                return sb.ToString();
            }
        }
    }

    I didn't use Portable Microsoft Visual C# 2008 Express Edition, it may not add these reference to your  project.

    Hope it can help you and feel free to follow up after you tried.

    Best Regards,


    Bruce Song [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Proposed as answer by Bruce Song Thursday, January 13, 2011 2:44 AM
    • Marked as answer by Bruce Song Thursday, January 13, 2011 10:35 AM
    Tuesday, January 11, 2011 10:51 AM

All replies

  • Hi Pkusogno,

    Thank you for posting and we are glad to help with you.

    After reading your post, I knew that you want to know whether a character is supported by it's current font via VBA. If I have misunderstood you, please let me know.

    After doing some research, I also found it is difficult to do it via VBA. But thank you for providing the CSharp code about doing this. And I think it can be achieved through calling .Net Dll in VBA. If someone can provide the VBA code directly achieve the function, it will be nicer.

    Below are the steps for calling the function in .Net Dll:

    1. Create a CSharp Library Project, and add the following code to DetectFont.cs

        [ClassInterface(ClassInterfaceType.AutoDual)]
        [ComVisible(true)]
        public class DetectFont
        {
            public string GetSupportedCharacterOfAFont(string fontPath)
            {
                var families = Fonts.GetFontFamilies(fontPath);
                StringBuilder sb = new StringBuilder();
                foreach (FontFamily family in families)
                {
                    var typefaces = family.GetTypefaces();
                    foreach (Typeface typeface in typefaces)
                    {
                        GlyphTypeface glyph;
                        typeface.TryGetGlyphTypeface(out glyph);
                        IDictionary<intushort> characterMap = glyph.CharacterToGlyphMap;

                        foreach (KeyValuePair<intushort> kvp in characterMap)
                        {
                            //Console.WriteLine(String.Format("{0}:{1}", kvp.Key, kvp.Value));
                            sb.Append(kvp.Key.ToString());
                            sb.Append(":");
                            sb.Append(kvp.Value.ToString());
                            sb.Append("\n");
                        }

                    }
                }

                return sb.ToString();
            }
        }

    2. Open the property of the project, click Build->Register for COM interop to make sure the checkbox is checked.

    3. Build the project.

    4. Using VBA to call the .Net Dll

    Private Sub CommandButton1_Click()
    Dim testClass As New CSFontLibForVBA.DetectFont
    Dim fontPath As String
    Dim result As String
    fontPath = "C:\WINDOWS\Fonts\Arial.TTF"
    result = testClass.GetSupportedCharacterOfAFont(fontPath)
    Debug.Print result
    End Sub

    I hope it can help you and feel free to follow up.

    Best Regards,

     


    Bruce Song [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, January 5, 2011 6:00 AM
  • Hi Bruce,

    Thank you for your help with the code.

    I'm a bit new for windows programming - learn a little vba by myself, but not that experienced in handling sophisticated problems. I'll try to carry out the above steps and give you feedback later.

    Warm regards,

     

     

     

     

    Wednesday, January 5, 2011 1:50 PM
  • Sorry for the late feedback, I'm quite busy working these days.

    I tried to build CSharp Library of step 1 using "Portable Microsoft Visual C# 2008 Express Edition" but got some errors, detailed below:

    I created a New Project named "CSFontLibForVBA"

    Renamed "Class1.cs" to "DetectFont.cs"

    Copied the codes of Step 1 into Code Window, the final content in the Code Window is

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace CSFontLibForVBA
    {
      [ClassInterface(ClassInterfaceType.AutoDual)]
      [ComVisible(true)]
      public class DetectFont
      {
        public string GetSupportedCharacterOfAFont(string fontPath)
        {
          var families = Fonts.GetFontFamilies(fontPath);
          StringBuilder sb = new StringBuilder();
          foreach (FontFamily family in families)
          {
            var typefaces = family.GetTypefaces();
            foreach (Typeface typeface in typefaces)
            {
              GlyphTypeface glyph;
              typeface.TryGetGlyphTypeface(out glyph);
              IDictionary<int, ushort> characterMap = glyph.CharacterToGlyphMap;
    
              foreach (KeyValuePair<int, ushort> kvp in characterMap)
              {
                //Console.WriteLine(String.Format("{0}:{1}", kvp.Key, kvp.Value));
                sb.Append(kvp.Key.ToString());
                sb.Append(":");
                sb.Append(kvp.Value.ToString());
                sb.Append("\n");
              }
    
            }
          }
    
          return sb.ToString();
        }
      }
    
    }
    

     

    After this, I performed step 2 and 3 and got these information in Error List window

    Error    1    The type or namespace name 'ClassInterface' could not be found (are you missing a using directive or an assembly reference?)    C:\Documents and Settings\sogno\Local Settings\Application Data\Temporary Projects\CSFontLibForVBA\DetectFont.cs    8    6    CSFontLibForVBA
    Error    2    The type or namespace name 'ClassInterfaceAttribute' could not be found (are you missing a using directive or an assembly reference?)    C:\Documents and Settings\sogno\Local Settings\Application Data\Temporary Projects\CSFontLibForVBA\DetectFont.cs    8    6    CSFontLibForVBA
    Error    3    The type or namespace name 'ComVisible' could not be found (are you missing a using directive or an assembly reference?)    C:\Documents and Settings\sogno\Local Settings\Application Data\Temporary Projects\CSFontLibForVBA\DetectFont.cs    9    6    CSFontLibForVBA
    Error    4    The type or namespace name 'ComVisibleAttribute' could not be found (are you missing a using directive or an assembly reference?)    C:\Documents and Settings\sogno\Local Settings\Application Data\Temporary Projects\CSFontLibForVBA\DetectFont.cs    9    6    CSFontLibForVBA

    I figured, should I use Microsoft.Visual.Studio.2008.Professional.Edition instead of "Portable Microsoft Visual C# 2008 Express Edition" ? If that's the problem, I'll try to install visual studio to test the code.

    As I explained in the previous post, I've never worked with Visual Studio series before. Hope it's not too foolish to raise these problems.

     

    Monday, January 10, 2011 4:22 PM
  • Hi Pkusogno,

    It seems that your project lack some assembly references, I use Visual Studio 2010:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Media;
    using System.Runtime.InteropServices;

    namespace CSFontLibForVBA
    {
        [ClassInterface(ClassInterfaceType.AutoDual)]
        [ComVisible(true)]
        public class DetectFont
        {
            public string GetSupportedCharacterOfAFont(string fontPath)
            {
                var families = Fonts.GetFontFamilies(fontPath);
                StringBuilder sb = new StringBuilder();
                foreach (FontFamily family in families)
                {
                    var typefaces = family.GetTypefaces();
                    foreach (Typeface typeface in typefaces)
                    {
                        GlyphTypeface glyph;
                        typeface.TryGetGlyphTypeface(out glyph);
                        IDictionary<intushort> characterMap = glyph.CharacterToGlyphMap;

                        foreach (KeyValuePair<intushort> kvp in characterMap)
                        {
                            //Console.WriteLine(String.Format("{0}:{1}", kvp.Key, kvp.Value));
                            sb.Append(kvp.Key.ToString());
                            sb.Append(":");
                            sb.Append(kvp.Value.ToString());
                            sb.Append("\n");
                        }

                    }
                }

                return sb.ToString();
            }
        }
    }

    I didn't use Portable Microsoft Visual C# 2008 Express Edition, it may not add these reference to your  project.

    Hope it can help you and feel free to follow up after you tried.

    Best Regards,


    Bruce Song [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Proposed as answer by Bruce Song Thursday, January 13, 2011 2:44 AM
    • Marked as answer by Bruce Song Thursday, January 13, 2011 10:35 AM
    Tuesday, January 11, 2011 10:51 AM
  • Hi Bruce,

    I managed to get all four steps done.

    I tried to read the CSharp codes, understood that what these codes actually do is to get "int" and "ushort" parameters in a defined font's charactermap. For step 4, I used selection.typetext instead of debug.print so that the result could be fully displayed in a new word document. I researched for some time on the relationship between "int" and unicode of a character, but haven't get any satisfactory answer yet.I will try to study more about charactermap some other time.

    Thank you for your help again.

     

    Thursday, January 13, 2011 4:36 PM
  • Hi Pkusogno,

    Thank you for your feedback you are welcome and glad to hear that you got it working.

    Best Regards,


    Bruce Song [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, January 14, 2011 1:26 AM