
How to run Truckers 2 under Wine, patch ddraw.c
I am an ardent fan of the game "Truckers-2", but unfortunately, I could not run them under Linux. I tried to make the game work for several years (this does not mean that I sat all day over it) with varying success. I tried different versions of wine, picked the settings, but the game did not give in. Once I had some free time, and I decided to find out why Truckers do not run under Wine, although they worked perfectly under Cedega. Next I will tell you how I did it.
First, I took the path of least resistance: try to tune the game itself. I partially succeeded. To start, you need to edit the TRUCK.INI file, namely the DRV section , and write the correct settings for the video adapter in it. I once managed to find the TRUCK.INI file with the correct settings and the game started, but when I sat down to write this article, I could not reproduce the launch of the game with the “correct” TRUCK.INI on unpatched wine. We consider this method unreliable.
I tried several versions that I had on hand (including the most recent of git). On none of them did the game run on “clean settings”. Therefore, it was decided to take the sources of the latest stable version. At the time of this writing, it was version wine-1.2.3 . Further, all the experiments I conducted on this particular version of wine.
When I start the game on “pure” wine, it shows me the starting splash-screen, after which it opens a window several times and turns off without any message. After such a launch, I looked into the game folder and saw a warn.log file with the following contents: This log gave me the first hint: we have the DirectDraw subsystem incorrectly initialized. I had no business with directdraw before, so this record helped me a little, but it was the first clue. Google on request "directdraw SetCoop" gave me information about the SetCooperativeLevel function. I did not go deep into the description of this function, instead I decided to go the other way (but I will return to this function).
I went to the office. site wine and started looking for information on how to get wine to give me a message about all the errors that occur when the application starts. All information is located at www.winehq.org/developer-cheatsheet . I want to say that the logging capabilities of wine are very rich, and allow you to get a variety of information about the program being launched (you can even trace the chain of calls of all WinAPI functions with all input and output parameters).
So, start the wine and remove logs:
First, I ran without parameters:
So, back to our task. After exploring the possibilities of logging, I started to run the game with different logging parameters, settled on the above.
After starting, I got a 40 megabyte log. It is clear that manually it is impossible to find something in it. At first I filtered it according to the ERR class , but did not find anything interesting there. Then I decided to return to the message from warn.log, and filtered it by SetCoop : Here are more interesting data. We see that incompatible parameters were passed to the SetCooperativeLevel function, this is already something. If you look at the previous lines in the log, then we will see all the parameters that are passed to the function: A description of all the parameters can be found on MSDN
Next, I went on to analyze the source code and documentation for the SetCooperativeLevel function.
Finding the right function in wine is easy, it is located in% SRC_ROOT% / dlls / ddraw / ddraw.c. The function is called IDirectDrawImpl_SetCooperativeLevel .
Open MSDN and find a description of the SetCooperativeLevel function and see: That is, this means that these flags cannot be together. It should be noted that the implementation of wine is fully consistent with the documentation and gives an error code DDERR_INVALIDPARAMS in this case. I decided for the test to try to remove the check for a specific combination of flags:
We compile and install wine, launch Truckers and ...
The familiar game menu is loading, victory! We are trying to create a game, the game is being created and I can ride my favorite Zil truck!
Having rolled enough on a virtual map, I decided that the game is working quite stably and that means it's time to fill out our results in the form of a patch and create an application in the wine bug tracker.
In order to fully understand this function, I decided to write a test program for win32 that would give an error code depending on the combination of flags DDSCL_ * and I saw that on the specific combination of flags (which are used by Truckers) the SetCooperativeLevel function returns DD_OK, then there is success. It is also worth noting that this function returns DD_OK much more often than described in MSDN . It is possible that the developers of the game did not take into account the difference in the description and implementation of this function and used flags that are prohibited in the documentation.
I created a request, attached a log and a patch to it.
In fact, the patch is very simple, I just commented out the check for prohibited flags (as in the example above), but this function is used in many applications, so you need to conduct a more detailed analysis. To do this, I attached a program for win32 to the application, which iterates over all possible combinations of flags and gives the corresponding error codes.
PS I checked everything works fine on wine-1.4.
In this version, SetCooperativeLevel has been substantially redesigned, and now the behavior of this function is close to real implementation in win32. I closed the corresponding application in wine. Thank you all for your comments.
Attempt No. 0. We twist a config
First, I took the path of least resistance: try to tune the game itself. I partially succeeded. To start, you need to edit the TRUCK.INI file, namely the DRV section , and write the correct settings for the video adapter in it. I once managed to find the TRUCK.INI file with the correct settings and the game started, but when I sat down to write this article, I could not reproduce the launch of the game with the “correct” TRUCK.INI on unpatched wine. We consider this method unreliable.
Attempt No. 1. We select the wine version
I tried several versions that I had on hand (including the most recent of git). On none of them did the game run on “clean settings”. Therefore, it was decided to take the sources of the latest stable version. At the time of this writing, it was version wine-1.2.3 . Further, all the experiments I conducted on this particular version of wine.
Game Log Analysis
When I start the game on “pure” wine, it shows me the starting splash-screen, after which it opens a window several times and turns off without any message. After such a launch, I looked into the game folder and saw a warn.log file with the following contents: This log gave me the first hint: we have the DirectDraw subsystem incorrectly initialized. I had no business with directdraw before, so this record helped me a little, but it was the first clue. Google on request "directdraw SetCoop" gave me information about the SetCooperativeLevel function. I did not go deep into the description of this function, instead I decided to go the other way (but I will return to this function).
warning : fail in SetCoop... One or more of the parameters passed to the method are incorrect. (unknown) 0
warning : DirectDraw4/7 not found 0
warning :
(09-03-12 11:09)
Внутренняя ошибка, пожалуйста свяжитесь с отделом сопровождения
(fail in SetCoop... One or more of the parameters passed to the method are incorrect. (unknown)(null))
0
We delve into the theory. Logging features in wine
I went to the office. site wine and started looking for information on how to get wine to give me a message about all the errors that occur when the application starts. All information is located at www.winehq.org/developer-cheatsheet . I want to say that the logging capabilities of wine are very rich, and allow you to get a variety of information about the program being launched (you can even trace the chain of calls of all WinAPI functions with all input and output parameters).
So, start the wine and remove logs:
First, I ran without parameters:
wine king > wine.dbg 2>&1
. I got the output.
There is nothing interesting here.fixme:win:EnumDisplayDevicesW ((null),0,0x32f110,0x00000000), stub!
fixme:win:EnumDisplayDevicesW ((null),0,0x32f424,0x00000000), stub!
A small digression: a description of the logging subsystem in wine
- In wine there are several classes (although I am more familiar with the word level) of logging - these are FIXME, ERR, WARN, TRACE, MESSAGE. They are responsible for the importance of the message and its type.
- Wine also has debugging channels, they are responsible for a particular subsystem inside wine. For example, reg is responsible for the registry subsystem, etc.
- Logging is controlled using the WINEDEBUG environment variable. For example, I ran with the following arguments: WINEDEBUG = warn + all, trace + all
So, back to our task. After exploring the possibilities of logging, I started to run the game with different logging parameters, settled on the above.
After starting, I got a 40 megabyte log. It is clear that manually it is impossible to find something in it. At first I filtered it according to the ERR class , but did not find anything interesting there. Then I decided to return to the message from warn.log, and filtered it by SetCoop : Here are more interesting data. We see that incompatible parameters were passed to the SetCooperativeLevel function, this is already something. If you look at the previous lines in the log, then we will see all the parameters that are passed to the function: A description of all the parameters can be found on MSDN
cat wine.dbg | grep SetCoop
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x15ae78)->(0x40066,0000105b)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x15ae78) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x15ae78)->(0x40066,00000008)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel SetCooperativeLevel retuning DD_OK
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x15ae78)->(0x40066,00000008)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel SetCooperativeLevel retuning DD_OK
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x15ae78)->((nil),00000008)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel SetCooperativeLevel retuning DD_OK
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x160420)->(0x40066,0000105b)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x160420) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x160420)->(0x40066,00000008)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel SetCooperativeLevel retuning DD_OK
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel (0x160420)->((nil),00000008)
0009:trace:ddraw:IDirectDrawImpl_SetCooperativeLevel SetCooperativeLevel retuning DD_OK
0009:trace:ddraw:DDRAW_dump_cooperativelevel - DDSCL_FULLSCREEN DDSCL_ALLOWREBOOT DDSCL_NORMAL DDSCL_ALLOWMODEX DDSCL_EXCLUSIVE
Source code analysis
Next, I went on to analyze the source code and documentation for the SetCooperativeLevel function.
Finding the right function in wine is easy, it is located in% SRC_ROOT% / dlls / ddraw / ddraw.c. The function is called IDirectDrawImpl_SetCooperativeLevel .
Open MSDN and find a description of the SetCooperativeLevel function and see: That is, this means that these flags cannot be together. It should be noted that the implementation of wine is fully consistent with the documentation and gives an error code DDERR_INVALIDPARAMS in this case. I decided for the test to try to remove the check for a specific combination of flags:
DDSCL_NORMAL
The application functions as a typical Windows application. This flag cannot be used with the DDSCL_ALLOWMODEX, DDSCL_EXCLUSIVE, or DDSCL_FULLSCREEN flags
/* DDSCL_NORMAL or DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE */
if(cooplevel & DDSCL_NORMAL)
{
/* Can't coexist with fullscreen or exclusive */
/** @note commented for test only
if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
{
TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
LeaveCriticalSection(&ddraw_cs);
return DDERR_INVALIDPARAMS;
}
*/
We compile and install wine, launch Truckers and ...
The familiar game menu is loading, victory! We are trying to create a game, the game is being created and I can ride my favorite Zil truck!
Research improvements
Having rolled enough on a virtual map, I decided that the game is working quite stably and that means it's time to fill out our results in the form of a patch and create an application in the wine bug tracker.
In order to fully understand this function, I decided to write a test program for win32 that would give an error code depending on the combination of flags DDSCL_ * and I saw that on the specific combination of flags (which are used by Truckers) the SetCooperativeLevel function returns DD_OK, then there is success. It is also worth noting that this function returns DD_OK much more often than described in MSDN . It is possible that the developers of the game did not take into account the difference in the description and implementation of this function and used flags that are prohibited in the documentation.
I created a request, attached a log and a patch to it.
In fact, the patch is very simple, I just commented out the check for prohibited flags (as in the example above), but this function is used in many applications, so you need to conduct a more detailed analysis. To do this, I attached a program for win32 to the application, which iterates over all possible combinations of flags and gives the corresponding error codes.
PS I checked everything works fine on wine-1.4.
In this version, SetCooperativeLevel has been substantially redesigned, and now the behavior of this function is close to real implementation in win32. I closed the corresponding application in wine. Thank you all for your comments.