Windows headers vs. nonameless struct/union

Francois Gouget fgouget at free.fr
Fri Aug 13 05:39:54 CDT 2004


MS made a token effort to make their headers compatible with compilers
that don't support nameless structs or unions. But it went no further
than that. The Windows headers are thus not usable if you expect not to
have nameless structs or unions.

Just three examples:

 * in wtypes.h DECIMAL contains nameless structs and unions and there is
no way to force them to have a name.
   This causes errors when compiling some of the oleaut32 tests.

 * the VARIANT type defined in oaidl.h has nameless structs and unions
but one can force these to be named by defining NONAMELESSUNION. This is
done in a non-standard way: NONAMELESSUNION affects both structs and
unions, instead of s, s1, u, u1 we have n1, n2, n3, etc.
   But more importantly, oleaut.h defines the V_DECIMAL() as follows:

   #define V_DECIMAL(X)     V_UNION(X, decVal)

   The problem is that V_UNION is fine for accessing fields that are in
the most nested struct/union (i.e. in X.n1.n2.n3), but decVal is the
exception: it is in X.n1. So V_DECIMAL() works fine as long as we use
nameless unions/structs and breaks otherwise.
  This causes more compilation errors in oleaut32 tests.

 * in mmsystem.h MIXERCONTROL contains namnameless structs and unions
and there is no way to force them to have a name.
   This causes errors when compiling some of the mixer winmm test.


This patch remedies these problems by:

 * not defining NONAMELESSUNION and NONAMELESSSTRUCT in our tests. This
lets them compile with the Windows headers.
 * with the Wine headers, winnt.h automatically determines whether the
compiler supports nameless structs/unions and sets NONAMELESSUNION and
NONAMELESSSTRUCT accordingly.
 * in our tests we check NONAMELESSUNION and NONAMELESSSTRUCT and define
our own access macros accordingly:

   #ifdef NONAMELESSSTRUCT
   # define S1(x) (x).s1
   #else
   # define S1(x) (x)
   #endif

   Then we can write S1(array[nc].Bounds).dwMinimum and that will work
whether we compile using the Windows or Wine headers, and whether we use
nameless structs or not.


Changelog:

 * dlls/oleaut32/tests/vartest.c
   dlls/oleaut32/tests/vartype.c
   dlls/winmm/tests/mixer.c

   The Windows headers support for NONAMELESSUNION and NONAMELESSSTRUCT
is unusable. So don't force this mode.
   Instead check whether NONAMELESSUNION and/or NONAMELESSSTRUCT are set
(by the Wine headers) and define custom access macros accordingly.
   This fixes compilation errors with the Windows headers in the
oleaut32 and winmm tests.


Index: dlls/oleaut32/tests/vartest.c
===================================================================
RCS file: /var/cvs/wine/dlls/oleaut32/tests/vartest.c,v
retrieving revision 1.29
diff -u -r1.29 vartest.c
--- dlls/oleaut32/tests/vartest.c	27 Apr 2004 23:29:58 -0000	1.29
+++ dlls/oleaut32/tests/vartest.c	12 Aug 2004 12:07:23 -0000
@@ -25,8 +25,6 @@
 #include <float.h>
 #include <time.h>

-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
 #include "windef.h"
 #include "winbase.h"
 #include "winsock.h"
@@ -42,6 +40,21 @@

 static HMODULE hOleaut32;

+#ifdef NONAMELESSUNION
+# define U(x)  (x).u
+# define U1(x) (x).u1
+#else
+# define U(x)  (x)
+# define U1(x) (x)
+#endif
+#ifdef NONAMELESSSTRUCT
+# define S(x)  (x).s
+# define S1(x) (x).s1
+#else
+# define S(x)  (x)
+# define S1(x) (x)
+#endif
+
 static HRESULT (WINAPI *pVarUdateFromDate)(DATE,ULONG,UDATE*);
 static HRESULT (WINAPI *pVarDateFromUdate)(UDATE*,ULONG,DATE*);
 static INT (WINAPI *pSystemTimeToVariantTime)(LPSYSTEMTIME,double*);
@@ -1815,11 +1828,11 @@
     ok(V_VT(&v) == VT_BSTR && V_BSTR(&v) == szNum1, "VarNot(1): changed input\n");

     V_VT(&v) = VT_DECIMAL;
-    pdec->u.s.sign = DECIMAL_NEG;
-    pdec->u.s.scale = 0;
+    S(U(*pdec)).sign = DECIMAL_NEG;
+    S(U(*pdec)).scale = 0;
     pdec->Hi32 = 0;
-    pdec->u1.s1.Mid32 = 0;
-    pdec->u1.s1.Lo32 = 1;
+    S1(U1(*pdec)).Mid32 = 0;
+    S1(U1(*pdec)).Lo32 = 1;
     VARNOT(DECIMAL,*pdec,I4,0);

     pcy->int64 = 10000;
@@ -2403,11 +2416,11 @@
        "VarFix: expected 0x0,%d got 0x%lX,%d\n", VT_NULL, hres, V_VT(&vDst));

     V_VT(&v) = VT_DECIMAL;
-    pdec->u.s.sign = DECIMAL_NEG;
-    pdec->u.s.scale = 0;
+    S(U(*pdec)).sign = DECIMAL_NEG;
+    S(U(*pdec)).scale = 0;
     pdec->Hi32 = 0;
-    pdec->u1.s1.Mid32 = 0;
-    pdec->u1.s1.Lo32 = 1;
+    S1(U1(*pdec)).Mid32 = 0;
+    S1(U1(*pdec)).Lo32 = 1;
     hres = pVarFix(&v,&vDst);
     ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && !memcmp(&v, &vDst, sizeof(v)),
        "VarFix: expected 0x0,%d,identical, got 0x%lX,%d\n", VT_DECIMAL,
@@ -2520,11 +2533,11 @@
        "VarInt: expected 0x0,%d got 0x%lX,%d\n", VT_NULL, hres, V_VT(&vDst));

     V_VT(&v) = VT_DECIMAL;
-    pdec->u.s.sign = DECIMAL_NEG;
-    pdec->u.s.scale = 0;
+    S(U(*pdec)).sign = DECIMAL_NEG;
+    S(U(*pdec)).scale = 0;
     pdec->Hi32 = 0;
-    pdec->u1.s1.Mid32 = 0;
-    pdec->u1.s1.Lo32 = 1;
+    S1(U1(*pdec)).Mid32 = 0;
+    S1(U1(*pdec)).Lo32 = 1;
     hres = pVarInt(&v,&vDst);
     ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && !memcmp(&v, &vDst, sizeof(v)),
        "VarInt: expected 0x0,%d,identical, got 0x%lX,%d\n", VT_DECIMAL,
@@ -2646,23 +2659,23 @@
        "VarNeg: expected 0x0,%d got 0x%lX,%d\n", VT_NULL, hres, V_VT(&vDst));

     V_VT(&v) = VT_DECIMAL;
-    pdec->u.s.sign = DECIMAL_NEG;
-    pdec->u.s.scale = 0;
+    S(U(*pdec)).sign = DECIMAL_NEG;
+    S(U(*pdec)).scale = 0;
     pdec->Hi32 = 0;
-    pdec->u1.s1.Mid32 = 0;
-    pdec->u1.s1.Lo32 = 1;
+    S1(U1(*pdec)).Mid32 = 0;
+    S1(U1(*pdec)).Lo32 = 1;
     hres = pVarNeg(&v,&vDst);
     ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
-       V_DECIMAL(&vDst).u.s.sign == 0,
+       S(U(V_DECIMAL(&vDst))).sign == 0,
        "VarNeg: expected 0x0,%d,0x00, got 0x%lX,%d,%02x\n", VT_DECIMAL,
-       hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign);
+       hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign);

-    pdec->u.s.sign = 0;
+    S(U(*pdec)).sign = 0;
     hres = pVarNeg(&v,&vDst);
     ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
-       V_DECIMAL(&vDst).u.s.sign == DECIMAL_NEG,
+       S(U(V_DECIMAL(&vDst))).sign == DECIMAL_NEG,
        "VarNeg: expected 0x0,%d,0x7f, got 0x%lX,%d,%02x\n", VT_DECIMAL,
-       hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign);
+       hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign);

     V_VT(&v) = VT_CY;
     pcy->int64 = -10000;
@@ -2766,23 +2779,23 @@
     todo_wine {
         DECIMAL *pdec = &V_DECIMAL(&v);
         V_VT(&v) = VT_DECIMAL;
-        pdec->u.s.sign = DECIMAL_NEG;
-        pdec->u.s.scale = 0;
+        S(U(*pdec)).sign = DECIMAL_NEG;
+        S(U(*pdec)).scale = 0;
         pdec->Hi32 = 0;
-        pdec->u1.s1.Mid32 = 0;
-        pdec->u1.s1.Lo32 = 1;
+        S1(U1(*pdec)).Mid32 = 0;
+        S1(U1(*pdec)).Lo32 = 1;
         hres = pVarRound(&v,0,&vDst);
         ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
-            V_DECIMAL(&vDst).u.s.sign == 0,
+            S(U(V_DECIMAL(&vDst))).sign == 0,
             "VarRound: expected 0x0,%d,0x00, got 0x%lX,%d,%02x\n", VT_DECIMAL,
-            hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign);
+            hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign);

-        pdec->u.s.sign = 0;
+        S(U(*pdec)).sign = 0;
         hres = pVarRound(&v,0,&vDst);
         ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
-            V_DECIMAL(&vDst).u.s.sign == DECIMAL_NEG,
+            S(U(V_DECIMAL(&vDst))).sign == DECIMAL_NEG,
             "VarRound: expected 0x0,%d,0x7f, got 0x%lX,%d,%02x\n", VT_DECIMAL,
-            hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign);
+            hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign);
     }
     */

Index: dlls/oleaut32/tests/vartype.c
===================================================================
RCS file: /var/cvs/wine/dlls/oleaut32/tests/vartype.c,v
retrieving revision 1.13
diff -u -r1.13 vartype.c
--- dlls/oleaut32/tests/vartype.c	12 Aug 2004 23:00:53 -0000	1.13
+++ dlls/oleaut32/tests/vartype.c	13 Aug 2004 07:24:24 -0000
@@ -17,8 +17,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
+
 #include "wine/test.h"
 #include "wine/unicode.h"
 #include "oleauto.h"
@@ -26,6 +25,21 @@

 static HMODULE hOleaut32;

+#ifdef NONAMELESSUNION
+# define U(x)  (x).u
+# define U1(x) (x).u1
+#else
+# define U(x)  (x)
+# define U1(x) (x)
+#endif
+#ifdef NONAMELESSSTRUCT
+# define S(x)  (x).s
+# define S1(x) (x).s1
+#else
+# define S(x)  (x)
+# define S1(x) (x)
+#endif
+
 /* Get a conversion function ptr, return if function not available */
 #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \
   if (!p##func) { \
@@ -80,13 +94,13 @@

 #define CONVERT_CY(func,val) in.int64 = (LONGLONG)(val * CY_MULTIPLIER); hres = p##func(in, &out)

-#define CONVERT_CY64(func,hi,lo) in.s.Hi = hi; in.s.Lo = lo; in.int64 *= CY_MULTIPLIER; hres = p##func(in, &out)
+#define CONVERT_CY64(func,hi,lo) S(in).Hi = hi; S(in).Lo = lo; in.int64 *= CY_MULTIPLIER; hres = p##func(in, &out)

-#define SETDEC(dec, scl, sgn, hi, lo) dec.u.s.scale = (BYTE)scl; dec.u.s.sign = (BYTE)sgn; \
-  dec.Hi32 = (ULONG)hi; dec.u1.Lo64 = (ULONG64)lo
+#define SETDEC(dec, scl, sgn, hi, lo) S(U(dec)).scale = (BYTE)scl; S(U(dec)).sign = (BYTE)sgn; \
+  dec.Hi32 = (ULONG)hi; U1(dec).Lo64 = (ULONG64)lo

-#define SETDEC64(dec, scl, sgn, hi, mid, lo) dec.u.s.scale = (BYTE)scl; dec.u.s.sign = (BYTE)sgn; \
-  dec.Hi32 = (ULONG)hi; dec.u1.s1.Mid32 = mid; dec.u1.s1.Lo32 = lo;
+#define SETDEC64(dec, scl, sgn, hi, mid, lo) S(U(dec)).scale = (BYTE)scl; S(U(dec)).sign = (BYTE)sgn; \
+  dec.Hi32 = (ULONG)hi; S1(U1(dec)).Mid32 = mid; S1(U1(dec)).Lo32 = lo;

 #define CONVERT_DEC(func,scl,sgn,hi,lo) SETDEC(in,scl,sgn,hi,lo); hres = p##func(&in, &out)

@@ -192,7 +206,7 @@
     hres = VariantChangeTypeEx(&vDst, &vSrc, 0, 0, VT_CY); \
     ok(hres == S_OK && V_VT(&vDst) == VT_CY && V_CY(&vDst).int64 == CY_MULTIPLIER, \
        "->VT_CY hres=0x%lX, type=%d (should be VT_CY), value (%08lx,%08lx) (should be CY_MULTIPLIER)\n", \
-       hres, V_VT(&vDst), V_CY(&vDst).s.Hi, V_CY(&vDst).s.Lo); \
+       hres, V_VT(&vDst), S(V_CY(&vDst)).Hi, S(V_CY(&vDst)).Lo); \
   } \
   if (V_VT(&vSrc) != VT_DATE) \
   { \
@@ -206,11 +220,11 @@
   { \
     hres = VariantChangeTypeEx(&vDst, &vSrc, 0, 0, VT_DECIMAL); \
     ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && \
-       V_DECIMAL(&vDst).u.s.sign == 0 && V_DECIMAL(&vDst).u.s.scale == 0 && \
-       V_DECIMAL(&vDst).Hi32 == 0 && V_DECIMAL(&vDst).u1.Lo64 == (ULONGLONG)in, \
+       S(U(V_DECIMAL(&vDst))).sign == 0 && S(U(V_DECIMAL(&vDst))).scale == 0 && \
+       V_DECIMAL(&vDst).Hi32 == 0 && U1(V_DECIMAL(&vDst)).Lo64 == (ULONGLONG)in, \
        "->VT_DECIMAL hres=0x%lX, type=%d (should be VT_DECIMAL), sign=%d, scale=%d, hi=%lu, lo=(%8lx %8lx),\n", \
-       hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign, V_DECIMAL(&vDst).u.s.scale, \
-       V_DECIMAL(&vDst).Hi32, V_DECIMAL(&vDst).u1.s1.Mid32, V_DECIMAL(&vDst).u1.s1.Lo32); \
+       hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign, S(U(V_DECIMAL(&vDst))).scale, \
+       V_DECIMAL(&vDst).Hi32, S1(U1(V_DECIMAL(&vDst))).Mid32, S1(U1(V_DECIMAL(&vDst))).Lo32); \
   } \
   hres = VariantChangeTypeEx(&vDst, &vSrc, 0, 0, VT_EMPTY); \
   ok(hres == S_OK && V_VT(&vDst) == VT_EMPTY, "->VT_EMPTY hres=0x%lX, type=%d (should be VT_EMPTY)\n", hres, V_VT(&vDst)); \
@@ -3390,12 +3404,12 @@

 #define EXPECTCY(x) \
   ok((hres == S_OK && out.int64 == (LONGLONG)(x*CY_MULTIPLIER)), \
-     "expected " #x "*CY_MULTIPLIER, got (%8lx %8lx); hres=0x%08lx\n", out.s.Hi, out.s.Lo, hres)
+     "expected " #x "*CY_MULTIPLIER, got (%8lx %8lx); hres=0x%08lx\n", S(out).Hi, S(out).Lo, hres)

 #define EXPECTCY64(x,y) \
-  ok(hres == S_OK && out.s.Hi == (long)x && out.s.Lo == y, \
+  ok(hres == S_OK && S(out).Hi == (long)x && S(out).Lo == y, \
      "expected " #x #y "(%lu,%lu), got (%lu,%lu); hres=0x%08lx\n", \
-      (ULONG)(x), (ULONG)(y), out.s.Hi, out.s.Lo, hres)
+      (ULONG)(x), (ULONG)(y), S(out).Hi, S(out).Lo, hres)

 static void test_VarCyFromI1(void)
 {
@@ -3888,19 +3902,19 @@
      "expected hres " #x ", got hres=0x%08lx\n", hres)

 #define EXPECTDEC(scl, sgn, hi, lo) ok(hres == S_OK && \
-  out.u.s.scale == (BYTE)(scl) && out.u.s.sign == (BYTE)(sgn) && \
-  out.Hi32 == (ULONG)(hi) && out.u1.Lo64 == (ULONG64)(lo), \
+  S(U(out)).scale == (BYTE)(scl) && S(U(out)).sign == (BYTE)(sgn) && \
+  out.Hi32 == (ULONG)(hi) && U1(out).Lo64 == (ULONG64)(lo), \
   "expected (%d,%d,%d,(%lx %lx)), got (%d,%d,%ld,(%lx %lx)) hres 0x%08lx\n", \
-  scl, sgn, hi, (LONG)((LONG64)(lo) >> 32), (LONG)((lo) & 0xffffffff), out.u.s.scale, \
-  out.u.s.sign, out.Hi32, out.u1.s1.Mid32, out.u1.s1.Lo32, hres)
+  scl, sgn, hi, (LONG)((LONG64)(lo) >> 32), (LONG)((lo) & 0xffffffff), S(U(out)).scale, \
+  S(U(out)).sign, out.Hi32, S1(U1(out)).Mid32, S1(U1(out)).Lo32, hres)

 #define EXPECTDEC64(scl, sgn, hi, mid, lo) ok(hres == S_OK && \
-  out.u.s.scale == (BYTE)(scl) && out.u.s.sign == (BYTE)(sgn) && \
-  out.Hi32 == (ULONG)(hi) && out.u1.s1.Mid32 == (ULONG)(mid) && \
-  out.u1.s1.Lo32 == (ULONG)(lo), \
+  S(U(out)).scale == (BYTE)(scl) && S(U(out)).sign == (BYTE)(sgn) && \
+  out.Hi32 == (ULONG)(hi) && S1(U1(out)).Mid32 == (ULONG)(mid) && \
+  S1(U1(out)).Lo32 == (ULONG)(lo), \
   "expected (%d,%d,%d,(%lx %lx)), got (%d,%d,%ld,(%lx %lx)) hres 0x%08lx\n", \
-  scl, sgn, hi, (LONG)(mid), (LONG)(lo), out.u.s.scale, \
-  out.u.s.sign, out.Hi32, out.u1.s1.Mid32, out.u1.s1.Lo32, hres)
+  scl, sgn, hi, (LONG)(mid), (LONG)(lo), S(U(out)).scale, \
+  S(U(out)).sign, out.Hi32, S1(U1(out)).Mid32, S1(U1(out)).Lo32, hres)

 #define EXPECTDECI if (i < 0) EXPECTDEC(0, 0x80, 0, -i); else EXPECTDEC(0, 0, 0, i)

@@ -4170,7 +4184,7 @@
   EXPECTDEC64(0,0,0xffffffff,0xffffffff,0xfffffffe);
   SETDEC64(l,0,0,0xffffffff,0xffffffff,0xffffffff);SETDEC(r,0,0,0,1); MATH2(VarDecAdd);
   ok(hres == DISP_E_OVERFLOW,"Expected overflow, got (%d,%d,%ld,(%8lx,%8lx)x) hres 0x%08lx\n",
-     out.u.s.scale, out.u.s.sign, out.Hi32, out.u1.s1.Mid32, out.u1.s1.Lo32, hres);
+     S(U(out)).scale, S(U(out)).sign, out.Hi32, S1(U1(out)).Mid32, S1(U1(out)).Lo32, hres);

   /* Promotes to the highest scale, so here the results are in the scale of 2 */
   SETDEC(l,2,0,0,0);   SETDEC(r,0,0,0,0); MATH2(VarDecAdd); EXPECTDEC(2,0,0,0);
Index: dlls/winmm/tests/mixer.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/tests/mixer.c,v
retrieving revision 1.3
diff -u -r1.3 mixer.c
--- dlls/winmm/tests/mixer.c	11 Aug 2004 18:50:09 -0000	1.3
+++ dlls/winmm/tests/mixer.c	12 Aug 2004 11:10:49 -0000
@@ -29,8 +29,6 @@
 #include <stdlib.h>
 #include <math.h>

-#define NONAMELESSSTRUCT
-#define NONAMELESSUNION
 #include "wine/test.h"
 #include "windef.h"
 #include "winbase.h"
@@ -40,6 +38,12 @@

 #include "winmm_test.h"

+#ifdef NONAMELESSSTRUCT
+# define S1(x) (x).s1
+#else
+# define S1(x) (x)
+#endif
+
 static const char * line_flags(DWORD fdwLine)
 {
     static char flags[100];
@@ -355,8 +359,8 @@
                                               control_flags(array[nc].fdwControl));
                                         trace("            Items=%ld Min=%ld Max=%ld Step=%ld\n",
                                               array[nc].cMultipleItems,
-                                              array[nc].Bounds.s1.dwMinimum,
-                                              array[nc].Bounds.s1.dwMaximum,
+                                              S1(array[nc].Bounds).dwMinimum,
+                                              S1(array[nc].Bounds).dwMaximum,
                                               array[nc].Metrics.cSteps);
                                     }
                                 }
@@ -578,8 +582,8 @@
                                               control_flags(array[nc].fdwControl));
                                         trace("            Items=%ld Min=%ld Max=%ld Step=%ld\n",
                                               array[nc].cMultipleItems,
-                                              array[nc].Bounds.s1.dwMinimum,
-                                              array[nc].Bounds.s1.dwMaximum,
+                                              S1(array[nc].Bounds).dwMinimum,
+                                              S1(array[nc].Bounds).dwMaximum,
                                               array[nc].Metrics.cSteps);
                                     }
                                 }


-- 
Francois Gouget         fgouget at free.fr        http://fgouget.free.fr/
                          La terre est une b\xEAta...



More information about the wine-patches mailing list