Question

I'm making use of the Setup... methods (such as SetupGetLineText) to read some content from inf files (I need this, not interested in a generic ini parser). These methods use Windows-1252 encoding and I need this to be converted to Unicode. I got this working with a string, such as this (input is of type string):

Encoding.UTF8.GetString(Encoding.GetEncoding(1252).GetBytes(input));

Even though this works fine, you can also immediately retrieve the bytes from the SetupGetLineText method (and others). However, I'm not entirely sure on how to convert the bytes now as they are different from what Encoding.GetEncoding(1252) returns. To make this a bit more clear I've uploaded a screenshot of the current situation. As you can see, the majority of the characters match (ignore the 0s), but there are a couple of situations with differences. For example, [4] and [5] are 26 and 32, whereas the string variant has just 130 listed. How can I get from 26 and 32 to 130? Or perhaps better, how can I directly go from the byte array to a UTF-8 string?

Some code:

public static readonly IntPtr INVALID_HANDLE = new IntPtr(-1);

public const int INF_STYLE_OLDNT = 0x00000001;

public const int INF_STYLE_WIN4 = 0x00000002;

[StructLayout(LayoutKind.Sequential)]
public struct InfContext
{
    IntPtr Inf;
    IntPtr CurrentInf;
    uint Section;
    uint Line;
}

[DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool SetupGetLineText([MarshalAs(UnmanagedType.Struct)] ref InfContext context, IntPtr infHandle, string section, string key, string returnBuffer, int returnBufferSize, out int requiredSize);

[DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr SetupOpenInfFile([MarshalAs(UnmanagedType.LPWStr)] string fileName, [MarshalAs(UnmanagedType.LPWStr)] string infClass, Int32 infStyle, out uint errorLine);

[DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool SetupEnumInfSections(IntPtr infHandle, uint index, string returnBuffer, int returnBufferSize, out int requiredSize);

 [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
 public static extern bool SetupFindFirstLine(IntPtr infHandle, string section, string key, [MarshalAs(UnmanagedType.Struct)]ref InfContext context);

    [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool SetupFindNextLine([MarshalAs(UnmanagedType.Struct)] ref InfContext contextIn, [MarshalAs(UnmanagedType.Struct)] ref InfContext contextOut);

    [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool SetupFindNextMatchLine([MarshalAs(UnmanagedType.Struct)] ref InfContext contextIn, string key, [MarshalAs(UnmanagedType.Struct)] ref InfContext contextOut);


// InfFile class

public InfFile(string path)
{
    _file = path;
}

public bool Open()
{
    uint errorLineNumber;
    _handle = NativeMethodsInf.SetupOpenInfFile(_file, null, INF_STYLE_OLDNT | INF_STYLE_WIN4, out errorLineNumber);

    return _handle != INVALID_HANDLE;
}

    public string EnumSection(uint index)
    {
        int requiredSize;
        string result = String.Empty.PadLeft(75-1);

        bool success = SetupEnumInfSections(_handle, index, result, 75, out requiredSize);
        if (requiredSize > 75)
        {
            result = result.PadLeft(requiredSize - 1);
            success = SetupEnumInfSections(_handle, index, result, requiredSize, out requiredSize);
        }

        return !success ? null : result.Substring(0, requiredSize - 1); // Still needs to be converted to proper encoding.
    }

    public InfLine FindFirstLine(string section)
    {
        return FindFirstKey(section, null);
    }

    public InfLine FindFirstKey(string section, string key)
    {
        InfContext infContext = new InfContext();

        return !SetupFindFirstLine(_handle, section, key, ref infContext) ? null : new InfLine(infContext);
    }

// InfLine class

    public bool FindNextLine()
    {
        return SetupFindNextLine(ref _context, ref _context);
    }

    public bool FindNextMatchLine(string key)
    {
        return SetupFindNextMatchLine(ref _context, key, ref _context);
    }

    public string GetCompleteValue()
    {
        int requiredSize;
        string result = String.Empty.PadLeft(250-1);

        bool success = SetupGetLineText(ref _context, IntPtr.Zero, null, null, result, 250, out requiredSize);
        if (requiredSize > 250)
        {
            result = result.PadLeft(requiredSize - 1);
            success = SetupGetLineText(ref _context, IntPtr.Zero, null, null, result, requiredSize, out requiredSize);
        }

        return !success ? null : result.Substring(0, requiredSize - 1);
    }

// And then use with something like:
using (InfFile file = new InfFile(@"..\..\..\test.inf"))
        {
            if (file.Open())
            {
                uint currentSection = 0;
                string section;
                while ((section = file.EnumSection(currentSection++)) != null)
                {
                    Console.WriteLine("Section: " + section);
                    var x = file.FindFirstKey(section, null);
                    if (x != null)
                        while (true)
                        {
                            string key = x.GetFieldValue(0);
                            string value = x.GetCompleteValue();
                            Console.WriteLine("Key: " + key + " || Value: " + value);
                            if (!x.FindNextLine())
                                break;
                        }
                }
            }
         }

Example inf:

; German Specific 
[Strings.0007] ; German
Provider="Hewlett-Packard"
Mfg="Hewlett-Packard"
CD="hp cd"

BUTTON_SCAN="Taste "Scannen" gedrückt"
LAUNCH_APPLICATION_SCAN="HP Scansoftware"

; Japanese Specific 
[Strings.0411] ; Japanese
Provider="Hewlett-Packard"
Mfg="Hewlett-Packard"
CD="hp cd"

BUTTON_SCAN="[スキャン] ボタンを押す"
LAUNCH_APPLICATION_SCAN="hp スキャニング ソフトウェア"

I need to convert section, key and value using:

public static string ConvertToUTF8(string input)
    {
        try
        {
            return Encoding.UTF8.GetString(Encoding.GetEncoding(1252).GetBytes(input)).Trim().Trim('\0');
        }
        catch
        {
            return input;
        }
    }

To get the proper values, otherwise you'll see that they aren't the original characters.

For example: Taste "Scannen" gedrückt becomes Taste Scannen gedrückt

Without calling ConvertToUTF8 first.

Was it helpful?

Solution

You're currently converting a string to Windows-1252 and then converting it back to a string by interpreting those bytes as UTF-8.

That is not working fine - that's broken, basically.

If you've already got a string, it's not in Windows-1252... it's in UTF-16 internally, but you can think of it as a character sequence. If you've actually started with a byte array, then you should use Encoding.GetEncoding(1252).GetString(bytes) to convert that byte array to a string.

(If you can use SetupGetLineTextW instead, you may be able to avoid all this ANSI business entirely.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top