- Continued on the new C parser.
- More reorganizations and fixes.
- API files update.

diff --git a/tools/winapi/c_function.pm b/tools/winapi/c_function.pm
new file mode 100644
index 0000000..ee96a91
--- /dev/null
+++ b/tools/winapi/c_function.pm
@@ -0,0 +1,168 @@
+package c_function;
+
+use strict;
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $self  = {};
+    bless ($self, $class);
+
+    return $self;
+}
+
+sub file {
+    my $self = shift;
+    my $file = \${$self->{FILE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$file = $_; }
+    
+    return $$file;
+}
+
+sub begin_line {
+    my $self = shift;
+    my $begin_line = \${$self->{BEGIN_LINE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$begin_line = $_; }
+    
+    return $$begin_line;
+}
+
+sub begin_column {
+    my $self = shift;
+    my $begin_column = \${$self->{BEGIN_COLUMN}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$begin_column = $_; }
+    
+    return $$begin_column;
+}
+
+sub end_line {
+    my $self = shift;
+    my $end_line = \${$self->{END_LINE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$end_line = $_; }
+    
+    return $$end_line;
+}
+
+sub end_column {
+    my $self = shift;
+    my $end_column = \${$self->{END_COLUMN}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$end_column = $_; }
+    
+    return $$end_column;
+}
+
+sub linkage {
+    my $self = shift;
+    my $linkage = \${$self->{LINKAGE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$linkage = $_; }
+    
+    return $$linkage;
+}
+
+sub return_type {
+    my $self = shift;
+    my $return_type = \${$self->{RETURN_TYPE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$return_type = $_; }
+    
+    return $$return_type;
+}
+
+sub calling_convention {
+    my $self = shift;
+    my $calling_convention = \${$self->{CALLING_CONVENTION}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$calling_convention = $_; }
+    
+    return $$calling_convention;
+}
+
+sub name {
+    my $self = shift;
+    my $name = \${$self->{NAME}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$name = $_; }
+    
+    return $$name;
+}
+
+sub argument_types {
+    my $self = shift;
+    my $argument_types = \${$self->{ARGUMENT_TYPES}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$argument_types = $_; }
+    
+    return $$argument_types;
+}
+
+sub argument_names {
+    my $self = shift;
+    my $argument_names = \${$self->{ARGUMENT_NAMES}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$argument_names = $_; }
+    
+    return $$argument_names;
+}
+
+sub statements_line {
+    my $self = shift;
+    my $statements_line = \${$self->{STATEMENTS_LINE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$statements_line = $_; }
+    
+    return $$statements_line;
+}
+
+sub statements_column {
+    my $self = shift;
+    my $statements_column = \${$self->{STATEMENTS_COLUMN}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$statements_column = $_; }
+    
+    return $$statements_column;
+}
+
+sub statements {
+    my $self = shift;
+    my $statements = \${$self->{STATEMENTS}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$statements = $_; }
+    
+    return $$statements;
+}
+
+1;
diff --git a/tools/winapi/c_parser.pm b/tools/winapi/c_parser.pm
index 957723a..87c880c 100644
--- a/tools/winapi/c_parser.pm
+++ b/tools/winapi/c_parser.pm
@@ -2,92 +2,218 @@
 
 use strict;
 
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+
 use options qw($options);
 use output qw($output);
 
-sub _update_c_position {
-    local $_ = shift;
-    my $refline = shift;
-    my $refcolumn = shift;
+use c_function;
 
-    my $line = $$refline;
-    my $column = $$refcolumn;
+########################################################################
+# new
+#
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $self  = {};
+    bless ($self, $class);
 
-    while($_) {
-	if(s/^[^\n\t\'\"]*//s) {
-	    $column += length($&);
-	}
+    my $file = \${$self->{FILE}};
+    my $found_comment = \${$self->{FOUND_COMMENT}};
+    my $found_declaration = \${$self->{FOUND_DECLARATION}};
+    my $create_function = \${$self->{CREATE_FUNCTION}};
+    my $found_function = \${$self->{FOUND_FUNCTION}};
+    my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
+    my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
+    my $found_statement = \${$self->{FOUND_STATEMENT}};
+    my $found_variable = \${$self->{FOUND_VARIABLE}};
 
-	if(s/^\'//) {
-	    $column++;
-	    while(/^./ && !s/^\'//) {
-		s/^([^\'\\]*)//s;
-		$column += length($1);
-		if(s/^\\//) {
-		    $column++;
-		    if(s/^(.)//s) {
-			$column += length($1);
-			if($1 eq "0") {
-			    s/^(\d{0,3})//s;
-			    $column += length($1);
-			}
-		    }
-		}
-	    }
-	    $column++;
-	} elsif(s/^\"//) {
-	    $column++;
-	    while(/^./ && !s/^\"//) {
-		s/^([^\"\\]*)//s;
-		$column += length($1);
-		if(s/^\\//) {
-		    $column++;
-		    if(s/^(.)//s) {
-			$column += length($1);
-			if($1 eq "0") {
-			    s/^(\d{0,3})//s;
-			    $column += length($1);
-			}
-		    }
-		}
-	    }
-	    $column++;
-	} elsif(s/^\n//) {
-	    $line++;
-	    $column = 0;
-	} elsif(s/^\t//) {
-	    $column = $column + 8 - $column % 8;
-	}
-    }
+    $$file = shift;
 
-    $$refline = $line;
-    $$refcolumn = $column;
+    $$found_comment = sub { return 1; };
+    $$found_declaration = sub { return 1; };
+    $$create_function = sub { return new c_function; };
+    $$found_function = sub { return 1; };
+    $$found_function_call = sub { return 1; };
+    $$found_preprocessor = sub { return 1; };
+    $$found_statement = sub { return 1; };
+    $$found_variable = sub { return 1; };
+
+    return $self;
 }
 
-sub parse_c {
+########################################################################
+# set_found_comment_callback
+#
+sub set_found_comment_callback {
+    my $self = shift;
+
+    my $found_comment = \${$self->{FOUND_COMMENT}};
+
+    $$found_comment = shift;
+}
+
+########################################################################
+# set_found_declaration_callback
+#
+sub set_found_declaration_callback {
+    my $self = shift;
+
+    my $found_declaration = \${$self->{FOUND_DECLARATION}};
+
+    $$found_declaration = shift;
+}
+
+########################################################################
+# set_found_function_callback
+#
+sub set_found_function_callback {
+    my $self = shift;
+
+    my $found_function = \${$self->{FOUND_FUNCTION}};
+
+    $$found_function = shift;
+}
+
+########################################################################
+# set_found_function_call_callback
+#
+sub set_found_function_call_callback {
+    my $self = shift;
+
+    my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
+
+    $$found_function_call = shift;
+}
+
+########################################################################
+# set_found_preprocessor_callback
+#
+sub set_found_preprocessor_callback {
+    my $self = shift;
+
+    my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
+
+    $$found_preprocessor = shift;
+}
+
+########################################################################
+# set_found_statement_callback
+#
+sub set_found_statement_callback {
+    my $self = shift;
+
+    my $found_statement = \${$self->{FOUND_STATEMENT}};
+
+    $$found_statement = shift;
+}
+
+########################################################################
+# set_found_variable_callback
+#
+sub set_found_variable_callback {
+    my $self = shift;
+
+    my $found_variable = \${$self->{FOUND_VARIABLE}};
+
+    $$found_variable = shift;
+}
+
+########################################################################
+# _parse_c
+
+sub _parse_c {
+    my $self = shift;
+
     my $pattern = shift;
     my $refcurrent = shift;
     my $refline = shift;
     my $refcolumn = shift;
 
+    my $refmatch = shift;
+
     local $_ = $$refcurrent;
     my $line = $$refline;
     my $column = $$refcolumn;
 
-    if(s/$pattern//) {
-	_update_c_position($&, \$line, \$column);
+    my $match;
+    if(s/^(?:$pattern)//s) {
+	$self->_update_c_position($&, \$line, \$column);
+	$match = $&;
     } else {
 	return 0;
     }
 
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
     $$refcurrent = $_;
     $$refline = $line;
     $$refcolumn = $column;
 
+    $$refmatch = $match;
+
     return 1;
 }
 
-sub parse_c_until_one_of {
+########################################################################
+# _parse_c_error
+
+sub _parse_c_error {
+    my $self = shift;
+
+    my $file = \${$self->{FILE}};
+
+    local $_ = shift;
+    my $line = shift;
+    my $column = shift;
+    my $context = shift;
+
+    my @lines = split(/\n/, $_);
+
+    my $current = "\n";
+    $current .= $lines[0] . "\n" || "";
+    $current .= $lines[1] . "\n" || "";
+
+    if($output->prefix) {
+	$output->write("\n");
+	$output->prefix("");
+    }
+    $output->write("$$file:$line." . ($column + 1) . ": $context: parse error: \\$current");
+
+    exit 1;
+}
+
+########################################################################
+# _parse_c_output
+
+sub _parse_c_output {
+    my $self = shift;
+
+    local $_ = shift;
+    my $line = shift;
+    my $column = shift;
+    my $message = shift;
+
+    my @lines = split(/\n/, $_);
+
+    my $current = "\n";
+    $current .= $lines[0] . "\n" || "";
+    $current .= $lines[1] . "\n" || "";
+
+    $output->write("$line." . ($column + 1) . ": $message: \\$current");
+}
+
+########################################################################
+# _parse_c_until_one_of
+
+sub _parse_c_until_one_of {
+    my $self = shift;
+
     my $characters = shift;
     my $refcurrent = shift;
     my $refline = shift;
@@ -98,11 +224,6 @@
     my $line = $$refline;
     my $column = $$refcolumn;
 
-    if(!defined($line) || !defined($column)) {
-	$output->write("error: \$characters = '$characters' \$_ = '$_'\n");
-	exit 1;
-    }
-
     if(!defined($match)) {
 	my $blackhole;
 	$match = \$blackhole;
@@ -179,10 +300,80 @@
     return 1;
 }
 
+########################################################################
+# _update_c_position
+
+sub _update_c_position {
+    my $self = shift;
+
+    local $_ = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    while($_) {
+	if(s/^[^\n\t\'\"]*//s) {
+	    $column += length($&);
+	}
+
+	if(s/^\'//) {
+	    $column++;
+	    while(/^./ && !s/^\'//) {
+		s/^([^\'\\]*)//s;
+		$column += length($1);
+		if(s/^\\//) {
+		    $column++;
+		    if(s/^(.)//s) {
+			$column += length($1);
+			if($1 eq "0") {
+			    s/^(\d{0,3})//s;
+			    $column += length($1);
+			}
+		    }
+		}
+	    }
+	    $column++;
+	} elsif(s/^\"//) {
+	    $column++;
+	    while(/^./ && !s/^\"//) {
+		s/^([^\"\\]*)//s;
+		$column += length($1);
+		if(s/^\\//) {
+		    $column++;
+		    if(s/^(.)//s) {
+			$column += length($1);
+			if($1 eq "0") {
+			    s/^(\d{0,3})//s;
+			    $column += length($1);
+			}
+		    }
+		}
+	    }
+	    $column++;
+	} elsif(s/^\n//) {
+	    $line++;
+	    $column = 0;
+	} elsif(s/^\t//) {
+	    $column = $column + 8 - $column % 8;
+	}
+    }
+
+    $$refline = $line;
+    $$refcolumn = $column;
+}
+
+########################################################################
+# parse_c_block
+
 sub parse_c_block {
+    my $self = shift;
+
     my $refcurrent = shift;
     my $refline = shift;
     my $refcolumn = shift;
+
     my $refstatements = shift;
     my $refstatements_line = shift;
     my $refstatements_column = shift;
@@ -191,6 +382,8 @@
     my $line = $$refline;
     my $column = $$refcolumn;
 
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
     my $statements;
     if(s/^\{//) {
 	$column++;
@@ -199,7 +392,7 @@
 	return 0;
     }
 
-    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 
     my $statements_line = $line;
     my $statements_column = $column;
@@ -207,7 +400,7 @@
     my $plevel = 1;
     while($plevel > 0) {
 	my $match;
-	parse_c_until_one_of("\\{\\}", \$_, \$line, \$column, \$match);
+	$self->_parse_c_until_one_of("\\{\\}", \$_, \$line, \$column, \$match);
 
 	$column++;
 
@@ -235,63 +428,161 @@
     return 1;
 }
 
-sub parse_c_expression {
+########################################################################
+# parse_c_declaration
+
+sub parse_c_declaration {
+    my $self = shift;
+
+    my $found_declaration = \${$self->{FOUND_DECLARATION}};
+    my $found_function = \${$self->{FOUND_FUNCTION}};
+
     my $refcurrent = shift;
     my $refline = shift;
     my $refcolumn = shift;
-    my $found_function_call_callback = shift;
 
+    local $_ = $$refcurrent;
     my $line = $$refline;
     my $column = $$refcolumn;
 
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    my $begin_line = $line;
+    my $begin_column = $column + 1;
+
+    my $end_line = $begin_line;
+    my $end_column = $begin_column;
+    $self->_update_c_position($_, \$end_line, \$end_column);
+
+    if(!&$$found_declaration($begin_line, $begin_column, $end_line, $end_column, $_)) {
+	return 1;
+    }
+    
+    # Function
+    my $function = shift;
+
+    my $linkage = shift;
+    my $calling_convention = shift;
+    my $return_type = shift;
+    my $name = shift;
+    my @arguments = shift;
+    my @argument_lines = shift;
+    my @argument_columns = shift;
+
+    # Variable
+    my $type;
+
+    # $self->_parse_c_output($_, $line, $column, "declaration");
+
+    if(0) {
+	# Nothing
+    } elsif(s/^(?:DEFAULT|DECLARE)_DEBUG_CHANNEL\s*\(\s*(\w+)\s*\)\s*//s) { # FIXME: Wine specific kludge
+	$self->_update_c_position($&, \$line, \$column);
+    } elsif(s/^extern\s*\"(.*?)\"\s*//s) {
+	$self->_update_c_position($&, \$line, \$column);
+	my $declarations;
+	my $declarations_line;
+	my $declarations_column;
+	if(!$self->parse_c_block(\$_, \$line, \$column, \$declarations, \$declarations_line, \$declarations_column)) {
+	    return 0;
+	}
+	if(!$self->parse_c_declarations(\$declarations, \$declarations_line, \$declarations_column)) {
+	    return 0;
+	}
+    } elsif($self->parse_c_function(\$_, \$line, \$column, \$function)) {
+	if(&$$found_function($function))
+	{
+	    my $statements = $function->statements;
+	    my $statements_line = $function->statements_line;
+	    my $statements_column = $function->statements_column;
+
+	    if(defined($statements)) {
+		if(!$self->parse_c_statements(\$statements, \$statements_line, \$statements_column)) {
+		    return 0;
+		}
+	    }
+	}
+    } elsif($self->parse_c_typedef(\$_, \$line, \$column)) {
+	# Nothing
+    } elsif($self->parse_c_variable(\$_, \$line, \$column, \$linkage, \$type, \$name)) {
+	# Nothing
+    } else {
+	$self->_parse_c_error($_, $line, $column, "declaration");
+    }
+    
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_declarations
+
+sub parse_c_declarations {
+    my $self = shift;
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_expression
+
+sub parse_c_expression {
+    my $self = shift;
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
+
     local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
 
-    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 
-    if(s/^(.*?)(\w+)(\s*)\(//s) {
+    if(s/^(.*?)(\w+\s*\()/$2/s) {
+	$column += length($1);
+
 	my $begin_line = $line;
-	my $begin_column = $column + length($1) + 1;
+	my $begin_column = $column + 1;
 
-	$line = $begin_line;
-	$column = $begin_column + length("$2$3") - 1;
-
-	my $name = $2;
-
-	$_ = "($'";
-
-	# $output->write("$name: $line.$column: '$_'\n");
-
+	my $name;
 	my @arguments;
 	my @argument_lines;
 	my @argument_columns;
-	if(!parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
+	if(!$self->parse_c_function_call(\$_, \$line, \$column, \$name, \@arguments, \@argument_lines, \@argument_columns)) {
 	    return 0;
 	}
 
-	if($name =~ /^sizeof$/) {
-	    # Nothing
-	} else {
-	    &$found_function_call_callback($begin_line, $begin_column, $line, $column, 
-					   $name, \@arguments);
-	}
-
-	while(defined(my $argument = shift @arguments) &&
-	      defined(my $argument_line = shift @argument_lines) &&
-	      defined(my $argument_column = shift @argument_columns))
+	if($name =~ /^sizeof$/ || 
+	   &$$found_function_call($begin_line, $begin_column, $line, $column, $name, \@arguments))
 	{
-	    parse_c_expression(\$argument, \$argument_line, \$argument_column, $found_function_call_callback);
+	    while(defined(my $argument = shift @arguments) &&
+		  defined(my $argument_line = shift @argument_lines) &&
+		  defined(my $argument_column = shift @argument_columns))
+	    {
+		$self->parse_c_expression(\$argument, \$argument_line, \$argument_column);
+	    }
 	}
     } elsif(s/^return//) {
 	$column += length($&);
-	parse_c_until_one_of("\\S", \$_, \$line, \$column);
-	if(!parse_c_expression(\$_, \$line, \$column, $found_function_call_callback)) {
+	$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+	if(!$self->parse_c_expression(\$_, \$line, \$column)) {
 	    return 0;
 	}
     } else {
 	return 0;
     }
 
-    _update_c_position($_, \$line, \$column);
+    $self->_update_c_position($_, \$line, \$column);
 
     $$refcurrent = $_;
     $$refline = $line;
@@ -300,22 +591,358 @@
     return 1;
 }
 
-sub parse_c_statement {
+########################################################################
+# parse_c_file
+
+sub parse_c_file {
+    my $self = shift;
+
+    my $found_comment = \${$self->{FOUND_COMMENT}};
+
     my $refcurrent = shift;
     my $refline = shift;
     my $refcolumn = shift;
-    my $found_function_call_callback = shift;
-
+    
+    local $_ = $$refcurrent;
     my $line = $$refline;
     my $column = $$refcolumn;
 
-    local $_ = $$refcurrent;
+    my $declaration = "";
+    my $declaration_line = $line;
+    my $declaration_column = $column;
 
-    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+    my $previous_line = 0;
+    my $previous_column = -1;
+
+    my $blevel = 1;
+    my $plevel = 1;
+    while($plevel > 0 || $blevel > 0) {
+	my $match;
+	$self->_parse_c_until_one_of("#/\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
+
+	if($line == $previous_line && $column == $previous_column) {
+	    # $self->_parse_c_error($_, $line, $column, "file: no progress");
+	}
+	$previous_line = $line;
+	$previous_column = $column;
+
+	# $self->_parse_c_output($_, $line, $column, "'$match'");
+
+	if(!$declaration && $match =~ s/^\s+//s) {
+	    $self->_update_c_position($&, \$declaration_line, \$declaration_column);
+	}
+	$declaration .= $match;
+
+	if(/^[\#\/]/) {
+	    my $blank_lines = 0;
+	    if(s/^\#\s*//) {
+		my $preprocessor_line = $line;
+		my $preprocessor_column = $column;
+
+		my $preprocessor = $&;
+		while(s/^(.*?)\\\s*\n//) {
+		    $blank_lines++;
+		    $preprocessor .= "$1\n";
+		}
+		if(s/^(.*?)(\/[\*\/].*)?\n//) {
+		    if(defined($2)) {
+			$_ = "$2\n$_";
+		    } else {
+			$blank_lines++;
+		    }
+		    $preprocessor .= $1;
+		}
+
+		if(!$self->parse_c_preprocessor(\$preprocessor, \$preprocessor_line, \$preprocessor_column)) {
+		    return 0;
+		}
+	    } 
+
+	    if(s/^\/\*(.*?)\*\///s) {
+		&$$found_comment($line, $column + 1, "/*$1*/");
+		my @lines = split(/\n/, $1);
+		if($#lines > 0) {
+		    $blank_lines += $#lines;
+		} else {
+		    $column += length($1);
+		}
+	    } elsif(s/^\/\/(.*?)\n//) {
+		&$$found_comment($line, $column + 1, "//$1");
+		$blank_lines++;
+	    } elsif(s/^\///) {
+		$declaration .= $&;
+	    }
+
+	    $line += $blank_lines;
+	    if($blank_lines > 0) {
+		$column = 0;
+	    }
+
+	    if(!$declaration) {
+		$declaration_line = $line;
+		$declaration_column = $column;
+	    } else {
+		$declaration .= "\n" x $blank_lines;
+	    }
+
+	    next;
+	} 
+
+	$column++;
+	if(s/^[\(\[]//) {
+	    $plevel++;
+	    $declaration .= $&;
+	} elsif(s/^[\)\]]//) {
+	    $plevel--;
+	    $declaration .= $&;
+	} elsif(s/^\{//) {
+	    $blevel++;
+	    $declaration .= $&;
+	} elsif(s/^\}//) {
+	    $blevel--;
+	    $declaration .= $&;
+	    if($plevel == 1 && $blevel == 1 && $declaration !~ /^typedef/) {
+		if(!$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
+		    return 0;
+		}
+		$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$declaration = "";
+		$declaration_line = $line;
+		$declaration_column = $column;
+	    }
+	} elsif(s/^;//) {
+	    if($plevel == 1 && $blevel == 1) {
+		if($declaration && !$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
+		    return 0;
+		}
+		$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$declaration = "";
+		$declaration_line = $line;
+		$declaration_column = $column;
+	    } else {
+		$declaration .= $&;
+	    }
+	} elsif(/^\s*$/ && $declaration =~ /^\s*$/ && $match =~ /^\s*$/) {
+	    $plevel = 0;
+	    $blevel = 0;
+	} else {
+	    $self->_parse_c_error($_, $line, $column, "file");
+	}
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_function
+
+sub parse_c_function {
+    my $self = shift;
+
+    my $file = \${$self->{FILE}};
+    my $create_function = \${$self->{CREATE_FUNCTION}};
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $reffunction = shift;
+    
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    my $linkage = "";
+    my $calling_convention = "";
+    my $return_type;
+    my $name;
+    my @arguments;
+    my @argument_lines;
+    my @argument_columns;
+    my $statements;
+    my $statements_line;
+    my $statements_column;
+
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    my $begin_line = $line;
+    my $begin_column = $column + 1;
+
+    $self->_parse_c("inline", \$_, \$line, \$column);
+    $self->_parse_c("extern|static", \$_, \$line, \$column, \$linkage);
+    $self->_parse_c("inline", \$_, \$line, \$column);
+    if(!$self->parse_c_type(\$_, \$line, \$column, \$return_type)) {
+	return 0;
+    }
+
+    $self->_parse_c("__cdecl|__stdcall|CDECL|VFWAPIV|VFWAPI|WINAPIV|WINAPI|CALLBACK", 
+	     \$_, \$line, \$column, \$calling_convention);
+    if(!$self->_parse_c("\\w+", \$_, \$line, \$column, \$name)) { 
+	return 0; 
+    }
+    if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
+	return 0; 
+    }
+    if($_ && !$self->parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
+	return 0;
+    }
+
+    my $end_line = $line;
+    my $end_column = $column;
+    
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    my $function = &$$create_function;
+
+    $function->file($$file);
+    $function->begin_line($begin_line);
+    $function->begin_column($begin_column);
+    $function->end_line($end_line);
+    $function->end_column($end_column);
+    $function->linkage($linkage);
+    $function->return_type($return_type); 
+    $function->calling_convention($calling_convention);
+    $function->name($name);
+    # if(defined($argument_types)) {
+    #     $function->argument_types([@$argument_types]);
+    # }
+    # if(defined($argument_names)) {
+    #     $function->argument_names([@$argument_names]);
+    # }
+    $function->statements_line($statements_line);
+    $function->statements_column($statements_column);
+    $function->statements($statements);
+
+    $$reffunction = $function;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_function_call
+
+sub parse_c_function_call {
+    my $self = shift;
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $refname = shift;
+    my $refarguments = shift;
+    my $refargument_lines = shift;
+    my $refargument_columns = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    my $name;
+    my @arguments;
+    my @argument_lines;
+    my @argument_columns;
+
+    if(s/^(\w+)(\s*)\(/\(/s) {
+	$column += length("$1$2");
+
+	$name = $1;
+
+	if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
+	    return 0;
+	}
+    } else {
+	return 0;
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    $$refname = $name;
+    @$refarguments = @arguments;
+    @$refargument_lines = @argument_lines;
+    @$refargument_columns = @argument_columns;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_preprocessor
+
+sub parse_c_preprocessor {
+    my $self = shift;
+
+    my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    my $begin_line = $line;
+    my $begin_column = $column + 1;
+
+    if(!&$$found_preprocessor($begin_line, $begin_column, "$_")) {
+	return 1;
+    }
+    
+    if(0) {
+	# Nothing
+    } elsif(/^\#\s*define\s+(.*?)$/s) {
+	$self->_update_c_position($_, \$line, \$column);
+    } elsif(/^\#\s*else/s) {
+	$self->_update_c_position($_, \$line, \$column);
+    } elsif(/^\#\s*endif/s) {
+	$self->_update_c_position($_, \$line, \$column);
+    } elsif(/^\#\s*(?:if|ifdef|ifndef)?\s+(.*?)$/s) {
+	$self->_update_c_position($_, \$line, \$column);
+    } elsif(/^\#\s*include\s+(.*?)$/s) {
+	$self->_update_c_position($_, \$line, \$column);
+    } elsif(/^\#\s*undef\s+(.*?)$/s) {
+	$self->_update_c_position($_, \$line, \$column);
+    } else {
+	$self->_parse_c_error($_, $line, $column, "preprocessor");
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_statement
+
+sub parse_c_statement {
+    my $self = shift;
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 
     if(s/^(?:case\s+)?(\w+)\s*://) {
 	$column += length($&);
-	parse_c_until_one_of("\\S", \$_, \$line, \$column);
+	$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
     }
 
     # $output->write("$line.$column: '$_'\n");
@@ -326,10 +953,10 @@
 	my $statements;
 	my $statements_line;
 	my $statements_column;
-	if(!parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
+	if(!$self->parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
 	    return 0;
 	}
-	if(!parse_c_statements(\$statements, \$statements_line, \$statements_column, $found_function_call_callback)) {
+	if(!$self->parse_c_statements(\$statements, \$statements_line, \$statements_column)) {
 	    return 0;
 	}
     } elsif(/^(for|if|switch|while)(\s*)\(/) {
@@ -341,35 +968,34 @@
 	my @arguments;
 	my @argument_lines;
 	my @argument_columns;
-	if(!parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
+	if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
 	    return 0;
 	}
 
-	parse_c_until_one_of("\\S", \$_, \$line, \$column);
-	if(!parse_c_statement(\$_, \$line, \$column, $found_function_call_callback)) {
+	$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+	if(!$self->parse_c_statement(\$_, \$line, \$column)) {
 	    return 0;
 	}
-	parse_c_until_one_of("\\S", \$_, \$line, \$column);
+	$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 
 	while(defined(my $argument = shift @arguments) &&
 	      defined(my $argument_line = shift @argument_lines) &&
 	      defined(my $argument_column = shift @argument_columns))
 	{
-	    parse_c_expression(\$argument, \$argument_line, \$argument_column, $found_function_call_callback);
+	    $self->parse_c_expression(\$argument, \$argument_line, \$argument_column);
 	}
     } elsif(s/^else//) {
 	$column += length($&);
-	if(!parse_c_statement(\$_, \$line, \$column, $found_function_call_callback)) {
+	if(!$self->parse_c_statement(\$_, \$line, \$column)) {
 	    return 0;
 	}
-    } elsif(parse_c_expression(\$_, \$line, \$column, $found_function_call_callback)) {
+    } elsif($self->parse_c_expression(\$_, \$line, \$column)) {
 	# Nothing
     } else {
-	# $output->write("error '$_'\n");
-	# exit 1;
+	# $self->_parse_c_error($_, $line, $column, "statement");
     }
 
-    _update_c_position($_, \$line, \$column);
+    $self->_update_c_position($_, \$line, \$column);
 
     $$refcurrent = $_;
     $$refline = $line;
@@ -378,18 +1004,24 @@
     return 1;
 }
 
+########################################################################
+# parse_c_statements
+
 sub parse_c_statements {
+    my $self = shift;
+
     my $refcurrent = shift;
     my $refline = shift;
     my $refcolumn = shift;
-    my $found_function_call_callback = shift;
 
+    my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
+
+    local $_ = $$refcurrent;
     my $line = $$refline;
     my $column = $$refcolumn;
 
-    local $_ = $$refcurrent;
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 
-    parse_c_until_one_of("\\S", \$_, \$line, \$column);
     my $statement = "";
     my $statement_line = $line;
     my $statement_column = $column;
@@ -398,7 +1030,7 @@
     my $plevel = 1;
     while($plevel > 0 || $blevel > 0) {
 	my $match;
-	parse_c_until_one_of("\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
+	$self->_parse_c_until_one_of("\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
 
 	# $output->write("'$match' '$_'\n");
 
@@ -410,8 +1042,7 @@
 	} elsif(s/^[\)\]]//) {
 	    $plevel--;
 	    if($plevel <= 0) {
-		$output->write("error $plevel: '$statement' '$match' '$_'\n");
-		exit 1;
+		$self->_parse_c_error($_, $line, $column, "statements");
 	    }
 	    $statement .= $&;
 	} elsif(s/^\{//) {
@@ -421,21 +1052,21 @@
 	    $blevel--;
 	    $statement .= $&;
 	    if($blevel == 1) {
-		if(!parse_c_statement(\$statement, \$statement_line, \$statement_column, $found_function_call_callback)) {
+		if(!$self->parse_c_statement(\$statement, \$statement_line, \$statement_column)) {
 		    return 0;
 		}
-		parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 		$statement = "";
 		$statement_line = $line;
 		$statement_column = $column;
 	    }
 	} elsif(s/^;//) {
 	    if($plevel == 1 && $blevel == 1) {
-		if(!parse_c_statement(\$statement, \$statement_line, \$statement_column, $found_function_call_callback)) {
+		if(!$self->parse_c_statement(\$statement, \$statement_line, \$statement_column)) {
 		    return 0;
 		}
 
-		parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 		$statement = "";
 		$statement_line = $line;
 		$statement_column = $column;
@@ -446,12 +1077,11 @@
 	    $plevel = 0;
 	    $blevel = 0;
 	} else {
-	    $output->write("error $plevel: '$statement' '$match' '$_'\n");
-	    exit 1;
+	    $self->_parse_c_error($_, $line, $column, "statements");
 	}
     }
 
-    _update_c_position($_, \$line, \$column);
+    $self->_update_c_position($_, \$line, \$column);
 
     $$refcurrent = $_;
     $$refline = $line;
@@ -460,7 +1090,12 @@
     return 1;
 }
 
+########################################################################
+# parse_c_tuple
+
 sub parse_c_tuple {
+    my $self = shift;
+
     my $refcurrent = shift;
     my $refline = shift;
     my $refcolumn = shift;
@@ -489,7 +1124,7 @@
     my $plevel = 1;
     while($plevel > 0) {
 	my $match;
-	parse_c_until_one_of("\\(,\\)", \$_, \$line, \$column, \$match);
+	$self->_parse_c_until_one_of("\\(,\\)", \$_, \$line, \$column, \$match);
 
 	$column++;
 
@@ -512,7 +1147,7 @@
 		push @$item_lines, $item_line;
 		push @$item_columns, $item_column;
 		push @$items, $item;
-		parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
 		$item_line = $line;
 		$item_column = $column + 1;
 		$item = "";
@@ -531,4 +1166,125 @@
     return 1;
 }
 
+########################################################################
+# parse_c_type
+
+sub parse_c_type {
+    my $self = shift;
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $reftype = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    my $type;
+
+    $self->_parse_c("const", \$_, \$line, \$column);
+
+
+    if(0) {
+	# Nothing
+    } elsif($self->_parse_c('ICOM_VTABLE\(.*?\)', \$_, \$line, \$column, \$type)) {
+		# Nothing
+    } elsif($self->_parse_c('\w+\s*(\*\s*)*', \$_, \$line, \$column, \$type)) {
+	# Nothing
+    } else {
+	return 0;
+    }
+    $type =~ s/\s//g;
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    $$reftype = $type;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_typedef
+
+sub parse_c_typedef {
+    my $self = shift;
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $reftype = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    my $type;
+
+    if(!$self->_parse_c("typedef", \$_, \$line, \$column)) {
+	return 0;
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    $$reftype = $type;
+
+    return 1;
+}
+
+########################################################################
+# parse_c_variable
+
+sub parse_c_variable {
+    my $self = shift;
+
+    my $found_variable = \${$self->{FOUND_VARIABLE}};
+
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $reflinkage = shift;
+    my $reftype = shift;
+    my $refname = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    my $begin_line = $line;
+    my $begin_column = $column + 1;
+
+    my $linkage = "";
+    my $type;
+    my $name;
+
+    $self->_parse_c("extern|static", \$_, \$line, \$column, \$linkage);
+    if(!$self->parse_c_type(\$_, \$line, \$column, \$type)) { return 0; }
+    if(!$self->_parse_c("\\w+", \$_, \$line, \$column, \$name)) { return 0; }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    $$reflinkage = $linkage;
+    $$reftype = $type;
+    $$refname = $name;
+
+    if(&$$found_variable($begin_line, $begin_column, $linkage, $type, $name))
+    {
+	# Nothing
+    }
+
+    return 1;
+}
+
 1;
diff --git a/tools/winapi/make_parser.pm b/tools/winapi/make_parser.pm
index ff0b517..1fa6e9d 100644
--- a/tools/winapi/make_parser.pm
+++ b/tools/winapi/make_parser.pm
@@ -51,9 +51,9 @@
     }
 
     if(defined($tool)) {
-	$output->write("make_filter: $context: can't parse output: '$current'\n");
+	$output->write("$directory: $context: can't parse output: '$current'\n");
     } else {
-	$output->write("make_filter: $context: can't parse output: '$current'\n");
+	$output->write("$directory: $context: can't parse output: '$current'\n");
     }
     exit 1;
 }
@@ -133,8 +133,12 @@
 	# Nothing
     } elsif($tool eq "gcc" && /^(?:In file included |\s*)from (.+?):(\d+)[,:]$/) {
 	# Nothing
-    } elsif($tool =~ /^gcc|ld$/ && s/^(.+?\.o(?:\(.*?\))?):\s*//) {
-	ld_output($1, $_)
+    } elsif($tool =~ /^gcc|ld$/ && s/^(.+?\.s?o)(?:\(.*?\))?:\s*//) {
+	$tool = "ld";
+	ld_output($1, $_);
+    } elsif($tool =~ /^gcc|ld$/ && s/^collect2:\s*//) {
+	$tool = "ld";
+	ld_output("collect2", $_);
     } elsif($tool eq "gcc" && s/^(.+?\.[chly]):\s*//) {
 	gcc_output($1, $_);
     } elsif($tool eq "winebuild" && s/^(.+?\.spec):\s*//) {
@@ -427,13 +431,13 @@
 		# Nothing
 	    } elsif(/^((?:signed |unsigned )?(?:int|long)) format, (different type|\S+) arg \(arg (\d+)\)$/) {
 		my $type = $2;
-		if($type =~ /^
-		   HACCEL|HANDLE|HBITMAP|HBRUSH|HCALL|HCURSOR|HDC|HDRVR|HDESK|
-		   HGDIOBJ|HKL|HGLOBAL|HINSTANCE|HKEY|
+		if($type =~ /^(?:
+		   HACCEL|HACMDRIVER|HANDLE|HBITMAP|HBRUSH|HCALL|HCURSOR|HDC|HDRVR|HDESK|HDRAWDIB
+		   HGDIOBJ|HKL|HGLOBAL|HIMC|HINSTANCE|HKEY|HLOCAL|
 		   HMENU|HMIDISTRM|HMIDIIN|HMIDIOUT|HMIXER|HMIXEROBJ|HMMIO|HMODULE|
-		   HLINE|HPHONE|HPHONEAPP|
-		   HRASCONN|HRGN|HRSRC|HWAVEIN|HWAVEOUT|HWINSTA|HWND|WSAEVENT|
-		   handle_t|pointer$/x) 
+		   HLINE|HPEN|HPHONE|HPHONEAPP|
+		   HRASCONN|HRGN|HRSRC|HWAVEIN|HWAVEOUT|HWINSTA|HWND|
+		   SC_HANDLE|WSAEVENT|handle_t|pointer)$/x) 
 		{
 		    $supress = 1;
 		} else {
@@ -580,8 +584,14 @@
     $file = shift;
     local $_ = shift;
 
-    if(/^the use of \`(.+?)\' is dangerous, better use \`(.+?)\'$/) {
-	# nothing
+    if(0) {
+	# Nothing
+    } elsif(/^In function \`(.*?)\':$/) {
+	$function = $1;
+    } elsif(0 && /^the use of \`(.+?)\' is dangerous, better use \`(.+?)\'$/) {
+	# Nothing
+    } else {
+	$message = "$_";
     }
 }
 
diff --git a/tools/winapi/output.pm b/tools/winapi/output.pm
index 018d63f..c6154ed 100644
--- a/tools/winapi/output.pm
+++ b/tools/winapi/output.pm
@@ -162,8 +162,13 @@
     my $prefix = \${$self->{PREFIX}};
     my $prefix_callback = \${$self->{PREFIX_CALLBACK}};
 
-    $$prefix = shift;
-    $$prefix_callback = undef;
+    my $new_prefix = shift;
+    if(defined($new_prefix)) {
+	$$prefix = $new_prefix;
+	$$prefix_callback = undef;
+    } else {
+	return $$prefix;
+    }
 }
 
 sub prefix_callback {
diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract
index 8423836..efae0ed 100755
--- a/tools/winapi/winapi_extract
+++ b/tools/winapi/winapi_extract
@@ -16,6 +16,12 @@
 use output qw($output);
 use winapi_extract_options qw($options);
 
+if($options->progress) {
+    $output->enable_progress;
+} else {
+    $output->disable_progress;
+}
+
 use function;
 use type;
 use winapi_function;
@@ -144,9 +150,7 @@
     my %functions;
 
     $progress_current++;
-    if($options->progress) {
-	$output->progress("$file: file $progress_current of $progress_max");
-    }
+    $output->progress("$file (file $progress_current of $progress_max)");
 
     my $create_function = sub {
 	if($options->stub_statistics) {
@@ -159,19 +163,20 @@
     my $found_function = sub {
 	my $function = shift;
 
+	my $internal_name = $function->internal_name;
+	$functions{$internal_name} = $function;
+	
+	$output->progress("$file (file $progress_current of $progress_max): $internal_name");
+	$output->prefix_callback(sub { return $function->prefix; });
+
 	my $documentation_line = $function->documentation_line;
 	my $documentation = $function->documentation;
 	my $function_line = $function->function_line;
 	my $linkage = $function->linkage;
 	my $return_type = $function->return_type;
 	my $calling_convention = $function->calling_convention;
-	my $internal_name = $function->internal_name;
 	my $statements = $function->statements;
 
-	$functions{$internal_name} = $function;
-
-	$output->prefix_callback(sub { return $function->prefix; });
-
 	if($options->spec_files) {
 	    documentation_specifications($function);
 	}
diff --git a/tools/winapi/winapi_fixup b/tools/winapi/winapi_fixup
index 3583143..6f79c36 100755
--- a/tools/winapi/winapi_fixup
+++ b/tools/winapi/winapi_fixup
@@ -19,9 +19,14 @@
 use output qw($output);
 use winapi_fixup_options qw($options);
 
+if($options->progress) {
+    $output->enable_progress;
+} else {
+    $output->disable_progress;
+}
+
+use c_parser;
 use type;
-use winapi_function;
-use winapi_parser;
 
 use winapi_fixup_documentation qw(&fixup_documentation);
 use winapi_fixup_editor;
@@ -39,50 +44,109 @@
     my $editor = new winapi_fixup_editor($file);
 
     $progress_current++;
-    if($options->progress) {
-	$output->progress("$file (file $progress_current of $progress_max)");
-    }
+    $output->progress("$file (file $progress_current of $progress_max)");
+    $output->prefix("$file:");
 
-    my $create_function = sub {
-	return 'winapi_function'->new;
+    {
+	open(IN, "< $file");
+	local $/ = undef;
+	$_ = <IN>;
+	close(IN);
+    }
+    
+    my $parser = new c_parser($file);
+
+    my $found_preprocessor = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	my $preprocessor = shift;
+
+	# $output->write("$begin_line.$begin_column: preprocessor: $preprocessor\n");
+
+	return 1;
     };
 
+    $parser->set_found_preprocessor_callback($found_preprocessor);  
+
+    my $found_comment = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	my $comment = shift;
+
+	# $output->write("$begin_line.$begin_column: comment: $comment\n");
+
+	return 1;
+    };
+
+    $parser->set_found_comment_callback($found_comment);  
+
+    my $found_declaration = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	my $end_line = shift;
+	my $end_column = shift;
+	my $declaration = shift;
+
+	# $output->write("$begin_line.$begin_column-$end_line.$end_column: declaration: \\\n$declaration\n");
+
+	return 1;
+    };
+
+    $parser->set_found_declaration_callback($found_declaration);  
+
+    my $function;
+
     my $found_function = sub {
-	my $function = shift;
-
-	my $internal_name = $function->internal_name;
-	if($options->progress) {
-	    $output->progress("$file (file $progress_current of $progress_max): $internal_name");
-	}
-
-	$output->prefix_callback(sub { return $function->prefix; });
-
+	$function = shift;
+	
+	my $name = $function->name;
+	my $begin_line = $function->begin_line;
+	my $begin_column = $function->begin_column;
+	
+	$output->progress("$file (file $progress_current of $progress_max): $name");
+	$output->prefix("$file:$begin_line: function $name: ");
+	# $output->prefix_callback(sub { return $function->prefix; });
+	
 	if($options->documentation) {
-	    fixup_documentation($function, $editor);
+	    # fixup_documentation($function, $editor);
 	}
-
+	
 	if($options->statements) {
 	    fixup_statements($function, $editor);
 	}
+	
+	my $statements = $function->statements;
+	if(!defined($statements)) {
+	    $function = undef;
+	    $output->prefix("$file: ");
+	}
 
-	$output->prefix("");
+	return 0;
     };
+    
+    $parser->set_found_function_callback($found_function);
 
-    my $create_type = sub {
-	return 'type'->new;
-    };
-
-    my $found_type = sub {
+    my $found_variable = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	my $linkage = shift;
 	my $type = shift;
+	my $name = shift;
+
+	# $output->write("$begin_line.$begin_column: $linkage $type $name\n");
+	
+	return 1;
     };
 
-    my $found_preprocessor = sub {
-	my $directive = shift;
-	my $argument = shift;
-    };
+    $parser->set_found_variable_callback($found_variable);        
 
-    &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
+    my $line = 1;
+    my $column = 0;
+    if(!$parser->parse_c_file(\$_, \$line, \$column)) {
+	$output->write("can't parse file\n");
+    }
+
+    $output->prefix("");
 
     $editor->flush;
 }
-
diff --git a/tools/winapi/winapi_fixup_editor.pm b/tools/winapi/winapi_fixup_editor.pm
index 89331b4..49f0bde 100644
--- a/tools/winapi/winapi_fixup_editor.pm
+++ b/tools/winapi/winapi_fixup_editor.pm
@@ -94,7 +94,7 @@
 
 	    my $line = $. - $lookahead_count;
 	    foreach my $action (@{$$triggers{$line}}) {
-		if($. < $action->{end_line}) {
+    		if($. < $action->{end_line}) {
 		    $lookahead = 1;
 		    next LINE;
 		}
diff --git a/tools/winapi/winapi_fixup_options.pm b/tools/winapi/winapi_fixup_options.pm
index 2acc704..c4a15e5 100644
--- a/tools/winapi/winapi_fixup_options.pm
+++ b/tools/winapi/winapi_fixup_options.pm
@@ -29,7 +29,7 @@
     "documentation-ordinal" => { default => 1, parent => "documentation", description => "documentation ordinal fixup" },
     "documentation-wrong" => { default => 1, parent => "documentation", description => "documentation wrong fixup" },
     "statements" => { default => 1, parent => "local", description => "statements fixup" },
-    "statements-windowsx" => { default => 1, parent => "local", description => "statements windowsx fixup" },
+    "statements-windowsx" => { default => 0, parent => "local", description => "statements windowsx fixup" },
     "stub" => { default => 0, parent => "local", description => "stub fixup" },
 
     "global" => { default => 1, description => "global fixup" },
diff --git a/tools/winapi/winapi_fixup_statements.pm b/tools/winapi/winapi_fixup_statements.pm
index f7706db..9eb648c 100644
--- a/tools/winapi/winapi_fixup_statements.pm
+++ b/tools/winapi/winapi_fixup_statements.pm
@@ -9,10 +9,19 @@
 @EXPORT = qw();
 @EXPORT_OK = qw(&fixup_statements);
 
+use config qw($wine_dir);
 use options qw($options);
 use output qw($output);
 
 use c_parser;
+use winapi_module_user qw(
+    &get_message_result_kind
+    &get_message_wparam_kind
+    &get_message_lparam_kind
+);
+
+########################################################################
+# fixup_function_call
 
 sub fixup_function_call {
     my $name = shift;
@@ -21,37 +30,58 @@
     return "$name(" . join(", ", @arguments) . ")";
 }
 
+########################################################################
+# _parse_makelong
+
 sub _parse_makelong {
-    my $value = shift;
+    local $_ = shift;
 
     my $low;
     my $high;
-    if($value =~ /^
-       (?:\(\w+\)\s*)?
-       MAKE(?:LONG|LPARAM|LRESULT|WPARAM)\s*
-       \(\s*(.*?)\s*,\s*(.*?)\s*\)$/sx)
+
+    my $name;
+    my @arguments;
+    my @argument_lines;
+    my @argument_columns;
+
+    my $parser = new c_parser;
+
+    my $line = 1;
+    my $column = 0;
+    if($parser->parse_c_function_call(\$_, \$line, \$column, \$name, \@arguments, \@argument_lines, \@argument_columns) &&
+       $name =~ /^MAKE(?:LONG|LPARAM|LRESULT|WPARAM)$/) 
     {
-	$low = $1;
-	$high = $2;
-    } elsif($value =~ /^(?:\(\w+\)\s*)?0L?$/) {
+	$low = $arguments[0];
+	$high = $arguments[1];
+    } elsif(/^(?:\(\w+\)\s*)?0L?$/) {
 	$low = "0";
 	$high = "0";
     } else {
-	$low = "($value) & 0xffff";
-	$high = "($value) << 16";
+	$low = "($_) & 0xffff";
+	$high = "($_) << 16";
     }
 
+    $low =~ s/^\s*(.*?)\s*$/$1/;
+    $high =~ s/^\s*(.*?)\s*$/$1/;
+
     return ($low, $high);
 }
 
-sub fixup_function_call_2_forward_wm_call {
+########################################################################
+# fixup_function_call_2_windowsx
+
+sub fixup_user_message_2_windowsx {
     my $name = shift;
     (my $hwnd, my $msg, my $wparam, my $lparam) = @{(shift)};
 
-    if($msg =~ /^(?:WM_BEGINDRAG|WM_ENTERMENULOOP|WM_EXITMENULOOP|WM_HELP|
-		  WM_ISACTIVEICON|WM_LBTRACKPOINT|WM_NEXTMENU)$/x) 
+    if($msg !~ /^WM_/) {
+	return undef;
+    } elsif($msg =~ /^(?:WM_BEGINDRAG|WM_ENTERMENULOOP|WM_EXITMENULOOP|WM_HELP|
+		       WM_ISACTIVEICON|WM_LBTRACKPOINT|WM_NEXTMENU)$/x) 
     {
 	return undef;
+    } elsif($msg =~ /^WM_(?:GET|SET)TEXT$/) {
+	return undef;
     }
 
     my $suffix;
@@ -62,8 +92,8 @@
 	$suffix = "";
     }
 
-    $wparam =~ s/^\(WPARAM\)//;
-    $lparam =~ s/^\(LPARAM\)//;
+    $wparam =~ s/^\(WPARAM\)\s*//;
+    $lparam =~ s/^\(LPARAM\)\s*//;
 
     my @arguments;
     if(0) {
@@ -131,67 +161,161 @@
     return "FORWARD_" . $msg . "(" . join(", ", @arguments) . ", $name)";
 }
 
+########################################################################
+# _fixup_user_message
+
+sub _get_messages {
+    local $_ = shift;
+
+    if(/^WM_\w+$/) {
+	return ($_)
+    } elsif(/^(.*?)\s*\?\s*(WM_\w+)\s*:\s*(WM_\w+)$/) {
+	return ($2, $3);
+    } elsif(/^\w+$/) {
+	return ();
+    } else {
+	$output->write("_fixup_user_message: '$_'\n");
+	exit 1;
+    }
+}
+
+########################################################################
+# _fixup_user_message
+
+sub _fixup_user_message {
+    my $name = shift;
+    (my $hwnd, my $msg, my $wparam, my $lparam) = @{(shift)};
+
+    my $modified = 0;
+
+    my $wkind;
+    my $lkind;
+    foreach my $msg (_get_messages($msg)) {
+	my $new_wkind = &get_message_wparam_kind($msg);
+	if(defined($wkind) && $new_wkind ne $wkind) {
+	    $output->write("messsages used together do not have the same type\n");
+	} else {
+	    $wkind = $new_wkind;
+	}
+
+	my $new_lkind = &get_message_lparam_kind($msg);
+	if(defined($lkind) && $new_lkind ne $lkind) {
+	    $output->write("messsages used together do not have the same type\n");
+	} else {
+	    $lkind = $new_lkind;
+	}
+    }
+
+    my @entries = (
+	[ \$wparam, $wkind, "W", "w" ],
+	[ \$lparam, $lkind, "L", "l" ]
+    );
+    foreach my $entry (@entries) {
+	(my $refparam, my $kind, my $upper, my $lower) = @$entry;
+
+	if(!defined($kind)) {
+	    if($msg =~ /^WM_/) {
+		$output->write("messsage $msg not defined\n");
+	    }
+	} elsif($kind eq "ptr") {
+	    if($$refparam =~ /^(\(${upper}PARAM\))?\s*($lower[pP]aram)$/) {
+		if(defined($1)) {
+		    $$refparam = $2;
+		    $modified = 1;
+		}
+	    } elsif($$refparam =~ /^(\(${upper}PARAM\))?\s*0$/) {
+	        $$refparam = "(${upper}PARAM) NULL";
+		$modified = 1;
+	    } elsif($$refparam !~ /^\(${upper}PARAM\)\s*/) {
+                $$refparam = "(${upper}PARAM) $$refparam";
+		$modified = 1;
+	    }
+	} elsif($kind eq "long") {
+	    if($$refparam =~ s/^\(${upper}PARAM\)\s*//) {
+		$modified = 1;
+	    }
+	}
+    }
+
+    if($modified) {
+	my @arguments = ($hwnd, $msg, $wparam, $lparam);
+	return "$name(" . join(", ", @arguments) . ")";
+    } else {
+	return undef;
+    }
+}
+
+########################################################################
+# fixup_statements
+
 sub fixup_statements {
     my $function = shift;
     my $editor = shift;
 
+    my $file = $function->file;
     my $linkage = $function->linkage;
-    my $internal_name = $function->internal_name;
+    my $name = $function->name;
     my $statements_line = $function->statements_line;
+    my $statements_column = $function->statements_column;
     my $statements = $function->statements;
-    
-    if(($linkage eq "extern" && !defined($statements)) ||
-       ($linkage eq "" && !defined($statements)))
-    {
+   
+    if(!defined($statements)) {
 	return;
     }
-    
-    if($options->statements_windowsx && defined($statements)) {
-	my $found_function_call = sub {
-	    my $begin_line = shift;
-	    my $begin_column = shift;
-	    my $end_line = shift;
-	    my $end_column = shift;
-	    my $name = shift;
-	    my $arguments = shift;
-	    
-	    foreach my $argument (@$arguments) {
-		$argument =~ s/^\s*(.*?)\s*$/$1/;
-	    }
 
-	    if($options->statements_windowsx &&
-	       $name =~ /^(?:DefWindowProc|SendMessage)[AW]$/ &&
-	       $$arguments[1] =~ /^WM_\w+$/) 
-	    {
-		fixup_replace(\&fixup_function_call_2_forward_wm_call, $editor,
-			      $begin_line, $begin_column, $end_line, $end_column,
-			      $name, $arguments);
-	    } elsif(0) {
-		$output->write("$begin_line.$begin_column-$end_line.$end_column: " .
-			       "$name(" . join(", ", @$arguments) . ")\n");
-	    }
-	};
+    if(0 && $statements_line > 490) {
+	$output->write("$statements_line: \\\n");
 	my $line = $statements_line;
-	my $column = 1;
-	
-	if(!&c_parser::parse_c_statements(\$statements, \$line, \$column, $found_function_call)) {
-	    $output->write("error: can't parse statements\n");
+	foreach my $statement (split(/\n/, $statements)) {
+	    $output->write("$line: $statement\n");
+	    $line++;
 	}
     }
-}
 
-sub fixup_replace {
-    my $function = shift;
-    my $editor = shift;
-    my $begin_line = shift;
-    my $begin_column = shift;
-    my $end_line = shift;
-    my $end_column = shift;
+    my $parser = new c_parser($file);
+    
+    my $found_function_call = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	my $end_line = shift;
+	my $end_column = shift;
+	my $name = shift;
+	my $arguments = shift;
+	
+	foreach my $argument (@$arguments) {
+	    $argument =~ s/^\s*(.*?)\s*$/$1/;
+	}
 
-    my $replace = &$function(@_);
+	my $fixup_function_call;
+	if($name =~ /^(?:DefWindowProc|SendMessage)[AW]$/)
+	{
+	    if($options->statements_windowsx) {
+		$fixup_function_call = \&fixup_user_message_2_windowsx;
+	    } else {
+		$fixup_function_call = \&_fixup_user_message;
+	    }
+	} 
 
-    if(defined($replace)) {
-	$editor->replace($begin_line, $begin_column, $end_line, $end_column, $replace);
+	if(defined($fixup_function_call)) {
+	    my $replace = &$fixup_function_call($name, $arguments);
+
+	    if(defined($replace)) {
+		$editor->replace($begin_line, $begin_column, $end_line, $end_column, $replace);
+	    }
+	}  elsif(0 || $options->debug) {
+	    $output->write("$begin_line.$begin_column-$end_line.$end_column: " .
+			   "$name(" . join(", ", @$arguments) . ")\n");
+	}
+
+	return 0;
+    };
+    
+    $parser->set_found_function_call_callback($found_function_call);
+    
+    my $line = $statements_line;
+    my $column = 0;	
+    if(!$parser->parse_c_statements(\$statements, \$line, \$column)) {
+	$output->write("error: can't parse statements\n");
     }
 }
 
diff --git a/tools/winapi/winapi_module_user.pm b/tools/winapi/winapi_module_user.pm
new file mode 100644
index 0000000..be853c5
--- /dev/null
+++ b/tools/winapi/winapi_module_user.pm
@@ -0,0 +1,445 @@
+package winapi_module_user;
+
+use strict;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw(
+    &is_user_function
+    &get_message_result_type
+    &get_message_result_kind
+    &get_message_wparam_type
+    &get_message_wparam_kind
+    &get_message_lparam_type
+    &get_message_lparam_kind
+);
+
+use config qw($wine_dir);
+use options qw($options);
+use output qw($output);
+
+use c_parser;
+
+########################################################################
+
+my $message;
+
+########################################################################
+# is_user_function
+
+sub is_user_function {
+    my $name = shift;
+    if($name =~ /^(?:DefWindowProc|SendMessage)[AW]?$/) {
+    }
+}
+
+########################################################################
+# $message
+
+$message = {
+    WM_ACTIVATE => {
+	id => 0, result => "void", wparam => ["", ""], lparam => "HWND" },
+    WM_ACTIVATEAPP => {
+	id => 0, result => "void", wparam => "BOOL", lparam => "LPARAM" },
+
+    WM_BEGINDRAG => {
+	id => 0, result => "", wparam => "", lparam => "" },
+
+    WM_CANCELMODE => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+    WM_CHAR => {
+	id => 0, result => "void", wparam => "TCHAR", lparam => ["", ""] },
+    WM_CHARTOITEM => {
+	id => 0x002f, result => "void", wparam => ["UINT", "int"], lparam => "HWND" },
+    WM_CLOSE => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+    WM_COMMAND => {
+	id => 0, result => "void", wparam => ["int", "UINT"], lparam => "HWND" },
+    WM_COPY => {
+	id => 0x0301, result => "void", wparam => "void", lparam => "void" },
+    WM_COMPACTING => { 
+	id => 0, result => "void", wparam => "UINT", lparam => "void" },
+    WM_COMPAREITEM => { 
+	id => 0, result => "int", wparam => "UINT", lparam => "const COMPAREITEMSTRUCT *" },
+
+    WM_CREATE => {
+	id => 0, result => "BOOL", wparam => "void", lparam => "LPCREATESTRUCT" },
+    WM_CTLCOLORBTN => {
+	id => 0x0135, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+    WM_CTLCOLORDLG => {
+	id => 0x136, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+    WM_CTLCOLOREDIT => {
+	id => 0x133, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+    WM_CTLCOLORLISTBOX => {
+	id => 0x134, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+    WM_CTLCOLORMSGBOX => {
+	id => 0x132, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+    WM_CTLCOLORSCROLLBAR => {
+	id => 0x137, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+    WM_CTLCOLORSTATIC => {
+	id => 0x138, result => "HBRUSH", wparam => "HDC", lparam => "HWND" },
+
+    WM_CUT => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+
+    WM_DEADCHAR => {
+	id => 0, result => "void", wparam => "TCHAR", lparam => ["", ""] },
+    WM_DELETEITEM => { 
+	id => 0, result => "void", wparam => "UINT", lparam => "const DELETEITEMSTRUCT *" },
+    WM_DEVMODECHANGE => {
+	id => 0, result => "void", wparam => "void", lparam => "LPCTSTR" },
+    WM_DESTROY => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+    WM_DRAWITEM => {
+	id => 0, result => "void", wparam => "void", lparam => "const DRAWITEMSTRUCT *" },
+    WM_DROPFILES => {
+	id => 0, result => "void", wparam => "HDROP", lparam => "void" },
+
+    WM_ENABLE => {
+	id => 0, result => "void", wparam => "BOOL", lparam => "void" },
+    WM_ENDSESSION => {
+	id => 0, result => "void", wparam => "BOOL", lparam => "void" },
+    WM_ENTERIDLE => {
+	id => 0x0121, result => "void", wparam => "UINT", lparam => "HWND" },
+    WM_ENTERMENULOOP => {
+	id => 0x0211, result => "", wparam => "", lparam => "" },
+    WM_ERASEBKGND => {
+	id => 0, result => "BOOL", wparam => "HDC", lparam => "void" },
+    WM_EXITMENULOOP => {
+	id => 0x0212, result => "", wparam => "", lparam => "" },
+
+    WM_FONTCHANGE => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+
+    WM_GETTEXT => {
+	id => 0, result => "int", wparam => "int", lparam => "LPTSTR" },
+    WM_GETTEXTLENGTH => {
+	id => 0, result => "int", wparam => "void", lparam => "void" },
+
+    WM_HELP => {
+	id => 0x0053, result => "", wparam => "", lparam => "" },
+    WM_HSCROLL => {
+	id => 0, result => "void", wparam => ["UINT", "int"], lparam => "HWND" },
+
+    WM_ICONERASEBKGND => {
+	id => 0, result => "BOOL", wparam => "HDC", lparam => "void" },
+    WM_INITMENU => {
+	id => 0, result => "void", wparam => "HMENU", lparam => "void" },
+    WM_INITMENUPOPUP => {
+	id => 0, result => "void", wparam => "HMENU", lparam => ["UINT", "BOOL"] },
+    WM_ISACTIVEICON => {
+	id => 0, result => "", wparam => "", lparam => "" },
+
+    WM_KEYDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_KEYUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_KILLFOCUS => {
+	id => 0, result => "void", wparam => "HWND", lparam => "void" },
+
+    WM_LBTRACKPOINT => {
+	id => 0, result => "", wparam => "", lparam => "" },
+    WM_LBUTTONDBLCLK => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_LBUTTONDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_LBUTTONUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+
+    WM_MBUTTONDBLCLK => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_MBUTTONDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_MBUTTONUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_MEASUREITEM => {
+	id => 0, result => "void", wparam => "UINT", lparam => "MEASUREITEMSTRUCT *" },
+    WM_MENUSELECT => {
+	id => 0, result => "void", wparam => ["", ""], lparam => "HMENU" },
+    WM_MENUCHAR => {
+	id => 0, result => "DWORD", wparam => ["", ""], lparam => "HMENU" },
+    WM_MOUSEACTIVATE => {
+	id => 0, result => "int", wparam => "HWND", lparam => ["", ""] },
+    WM_MOUSEMOVE => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_MOVE => {
+	id => 0, result => "void", wparam => "void", lparam => ["", ""] },
+
+    WM_NCACTIVATE => {
+	id => 0, result => "BOOL", wparam => "BOOL", lparam => "void" },
+    WM_NCLBUTTONDBLCLK => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCLBUTTONDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCLBUTTONUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCMOUSEMOVE => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCMBUTTONDBLCLK => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCMBUTTONDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCMBUTTONUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCRBUTTONDBLCLK => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCRBUTTONDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCRBUTTONUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_NCCALCSIZE => {
+	id => 0, result => "UINT", wparam => "void", lparam => "LPARAM" },
+    WM_NCCREATE => {
+	id => 0, result => "BOOL", wparam => "void", lparam => "LPCREATESTRUCT" },
+    WM_NCDESTROY => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+    WM_NCPAINT => {
+	id => 0, result => "void", wparam => "HRGN", lparam => "void" },
+    WM_NEXTMENU => {
+	id => 0x0213, result => "", wparam => "", lparam => "" },
+    WM_NOTIFY => {
+	id => 0x004e, result => "LRESULT", wparam => "int", lparam => "NMHDR *" },
+
+
+    WM_PALETTEISCHANGING => {
+	id => 0, result => "void", wparam => "HWND", lparam => "void" },
+    WM_PALETTECHANGED => {
+	id => 0, result => "void", wparam => "HWND", lparam => "void" },
+    WM_PAINT => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+    WM_PASTE => {
+	id => 0x0302, result => "void", wparam => "void", lparam => "void" },
+    WM_POWER => {
+	id => 0, result => "void", wparam => "int", lparam => "void" },
+
+    WM_QUERYDRAGICON => {
+	id => 0, result => "HICON", wparam => "void", lparam => "void" },
+    WM_QUERYENDSESSION => {
+	id => 0, result => "BOOL", wparam => "void", lparam => "void" },
+    WM_QUERYNEWPALETTE => {
+	id => 0, result => "BOOL", wparam => "void", lparam => "void" },
+    WM_QUERYOPEN => {
+	id => 0, result => "BOOL", wparam => "void", lparam => "void" },
+    WM_QUIT => {
+	id => 0, result => "void", wparam => "WPARAM", lparam => "void" },
+
+    WM_RBUTTONDBLCLK => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_RBUTTONDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_RBUTTONUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+
+    WM_SETCURSOR => {
+	id => 0x0020, result => "", wparam => "HWND", lparam => ["UINT", "UINT"] },
+    WM_SETFOCUS => {
+	id => 0, result => "void", wparam => "HWND", lparam => "void" },
+    WM_SETFONT => {
+	id => 0x0030, result => "void", wparam => "HFONT", lparam => "BOOL" },
+    WM_SETREDRAW => {
+	id => 0, result => "void", wparam => "BOOL", lparam => "void" },
+    WM_SETTEXT => {
+	id => 0, result => "void", wparam => "void", lparam => "LPCTSTR" },
+    WM_SHOWWINDOW => {
+	id => 0, result => "void", wparam => "BOOL", lparam => "UINT" },
+    WM_SIZE => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_SPOOLERSTATUS => {
+	id => 0, result => "void", wparam => "WPARAM", lparam => ["", ""] },
+    WM_SYSCHAR => {
+	id => 0, result => "void", wparam => "TCHAR", lparam => ["", ""] },
+    WM_SYSCOLORCHANGE => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+    WM_SYSDEADCHAR => {
+	id => 0, result => "void", wparam => "TCHAR", lparam => ["", ""] },
+    WM_SYSKEYDOWN => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+    WM_SYSKEYUP => {
+	id => 0, result => "void", wparam => "UINT", lparam => ["", ""] },
+
+    WM_TIMECHANGE => {
+	id => 0, result => "void", wparam => "void", lparam => "void" },
+
+    WM_VKEYTOITEM => {
+	id => 0x002e, result => "void", wparam => ["UINT", "int"], lparam => "HWND" },
+    WM_VSCROLL => {
+	id => 0, result => "void", wparam => ["UINT", "int"], lparam => "HWND" },
+
+    WM_WINDOWPOSCHANGING => {
+	id => 0, result => "BOOL", wparam => "void", lparam => "LPWINDOWPOS" },
+    WM_WINDOWPOSCHANGED => {
+	id => 0, result => "void", wparam => "void", lparam => "LPARAM" },
+    WM_WININICHANGE => { 
+	id => 0, result => "void", wparam => "void", lparam => "LPCTSTR" }
+};
+
+########################################################################
+# _get_kind
+
+sub _get_kind {
+    local $_ = shift;
+
+    if(!defined($_)) {
+	return undef;
+    } elsif(/^(?:HBRUSH|HDC|HFONT|HMENU|HRGN|HWND)$/ || /\*$/ ||
+	    /^LP(?!ARAM)/)
+    {
+	return "ptr";
+    } else {
+	return "long";
+    }
+}
+
+########################################################################
+# get_message_result_type
+
+sub get_message_result_type {
+    my $name = shift;
+    return $$message{$name}{result};
+}
+
+########################################################################
+# get_message_result_kind
+
+sub get_message_result_kind {
+    return _get_kind(get_message_result_type(@_));
+}
+
+########################################################################
+# get_message_wparam_type
+
+sub get_message_wparam_type {
+    my $name = shift;
+    return $$message{$name}{wparam};
+}
+
+########################################################################
+# get_message_wparam_kind
+
+sub get_message_wparam_kind {
+    return _get_kind(get_message_wparam_type(@_));
+}
+
+########################################################################
+# get_message_lparam_type
+
+sub get_message_lparam_type {
+    my $name = shift;
+    return $$message{$name}{lparam};
+}
+
+########################################################################
+# get_message_lparam_kind
+
+sub get_message_lparam_kind {
+    return _get_kind(get_message_lparam_type(@_));
+}
+
+########################################################################
+# _parse_windowsx_h
+
+sub _parse_windowsx_h {
+    my $file = "$wine_dir/include/windowsx.h";
+    {
+	open(IN, "< $file");
+	local $/ = undef;
+	$_ = <IN>;
+	close(IN);
+    }
+
+    my $parser = new c_parser($file);
+
+    my $found_preprocessor = sub {
+	my $begin_line = shift;
+	my $begin_column = shift;
+	local $_ = shift;
+
+	if(!s/^\#\s*define\s*// || !/^FORWARD_WM_/) {
+	    return 1;
+	}
+	
+	my $msg;
+	if(s/^FORWARD_(\w+)\([^\)]*\)\s*(.*?)\s*$/$2/s) {
+	    $msg = $1;
+	}
+
+	if($msg eq "WM_SYSTEMERROR") {
+	    return 1;
+	}
+
+	my $return_type;
+	if(s/^\(\s*(\w+)\s*\)(?:\(\s*\w+\s*\))*\(\s*\w+\s*\)\(\s*(?:hwnd|\(hwnd\))\s*,\s*(.*?)\s*\)$/$2/) {
+	    $return_type = $1;
+	} else {
+	    die "$msg: '$_'";
+	}
+	
+	my @msgs = ();
+	if(s/^$msg\s*,\s*//) {
+	    @msgs = $msg;
+	} elsif(s/^\(\w+\)\s*\?\s*(\w+)\s*:\s*(\w+)\s*,\s*//s) {
+	    @msgs = ($1, $2);
+	} else {
+	    die "$msg: '$_'";
+	}
+	
+	my $wparam;
+	if(s/^\(WPARAM\)(?:\(\s*(\w+)\s*\))*\((.*?)\)\s*,\s*//) {
+	    if(defined($1)) {
+		$wparam = $1;
+	    } else {
+		$wparam = "WPARAM";
+	    }
+	} elsif(s/^MAKEWPARAM\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*,\s*//) {
+	    $wparam = "(,)"; # "($1, $2)";
+	} elsif(s/^\((.*?)\)$//) {
+	    $wparam = "WPARAM";
+	} elsif(s/^0L\s*,\s*//) {
+	    $wparam = "void";
+	} else {
+	    die "$msg: '$_'";
+	} 
+
+	my $lparam;
+	if(s/^\(LPARAM\)(?:\(\s*(\w+)\s*\))*\((.*?)\)$//) {
+	    if(defined($1)) {
+		$lparam = $1;
+	    } else {
+		$lparam = "LPARAM";
+	    }
+	} elsif(s/^MAKELPARAM\(\s*(.*?)\s*,\s*(.*?)\s*\)$//) {
+	    $lparam = "(,)"; # "($1, $2)";
+	} elsif(s/^\((.*?)\)$//) {
+	    $lparam = "LPARAM";
+	} elsif(s/^0L$//) {
+	    $lparam = "void";
+	} else {
+	    die "$msg: '$_'";
+	} 
+
+	foreach my $msg (@msgs) {
+	    $output->write("$msg => { result => \"$return_type\", wparam => \"$wparam\", lparam => \"$lparam\" },\n");
+	}
+
+	return 1;
+    };
+
+    $parser->set_found_preprocessor_callback($found_preprocessor);
+
+    my $line = 1;
+    my $column = 0;
+
+    my $old_prefix = $output->prefix;
+    $output->progress("$file");
+    $output->prefix("$file: ");
+
+    if(!$parser->parse_c_file(\$_, \$line, \$column)) {
+	$output->write("can't parse file\n");
+    }
+
+    $output->prefix($old_prefix);
+}
+
diff --git a/tools/winapi_check/modules.pm b/tools/winapi_check/modules.pm
index 1880b49..a6598b6 100644
--- a/tools/winapi_check/modules.pm
+++ b/tools/winapi_check/modules.pm
@@ -70,9 +70,7 @@
 
     my $module_file = "$winapi_check_dir/modules.dat";
 
-    if($options->progress) {
-	$output->progress("modules.dat");
-    }
+    $output->progress("modules.dat");
 
     my %spec_file_found;
     my $allowed_dir;
diff --git a/tools/winapi_check/nativeapi.pm b/tools/winapi_check/nativeapi.pm
index dc5bf38..969e58c 100644
--- a/tools/winapi_check/nativeapi.pm
+++ b/tools/winapi_check/nativeapi.pm
@@ -36,9 +36,7 @@
     $configure_in_file =~ s/^\.\///;
     $config_h_in_file =~ s/^\.\///;
 
-    if($options->progress) {
-	$output->progress("$api_file");
-    }
+    $output->progress("$api_file");
 
     open(IN, "< $api_file");
     local $/ = "\n";
@@ -51,9 +49,7 @@
     }
     close(IN);
 
-    if($options->progress) {
-	$output->progress("$configure_in_file");
-    }
+    $output->progress("$configure_in_file");
 
     my $again = 0;
     open(IN, "< $configure_in_file");   
@@ -102,9 +98,7 @@
     }
     close(IN);
 
-    if($options->progress) {
-	$output->progress("$config_h_in_file");
-    }
+    $output->progress("$config_h_in_file");
 
     open(IN, "< $config_h_in_file");
     local $/ = "\n";
diff --git a/tools/winapi_check/win32/kernel32.api b/tools/winapi_check/win32/kernel32.api
index a062a4e..2106c83 100644
--- a/tools/winapi_check/win32/kernel32.api
+++ b/tools/winapi_check/win32/kernel32.api
@@ -136,8 +136,6 @@
 PLONG
 PTIMERAPCROUTINE
 PULARGE_INTEGER
-PVOID
-PVOID *
 SECURITY_ATTRIBUTES *
 SYSLEVEL *
 SYSLEVEL **
diff --git a/tools/winapi_check/win32/oleaut32.api b/tools/winapi_check/win32/oleaut32.api
index 5eebc41..616df9d 100644
--- a/tools/winapi_check/win32/oleaut32.api
+++ b/tools/winapi_check/win32/oleaut32.api
@@ -66,10 +66,12 @@
 LPOCPFIPARAMS
 LPPICTDESC
 LPSTREAM
+LPSYSTEMTIME
 LPUNKNOWN
 LPUNKNOWN *
 LPVOID
 LPVOID *
+NUMPARSE *
 OLECHAR *
 OLECHAR **
 REFCLSID
@@ -78,6 +80,7 @@
 SAFEARRAY *
 SAFEARRAY **
 SAFEARRAYBOUND *
+UDATE *
 UINT *
 ULONG *
 USHORT *
diff --git a/tools/winapi_check/win32/quartz.api b/tools/winapi_check/win32/quartz.api
index b4d5096..c9b8791 100644
--- a/tools/winapi_check/win32/quartz.api
+++ b/tools/winapi_check/win32/quartz.api
@@ -1,6 +1,5 @@
 %long
 
-DWORD
 HRESULT
 
 %ptr
diff --git a/tools/winapi_check/win32/shell32.api b/tools/winapi_check/win32/shell32.api
index 20ce347..d4afdf2 100644
--- a/tools/winapi_check/win32/shell32.api
+++ b/tools/winapi_check/win32/shell32.api
@@ -6,6 +6,7 @@
 HANDLE
 HBITMAP
 HDROP
+HGLOBAL
 HMENU
 HICON
 HINSTANCE
diff --git a/tools/winapi_check/win32/ttydrv.api b/tools/winapi_check/win32/ttydrv.api
index e08e9d3..39439a3 100644
--- a/tools/winapi_check/win32/ttydrv.api
+++ b/tools/winapi_check/win32/ttydrv.api
@@ -43,7 +43,7 @@
 RECT *
 WINDOWPOS *
 struct tagCURSORICONINFO *
-struct tagWND *
+
 void *
 
 %str
diff --git a/tools/winapi_check/win32/x11drv.api b/tools/winapi_check/win32/x11drv.api
index 77363b9..f811145 100644
--- a/tools/winapi_check/win32/x11drv.api
+++ b/tools/winapi_check/win32/x11drv.api
@@ -53,7 +53,6 @@
 RECT *
 TEXTMETRICW *
 WINDOWPOS *
-WND *
 void *
 
 %str
diff --git a/tools/winapi_check/winapi.pm b/tools/winapi_check/winapi.pm
index 4eb33e4..b7d32fe 100644
--- a/tools/winapi_check/winapi.pm
+++ b/tools/winapi_check/winapi.pm
@@ -105,9 +105,7 @@
     my $extension = 0;
     my $forbidden = 0;
 
-    if($options->progress) {
-	$output->lazy_progress("$file");
-    }
+    $output->lazy_progress("$file");
 
     open(IN, "< $wine_dir/$file") || die "$wine_dir/$file: $!\n";
     $/ = "\n";
@@ -217,9 +215,7 @@
     my $module;
     my $module_file;
 
-    if($options->progress) {
-	$output->lazy_progress("$file");
-    }
+    $output->lazy_progress("$file");
 
     open(IN, "< $file") || die "$file: $!\n";
     $/ = "\n";
diff --git a/tools/winapi_check/winapi_check b/tools/winapi_check/winapi_check
index b7feb37..16b6102 100755
--- a/tools/winapi_check/winapi_check
+++ b/tools/winapi_check/winapi_check
@@ -26,6 +26,13 @@
 );
 use output qw($output);
 use winapi_check_options qw($options);
+
+if($options->progress) {
+    $output->enable_progress;
+} else {
+    $output->disable_progress;
+}
+
 use modules qw($modules);
 use nativeapi qw($nativeapi);
 use winapi qw($win16api $win32api @winapis);
@@ -50,9 +57,7 @@
 
     foreach my $file (@files) {
 	$progress_current++;
-	if($options->progress) {
-	    $output->lazy_progress("$file: file $progress_current of $progress_max");
-	}
+	$output->lazy_progress("$file: file $progress_current of $progress_max");
 
 	my $file_dir = $file;
 	if(!($file_dir =~ s%(.*?)/[^/]+$%$1%)) {
@@ -128,9 +133,7 @@
 	my %functions;
 	
 	$progress_current++;
-	if($options->progress) {
-	    $output->progress("$file: file $progress_current of $progress_max");
-	}
+	$output->progress("$file: file $progress_current of $progress_max");
 
 	my $create_function = sub {
 	    return 'winapi_function'->new;
@@ -139,11 +142,13 @@
 	my $found_function = sub {
 	    my $function = shift;
 
+	    my $internal_name = $function->internal_name;
+
+	    $output->progress("$file (file $progress_current of $progress_max): $internal_name");
 	    $output->prefix_callback(sub { return $function->prefix; });
 
 	    my $function_line = $function->function_line;
 	    my $linkage = $function->linkage;
-	    my $internal_name = $function->internal_name;
 	    my $external_name = $function->external_name;
 	    my $statements = $function->statements;
 
@@ -200,9 +205,7 @@
     my $file_module32 = $modules->allowed_modules_in_file("$current_dir/$file");
 
     $progress_current++;
-    if($options->progress) {
-	$output->progress("$file: file $progress_current of $progress_max");
-    }
+    $output->progress("$file (file $progress_current of $progress_max)");
 
     my $file_dir = $file;
     if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) {
@@ -216,11 +219,12 @@
     my $found_function = sub {
 	my $function = shift;
 
-	$output->prefix_callback(sub { return $function->prefix; });
-
 	my $internal_name = $function->internal_name;
 	$functions{$internal_name} = $function;
 
+	$output->progress("$file (file $progress_current of $progress_max): $internal_name");
+	$output->prefix_callback(sub { return $function->prefix; });
+
 	my $declared_function = $declared_functions{$internal_name};
 
 	my $documentation_line = $function->documentation_line;