This is going to be a really stupid question and I hope it's fine for Stack Exchange at all, let alone just this part of it...
Right now, my custom Table control uses panic()
functions that print an error on screen and DebugBreak()
when a Windows API error occurs.
This is obviously an issue, but I'm not completely sure how to go about fixing it without effectively ignoring errors entirely. Keyword "effectively": even if I catch errors, if I can't do anything with them (be it forward the error to the user or to something else) it doesn't really count if I check for them.
Now for user-initiated functions (like tableAddColumn
in my control) this isn't really an issue: just return the error information as a return value to the function.
My question is: what's the best way to handle Windows API errors in response to things where I can't obviously just return error information somehow. For instance, what if one of the drawing functions that I call in response to WM_PAINT
fails? None of the system-provided messages provide functionality to return the API error to the system; they all just tell you to return zero if you handled the message.
I was thinking of creating a WM_NOTIFY
notification tableErrorOccurred
that gets sent to the control's parent when an API error occurs. However, I'm not sure how that would interact with the accessibility code. Windows accessible code is all COM, so I can freely return API errors via the HRESULT returns. Should those count toward the notification, or not? (Especially since the notification can and will return more information than just the HRESULT.)
I'm not sure whatever options there are, other than discounting the possibility of an error when all error conditions are made impossible. My current policy is to only check for an error when a function explicitly says it returns an error and how (for example, SendMessage()
, EndPaint()
, and SetScrollInfo()
don't), and to ignore any commentary on which errors can be returned, in case the list of possible errors for whatever reason changes in the future. Am I wrong in this particular scenario: that is, would the error returns be guaranteed to never change and thus functions that only return errors on invalid parameters guaranteed to never fail with known valid parameters?
Some people have told me or talked about another Raymond Chen adage, "don't check for errors you don't know how to handle". Maybe someone can tell me that I'm misinterpreting this statement or something to that extent? Especially after the second link: it asks about what you would do with the error. I know what I want to do with these API errors: send them up to the thing that issued my own API request, just like every other API request in (almost) every other API ever! Is there a difference between doing this and "handling" the error? (You can tell that as I write more and more of this question, I am getting less and less sure of what my own opinion is, or whether any of this even IS a problem...)
The most common cases are calling GetClientRect()
, which I could just save in my data structure if I can guarantee there are no cases in which the return value can change without a WM_WINDOWPOSCHANGED
, and getting the height of the currently selected text font, which I can't save without sacrificing DPI independence (I deliberately get it every time to avoid the risk of crossing a DPI change boundary should a user program enable DPI awareness). The files util.h
and coord.h
have more info, but scroll.h
and draw.h
have the most API calls as far as I know.
The bits of the wine source code that I've seen don't check for errors. That's the only bit of information I have to say at this point. I'm not going to doubt that wine is a quality piece of software with a lot of effort put into it, but it seems odd to me that it does work well without explicit error checks on every API call...
I really don't want to rant about things here, so apologies in advance if this paragraph (and the previous) doesn't seem to go anywhere: It would be easier if I could return errors up to the system, or from SendMessage()
(with the LRESULT
as an out parameter, like COM method calls do). I don't really know. My experience with other GUI toolkits is that in most cases the only errors are incorrect parameters, but that really seems suspiciously optimistic to me. My main programming language for non-GUI stuff right now is Go, where errors are so fundamental that they're handled throughout both the standard library and user libraries (and have always been this way, without changes over time), and thus we know to carry errors up through the call chain; this reflects my own idea of error handling (and vice versa, to some extent).
So if anyone has any advice from the real world, that would be great, especially as I am close to finishing this and splitting out from the github project linked into something general purpose. Thanks.
EDIT 1 March 2015
I don't know why I forgot to paste this earlier but this is what some people on IRC said the day I posted this
[Sunday, February 15, 2015] [06:09:44 PM] <Rena> andlabs, I think by "don't check for errors you can't handle" they mean just ignore them entirely.
[Sunday, February 15, 2015] [06:09:59 PM] <Rena> I mean I can't really think of a sane thing to do if WM_PAINT is failing
[Sunday, February 15, 2015] [06:10:39 PM] <Rena> sometimes there's nothing you can do but let it break
[Sunday, February 15, 2015] [06:19:17 PM] <andlabs> Rena: yes, and that just goes against /everyhting/ I've been taugh tand everyone has been teaching everytone else!
[Sunday, February 15, 2015] [06:19:23 PM] <andlabs> that's why I'm [expletive] confused!
[Sunday, February 15, 2015] [06:20:54 PM] <andlabs> Rena: point that out anyway :S
[Sunday, February 15, 2015] [06:21:09 PM] <devin> nobody ever tries to catch std::bad_alloc in C++ because if you've even reached the point where that's being thrown under normal circumstances then you're probably [expletive] and should just let the ship sink anyway
[Sunday, February 15, 2015] [06:21:37 PM] <Rena> well things like, what are you even going to do if drawing something fails? it's not a huge issue and there's probably nothing you can do about it.
[Sunday, February 15, 2015] [06:21:49 PM] <Rena> probably it means the system is running out of GDI memory or something
[Sunday, February 15, 2015] [06:22:47 PM] <andlabs> Rena: right, at least in the case of WM_PAINT
[Sunday, February 15, 2015] [06:23:09 PM] <Rena> if it's like memory allocation failed in some tool, it'd be a good idea to handle that by throwing up an "out of memory" message and/or trying to save the current file to a scratch file somewhere, instead of just crashing and losing work
[Sunday, February 15, 2015] [06:23:43 PM] <andlabs> right
[Sunday, February 15, 2015] [06:23:59 PM] <andlabs> ...actually I'll have to keep a note of that
[Sunday, February 15, 2015] [06:24:23 PM] <andlabs> the other situations in which a reallocation would fail is
[Sunday, February 15, 2015] [06:24:25 PM] <andlabs> a) heap corruption
[Sunday, February 15, 2015] [06:24:30 PM] <andlabs> in which case you actually ARE [expletive]
[Sunday, February 15, 2015] [06:24:40 PM] <andlabs> b) passing a pointer to something that isn't part of the realloc heap
[Sunday, February 15, 2015] [06:24:51 PM] <andlabs> c) passing an obviously bad size like -4
[Sunday, February 15, 2015] [06:38:02 PM] <andlabs> Rena, devin - yeah :/
[Sunday, February 15, 2015] [06:38:07 PM] <andlabs> I figure that much :S
FillRect
, what could you possibly do about it? Crash, or continue without that rectangle?