Using multiple DLL's written in C within a C# program - c#

I have a program written in C#. I want to use a DLL made in C within this program.
public class Test
{
[DllImport(#"C:/.../surcouche2.dll")]
public static extern int refreshEntities();
}
I call the function as:
Test.refreshEntities();
I am using Visual Studio. To create the DLL surcouche2.dll, I created a new Visual C++ Application Console, then I chose DLL and left the options on their defaults. Then, I told to VS to compile using C.
The function is :
__declspec(dllexport) int refreshEntities() {
int ret = 0;
LibData *n;
n = newLibData(LIB_MODULES_MODULE_ENTITES, LIB_MODULES_ACTION_SELECT,
"http://10.0.2.2:4242/WebService1.asmx");
if (n)
{
ret = n->refreshDb(n);
n->destroy(n);
}
return (ret);
}
The functions called in are in another DLL (that is referenced). But I get this error:
system.DllNotFoundException: Impossible de charger la DLL 'C:/.../surcouche2.dll': Le module spécifié est introuvable. (Exception de HRESULT : 0x8007007E)
à app.Lol.refreshEntities()
à app.MainWindow..ctor() dans c:\...\MainWindow.xaml.cs:ligne 30
But, if I change the function refreshEntities like this, then it works fine:
__declspec(dllexport) int refreshEntities() {
return (42);
}
The second DLL uses another DLL (both in C). I created them with the option "create an empty project" so I haven't the stdafx.h, ... files. I guess it's not a problem because I can use a function from the third DLL in the second one.

This error can happen if a dependency of loaded dll can't be resolved.
First of all I propose you to put both native assemblies in a bin folder and change a reference
from [DllImport(#"C:/.../surcouche2.dll")] to [DllImport("surcouche2.dll")]
In general to debug dependency issues tools like Dependency Walker and Process Monitor can be useful. First helps to understand what the dependencies are, second to check there your application is trying to find the assemplies.
Configure Process Monitor's to show process activity only and apply process name filter with your application name like on the picture below and you will get all files your app trying to access. It will help to find missing dll's.

[DllImport(#"C:/.../surcouche2.dll")]
This is bad idea, you are getting a preview of what is going to go wrong on your user's machine as well. Hard-coding the path to the DLL like that helps the pinvoke marshaller to find the DLL file on disk. But it does absolutely nothing to help the operating system to find DLLs that surchouce2.dll needs. Like the one that contains the newLibData() function.
The error message is often mis-interpreted. It says it "cannot load" surcouche2.dll. Which is accurate, but most programmers will read the message as "cannot find" surcouche2.dll. The most common reason for the exception. Not the problem here.
Never mess with DLL Hell. The days that keeping DLLs in a separate directory and sharing them between different programs was useful are long, long gone. Always copy dependent DLLs into the same directory as the EXE that needs them. Makes it very easy on the operating system to find them. And avoids the considerable misery you'll have to deal with when it finds the wrong file.
Use Project + Add Existing Item and select the DLLs. Set their Copy Local property to True. If you don't like the clutter then use XCOPY in a post-build event.

Related

Unable to load DLL in WPF C# application

I get following error message (VS2010) when running in debug mode my C# WPF appliction:
"Unable to load DLL 'VCECLB.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)"
The code where this error occurs is (see hDevEnum):
namespace Imperx.FLExGrabber
{
public class Enumerator:IEnumerator
{
private IntPtr hDevEnum;
VCECLB_EnumData enumData;
/// Default constructor
public Enumerator()
{
enumData.cbSize = (UInt32)Marshal.SizeOf(enumData);
// Open enumerator handle
hDevEnum = NativeFunctions.VCECLB_EnumInit(); <<--- Error message here!!!
}
/// Destructor
~Enumerator()
{
NativeFunctions.VCECLB_EnumClose(hDevEnum);
}
}
}
From the existing project, which uses a windows form application, it runs perfectly. Now I need to transfer this solution into a WPF-application. Therefore I am using the same machine (Win7/64ibt) with the same VS2010. The platform target is X64.
Question: Where I need to add the VCECLB.dll file into my project? I can not add it under references and therefore I put it into the folder "...\bin\x64\Release" - but no success.
When I check the VCECLB.dll with dependency walker I get following:
Does the question marks means that those dll's are missing? If so, why I can run the windows form project with the same VCECLB.dll?
Does anybody know how I can solve this issue?
Thanks in advance
There are two common causes for such an error:
The DLL that you are referring to is not on the DLL search path, or
The DLL that you are referring to is found, but its dependencies cannot be found.
Resolve problem 1 by putting the DLL in the same directory as the executable. Resolve problem 2 by making sure that all dependencies are installed. Typically this involves deploying the MSVC runtime that the DLL depends upon.
You can put your VCECLB.dll any where in your solution (in root for example by Drag & Drop)
Then, once you added the file, click right on your file, choose properties
In Advanced three:
Choose content in Build Action
And Always copy in Copy to output Directory
to get something like the follwing:

Import and use C++ DLL functions in C# application

I am developing an application that communicates with some hardware using the C++ DLL provided by the hardware provider. I also have a header file for this DLL, but no source file. In my C# application, I'm trying to import and call the DLL's functions like this:
public class MyClass
{
[DllImport("CaGe.dll")]
public static extern long someLibraryFunction();
public void callLibFunction()
{
Console.WriteLine("function call: " + someLibraryFunction());
}
}
The library.dll file is located in the same folder as the MyClass.cs file and also the rest of the project files. When I start the debugging session however, I first receive a dialog window from system saying: CAGE InitDll: Erro on load library "CdbClientInit" and after I click OK on that, an unhalted exception on the line where I call the library function occours.
The exception says: System.DllNotFoundException: Exception from HRESULT: 0x8007045A
I found on the internet that this may be caused by a missing DLL that the CaGe.dll needs, so I tried to put the DLL through the Dependency Walker, but the results are a little bit confusing for me. Under the CAGE.DLL there are WS32_32.DLL, VERSION.DLL, KERNEL.DLL and USER32.DLL tabs, I susspect that the libraries I need are somwhere under the USER32.DLL tab, but I don't recognize any of them (if a missing DLL is what is causing this problem).
Any advice would be much appretiated :)
More help to use C++ function in C# please check below URL
http://www.codeproject.com/Questions/107152/Using-a-C-dll-in-a-C-application

Launching C# WPF from Java causes FileNotFoundExceptions

I have a existing Java Project which needs functionality from a SDK written in C#. It should open a WPF Window and send the information back to Java on close.
For a basic connection of those two worlds i created a Java Project ("DotNetCaller") calling native functions. These are implemented in a C++/CLI Project ("DotNetBridge") which calls the C# Project ("DotNetApplication").
I already can set Strings from Java in C# and callback from C# to Java.
But as soon as i add a WPF Window and try to launch it with:
Application app = new Application();
app.Run(new DotNetWindow());
in a STA Thread it crashes.
The DotNetApplication doesnt find mscorlib.resources, after i provide the DLL, PresentationFramework.resources is missing and if i provide that, the DotNetApplication.resource is missing (which i cant provide).
If i call the DotNetApplication alone or from the DotNetBridge the Window displays as expected.
Can anyone tell ma what i'm really missing here?
Thanks
Edit:
I looked at this example once more and tried to adapt it to my needs.
I have set the dll directory of the ResolveEventHandler to the .NET dir in "Referenced Assemblies"
C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework.NETFramework\v4.0
and added a Window in C#.
It failed aswell but with a new exception in the C++ part rather than C#.
The ResolveHandler gets called with an empty argument causing an uncatchable exception in mscorelib.
I added a check if the String is empty and this basic approach works fine now.
I'm still unsure if i have the correct approach for this, so feel free to contribute.
Your AppDomain::AssemblyResolve handler probably needs to be overhauled and based on your own understanding of what you want to do. There is some guidance here. The basic rule is that you return nullptr for requests that you can't handle.
But first you have to plan the locations in which you want to deploy (and/or debug) your assemblies. A simple layout would be to put all of the assemblies that your JNI DLL depends on in the same folder as the JNI DLL (with the exception of any that will be installed in the GAC). You can then use its location to satisfy resolution requests. But remember to return nullptr if no file containing a manifest for an assembly with the requested name is present there. (This is likely the case with your ".resources" requests. If there isn't one it's okay unless you know otherwise.)
I'd be a little surprised if an assembly in a Reference Assemblies folder wasn't also in the GAC—but it'd be up to the assembly provider. Reference Assemblies is for design and build tools (e.g. Visual Studio). (The old way was for each folder that had assemblies in it to be registered for each version of Visual Studio so the assemblies could be used for design and build.) If a dependency is not in the GAC, you can use the "Copy Local" property on the reference to make it available for debugging.
You might find the Assembly Binding Log Viewer useful while designing and troubleshooting. With it you can see all the folders and extensions that are tried before giving over to calling the AppDomain::AssemblyResolve handler chain. (Disable logging when you are done.)

Using DllImport to load unmanaged dll into managed application

In my project I have an unmanaged native C++ dll and a C# application. I am trying to import a function from the unmanaged dll using DllImport but I keep getting a DllNotFoundException.
Here is my code that calls the DLL.
using System.Runtime.InteropServices;
namespace TestApp
{
public delegate void UpdateDelegate(string s);
class Program
{
[DllImport("CGPUnmanagedLibrary.dll")]
internal static extern int parse_raw_gsod_file(
[MarshalAs(UnmanagedType.LPStr)]
string filePath,
int minTemp,
UpdateDelegate callBack);
static void Main(string[] args)
{
UpdateDelegate myCallBack = new UpdateDelegate(Program.Report);
string path = #"C:\Creative Solutions\Projects\Clyde's Garden Planner\Frost Data Database\GSOD Data\GSOD_RAW_DATA\1992\gsod_1992.txt";
int result = parse_raw_gsod_file(path, 32, myCallBack);
Console.Write("Parse completed with exit code: " + result.ToString());
Console.ReadLine();
} // end main function
public static void Report(string msg)
{
Console.Write("Message is ");
Console.WriteLine(msg);
}
} // End class
} // end namespace
I tried copying the DLL to the app output directory but it still can't find it. I also tried adding the DLL project as a reference but I get a popup window saying it can't be added. How do you properly link an unmanged DLL to a managed application?
Update - Here is the full error:
Unable to load DLL 'CGPUnmanagedLibrary': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
Update 2 - I know for sure that the DLL is in the same directory as the .exe trying to load it. This makes me think there is a dependency in the DLL that isn't getting loaded. I'm only using basic C++ libraries in the DLL (string, math, iostream, etc). Any ideas what could not be loading and why?
Update 3 - Tested with Dependency Walker
Loading my unmanaged C++ DLL in dependency walker showed no errors. I also tried to open my executable in dependency walker and it showed errors loading two DLLs: GPSVC.DLL and IESHIMS.DLL - doesn't make any sense because I am only using standard c++ libraries in my code. I think it may have something to do with the fact that I have a managed C++/CLI DLL trying to load the unmanaged DLL as well (I was trying to implement some C++/CLI wrappers). Anyway, I have since started a new VS solution and moved on. See my answer.
In all likelihood the problem isn't the DLL you're trying to load but one of its (chained) dependencies. Run depends.exe or a similar utility on the DLL to see if all the dependencies can be found. The misleading message "The specified module could not be found" has become a classic annoyance (if not FAQ material!): it leads you to think that your DLL is not being found when almost all of the time it's one of its dependencies that's not being found.
To test, the *.dll needs to be in the same directory as the .exe that is trying to load it. Don't trust Visual Studio to do it for you at this point. Physically copy the file to C:******\Debug\x86\bin\ or whichever configuration you are running under. If in doubt, copy it to all of your bin folders. After you figure out the path, then you start finding ways to automate the project build to copy the file correctly. If that doesn't do it, put it in system32--it will certainly find it there. However, if after doing these things, you still can't find it. There is probably a dependency to your unmanaged dll that is also missing.
First I want to thank everyone for their help. Unfortunately I never did solve this issue (see edits in my main question). The answer turned out to be starting a totally new Visual Studio solution and creating two new projects: C# app and C++ dll. I did away with the need for wrappers as I am now just marshaling two main functions.
Thanks again.
The anwer of user arayq2 made much sense and I was quickly able to solve my problem also.
The dll that couldn't be loaded (DllNotFoundException) in my case is depending upon another dll. This dll (that is not part of my project) was actually compiled with newer versions of certain .h and .lib files. Older versions of these .h and .lib files (with the same filename) were part of the project that compiled the dll that couldn't be loaded.
After I updated my dll project with the newer versions of these .h and .lib files and recompiling my dll project, my problem was solved.
Thank you arayq2!

Problem loading UserControl with DLL reference in Design View

I have a C# project with a UserControl in it.
This user control depends on a particular C++ Mixed mode dll which in turns, acts as a facade to an unmanaged C++ DLL
C# C++ Mixed C++ Umnanaged
[ main app ] ---> [ myUC ] ---> [ OCShell.dll ] ---> [ OCC.dll ]
In the Design View, I cannot add the UserControl. It says that there is a FileNotFoundException on OCShell (or one of its dependency). However, via code, everything works fine. In main app (windows form) I can
myUC uc = new myUC();
this.Controls.Add(uc);
and this works fine. The right code gets executed properly.
I checked with Dependency Walker and everything is ok. Everything gets properly copied to the Bin\Debug\ directory and each of those DLL sees each other.
My guess is that the Design View Editor does not check the proper paths for those DLL and thus returns an error.
I also tried copying every dll to every possible directory in my solution but that didn't help either
Yes, that's a problem. At issue is that the code is executing in Visual Studio, not your app. The probing path that's used to find dependent assemblies will only include private directories of VS (Common7\IDE\PrivateAssemblies and PublicAssemblies), not the build directory of your project. You can make it find OCShell.dll by copying it into one of those directories, but the unmanaged DLL is going to have to be put in a directory that Window will search when looking for DLLs. Which, other than the Windows side-by-side cache which requires a manifest, is limited to a directory on the system PATH environment variable.
These are not pleasant options. The best thing to do is to ensure that the code in these DLLs cannot execute at design time. You do so by using the DesignMode property, bypass calls if it is True. That needs to be done in at least the constructor and the Load event. Other events can run as well. Also greatly minimizes the odds that you'll crash Visual Studio because of a bug in the unmanaged code. If this impacts the design-time view of the control then you may need to write a designer to make up for that.
I had the same problem. If you have a DLL, that uses many other DLL's, and probably written in C++, it often requires many other dependencies. In runtime, they get resolved perfectly, but not in Design mode.
Using Hans Passant's answer, you need to put this code in front of every function call, related to this DLL.
if ( !DesignerProperties.GetIsInDesignMode(this) )
I had 2 Connect() and 2 Disconnect() calls from my DLL, and after I put this before every occasion, the Designer could now perfectly load the layout for the UserControl. Thanks for the solution.

Categories

Resources