Displaying Error Text from Enumeration

In my program, I am loading an image from a file, using the GDI+ function, Image::FromFile(). I then check for errors, using Image::GetlastStatus(). This function returns an integer value, which corresponds to a sting in the "Status" enumeration.

My question is: How do I acquire the text string in that enumeration, so that I can display it for error handling? Do I need to copy it into my own array of strings? Or, has it already been declared in a Windows header file? I can't seem to access it, even though I have included both "windows.h" and "gdiplus.h".

Here is the MS documentation on the Status enumeration:

https://docs.microsoft.com/en-us/windows/win32/api/gdiplustypes/ne-gdiplustypes-status
For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
auto img = Image::FromFile()
Status status = GetLastStatus();

switch (status)
{
      case Ok:
           break; // no error

      case GenericError:
           MessageBox(... show error here );

          // ...
      case InsufficientBuffer:
          MessageBox(... show error here );

         // AND SO ON
}


You wrap this switch into some function and then call it each time to check for error.
Thanks Malibor. Using a switch statement is one of the options that I have considered. I have also considered copying the text of the enum into an array of strings, and placing it in a header file. Of course, this is assuming that MS has posted them in the correct order.
You don't need to care about the order if you use switch and it's less error prone.

Copy paste enum from MS, duplicate it, then copy paste one quotation " an just do CTRL + V from each side to turn it into a string, then CTRL + X each string into first enum, that's less than a minute to make full switch. and error function is ready done.
OK, you don't have to anything, thanks to google, just click the link bellow, copy/paste and that's it ;)

https://stackoverflow.com/questions/4933662/how-to-convert-gdi-status-to-string/33453565#33453565

Although I would prefer message box so I can click OK/CANCEL :D
Last edited on
Oh, there will definitely be a message box. Thanks for finding that. Now, i just have to decide how I am going to package my function.
Interesting result: I used that switch statement (though I had to do a bit of cutting and pasting to put the messages into message boxes. Now, the interesting part: I purposely used a bad file name. However, the error message said, "Out of Memory". Not a mistake on my part.
can you post your function?
Here is the function. The sole parameter is the result of the GetLastStatus() function. The return value is a yea-or-nay flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bool GdipErrorHandler(int code) {
    switch (code) {
        case Gdiplus::Ok:                                                                                                    return 1;
        case Gdiplus::GenericError:               MessageBoxW(0, L"Generic Error", L"Error", MB_ICONWARNING);                return 0;
        case Gdiplus::InvalidParameter:           MessageBoxW(0, L"Invalid Parameter", L"Error", MB_ICONWARNING);            return 0;
        case Gdiplus::OutOfMemory:                MessageBoxW(0, L"Out Of Memory", L"Error", MB_ICONWARNING);                return 0;
        case Gdiplus::ObjectBusy:                 MessageBoxW(0, L"Object Busy", L"Error", MB_ICONWARNING);                  return 0;
        case Gdiplus::InsufficientBuffer:         MessageBoxW(0, L"Insufficient Buffer", L"Error", MB_ICONWARNING);          return 0;
        case Gdiplus::NotImplemented:             MessageBoxW(0, L"Not Implemented", L"Error", MB_ICONWARNING);              return 0;
        case Gdiplus::Win32Error:                 MessageBoxW(0, L"Win32 Error", L"Error", MB_ICONWARNING);                  return 0;
        case Gdiplus::Aborted:                    MessageBoxW(0, L"Aborted", L"Error", MB_ICONWARNING);                      return 0;
        case Gdiplus::FileNotFound:               MessageBoxW(0, L"File Not Found", L"Error", MB_ICONWARNING);               return 0;
        case Gdiplus::ValueOverflow:              MessageBoxW(0, L"Value Overflow", L"Error", MB_ICONWARNING);               return 0;
        case Gdiplus::AccessDenied:               MessageBoxW(0, L"Access Denied", L"Error", MB_ICONWARNING);                return 0;
        case Gdiplus::UnknownImageFormat:         MessageBoxW(0, L"Unknown Image Format", L"Error", MB_ICONWARNING);         return 0;
        case Gdiplus::FontFamilyNotFound:         MessageBoxW(0, L"Font Family Not Found", L"Error", MB_ICONWARNING);        return 0;
        case Gdiplus::FontStyleNotFound:          MessageBoxW(0, L"Font Style Not Found", L"Error", MB_ICONWARNING);         return 0;
        case Gdiplus::NotTrueTypeFont:            MessageBoxW(0, L"Not TruType Font", L"Error", MB_ICONWARNING);             return 0;
        case Gdiplus::UnsupportedGdiplusVersion:  MessageBoxW(0, L"Unsupported Gdiplus Version", L"Error", MB_ICONWARNING);  return 0;
        case Gdiplus::GdiplusNotInitialized:      MessageBoxW(0, L"Gdiplus Not Initialized", L"Error", MB_ICONWARNING);      return 0;
        case Gdiplus::PropertyNotFound:           MessageBoxW(0, L"Property Not Found", L"Error", MB_ICONWARNING);           return 0;
        case Gdiplus::PropertyNotSupported:       MessageBoxW(0, L"Property Not Supported", L"Error", MB_ICONWARNING);       return 0;
        default:                                  MessageBoxW(0, L"Unknown Error", L"Error", MB_ICONWARNING);                return 0;
     }
    return 0;
 }
Last edited on
One possibility, is that I'm using the wrong data type for the return value of Image::GetLastStatus(). The MS doc says that the return type is "Status". But, there is no data type "Status" or "status". I get an error. So, I used an "int" type, instead. I don't get any errors or warnings that way. So, I figured that was what I needed.
But, there is no data type "Status" or "status"

What do you think typedef enum Status is ?
Since I don't know what character encoding you use, here is a generic function that should work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
bool GdiStatus(const Gdiplus::Status code)
{
	#ifdef UNICODE
	std::wstring error = TEXT("No Error");
	#else
	std::string error = TEXT("No Error");
	#endif // UNICODE

	switch (code)
	{
	case Gdiplus::Ok:
		return false;  // Not an error
	case Gdiplus::GenericError:
		error = TEXT("GenericError");
		break;
	case Gdiplus::InvalidParameter:
		error = TEXT("InvalidParameter");
		break;
	case Gdiplus::OutOfMemory:
		error = TEXT("OutOfMemory");
		break;
	case Gdiplus::ObjectBusy:
		error = TEXT("ObjectBusy");
		break;
	case Gdiplus::InsufficientBuffer:
		error = TEXT("InsufficientBuffer");
		break;
	case Gdiplus::NotImplemented:
		error = TEXT("NotImplemented");
		break;
	case Gdiplus::Win32Error:
		error = TEXT("Win32Error");
		break;
	case Gdiplus::Aborted:
		error = TEXT("Aborted");
		break;
	case Gdiplus::FileNotFound:
		error = TEXT("FileNotFound");
		break;
	case Gdiplus::ValueOverflow:
		error = TEXT("ValueOverflow");
		break;
	case Gdiplus::AccessDenied:
		error = TEXT("AccessDenied");
		break;
	case Gdiplus::UnknownImageFormat:
		error = TEXT("UnknownImageFormat");
		break;
	case Gdiplus::FontFamilyNotFound:
		error = TEXT("FontFamilyNotFound");
		break;
	case Gdiplus::FontStyleNotFound:
		error = TEXT("FontStyleNotFound");
		break;
	case Gdiplus::NotTrueTypeFont:
		error = TEXT("NotTrueTypeFont");
		break;
	case Gdiplus::UnsupportedGdiplusVersion:
		error = TEXT("UnsupportedGdiplusVersion");
		break;
	case Gdiplus::GdiplusNotInitialized:
		error = TEXT("GdiplusNotInitialized");
		break;
	case Gdiplus::PropertyNotFound:
		error = TEXT("PropertyNotFound");
		break;
	case Gdiplus::PropertyNotSupported:
		error = TEXT("PropertyNotSupported");
		break;
	default:
		MessageBox(nullptr, TEXT("Unknown Error"), TEXT("GDI+ Error"), MB_OK);
		return false;	// Not GDI+ error
	}

	MessageBox(nullptr, error.c_str(), TEXT("GDI+ Error"), MB_OK);
	return true;
}


Here is how you test it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// TEST CASE
int main()
{
	// TODO: update image file name
	Gdiplus::Image* img = Gdiplus::Image::FromFile(TEXT("image.jpg"));

	if (img)
	{
		Gdiplus::Status code = img->GetLastStatus();
		GdiStatus(code);
	}

        // make explicit test
	GdiStatus(Gdiplus::Status::InsufficientBuffer);
}

Last edited on
The type is actually Gdiplus::Status so whether or not Status alone works will depend on a using namespace Gdiplus; being used (or not.)

For your function GdipErrorHandler(), using an int parameter isn't such a bad idea, as you're handling the "Unknown Error" case.

You could consider splitting your function into two: one which get the text for the Gdiplus status and another which displays the popup if it's not a success. The first of these could then be used if you wanted to implement error logging or the like.

Andy

EDIT corrected namespace from GdiPlus to Gdiplus
Last edited on
Thanks Andywestken. "Gdiplus::Status" works--it is accepted as a valid type. By the way, it's "Gdiplus", not "GdiPlus" (for those who might be reading this later). The 'p' is not capitalized. You know, I tried every combination typedefs, except that one. It should have been obvious. I should have known better than to try to code, after tiring myself out, mowing the yard.

I also broke-up the function, along the lines of what Malibor suggested. Here is the code fragment, where I call the GdipErrorHandler() function:

1
2
3
4
5
6
7
8
9
10
11
    static bool  bFileFlag=0;
    ...    
    ...
       case WM_CREATE:
         {
            Gdiplus::Status Sts;

            image1 = Gdiplus::Image::FromFile(L"Night BW test.jpg");
            Sts = image1->GetLastStatus();
            bFileFlag = GdipErrorHandler(Sts);
          }


The variable "bFileFlag" is used later in WM_PAINT. If bFileFlag is "TRUE", paint the image. If "FALSE", paint a blank window. This will come in handy later, when the routine is started without an image, and the image is later loaded from a dialog box.

Here is the new version of the GdipErrorHandler() function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
bool GdipErrorHandler(Gdiplus::Status code) {
    bool flag;
    const wchar_t *txt = nullptr;

    switch (code) {
        case Gdiplus::Ok:                                                                flag = 1;   break;
        case Gdiplus::GenericError:               txt = L"Generic Error";                flag = 0;   break;
        case Gdiplus::InvalidParameter:           txt = L"Invalid Parameter";            flag = 0;   break;
        case Gdiplus::OutOfMemory:                txt = L"Out Of Memory";                flag = 0;   break;
        case Gdiplus::ObjectBusy:                 txt = L"Object Busy";                  flag = 0;   break;
        case Gdiplus::InsufficientBuffer:         txt = L"Insufficient Buffer";          flag = 0;   break;
        case Gdiplus::NotImplemented:             txt = L"Not Implemented";              flag = 0;   break;
        case Gdiplus::Win32Error:                 txt = L"Win32 Error";                  flag = 0;   break;
        case Gdiplus::Aborted:                    txt = L"Aborted";                      flag = 0;   break;
        case Gdiplus::FileNotFound:               txt = L"File Not Found";               flag = 0;   break;
        case Gdiplus::ValueOverflow:              txt = L"Value Overflow";               flag = 0;   break;
        case Gdiplus::AccessDenied:               txt = L"Access Denied";                flag = 0;   break;
        case Gdiplus::UnknownImageFormat:         txt = L"Unknown Image Format";         flag = 0;   break;
        case Gdiplus::FontFamilyNotFound:         txt = L"Font Family Not Found";        flag = 0;   break;
        case Gdiplus::FontStyleNotFound:          txt = L"Font Style Not Found";         flag = 0;   break;
        case Gdiplus::NotTrueTypeFont:            txt = L"Not TruType Font";             flag = 0;   break;
        case Gdiplus::UnsupportedGdiplusVersion:  txt = L"Unsupported Gdiplus Version";  flag = 0;   break;
        case Gdiplus::GdiplusNotInitialized:      txt = L"Gdiplus Not Initialized";      flag = 0;   break;
        case Gdiplus::PropertyNotFound:           txt = L"Property Not Found";           flag = 0;   break;
        case Gdiplus::PropertyNotSupported:       txt = L"Property Not Supported";       flag = 0;   break;
        default:                                  txt = L"Unknown Error";                flag = 0;
     }

    if (!flag)  MessageBoxW(0, txt, L"Error", MB_ICONWARNING);
    return flag;
 }


Yet, when I give it a bad file name, it still returns "Out of Memory". I have tried feeding that function hard-coded variables, as Malibor suggested. They all check-out--the correct results are displayed each time. My only conclusion is that GetLastStatus() is returning the wrong value.
Why do you write switch like this? all on one line..

why not setting flag variable to false right away, and setting it to true only in case Gdiplus::Ok:?

You don't even need that variable btw.

Also your test case in case WM_CREATE: is not good.
Last edited on
Yeah, I probably should set the flag to '0', right off---the way I do in the WndProc() procedure. Writing switch/case statements on one line is an old habit of mine. Somehow, for me, it makes it easier to read. Plus, I don't have to scroll through nearly as many lines.

I am curious though, why you think my test in WM_CREATE is no good. I ask because, that may be the reason why I am getting the wrong error message.
It's not good because if Image::FromFile fails, then your next call to image1->GetLastStatus() will crash the program.

secondly
GetLastStatus()
returns an error code for the last method call, but you called none of the methods yourself.

The most likely reason you get OutOfMemory error is because the Image object did some memory allocation, failed and then recovered.

What you did is call get last error and that's what you got.

If you want to verify this then call some method on your image1 pointer after creating it and then check error code to get correct result.
Last edited on
Actually, the program works quite well, if I supply a valid file name. The image loads and displays, as it should. Even if I supply a bogus file name, it still functions as it should. If there is an error in loading the image, my function returns a flag, telling the rest of the program that there is no image. The program proceeds accordingly. No crash. The only "problem" seems to be, getting the wrong error code.

I see what you mean though, about the "image1->GetLastStatus()" function. If the file doesn't load, how can there be any "status". I will say however, that the object is defined long before the FromFile() call. This is the statement that I have at the head of the WndProc)() function:

static Gdiplus::Image *image1=nullptr;

I have checked though, to see if there are other means of error checking. But, all of the documentation that I find, steers me back to GetLastStatus().
Topic archived. No new replies allowed.