Итак, постановка задачи:
Есть бибилотека someDll.dll, которая является не .net сборкой, а так называемым двоичным кодом(или "родным" (native)). Обычно такие библиотеки написаны на С++ или Delphi. Эта библиотека экспортирует функцию
void libraryFunction(char* text);
Необходимо вызвать эту функцию в проекте .net на этапе выполнения. В данном примере - в проекте на языке C#
Порядок действий.
1. Необходимо описать список win32 api функций, необходимых для работы с библиотеками. Использование этих функций легко организовать при помощи статического связывания при помощи InteropServices(Не забывайте добавлять директиву "using System.Runtime.InteropServices;" вначале файла) и использования аттрибута DllImport. Рекоммендую ресурс PInvoke.net для поиска готовых описаний системных функций, чтобы не ошибится при использовании функций со сложными входными параметрами и возвращаемыми значениями. Если вы используете SharpDevelop, то в контекстном меню редактора есть пункт "Insert PInvoke Signature" и выбрав его и введя в строке поиска необходимую функцию, вы сразу можете вставить готовое описание.
2. Для загрузки библиотеки необходима функция LoadLibrary. Она возвращает дескриптор библиотеки, который необходим для использования ее функций. В качестве параметра используется char[] который вы можете получить, используя метод ToCharArray() у класса string.
3. Необходимо получить адрес функции, которую вы хотите использовать. Используем GetProcAddress, первым параметром указываем дескриптор загруженной библиотеки, который мы получили вызвав LoadLibrary, а вторым параметром указываем название функции, которую хотим вызвать.
Примечание: Название функции содержит только имя функции без скобок, параметров и возвращаемого значения. Иначе функция вернет вам адресс IntPtr.Zero
4. Так как .net считается безопасным кодом, то преобразовать адрес функции в функцию невозможно. Но среда предоставляет возможность безопасно преобразовать адрес в делегат. Нам необходима функция "void libraryFunction(char* text);". Для этого объявим делегат
internal delegate void functionDelegate(char[] text);
Преобразовываем адрес функции в делегат(аналог безопасного варианта указателя на функцию в C++ для среды .net) при помощи метода Marshal.GetDelegateForFunctionPointer
functionDelegate libFunction = (functionDelegate)Marshal.
GetDelegateForFunctionPointer(procID, typeof(
functionDelegate));
5. И теперь мы свободно можем пользоваться нашей функцией при помощи делегата.
6. Не забваем выгрузить библиотеку при помощи FreeLibrary после того, как библиотека стала не нужной.
using System;
using System.Runtime.InteropServices;
class Imports
{
#region external imports
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr LoadLibrary(string
lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi,
ExactSpelling = true, SetLastError = true)]
public internal static extern IntPtr GetProcAddress(
IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
#endregion
}
class DLL_Loader
{
internal delegate void functionDelegate(char[] text);
public void useFunctionFromDLL()
{
IntPtr libID = Imports.LoadLibrary("someDll.dll");
IntPtr procID = Imports.GetProcAddress(libID,
"libraryFunction");
functionDelegate libFunction = (functionDelegate)
Marshal.GetDelegateForFunctionPointer(procID, typeof(
functionDelegate));
libFunction("my string".ToCharArray());
Imports.FreeLibrary(libID);
}
}
No comments:
Post a Comment