I've been using 64-bit versions of Windows for quite some time now, and it's always annoyed me that there's no clean way to combine 32-bit code and 64-bit code in your executables.
I can either generate a 32-bit or 64-bit binary. Then if I want other people to use it, I have to distribute both, and the user will have to pick which one they need. I'm not a fan of making separate bin32/bin64 directories, as it gets confusing, and makes sharing data between the different versions more difficult. Although in some cases, there isn't really much of a choice. Some DLLs have the same name for the 32-bit and 64-bit version for example. If you want to include those, you need to keep the binaries separate. Either that, or you need to create an installer to copy them to the system32 and syswow64 directories. But for small tools, applets etc, that's just a bit over the top.

Now I've got this idea of using a separate launcher to hide the actual binaries and automatically select the best one for the user.
This launcher will be 32-bit only, but will know how to detect the presence of a 64-bit OS. So it works on all versions of Windows.
The actual binaries will not be called .exe, so the user isn't tempted to try and start them manually. Something like myapp32.bin and myapp64.bin, for example.
The launcher will then just call CreateProcess() on the best match, and then exit.
Sounds like a clean solution?

In my case I'll actually expand on this to also pick the proper Direct3D engine for your OS and hardware. I have a single codebase which can be compiled for D3D9, D3D10 or D3D11. This way the entire engine is always optimized for the API it's compiled for, rather than trying to solve the differences between the APIs at runtime, which can sometimes be quite difficult and/or inefficient.
Now I'd like to compile them for different APIs and put them into separate DLLs. Then the executable will simply try to load each DLL dynamically (eg, on an XP system some of the D3D10/11 DLLs simply don't exist, so static linking will make the entire exe fail to run). If the DLL loads, it will call a simple function in the DLL which tests whether a device can be created.
The executable then decides the best match for your hardware, and runs it.

Sounds good in theory, I hope. Now I need to bang my code into shape to see if I can also make it work this way in practice.
Posted on 2009-06-30 08:04:12 by Scali
Just had a nice and simple idea...
If I create the wrapper with a name of "myapp.exe", and then add the actual binares as "myapp32.bin" and "myapp64.bin" or something like that, then I can just have the wrapper construct the filenames of the binaries from its own filename. This would mean that it's very easy to 'recycle' the wrapper, and no need for extra configuration. Just give all your binaries the right filenames, and it works instantly.
Posted on 2009-06-30 11:43:48 by Scali
Whatever happened to installers?
Posted on 2009-06-30 13:58:23 by Ultrano
Like I said, I think installers are a bit over-the-top for simple utilities or demos.
I like it when an application can just be downloaded and executed right from the zip file. You don't want to have to install a simple demo before you can watch it.
Posted on 2009-06-30 14:16:57 by Scali
Okay, here it is:
http://bohemiq.scali.eu.org/Launch3264.zip

It seems to work on my system in WinXP 32-bit and Vista x64.
Feel free to test it. I'd be especially interested in Windows XP pre-SP2 or older OSes. They lack the IsWow64Process() function that I use to check for a 64-bit OS. I can't test if it also works when the function isn't there, because I don't have an OS old enough. It should work though, I just use GetProcAddress(), if that fails I assume 32-bit.

If it works, and you like it, feel free to use it yourself.
Posted on 2009-06-30 16:49:23 by Scali
Ah, I was then going to argue that simple utilities and demos then don't need a 64-bit version,  but ISA-specific optimizations would be neat.
Anyway, runs under Win2k SP5 with VirtualBox (WinXP SP2 host).
With the lack of the MSVC90 dll. At least it's not asking for manifests :) .
Posted on 2009-06-30 21:27:12 by Ultrano

Ah, I was then going to argue that simple utilities and demos then don't need a 64-bit version,  but ISA-specific optimizations would be neat.


Yea, for demos 64-bit may give you extra performance, and it makes using a lot of memory easier.
I think there are actually rules against using installers at most parties. I've never actually seen a demo with an installer anyway. Wouldn't want it either... anything you install needs to be uninstalled aswell. It's bad enough that the demos from nVidia and AMD nearly always require installers. As if I want to keep them on my system for years, and run them a few times a day?


Anyway, runs under Win2k SP5 with VirtualBox (WinXP SP2 host).
With the lack of the MSVC90 dll. At least it's not asking for manifests :) .


Ah right, I should compile it with a static crt. I guess DLLs are the default option in newer versions of VS. Didn't bother to check the project settings. But good to know it works on ancient OSes. That was the point. Just click and run, don't bother the user with a bunch of installers, exe's etc.
Posted on 2009-07-01 02:06:51 by Scali
ProcessExplorer from SysInternals unpacks a 64 bit image from the resource section and runs it as a child process if the the host system is a 64 bit one.
It probably uses IsWow64Process().
Posted on 2009-07-01 04:32:11 by ChaperonNoir
Well depends on the application really. For a real product that consumers are going to commercially use, it HAS to have an installer. Otherwise, it will be a bit "suspicious" you know. It's like going to a superstore and buying everything without packaging. You buy ham slices that are thrown on the ground and you just go pick them. It's just not nice lol.
Posted on 2009-07-01 05:30:49 by XCHG
Actually, I think I should make the code a bit better than just IsWow64Process().
Namely, I think this will also return true on Itanium systems.
So I should also check the architecture to see if it's an x86-variant or not (and I could expand the launcher to also support IA64 binaries in the same way. Perhaps instead of 32/64, I should call them myappx86.bin, myappx64.bin and myappIA64.bin or something).
Posted on 2009-07-01 06:38:02 by Scali
It would launch at all on Itanium?
I'm not familiar with the Architecture but I thought you had to recompile everything for the Itanium since it's a different architecture.
Posted on 2009-07-01 17:15:30 by ChaperonNoir

It would launch at all on Itanium?
I'm not familiar with the Architecture but I thought you had to recompile everything for the Itanium since it's a different architecture.


Well, the Itanium version of Windows has an x86 emulator built in, which is called Wow64 just like when running 32-bit applications on an x64 machine. So standard 32-bit x86 applications will just run.
I don't think the emulator supports x64 though. So that would mean that my 32-bit launcher would run, it would detect that it is running as a Wow64 process, and then assume the CPU is x64, so it would launch the x64 binary, which would not run.

I have now added some extra code. If I detect a Wow64 process, I use GetNativeSystemInfo() to see whether Windows reports an AMD64 architecture. If not, I currently just launch the 32-bit process (which should work on Itanium)... but in theory I could add a third case and launch a special Itanium binary.
At least it should not crash if anyone ever did try to run it on an Itanium (or whatever other non-x64 architecture that may run Windows in the future) :)
Posted on 2009-07-01 17:23:49 by Scali
Well, I've been busy last night... I managed to separate my general application code from the specific engine-related code, and put the engine into a DLL which can be loaded dynamically.

Tonight I hope to implement some simple code to test for compatibility with D3D9, D3D10 and D3D11.
Then I'll try to put together a package which will pick not only a 32-bit or 64-bit binary, but also picks the best possible 3D API for your system.
Posted on 2009-07-02 04:12:49 by Scali
D'oh... I managed to get the 64-bit version working last night... Runs D3D11 on my Vista installation, and D3D9 on XP...
But the 32-bit version seems to crash when you start to render (the dialog with graphics settings does pop up, and when you click 'ok', it creates the main window... then *boom*)... Ofcourse this only happens with a release build, not with a debug build.
Then I ran out of time.
So hopefully tonight I'll find whatever the problem is with the 32-bit version, and then I should be able to post a little ditty, which runs on 32-bit and 64-bit, and D3D9, D3D10 and D3D11. All with just a single click.
Posted on 2009-07-03 02:10:05 by Scali
Okay, there we go:
http://bohemiq.scali.eu.org/LaunchEngine.rar

This *should* launch on any Windows with D3D9 or higher and an SM3.0 videocard. It should run D3D11 if the DX SDK beta runtime for D3D11 is installed. It should run D3D10 on any Vista or higher system with an SM4.0 card, and it should run D3D9 on Vista with an SM3.0 card, or on XP/2000/98/98SE/ME.
It should also run in 64-bit mode if possible.

You will need the March 2009 DirectX runtime:
http://www.microsoft.com/downloads/details.aspx?FamilyID=0cf368e5-5ce1-4032-a207-c693d210f616&displaylang=en
Posted on 2009-07-04 02:15:54 by Scali
I can tell from my server logs that some people bothered to download the above file.
Could you please tell me if it worked for you or not, and what OS and hardware you were using? Thanks.
Posted on 2009-07-06 06:34:59 by Scali
Link is dead for me here.
Posted on 2009-07-06 07:23:36 by ChaperonNoir
Yes, it seems that the DNS server is unavailable at this point. I hope it will come back online soon.

Edit: it would appear that the site is back online.
Posted on 2009-07-06 07:32:52 by Scali
It starts the 64-bit version ("Engine64.bin" in the process list) on windows XP 64-bit (NT5.2) and properly says "64-bit Direct3D9".

The rendering starts and works properly both in windowed and fullscreen mode, both antialiased and not antialiased.

I see 3 problems with the app:
1) It shows 2 exactly same strings for 2 different display outputs (I have 1 monitor and 1 HDTV attached to a GeForce 9600 GT -- see attached image). You should enumerate available monitors attached to the selected adapter and include their names in the selection strings.

2) Minimizing then maximizing stops the rendering (displays black screen).

3) There is no acpect-ratio compensation. The ring is elliptic at 16:9. It would be even more elliptic at 2.39:1.
Attachments:
Posted on 2009-07-10 18:13:13 by ti_mo_n
Thanks for testing, ti_mo_n.


1) It shows 2 exactly same strings for 2 different display outputs (I have 1 monitor and 1 HDTV attached to a GeForce 9600 GT -- see attached image). You should enumerate available monitors attached to the selected adapter and include their names in the selection strings.


Yes, I did spend some time on that in the past, but I couldn't figure out how to get to the actual names of the attached monitors.
In D3D10 I got *some* names, but they are only \\DISPLAY1 and \\DISPLAY2.
So if anyone knows a good way to get the actual display names, both in D3D9 and D3D10, I'm all ears :)


2) Minimizing then maximizing stops the rendering (displays black screen).


I know that rendering stops when it's minimized, but it should start again when it's resized to anything else...
I wasn't able to reproduce this myself, when I either used the buttons in the top-right of the window, or when right-clicking minimize/maximize on the taskbar button.
Perhaps you did the resizing in yet another way, that doesn't work?
Or perhaps it only happens in XP64, I used Vista x64, forcing the D3D9 engine.


3) There is no acpect-ratio compensation. The ring is elliptic at 16:9. It would be even more elliptic at 2.39:1.


Correct. The aspect-ratio is calculated in the config dialog, but it is never used in the simple test-scene I've used here.
I will add it in a later version, and then it should work... it always did in the past :)
Posted on 2009-07-11 03:25:06 by Scali