2015-06-04 4 views
1

Пример: в приложении app1 функции function_1() и function_2(). Затем в app2 пользователь хочет вызвать функцию_2(). Я искал в Google, и единственное, что я нашел, чтобы написать этот код:Использование переменного числа функций

class Program 
{ 
    [DllImport("functions.dll")] 
    public static extern void function_1(); 


    static void Main(string[] args) 
    { 
     function_1(); 
    } 
} 
+0

Так что очевидный вывод в том, что это неуправляемый –

+0

Единственным способом можно выборочно загрузить DLL во время выполнения с (не .NET DLL?) LoadLibrary, хотя я не уверен, что это соответствует вашим требованиям. Отличная, если немного устаревшая статья на http://goo.gl/hm4NVz (должна была опубликовать сокращенную ссылку), которая подробно описывает это. –

ответ

3

Вы должны будете использовать некоторые PInvoke код, чтобы получить DLL загружается (LoadLibrary) и получить указатель на функцию (GetProcAddess) и Marshal.GetDelegateForFunctionPointer, чтобы получить делегата, который вы затем можете вызвать.

0

Полный пример того, что написал 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, но это совершенно очевидно)

+0

@ ale93 Он был полностью измучен SO ... Попробуйте вставить его в вопрос. – xanatos

+0

Я редактировал вопрос. – ale93

+0

@ ale93 Если у вас несколько типов подписи (в данном случае несколько типов возврата == несколько подписей), вам придется обрабатывать их вручную через несколько типов делегатов ... И это 'void **', я не думаю его можно легко сделать в C#. – xanatos

0

Вы можете использовать SymEnumerateSymbols64 из dll dbghelp для получения списка существующих функций в вашей DLL. Затем пользователь может выбрать, какую функцию запускать.

Вы можете найти более подробное объяснение здесь: C# get the list of unmanaged C dll exports