So I created the following test project:
[DllImportAttribute("TestMFCDLL.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int test(int number);
private void button1_Click(object sender, EventArgs e)
{
int x = test(5);
}
Which works fine for my MFC dll that has the function test defined, however what I actually have is many MFC dlls that all share a common entry function and run differently based on my inputs. So basically I have tons of dlls that I cannot know at compile time what the name is, I just know that they have a function similar to how this program is setup, is there a way to import a dll based on run-time knowledge? Simply doing this returns an error:
static string myDLLName = "TestMFCDLL.dll";
[DllImportAttribute(myDLLName, CallingConvention = CallingConvention.Cdecl)]
An attribute argument must be a constant expression, typeof expression
or array creation expression of an attribute parameter type
If you want to dynamically load a DLL and use the functions in the DLL, then you'll need to do a little bit more. First you need to load the DLL dynamically. You can use LoadLibrary and FreeLibrary for that.
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
Second you need to get the address of the function in the DLL and call it.
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string functionName);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int Test(int number);
Putting that all together:
IntPtr pLib = LoadLibrary(#"PathToYourDll.DLL");
IntPtr pAddress = GetProcAddress(pLib, "test");
Test test = (Test)Marshal.GetDelegateForFunctionPointer(pAddress, typeof(Test));
int iRresult = test(0);
bool bResult = FreeLibrary(pLib);
Related
I'm using an external DLL which is written in C++. It's a cURL Wrapper. I do not have access the code, just DLL.
//Import kernel32 DLL
static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
//Create delegate function
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int curlInit(ref CurlSettings settings);
//Import library
dllPointer = NativeMethods.LoadLibrary(DLLPath);
ptrInit = NativeMethods.GetProcAddress(dllPointer, "curlInit");
var initFunction = (curlInit)Marshal.GetDelegateForFunctionPointer(ptrInit, typeof(curlInit));
initFunction(ref defaultSettings); <-- This works
//Try to get rid of this DLL
initFunction = null;
NativeMethods.FreeLibrary(dllPointer);
GC.Collect();
//Load library again
...
...
initFunction(ref defaultSettings); <-- Raise and error
I need to initialize cURL, everytime I changed a setting.
For the first time, init function works perfectly. However when I try it second time, init function return error value (even with the same params), so I get that DLL and resources not removed successfully.
What I tried:
I set everything I used, to NULL,
I called FreeLibrary
I called my boy, GC.Collect()
Any idea?
Edit: NativeMethods.FreeLibrary(dllPointer); return True
I have C# wrapper project that uses C++ unmanaged dll code with help of [DllImport] attribute and static extern methods. This is the preferred method described by MSDN.
The problem is that we can have only one of the c++ runner, which means we can't run tasks in parallel.
How to call the unmanaged C++ without using the dllimport + static extern methods so that when we instantiate one of the c# objects it instantiates a new c++ dll object
This is how we are calling C++ code right now.
public class FMU : IDisposable
{
[DllImport("FMU.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
private static extern IntPtr Load(string fmuFileName, bool isCoSimulation, AddMessageDelegate messageDelegate, int arrayLocation);
[DllImport("FMU.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Instantiate(IntPtr fmu, bool isCoSimulation, bool loggingOn, int nCategories, string[] categories);
[DllImport("kernel32", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);
I have a C# application which needs to import a function from a C++ dll. I use DLLImport to load the function. It works fine in English and Chinese environment, but it always raise 'Module not found' exception in French operating system.
The code snapshot:
[DllImport("abcdef.dll", CallingConvention = CallingConvention.StdCall)]
public static extern string Version();
Note that letters in the name of module have been replaced but the name itself is in the same format and the same length.
And a screenshot:
Any ideas?
I have tried all methods you proposed, however the problem still exists.
Here is an alternative way which could avoid that error. It uses Win32 APIs to load the library and find the address of the function, then invoke it. Demo code follows:
class Caller
{
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
private IntPtr _hModule;
public Caller(string dllFile)
{
_hModule = LoadLibrary(dllFile);
}
~Caller()
{
FreeLibrary(_hModule);
}
delegate string VersionFun();
int main()
{
Caller caller = new Caller("abcdef.dll");
IntPtr hFun = GetProcAddress(_hModule, "Version");
VersionFun fun = Marshal.GetDelegateForFunctionPointer(hFun, typeof(VersionFun)) as VersionFun;
Console.WriteLine(fun());
return 0;
}
}
While going through SWig generated wrappers, I find that the PInvokes don't have any entry point defined, but some places do have an entry point. So what is the difference between them? When do I need to define an EntryPoint, and when do I not need to?
Defined without EntryPoint:
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
public static extern bool ReadFile(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
int flag);
Defined with Entrypoint:
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "ReadFile")]
public static extern bool ReadFile2(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
Overlapped2 flag);
Also why does the function have to be static as in public static extern? I assume that extern is telling the compiler that this method is defined externally?
The EntryPoint field serves to tell the .NET runtime which function to call from the DLL being invoked; if it's not set, the default is the same name that the .NET method declaration has. In your second example, omitting EntryPoint = "ReadFile" would result in the runtime trying to call a function named ReadFile2 (which does not exist).
The prototype needs to have the static and extern modifiers because the specification says so. It does not need to be public; controlling the visibility of the method is entirely up to you.
I know the title is bit confusing for my question.
Let me explain:-
There are some DLLs written by my seniors and I use them in C# as follows:
Say, Existing DLL name is SeniorDLL and I want to use function SeniorFunc from that DLL.
What I do is:-
private delegate int SeniorFunc(IntPtr Blah);
[DllImport("kernel32")]
public extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
SeniorFunc fp_Senior;
and in function where I want to use this function, Before first function call I write:
IntPtr handle;
handle = IntPtr.Zero;
handle = LoadLibrary("<DLL Path>");
IntPtr fPtr = GetProcAddress(handle, "SeniorFunc");
fp_Senior = (SeniorFunc)Marshal.GetDelegateForFunctionPointer(fPtr, typeof(SeniorFunc));
and then I use this function via fp_Senior(<Parameter>);
Now I want to create such DLL for me in C# by which I'll be able to call functions from DLL.
Currently I created a DLL but I have create an instance of class in DLL and then have to access like ClassInstance.MyFunction(<Parameters>);
How can I get directly function calls without creating an instance?
In other words, (I don't know I am correct or wrong) How can I create APIs??
Thanks!!
You don't need an instance here, everything can be static. Something like this, with the necessary error checking added:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal static class NativeMethods {
public static void SeniorFunc(IntPtr arg) {
if (fp_Senior == null) lookUpSenior();
fp_Senior(arg);
}
private static void lookUpSenior() {
loadSenior();
IntPtr addr = GetProcAddress(SeniorModule, "seniorfunc");
if (addr == IntPtr.Zero) throw new Win32Exception();
fp_Senior = (SeniorFuncDelegate)Marshal.GetDelegateForFunctionPointer(addr, typeof(SeniorFuncDelegate));
}
private static void loadSenior() {
if (SeniorModule == IntPtr.Zero) {
SeniorModule = LoadLibrary("mumble.dll");
if (SeniorModule == IntPtr.Zero) throw new Win32Exception();
}
}
private static IntPtr SeniorModule;
private delegate int SeniorFuncDelegate(IntPtr Blah);
private static SeniorFuncDelegate fp_Senior;
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
}
The point of keeping lookupSenior in a separate method is to allow SeniorFunc() to get inlined so it is fast. If you know you'll always use these functions in your program then you can also write a static constructor for the class and do the lookup there. Saves the null check but makes an exception a bit harder to interpret.
There is no such a thing as a method outside a class in C#. So if you must call a method, you have to specify the class name.
The difference with the DLLs you are currently using is that those DLLs are written in C/C++ or other non-.NET language which does not enforce a strict object-oriented approach like C# does.
Thus, nothing forces you to create an instance of a class when calling a method from a .NET library. If a method is declared as static, you can call it directly through ClassName.MethodName().