Let's dedicate this thread to the games and applications that fail to initialize graphics because of that awful practice of doing it in DllMain. If you know such an application/game, you can post about it here and I can try to patch it, but no guarantees. There probably aren't many of them out there. So far, the following has been patched:
Right now, I'm fiddling with Soulbringer (GOG version) and having little trouble, I set the breakpoint on DLL entry point and it isn't hit, I set it on DDraw.dll exports any they aren't hit...it does throw out a message box complaining that it can't enumerate display devices and pauses there. I also see a bunch of these scrolling through the stack, so hopefully it gets me somewhere:
DXGI ERROR: CreateDXGIFactory cannot be called from DllMain. [ MISCELLANEOUS ERROR #76: ]
Speaking of GOG, would be nice if they patched all games they sell thoroughly. From Soulbringer page: ATI/AMD notice: ATI/AMD cards are not supported for this title.
Last edited by UCyborg on 2017-01-23, 22:48. Edited 3 times in total.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
DXGI ERROR: CreateDXGIFactory cannot be called from DllMain. [ MISCELLANEOUS ERROR #76: ]
If nothing else, you can install Windows SDK and enable the DX11 Debug layer along with debug-breaks on error messages.
So, when you launch the game from the debugger then it breaks when DXGI dumps the error message. From then, you can unwind the callstack to see where it came from.
Back then when Soul Bringer was reported, I tried to quickly patch it but as far as I remember, it wasn't easy because the renderer dll of the game has an internal c-style interface with various functions, and when I tried to call the same DDraw init from the renderer dll Init () then it turned out
that some information (data?) was needed from the result of DllMain. In other words, there was a dependency between DllMain and Init which was not easy to resolve (I emphasize, if I remember right, it was long ago 😀 ), so I gave up and continued on dgVoodoo.
UCyborg wrote:
Speaking of GOG, would be nice if they patched all games they sell thoroughly. From Soulbringer page: ATI/AMD notice: ATI/AMD cards are not supported for this title.
😀
It's nice...
spiroyster wrote:
Why is this an awful practice?
What are you debugging and how are you doing it?
When DllMain is being called by the OS loader (or from LoadLibrary) then the process is in kind of a "critical section" (an internal lock count is incremented) which can easily cause deadlock if any of the WinAPI funtions is called. It's not an obscure thing, documented even in MSDN.
In fact, DllEntryPoint is useful only (designed) for running the dll's global constructors (which also shouldn't do anything, only initializing needed things with constants, like zeroing memory or sg like that) and storing the module handle for later usage.
GOG version patches, which take care of aspect ratio and cinematic issues, don't work when we put dgVoodoo in game folder, but dgVoodoo can take care of aspect ratio (select 4:3 resolution in game, set Scaling mode in dgVoodoo to Stretched, keep Aspect Ratio). They also don't work with DX7 modes (stretched image). EAX enabled executable also doesn't work, just crashes, seems like they haven't patched it like the non-EAX one. I do have working Creative ALchemy installation, including EAX Unified, which other games are able to use just fine for querying EAX capabilities. Parts of the game also stutter a little.
So I went on and patched the retail version files, put dgVoodoo in the folder and things look mostly fine at first glance. 256-color software mode works as well as DX6, which allows 32-bit color mode (though game textures are only 16-bit I think). DX7 modes result in black screen, music plays, the game runs, just nothing is shown. Seems to run smoothly. EAX .exe works as good as the other one.
The game really doesn't like AMD cards out-of-the-box, there is another issue in addition to DllMain. Impossible to even reach main menu as long as it's running via native Direct3D, no matter what. Get dgVoodoo in its place and it works!
One oddity that remains when ran through dgVoodoo is the intro cinematic, it runs in a small borderless window on the top-left and the taskbar flickers like crazy when said window appears when scaling mode is set to Unspecified. If dgVoodoo is allowed to control fullscreen/windowed state, borders appears around it and there is no taskbar flickering. If I set Stretched, keep Aspect ratio, it appears fullscreen, but there is just blackness (just like with native DirectX). GOG version has a patch for that that only works with native DirectX. Similar problem exists with a brief screen with game logo that displays after the intro cinematic, it appears in a small borderless window in the top-left corner.
Launcher can be buggy, probably the best to use it to set resolution then launch the game via one of the other executables. Can run via native DirectX 6 or 7 with some fiddling on NVIDIA graphics card, best not to try though.
TL;DR This was all over the place. It's a buggy game out-of-the box, less buggy when you get it running via dgVoodoo. You can download patched binaries and try it out with dgVoodoo if you'd like.
The attachment Soulbringer.png is no longer available
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
About that issue I had, it was just OllyDbg being quirky, sometimes it doesn't pick up on a loaded library unless you pause the execution.
As for how I do it, in a nutshell, I use OllyDbg to put 2 codecaves in 2 places. OllyDbg is assembly-level analysing debugger, so all the code is written in x86 ASM.
One place is inside the function that acts as a DLL entry point (DllMain), the branch that gets executed when DLL in question is being loaded. From there, I jump to a small piece of code I put in the empty space of code section:
1CPU Disasm 2Address Hex dump Command Comments 310061BC0 |> 833D F88F0810 CMP DWORD PTR DS:[10088FF8],1 ; Check the variable that says if we've been called before 410061BC7 |. C705 F88F0810 MOV DWORD PTR DS:[10088FF8],1 ; We're being called, set the variable to 1 510061BD1 |.- 0F85 D33EFFFF JNE 10055AAA ; If variable hasn't been set to 1 yet when we've checked it, bail out 610061BD7 |. A1 F8840810 MOV EAX,DWORD PTR DS:[100884F8] ; If it has, execute original instruction from where we've jumped here 710061BDC \.- E9 613EFFFF JMP 10055A42 ; And continue as usual
This just prevents the code in DllMain from being executed when OS calls it, so we have to do it ourselves. In this example, variable at 10088FF8 is located at the end of DLL .data section, where global variables go. Generally, there is varying amount of unused space left with different binaries. If more space is needed, it's possible to create an extra section.
The next snippet resides in whatever executable module uses LoadLibrary function to load the problematic DLL, we make the code cave (a jump) somewhere after the LoadLibrary call. Then, we start with pushing the function arguments for DllMain in reverse order onto the stack, note that at this point, register EAX holds the address (handle) of the loaded DLL:
1CPU Disasm 2Address Hex dump Command Comments 302128B54 /> 6A 00 PUSH 0 ; lpvReserved = NULL 402128B56 |. 6A 01 PUSH 1 ; fdwReason = DLL_PROCESS_ATTACH 502128B58 |. 50 PUSH EAX ; hinstDLL 602128B59 |. 8B70 3C MOV ESI,DWORD PTR DS:[EAX+3C] ; Get the relative address of IMAGE_OPTIONAL_HEADER 702128B5C |. 8B4C06 28 MOV ECX,DWORD PTR DS:[EAX+ESI+28] ; Get the relative address of DLL entry point from IMAGE_OPTIONAL_HEADER 802128B60 |. 8D3401 LEA ESI,[EAX+ECX] ; Calculate the actual address of DLL entry point (DllMain) 902128B63 |. FFD6 CALL ESI ; Call it 1002128B65 |. 8B53 28 MOV EDX,DWORD PTR DS:[EBX+28] ; Execute whatever we've overwritten by writing a jump to here 1102128B68 |. 8D73 28 LEA ESI,[EBX+28] 1202128B6B \.- E9 6E55FEFF JMP 0210E0DE ; Continue as usual
And that's the whole magic behind my patches. The similar can be done if DLL makes dangerous calls in DllMain when it's being unloaded by calling it right before FreeLibrary.
I also use Relocation Section Editor. Whenever you add an instruction in a DLL that contains the absolute address, the address of the said address must be referenced in the relocation table of the DLL so the OS can adjust those addresses accordingly when the DLL is loaded since DLLs are not loaded at constant/fixed address in memory. Obviously, you must make appropriate changes also when you've changed the instruction that contained the absolute address before if needed, depending on the change.
Generally, when programming your own DLL, you're going to make some of its functions publicly available. While you're at it, might as well write the special initialization function if needed and require consumers of the DLL to call it before they make calls to other functions. Much better than relying on DllMain, which just causes headaches in practice since it wasn't designed for such purposes.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
Many thanks for the clarification on these. Mucho respecto to your low-level skills there 😀.
Didn't realise DllMain was such an issue. Personally I diverged away from using Dll's in this manner as I didn't like this tighter coupling between application and dll, opting instead for the dll to fully understand how it should manage its own contexts. This gives rise to a design in which there are usually 3 main C-style function prototype along the lines of.. 'bool XXXInit()', 'bool XXXKill()' and 'void* XXXInstance()' to get a handle to 'service' provided by the dll (be it singleton, or in a multi-context managed by dll), called by the application after it has a handle (from LoadLibrary()). I'm hoping you'll say this is the 'better' way than using DllMain as an initialisation routine? Not that it makes a difference to how someone else decided to write it. o.0
Forgive my naivety here, So if I'm understanding the process right, it is not possible to create a kinda of complex middleware like a message broker which can hook into the calls from Application, and give better control over the context? This can't solve the Soulbringer problem since you don't know what information is returned (and what is done) by the DllMain routine (which may have to be temporarily persisted somewhere) irrelevant of you bypassing it, and then some weird race condition that means the hooks occur before DllMain is called? If I'm understanding the problem here?
UCyborg, many thanks for that little snippet 😀. I wouldn't mind giving this a go on something, I've 'stack smashed' and 'overflowed' my own programs before, but the never something from somebody else. I find it quite scary having to enter a mass of code of which I have no idea of its flow o.0.
Sorry, one more (series of) question(s)...
So a code cave is different/safer than a smash since flow is simply redirected within a valid frame (rather than jumping to somewhere else in the stack)? And you use OllyDbg to insert the jump/cave thus being able to jump to your own injected code (added by OllDbg in the 'globals' section, or insert another section into the dll)? The patch you do is specifically for the dgVoodoo? or this patch so that it can run at all with later api's?
Why was this once considered safe (enough for the original authors to do stuff in DllMain), but now causing problems?
Didn't realise DllMain was such an issue. Personally I diverged away from using Dll's in this manner as I didn't like this tighter coupling between application and dll, opting instead for the dll to fully understand how it should manage its own contexts. This gives rise to a design in which there are usually 3 main C-style function prototype along the lines of.. 'bool XXXInit()', 'bool XXXKill()' and 'void* XXXInstance()' to get a handle to 'service' provided by the dll (be it singleton, or in a multi-context managed by dll), called by the application after it has a handle (from LoadLibrary()). I'm hoping you'll say this is the 'better' way than using DllMain as an initialisation routine? Not that it makes a difference to how someone else decided to write it. o.0
Yes, this is exactly how you should it. The main point is, you don't put the initialization/cleanup code in DllMain under DLL_PROCESS_ATTACH/DLL_PROCESS_DETACH, but in XXXInit/XXXKill.
spiroyster wrote:
Forgive my naivety here, So if I'm understanding the process right, it is not possible to create a kinda of complex middleware like a message broker which can hook into the calls from Application, and give better control over the context? This can't solve the Soulbringer problem since you don't know what information is returned (and what is done) by the DllMain routine (which may have to be temporarily persisted somewhere) irrelevant of you bypassing it, and then some weird race condition that means the hooks occur before DllMain is called? If I'm understanding the problem here?
If it can be done, it must require some trickery. I know you could intercept calls to LoadLibrary to be able to tamper with a loaded DLL, but the ideal DLL wouldn't do anything in DllMain. But if it does, that DLL will already run some code before you even get its handle from LoadLibrary, at which point it might be too late to do whatever you wanted to do. If it has special initialization routine, you can hook it as soon as you got the handle with the help of GetProcAddress function.
And while you probably could hook calls to Windows APIs the DLL in question makes before you load it, its DllMain will be called when the loader lock is held, so, possible deadlocks. These guys put it well: http://help.autodesk.com/cloudhelp/2017/ENU/M … B6650477CF1.htm
Writing correct DllMain() functions is difficult. MSDN describes a series of restrictions, but these are so often ignored that Microsoft had to relax these restrictions by adding IJW ("It Just Works") technology.
I've read somewhere some time ago that even GetModuleHandle is forbidden, though it's possible to use it without negative consequences.
spiroyster wrote:
UCyborg, many thanks for that little snippet 😀. I wouldn't mind giving this a go on something, I've 'stack smashed' and 'overflowed' my own programs before, but the never something from somebody else. I find it quite scary having to enter a mass of code of which I have no idea of its flow o.0.
Copied from patched Max Payne 1 DLLs, not meant to be directly copy pasted somewhere, just as a demonstration of the concept. You have to piece the rest of the puzzle together yourself. Soulbringer version also has some checks in place that make my magic work only if the specific DLL is loaded, since it uses a common function for library loading, which also loads DLLs not related to rendering.
spiroyster wrote:
So a code cave is different/safer than a smash since flow is simply redirected within a valid frame (rather than jumping to somewhere else in the stack)? And you use OllyDbg to insert the jump/cave thus being able to jump to your own injected code (added by OllDbg in the 'globals' section, or insert another section into the dll)?
Actually, there isn't much involving the stack with these patches. Think of it like this, I'm simply modifying it as it was originally written in assembly. But because I don't have assembly sources, I can't just insert the new line and put some extra code in the middle of the function (sometimes you can if there is enough space, it's a bit cumbersome task though) so I write a jump that jumps down there in the empty part of code section, occupied by zeros, where I put the extra instructions and the jump back to where I've come from.
One thing about DllMain, when you open a DLL in OllyDbg, the code you see right away as the entry point isn't really the one written in DllMain by the programmer, the one programmer wrote is called as one of the subroutines there.
I did manage to write some patches for Drakan: Order of the Flame as part of my AiO Patch that don't jump to the empty section of code, simply because there was enough space to do so. For example, one original function looks like this:
Saved some space because the WSAGetLastError call wasn't actually needed. 😁
Anyway, I think the term injection only applies if you're modifying/inserting the code during runtime. Patches in this thread are simply modified binaries, so nothing new is written when they're being used, just existing code flowing differently due to extra checks.
Back to my Drakan AiO Patch, the simpler fixes (which is actually a majority) are implemented as regular assembly code fixes and they work by just having the patched executables in place, same as patches in this thread, more complicated fixes are implemented in proxy dinput.dll, powered by this code. One of the strangest pieces of code, I use the DetourFunction to insert the jump right in the middle the function (it's usually used to redirect the flow right at the beginning of the function), which makes a jump to the code in my DLL, the relevant lines are 538 and 309-325. It's a wonder that mess of the code works as good as it does! 😁
One thing about working with disassembled code, you have to be careful with register usage. AiO Patch had a bug at one point in time which would mysteriously cause the game server to crash on older Windows versions after player connected. It was because I made a call to one of the API functions, overlooking the details regarding calling conventions and associated register preservation rules. XP version of the API overwrote one of the registers which content was needed by game code after the call. It worked on later versions simply because the API function was optimized better and didn't utilize register in question, but it could if it wanted to. The API in question was ntohl/htonl, which just changes endianness of the integer.
spiroyster wrote:
The patch you do is specifically for the dgVoodoo? or this patch so that it can run at all with later api's?
Nope, it allows the games to run at all out-of-the box. Max Payne is very famous for not starting at all with ATI cards without bizarre workarounds like setting process affinity to one core (which is not needed anymore with this patch), maybe Intel too, but I haven't tried. Nothing is shown on the screen, just the process hangs in the Task Manager. Note that this isn't driver issue at all, although people love to blame everything from drivers to Windows. Soulbringer now also doesn't hang anymore on AMD hardware, although there is a separate compatibility issue preventing it from working with native DirectX, but dgVoodoo helps with that.
spiroyster wrote:
Why was this once considered safe (enough for the original authors to do stuff in DllMain), but now causing problems?
Under certain circumstances, it just works, but it's pure luck. MSDN says DllMain shouldn't be used like that, on the other hand, default project template in Visual Studio 2015 for DLL puts DllMain in code without any warnings, so it may look tempting to use it. Another thing worth mentioning, DllMain is Windows-specific, there is no exact equivalent Linux, closest things are __attribute__((constructor)) and __attribute__((destructor)), but why make life difficult when writing special initialization function is so simple?
I've read somewhere when with this type of problem occured, one thing people with AMD cards also did is placing older atiumdag.dll in the game folder. So, mixing older driver DLLs with newer ones, that's also the recipe for disaster.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
UCyborg wrote:GOG version patches, which take care of aspect ratio and cinematic issues, don't work when we put dgVoodoo in game folder, but d […] Show full quote
GOG version patches, which take care of aspect ratio and cinematic issues, don't work when we put dgVoodoo in game folder, but dgVoodoo can take care of aspect ratio (select 4:3 resolution in game, set Scaling mode in dgVoodoo to Stretched, keep Aspect Ratio). They also don't work with DX7 modes (stretched image). EAX enabled executable also doesn't work, just crashes, seems like they haven't patched it like the non-EAX one. I do have working Creative ALchemy installation, including EAX Unified, which other games are able to use just fine for querying EAX capabilities. Parts of the game also stutter a little.
So I went on and patched the retail version files, put dgVoodoo in the folder and things look mostly fine at first glance. 256-color software mode works as well as DX6, which allows 32-bit color mode (though game textures are only 16-bit I think). DX7 modes result in black screen, music plays, the game runs, just nothing is shown. Seems to run smoothly. EAX .exe works as good as the other one.
The game really doesn't like AMD cards out-of-the-box, there is another issue in addition to DllMain. Impossible to even reach main menu as long as it's running via native Direct3D, no matter what. Get dgVoodoo in its place and it works!
One oddity that remains when ran through dgVoodoo is the intro cinematic, it runs in a small borderless window on the top-left and the taskbar flickers like crazy when said window appears when scaling mode is set to Unspecified. If dgVoodoo is allowed to control fullscreen/windowed state, borders appears around it and there is no taskbar flickering. If I set Stretched, keep Aspect ratio, it appears fullscreen, but there is just blackness (just like with native DirectX). GOG version has a patch for that that only works with native DirectX. Similar problem exists with a brief screen with game logo that displays after the intro cinematic, it appears in a small borderless window in the top-left corner.
Launcher can be buggy, probably the best to use it to set resolution then launch the game via one of the other executables. Can run via native DirectX 6 or 7 with some fiddling on NVIDIA graphics card, best not to try though.
TL;DR This was all over the place. It's a buggy game out-of-the box, less buggy when you get it running via dgVoodoo. You can download patched binaries and try it out with dgVoodoo if you'd like.
Soulbringer.png
Thanks! Cool!! 😎
I've just tried it and indeed, cinematics doesn't work in fullscreen (probably Intel Indeo which is not supported through dgVoodoo, can only be displayed in windowed mode, old issue) and DX7 gives black screen (that one should be fixed).
Thanks! Cool!! 😎
I've just tried it and indeed, cinematics doesn't work in fullscreen (probably Intel Indeo which is not supported through dgVoodoo, can only be displayed in windowed mode, old issue) and DX7 gives black screen (that one should be fixed).
Didn't have much time so far but:
- I was wrong, cinematics are not Intel Indeo. This game gets switched back to windowed mode at movie presentations (must do sg similar like SC1) and the wrapper couldn't handle that unexpected situation, movies fixed
- Rendering through DX7 is also fixed, the game performs its texture uploadig in a valid, but for dgVoodoo an unexpected way, fixed (at least it got revealed)
Updated all patches to handle the case when DllMain returns FALSE when called with DLL_PROCESS_ATTACH, in which scenario the library must be unloaded. For correctness sake.
I've also upgraded the Soulbringer patch to get it working a little better under native DirectX. DX7 renderer doesn't enable VSYNC on its own so it runs too fast which makes the game glitchy. BTW, I noticed that whatever guys at GOG did with their version, their tweaks also influence the game flow itself in subtle ways and introduce stutter. Like in the first cutscene, the ferryman goes around the house to reach the door like he's drunk, then noclips through it, funny. Original version doesn't have that issue.
I'm glad you found the problem with DX7. I wonder though, does Soulbringer's DX7 mode have VSYNC under dgVoodoo without forcing it? Because it seem to get activated only with DX6. It must run at 60 FPS, otherwise it gets glitchy. Interestingly, it runs at correct speed on its own under native DX7 if you leave maximized windowed mode enabled. But contrary to what the ReadMe says, at least under native DX7, it runs slower than DX6.
About Indeo Video, it works with Mafia just fine, though I remember you said one time things don't work when DirectShow is involved. It just takes running regsvr32 ir50_32.dll from SysWOW64/System32 directory. Windows XP compatibility mode might work too. No issues with dgVoodoo in that regard, though parts of the game are still flickery, at least with Water Shader Mod installed, which is actually D3D8 proxy which injects shaders to make water have reflections. The proxy is named d3df.dll so therefore it modifies import table in a game engine binary to point to that. I haven't tried without it yet.
Last edited by UCyborg on 2017-01-27, 23:34. Edited 2 times in total.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
One more thing regarding Soulbringer, in software mode, it crashes or hangs in one of graphics driver DLLs when you use quit menu option to close it.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
I'm glad you found the problem with DX7. I wonder though, does Soulbringer's DX7 mode have VSYNC under dgVoodoo without forcing it? Because it seem to get activated only with DX6. It must run at 60 FPS, otherwise it gets glitchy. Interestingly, it runs at correct speed on its own under native DX7 if you leave maximized windowed mode enabled. But contrary to what the ReadMe says, at least under native DX7, it runs slower than DX6.
No, it runs at ~1200 FPS through DX7, so there is no vsync.
UCyborg wrote:
About Indeo Video, it works with Mafia just fine, though I remember you said one time things don't work when DirectShow is involved. It just takes running regsvr32 ir50_32.dll from SysWOW64/System32 directory. Windows XP compatibility mode might work too.
Well, the problem is not with the codec used for movies but the fact that the movie player renders the movie through DDraw/DX8 or legacy GDI.
GDI is not compatible with DXGI in fullscreen that's why no movies in those cases. Intel Indeo always comes paired with a videoplayer that renders through GDI (ok, maybe I'm wrong, I didn't checked the cases when there were no problems with the playback 😀 ).
On the other hand, DirectShow should be OK because that renders through DirectDraw. The latest WIP contains a fix for Win10 though, DDraw+DX8 scenario didn't always work (some mysterious dll path-thing when DShow loads DDraw).
UCyborg wrote:
No issues with dgVoodoo in that regard, though parts of the game are still flickery, at least with Water Shader Mod installed, which is actually D3D8 proxy which injects shaders to make water have reflections. The proxy is named d3df.dll so therefore it modifies import table in a game engine binary to point to that. I haven't tried without it yet.
One more thing regarding Soulbringer, in software mode, it crashes or hangs in one of graphics driver DLLs when you use quit menu option to close it.
It does for me too, with my nVidia. It gets stuck gratuitously in a swapchain call (WaitForSingleObject in the deepness of the driver). 😕
Works OK with Intel HD.
Well, now you have and can test dgVoodoo with it! 😁 It also alters some data files to work properly. Either way, the game is still rendered flawlessly on Linux under Wine, with the mod or not. No shadow flickering neither. Just runs slower.
Dege wrote:
It does for me too, with my nVidia. It gets stuck gratuitously in a swapchain call (WaitForSingleObject in the deepness of the driver). 😕
Works OK with Intel HD.
Interesting, I got the same result as you with NVIDIA (GeForce GTX 750 Ti - 372.90 drivers) and a crash on AMD (Radeon R2 - 16.11 driver). NVIDIA went downhill with drivers these days generally.
Last edited by UCyborg on 2017-01-25, 01:44. Edited 1 time in total.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
One more thing when you have the time, can you try Soulbringer with forcing VSYNC off through drivers and check whether it runs slower or faster in DX6 mode on your end?
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
I tried the patch you made for 3DMark99 Max, but I am unable to get the application to start on my Windows 7 Ultimate 64bit with GT230M laptop. I just installed the program in admin mode and applied your patch. I did not apply any compatibility settings. When I run the application I get an error that says "3DMark needs Directx 6.1" and it shuts down. I get the same error with and without dgVoodoo.
Are you able to run 3DMark99 Max on your computer? Can you give me some tips to run it?
I tried the patch you made for 3DMark99 Max, but I am unable to get the application to start on my Windows 7 Ultimate 64bit with GT230M laptop. I just installed the program in admin mode and applied your patch. I did not apply any compatibility settings. When I run the application I get an error that says "3DMark needs Directx 6.1" and it shuts down. I get the same error with and without dgVoodoo.
Are you able to run 3DMark99 Max on your computer? Can you give me some tips to run it?
I personally use compatibility database with the following fixes:
DXPrimaryEmulation -DisableMaxWindowedMode
FileVersionInfo
EmulateHeap
The first one is needed on Windows 8+ to get real fullscreen mode under native Direct3D, that is, without dgVoodoo, but there's no harm if it's enabled on Windows 7, the second one makes sure the game doesn't complain about DirectX because it checks version of some DirectX DLL and bails out when it sees it's not the version it excepts, the 3rd one compensates for buggy memory management in the program which makes it randomly crash either during transitions between tests or before showing the final scores when it tries to release block of memory. The crash point is inside ntdll.dll.
I'm attaching updated .sdb file. If you want, you can search for Compatibility Toolkit 5.6, which includes Compatibility Administrator, which is the program for working with these .sdb files and lets you see what's inside and change them. For Windows 8+, there's Windows 8 and Windows 10 ADK respectively, which includes Compatibility Administrator.
The thing about the database from teleguy, it lacks EmulateHeap, which is critical for preventing random crashes and includes bunch of redundant fixes. Applying Windows 98 compatibility mode from .exe file's Properties also gives you a lot of unneeded fixes as well. It's a good practice to use only minimum amount of fixes required by certain application/game.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.
Thanks for the compatibility fix. It worked for me.
UCyborg,
Thanks for the updated/enhanced fix and the detailed explanations. I am using your fix now. When combined with your DLL patch, I was able to run 3DMark99 Max both with and without dgVoodoo. I also downloaded the Compatibility Toolkit and will use it.
There is another advantage of getting familiar with Compatibility Administrator, you can put fixes for many applications in one database. Windows comes with a huge database with fixes for tons of different applications. It's common for people to distribute databases with a fix for a single application, which is understandable, as it's the easy way to get the fixes to end users who are unfamiliar with technical details involved. By having all of the fixes in one database, it's easy to transfer all of them to a different machine.
As a point of interest, Compatibility Administrator 5.6 has 2 annoying bugs, I seem to remember uninstalling database from the system, making modifications to the copy you have elsewhere (you can't modify installed version) and installing it again seems to fail, unless you close and re-open program when you want to re-install database.
Sometimes you need to disable entries in system database because some things aren't needed anymore. For example, alt-tab combination is needlessly blocked for Drakan: Order of the Flame. There is a bug in 5.6 version of the program that writes this information in the wrong part of the registry on 64-bit systems, so it's impossible to disable certain entry without manually inspecting registry and putting the information in correct place. It writes to HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\AppCompatFlags instead of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags This was solved with later versions, but they don't work on Windows 7.
Oh. and technically correct term for individual fix is shim.
Arthur Schopenhauer wrote:
A man can be himself only so long as he is alone; and if he does not love solitude, he will not love freedom; for it is only when he is alone that he is really free.