views:

535

answers:

4

When compiling, I always set it for Any CPU. However there are some customers that do not have a 64 bit version of a required binary, even when running on an x64 system. In these instances I have asked them to modify my binary with the corflags.exe /32BIT+ option:

http://msdn.microsoft.com/en-us/library/ms164699(VS.80).aspx

I would like to make this transparent and modify the binary myself during installation time if the 64 bit version is not present. I would prefer not to make a call to corflags.exe myself as that would mean I would need to redistribute the application which is not allowed as part of our shipping requirements.

So my question is; is there any way to modify this flag programatically myself, or alternatively to modify the binary directly (is it just setting a byte somewhere in the file itself)?

+1  A: 

For the file itself, I believe (haven't confirmed) you could just modify the IMAGE_COR20_HEADER yourself. Just setting MinorRuntimeVersion should do the trick. Here is an (somewhat outdated) explanation on how the IMAGE_COR20_HEADER is used for determining which runtime is loaded: http://blogs.msdn.com/joshwil/archive/2004/10/15/243019.aspx

Why not just always compile for x86, does the 64bit runtime give you any benefit?

Note that some code (interop/P/invoke) will only work in either 32 or 64 bit runtime, so just loading the same assembly into another runtime won't work.

Edit: quick and dirty sample to read IMAGE_COR20_HEADER:

_pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(_pFileBase);
_pNTHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(_pFileBase + _pDosHeader->e_lfanew);
_pFileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(&_pNTHeader->FileHeader);
_pOptionalHeader = reinterpret_cast<PIMAGE_OPTIONAL_HEADER>(&_pNTHeader->OptionalHeader);
IMAGE_DATA_DIRECTORY const* entry = NULL;
entry = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COMHEADER];
if (entry->VirtualAddress == 0 || entry->Size == 0  || entry->Size < sizeof(IMAGE_COR20_HEADER)) {
return E_FAIL;
}
pClrHeader = reinterpret_cast<IMAGE_COR20_HEADER*>(RtlImageRvaToVa32(_pNTHeader, _pFileBase, entry->VirtualAddress, 0));

Not convinced it's a good idea doing this as an installer step though.

Ben Schwehn
A: 

If you can detect this during the install, why not just run corflags.exe from the installer directly? This sounds much better to me, rather than trying to alter the binary data myself.

TheSean
+1  A: 

Why not just build your assemblies for both architectures (32-bit and 64-bit) specifically, include both in your installer, and then at install time, detect which version of this dependent assembly your client has and then install the appropriate architecture version of your application. This way there's no messing around modifying binaries manually or needing to include corflags in your installer.

Daniel Chambers
I'm leaning toward this method now, I was just hoping to avoid distributing 2 binaries.
esac
+2  A: 

I have not tried this however are you able to run corflags on a copy of the binary and do a binary diff to determine what offset was modified. You could do this as a build action of your install script and store the offset with the installer.

At install time just alter the offset that if needed.

Of course I would never endorse such actions, just sayin'

;-)

As an aside, if you are continually needing to mark the assembly for 32bit you may consider just targeting that platform instead of altering it as 32bit after the fact.

Cheers.

another average joe