This is how I use/import the DLL using c#. How do I do it on c++ project?
[DllImport(#".\x64\something.dll", EntryPoint = "somthng", CharSet = CharSet.Unicode)]
static extern int somthng(string input);
Provided that you do not have the development header and lib files available for the DLL and you need to dynamically load the DLL into your C++ project, then you can do the following.
Define a function pointer (equivalent to your extern declaration):
typedef int FnSomeFunction(const char* input);
Load the library (I'm using LoadLibraryA here to load an ansi-named DLL, this depends on your C++ project). The DLL must be in the search path, i.e. in the same path as the executable):
HMODULE hModule = LoadLibraryA("something.dll");
Check that the module is successfully loaded:
if (hModule == nullptr)
throw std::runtime_error("Lib not loaded");
Get the function entry point from the library:
FnSomething* fnSomething = (FnSomeFunction*)GetProcAddress(hModule, "somthng");
Call the function:
(*fnSomething)("some text");
Free the library when no longer needed:
FreeLibrary(hModule);
Related
I am trying to follow tutorial calling code from C++ into C#.
I followed the coding part correctly.
But when I run the code I get exception:
System.DllNotFoundException: 'Unable to load DLL 'SampleNativeLib': The specified module could not be found. (Exception from HRESULT: 0x8007007E)'
I create C# library as simple application file.
And C++ as dynamic .dll.
In the original tutorial (I also have full project file of it) in the C# project in the references there are no references to C++ .dll.
I would like to ask how C++ is referenced to C#?
The code of C#
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace ObjectPinning {
class Program {
[DllImport("SampleNativeLib")]
static extern int SetData([MarshalAs(UnmanagedType.LPArray)] int[] darray);
[DllImport("SampleNativeLib")]
static extern int DoCalc();
static void Main(string[] args) {
var data = Enumerable.Range(0, 10).Select(i => i + 1).ToArray();
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
Console.WriteLine(SetData(data));
Console.WriteLine(DoCalc());
Console.ReadLine();
GC.Collect();//Clean up any garbage object
Console.WriteLine(DoCalc());
handle.Free();
}
}
}
The code of C++:
// SampleNativeLib.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
int* g_pData;
extern "C" __declspec(dllexport) int WINAPI DoCalc() {
int sum = 0;
for(int i = 0; i < 10; i++)
sum += g_pData[i];
return sum;
}
extern "C" __declspec(dllexport) int WINAPI SetData(int* data) {
g_pData = data;
return DoCalc();
}
My project file:
Download
Teachers File:
Download
My file
Teacher File
The exception you get is most likely because you didn't add the dll to the C# executable path. In the first step the application searching the dependencies in the exe directory, if not found, then it goes through the Window environment variables. That is why we don't need to copy the dlls when we use some of the Windows API function, because if you look at at your PATH variable, you'll have %SystemRoot% variable which links to your windows folder.
In C# you can't really reference C++ projects as you already know when adding another C# project, since you calling from managed code to unmanaged/native code.
Important note when you building your own C++ dll, make sure the compiler environment set to x32 bit, otherwise you'll get some other exceptions when calling C++ code from C#.
What actually expose the C++ function to allow for it consumed by other languages, is the:
extern "C" __declspec(dllexport)
On the signature of the function. So that gives you the power to do almost everything you can do with C++ also in C#/Java.
i have a project in c# that use a unmanaged dll from another project, i have try to import that dll file, but i cannot use that dll file because Visual Studio cannot find its .pdb file, me neither.
i have tried to dll import
[DllImport("unmanaged.dll", EntryPoint= "Analyse", CallingConvention = CallingConvention.Cdecl)]
private static extern unsafe long* Analyse(byte[] bImgData, uint nLength, ushort nWidth, ushort nHeigth, uint nMaxCodeCount, short nAnalyseLevel);
but the method just doesnt return any value.
and in Output List there are:
'CCan.exe' (Win32): Loaded 'C:\Users\Masbro\Documents\Visual Studio 2013\Projects\CCan\CCan\bin\x86\Debug\unmanaged.dll'. Cannot find or open the PDB file.
can i use unmanaged DLL without its pdb file?or can i generate its .pdb file?
You don't need the PDB. However, you do need to know the entry point and function signature of the API you're calling in the DLL; Visual Studio won't figure those out for you. However, if your DLL exports its function names, you can find them using various tools. Some examples here, on MSDN: http://msdn.microsoft.com/en-us/library/vstudio/31d242h4(v=vs.100).aspx
For example, let's say your library, unmanaged.dll, has the following API:
void* DoStuff (DWORD number, LPWSTR str, PDWORD outval);
To call that from C# code, you would need to define the following extern function in in one of your classes:
using System.Runtime.InteropServices
[DllImport("unmanaged.dll", CharSet=Unicode)]
public static extern IntPtr DoStuff (UInt32 number, String str, out UInt32 outval);
The visibility modifier (public) isn't important, except that you need to be able to see the function from wherever you call it. The DllImport attribute is defined in System.Runtime.InteropServices, hence the using statement.
DllImport requires the first value, the string giving the DLL name, but it also has a ton of other parameters which are sometimes helpful or even required (such as CharSet). In particular, if your unmanaged library doesn't export names (or you want to use a different name in C# than the exported unmanaged name) then you need to specify the EntryPoint field of the DllImport attribute. An example of accessing a function without an exported name if you know the function's ordinal:
[DllImport("unmanaged.dll", CharSet=Unicode, EntryPoint="#1")]
public static extern IntPtr DoStuff (UInt32 number, String str, out UInt32 outval);
Take a look at the MSDN documentation for more info.
I am trying to use MimeTex.dll in Mixed Mode of C++/CLI project. I include the dll by:
#pragma comment(lib,"MimeTex.dll")
and I tried to call this method:
CreateGifFromEq("expression","path");
but the compiler inform that it doesn't know CreateGifFromEq() method.
I didn't find resources in the web in how to use MimeTex.dll in C++. I just find how to use it with C# in this link by Pinvok like:
[System.Security.SuppressUnmanagedCodeSecurity()]
internal class NativeMethods
{
private NativeMethods()
{ //all methods in this class would be static
}
[System.Runtime.InteropServices.DllImport("MimeTex.dll")]
internal static extern int CreateGifFromEq(string expr, string fileName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
internal extern static IntPtr GetModuleHandle(string lpModuleName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
internal extern static bool FreeLibrary(IntPtr hLibModule);
}
and then call it like:
NativeMethods.CreateGifFromEq(equation, tempGifFilePath);
How I can call it without Pinvok in mixed mode of C++/CLI?
Surely you meant to write:
#pragma comment(lib,"MimeTex.lib")
In other words, you pass the .lib file to the linker rather than the .dll. When you compiled the DLL, a .lib file will have been generated.
But that's not your immediate problem. The compiler has no declaration for CreateGifFromEq. That's because you have not included the library's header file in your C++ code. Doing that should resolve the issue.
If all you need is that one function then it should be trivial to declare it in your C++ code.
__declspec(dllimport) extern int CreateGifFromEq(char *expr, char *fileName);
You probably will need to wrap that in an extern "C" block too.
Actually, having looked at the library, the header file that is supplied with the source does not declare that function, even though it's present in the library.
In C++/CLI you can use P/Invoke as in C#.
If you don't want to use P/Invoke, the other way is to load the DLL with LoadLibrary and get pointers to the functions with GetProcAddress.
Here's the equivalent of the C# code in C++/CLI:
using namespace System;
using namespace System::Runtime::InteropServices;
private ref class NativeMethods abstract sealed
{
internal:
[DllImport("MimeTex.dll")]
static int CreateGifFromEq(String^ expr, String^ fileName);
[DllImport("kernel32.dll")]
static IntPtr GetModuleHandle(String^ lpModuleName);
[DllImport("kernel32.dll")]
[returnvalue: MarshalAs(UnmanagedType::Bool)]
static bool FreeLibrary(IntPtr hLibModule);
};
As you can see it's almost identical to the C# code except for some minor syntax changes.
Here's how you would use LoadLibrary and GetProcAddress (which has the advantage of not requiring marshaling, which is unnecessary in C++ anyway):
HMODULE hModule = LoadLibrary(L"MimeTex.dll");
int (*fpCreateGifFromEq)(WCHAR*, WCHAR*) = GetProcAddress(hModule, "CreateGifFromEq");
(*fpCreateGifFromEq)(L"expression", L"filename");
You don't need to do that for GetModuleHandle and FreeLibrary, because they're from kernel32.dll so you can just include Windows.h and call them normally.
There's a cleaner way of doing things:
Create a C++/CLI project. It will be your interface between C# and C++ (this is what C++/CLI is aimed at).
Make your C# project have a reference to this new assembly.
Inside your new C++/CLI project, configure project options so as you point to the directory with mimetex .h files for the compiler to compile your project, and the directory with .lib/.dll for the linker.
Inside your C++/CLI part, you just write C++ inside the functions. They are exposed to your C# assembly, but in the inside it's just calls to C++ functions as usual.
(You should check a C++CLI tutorial to know what to do with strings to convert them to native char or std::string. I remember I had to look at that.)*
In your C# part, you just call the C++CLI project assembly exposed functions like normal C# functions, without noticing it's native code called behind.
I'm writing a cross-platform .NET library that uses some unmanaged code. In the static constructor of my class, the platform is detected and the appropriate unmanaged library is extracted from an embedded resource and saved to a temp directory, similar to the code given in another stackoverflow answer.
So that the library can be found when it isn't in the PATH, I explicitly load it after it is saved to the temp file. On windows, this works fine with LoadLibrary from kernel32.dll. I'm trying to do the same with dlopen on Linux, but I get a DllNotFoundException when it comes to loading the P/Invoke methods later on.
I have verified that the library "libindexfile.so" is successfully saved to the temp directory and that the call to dlopen succeeds. I delved into the mono source to try figure out what is going on, and I think it might boil down to whether or not a subsequent call to dlopen will just reuse a previously loaded library. (Of course assuming that my naïve swoop through the mono source drew the correct conclusions).
Here is the shape of what I'm trying to do:
// actual function that we're going to p/invoke to
[DllImport("indexfile")]
private static extern IntPtr openIndex(string pathname);
const int RTLD_NOW = 2; // for dlopen's flags
const int RTLD_GLOBAL = 8;
// its okay to have imports for the wrong platforms here
// because nothing will complain until I try to use the
// function
[DllImport("libdl.so")]
static extern IntPtr dlopen(string filename, int flags);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string filename);
static IndexFile()
{
string libName = "";
if (IsLinux)
libName += "libindexfile.so";
else
libName += "indexfile.dll";
// [snip] -- save embedded resource to temp dir
IntPtr handle = IntPtr.Zero;
if (IsLinux)
handle = dlopen(libPath, RTLD_NOW|RTLD_GLOBAL);
else
handle = LoadLibrary(libPath);
if (handle == IntPtr.Zero)
throw new InvalidOperationException("Couldn't load the unmanaged library");
}
public IndexFile(String path)
{
// P/Invoke to the unmanaged function
// currently on Linux this throws a DllNotFoundException
// works on Windows
IntPtr ptr = openIndex(path);
}
Update:
It would appear that subsequent calls to LoadLibrary on windows look to see if a dll of the same name has already been loaded, and then uses that path. For example, in the following code, both calls to LoadLibrary will return a valid handle:
int _tmain(int argc, _TCHAR* argv[])
{
LPCTSTR libpath = L"D:\\some\\path\\to\\library.dll";
HMODULE handle1 = LoadLibrary(libpath);
printf("Handle: %x\n", handle1);
HMODULE handle2 = LoadLibrary(L"library.dll");
printf("Handle: %x\n", handle2);
return 0;
}
If the same is attempted with dlopen on Linux, the second call will fail, as it doesn't assume that a library with the same name will be at the same path. Is there any way round this?
After much searching and head-scratching, I've discovered a solution. Full control can be exercised over the P/Invoke process by using dynamic P/Invoke to tell the runtime exactly where to find the code.
Edit:
Windows solution
You need these imports:
[DllImport("kernel32.dll")]
protected static extern IntPtr LoadLibrary(string filename);
[DllImport("kernel32.dll")]
protected static extern IntPtr GetProcAddress(IntPtr hModule, string procname);
The unmanaged library should be loaded by calling LoadLibrary:
IntPtr moduleHandle = LoadLibrary("path/to/library.dll");
Get a pointer to a function in the dll by calling GetProcAddress:
IntPtr ptr = GetProcAddress(moduleHandle, methodName);
Cast this ptr to a delegate of type TDelegate:
TDelegate func = Marshal.GetDelegateForFunctionPointer(
ptr, typeof(TDelegate)) as TDelegate;
Linux Solution
Use these imports:
[DllImport("libdl.so")]
protected static extern IntPtr dlopen(string filename, int flags);
[DllImport("libdl.so")]
protected static extern IntPtr dlsym(IntPtr handle, string symbol);
const int RTLD_NOW = 2; // for dlopen's flags
Load the library:
IntPtr moduleHandle = dlopen(modulePath, RTLD_NOW);
Get the function pointer:
IntPtr ptr = dlsym(moduleHandle, methodName);
Cast it to a delegate as before:
TDelegate func = Marshal.GetDelegateForFunctionPointer(
ptr, typeof(TDelegate)) as TDelegate;
For a helper library that I wrote, see my GitHub.
Try running it like this from a terminal:
export MONO_LOG_LEVEL=debug
export MONO_LOG_MASK=dll
mono --debug yourapp.exe
Now every library lookup will be printed to the terminal, so you'll be able to find out what's going wrong.
I needed to load a native library extracted to a temporary location, and I almost found a solution. I've checked Mono's source code and figured out a way:
[DllImport("__Internal", CharSet = CharSet.Ansi)]
private static extern void mono_dllmap_insert(IntPtr assembly, string dll, string func, string tdll, string tfunc);
// and then somewhere:
mono_dllmap_insert(IntPtr.Zero, "somelib", null, "/path/to/libsomelib.so", null);
This kind of works. The problem is, you cannot allow Mono's stupid JIT compiler to catch a whiff of any DllImported method referring this library before calling mono_dllmap_insert().
Because if it does, strange things will happen:
Mono: DllImport searching in: '/tmp/yc1ja5g7.emu/libsomelib.so' ('/tmp/yc1ja5g7.emu/libsomelib.so').
Mono: Searching for 'someGreatFunc'.
Mono: Probing 'someGreatFunc'.
Mono: Found as 'someGreatFunc'.
Error. ex=System.DllNotFoundException: somelib
So now that I'm calling my native someGreatFunc(), Mono is able to find the library and load it (I checked), it is able to find the symbol (I checked), but because somewhen in the past when it was doing JIT it was not able to load that library, it decides to throw DllNotFoundException anyway. I guess the generated code contains a hardcoded throw statement or something :-O
When you call another native function from the same library that happens not to have been JITted before you called mono_dllmap_insert(), it will work.
So you can either use the manual solution added by #gordonmleigh or you must tell Mono where the library is BEFORE it JITs any of these imports. Reflection may help there.
Not sure why you think this is related to mono, since the issue you're having is not about mono's dynamic loading facilities.
If your updated sample works, it just means that LoadLibrary() on windows has different semantics than dlopen() on Linux: as such you either have to live with the difference or implement your own abstraction that deals with the directory issue (my hunch is that it's not the directory that is retained, but windows simply looks to see if a library with the same name was already loaded and it reuses that).
I am working on a project that requires some image processing. The front end of the program is C# (cause the guys thought it is a lot simpler to make the UI in it). However, as the image processing part needs a lot of CPU juice I am making this part in C++.
The idea is to link it to the C# project and just call a function from a DLL to make the image processing part and allow to the C# environment to process the data afterwards. Now the only problem is that it seems I am not able to make the DLL. Simply put the compiler refuses to put any function into the DLL that I compile.
Because the project requires some development time testing I have created two projects into a C++ solution. One is for the Dll and another console application. The console project holds all the files and I just include the corresponding header into my DLL project file. I thought the compiler should take out the functions that I marked as to be exported and make the DLL from them. Nevertheless this does not happens.
Here it is how I defined the function in the header:
extern "C" __declspec(dllexport) void _stdcall RobotData(BYTE* buf, int** pToNewBackgroundImage, int* pToBackgroundImage, bool InitFlag, ObjectInformation* robot1, ObjectInformation* robot2, ObjectInformation* robot3, ObjectInformation* robot4, ObjectInformation* puck);
extern "C" __declspec(dllexport) CvPoint _stdcall RefPointFinder(IplImage* imgInput, CvRect &imgROI,
CvScalar &refHSVColorLow, CvScalar &refHSVColorHi );
Followed by the implementation in the cpp file:
extern "C" __declspec(dllexport) CvPoint _stdcall RefPointFinder(IplImage* imgInput, CvRect &imgROI,&refHSVColorLow, CvScalar &refHSVColorHi ) { \\...
return cvPoint((int)( M10/M00) + imgROI.x, (int)( M01/M00 ) + imgROI.y) ;}
extern "C" __declspec(dllexport) void _stdcall RobotData(BYTE* buf, int** pToNewBackgroundImage, int* pToBackgroundImage, bool InitFlag, ObjectInformation* robot1, ObjectInformation* robot2, ObjectInformation* robot3, ObjectInformation* robot4, ObjectInformation* puck) { \\ ...};
And my main file for the DLL project looks like:
#ifdef _MANAGED
#pragma managed(push, off)
#endif
/// <summary> Include files. </summary>
#include "..\ImageProcessingDebug\ImageProcessingTest.h"
#include "..\ImageProcessingDebug\ImageProcessing.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
Needless to say it does not work. A quick look with DLL export viewer 1.36 reveals that no function is inside the library. I don't get it. What I am doing wrong ?
As side not I am using the C++ objects (and here it is the C++ DLL part) such as the vector. However, only for internal usage. These will not appear in the headers of either function as you can observe from the previous code snippets.
Any ideas? Thx,
Bernat
It seems you are confused about which files to include in your DLL project vs your console project. If it is true that "The console project holds all the files" then this is your problem.
Your DLL project needs to include the cpp file which has the __declspec(dllexport)s. As you describe it, you have included your RefPointFinder() & RobotData() functions in the console project. In other words your DLL has no functions in it whatsoever, regardless of whether anything is exported.
Just including the .h files in the DLL main file does nothing by itself. It doesn't include these functions in the DLL.