Loading a 32-/64-bit assembly automatically - c#

My C#/.NET program compiles as AnyCPU, and references Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll, which is installed with Visual Studio (or Team Explorer). My program must run on computers without VS installed, both 32- and 64-bit, so I have to bring this assembly with my program. It currently runs on 32-bit computers, but not on 64-bit, since it can't load this assembly.
After build, in bin\Debug I get a 32-bit version of this assembly, which VS presumably takes from C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll. This is how the program works on 32-bit computers. But my program also runs as 64-bit locally, and the 32-bit assembly gets loaded, how can that be? To check, I wrote me a little PowerShell:
param([string] $path)
$AssemblyName = [Reflection.Assembly]::Loadfile($path).GetName()
write-output $AssemblyName | fl
And ran it as both 32-bit and 64-bit:
> powershell.exe -ExecutionPolicy ByPass -f .\f.ps1 Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll
(...)
CodeBase : file:///C:/windows/assembly/GAC_64/Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader/11.0.0.0
> C:\Windows\SysWow64\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -f .\f.ps1 Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll
(...)
CodeBase : file:///C:/windows/assembly/GAC_32/Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader/11.0.0.0__b03f5f7f11d50a3a/Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll
Ah, looks like VS installed the assembly to the GAC in both 32- and 64-bit, and the .NET loader knows to load the correct one.
My question: How can I simulate such behavior when I can't install VS?
Option 1: Compile twice as 32-bit and 64-bit, and then I guess I'd get the correct binary in bin\Debug. I'd like not to do that...
Options 2: Deploy these 32/64 assemblies to the GAC in the runtime machine. I'd like to keep my deployment to a simple xcopy...

I am not sure you can redistribute this assembly with your program since they are part of Visual Studio. At least you would need to look at what parts and how you can redistribute the Visual Studio SDK where this assembly is part of. See here and here.
They are also part of the TFS Object Model, but you can't distribute the assemblies from that package either. You can however ask users to download and install that before using your software. And it seems that they are 32 bits only, so you would still need to compile your application as 32 bits.
An alternative would be using the webservices directly. See here. You can call them AnyCPU without problems.

You can try installing the assembly in GAC programmatically by leveraging fusion API.
More details here: http://www.codeproject.com/Articles/8285/GAC-API-Interface

Related

AutoIt (AutoItX) on C# Windows 7 App System.DllNotFoundException

I have a C# application that uses AutoItX for automation. This application works fine in my Windows 8.1 x64 environment compiled with Microsoft Visual Studio 2013 release 3.
I pushed a copy of the app code to a bitbucket repository and cloned it to a computer running Windows 7 x64. AutoItX version 3.14.2 was installed and the 32bit calls were selected. The application was compiled using Visual Studio 2013 release 4.
The app compiled fine, but the first use of the AutoIt functions resulted in an error:
An unhandled exception of type 'System.DllNotFoundException' occurred in AutoItX3.Assembly.dll
I tried the following steps. The app was tested after each of these steps
Attempted to register the .dll manually using regsrv32
regsrv32 "C:\Program Files (x86)\AutoIt3\AutoItX\AutoItX3.dll"
Uninstalled VisualStudio 2013 R4 and attempted to reinstall VisualStudio 2013 R3 {The installation of R3 failed because it required internet explorer version 10 and version 11 has already been installed on this computer} so R4 was reinstalled
Uninstalled AutoIt and reinstalled selecting the 64 bit library preference. Compiled the app with x64 Platform option
Uninstalled AutoIt and reinstalled using the 32 bit library preference
Compiled the app with the X86 Platform option
Manually copied AutoItX3.dll to the C:\windows\System32 directory
Manually copied AutoItX3_x64.dll to the c:\Windows\SysWOW64 directory. Compiled the app for x64 platform
Wiped computer clean and reinstalled windows 7, AutoIt (32 bit preference), Visual Studio 2013 R4
Installed AutoIt v14
Installed the beta version of AutoIt v15
Performed a Windows update - 213 updates (!) installed
Installed Internet Explorer v11
Performed a Windows update - 4 updates installed
Installed AutoIt version 3.10.2 that worked on the Windows 8 system
I would appreciate suggestions on what to try next. I'm probably missing something very basic, but I just can't find a solution
Manually copied AutoItX3.dll to the C:\windows\System32 directory
Manually copied AutoItX3_x64.dll to the c:\Windows\SysWOW64 directory. Compiled the app for x64 platform
That's the only thing you did wrong, you reversed the copies. There are no other DLLs you could be missing, the AutoItX3.dll and AutoItX3_x64.dll files themselves have no other dependencies that are not already available on any Windows machine. Just operating system DLLs, they've been around forever. Something you can see with Dumpbin.exe /imports.
And the exception message comes out of .NET, it is caused by a [DllImport] attribute. You can see the content of AutoItX3.Assembly.dll with a decompiler like ILSpy or Reflector. There is very little to it, only two DLLs are ever used. AutoItX3.dll for 32-bit code and AutoIt_x64.dll for 64-bit code.
Fairly tragic btw, otherwise a side-effect of ab/using the operating system directories for non-operating system DLLs. The only real way to make sense of why this is backwards is to know the history of Windows.
Back in the early days of Windows when it was still a 16-bit operating system (versions 1 through 3.11), c:\windows\system was the home directory for the operating system executables. Starting with NT 3.11 and Windows 95, the first 32-bit versions, that directory was renamed to c:\windows\system32. When the 64-bit version became available, Microsoft could not rename it to c:\windows\system64 anymore. Too many programs hard-coded the name of that directory in their source code. Breaking those programs would have been a good idea, just not a good strategy to get customers to move to the next version.
The 64-bit version has an emulator that can run 32-bit programs, it is called WOW64. "Windows on 64-bit Windows". The c:\windows\syswow64 directory is therefore the home directory of the 32-bit executables.
Exactly backwards from what the names would suggest. Just reverse the copies and that runtime error will disappear.
Generic advice applies:
The official way to get the loader to tell you about missing DLLs is to enable loader snaps. It is the most reliable way, albeit a bit clumsy.
Dependency Walker has not been maintained for a very long time and produces far too many false warnings. It also has a problem with .NET programs like this, it cannot see the dependency on AutoItX3.dll. You should still get something out of it when you use its Profile mode.
Process Monitor was always the best tool to troubleshoot missing DLLs. You'll see your program searching for the missing DLL, you can tell its name and the directories it looks in from the trace. Start near the bottom working backwards to avoid drowning in the data. I should however note that its been unreliable lately on the machine I use since ~Win81, the trace is just missing stuff I know should have been there. YMMV.
Such an issue can be caused by a missing DLL or a dependency of a missing DLL. I never got good results with Dependency Walker but I have successfully tracked down such issues with Process Monitor.
It should not be a 32/64 bit issue directly, since that would result in a BadImageFormatException instead.
You can debug missing DLL issues like this:
Start Process Monitor
Set a filter for your executable
Reproduce the issue (i.e. run your application)
Save the log in XML file format
Open the XML in Process Monitor Log Analyzer (Disclaimer: I'm the author of that free tool)
Check from top down which DLL is really missing. There may be some where the program can gracefully degrade, so not all of them are necessarily required.
Short solution
Copy and paste the AutoItX3.dll file to /bin/Debug or /bin/Release folder.
Project solution
What you can do is to put in the project's Post-build event command line:
copy /Y "$(SolutionDir)\packages\AutoItX.3.3.12.0\AutoItX3.dll" "$(ProjectDir)\bin\Debug"
 
copy /Y "$(SolutionDir)\packages\AutoItX.3.3.12.0\AutoItX3.dll" "$(ProjectDir)\bin\Release"

Platform target x86 and x64 at the same time in Visual Studio 2012

I know how to change the Platform target of my C# project from here: http://msdn.microsoft.com/en-us/library/ms185328.aspx But my question is: Is it possible to target platforms x86 and x64 at the same time in visual studio 2012, so i will have two folders in my Debug directory like this:
Bin\Debug\x86(x86 dlls & exe)
Bin\Debug\x64(x64 dlls & exe)
So i always have the two platforms assemblies available on every build of my project.
EDIT:
using Any CPU: When build my application using "Any CPU" platform and run it on a 64-bit operating system, the process has the extension 32* in Task Manager which means that it is a 32-bit assembly not 64-bit
I tried to build my application using "Any CPU" and when i run it on x64 windows, i found that the process in Task Manager has the extension 32*
You are being confuzzled by the solution configuration name. It defaults to "AnyCPU" for managed projects in VS2012 and up. Which is a fairly accurate name, a .NET project can run on any CPU thanks to the jitter. These configuration names are however only relevant to native projects (C and C++), they pick the kind of compiler that is used to build the project. Since they get built straight to machine code, a different compiler is needed to generate x64 code.
You can select the kind of jitter that's used at runtime, a modern version of Windows is able to run both 32-bit and 64-bit processes. But that's an entirely different setting, it doesn't have anything to do with the configuration name.
Right-click your EXE project, Properties, Build tab. Ensure that the Platform target setting is AnyCPU, untick the "Prefer 32-bit" checkbox if you see it. That removes the jitter choice forcing, your process will now be a 64-bit process on a 64-bit version of Windows. And still run on a 32-bit version, thanks to the jitter. Repeat this setting change for the Release configuration.
Do beware that you'll have to test this, there are various subtleties involved, related to the file system and the registry views that are different depending on the bitness. Having to test both flavors is the one of the reasons why .NET projects default to 32-bit mode.

DLL load error in debug mode ,but release mode is ok

When I use the VS2008 to build my project, I use my own DLL. It works all right in release mode, but when I change it to debug mode, I get an error:
An unhandled exception of type 'System.DllNotFoundException' occurred in DDKWidget.exe
Additional information: Unable to load the DLL "DDKLibA.dll": The specified module could not be found.
The DDKWidget and DDKLibA.dll is my project excutable file and my self-created DLL.
I created my DLL in C++,but I use my it in my C# project, using [DllImport("DDKLibA.dll")].
My OS is Win7 64 bit.
My IDE is VS2008 SP1.
Did anyone encounter this before?
BTW, it was all ok some time ago, but recently, since I re-installed my OS, I started getting these errors. Can any one help me?
This sounds like a problem with 64-bit vs 32-bit mismatch. CLR applications by default get compiled for "AnyCPU" which means that they would automatically run as 64-bit processes on a 64-bit OS.
On the other hand, C++ dlls have to be compiled either for 32-bit or 64-bit and once compiled they stay that way.
You can force a C# app to run in 32-bit mode even under 64-bit OS but that setting can be changed independently for Debug and Release configurations.
My guess would be that your C++ dll is compiled as 32-bit and your Debug setting for your C# dll is also 32-bit but in the Release mode it is set to AnyCPU. That way it would runs as 64-bit process and will not be able to load the 32-bit C++ dll.
where in the filesystem is the dll located? Maybe you copied it to the same directory as your release exe, but forgot to do the same for the debug exe?
The only time I've seen this occur is when a dependent DLL is missing. For example, the release version of your assembly is dependent on foo.dll, but the debug version is dependent on foo-debug.dll. If foo-debug.dll is not installed on the target system, the debug version of your assembly can't be loaded.
I suggest you use a file monitoring utility such as FileMon to see which files the OS is attempting to load when your DLL is loaded.

C# Missing MSVCR100.dll

I'm developing an app that execute another app and I received this error:
the program can't start because MSVCR100.dll is missing from your
computer
with my C# app, can I fix this problem copying this .dll into windows/system32 folder?
Or exists another method to do this?
This links below point to the proper downloads for the MSVCRT100 installer. This is likely what you want your customers to run before installing your app. This will properly install the MSVCRT DLLs in the proper directory such that all applications can use it.
Microsoft Visual C++ 2010 Redistributable Package (x86) (probably what you need for 32-bit and 64-bit os)
Microsoft Visual C++ 2010 Redistributable Package (x64) (Only if your app itself is 64-bit)
If you actually want to install the MSVCRT100 DLLs through a merge module within your own MSI - you can link your MSI to the MSMs that are located in the x86 version your "c:\program files\common files\merge modules" directory" (Assuming you have Visual Studio 2010 installed).
C:\Program Files (x86)\Common Files\Merge Modules>dir *CRT*.msm
Volume in drive C has no label.
Volume Serial Number is 60A4-1718
Directory of C:\Program Files (x86)\Common Files\Merge Modules
04/22/2011 01:18 PM 584,192 Microsoft_VC100_CRT_x64.msm
04/22/2011 01:41 PM 571,904 Microsoft_VC100_CRT_x86.msm <-- This is likely the MSM you want if your app is 32-bit.
04/22/2011 01:14 PM 847,360 Microsoft_VC100_DebugCRT_x64.msm
04/22/2011 01:39 PM 801,792 Microsoft_VC100_DebugCRT_x86.msm
Two other alternatives:
Instead of copying MSVCRT100.dll into a system directory, copy it into the directory of the EXE app you are trying to launch that depends on this DLL. This isn't recommended, but won't run the risk of breaking other apps.
Another alternative. If you actually have the source code to the EXE that you are trying to launch, you can completely bypass all of this "install msvcrt100.dll" noise by just statically linking to it. In visual studio, it's the option in the project's propery dialog under C/C++ (under the Code Generation tab). Change "runtime library" from "Multi-threaded Dll" to just "Multi-threaded". This adds the /MT compiler switch.
Whatever program you're trying to start has to be properly installed first. Msvcr100.dll is one of the DLLs that need to be deployed for programs written in C or C++ with VS2010. It is simple with a Setup and Deployment project or by building the program with the /MT option. Contact the program owner for support.
what is missing is the Visual C++ runtime.
are you starting a C++ application from your C# code? if so, make sure the proper runtime is available on the client machines.
You should be able to fix this by copying it and registering it (with command line: regsvr32 "DLLNAME") or you can ship it with your executable and it should work
WARNING: Please consult the following article before including the file with your software... http://msdn.microsoft.com/en-us/library/ms235299.aspx
I take no responsibility for your actions

BadImageFormatException when loading 32 bit DLL, target is x86

I have a DLL (FreeType) which is certainly 32-bit (header: IMAGE_FILE_MACHINE_I386).
I want to use it from C# code, using DllImport.
Target of my application is x86, IntPtr.Size is 4, process is 32-bit.
But I get BadImageFormatException (Exception from HRESULT: 0x8007000B). What can be wrong?
Of course I use 64-bit Windows 7.
From what I understand, an assembly specifically built for x86 and running in a 64-bit operating system can only load libraries built for x86 or a BadImageFormatException will be thrown. In a 64-bit OS, an assembly built for Any CPU or x64 will throw the same exception when trying to load an x86 library.
So, assuming nothing incredibly weird is going on, I would ensure that you've set your application to build as x86 by opening the project properties and clicking on the Build tab. Ensure 'Platform Target' is set as 'x86' and not Any CPU.
Alternatively, you could try to find a 64-bit version of the DLL for testing purposes.
Recompile the dll with the option "Any CPU" in Build -> Platform.
OK, seems like a false alert. It was not related to bitness, there was just other DLL missing that freetype depends on. However error messages could be more helpful.
Got the same error when calling a 64-bit C Dll from C#. I had to manually change C# Properties->Build->Platform target from Any Cpu to x64. Apparently Any Cpu is sometimes NoCpu.
Besides, for web-application needs resolve to run 32-Bit Applications in IIS 7. See http://www.fishofprey.com/2009/04/badimageformatexception-in-iis-70-on-64.html
I had a similar error.
I could solve it by adding the ucrtbase.dll or ucrtbased.dll for debug as well as the vcruntime140.dll or vcruntime140d.dll for debug into the directory of the executable.
I think the 140 depends on the version number of Visual Studio you are using.
ucrtbase.dll usually lies in C:\Windows\System32.
vcruntime140.dll lies in C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Remote Debugger\x86\vcruntime140.dll
You can find more information here: http://blogs.msdn.com/b/vcblog/archive/2015/03/03/introducing-the-universal-crt.aspx
I suspect the common cause of this exception has changed in the 8 years since the question was first asked. On my setup using VS 2017 I found that unchecking "Prefer 32-bit" solved the issue:
Uncheck "Prefer 32-bit" in the Build options
This made my 64-bit DLL built from C++ load correctly. Conversely, checking this option should make 32-bit DLLs load correctly.
When you build a native application/DLL something with Visual Studio, it gains a dependency on the "redistributable" package for that version of Visual Studio. That contains DLLs like msvcr100.dll and msvcp100.dll (for various values of 100).
In my case, I had seen those DLLs in the target machine's Windows/system32 directory, so I thought all was well. It turns out that those DLLs were x64! I have no idea why a directory called system32 contains 64-bit DLLs. So I searched my Visual Studio 2010 directory for everything named msvc*.dll, and found x86 versions of msvcr100.dll and msvcp100.dll. I copied those to the target machine (in a place accessible from my program's path) and all was well.
I hope this helps someone else confronted with Microsoft's sheer madness.
you use Properties in C# project, and change "Platform target" to x64.
enter image description here
You can try check the option "Properties" -> "Build" -> "Allow unsafe code".
You have to look at the dependents of the DLL, since one of the dependents may use a 64 bit DLL which makes it incompatible with your project.
visual studio -> tools -> command line -> powershell
dumpbin /dependents your_dll_file.dll
and check these dll's and find out which one is actually not the same with your dll.
I had the same Exception in MS Visual C# Express 2010. I checked all build .dll and .exe files with Dependency Walker and MiTeC EXE Explorer, everything was build for 32bit!
In the end, it was the following line missing in my .csproj file:
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'MY_CONFIG|x86'">
...
<PlatformTarget>x86</PlatformTarget>
...
</PropertyGroup>
I don't know why it was missing ... I guess MS Visual C# Express 2010 is not bugfree ;)

Categories

Resources