RE: Wine 1.0, the sequel

2000-05-19 Thread Patrik Stridvall

 B.  Obtain commitments for work
 I would like to start having people indicate
 whether or not they are working or will be working on a
 task.
 
 For our part, CodeWeavers is going to volunteer to do the
 jobs no
 one else wants (like QA and documentation).  
 Really we will,
 let me just twist a few more arms...g
[snip]

Personally I'm intrested in and are working on "meta-QA"
and "meta-documentation", but not some much actual QA
and actual documentation.

In other words to write tools like winapi_check and the
new not yet released winapi_test.

winapi_check have a lot of options that a turned off by default
since they produce to much output. Of course most reported
things are not actual bugs but potential bugs but there
is not possible for me to tell which is which, since it either
is to complicated or the information required is not possible
to get from the source even in theory.

One example of this is the signed/unsigned mismatch in over 200
Win16 API functions. In most of these cases it isn't a real bug
since the most significant bit in the 16-bit word is never used
and can never be set and thus can never be wrongly sign extended.
But there might be real bugs hidden in all these output,
they must _all_ be fixed in order to nail down the real ones.
Run "winapi_check --argument-kind=word,s_word" to see them.

There are also a lot of functions that lack prototypes,
which is bad for WineLib applications.
Run "winapi_check --headers" to see them.

What I'm trying to point out is that tools like winapi_check
is very useful in finding bugs actual or potential, bug actually
fixing them is very boring that why I haven't done it except
on to a small degree.

So if you assign somebody to do the boring work of fixing the potential
(in the prototype case always real) bugs reported by winapi_check
and in the future winapi_test. I'm prepare to help you by
implementing more checks. Feel free to suggest new ones.

Note, be very careful, do not trust the output of winapi_check,
in some case I might have made mistakes both logical and
implementation wise in some case whether it is bug or not
depend on the documentation of the function, so read it
_carefully_ before deciding whether winapi_check is correct or not.
But I probably needn't had to said that since that should be
obvious to all programmers.

In short, if you do QA, I will do meta-QA. :-)

 4.  After the requirements for release have been met,
 declare Wine ready for release.
 (is this point decided by consensus?  Fiat by Alexandre?)

IMHO Alexandre decides. I'm not a believer in voting about it.

 *   some kind of automated regression testing, at least for
 non-graphical APIs  (Alexandre Julliard)

I have meantion earlier I'm working on a new project winapi_test
that does brute force testing of the API:s. 

What it does is that is generates a Windows (WineLib) application
that can be compiled and run under both Wine and Windows and
produces logs that can be compared and bugs fixed.

Currently it only implements a NULL test where all functions
are called with all NULL arguments, but even this very simple
test have found a _lot_ of errors. I have already used it to
fix a few of them (already in the CVS).

   Not absolutely required for release IMHO:
 
 * Many sample applications compile and work with Winelib 
 'out of the
box' (along the lines of the work that Francois Gouget 
 is doing).
 (Jeremy White)  (Okay, Marcus, I pushed it down to here,
 but I reserve the option to make this happen anyway g)

Personally I think it is very important, since I think a 1.0 will
make many companies start investigating whether a port of their
software is realistic or not.




MFC questions

2000-05-19 Thread Wilbur N. Dale

Hello,

Over the past few months I have been working with wine and winelib in my spare
time. Eventually I hope to port a Win32 app to linux using winelib. The next
major hurdle in the port is MFC. I see two paths and I am seeking advice and
help.

1. Compile MFC.  Several years ago we (Lumin Software) tried to compile MFC. 
The attempt failed and we found another way to do what we wanted. MS
documentation states that compiling MFC was deliberately made difficult.
Considering my experience with stuff they call "easy" I am not looking forward
to compiling MFC. We are currently using Visual Studio 5 for windows
development.

2. Create some code that loads and initializes the MFC library and allows
access to the MFC functions from within winelib. I know how to do this. I
successfully ran the EdrTest/EdrLib example from Petzold last weekend. In my
code, I had edrtest compiled under winelib and it ran the functions using the
windows compiled edrlib.dll. I think this solution may be easier, but it
requires over a thousand functions in MFC to be hooked up. However, it looks
like the process can be automated. There is a text file (MFC42.DEF) with the MFC
libraries that contains the ordinals and the mangled names. From this file it
is possible to automatically create the spec file, the pointers to functions,
and the initialization of the pointers. The automation would require a name
de-mangler. So far I have found no documentation on MS C++ name mangling.

In short, which of these paths has the most chance of success (most likely to
succeed with the least work) ? Does anyone know the MS name mangling scheme? 

If the second path is most likely, the glue code I write can be put in the wine
tree for others to use. However, each user of wine/winelib would need to provide
their own MFC dll.  The MFC dll is redistributable as long as I am
distributing it as part of an application that provides significant added
functionality. Hence, I can distribute the MFC dll with my application. (I read
this from the license, but I am not a lawyer nor do I play one on TV).

-- 
Wilbur Dale
Lumin Software BV
Zandheuvel 52 B
4901 HW Oosterhout (NB)
The Netherlands

phone: +31-(0)162-47.88.42
fax:   +31-(0)162-43.31.52




Re: Automatic CDECL / STDCALL translation

2000-05-19 Thread Lionel Ulmer

 [snip]
  +print '"\tpopl %ecx\n"' . " \\\n";=0A=
  +print '"\tsubl $" #argsize ", %esp\n"' . " \\\n";=0A=
  +print '"\tjmp *%ecx\n"' . " \\\n";=0A=
 
 This appears to be broken;  you need to *add* the argsize instead
 of subtracting it, and furthermore the return address lies now
 *above* the arguments after the stack permutation you did above ;-)
 
 What about this instead of the last three lines:
 
   print "\taddl $" #argsize ", %esp\n";
   print "\tret\n";

I did that and it does not solve the problem : it crashes at the same
GL call (glGetString) but this time at address 0x and not
0x1F00 as before.

How can I help debugging this further (except by looking at an x86 ASM
book :-) ) ?

-- 
   Lionel Ulmer   -   [EMAIL PROTECTED]
My Advogato Wine diary : http://www.advogato.org/person/bbrox/




Re: Wine 1.0, the sequel

2000-05-19 Thread Alexandre Julliard

Patrik Stridvall [EMAIL PROTECTED] writes:

 Well there are two cases here
 (1) The application really behaves this way and this
works on Windows.
 (2) A previous API that failed cause directly or
 indirectly a NULL value being passed.
 
 The (1) case should obviously be fixed, case (2) is
 more problematic of course. But the problem is that
 one application might work if a function doesn't crash
 and another might be harder to debug because it didn't
 crash.
 
 So it is an issue between teoretical correctness
 vs practical easy of debugging. Since the debugging
 problem can be solved by other means, it doesn't weight
 very much compared to correctness IMHO.

I disagree. We should try to catch problems as soon as possible, not
hide them and hope the app will stumble along for a little while
longer. Unfortunately Win 95 uses the latter approach so there are
cases where we have to ignore bad inputs; but we shouldn't do it
unless there is a real app that depends on it. Feeding garbage to all
the APIs and fixing them to ignore it is counterproductive at this
point IMO.

-- 
Alexandre Julliard
[EMAIL PROTECTED]




tiny Patch for reading CachedMetrics

2000-05-19 Thread michael cardenas

Just adds a useful error message when we have to rebuild the cached
metrics. It attempts to print out the name of teh last successfully read
font. 


--- /devel/corelwineVirgin/corelwine/graphics/x11drv/xfont.cMon May 15
10:48:04 2000
+++ xfont.c Tue May 16 16:43:23 2000
@@ -2458,6 +2458,8 @@
  */
 static BOOL XFONT_ReadCachedMetrics( int fd, int res, unsigned
x_checksum, int x_count )
 {
+fontInfo*   previous = NULL;
+
 if( fd = 0 )
 {
unsigned u;
@@ -2489,6 +2491,7 @@
read( fd, fontList, i); /* read all metrics at once */
while( offset  length )
{
+   previous = pfi;
offset += sizeof(fontResource) + sizeof(fontInfo);
pfr-fi = pfi = (fontInfo*)(pfr + 1);
j = 1;
@@ -2545,8 +2548,14 @@
}
}
 fail:
+   printf("Reading font metrics failed. Rebuilding.\n");
+   printf("This usually means a bad font was found.\n");
+   
+   if(previous != NULL)
+ printf("Last font successfully read: %s\n", previous-df.dfFace);
+
if( fontList ) HeapFree( SystemHeap, 0, fontList );
-   fontList = NULL;
+   fontList = NULL;
close( fd );
 }
 return FALSE;




RE: Wine 1.0, the sequel

2000-05-19 Thread Patrik Stridvall

  So it is an issue between teoretical correctness
  vs practical easy of debugging. Since the debugging
  problem can be solved by other means, it doesn't weight
  very much compared to correctness IMHO.
 
 I disagree. We should try to catch problems as soon as possible, not
 hide them and hope the app will stumble along for a little while
 longer. Unfortunately Win 95 uses the latter approach so there are
 cases where we have to ignore bad inputs;

Note that there are three primary kind of bad inputs.
(1) Random values because of unitialized values
(2) NULL values because something earlier failed.
(3) NULL values because the developer didn't check
for it because he knew Windows would do it.

Note that (2) might be delibarate that something
earlier failed doesn't nessessarily imply the
Wine is buggy. 

There might be application that do
BOOL Example(ARG1 arg1, ARG2 arg2) {
HANDLE handle = Foo(arg1, arg2);
return Bar(handle);
}
If Foo fails Bar will fail to and thus Example will fail...
This is not the fault of Wine. For and as the result Example
will fail on Windows to because of the value of the arguments.

 but we shouldn't do it unless there is a real app that depends on it.

The point is that you don't know if a real application depends on it
until you run it. When we release Wine 1.0 we will hopeful get a few
more companies that will consider running Wine. They try their
application under Wine (Wine, not WineLib) it crashes. They
don't know how to fix the problem and they don't bother sending
us a bug report. We have just lost a potential user of Wine.

That is why I wish to make every function behave like Windows
for NULL values.

 Feeding garbage to all
 the APIs and fixing them to ignore it is counterproductive at this
 point IMO.

NULL values are not garbage IHMO, there are legitime uses for depending
on NULL values returning failure because 
1. Checking for NULL is a waste of time since the API already does it.
2. An explict check "pollutes" the code and is potentially less readable.

I can understand you concern but not fixing broken functions is not
the way to debug Wine IMHO.

Note that said that the debugging problem can be solved by other means.
We could for example do.

BOOL Foo(ARG1 arg1, ARG2 arg2)
{
if(!arg1) FAIL(FALSE);
/* ... */   
}

Where FAIL is like

#ifdef SOMETHING
#define FAIL(value) do { DebugBreak(); return (value); } while(0);
#elif defined(SOMETHING_ELSE) 
#define FAIL(value) do { if(OPTION_fail) DebugBreak(); return (value); }
while(0);
#else
#define FAIL(value) do { return (value); } while(0);
#endif

Then we could both have the cake and eat it. :-)




Re: Wine 1.0, the sequel

2000-05-19 Thread Alexandre Julliard

Patrik Stridvall [EMAIL PROTECTED] writes:

 NULL values are not garbage IHMO, there are legitime uses for depending
 on NULL values returning failure because 
 1. Checking for NULL is a waste of time since the API already does it.
 2. An explict check "pollutes" the code and is potentially less readable.

This is unfortunately the attitude that Microsoft is promoting in
Win95; but it is _wrong_. If a function doesn't expect a NULL pointer
and gets one, this is an application bug; by hiding them Microsoft
only makes debugging applications harder.

In our case it can either be an app bug or a Wine bug, and we can't
know until we have looked into it. If it turns out to be an app bug,
_then_ we have to add a NULL check; but the last thing we want to do
is to add preventive checks everywhere, since this will hide Wine bugs
too.

So yes, we may want to have more checks in 1.0; but we must not start
adding them before the rest of the code has been debugged properly.

-- 
Alexandre Julliard
[EMAIL PROTECTED]




Re: Wine 1.0, the sequel

2000-05-19 Thread Andreas Mohr

On Fri, May 19, 2000 at 03:55:33PM -0700, Alexandre Julliard wrote:
 So yes, we may want to have more checks in 1.0; but we must not start
 adding them before the rest of the code has been debugged properly.
 
 -- 
 Alexandre Julliard
 [EMAIL PROTECTED]
This is exactly my opinion expressed in a very nice little sentence ! :)

Andreas Mohr




RE: Wine 1.0, the sequel

2000-05-19 Thread Patrik Stridvall

 Patrik Stridvall psÉleissner.se writes:
 
  NULL values are not garbage IHMO, there are legitime uses 
 for depending
  on NULL values returning failure because 
  1. Checking for NULL is a waste of time since the API 
 already does it.
  2. An explict check "pollutes" the code and is potentially 
 less readable.
 
 This is unfortunately the attitude that Microsoft is promoting in
 Win95; but it is _wrong_. If a function doesn't expect a NULL pointer
 and gets one, this is an application bug; by hiding them Microsoft
 only makes debugging applications harder.

Note that checking explictly for NULL or checking the return value
are complete identicals operation from a purely semantical point of view

What difference it their between:
if(arg1==NULL || arg2==NULL || !Foo(arg1, arg2)) {
/* Handle error */
}
or
if(!Foo(arg1, arg2)) {
/* Handle error */
}

So you are probably want it to crash (throw an "SEH") instead.
Great now we need to do 

__try {
bResult = Foo(arg1, arg2);
} __except(/* something */) {
bResult = FALSE;
}
if(!bResult) {
/* Handle error */  
}
 
Don't you think.
if(!Foo(arg1, arg2)) {
/* Handle error */
}
is much nicer.

Because you are not really suggested that we let the application crash?
Sure it helps for the programmer that has a debugger,
but the user that run the application won't be very happy
when he loses his not recently saved document.

Throwing exception is a double edged sword, it is very powerful
but if you don't catch it in _every_ function you are almost
guaranteed that the internal state of the application will be badly
damaged. Functions returning FALSE is increases the chance of
recovery quite a lot even for carelessly programmed applications.

In short crashes/exceptions might be useful for programmers,
for fixing "can't happend" cases but for the user of the
application it is worse than useless.

Exceptions look very nice on paper but in real life,
it is preferably to avoid them unless in special cases.

 In our case it can either be an app bug or a Wine bug, and we can't
 know until we have looked into it. If it turns out to be an app bug,
 _then_ we have to add a NULL check; but the last thing we want to do
 is to add preventive checks everywhere, since this will hide Wine bugs
 too.

Personally I think we are much better off using some about mechism for
cathing Wine bugs. We could use my previous suggested FAIL macro,
we could use MFC style ASSERT, we could use some other mechanism.
Suggestions?
 
 So yes, we may want to have more checks in 1.0; but we must not start
 adding them before the rest of the code has been debugged properly.

I repeat, we can use other mechanism for catching bugs, using incorrectly
implemented functions is not the way to go IMO.




RE: Automatic CDECL / STDCALL translation

2000-05-19 Thread Patrik Stridvall

  What about this instead of the last three lines:
  
print "\taddl $" #argsize ", %esp\n";
print "\tret\n";
 
 I did that and it does not solve the problem : it crashes at the same
 GL call (glGetString) but this time at address 0x and not
 0x1F00 as before.
 
 How can I help debugging this further (except by looking at an x86 ASM
 book :-) ) ?

Hmm. I have finally managed to test it and it work fine for me.
In addition to a simple example application, I ran through _every_
OpenGL API with NULL values using winapi_test.

You do compile with -fPIC don't you?

Anyway here is my latest version.

Index: wine/dlls/opengl32/make_opengl_norm
===
RCS file: /home/wine/wine/dlls/opengl32/make_opengl_norm,v
retrieving revision 1.2
diff -u -u -r1.2 make_opengl_norm
--- wine/dlls/opengl32/make_opengl_norm 2000/05/18 00:07:53 1.2
+++ wine/dlls/opengl32/make_opengl_norm 2000/05/20 00:09:05
@@ -1,5 +1,9 @@
 #!/usr/bin/perl -w
 
+my $i386 = 1;
+my $critical_section = 1;
+my $pic = 1;
+
 print "
 /* Auto-generated file... Do not edit ! */
 
@@ -9,10 +13,56 @@
 
 ";
 
+print '#define THUNK_STDCALL_TO_CDECL(stdcall_name, cdecl_name, argsize)' .
" \\\n";
+print '  asm("\t.globl\t" #stdcall_name "\n"' . " \\\n";
+print '"\t.type\t" #stdcall_name ", @function\n"' . " \\\n";
+print '#stdcall_name ":\n"' . " \\\n";
+print '"\tmovl (%esp), %eax\n"' . " \\\n";
+print '"\tleal " #argsize "(%esp), %edx\n"' . " \\\n";
+print '"." #stdcall_name ":\n"' . " \\\n";
+print '"\tmovl (%edx), %ecx\n"' . " \\\n";
+print '"\tmovl %eax, (%edx)\n"' . " \\\n";
+print '"\tmovl %ecx, %eax\n"' . " \\\n";
+print '"\tsubl $4, %edx\n"' . " \\\n";
+print '"\tleal (%esp), %ecx\n"' . " \\\n";
+print '"\tcmpl %ecx, %edx\n"' . " \\\n";
+print '"\tjge ." #stdcall_name "\n"' . " \\\n";
+if($critical_section) {
+if($pic) {
+   print '"\tcall ." #stdcall_name ".getgot.enter\n"' . " \\\n";
+   print '"." #stdcall_name ".getgot.enter:\n"' . " \\\n";
+   print '"\tpopl %ebx\n"' . " \\\n";
+   print '"\taddl $_GLOBAL_OFFSET_TABLE_+[.-." #stdcall_name
".getgot.enter], %ebx\n"' . " \\\n";
+   print '"\tpushl X11DRV_CritSection@GOT(%ebx)\n"' . " \\\n";
+   print '"\tcall EnterCriticalSection@PLT\n"' . " \\\n";
+} else {
+   print '"\tpushl $X11DRV_CritSection\n"' . " \\\n";
+   print '"\tcall EnterCriticalSection\n"' . " \\\n";
+}
+}
+print '"\tcall " #cdecl_name "@PLT\n"' . " \\\n";
+if($critical_section) {
+if($pic) {
+   print '"\tcall ." #stdcall_name ".getgot.leave\n"' . " \\\n";
+   print '"." #stdcall_name ".getgot.leave:\n"' . " \\\n";
+   print '"\tpopl %ebx\n"' . " \\\n";
+   print '"\taddl $_GLOBAL_OFFSET_TABLE_+[.-." #stdcall_name
".getgot.leave], %ebx\n"' . " \\\n";
+   print '"\tpushl X11DRV_CritSection@GOT(%ebx)\n"' . " \\\n";
+   print '"\tcall LeaveCriticalSection@PLT\n"' . " \\\n";
+} else {
+   print '"\tpushl $X11DRV_CritSection\n"' . " \\\n";
+   print '"\tcall LeaveCriticalSection\n"' . " \\\n";
+}
+}
+print '"\taddl $" #argsize ", %esp\n"' . " \\\n";
+print '"\tret\n"' . " \\\n";
+print '"\t.size\t" #stdcall_name  ", .-" #stdcall_name "\n"' . " \\\n";
+print '  );' . "\n";
+
 #
 # Now, the functions from the include file
 #
-open(INC, "/usr/X11R6/include/GL/gl.h") || die "Could not open GL/gl.h";
+open(INC, "/usr/include/GL/gl.h") || die "Could not open GL/gl.h";
 while ($line = INC) {
 if ($line =~ /GLAPI.*GLAPIENTRY/) {
# Start of a function declaration
@@ -22,9 +72,11 @@
if (($name !~ /(MESA|PGI|ARB|EXT)/) ||
($name =~ /MultiTexCoord/) ||
($name =~ /ActiveTextureARB/)) {
+
print
"/***\n"
;
print " *\t\t$name\n";
print " */\n";
+   print "\n/* " if $i386;
print "$ret WINAPI wine_$name(";
@rargs = ();
@names = ();
@@ -61,32 +113,41 @@
foreach (@rargs) {
print ", $_";
}
-   print ") {\n";
-   if ($ret !~ /void/) {
-   print "  $ret ret;\n";
-   }
-   print "  ENTER_GL();\n";
-   if ($ret !~ /void/) {
-   print "  ret = ";
+   if($i386) {
+   print ") */\n";
} else {
-   print "  ";
+   print ") {\n";
}
-   print "$name(";
-
-   $farg = shift @names;
-   if ($farg) {
-   print "$farg";
 
-   foreach (@names) {
-   print ", $_";
+   if(!$i386) {
+   if ($ret !~ /void/) {
+   print "  $ret ret;\n";
}
+   print "  ENTER_GL();\n";
+   if ($ret !~ /void/) {

Re: MFC questions

2000-05-19 Thread Jeremy White

"Wilbur N. Dale" wrote:
[snip]
 1. Compile MFC.  Several years ago we (Lumin Software) tried to compile MFC.
 The attempt failed and we found another way to do what we wanted. MS
 documentation states that compiling MFC was deliberately made difficult.
 Considering my experience with stuff they call "easy" I am not looking forward
 to compiling MFC. We are currently using Visual Studio 5 for windows
 development.

Wilbur, I personally think that this is the 'right' approach, although
approach #2 may prove faster.  

Despite your previous experience, and despite my earlier incorrect
statements,
I think that this is simpler than you fear.  It's one of those tasks
that's
darkest before the storm - you spend all of your energy getting all the
include files to work.  Once you have *one* object file, the rest go
much more quickly (alright, getting it to link is also a hairball of a
job,
but it's tractable g).

If you're not in a hurry, getting MFC to compile, and having a
documented
procedure for compiling it is on our agenda for the relatively near
future (see the Wine 1.0 task list).  

Jer

p.s.  Stick with Visi C++ 5.  IMHO its MFC license is cleaner than that
of VC 6.