Reputation: 11
Ex: in app1 user creates function_1() and function_2(). Then in app2 user wants to call function_2(). I searched on google and the only thing I found was to write this code:
class Program
{
[DllImport("functions.dll")]
public static extern void function_1();
static void Main(string[] args)
{
function_1();
}
}
Upvotes: 1
Views: 191
Reputation: 111920
Full example of what Damien wrote... Note that it works only if methods have all the same signature (in this example void function_X()
). Additionally it is "difficult" to explore a dll to discover what methods are exported, so it is better if you already know what methods there should be in the dll.
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
// Set the correct calling convention
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void DllMethodDelegate();
IntPtr dll = LoadLibrary(@"PathToYourDll.DLL");
if (dll == IntPtr.Zero)
{
throw new Exception();
}
string methodName = "function_1";
IntPtr method = GetProcAddress(dll, methodName);
if (method == IntPtr.Zero)
{
throw new Exception();
}
DllMethodDelegate method2 = (DllMethodDelegate)Marshal.GetDelegateForFunctionPointer(method, typeof(DllMethodDelegate));
// Now you can do method2();
Note that you have to set the correct calling convention in the DllMethodDelegate()
definition. Normally dll methods should be StdCall
.
The signature for the method you wrote is:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate int DllMethodDelegate(char cmd, ref IntPtr out_address);
Note that "filling" the out_address
is very complex (headache complex).
{
// I case:
IntPtr ret = IntPtr.Zero;
int result = method2('I', ref ret);
}
{
// R case:
IntPtr ptr = IntPtr.Zero;
int result = method2('R', ref ptr);
int value = Marshal.ReadInt32(ptr);
}
{
// W case:
int value = 100;
GCHandle handle = default(GCHandle);
try
{
int[] value2 = new int[] { value };
handle = GCHandle.Alloc(value2, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
int result = method2('W', ref ptr);
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
}
It is possible (but I'm not sure) that for the third example, you could do
object value2 = value;
instead of
int[] value2 = new int[] { value };
The interaction of boxing and GCHandle
isn't very documented, but it seems to work. C# specifications 4.3 seems to ok it... but I wouldn't trust it, and this technique seems to be described in the book ".NET and COM: The Complete Interoperability Guide", in the chapter "Obtaining the Address of Value Types" (that chapter is searchable in google, use the exact chapter title I gave. The example is in VB.NET but it is quite clear to read)
Upvotes: 0
Reputation: 1
You can use SymEnumerateSymbols64 from dbghelp dll to obtain the list of existent functions in your DLL. Then the user can choose which function to run.
You can find a more detailed explanation here: C# get the list of unmanaged C dll exports
Upvotes: 0
Reputation: 239774
You'll have to use some PInvoke code to get the DLL loaded (LoadLibrary) and to get a function pointer (GetProcAddess) and Marshal.GetDelegateForFunctionPointer to obtain a delegate that you can then invoke.
Upvotes: 3