I am working on a piece of code in the old application, using C++ in Visual Studio 2008. It attempts to read some values from an INI file, and I'm trying to do some error handling in the case of the section or key I am trying to read does not exist in the file.
Here is the code snippet:
int nValue = GetPrivateProfileInt (SECTION, KEY, -1, sINIFile);
if(nValue == -1) // default value
{
int nLastError = GetLastError();
if(nLastError != 0)
{
// do something
}
}
sINIFile contains the full path to my required INI file.
After some testing, I've found that GetLastError() returns 2 (ERROR_FILE_NOT_FOUND) if:
the file doesn't exist OR,
the section doesn't exist OR,
the key doesn't exist.
I would like to know the specific reason the GetPrivateProfileInt returned the default value - is this possible?
Note: I've looked into checking the value of 'errno' (or errorno, as it says on the MSDN page) but this is always 0 for any of the above cases.
If GetLastError() won't help, then you need to do some detective work. You should check yourself if the registry key or file exists (you know that most ini files are mapped to the registry, right?), or if the section doesn't exist (GetPrivateProfileSection), and if neither of those apply, then the key doesn't exist.
Related
Consider a following snippet of code
#include <iostream>
#include <windows.h>
int main()
{
WIN32_FILE_ATTRIBUTE_DATA wfad;
GetFileAttributesEx(("C:\\TEMP\\noreadfile"), GetFileExInfoStandard, &wfad); //"noreadfile" is unreadable file
std::cout << wfad.dwFileAttributes; // 128
return 0;
}
For an unreadable file (File that does not have read permissions or file that has its read permissions set as "Deny" in its properties -> security tab) on Windows, GetFileAttributesEx returns FILE_ATTRIBUTE_NORMAL, which means that no other attribute is set for that file.
This attribute is also returned for a writeable as well as non-readonly files.
We use this information to set the permissions for files in our product code.
We concluded that GetFileAttributesEx might be returning incorrect attribute in case of unreadable files. We wonder if our conclusion is right or not.
If yes, then is this a known issue with GetFileAttributesEx ?
If not then
What is the correct way to get the file attributes (file permissions perhaps ?) for an unreadable file using Windows API or if possible using Boost or standard C++ filesystem libraries ?
It's probably not succeeding at all. If you look at the documentation for GetFileAttributesEx, it actually returns a BOOL.
Return value If the function succeeds, the return value is a nonzero
value.
If the function fails, the return value is zero (0). To get extended
error information, call GetLastError.
My guess is that "fwad" is undefined if the call fails. Try checking the return value for a failure indication. My guess is that GetLastError will return something like ERROR_ACCESS_DENIED.
The Windows API doesn't throw exceptions, so unfortunately you'll have to check just about every return value.
Suppose you want to develop a function that, given a valid registry key handle and a value name, returns true if the value exists under the input key, false if it doesn't, and throws a C++ exception in all other cases.
bool RegValueExists(HKEY hKey, const std::wstring& value)
{
LRESULT retCode = ::RegGetValue(
hKey,
nullptr, // no subkey
value.c_str(),
RRF_RT_ANY, // any type
nullptr, nullptr, nullptr // not interested in these
);
If RegGetValue succeeds, it returns 0; so, in this case I can return true to the caller.
But, from the MSDN documentation of RegGetValue, it's not clear what the API returns in case of registry value not found:
Return value
[...] If the function fails, the return value is a system error code.
In my tests, RegGetValue returns 2 (i.e. ERROR_FILE_NOT_FOUND) in case of values not found. However, I cannot find any official MSDN page documenting that. (Moreover, since when is a registry value a file??)
Among the "system error codes" there's also an ERROR_NOT_FOUND code (1168). Would it be reasonable to expect it as a return code for "registry value not found"?
I think there should be a clear explanation of at least the common error codes in MSDN.
RegQueryValueEx has a more detailed error specification:
If the lpValueName registry value does not exist, the function returns
ERROR_FILE_NOT_FOUND.
So if you want to be on the safe side, use that function instead of RegGetValue.
From your example I see that you don't need any of the special features of RegGetValue and I think these features could even be emulated with a combination of RegOpenKeyEx and RegQueryValueEx.
There is no documentation of all the failure modes and their error codes. That's just the way of things. Certain failure modes are explicitly called out with the error code documented.
However, I can confirm that ERROR_FILE_NOT_FOUND is the error code associated with the failure mode described in the question.
It would be reasonable to expect any returned value but ERROR_SUCCESS to be an error code. The exact list of potentially returned error codes probably varies between Windows versions.
I think there should be a clear explanation of at least the common error codes in MSDN.
But your quote from MSDN page actually contains a link to the list of system error codes, you can also get an error description at any time by calling FormatMessageW.
i am trying to output a buffer to a file using visual c++.
my code for doing it is-
FILE *stream;
stream=fopen("C:\\Users\\sshekha\\Desktop\\z.txt","r");
//I also tried with "w" mode
//the differencein behavious on executing these two is that when it is in read mode it
//executes the else condition in the code below whereas in "w" mode it executes the "if"
// condition,
//moreover even if i change the path it don't execute the "else" condition-that means this path
//is effective to the code. and the another surprising thing is when i open the file manually
// and then run the code with "r" mode it still executes the "else" part (which it shouldn't
// because the file is already open.)
if( stream == 0 )
{
MessageBox(m_hwndPreview,L" the file is not opened ",L"BTN WND",MB_ICONINFORMATION);
}
else
{
MessageBox(m_hwndPreview,L" the file is opened ",L"BTN WND",MB_ICONINFORMATION);
int check=fputs (HtmlFileContents,stream);
fclose(stream);
return 0;
}
I tried to check the results using different mode in order to understand whats teh probem going on . when i debug it , i get the value of (in Read mode) :
stream = 0x000000005c5c76f0 { _ptr=0x0000000000000000 _cnt=0 _base=0x0000000000000000 ...}
I don't know it gib=ves bad pointer and even then it go to else part of the loop. Why ?
and in write mode
stream = 0x0000000000000000 {_ptr=??? _cnt=??? _base=??? ...}
So go to the if part of the loop.
Moreover my path is correct and i have enough permission to do the task I wish. But why does it give bad pointer ? Why have I these strange values of stream and what should I do to copy the content of my buffer HtmlFileContents in to z.txt ? Any ideas ?
You're opening the file in read-only mode: fopen("C:\\Users\\sshekha\\Desktop\\z.txt","r");. Here "r" says you only intend to read from file. To be able to write contents (i.e. fputs(...)), open the file in write mode like so: fopen("C:\Users\sshekha\Desktop\z.txt","w")(or"a"` if you want to append). For more information, read fopen documentation.
EDIT: I see that you've tried both read and write modes. You're code only shows read-mode and hence my assumption on the read-only problem. Let me do a bit more research and get back.
Please write the following code in your if statement:
perror("The following error occurred:");
if you don't have a console, use this to store the error string:
char* errorCause = strerror(errno); MessageBoxA(m_hwndPreview, errorCause, "BTN WND", MB_ICONINFORMATION);
and let us know what you see as the cause.
EDIT 2: Since you've mentioned that you're using Visual Studio 2010, are you running it as yourself? This stackoverflow answer shows that VS2010 has different options when debugging applications; https://stackoverflow.com/a/3704942/210634
NOTE: That feature is only available on 'Pro' versions.
Here's a working example: https://ideone.com/hVLgc4
If the file is "read only", opening with it with write permissions should fail.
to see if that is the case,under windows:
right click the file
press properties
at the bottom, see if "Read-only" attribute i marked with "v"
(uncheck it if you desire writing to the file)
refer to :
http://msdn.microsoft.com/en-us/library/aa365535(v=vs.85).aspx
on how to change file permissions from your code
This is what I did:
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;
mciOpenParms.lpstrDeviceType = _T("MPEGvideo");
mciOpenParms.lpstrElementName = m_tmpFileName;
dwReturn = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
(DWORD)(LPVOID) &mciOpenParms);
if (dwReturn)
{
wchar_t chError[100];
mciGetErrorString(dwReturn,chError,sizeof(chError));
//report the error here
}
When I run the code, I see that dwReturn is 266 and chError is set to "Unknown problem while loading the specified device driver". What could be wrong?
Note: I also tried "mpegvideo" instead of "MPEGvideo"; it didn't help. Where are these things documented anyway?
It works for me. Maybe (likely) you have the MCI register all screwed up. Or maybe the file you are opening is corrupted somehow.
As far as I know these device names are not documented anywhere. But you can find the ones configured in your system in the registry: HKLM\Software\Microsoft\Windows NT\CurrentVersion\MCI32. My system has:
AVIVideo
CDAudio
MPEGVideo
Sequencer
WaveAudio
And given that the MCI is not used much nowadays, I'd say that they are pretty standard.
If you're specifying MCI_OPEN_ELEMENT then mciOpenParms.lpstrDeviceType must be null.
See the Remarks section.
*To use automatic type selection (via the entries in the registry), assign the filename and file extension to the lpstrElementName member of the structure identified by lpOpen, set the lpstrDeviceType member to NULL, and set the MCI_OPEN_ELEMENT flag.*
I am looking for a clean way to check if a registry key exists. I had assumed that RegOpenKey would fail if I tried to open a key that didn't exist, but it doesn't.
I could use string processing to find and open the parent key of the one I'm looking for, and then enumerate the subkeys of that key to find out if the one I'm interested in exists, but that feels both like a performance hog and a weird way to have to implement such a simple function.
I'd guess that you could use RegQueryInfoKey for this somehow, but MSDN doesn't give too many details on how, even if it's possible.
Update: I need the solution in Win32 api, not in managed code, .NET or using any other library.
The docs in MSDN seem to indicate that you should be able to open a key for read permission and get an error if it doesn't exist, like this:
lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS)
{
if (lResult == ERROR_FILE_NOT_FOUND) {
However, I get ERROR_SUCCESS when I try this.
Update 2: My exact code is this:
HKEY subKey = nullptr;
LONG result = RegOpenKeyEx(key, subPath.c_str(), 0, KEY_READ, &subKey);
if (result != ERROR_SUCCESS) {
... but result is ERROR_SUCCESS, even though I'm trying to open a key that does not exist.
Update 3: It looks like you guys are right. This fails on one specific test example (mysteriously). If I try it on any other key, it returns the correct result. Double-checking it with the registry editor still does not show the key. Don't know what to make of all that.
First of all don't worry about performance for stuff like this. Unless you are querying it 100x per sec, it will be more than fast enough. Premature optimization will cause you all kinds of headaches.
RegOpenKeyEx will return ERROR_SUCCESS if it finds the key. Just check against this constant and you are good to go.
RegOpenKey does return an error if the key does not exist. How are you using it? The expected return value is ERROR_FILE_NOT_FOUND.
From your code:
HKEY subKey = nullptr;
LONG result = RegOpenKeyEx(key, subPath.c_str(), 0, KEY_READ, &subKey);
if (result != ERROR_SUCCESS) {
I would look at the value of key and subPath and make sure they are what you expect, and that the key does not actually exist. What is the value of subKey afterwards? It is obviously opening something - try enumerating it to see what the keys and values under it are.
There is no issue with RegOpenKey not returning an error if the key does not exist - I would not try to assume there is some kind of weird OS bug in something as commonly used as the registry.
Maybe you have a registry key that is not visible to you, the user that is running the registry editor, but not to your code? A permissions problem perhaps? Is your code running as an elevated user in windows Vista or server 2008? Did you try running the registry editor as administrator?
Note that beside the "core" Registry functions that start with "Reg" there are also helper functions starting with "SHReg". These are intended for use by the Shell i.e. Explorer but are documented and can be used in normal applications too. They're typically thin wrappers that make some common tasks easier. They're part of the "Shell LightWeight API" (shlwapi.dll)