I'm developing an application that uses a plugin mechanism to load libraries. Usually the hosting application runs as 64bit application.
So far everything worked as expected. x64 assemblies could be loaded, AnyCPU could be loaded and x86 assemblies failed. That is - until someone came up with the idea and created an x86 Console Application - and it could be loaded as well.
Why is it possible to load an x86 console application assembly (exe) from a 64bit host process, but it fails to load an x86 library (dll)? Just for clarification - I'm not trying to load x86 dll's and not intend to - just curious why it's allowed to load x86 applications.
(If anyone is interested I can attach the sample code that I used)
The response to this was given in Microsoft Connect some time ago... however I can't seem to find the link.
I did, however, find a thread where they reference it with the response here.
Quoting:
Hi. Thank you for reporting the issue. It looks like you stumbled on an implementation detail - we do not use LoadLibrary for executables and it looks like in this case it does a validation that we do not. I cannot say this difference was the intended behavior, however if we were to to add an additional check now we could break someone, and the issue does not seem serious enough to take the risk.
Related
I am designing a client application that will list several applications that I offer. A user will pick the application, and press run, then the application will be downloaded and will be loaded into the client application's domain using Assembly.Load. Here's the snippet of where it gets loaded:
var vAsm = Assembly.Load(client.GetBase());
var vEP = vAsm.EntryPoint;
var vSC = vAsm.GetType(vEP.DeclaringType.FullName).GetMethod("SetClient");
var vInst = vAsm.CreateInstance(vEP.Name);
vSC.Invoke(vInst, new object[] { client, license });
vEP.Invoke(vInst, null);
Problem: Two of the current applications are 32bit. However one of my applications is 64bit.
Question: If I build the client application in AnyCPU, will it be able to load both the 32bit applications AND the 64bit application? Or is there maybe a setting that launches it in 64bit if the machine supports it? This would be ideal, as I would just detect if they are 32bit/64bit and warn them that the one application is not supported on their machine if that's the case.
I will be testing this myself, but maybe somebody could give me some sort of advice to handle this.
Thanks!
To answer your first question, if you compile the application as AnyCPU you let Windows decide which CLR to pick. In my experience, it usually works out to Windows picking the x64 CLR on x64 operating systems and the x86 CLR on x86 operating systems but I'm not certain if that's always a guarantee. AnyCPU does not mean that it gets to run in both. You will only be able to load the version of the application which corresponds to the architecture of the CLR which loaded your client application.
I've had to deal with this sort of thing in some of the applications that I work with at the place where I'm working. I've run into some frustrating bugs when I tried interoperating with applications compiled for a specific architecture and applications compiled for AnyCPU. To make things easier and more predictable, I just ended up compiling the "AnyCPU" applications which had to interact with the "non AnyCPU" applications for each architecture for which they had to interact. There may be some people who have a more sophisticated setup but it wasn't worth the headache for me.
So, the answer to the second question is more advice. I'd just compile the client application for a specific architecture so that you know for sure which architecture that you're dealing with and then add appropriate code to detect the architecture. In fact, I think that you could use some compiler directives to store some sort of indicator as to which architecture that you're running under or even put a "detection" branch specific to each architecture in the compiler directive and that would help you do the warning that you're thinking of doing.
The alternative is to keep the client application as AnyCPU and detect which architecture the application is currently running under (if memory serves, it's IntPtr.Size == 8 for x64 applications but there may be more reliable methods; not sure...) and then only launch the appropriate applications. But still, you have to be mindful of the fact that, even with AnyCPU, you can only load applications of the specific architecture of the CLR which is running your AnyCPU client application.
Does that make sense?
You should build all your binaries in AnyCPU. That way, on a 64-bit OS, they'll run as 64-bit and on a 32-bit OS, they'll run as 32-bit. If you compile to x64, it won't run on a 32-bit OS at all. If you compile to x86, you'll always run as 32-bit, even on a 64-bit OS. The final rule is that you can't mix & match x86 and x64 bins in the same process. The mismatching ones will fail to load.
I made a default Silverlight 5 project in VS2013 and let Visual Sudio create the sample web host as a web application. I then ran it and saw that it loaded fine.
Now things get odd: I want to call some C++ code (cryptopp) so I think that I need Silverlight to run as x86 to include it. When I swap it to build as x86 and run the app in the browser it crashes (not calling anything yet, only swapping the debug build configuration to x86).
So: Is it even possible to run Silverlight as x86?
Edit:
64 bit OS. 32bit and 64bit IE both fail to display
Your only chance to call a lib written in C++ (and therefore unmanaged code) is to run your silverlight app with elevated trust.
You did not mention that you configured it to require elevated trust, so maybe that's where your actual problem lies? I don't think it has anything to do with x86 vs x64.
The answer is apparently no.
No you cannot run a Silverlight app that has been compiled as x86. It fails to initialize.
It appears to have a hard time loading an assembly that is required for a base, empty Silverlight app. We've verified it on 3 machines in both Silverlight 4 and 5.
I have compiled a c natives 32bit DLL with Dev-C++, create the reference on my asp.net project, write a dllImport directives and use my new DLL. When launch my DEBUG session all work very well but when deploy my project on Web Server the runtime not load my DLL.
My IIS 7.0 w3wp.exe runs as a 64 bit process (to check if your process running as a 32 bit process under WOW64, open the task manager's Process tab and see if the process name contains "*32").
I believe that a 64 bit process can only load 64 bit native DLLs (and managed DLLs built for "Any CPU" or "X64"). Perhaps your debug session is a 32 bit session? If this is the cause, take a look at Using a 32bit or 64bit dll in C# DllImport .
For those of you who still cannot find a proper way to use a 32-bit DLL under a 64-bit IIS Application Pool, either by tweaking the registry, or by trying how to deal with the "COM+ Components Services", I have found a perfectly working solution : "Encapsulating" the 32-bit component into a new COM object as described on this page did the job perfectly, and I think that a lot of you will be interested to solve the problem this way ;)
http://www.chestysoft.com/component-services.asp
In my case, that allowed me to use the "XStandard.Zip" free Component from XStandard, which is sadly only available as a 32-bit ASP component, and that have an "InProcServer32" Key in the registry apparently preventing it to work by tweaking the registry, as described here : https://techtalk.gfi.com/32bit-object-64bit-environment/
In this post, a lot of comments reported that "InProcServer32-IDs are not reflected because Microsoft assumes that these are only InProc-Calls and not Out-Of-Proc-Calls".
And that was my case too, leading me to the situation where the registry tweaking solution described in the previous post was not working in my case, as other users.
Hoping having saved some days... or nights !
I am trying to get registration-free COM interop between a 64-bit COM dll and a C# app to work.
In the answers to a previous question of mine, I got help that allowed me to successfully call a HelloWorld method on the 64-bit COM dll for C#.
However, this was only possible by registering the COM dll globally using regsrv32.exe.
Based on this answer to a related question, I think that I need to set the Isolated flag on the reference of the COM dll to true. However, this leads to the following build error:
Problem isolating COM reference 'ComLibInteropLib':
No registered classes were detected for this component.
The answer to a question on MSDN social seems to indicate that there is a solution for this problem if one can compile a 32-bit version of the dll.
However, my COM interop library needs to link to a 'normal' C++ dll, for which I do not have the source and that is only available as x64.
So my question is: How can I enable the Isolated flag (or otherwise get side-by-side to work) between a 64-bit COM dll and a C# application?
I am happy to use regsrv32.exe on my machine or other developer's machine, but we cannot register any COM dlls on production machines, where the final application must run.
This is a side-effect of the original problem you had, the COM server wasn't getting registered properly. When you Isolated option to true, the build system auto-generates the required manifest entries for you. But the content of the manifest needs to come from somewhere, it uses the registry keys. Since they are not there, it can't generate the manifest.
You can write the manifest yourself but that requires enough insight in what the manifest should look like. With very high odds of making mistakes, the incantations are quite obscure. So avoid that, you just need to get the COM server registered to get ahead. Just on your build machine, it doesn't have to be registered on the client's machine since it will use the manifest.
You mentioned a 64-bit COM server, that's another possible failure mode. The build system is still 32-bit so you'll have high odds that it looks at the wrong keys. HKLM\Software\Wow6432Node instead of HKLM\Software. Battle that problem by building both flavors of the COM server. Beware of having the same kind of problem when you use Regsvr32.exe yourself, there are two of them. The one in c:\windows\syswow64 should be used to register the 32-bit version of the server, the one in c:\windows\system32 for the 64-bit version.
I wrote an application that uses sqlite and it works great on most of the systems. It is written in C#, and the only non-framework assembly is sqlite, which is included by System.Data.SQLite.dll .
I deploy it the same way on all of the machines (copy pasting the exe file, the database file and the System.Data.SQLite file). It works great for all my PC's and most of the PC's I've tried.
But then I've got reports that for some people it throws the following exception:
Could not load file or assembly
'System.Data.SQLite, Version=1.0.65.0,
Culture=neutral,
PublicKeyToken=db937bc2d44ff139' or
one of its dependencies. An attempt
was made to load a program with an
incorrect format.
Now I've made sure the dll file is in the same folder than the application exe file. It's the same dll, with the same version as stated in the exception message above.
I was really confused by this, so I created a fresh virtual machine, installed windows 7 professional on it, and just copy pasted the files, and the thing worked. So if it works on a fresh windows, I can't imagine what the other PC's could be missing...
Note: Two of those machines where the project throws the exception are also running windows 7 proffesional.
I would really appreciate any help on this, because I'm fresh out of ideas...
Here's a possibility: Is the difference between the working and not-working machines 32-bit vs. 64-bit? Are you building for "Any CPU", when you should be building for just the bitness of your external DLL?
It is possible that the machines that throw the exception are running a 64-bit version of Windows and that your program is using the AnyCPU configuration. The System.Data.SQLite DLL is a two-faced beast: a managed part and a native-part. It could be that the native-part is responsible for the exception.
See this question for more info.
Have you checked whether the target system is 64-bit or 32-bit?
It might be that one of your dependencies requires a 32-bit version of Windows. To solve the issue you can specify a platform target in the properties of your C# project: Choose x86 instead of Any CPU.