Why can't I get GetPrivateProfileString to work via pinvoke?

一笑奈何 提交于 2019-12-07 08:34:04

问题


Running a c# console app I wrote on 64 bit Vista. Here's the code:

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

I'm sure I'll get a big "DUH!" for an answer, but I'm not seeing why this fails to work. Other than the Debug.Assert, this code was cut from the c# sample at this page


回答1:


This one has been busting my chops all day, too. I think I found a work-around, which I really don't want to have to deal with: insert a blank line before the first section header in your .ini file. Now run your app and see if you don't start seeing the values you were expecting.

Considering this bug has apparently been around for years, I'm surprised MS hasn't fixed it by now. But then, .ini files were supposed to have gone away years ago. Which of course is funny, because there are a lot of places MS uses .ini file (e.g, desktop.ini). But I think MS is aware of the bug, because I notice my desktop.ini files include a leading blank line. Hmmm...




回答2:


The main thing I see is that you should be passing in an uint for nSize, as well as the return value. This is because the return and nSize parameters of GetPrivateProfileString are DWORD values, which are unsigned 32bit integers.

I personally have used the syntax on PInvoke.net:

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

In addition, you'll need to put the full path to the file in place, unless the file is located in the Windows directory. From the docs:

If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory.




回答3:


If no path is specified, GetPrivateProfileString will look for Test.ini in the Windows directory.

Old APIs like GetPrivateProfileString don't handle Unicode well (even though there's a GetPrivateProfileStringW function). If Test.ini contains a UTF header or Unicode characters, that might be enough to prevent GetPrivateProfileString from working correctly.

Also, Vista's UAC can make handling files that are in "special" places tricky (C:\, C:\Windows, C:\Program Files, etc.). Try putting Test.ini in a folder rather than in the root of the C: drive, or turn off UAC. There's a thread on CodeProject that discusses GetPrivateProfileString failing silently when trying to read an .ini from a folder controlled by UAC.




回答4:


According to pinvoke.net, nSize should be a UINT. Also they are using an absolute path in their example.

Other than those differences, I can't see anything else.

Providing it's throwing a invalid format exception, try setting target platform to x86 to solve the problem.

Usage example from pinvoke.net is

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



回答5:


Maybe you should look into looking at an open source solution that will do exactly that without you worrying about p/Invoke's. The project targetted for .NET is called nini I am using this in a project I am working on and I recommend it.

Hope this helps, Best regards, Tom.




回答6:


Can you verify the contents of your test.ini file? Given all of the steps that you've tried, I'm beginning to suspect that your data file is not formatted correctly (misspelling, etc.) In other words, GetPrivateProfileString may be "working", but just not finding your string. Based on the code that you posted, your test.ini file should look something like this:

[AppName]
KeyName=foo



来源:https://stackoverflow.com/questions/1891279/why-cant-i-get-getprivateprofilestring-to-work-via-pinvoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!