Patrik Stridvall ps@leissner.se writes:
So the question is: Should we use the FORWARD_WM_* macros to avoid typecasts (or rather avoid visable typecast) or should we not? If not how should we fix the problems?
I think it's better to avoid that. Hiding the typecasts in the macros doesn't really make things cleaner IMO. This is a case where the API design forces us to use a typecast, so we might as well make it explicit.
True, but be aware of the macros often use a double type cast like (LPARAM)(HWND). I'm not sure this is really helpful, since I guess it will reveal but a few type error if any at all.
Also note that the macros also takes care of MAKEWPARAM and MAKELPARAM stuff so it makes the code a little more readable.
Anyway, never mind. We could be a little more clever than the macros permit that if we like. See below.
Note that for the specific case of WM_GET/SETTEXT, it would be much better to use Get/SetWindowText which will do correct type checks.
True. They was just an example. They are a few more with similar problems but they are few (less than 10 IIRC). I guess we can worry about them later.
But for messages that don't have a corresponding function we have to do the typecast.
As the macros work now, yes. But we could extend the "macros" to be a little more clever than that.
Take for example one of the more advanced macros #define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
We could quite easily write it like: #define _FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) #if defined(__WINE__) && defined(__GNUC__) extern inline void _WINE_FORWARD_WM_LBUTTONDOWN(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags, WNDPROC *fn) { /* return */ _FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, *fn); } #define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ _WINE_FORWARD_WM_LBUTTONDOWN((hwnd), (fDoubleClick), (x), (y), (keyFlags), &(fn)) #else #define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ _FORWARD_WM_LBUTTONDOWN((hwnd), (fDoubleClick), (x), (y), (keyFlags), (fn)) #endif
Or something like that. I'm not even sure the __WINE__ is needed. I not sure that any Winelib application could possibly misuse the macros in such a way that the result is not semantically the same (type warnings/errors excluded of course).
Note that it is quite easy to write script that automatically does this to avoid subtle bugs especially since the correct (almost) prototype is already before each macro. Like in the case above: /* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
This will give us all the advantages of the "macros" without any typecasts that could possibly hide a type error.
What do you say?
Note that we don't have to implement the solution above right now either. Using the macros as they are will not gain us very much (except possible a cleaner looking code), true. However when we implement the type safe "macros" as described above we will immediately find any and all type errors concerning such code.
Anway fixing windowsx.h to look like above will not be very difficult either so there is no real reason to wait is it?
PS. As hinted above this will also work with most (all?) Winelib applications that happends to use the windowsx.h macros and enable the finding of subtle type errors in such applications.