RE: Wine 1.0, the sequel
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
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
[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
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
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
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
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
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
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
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
"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.