How to programatically set or clear the 32BIT flag?
Asked Answered
N

4

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)?

Numeral answered 1/6, 2009 at 22:55 Comment(4)
not exactly sure what you're trying to achieve by doing this?Brunei
An alternative solution could be to include the 64 bit version of the library you are using, if the user has the 32 bit version and are running on a 64 bit machine the local version will be in the search path with your application and should load.Zoomorphism
@Mitch: we reference a 3rd party library, not open source. It is a C++ Mixed Mode library. In an earlier version, there is only a 32 bit version available. So even if they are running on an x64 machine, they do not have the x64 version of this library. My tool is C# and compiled as Any CPU. So when it runs on one of these machines, it does not find the correct DLL.Numeral
@Average Joe: It is a 3rd party library, not open source, and we are not allowed to redistribute 3rd party tools (legal reasons), which is why I also can't just ship out corflagsNumeral
D
1

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.

Duncan answered 2/6, 2009 at 3:44 Comment(2)
I'm leaning toward this method now, I was just hoping to avoid distributing 2 binaries.Numeral
I'm building both a X86 and AnyCPU, but it doubles the installer size. We built a simple setup program that determines which version to install (based on Office install type 32/64). It would be nice to be able to tell the installer which version to install from the AnyCPU instead of bundling both, and forcing a X86 on X64 by installing a x86 only MSI.Ruche
Z
3

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.

Zoomorphism answered 2/6, 2009 at 4:16 Comment(0)
D
2

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.

Death answered 2/6, 2009 at 0:51 Comment(0)
D
1

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.

Duncan answered 2/6, 2009 at 3:44 Comment(2)
I'm leaning toward this method now, I was just hoping to avoid distributing 2 binaries.Numeral
I'm building both a X86 and AnyCPU, but it doubles the installer size. We built a simple setup program that determines which version to install (based on Office install type 32/64). It would be nice to be able to tell the installer which version to install from the AnyCPU instead of bundling both, and forcing a X86 on X64 by installing a x86 only MSI.Ruche
G
0

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.

Glutamine answered 2/6, 2009 at 2:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.