- Minor improvements.
- Added tests for GDI and USER.

diff --git a/tools/winapi/c_type.pm b/tools/winapi/c_type.pm
index ac099e8..31772d8 100644
--- a/tools/winapi/c_type.pm
+++ b/tools/winapi/c_type.pm
@@ -69,6 +69,17 @@
     }
 }
 
+sub pack {
+    my $self = shift;
+    my $pack = \${$self->{PACK}};
+    
+    local $_ = shift;
+
+    if(defined($_)) { $$pack = $_; }
+
+    return $$pack;
+}
+
 sub fields {
     my $self = shift;
 
diff --git a/tools/winapi/tests.dat b/tools/winapi/tests.dat
index 4bf46f7..9db5203 100644
--- a/tools/winapi/tests.dat
+++ b/tools/winapi/tests.dat
@@ -52,3 +52,251 @@
 WIN32_FIND_DATAA
 WIN32_FIND_DATAW
 WIN32_STREAM_ID
+
+%%%dlls/gdi/tests
+
+%%pack
+
+%description
+
+Unit tests for data structure packing
+
+%include
+
+wingdi.h
+
+%struct
+
+ABC                                                    
+ABCFLOAT
+BITMAP
+BITMAPCOREHEADER
+# BITMAPCOREINFO
+BITMAPFILEHEADER
+# BITMAPINFO
+BITMAPINFOHEADER
+# BITMAPV4HEADER
+# BITMAPV5HEADER
+BLENDFUNCTION
+# CHARSETINFO
+CIEXYZ
+# CIEXYZTRIPLE
+# COLORADJUSTMENT
+# DEVMODEA
+# DEVMODEW
+# DIBSECTION
+DISPLAY_DEVICEA
+DISPLAY_DEVICEW
+DOCINFOA
+DOCINFOW
+EMR
+EMRABORTPATH
+EMRANGLEARC
+EMRARC
+EMRBITBLT
+# EMRCREATEBRUSHINDIRECT
+# EMRCREATECOLORSPACE
+# EMRCREATECOLORSPACEW
+EMRCREATEDIBPATTERNBRUSHPT
+EMRCREATEMONOBRUSH
+# EMRCREATEPALETTE
+# EMRCREATEPEN
+EMRDELETECOLORSPACE
+EMRDELETEOBJECT
+EMRELLIPSE
+EMREOF
+EMREXCLUDECLIPRECT
+# EMREXTCREATEFONTINDIRECTW
+# EMREXTCREATEPEN
+EMREXTFLOODFILL
+# EMREXTSELECTCLIPRGN
+# EMREXTTEXTOUTA
+EMRFILLPATH
+# EMRFILLRGN
+EMRFORMAT
+# EMRFRAMERGN
+# EMRGDICOMMENT
+# EMRGLSBOUNDEDRECORD
+# EMRGLSRECORD
+# EMRINVERTRGN
+EMRLINETO
+EMRMASKBLT
+EMRMODIFYWORLDTRANSFORM
+EMROFFSETCLIPRGN
+# EMRPIXELFORMAT
+EMRPLGBLT
+# EMRPOLYDRAW
+EMRPOLYLINE
+EMRPOLYPOLYLINE
+# EMRPOLYTEXTOUTA
+EMRRESIZEPALETTE
+EMRRESTOREDC
+EMRROUNDRECT
+EMRSCALEVIEWPORTEXTEX
+EMRSELECTCLIPPATH
+EMRSELECTPALETTE
+EMRSETARCDIRECTION
+EMRSETBKCOLOR
+EMRSETBRUSHORGEX
+# EMRSETCOLORADJUSTMENT
+EMRSETDIBITSTODEIVCE
+EMRSETMAPPERFLAGS
+EMRSETMITERLIMIT
+EMRSETPALETTEENTRIES
+EMRSETPIXELV
+EMRSETTEXTJUSTIFICATION
+EMRSETVIEWPORTEXTEX
+EMRSETWORLDTRANSFORM
+EMRSTRETCHBLT
+EMRSTRETCHDIBITS
+EMRTEXT
+# ENHMETAHEADER
+ENHMETARECORD
+# ENUMLOGFONTA
+# ENUMLOGFONTEXA
+# ENUMLOGFONTEXW
+# ENUMLOGFONTW
+# EXTLOGFONTA
+# EXTLOGFONTW
+EXTLOGPEN
+# FIXED
+FONTSIGNATURE
+GCP_RESULTSA
+GCP_RESULTSW
+# GLYPHMETRICS
+GRADIENT_RECT
+GRADIENT_TRIANGLE
+HANDLETABLE
+KERNINGPAIR
+LOCALESIGNATURE
+LOGBRUSH
+# LOGCOLORSPACEA
+# LOGCOLORSPACEW
+# LOGFONTA
+# LOGFONTW
+LOGPALETTE
+LOGPEN
+MAT2
+METAFILEPICT
+METAHEADER
+METARECORD
+# NEWTEXTMETRICA
+# NEWTEXTMETRICEXA
+# NEWTEXTMETRICEXW
+# NEWTEXTMETRICW
+# OUTLINETEXTMETRICA
+# OUTLINETEXTMETRICW
+PALETTEENTRY
+# PANOSE
+PELARRAY
+PIXELFORMATDESCRIPTOR
+POINTFX
+# POLYTEXTA
+# POLYTEXTW
+# RASTERIZER_STATUS
+RGBQUAD
+# RGBTRIPLE
+# RGNDATA
+# RGNDATAHEADER
+TEXTMETRICA
+TEXTMETRICW
+# TRIVERTEX
+# TTPOLYCURVE
+# TTPOLYGONHEADER
+XFORM
+
+%%%dlls/user/tests
+
+%%pack
+
+%description
+
+Unit tests for data structure packing
+
+%include
+
+winbase.h
+winuser.h
+
+%struct
+
+# ACCEL                                                   
+ACCESSTIMEOUT
+ANIMATIONINFO
+CBTACTIVATESTRUCT
+CBT_CREATEWNDA
+CBT_CREATEWNDW
+CLIENTCREATESTRUCT
+COMPAREITEMSTRUCT
+COPYDATASTRUCT
+CREATESTRUCTA
+CREATESTRUCTW
+CURSORINFO
+CWPRETSTRUCT
+CWPSTRUCT
+DEBUGHOOKINFO
+DELETEITEMSTRUCT
+DLGITEMTEMPLATE
+DLGTEMPLATE
+DRAWITEMSTRUCT
+DRAWTEXTPARAMS
+EVENTMSG
+FILTERKEYS
+HARDWAREHOOKSTRUCT
+HARDWAREINPUT
+HELPINFO
+HELPWININFOA
+HELPWININFOW
+HIGHCONTRASTA
+HIGHCONTRASTW
+ICONINFO
+# ICONMETRICSA
+# ICONMETRICSW
+# INPUT
+KBDLLHOOKSTRUCT
+KEYBDINPUT
+MDICREATESTRUCTA
+MDICREATESTRUCTW
+MDINEXTMENU
+MEASUREITEMSTRUCT
+MENUINFO
+MENUITEMINFOA
+MENUITEMINFOW
+# MENUITEMTEMPLATE
+MENUITEMTEMPLATEHEADER
+MINIMIZEDMETRICS
+MINMAXINFO
+MONITORINFO
+# MONITORINFOEXA
+# MONITORINFOEXW
+MOUSEHOOKSTRUCT
+MOUSEINPUT
+MOUSEKEYS
+MSG
+MSGBOXPARAMSA
+MSGBOXPARAMSW
+MSLLHOOKSTRUCT
+MULTIKEYHELPA
+MULTIKEYHELPW
+NCCALCSIZE_PARAMS
+NMHDR
+# NONCLIENTMETRICSA
+# NONCLIENTMETRICSW
+PAINTSTRUCT
+SCROLLINFO
+SERIALKEYSA
+SERIALKEYSW
+SOUNDSENTRYA
+SOUNDSENTRYW
+STICKYKEYS
+STYLESTRUCT
+TOGGLEKEYS
+TPMPARAMS
+TRACKMOUSEEVENT
+WINDOWINFO
+WINDOWPLACEMENT
+WINDOWPOS
+WNDCLASSA
+WNDCLASSEXA
+WNDCLASSEXW
+WNDCLASSW
diff --git a/tools/winapi/winapi_test b/tools/winapi/winapi_test
index f014bbc..7fc9cff 100755
--- a/tools/winapi/winapi_test
+++ b/tools/winapi/winapi_test
@@ -91,6 +91,7 @@
 
     my $line;
     my $type;
+    my @packs = (4);
 
     my $update_output = sub {
 	my $progress = "";
@@ -116,9 +117,28 @@
     };
     $parser->set_found_line_callback($found_line);
 
+    my $found_preprocessor = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	my $preprocessor = shift;
+
+	local $_ = $preprocessor;
+	if (/^\#\s*include\s+\"pshpack(\d+)\.h\"$/) {
+	    push @packs, $1;
+	} elsif(/^\#\s*include\s+\"poppack\.h\"$/) {
+	    unshift @packs;
+	}
+
+	return 1;
+    };
+    $parser->set_found_preprocessor_callback($found_preprocessor);
+
     my $found_type = sub {
 	$type = shift;
 
+	my $pack = $packs[$#packs];
+	$type->pack($pack);
+
 	my $name = $type->name;
 	$file2types{$file}{$name} = $type;
 
@@ -139,20 +159,25 @@
     $output->prefix("");
 }
 
+########################################################################
+# output_header
+
 sub output_header {
     local *OUT = shift; 
 
     my $test_dir = shift;
-    my $test = shift;
+    my @tests = @{(shift)};
 
-    print OUT "/* File generated automatically from $wine_dir/tools/winapi/test.dat; do not edit! */\n";
+    print OUT "/* File generated automatically from tools/winapi/test.dat; do not edit! */\n";
     print OUT "/* This file can be copied, modified and distributed without restriction. */\n";
     print OUT "\n";
 
     print OUT "/*\n";
-    my @description = $tests->get_section($test_dir, $test, "description");
-    foreach my $description (@description) {
-	print OUT " * $description\n";
+    foreach my $test (@tests) {
+	my @description = $tests->get_section($test_dir, $test, "description");
+	foreach my $description (@description) {
+	    print OUT " * $description\n";
+	}
     }
     print OUT " */\n";
 
@@ -160,25 +185,37 @@
     print OUT "#include <stdio.h>\n";
     print OUT "\n";
     print OUT "#include \"wine/test.h\"\n";
-    my @includes = $tests->get_section($test_dir, $test, "include");
-    foreach my $include (@includes) {
-	print OUT "#include \"$include\"\n";
+    foreach my $test (@tests) {
+	my @includes = $tests->get_section($test_dir, $test, "include");
+	foreach my $include (@includes) {
+	    print OUT "#include \"$include\"\n";
+	}
     }
     print OUT "\n";
-
-    print OUT "START_TEST(generated_$test)\n";
-    print OUT "{\n";
 }
 
+########################################################################
+# output_footer
+
 sub output_footer {
     local *OUT = shift; 
 
     my $test_dir = shift;
-    my $test = shift;
+    my @tests = @{(shift)};
 
+    print OUT "START_TEST(generated)\n";
+    print OUT "{\n";
+    foreach my $test (@tests) {
+	print OUT "    test_$test();\n";
+    }
     print OUT "}\n";
 }
 
+########################################################################
+# output_field_size
+
+my %type_name2size;
+
 sub field_size {
     my $name = shift;
     my $field_type = shift;
@@ -194,15 +231,19 @@
     }
 
     my $size;
-    if(/^(?:(?:signed\s+|unsigned\s+)?char|CHAR|BYTE|UCHAR)$/) {
+    if (defined($size = $type_name2size{$field_type})) {
+	# Nothing
+    } elsif(/^(?:(?:signed\s+|unsigned\s+)?char|CHAR|BYTE|UCHAR)$/) {
 	$size = 1;
-    } elsif (/^(?:(?:signed\s+|unsigned\s+)?short|UWORD|WCHAR|WORD)$/) {
+    } elsif (/^(?:(?:signed\s+|unsigned\s+)?short|ATOM|UWORD|WCHAR|WORD)$/) {
 	$size = 2;
     } elsif (/^(?:FILETIME|LARGE_INTEGER|LONGLONG|ULONGLONG)$/) {
 	$size = 8;
-    } elsif (/^(?:SYSTEMTIME)$/) {
+    } elsif (/^(?:EMR|POINTL?|SIZEL)$/) {
+	$size = 8;
+    } elsif (/^(?:RECTL?|SYSTEMTIME)$/) {
 	$size = 16;
-    } elsif (/^(?:CRITICAL_SECTION)$/) {
+    } elsif (/^(?:CRITICAL_SECTION|XFORM)$/) {
 	$size = 24;
     } elsif (/^(?:DCB)$/) {
 	$size = 28;
@@ -232,27 +273,37 @@
 }
 
 ########################################################################
-# output_file
+# output_test_pack
 
-sub output_file {
+sub output_test_pack {
     local *OUT = shift;
 
     my $test_dir = shift;
     my $test = shift;
 
-    output_header(\*OUT, $test_dir, $test);
-    
     my @includes = $tests->get_section($test_dir, $test, "include");
     my @type_names = $tests->get_section($test_dir, $test, "struct");
-    
+
+    my %type_name_not_used;
+
+    foreach my $type_name (@type_names) {
+	$type_name_not_used{$type_name} = 1;
+    }
+
+    # FIXME: Topological sort of @type_names
+
     foreach my $include (@includes) {
 	my $types = $file2types{"include/$include"};
 	
-	foreach my $type_name (@type_names) {
-	    my $pack = 4; # FIXME: Not always correct
-	    
+	foreach my $type_name (@type_names) {	    
 	    my $type = $$types{$type_name};
-	    
+	    if (!defined($type)) {
+		next;
+	    }
+	    $type_name_not_used{$type_name} = 0;
+
+	    my $pack = $type->pack;
+
 	    my $offset = 0;
 	    my $offset_bits = 0;
 	    
@@ -284,7 +335,8 @@
 	    if ($type_size % $pack != 0) {
 		$type_size = (int($type_size / $pack) + 1) * $pack;
 	    }
-	    
+	    $type_name2size{$type_name} = $type_size;
+
 	    print OUT "    ok(sizeof($type_name) == $type_size, ";
 	    print OUT "\"sizeof($type_name) == %d (expected $type_size)\", ";
 	    print OUT "sizeof($type_name));\n";
@@ -292,13 +344,47 @@
 	}
     }
 
-    output_footer(\*OUT, $test_dir, $test);
+    foreach my $type_name (@type_names) {
+	if ($type_name_not_used{$type_name}) {
+	    $output->write("$test_dir: $test: $type_name: type not found (ignored)\n");
+	}
+    }
 }
 
-foreach my $test (@tests) {
-    my @test_dirs = $tests->get_test_dirs($test);
-    foreach my $test_dir (@test_dirs) {
-	my $file = "$wine_dir/$test_dir/generated_$test.c";
-	replace_file($file, \&output_file, $test_dir, $test);
+
+########################################################################
+# output_file
+
+sub output_file {
+    local *OUT = shift;
+
+    my $test_dir = shift;
+    my @tests = @{(shift)};
+
+    output_header(\*OUT, $test_dir, \@tests);
+
+    foreach my $test (@tests) {
+	print OUT "void test_$test(void)\n";
+	print OUT "{\n";
+	
+	if ($test eq "pack") {
+	    output_test_pack(\*OUT, $test_dir, $test);
+	} else {
+	    die "no such test ($test)\n";
+	}
+
+	print OUT "}\n";
+	print OUT "\n";
     }
+
+    output_footer(\*OUT, $test_dir, \@tests);
+}
+
+########################################################################
+# main
+
+my @test_dirs = $tests->get_test_dirs();
+foreach my $test_dir (@test_dirs) {
+    my $file = "$wine_dir/$test_dir/generated.c";
+    replace_file($file, \&output_file, $test_dir, \@tests);
 }