-2

this is a followup on 'LPCTSTR typecast for use with GetFileAttributes'

i extended my method by GetLastError();.

I cast DWORD into a unsigned int and try to display it with a MessageBox.

the code does work, but i fail to visualize the value of DWORD dw or Unsigned int test from the GetLastError(); method using a MessageBox and figuring how to proceed.

this a win32 project and i trying to build a method to see if a file exist on the harddrive.

there are over 15.000 error codes and it´s imposible to hardcode them all. http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx

BOOL FileExists(LPCTSTR szPath)
{
    //MessageBox(NULL,szPath,L"File Error",MB_OK);
    DWORD dwAttrib = GetFileAttributes(szPath);

    unsigned int test;
    DWORD dw = GetLastError();
    test =(unsigned int)dw;
    if(test == 0){
        MessageBox(NULL,(LPCWSTR)test, L"Target == 0",MB_OK);
    }
    else
    {
        MessageBox(NULL,(LPCWSTR)test, L"Target != 0",MB_OK);
    }

    switch(dw)
    {
    case ERROR_SUCCESS:
        MessageBox(NULL,L"ERROR_SUCCESS", L"File Error",MB_OK);
        break;
    case ERROR_PATH_NOT_FOUND:
        MessageBox(NULL,L"ERROR_PATH_NOT_FOUND", L"File Error",MB_OK);
        break;
    default:
        MessageBox(NULL,(LPCWSTR)dw, L"File Error",MB_OK);
        break;
    }

    switch(dwAttrib)
    {

        case FILE_ATTRIBUTE_DIRECTORY:
            MessageBox(NULL,L"FILE_ATTRIBUTE_DIRECTORY", L"File Error",MB_OK);
            break;
        case FILE_ATTRIBUTE_ARCHIVE:
            MessageBox(NULL,L"FILE_ATTRIBUTE_ARCHIVE", L"File Error",MB_OK);
            break;
        case FILE_READ_ONLY_VOLUME:
            MessageBox(NULL,L"FILE_READ_ONLY_VOLUME", L"File Error",MB_OK);
            break;
        case FILE_INVALID_FILE_ID:
            MessageBox(NULL,L"FILE_INVALID_FILE_ID", L"File Error",MB_OK);
            break;
        //case INVALID_FILE_ATTRIBUTES:
        //  MessageBox(NULL,L"INVALID_FILE_ATTRIBUTES",L"File Error",MB_OK);
        //  break;
        //case FILE_INVALID_FILE_ID:
        //  MessageBox(NULL,L"Failed to get image file,\\please check game folder",L"File Error",MB_OK);
        //  break;
        default:
            MessageBox(NULL,(LPCWSTR)dwAttrib,L"File Error",MB_OK);
            break;
    }

  return true; // testing phase
}
Community
  • 1
  • 1
NaturalDemon
  • 934
  • 1
  • 9
  • 21
  • [`FormatMessage`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx). Also, you should get your basics straight. Pick up any introduction from [The Definitive C++ Book Guide and List](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – IInspectable May 29 '14 at 17:27

2 Answers2

3

The fundamental problem you have is that your casts are incorrect. When the compiler tells you that the parameters you pass have the wrong type, the correct approach is to find a way to pass something with the right type. Instead you cast the value which simply says to the compiler, "I know better than you, please ignore the type of the variable and pretend it is what I said it is."

So, instead of writing

(LPCWSTR)test

you need to convert the integer test to a null-terminated wide string. There are lots of ways to do that. For instance, you might use a string stream:

std::wstringstream sstream;
sstream << test;
std::wstring str = test.str();

Then you can pass str.c_str() to the MessageBox API.

In C++11 you could use std::to_wstring() like this:

std::wstring str = std::to_wstring();

You are interpreting the values returned by GetFileAttributes incorrectly. These are combinations of bit flags. In other words, multiple file attribute flags may be set. You need to use the bitwise and operator, & to test for the presence of the flags.


You also get the error checking badly wrong. The documentation says:

If the function fails, the return value is INVALID_FILE_ATTRIBUTES. To get extended error information, call GetLastError.

In other words, you should only call GetLastError when GetFileAttributes returns a value of INVALID_FILE_ATTRIBUTES. This is an incredibly common mistake, that of thinking that errors are indicated by GetLastError returning a non-zero value. You must read the documentation for each and every API function to be clear on how it signals errors.


Finally, if you do successfully obtain a valid Win32 error code, use FormatMessage to get a textual description of the error.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Your answer was very informative, i started c++ about 1,5 years ago on my own on the sofa. i'm trying to understand the messages from `GetFileAttributes` without hardcode all the posibilities. to prevent my directX experiment to jam because it can´t find the bmp file. thank you! – NaturalDemon Jun 01 '14 at 00:40
1

You cannot type-cast a DWORD into a string. You have to format it.

Your error checking is wrong.

On success, GetFileAttributes() can (and frequently does) return multiple attributes at a time, but you are not handling that possibility. And some of the values you are checking for are not even value attributes to begin with.

Try this instead:

BOOL FileExists(LPCTSTR szPath)
{
    DWORD dwAttrib = GetFileAttributes(szPath);
    if (dwAttrib == INVALID_FILE_ATTRIBUTES)
    {
        DWORD dw = GetLastError();
        switch (dw)
        {
            case ERROR_PATH_NOT_FOUND:
                MessageBoxW(NULL, L"ERROR_PATH_NOT_FOUND", L"File Error", MB_OK);
                break;

            case ERROR_FILE_NOT_FOUND:
                MessageBoxW(NULL, L"ERROR_FILE_NOT_FOUND", L"File Error", MB_OK);
                break;

            default:
            {
                std::wstringstream msg;
                msg << L"Error Code: " << dw;

                LPWSTR lpMsg = NULL;
                if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dw, 0, (LPWSTR)&lpMsg, 0, NULL))
                {
                    msg << std::endl << lpMsg;
                    LocalFree(lpMsg);
                }

                MessageBoxW(NULL, msg.str().c_str(), L"File Error", MB_OK);
                break;
            }
        }

        return false;
    }
    else
    {
        std::wstringstream attribs;

        if (dwAttrib & FILE_ATTRIBUTE_READONLY)
        {
            attribs << L"FILE_ATTRIBUTE_READONLY" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
        }

        if (dwAttrib & FILE_ATTRIBUTE_HIDDEN)
        {
            attribs << L"FILE_ATTRIBUTE_HIDDEN" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN;
        }

        if (dwAttrib & FILE_ATTRIBUTE_SYSTEM)
        {
            attribs << L"FILE_ATTRIBUTE_SYSTEM" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM;
        }

        if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)
        {
            attribs << L"FILE_ATTRIBUTE_DIRECTORY" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_DIRECTORY;
        }

        if (dwAttrib & FILE_ATTRIBUTE_ARCHIVE)
        {
            attribs << L"FILE_ATTRIBUTE_ARCHIVE" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE;
        }

        if (dwAttrib & FILE_ATTRIBUTE_DEVICE)
        {
            attribs << L"FILE_ATTRIBUTE_DEVICE" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_DEVICE;
        }

        if (dwAttrib & FILE_ATTRIBUTE_NORMAL)
        {
            attribs << L"FILE_ATTRIBUTE_NORMAL" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_NORMAL;
        }

        if (dwAttrib & FILE_ATTRIBUTE_TEMPORARY)
        {
            attribs << L"FILE_ATTRIBUTE_TEMPORARY" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_TEMPORARY;
        }

        if (dwAttrib & FILE_ATTRIBUTE_SPARSE_FILE)
        {
            attribs << L"FILE_ATTRIBUTE_SPARSE_FILE" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_SPARSE_FILE;
        }

        if (dwAttrib & FILE_ATTRIBUTE_REPARSE_POINT)
        {
            attribs << L"FILE_ATTRIBUTE_REPARSE_POINT" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_REPARSE_POINT;
        }

        if (dwAttrib & FILE_ATTRIBUTE_COMPRESSED)
        {
            attribs << L"FILE_ATTRIBUTE_COMPRESSED" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_COMPRESSED;
        }

        if (dwAttrib & FILE_ATTRIBUTE_OFFLINE)
        {
            attribs << L"FILE_ATTRIBUTE_OFFLINE" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_OFFLINE;
        }

        if (dwAttrib & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
        {
            attribs << L"FILE_ATTRIBUTE_NOT_CONTENT_INDEXED" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
        }

        if (dwAttrib & FILE_ATTRIBUTE_ENCRYPTED)
        {
            attribs << L"FILE_ATTRIBUTE_ENCRYPTED" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_ENCRYPTED;
        }

        if (dwAttrib & FILE_ATTRIBUTE_VIRTUAL)
        {
            attribs << L"FILE_ATTRIBUTE_VIRTUAL" << std::endl;
            dwAttrib &= ~FILE_ATTRIBUTE_VIRTUAL;
        }

        if (dwAttrib != 0)
            attribs << L"Other: " << std::hex << std::showbase << std::setw(8) << std::setfill(L'0') << dwAttribs << std::endl;

        MessageBoxW(NULL, attribs.str().c_str(), L"File Attributes", MB_OK);

        return true;
    }
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • It is not undefined behavior. It is defined behavior. A temporary is not destroyed until it goes out of scope, and it does not go out of scope until the entire full-expression is finished. In this case, not until `MessageBoxW()` has been called and exited. – Remy Lebeau May 29 '14 at 18:04
  • this is not the final version of the method, i´m just figuring out how to visualize the values. but i do take your advice on multiple attributes in consideracion. you suggest a while a do while? to scan for multiple? – NaturalDemon Jun 01 '14 at 00:31
  • Thank you, after adding the corresponding header files, it worked and cleared alot of things, thanks again. – NaturalDemon Jun 01 '14 at 01:37
  • You are writing a file existence checker. The only flag that is relevant to that logic is `FILE_ATTRIBUTE_DIRECTORY`. The rest of the checker logic relies on `GetLastError()` instead. If you want to display the attributes of a file, you should write a separate function for that purpose. – Remy Lebeau Jun 01 '14 at 02:10