VisualStudio unit test doesn't find my DLL with P/Invoke. How can I fix this? - visual-studio

I'm working on Windows 7 with Visual Studio 2008.
I have a .NET assembly that makes calls into a native DLL with P/Invoke. I have set up a separate .NET unit test project in my Visual Studio solution that tests the assembly by making various calls into it. However, when the unit test makes a call into the assembly, and the assembly makes a call using P/Invoke, it can't find the native DLL.
When I write a standalone .NET console application, there is no problem. The assembly can use P/Invoke and find the DLL successfully.
I can make the unit test work by calling LoadLibrary with the absolute path of the DLL before using the assembly. However, this approach is ugly and requires an absolute path - which will be problematic for other users.
In short, my question is - how can I specify or amend the DLL search path that is being used when a Visual Studio unit test is being executed?
Any help will be greatly appreciated.
Regards,
Dan

It sounds like the problem is that your native DLL is not being deployed with your unit test DLLs. This is not an uncommon problem since managed DLL's have no reference to native ones in metadata and hence deployment packages don't know to deploy them.
The most appropriate solution is to fix deployment as opposed to changing the DLL search paths. This is a unit test specific problem though. Can you tell us what framework you're using so we can help you out?

If you are using the Visual Studio 2008 integrated testing framework, you should check out the DeploymentItemAttribute Class
Basically you just decorate your test method with this attribute and it automatically copies the deployment item into the output directory before the test executes. You can even copy a whole tree of dependencies using this. It supports variable expansion and relative paths.
Also please see How to: Configure Test Deployment for more generalized information on VS2008 test deployment.

My solution was adding a post build command to my test project as follows:
xcopy /Y /S "$(SolutionDir)\ShredLibraries\*" "$(TargetDir)"
this is explained in msdn docs:
https://msdn.microsoft.com/en-us/library/ms182475.aspx

Related

What is the .exe file that VS generates via .NET Core self-contained deployment?

[I'm using Windows conventions for convenience but this is an x-platform question.]
When I publish a .NET Core project (named, say, Tannery) via SCD, Visual Studio generates the application file publish\Tannery.exe, which is my entry point into publish\Tannery.dll. In addition, from what I've tested, publish\Tannery.exe automagically works with any config/build of Tannery.dll [on the target runtime].
This suggests Tannery.exe is just a thin wrapper around dotnet.exe and tantamount to dotnet Tannery.dll. However, I can't find documentation on this. So, what "is" this application file, and how flexibly can one use it?
When you use SCD you build your project for a specific runtime (e.g. windows x64), the build would include all the dotnet dependencies, so when you run your SCD on a system without the dotnet SDK, it will run without problem.
You can think about it as a wrapper around dotnet.exe, where the dotnet.exe is part of the build and not a system dependency.

Visual Studio and Nuget based Test Runners/Adapters

Recently I came to know about the nuget based adapter/runner (http://xunit.github.io/docs/running-tests-in-vs.html)
I was trying to understand how these runners/adapters are recognized by Visual Studio and then used by the TestWindow.
For example, if I install "xunit.runner.visualstudio" nuget package all the xUnit based tests in my project are discovered and displayed in the Test Window.
I am trying to understand how does VS hook the Test Discovery using the package installed in packages folder?
Where/how do VS and nuget based adapter get hooked?
I tried finding this information but my google fu failed me. :(
I checked answer for the question (Custom test adapter installed via NuGet isn't discovering tests) and it does say that VS copies the packages to the path %TEMP%\VisualStudioTestExplorerExtensions but that's pretty much it.
Since this involves a lot of how VS works internally, I don't think you'll get a totally definitive answer. However, to solve the issue you linked to I looked at a bunch of disassembled code, so I have a pretty good idea. Here's how it seems to work:
You build a project that references a package named Sample.TestAdapter
VS copies Sample.TestAdapter directory from packages to %TEMP%\VisualStudioTestExplorerExtensions
Something triggers test discovery - rebuild always does, sometimes incremental builds do too. vstest.console.exe is useful here for debugging.
VS launches vstest.discovery.exe which looks in VisualStudioTestExplorerExtensions for an assembly that implements ITestDiscoverer
If an ITestDiscoverer is found, VS calls it with a list of assemblies that may contain tests
Tests that are discovered are sent back to VS by your test adapter
So, as far as I can tell it's a pretty simple reflection based plug-in architecture. Hope that helps.

System.IO.FileNotFoundException when trying to load DLL

I'm not a a very experienced Windows developer, so I hope this all makes sense.
I created a Managed Assembly DLL using Visual Studio 2010. The DLL (Plip.dll) contains a C++ class that is using System.IO.SerialPort class to do some simple communication over a serial port.
In a second Visual Studio project I created a simple GUI that uses the class found in Plip.dll. In my GUI project I have the line : #using "Plip.dll" . In the Project Properties I set the 'Resolve #using References' value to the correct location of Plip.dll. The GUI builds just fine. If I copy the GUI.exe and Plip.dll to the same folder, the GUI runs just fine on my computer.
The problem I am having is that when I copy both files to a second computer, I cannot get the GUI executable to run. I get the following error : "System.IO.FileNotFoundException. Could not load file or assembly "Plip.dll" Vesion=.... ". I get this error even though both the exe and dll are located in the same folder.
Any suggestions on how to resolve this issue? Is there some option I need to set in my GUI project to load the DLL correctly at run time?
I suppose the problem is not the Plip.dll, but it's dependencies.
Use Dependency Walker on the second computer to see if it needs any other dll's (they might be installed in System folder or in %PATH% on your development computer, but not on the other).
If this second computer doesn't have Visual Studio installed, you are probably missing Microsoft Visual C++ 2010 Redistributable Package (you need to install it on the other computer)
Also make sure that you compile in Release because debug builds need debug dependencies.
I found the answer to this problem to be much simpler than Dependency Walker (but admittedly, that was fun to look at).
In my case, the issue was a mis-match between the .DotNet versions in the DLL and with the application's .net version. This was caused by building the "class library" using .DotNet 6.0 (dot net core?).
Instead, the entire class needed to be re-built using "Class Library (.NET Framework)"
enter image description here
I wrote an article on this problem.
https://keyliner.blogspot.com/2022/09/visual-studio-c-linked-dll-exception.html

NUnit tests in a separate project, same solution

I have a solution containing my main project and a test project using NUnit. Everything compiles but when I run NUnit I get the exception below after the tests load, and the tests fail. I've added the main project as a reference, and I have $(ProjectDir)bin/Debug/$(TargetName)$(TargetExt) in the arguments for NUnit in the external tools setup, with a blank initial directory.
MyMainProjectTests.Database.TestAddDelete:
System.BadImageFormatException : Could not load file or assembly 'MyMainProject,
Version=1.1.1.0, Culture=neutral, PublicKeyToken=null' or one of its
dependencies. An attempt was made to load a program with an incorrect format.
TearDown : System.Reflection.TargetInvocationException : Exception has been
thrown by the target of an invocation.
----> System.BadImageFormatException : Could not load file or assembly
'ChickenPing, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null' or one
of its dependencies. An attempt was made to load a program with an incorrect
format.
After scouring for hours the only thing I've found is a bug in VS2005 which mentions the /bin and /obj directories, but the answer provided didn't help.
Any solutions?
Instead of setting up NUnit as an External Tool, I set the unit test project as the StartUp project. In the project's Properties screen, set the Start Action to "Start external program" and point it to nunit.exe. In the Start Options section, I specify the test assembly (no path necessary) in the "Command line arguments" box. At this point, simply press F5 to start up NUnit.
Use the nunit-x86.exe instead of nunit.exe as your runner.
A better longer term solution may be to buy ReSharper that includes a much nicer test runner for NUnit that fully integrates into Visual Studio. It auto detects your .NET project type (x68 or x64). ReShaper comes with tons of other features of which unit testing is just one. Their test runner also integrates with their DotCover code coverage analyser.
You may find that you'll need a later version of Visual Studio to use ReSharper. The latest version works with Visual Studio 2013 Community Edition that you can get for free though I understand you may have issues upgrading some project features from such a rather old VS2005 project.
I don't have any affiliation with ReSharper.
Are you running on x64? You will get that error if loading a x64 bit from x86 and vise versa. Also, the path you are trying to create should be the $(TargetPath) macro.
Just set "Platform target" of Tests project to "x86".
Is your main project a .exe or a .dll? Older versions of .NET couldn't reference an .exe, so that might be the problem.
In either case, I'd expect problems if the main assembly didn't end up somewhere accessible by your test assembly (for example, in the same directory). You could check that, and if not make it so, perhaps by having Visual Studio copy the referenced (main) assembly to the local directory.
The "An attempt was made to load a program with an incorrect format." makes me wonder if the "missing assembly" theory is right, but without more info, it's the best guess I can think of.
Go the the NUnit install (example: C:\Program Files (x86)\NUnit 2.6.3\bin) location and open nunit-86.exe.

DSL Tools: How to create the DLL as weak-named

I have a DSL Tools solution.
I need to add a weak-named reference to this project.
Because the DSL Tools project DLL is strong-named i cannot used the weak-named DLL.
I cannot make the DLL strong-named because i cannot recompile it.
I tried to make my DSL Tools project DLL weak-named by going to the Dsl and DslPackage project properties and unchecked the option "Sign the assembly" in the Sigining tab.
Then i compile it.
The error list gives the following error
"gacutil.exe" exited with code 1
Looking at the VS2005 output window i see gacutil is being called
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\gacutil.exe -nologo -i "C:\Academy\ResearchAndDevelopment\FrontendGenerator\DslPackage\bin\Debug\vantyx.FEGenerator.DslPackage.dll"
After that i used the command prompt and the gacutil.exe error displays as this:
Z:\>"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\gacutil.exe" -nologo -i "C:\Academy\ResearchAndDevelopment\FrontendGenerator\DslPackage\bin\Debug\vantyx.FEGenerator.DslPackage.dll"
Failure adding assembly to the cache: Attempt to install an assembly without a strong name
I don't know why and how gacutil.exe is being called.
I looked at the project and solution properties and there is no option configured to call gacutil.exe.
I even looked inside every file for "gacutil.exe" but i found nothing.
What i really want is to be able to use the weak-named DLL that i cannot make strong-named.
As a result of this, i've been trying to make my DSL Tools DLL weak-named but i can't.
Any help on how i can workaround this?
Many thanks in advance,
Luís Filipe
Using runtime binding with reflexion is a good solution and works. The other solution I've implemented besides that one is to launch a separate AppDomain and have that AppDomain doing the loading of the assembly and running whatever methods you want. The downside of this approach is the extra complexity and performance. One really has to know what he is doing as he is in practice launching a separate .net application in Visual Studio's process space. The upside is that with some care, you can get type safety all the way.
With the exception of the answer written above,
All add-ins for Visual Studio must be strong-named.
One may workaround some of the issues by loading the assembly on run-time and using reflection to invoke methods.
Regards,
Luís

Resources