2010-03-19 37 views
2

我在使用C#中的pinvoke調用_snwprintf時遇到了一個有趣的問題。它適用於整數類型,但不適用於浮點數。在c#中使用pinvoke在64位調用sprintf和好友

這是在64位Windows上,它在32位上工作正常。

我的代碼如下,請記住,這是一個人爲的例子,顯示我看到的行爲。

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(); 
    } 
} 

該程序的輸出是

0.0 
    1 

它應該打印1.0在第一行上,而不是0.0,到目前爲止我難倒。

+1

什麼樣的惡魔會開車送你到PInvoke的C運行時的printf家庭? C調用約定,可變參數,非操作系統部署的DLL,它像breweing完美的風暴! – 2010-03-19 17:10:01

+1

是不是string.Format足夠你? – zneak 2010-03-19 17:12:50

+0

@Remus - 我意識到這並不是一件好事,而是在尋求麻煩,然而有時候我們都必須忍受現有的代碼。此外,儘管可能會有多麼可怕,但在我看來,它仍然應該起作用。 – WildCrustacean 2010-03-19 17:13:13

回答

5

我不完全確定您的呼叫無法正常工作,但secured versions of these methods在x86和x64中均可正常工作。

下面的代碼不工作,如所預期:

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(); 
    } 
} 
+0

這不起作用。如果我使用Single而不是Double,則會發生同樣的問題。我會改變這個例子來使用lf。看到爲什麼我試圖做到這一點的主要意見。 – WildCrustacean 2010-03-19 17:18:35

+0

@bde:我只是重複了我的答案。那裏的代碼工作在x86和x64,沒有問題。 – 2010-03-19 17:43:29

+0

謝謝,這也適用於我。 – WildCrustacean 2010-03-19 17:48:59

0

uint是32位。 snprintf的長度參數是size_t,在64位進程中是64位。將第二個參數更改爲IntPtr,它是size_t最接近的.NET等效項。

此外,您需要預先分配您的StringBuilder。目前你有一個緩衝區溢出。

+0

試過了,同樣的問題。我會更新我的示例,但它應該使用IntPtr。 – WildCrustacean 2010-03-19 17:10:46

0

嘗試的MarshalAs R8(這就是真正的/浮動8(它是雙))上在第二函數的最後一個參數。

+0

也試過了,結果一樣。 – WildCrustacean 2010-03-19 17:37:12

+0

我剛剛閱讀msdn的幫助,第二個參數預期是在參數數組的形式,我不知道如何編組到c的參數數組,即使你發送你的參數爲double,可能是運行時不期待它在同樣的形式,我想知道int如何工作,double也應該工作。嘗試將它作爲最後一個參數的double數組中的第一項發送並嘗試放置參數。 – 2010-03-19 17:50:25

+0

C和C++可變參數在.NET參數數組下面非常不同。 sprintf絕對使用傳遞值。 – 2010-03-19 18:19:22

3

有可能與無證__arglist關鍵字:

using System; 
using System.Text; 
using System.Runtime.InteropServices; 

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

    static void Main(string[] args) { 
     Double d = 1.0f; 
     Int32 i = 1; 
     String s = "nobugz"; 
     StringBuilder str = new StringBuilder(666); 

     _snwprintf(str, str.Capacity, "%10.1lf %d %s", __arglist(d, i, s)); 
     Console.WriteLine(str.ToString()); 
     Console.ReadKey(); 
    } 
} 

請不要使用。

+0

對不起復制後,沒有看到你的__arglist時發佈我的答案:) – 2010-03-19 17:52:30

+0

我其實已經嘗試過,今天早些時候,我無法得到它的工作。所有這些示例代碼對我來說都是打印格式字符串。也許我在這裏錯過了一些東西。我同意我寧願不使用這種方法。 – WildCrustacean 2010-03-19 17:56:36

+0

@bde:Project + Properties,Application選項卡,Platform Target = x86。這是危險。 – 2010-03-19 18:00:02