Полный пример того, что написал Damien ... Обратите внимание, что он работает только в том случае, если методы имеют одинаковую подпись (в этом примере void function_X()
). Кроме того, «сложно» исследовать DLL, чтобы узнать, какие методы экспортируются, поэтому лучше, если вы уже знаете, какие методы должны быть в 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();
Обратите внимание, что вы должны установить правильное соглашение о вызовах в DllMethodDelegate()
определения. Обычно методы dll должны быть StdCall
.
Сигнатура методы вы написали:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate int DllMethodDelegate(char cmd, ref IntPtr out_address);
Обратите внимание, что «заполнение» out_address
очень сложны (головная боль комплексы).
{
// 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();
}
}
}
Возможно (но я не уверен), что для третьего примера, вы могли бы сделать
object value2 = value;
вместо
int[] value2 = new int[] { value };
Взаимодействие бокса и GCHandle
ISN «Очень документировано, но, похоже, это работает. Спецификации C# 4.3, похоже, в порядке ... но я бы не стал им доверять, и этот метод, как представляется, описан в книге «.NET и COM: полное руководство по совместимости» в главе «Получение адреса типов значений» «(эта глава доступна для поиска в google, используйте точный заголовок главы, который я дал). Пример приведен в VB.NET, но это совершенно очевидно)
Так что очевидный вывод в том, что это неуправляемый –
Единственным способом можно выборочно загрузить DLL во время выполнения с (не .NET DLL?) LoadLibrary, хотя я не уверен, что это соответствует вашим требованиям. Отличная, если немного устаревшая статья на http://goo.gl/hm4NVz (должна была опубликовать сокращенную ссылку), которая подробно описывает это. –