C# 为什么可以';我不能通过pinvoke让GetPrivateProfileString工作吗?

C# 为什么可以';我不能通过pinvoke让GetPrivateProfileString工作吗?,c#,64-bit,pinvoke,windows-vista,C#,64 Bit,Pinvoke,Windows Vista,运行我在64位Vista上编写的c#控制台应用程序。代码如下: class Class1 { static void Main(string[] args) { Debug.Assert(File.Exists(@"c:\test.ini")); StringBuilder sb = new StringBuilder(500); uint res = GetPrivateProfileString("AppName", "KeyN

运行我在64位Vista上编写的c#控制台应用程序。代码如下:

class Class1
{
    static void Main(string[] args)
    {
        Debug.Assert(File.Exists(@"c:\test.ini"));
        StringBuilder sb = new StringBuilder(500);
        uint res = GetPrivateProfileString("AppName", "KeyName", "", sb, sb.Capacity, @"c:\test.ini");
        Console.WriteLine(sb.ToString());
    }
    [DllImport("kernel32.dll")]
    static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);
}

我肯定我会得到一个很大的“DUH!”作为回答,但我不明白为什么这不起作用。根据pinvoke.net的说法,除了Debug.Assert之外,这段代码是从c#sample的

中截取的,nSize应该是UINT。他们在示例中也使用了绝对路径

除了这些差异,我看不到其他任何东西

如果抛出无效格式异常,请尝试将目标平台设置为x86以解决此问题

pinvoke.net的使用示例如下

[DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
    static extern uint GetPrivateProfileString(
    string lpAppName, 
    string lpKeyName,
    string lpDefault, 
    StringBuilder lpReturnedString, 
    uint nSize,
    string lpFileName);


 static void Main(string[] args)
 {
   StringBuilder sb = new StringBuilder(500);
   uint res = GetPrivateProfileString("AppName", "KeyName", "", sb, (uint)sb.Capacity, @"c:\test.ini");
   Console.WriteLine(sb.ToString());
 }

我看到的主要情况是,您应该为nSize传递一个uint,以及返回值。这是因为的返回和nSize参数是
DWORD
值,它们是无符号32位整数

我个人在以下方面使用了该语法:

此外,除非文件位于Windows目录中,否则需要将文件的完整路径放置到位。从文档中:

如果此参数不包含文件的完整路径,系统将在Windows目录中搜索该文件

如果未指定路径,将在Windows目录中查找Test.ini

像GetPrivateProfileString这样的旧API不能很好地处理Unicode(即使有GetPrivateProfileStringW函数)。如果Test.ini包含UTF头或Unicode字符,这可能足以阻止GetPrivateProfileString正常工作


此外,Vista的UAC可以使处理位于“特殊”位置的文件变得棘手(C:\、C:\Windows、C:\Program files等)。尝试将Test.ini放在文件夹中而不是C:驱动器的根目录中,或者关闭UAC。有一个例子讨论了GetPrivateProfileString在尝试从UAC控制的文件夹中读取.ini时失败的问题。

也许您应该研究一种开源解决方案,它可以完全做到这一点,而不用担心p/Invoke。针对.NET的项目名为“我正在从事的一个项目中使用它”,我推荐它

希望这有帮助, 顺致敬意,
汤姆。

这件事也让我忙了一整天。我想我找到了一个解决办法,我真的不想处理它:在.ini文件的第一个节头前插入一个空行。现在运行你的应用程序,看看你是否开始看到你期望的值


考虑到这个bug显然已经存在多年了,我很惊讶MS现在还没有修复它。但是,.ini文件应该在几年前就消失了。这当然很有趣,因为MS在很多地方使用.ini文件(例如desktop.ini)。但是我认为微软已经意识到了这个错误,因为我注意到我的desktop.ini文件包含一个前导的空行。嗯…

您能验证
test.ini
文件的内容吗?考虑到您尝试过的所有步骤,我开始怀疑您的数据文件格式不正确(拼写错误等)。换句话说,
GetPrivateProfileString
可能正在工作,但只是找不到您的字符串。根据您发布的代码,您的
test.ini
文件应该如下所示:

[AppName]
KeyName=foo



该页的注释部分还指出,可以在size参数上使用int而不是union,以防止必须对sb.Capacity进行大小写。是否收到无效的格式异常?或者抛出/返回什么异常/错误?函数似乎成功,但返回零。当我检查Marshal.GetLastWin32Error时,它的值为1008==ERROR\u NO\u对不起,这是个误会。在调用GetPrivateProfileString之前,Marshal.GetLastWin32Error是1008。@Charles:如果DllImport属性中没有SetLastError=true,GetLastWin32Error()可能会返回一个伪值。No。不是这样。我将它复制到Windows目录中,但没有成功。我还添加了Debug.Assert(File.Exists(“Test.ini”)—我正在尝试读取当前工作目录中的文件。没有前导空行,但保存为ANSI(而不是UTF8)文件的GetPrivateProfileString工作正常。谢谢,但我正在尝试解决我的问题,找不到合适的解决方案。@Charles:好的……你已经看了这篇文章,其中包括如何使用它的示例?@Charles:顺便说一下……我忍不住注意到……你说过你是在64位vista上写的……api会改变吗?只是想先问一些简单的问题来帮助你…@Charles:在示例中,它是uint res=GetPrivateProfileString(…),在代码中有int?希望这有帮助…根据该页上的注释,int和uint可以互换。如果我按原样使用他们的c#示例(您必须修复编译器错误),它仍然不起作用。我忘了提到,我正在XP Pro 32位上运行此代码。我只是尝试了GetPrivateProfileSectionW和GetPrivateProfileSectionNamesW。两者都以同样的方式失败。同样有趣的是,当我尝试检索节名时,只返回第一个节,无论是使用GetPrivateProfileStringW还是GetPrivateProfileSectionNamesW获取。我已经玩得很开心了。CodePlex看起来可能有几个替代品。如果这两个都不管用,我就自己滚。天哪!你说得对!我试图读取的部分不能是INI文件的第一行!难以置信的谁会知道呢?非常感谢。很快就可以澄清了。问题是VS编辑器将UTF-8字节顺序标记(EF BB BF)放在文件的开头。INI读/写功能不处理BOM。由于我正在阅读的节位于第一行,GetPrivateProfileString没有看到“[AppName]”而是“\xEF\xBB\xBF[AppName]”,因此它从未找到我要查找的节。在文件的开头添加一个空行,将BOM表放在第一行,“[AppName]”放在第二行,这样就可以找到它。祝我好运,谢谢!我也在努力解决同样的问题。不知道为什么会这样
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
static extern uint GetPrivateProfileString(
   string lpAppName, 
   string lpKeyName,
   string lpDefault, 
   StringBuilder lpReturnedString, 
   uint nSize,
   string lpFileName);