Identifying problematic dependencies in C++/CLI project - c#

My application compiles fine, but I get the following runtime error:
System.IO.FileNotFoundException was unhandled
HResult=-2147024770
Message=Could not load file or assembly {Wrapper} or one of its dependencies. The specified module could not be found.
The reference to Wrapper in the calling Application looks correct. The Wrapper dll exists in the correct location.
This project used to build and run on someone else's system, I saw it demonstrated several times. That person/computer is no longer available. Some paths of some dependencies have changed since the last time it was successfully built and run, I have fixed all compile errors related to this.
Just to clarify my project structure:
Digraph G
{
App [ label = "My C# Application"]
Wrapper [ label = "C++/CLI Wrapper"]
Lib [ label = "C++ Library"]
Dll [ label = "My helper C# DLL"]
CDep [ label = "Series of deep C++ dependencies managed \n by CMake for Lib, hard coded relative paths for Wrapper."]
App->Wrapper->Lib->CDep;
App->Dll->Wrapper->CDep;
}
Wrapper is a C++/CLI wrapper around a C++ library. The error is triggered when we try to load a class in the Application that has a using statement for the Wrapper.
Wrapper does have a lot of dependencies, but the error message does not indicate which dependency is problematic. This is a large, complicated system, most of which is built by other teams. The C++ components use CMake to get all the dependencies correct, but CMake does not natively support C#.
I tried using fuslogvw to find the binding error, but it showed me absolutely nothing until I changed settings to include all binds, and then it only showed successful binds.
http://msdn.microsoft.com/en-us/library/e74a18c4(v=vs.100).aspx
The paths are long, but not over 256 characters.
I had a warning in the compile for Dll (see graph above):
Warning 1 There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "{cli_wrapper.dll}", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
In Configuration Manager, the Dll is building for Platform "Any CPU" and Wrapper is building for "x64". I changed the dll to x64. I still get the runtime error.
Could not load file or assembly or one of its dependencies
Performed a clean, deleted build directory contents. No change.
Re-opened Visual Studio. No change.
Tried changing assembly name, default namespace, and project name to match. No change.
Could not load file or assembly 'xxx' or one of its dependencies. An attempt was made to load a program with an incorrect format
I believe we have to compile for 64 bit. We are dependant on a 64 bit C++ library.
Could not load file or assembly ... The parameter is incorrect
I am local administrator.
How to enable assembly bind failure logging (Fusion) in .NET
Tried the registry settings, but they appear to just be fuslogvw settings. No improvement in available log data.
Many other similar questions had ASP or service install specific answers.

I found the problem. There was more than one version of the library available to me, and I was using the include files from one version and the compiled library of the other. Dependancy Walker was key to finding which library had the problem, and if Aschratt had posted that as an answer rather than as a comment I would have accepted his answer.

I had the same error with a similar project earlier this week. First, when using C++/CLI, "Any CPU" doesn't exist. I had to build both for x86 to get through things.
Also, though my wrapper's dependencies were satisfied, it's the wrapper's exception that is caught by the CLR so it claims that the wrapper is missing a dependency. I was actually missing a dependency for the C++ DLL my wrapper wrapped (in my case, it was just a matter of forgetting to drop SDL2.dll and OpenAL32.dll in my new "Release" configuration output folder... I'd previously only worked with the Debug configuration where I'd already dropped those DLLs.
If you're positive you've got your wrapper's dependencies worked out, I'd recommend using Dependency Walker to check out the native DLL's dependencies. You could use Assembly.GetReferencedAssemblies with an outside script/program to double-check your wrapper as well (or ILSpy: http://ilspy.net/).
Last but not least, take a look at this: http://www.codeproject.com/Articles/442784/Best-gotchas-of-Cplusplus-CLI. He details the first two recommendations I made as well as some others.
Good luck!

One alternate root cause I've been running into quite a bit later, is that the application I'm working on uses impersonation, and the impersonated user does not have permissions to the GAC or to the folder that some dlls are in. You need to either give that user permissions, or change the way you do impersonation to load the dependencies before impersonation starts.

Related

loading multiple.net assemblies with same AssemblyVersion from a plugin

I'm in dll hell.
I'm building a plugin for a huge, ancient and very powerful software suite called ANSYS. They have a plugin framework. I had hoped that they would magically handle everything for me via AssemblyContexts or AppDomains or some other clever dotnet device that I don't understand. They do not.
The result is that I've created an application that depends on GRPC.core 1.16.0 via nuget. I wrote a little application that drives my plugin with a winform host. It loads and works perfectly, finding my library in ~/myproject/bin/debug/grpc.core.1.1.16.dll that exists right beside the class-library that is my plugin, no problem.
When I run my plugin in the ANSYS process space, which happens to also depend on grpc 1.0.0.0, the linker finds C:\Program FIles\ANSYS\...\WIN64\grpc.core.dll. No Good.
One odd thing about the Nuget GRPC package is that it adds a reference with a "reference version" of 1.0.0.0, where most other nuget packages have their reference version match the nuget package version. If i manually change the reference version the compiler wont find the library.
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad">
<HintPath>..\packages\Grpc.Core.1.16.1\lib\net45\Grpc.Core.dll</HintPath>
</Reference>
edit: the key is in the above line. The Nuget published Grpc.core artifact is at AssemblyInformationVersion=1.16.1.0, AssemblyFileVersion=1.16.1.0, AssemblyVersion=1.0.0.0. I logged this as a request against GRPC. More Below.
Thus I need to tell the runtime linking facilities not to use grpc.core...dll found in ANSYS's own binary directoryWhats more, there is exactly one dll (and its dependents) that I wish to load from my parent processes context: and that's ANSYS API dlls themselves, which are probably already in the GAC. In my project I've included this as a non-nuget reference with "build action: do not copy" selected.
So my questions:
is there something simple and easy I can do at runtime to tell the runtime-linker "when somebody loads a type from an assembly you think should be grpc.core, do not load 1.0.0.0, find 1.16.0.0 exactly"?
the runtime was already matching the needed library by "strong
name". The problem is that the 1.16.0 is a misnomer. That version
string was informational, but the assembly itself was version
1.0.0.0. Fusion was loading the library I wanted by exact match already.
is there something smarter I can do with appdomains or contexts or another C# device to explictly enter some kind of nested scope? Could I go so far as to log this as a bug in ANSYS's API?
I've tried digging into this myself, but I'm not a dotnet expert and finding out whether I'm looking at a nuget package configuration option --which isn't relevant to me, or an old-fashioned dotnet runtime option, has been very tricky.
update 1:
I've tried using AppDomain.CreateDomain, and it does indeed solve my problem, but it also requires me to provide a marshalling strategy for the already-loaded API objects. In other words, if you're programming against a plugin framework that has an api similar to:
public void DoMyPluginsFunctionality(ApiProvidedInputContext context){
var myPlugin = AppDomain.Create(
strongName: "MyCompany.MyPlugin.; Version=1.2.3.4 ...",
baseDirectory: "C:\\Program Files\\MyPlugin\\bin"
)
//success! MyCompany.MyPlugin loads the version of GRPC I want!
myPlugin.unWrapAsDynamicProxy().doFunctionality(context)
//error: No marshalling strategy and/or not serializable and/or swizzling errors
}
Then the runtime will require you to marshall (serialize) the context variable, because .net will not let you share memory across AppDomain boundaries.
So my new question:
- given I cant use AppDomains myself
- given that Grpc.core is always published as AssemblyVersion=1.0.0.0
What are my options?
Stop using newer features of GRPC.core and live in fear of my parent processes dependencies
use a strategy similar to shading. Is there something like shading in the .net world?
Edit the published binary's version metadata. Can I dynamically edit a published binaries version?
rebuild GRPC myself with the version string updated --effectively a private fork of GRPC.
update 2:
The GRPC build system seems like its quite large and well maintained, so I'm hoping I can simply build it and change a vcproj file to include an updated version string.
Unfortunately it also seems quite complex, and I haven't quite got the targeting/cross-compiling (x64 targeting x86) worked out.

How to sign C++/CLI Project to use it in C# Signed Solution?

I am using VS2012. I have a C++ Native Library and a C++/CLI project that I built to wrap the C++ Native library. I am bulding the projects for x64 bits.
I don't have much experience with C++ or C++/CLI, this is the first project I am trying to sign.
How I signed my C++/CLI project:
I placed my strong name in the same folder where the C++/CLI is located and then I went to:
Right Click on the project -> Configuration Properties -> Linker -> Advanced -> Key File.
I wrote the name of my file in the Key File attribute: StrongNameKey.snk.
It builds without errors and I can run the tests. I also have another Solution that uses the resulting dll, and it builds fine and the test pass. But that solution it is not using signed assemblies.
The Errors I am getting:
I have a C# Solution with all its assemblies signed.
At first I was using my C++/CLI dll in this solution without signing it, and it was mostly working. But I was getting an error similar to this when trying to use one of the Wrapper classes in a ComboBox in WPF.
That post made me realize I had forgotten to sign the C++/CLI assembly.
So then I signed them as I described above, but when I tried to use the dll in my C# Solution I was getting a lot of errors. None of them seemed related to my dll, except 2 warnings.
First Warning
Warning 18 There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "MyNamespace.MyCppCLI", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project. MyTestApp
I don't have anything set as AMD, I just have it configured to x64. My C# Project is configured for AnyCPU.
Second Warning:
The error said like there was 2 different locations of the signature.
I was using the same "name" both for the C# and the C++/CLI signature (the files were copies). I changed the name of the C++/CLI signature, and built the project again. And now the C# project builds, but I am still not able to use the class in the ComboBox and the designer throws the error of the other post, except that the public token is not null.
I don't know what I am doing wrong.
What are the correct steps to sign a C++/CLI Project? Where should I place the signature file?

Assembly being copied local when it shouldn't be

Here's my sample scenario. I have a Console application and a class library dll (call it libraryA). The LibraryA dll has a reference to Oracle.DataAccess.dll version 4.112.2.0. The Oracle DLL is in the GAC. The reference to the Oracle DLL in LibraryA is "Copy Local = false." So far so good. If you build the libraryA dll, then Oracle.DataAccess.dll does not show up in its output directory. OK. Now I reference the libraryA dll in my console app. The reference to libraryA dll is "copy local = true". Now, when I build the console application, the Oracle.DataAcess.dll does show up in the output directory for the console application. However, it appears that the ONLY DLL that acts this way is the Oracle dll. Here is the complete code from LibraryA
public void Foo() {
Oracle.DataAccess.Client.OracleConnection c = new Oracle.DataAccess.Client.OracleConnection();
WebMatrix.WebData.OAuthAccountData x = new WebMatrix.WebData.OAuthAccountData("asd", "asd");
DevExpress.Web.ASPxCallback.ASPxCallback cvv = new DevExpress.Web.ASPxCallback.ASPxCallback();
}
WebMatrix and DevExpress are also in the GAC just like the Oracle DLL. However, neither of those DLLs are output to the output directory, only the Oracle dll. Why? What's happening here?
For that matter, you can create another class library, call it libraryB, DON'T put libraryB in the GAC, reference LibraryB from LibraryA and set copy local = false. Even when you do that, libraryB is not copied to the output directory of the console app. Of course, in this case, the program blows up because it can't find library B, but at least Visual Studio is respecting the copy local flag = false. What is different about this stupid Oracle DLL?
Oh, one other thing that's funny. If, in my console application, I explicitly add a reference to the Oracle.DataAccess.dll, and say copy local = false, then it doesn't show up in the output directory. It seems kind of hilarious that to not have a DLL show up in the output directory, I have to actually reference it :)
Edit:
Another clue. Oracle, in order to torture developers, do not have one DLL built for AnyCPU. They have an x86 and and an x64 version. In my case, I am referencing an x86 version and building for AnyCPU. However, if I build for x86 (to match the oracle dll), then the Oracle DLL is not copied to the output directory. when building in AnyCPU, MSBUILD says:
"warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "Oracle.DataAccess, Version=4.112.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342, processorArchitecture=x86", "x86". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project." So, it almost looks like Msbuild is ultimately deciding that, ok, you have a mismatch, so let me go ahead and copy this dll to your output directory, thereby guaranteeing that your application will blow up. :)
By not referencing it, you are letting it use implicit rules. Well, the implicit default here is "copy it local", because most dlls are not in the GAC. The IDE has the crazy notion of defaulting to "make it work", which means "assume it isn't going to be in the GAC".
If you want to use explicit rules, then yes: you need to tell it what you want. And the way you do that is by adding a reference, and then by setting the options you want.
After a good amount of investigation on what seems to be the same issue in a solution I work on, we've found that this issue appears to be caused by a new check which was introduced with the release of .NET 4.5, as mentioned here: at build time, references are now being checked to make sure that their processor type matches that of the projects.
While previously we didn't see any such error in the build log, on affected machines we now see a message indicating that the projects are building for MSIL and the DLL is built for x86 - rather than making available one DLL built for all CPUs, the third-party creator provides two separate DLLs for x86 and x64, both of which are in our GAC. Prior to this check being introduced, the system would use the DLL from the GAC and select the appropriate version, but it seems that after installing .NET 4.5, the build process is determining that neither version in the GAC is acceptable so it's pulling in a local copy.
We have not been able to identify any way to disable this behavior, so our resolution options are going to have to be to either just add a post-build event to delete the local copies, or (as mentioned in the question) to add references to the problem DLL to all projects which reference our "Library A" and then set those references to "copy local = false", which seems to also prevent copying a non-working local version into the output.

External component has thrown an exception from third party assembly

We use a 3rd party mixed mode assembly that interfaces with a printer device.
In one of our applications, the assembly functions correctly.
In another application, it was generating the following exception:
Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.
After doing some research, I discovered that I could add the following to the app.config file to resolve this problem:
<startup useLegacyV2RuntimeActivationPolicy="true">
(The application that works already had this setting in its app.config)
Although this did resolve the "Mixed mode assembly" issue, now I'm seeing a somewhat different problem:
External component has thrown an exception
The strange thing is that I have one application which works correctly and another application which does not. They both call the third party assembly via the same code (which is another one of our assemblies).
I tried creating a very simple test app which calls the third party assembly using the same code path, and it also fails with the "External component has thrown an exception" error.
I've compared the app.config files for all of the applications and they are essentially the same, and I've double checked that all of the build settings are the same for each. Both projects target .NET 4.0 and X86.
There is obviously something different about the two applications but I'm at a loss to identify what it is.
Development environment is Visual Studio 2010.
Does anyone have any suggestions on what other areas I could investigate?
#tsells was right: there was a missing dependency
The third party assembly in question depended on another DLL that was present in the first applications bin folder.
I copied all of the files from the working application's bin folder to the non-working application's bin folder, and it resolved the problem.
From there it was just a matter of deducing which DLL was missing and including it in the second applications project.
When there are dependencies missing, you can use tools like CheckAsm for managed and Dependency Walker for unmanaged libraries to check for dependencies.

Referencing external assemblies from PowerShell snap-in

I'm developing a custom PowerShell snap-in, which references another project in the solution.
When I try to debug the snap-in (following [these instructions][1]), the assembly fails to load and my cmdlet fails with the message "Could not load file or Assembly..."
How do you instruct PowerShell on how to locate assemblies, or how do you specify where are located the assemblies needed by the snap-in?
I'd prefer to avoid registering the assemblies in the GAC, at least during development.
Not sure of the exact behaviour, but I would try and make use of fuslogvw to see exactly where the runtime is looking for the problematic assemblies. That would give you a clue as to how to get them to be copied into the correct place on build. This post by Scott Hanselman is quite useful, and this is the official documentation.
If you find the solution, please add an answer, as this must be a common scenario.
SOLUTION (Posting it here as suggested by one of the comments to my question)
My problem was rather specific, as I'm developing on a 64 bits server machine, but I'm posting the solution in case it could help someone else as well.
Using fuslogvw as suggested, I saw that the dependent assembly was being searched using the machine.config file under C:\Windows\Microsoft.NET\Framework64 and then the binding failed; launching the project with "start without debugging", instead, the machine.config file under C:\Windows\Microsoft.NET\Framework was taken (notice the missing 64 at the end).
I thought that the problem could be due to the image format, and infact the dependent assembly was being compiled with x86 as CPU target; I changed it to "Any CPU" and now the assembly is loaded correctly.

Categories

Resources