It is common to direct developers to compile their PInvoke-using app as x86 if they want it to run in a 64-bit environment. I would like to be able to choose between a 64-bit and a 32-bit version of the native dll at runtime. Reasons:
1. I do not want to sacrifice the peformance available to the 64-bit environment.
2. Vendors often supply 64-bit and 32-bit versions of native DLLs my app depends on (but not the source
)
3. The DllImport statment appears to use dynamic linking to the native DLL; I just want access to the name passed to the dynamic link at runtime.
Anyone have any ideas how this may be done?
-
-
If the EXE is 32-bit, it uses only 32-bit DLLs. If it's 64 bit, it only use 64-bit DLLs. You can't mix it.
If you could mix it, there definately no point in hiding 32-bit OBDC drivers from the sight of my 64-bit executables. And Microsoft's action on creating 32-bit MS Access ODBC driver only won't annoy so many people. -
Cheong, the problem at hand relates to .Net. A .Net application will execute as real 64 bit on Windows x64, so if it tries to use a native 32 bit DLL it will fail. The only way to work around that is to set the assembly's target architecture to x86, which will cause it to execute as 32 bit even on x64.cheong said:If the EXE is 32-bit, it uses only 32-bit DLLs. If it's 64 bit, it only use 64-bit DLLs. You can't mix it.
If you could mix it, there definately no point in hiding 32-bit OBDC drivers from the sight of my 64-bit executables. And Microsoft's action on creating 32-bit MS Access ODBC driver only won't annoy so many people.
Mozzis is asking whether it's possible to have it automatically use a 64 bit native DLL instead when running under x64. As far as I know that's not possible. The only thing I can think of is to use [DllImport("foo.dll")], and include both a foo32.dll and foo64.dll and copy one of them to foo.dll when the application starts (before the first PInvoke call), but that would cause trouble if the user trying to execute the application has no write permissions to the application's directory. -
Presumably you can include both signatures:Sven Groot said:
Cheong, the problem at hand relates to .Net. A .Net application will execute as real 64 bit on Windows x64, so if it tries to use a native 32 bit DLL it will fail. The only way to work around that is to set the assembly's target architecture to x86, which will cause it to execute as 32 bit even on x64.cheong said:*snip*
Mozzis is asking whether it's possible to have it automatically use a 64 bit native DLL instead when running under x64. As far as I know that's not possible. The only thing I can think of is to use [DllImport("foo.dll")], and include both a foo32.dll and foo64.dll and copy one of them to foo.dll when the application starts (before the first PInvoke call), but that would cause trouble if the user trying to execute the application has no write permissions to the application's directory.class MyFoo {// this is a bad signature when running in 64bit code, but 64bit code never calls this function[DllImport("foo32.dll", EntryPoint="foo")]static extern int _foo32(IntPtr foo);// this is a bad signature when running in 32bit code, but 32bit code never calls this function[DllImport("foo64.dll", EntryPoint="foo")]static extern int _foo64(IntPtr foo);private static bool IsX86 {get { return IntPtr.Size == 4; }}public static int Foo(IntPtr foo){
if(IsX86)return _foo64(foo);elsereturn _foo32(foo);
}}I can't actually remember whether or not there was an issue with checking IntPtr.Size on x64 machines running the app as x86, but I think that works (since on an x86 machine Foo64.dll is never loaded, on x64 the Foo32.dll is never loaded and on x64-v86 Foo32.dll is used) -
That would work of course, but unfortunately you'd have to write that code for every method. I got the impression that Mozzis was looking for a way to do it automatically, and I don't think there is one.evildictaitor said:
Presumably you can include both signatures:Sven Groot said:*snip*class MyFoo {// this is a bad signature when running in 64bit code, but 64bit code never calls this function[DllImport("foo32.dll", EntryPoint="foo")]static extern int _foo32(IntPtr foo);// this is a bad signature when running in 32bit code, but 32bit code never calls this function[DllImport("foo64.dll", EntryPoint="foo")]static extern int _foo64(IntPtr foo);private static bool IsX86 {get { return IntPtr.Size == 4; }}public static int Foo(IntPtr foo){
if(IsX86)return _foo64(foo);elsereturn _foo32(foo);
}}I can't actually remember whether or not there was an issue with checking IntPtr.Size on x64 machines running the app as x86, but I think that works (since on an x86 machine Foo64.dll is never loaded, on x64 the Foo32.dll is never loaded and on x64-v86 Foo32.dll is used)
IntPtr.Size will work fine, it'll return 4 if the app is running under WoW64 on x64, and 8 only when it's running on real 64 bits.
Of course, IntPtr.Size will also return 8 when the app is running on IA64 (Itanium), but I don't think that's going to be a major issue for the vast majority of applications out there. -
Sven Groot said:
Cheong, the problem at hand relates to .Net. A .Net application will execute as real 64 bit on Windows x64, so if it tries to use a native 32 bit DLL it will fail. The only way to work around that is to set the assembly's target architecture to x86, which will cause it to execute as 32 bit even on x64.cheong said:*snip*
Mozzis is asking whether it's possible to have it automatically use a 64 bit native DLL instead when running under x64. As far as I know that's not possible. The only thing I can think of is to use [DllImport("foo.dll")], and include both a foo32.dll and foo64.dll and copy one of them to foo.dll when the application starts (before the first PInvoke call), but that would cause trouble if the user trying to execute the application has no write permissions to the application's directory.I'm not sure if I misread the question, as it says "choose between the versions at runtime"...
======
But... there's no need to do so, right?
As long as you have the 32-bit copy of DLL in SysWow64 folder, and 64-bit copy in system32 folder. The program should find the matching version through the automatic filesystem redirector.
That leaves the function signature problem. Like Sven said IntPtr.Size will work fine. But it's likely that the size of structures for parameter passing/retrival will change to match the alignment too (say, a struct of <32 bit size could be resized to 32 bits. And individual variables within that structure may change size for the same reason, unless the writer of that native DLL "fixed" the alignment specifically). So like what evildictator said, the user should have another function defination for 64-bit version of DLL.
Therefore, it would not be able to choose in runtime.
An exception is COM+ DLLs. You application will choose the matching 32/64 bit interface for you, and all the parameters will be converted to appropiate size automatically. -
I solved this via a "trick":
- I have an x64 directory under my application directory, in which I place 64-bit versions of the DLLs in question.
- At runtime, I construct the path to the DLL I want to use based on the application's directory + "x64" if running as a 32-bit application. This is easy to detect using IntPtr.Size.
- At runtime, I call the Windows API function LoadLibrary and pass it the path I have constructed to satisfy the DLLImport signatures (each of which is specified with no path).
- And It Just Works. (
When .Net creates the linkages, it uses the already loaded instance of the DLL.
I certainly do not want to put files into the System32 or SysWow64 directories. The approach I used seems to work very well. This also solves the problem of what dependent dlls the target dll will use: if everything was in one directory, then there might be conflicts, but now everything is separated.
Thread Closed
This thread is kinda stale and has been closed but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.