Hello,
I've been following the wine-devel lists for some time now, but I never found time to actually work on something... until now. I am trying to get civilization 2 to work (with some succes). I chose that game for some reasons (I like the game and the error looks easy, a bit like the tutorials).
I made the following trace:
0013:Call user32.GetWindowLongA(00170034,0000000a) ret=005d2a16 0013:Ret user32.GetWindowLongA() retval=00000000 ret=005d2a16 0013:Call user32.GetClassLongA(00170034,ffffffee) ret=005d2a25 0013:Ret user32.GetClassLongA() retval=0000000c ret=005d2a25 0013:Call user32.GetWindowLongA(00170034,00000004) ret=005d2a39 0013:Ret user32.GetWindowLongA() retval=778bfd70 ret=005d2a39 0013:trace:seh:__regs_RtlRaiseException code=c0000005 flags=0 addr=0x40f81f 0013:trace:seh:__regs_RtlRaiseException info[0]=00000000 0013:trace:seh:__regs_RtlRaiseException info[1]=00000008 0013:trace:seh:__regs_RtlRaiseException eax=00000000 ebx=7793cd94 ecx=00000000 edx=7794dfe4 esi=00170034 edi=000c0054
It shows a call to GetWindowLongA with nIndex = 10, which is not valid, and so it returns NULL. After this the program generates a STATUS_ACCESS_VIOLATION, and hangs.
After searching trough win.c I found the following comment:
/* * Some programs try to access last element from 16 bit * code using illegal offset value. Hopefully this is * what those programs really expect. */
changing the if statement that follows according to the following patch made civilization 2 work, although the performance is really bad. I tried making a test for this, to check if this behaviour is the same on windows, but I'm unable to make a test that will run. I don't know h ow to make the cbWndExtra and wExtra fields in the WND struct into something usefull, so it will not segfault. Mayby it is possible to leave them empty, but I don't know how, if I leave them empty every test with nIndex > 0 failes.
I hope this is somewhat usefull.
Krist
Index: dlls/user/win.c =================================================================== RCS file: /home/wine/wine/dlls/user/win.c,v retrieving revision 1.6 diff -u -p -r1.6 win.c --- dlls/user/win.c 7 Jun 2005 20:11:17 -0000 1.6 +++ dlls/user/win.c 13 Jun 2005 19:08:25 -0000 @@ -1863,8 +1863,7 @@ static LONG_PTR WIN_GetWindowLong( HWND * code using illegal offset value. Hopefully this is * what those programs really expect. */ - if (type == WIN_PROC_16 && - wndPtr->cbWndExtra >= 4 && + if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD)) { INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
One day further, one day wiser...
I learnt how to write tests... Windows XP works exaclty like the original (wine) code, setting last error = ERROR_INVALID_INDEX. Windows 98 however sets it = ERROR_INVALID_PARAMETER (1). So, the "fix" that made civilization work for me is not the right one...
I'll look further into it, it is a learning example for me. It works in windows XP, so as long as it doesn't explicitly test for civ2, it should be possible to get it to work. Mayby I'll have tot test with a native user32.dll, and see some relay/snoop log.
Krist
(1) does this imply that if we're emulating win95/98/Me behaviour, we have to set the last error = ERROR_INVALID_PARAMETER, otherwise to ERROR_INVALID_INDEX?
Kristiaan Lenaerts wrote:
One day further, one day wiser...
I learnt how to write tests... Windows XP works exaclty like the original (wine) code, setting last error = ERROR_INVALID_INDEX. Windows 98 however sets it = ERROR_INVALID_PARAMETER (1). So, the "fix" that made civilization work for me is not the right one...
I'll look further into it, it is a learning example for me. It works in windows XP, so as long as it doesn't explicitly test for civ2, it should be possible to get it to work. Mayby I'll have tot test with a native user32.dll, and see some relay/snoop log.
Wine can not use a couple of native dlls and user32 is one of those. For the other ones see the documentation on http://www.winehq.org/
bye michael