GetPrivateProfileString
-
The documentation[^] for GetPrivateProfileString says that in the case that the ini file is not found "this function will set errorno with a value of '0x2' (File Not Found)." (actually, they mean errno, not 'errorno'). When I tested this with a path to a file that doesn't exist, the function didn't update errno; it just silently failed and filled the string buffer with an empty string. I'm on Windows 7, 64 bit. Can anyone verify this behavior?
-
The documentation[^] for GetPrivateProfileString says that in the case that the ini file is not found "this function will set errorno with a value of '0x2' (File Not Found)." (actually, they mean errno, not 'errorno'). When I tested this with a path to a file that doesn't exist, the function didn't update errno; it just silently failed and filled the string buffer with an empty string. I'm on Windows 7, 64 bit. Can anyone verify this behavior?
The documentation also says "Note This function is provided only for compatibility with 16-bit Windows-based applications. Applications should store initialization information in the registry.". You also did not show the code that you are using so it's difficult to offer any suggestion as to why you got the results that you did.
Use the best guess
-
The documentation also says "Note This function is provided only for compatibility with 16-bit Windows-based applications. Applications should store initialization information in the registry.". You also did not show the code that you are using so it's difficult to offer any suggestion as to why you got the results that you did.
Use the best guess
Here is a working console app example. It assumes the existence of an INI file in the current directory named test.ini. The test.ini file should have the following contents:
[test]
key=value#include #include #include int _tmain(int argc, _TCHAR* argv[])
{
const int stringMaxLength = 64;
TCHAR stringBuffer[stringMaxLength];// This INI file exists. TCHAR validIniFileName\[\] = \_T(".\\\\test.ini"); ::GetPrivateProfileString(\_T("test"), \_T("key"), NULL, stringBuffer, stringMaxLength, validIniFileName); // Since the INI file exists and has no errors, errno should be 0x00. assert(errno == 0x00); // This INI file does not exist. TCHAR invalidIniFileName\[\] = \_T(".\\\\foo.ini"); ::GetPrivateProfileString(\_T("test"), \_T("key"), NULL, stringBuffer, stringMaxLength, invalidIniFileName); // Since the INI file does not exist, errno should be 0x02 (File Not Found). assert(errno == 0x02); return 0;
}
I've read the note about this function only provided for compatibility with 16-bit Windows applications. But I need to parse ini files, so I decided to use this function anyway. The app I'm writing will allow users to edit an ini file in order to configure aspects of the application. Do you think the compatibility issue is the reason errno isn't being set?
-
Here is a working console app example. It assumes the existence of an INI file in the current directory named test.ini. The test.ini file should have the following contents:
[test]
key=value#include #include #include int _tmain(int argc, _TCHAR* argv[])
{
const int stringMaxLength = 64;
TCHAR stringBuffer[stringMaxLength];// This INI file exists. TCHAR validIniFileName\[\] = \_T(".\\\\test.ini"); ::GetPrivateProfileString(\_T("test"), \_T("key"), NULL, stringBuffer, stringMaxLength, validIniFileName); // Since the INI file exists and has no errors, errno should be 0x00. assert(errno == 0x00); // This INI file does not exist. TCHAR invalidIniFileName\[\] = \_T(".\\\\foo.ini"); ::GetPrivateProfileString(\_T("test"), \_T("key"), NULL, stringBuffer, stringMaxLength, invalidIniFileName); // Since the INI file does not exist, errno should be 0x02 (File Not Found). assert(errno == 0x02); return 0;
}
I've read the note about this function only provided for compatibility with 16-bit Windows applications. But I need to parse ini files, so I decided to use this function anyway. The app I'm writing will allow users to edit an ini file in order to configure aspects of the application. Do you think the compatibility issue is the reason errno isn't being set?
The documentation is, I think, correct in that it sets
errorno
rather thanerrno
, and you need to check the return value fromGetPrivateProfileString
, and then useGetLastError()
to retrieve the error code, thus:DWORD dwError;
DWORD dwCount = ::GetPrivateProfileString(_T("test"), _T("key"), NULL, stringBuffer, stringMaxLength, validIniFileName);
if (dwCount == 0)
{
// GetPrivateProfileString failed so get the error code
dwError = GetLastError();
// and take action accordingly
}Use the best guess
-
The documentation is, I think, correct in that it sets
errorno
rather thanerrno
, and you need to check the return value fromGetPrivateProfileString
, and then useGetLastError()
to retrieve the error code, thus:DWORD dwError;
DWORD dwCount = ::GetPrivateProfileString(_T("test"), _T("key"), NULL, stringBuffer, stringMaxLength, validIniFileName);
if (dwCount == 0)
{
// GetPrivateProfileString failed so get the error code
dwError = GetLastError();
// and take action accordingly
}Use the best guess
You're right, of course. :) I should be more careful with my assumptions. Also, I need to treat the comments in the 'Community Additions' section of the documentation more skeptically; there is a comment there for this function saying that errorno should be errno. I appreciate your code snippet. That appears to be the proper way to check for errors with this function. Thank you.
-
You're right, of course. :) I should be more careful with my assumptions. Also, I need to treat the comments in the 'Community Additions' section of the documentation more skeptically; there is a comment there for this function saying that errorno should be errno. I appreciate your code snippet. That appears to be the proper way to check for errors with this function. Thank you.
-
The documentation[^] for GetPrivateProfileString says that in the case that the ini file is not found "this function will set errorno with a value of '0x2' (File Not Found)." (actually, they mean errno, not 'errorno'). When I tested this with a path to a file that doesn't exist, the function didn't update errno; it just silently failed and filled the string buffer with an empty string. I'm on Windows 7, 64 bit. Can anyone verify this behavior?
Leslie Sanford wrote:
I'm on Windows 7, 64 bit.
As soon as I saw the API, I knew you were on WfW 3.11! If you "must" use the old text-format, for whatever perverse reason, then read it as a textfile. "GetPrivateProfileString" does a whole lot more than simply opening an INI-file - it maps a lot of them to the registry. Using it under Windows 7 is wrong, it's there for compatibility-reasons. If you simply need a configuration-file that can be edited by hand, use XML; it's more flexible and there's more support under .NET.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
-
Leslie Sanford wrote:
I'm on Windows 7, 64 bit.
As soon as I saw the API, I knew you were on WfW 3.11! If you "must" use the old text-format, for whatever perverse reason, then read it as a textfile. "GetPrivateProfileString" does a whole lot more than simply opening an INI-file - it maps a lot of them to the registry. Using it under Windows 7 is wrong, it's there for compatibility-reasons. If you simply need a configuration-file that can be edited by hand, use XML; it's more flexible and there's more support under .NET.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
I too agree with Eddy Vlugen on not relying on deprecated functions from API although name value pairs are something that I too prefer over XML. For novice users, getting them to edit XML files is a challenge and for skilled one, I am more worried about how to prevent them from hacking my app. I have written a very simple text parser and use Dictionary with a Pre-defined Enum which effectively acts a parser.
public void ParseStartupFile(String fileName)
{
String singleLine;
_appStartupParameters.Clear();using (StreamReader txtReader = new StreamReader(fileName))
{
while (!txtReader.EndOfStream)
{
singleLine = txtReader.ReadLine();
String[] split = singleLine.Split(new Char[]
{ '\"', '=', ';' });EnumOfAllAllowedKeywords keyword;
if (split.Length >= 3)
{
// Convert string to enum'keyword....
// If keyword is not valid, it will throw exception
keyword = GetEnumeratedValue
(split[0]);for (int j = 1; j < split.Length; j++) if (!String.IsNullOrEmpty(split\[j\])) break; //\_appStartupParameters is generic dictionary // Dictionary \_appStartupParameters.Add(keyword, split\[j\]);
}
}
}
}