Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using pinvoke in c# to call sprintf and friends on 64-bit

Tags:

c#

64-bit

pinvoke

I am having an interesting problem with using pinvoke in C# to call _snwprintf. It works for integer types, but not for floating point numbers.

This is on 64-bit Windows, it works fine on 32-bit.

My code is below, please keep in mind that this is a contrived example to show the behavior I am seeing.

class Program
{
    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr length, String format, int p);

    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr length, String format, double p);

    static void Main(string[] args)
    {
        Double d = 1.0f;
        Int32 i = 1;
        Object o = (object)d;
        StringBuilder str = new StringBuilder(32);

        _snwprintf(str, (IntPtr)str.Capacity, "%10.1lf", (Double)o);
        Console.WriteLine(str.ToString());

        o = (object)i;
        _snwprintf(str, (IntPtr)str.Capacity, "%10d", (Int32)o);
        Console.WriteLine(str.ToString());

        Console.ReadKey();
    }
}

The output of this program is

   0.0
     1

It should print 1.0 on the first line and not 0.0, and so far I am stumped.

like image 462
WildCrustacean Avatar asked Dec 29 '22 22:12

WildCrustacean


1 Answers

I'm not exactly sure why your calls do not work, but the secured versions of these methods do work properly in both x86 and x64.

The following code does work, as expected:

class Program
{
    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf_s([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr bufferSize, IntPtr length, String format, int p);

    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf_s([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr bufferSize, IntPtr length, String format, double p);

    static void Main(string[] args)
    {
        // Preallocate this to a given length
        StringBuilder str = new StringBuilder(100);
        double d = 1.4;
        int i = 7;
        float s = 1.1f;

        // No need for box/unbox
        _snwprintf_s(str, (IntPtr)100, (IntPtr)32, "%10.1lf", d);
        Console.WriteLine(str.ToString());

        _snwprintf_s(str, (IntPtr)100, (IntPtr)32, "%10.1f", s);
        Console.WriteLine(str.ToString());

        _snwprintf_s(str, (IntPtr)100, (IntPtr)32, "%10d", i);
        Console.WriteLine(str.ToString());

        Console.ReadKey();
    }
}
like image 143
Reed Copsey Avatar answered Jan 18 '23 01:01

Reed Copsey