Moving on to 64-Bit
Long ago we contended with the migration of our Windows programs from 16-Bit to 32-Bit. This was catalyzed by the release of Windows 95 which was the first popular desktop version of Windows at this bitness. At that time everyone jumped on 32-bits because under 16-bits you could only address 64K of RAM and this just wasn’t enough. With 32-bits suddenly we could address 2 gigabytes of RAM. Plus the Windows 32-Bit API fixed many problems in the Windows API and allowed true and proper multi-tasking. At this point Windows had become a true OS. Perhaps we weren’t really happy with Windows until Windows XP, but at least it was starting to be powerful enough for typical usage.
We’ve started seeing 64-Bit versions of Windows for a while now, but it was really with Windows 7 and Windows Server 2008 that these were finally working well enough to be compelling. Plus now it is quite inexpensive to purchase more the 2Gig or RAM and if you don’t have a 64-Bit operating system then all that extra RAM isn’t going to get used. The nice thing about these 64-Bit versions of Windows is that they run 32-Bit Windows programs extremely well and then each separate 32-Bit program can get up to 2Gig of RAM and you can run a whole bunch of these.
We haven’t seen the same mad rush to 64-Bit applications, like we saw a big rush to 32-bit applications. This is because for most purposes 32-bits is just fine and 2Gig of addressable RAM is plenty. Another reason is that there is no “thunking” mechanism to allow 64-Bit processes call 32-Bit DLLs or vice versa. So your application has to be 100% 64Bit or 100% 32Bit. This then means you need to move your application along with all libraries, add-ons and anything else all to 64-Bit. This can be a logistical problem and is the main reason people still run 32-Bit Internet Explorer and Office.
So what sort of programs benefit from 64 bits? The main ones are server processes like SQL Server. When running on a server with say 64Gig RAM, why shouldn’t SQL Server use 32Gig for cache? And then to efficiently access this it needs to be 64-Bit. Similarly programs like Adobe Photoshop need to handle huge amounts of RAM to do their job and are far more efficient at this as 64 Bit programs.
But what about business applications like Sage 300 ERP? Does it make sense for this to be 64 Bits? For the regular Windows Desktop and for regular data entry screens it doesn’t make any sense. The heavy lifting is done by SQL Server and communicating with 64-Bit SQL server over the network is no problem. For individual screens, they don’t need anywhere near 2Gig or RAM, so they are fine as 32-Bit programs. Then there is no problem with customizations and integrations to other programs, it all continues to work.
The difference is once we start accessing our business logic from a web server. Then we might want hundreds of users using our business logic. Web servers typically run as one process (i.e. an IIS application pool or a Java Tomcat Server) and then all the users run as separate threads inside this process. So if we want to fully exploit the power of a powerful server with lots of RAM and many processors then we need to be a 64-Bit program.
The 64 Bit C/C++ Compiler
For the most part Microsoft left the command line arguments and functioning of the C/C++ compiler the same between 32-Bit and 64-Bit programs. You only need to invoke a different one depending on if you want to compile 32 or 64 bit. If you want to compile for 32 Bit then set your path to “C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin” and if you want to compile for 64 Bit then set your PATH to “C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64”. You also need to ensure you keep your 32-Bit libraries separate from your 64-Bit libraries.
If you are building directly from Visual Studio or using MSBuild then you need to either add or change your configuration to target x64. All in all rather easy.
When you build 32-Bit you can #ifdef using WIN32. Be careful in 64 Bit because both WIN32 and WIN64 are defined. This is because most programs mean not WIN32 to mean WIN16, so strangely this leads to more correct behavior, which you do need to be aware of it.
Building C/C++ Programs
The big differences going to 64 Bit are that pointers are now 64 Bits, you can more easily use 64 Bit integers and structures are now aligned on 8 byte boundaries. All the regular C data types like int and long are still 32 bits in size. So let’s look at some of the things that need dealing with and some of the things that don’t.
When we migrated from 16-Bits to 32-Bits the big killer was the changes to the Windows Proc. This is the callback function that gets called for each Windows or Dialog box message. In 32 Bits Microsoft changed which parameter did what and it caused havoc. They introduced macros to help and everyone had to adopt these macros and then do lots of debugging. I suppose with these macros in place, this should be easier this time around, but actually I don’t care! For this port to 64 Bits I only want to port the API to be used by server processes like web servers. I don’t actually want to port any C based UIs to 64 Bits, so I don’t really care if these Windows Procs work or not. For now I’m just ignoring them entirely. This also gives us a chance to produce a version of System Manager with far fewer DLLs that can easily be installed in a PaaS environment where you need to quickly install your software as a VM boots.
Generally I found that porting to 64 Bit is helped by a good debugger so once you get test programs working 64 Bits its fairly easy to sort out what is going on. Plus when you google on the various errors or functions that are failing, you get lots of good hits.
Some things that cause problems are:
- Since pointers (and hence handles) are 64-Bit, you cannot store them in longs or DWORDS. The compiler gives you warning about doing this and at some point these will need to be fixed. Superficially these may work, since most of these pointers seem to have the high 32-bits set to 0 on my computer. But you are living on borrowed time.
- Similarly some lengths like SQLLEN in ODBC are now 64-Bit, this way you can have more than 2Gig records in a SQL table. Basically you have to be careful and use the correct types or you will get many compiler warnings and will overflow if you ever get this many records. Worse if you pass a pointer to an int type then it will overrun and corrupt something else or GPF.
- 32-Bit windows was fairly efficient, so even though it had a structure packing of 4, most Windows related structures had no empty space, so you didn’t have problems if say you compiled with the –Zp option (which sets structure packing to 1). However in 64 Bits these Windows structures are sets of ints and longs and the structure packing of 8 leaves lots of empty space and is incompatible with –Zp. I ran into problems here with Windows security descriptors; that basically all the functions and macros for dealing with these don’t work under a different packing option.
- Beware that registry entries are no longer under Wow6432Node, you get to use the real entries now. Also make sure you use the 64-Bit versions of ODBC and RegSvr32.exe. A lot of EXEs that got 32 tacked on the end, now have 64 bit versions, but remain with the same file name.
- The 64-Bit compiler doesn’t support the _asm keyword, so no inline assembler. We only had a few instances of this that were cut/paste from MSDN for diagnostics like reporting a stack trace when something when wrong.
Moving to 64 Bits isn’t for everything; however, for running in the context of a Web Server it makes a lot of sense. I think the migration from 32 Bit to 64 Bit is much easier than the migration from 16 Bit to 32 Bit was. The tools are much better these days and the tools behave the same way in 32 or 64 bits. Plus all the work we did to use macros and make things type safe when we went from 16 Bits to 32 Bits now helps with the transition to 64 Bits. The only hard part is that you need to go all 64 Bit and can’t just call 32 Bit DLLs. Now I just wonder how long before we need to re-compile for 128 Bits.