Можно ли использовать переменную для пути DLL в C # атрибут DllImport? [Дубликат]

Вот довольно простое сообщение, которое использует метод split из accessand pandas str, а затем использует NumPy для выравнивания каждой строки в один массив.

Соответствующие значения извлекаются путем повторения нерасширенный столбец правильное количество раз с np.repeat.

var1 = df.var1.str.split(',', expand=True).values.ravel()
var2 = np.repeat(df.var2.values, len(var1) / len(df))

pd.DataFrame({'var1': var1,
              'var2': var2})

  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5    f     2
110
задан Jsncrdnl 16 January 2012 в 11:52
поделиться

6 ответов

В отличие от предложений по некоторым другим ответам, использование атрибута DllImport по-прежнему является правильным.

Я честно не понимаю, почему вы не можете делать так, как все остальные в мир и укажите путь relative к вашей DLL. Да, путь, в котором ваше приложение будет установлено, отличается на компьютерах разных людей, но это в основном универсальное правило, когда дело доходит до развертывания. Механизм DllImport разработан с учетом этого.

На самом деле это даже не работает DllImport. Это правила загрузки загружаемых файлов Win32 DLL, которые управляют вещами, независимо от того, используете ли вы удобные управляемые обертки (маршаллер P / Invoke просто вызывает LoadLibrary ). Эти правила перечислены здесь подробно здесь , но важные из них здесь взяты:

Прежде чем система будет искать DLL, она проверит следующее:

  • Если DLL с тем же именем модуля уже загружена в память, система использует загруженную DLL, независимо от того, в какой директории она находится. Система не ищет DLL.
  • Если DLL находится в списке известных DLL для версии Windows, на которой выполняется приложение, система использует свою копию известной DLL (и известных DLL-зависимых библиотек DLL, если таковая имеется). Система не ищет DLL.

Если функция SafeDllSearchMode включена (по умолчанию), порядок поиска выглядит следующим образом:

  1. Каталог, из которого загружено приложение.
  2. Системный каталог. Используйте функцию GetSystemDirectory, чтобы получить путь к этому каталогу.
  3. 16-разрядный системный каталог. Нет функции, которая получает путь к этому каталогу, но его обыскивают.
  4. Каталог Windows. Используйте функцию GetWindowsDirectory, чтобы получить путь к этому каталогу.
  5. Текущий каталог.
  6. Каталоги, указанные в переменной среды PATH. Обратите внимание, что это не включает путь для каждого приложения, указанный в разделе реестра приложений. Ключ App Paths не используется при вычислении пути поиска DLL.

Итак, если вы не назовете свою DLL той же самой вещи, что и системная DLL (что вы должны явно не выполняйте ни при каких обстоятельствах), порядок поиска по умолчанию начнет искать в каталоге, из которого было загружено ваше приложение. Если вы разместите DLL там во время установки, он будет найден. Все сложные проблемы исчезают, если вы просто используете относительные пути.

Просто напишите:

[DllImport("MyAppDll.dll")] // relative path; just give the DLL's name
static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);

Но если этот не работает , причине, и вам нужно заставить приложение искать в другом каталоге DLL, вы можете изменить путь поиска по умолчанию, используя функцию SetDllDirectory . Обратите внимание, что в соответствии с документацией:

После вызова SetDllDirectory стандартный путь поиска DLL:

  1. Каталог, из которого загружено приложение.
  2. Каталог, заданный параметром lpPathName.
  3. Системный каталог. Используйте функцию GetSystemDirectory, чтобы получить путь к этому каталогу.
  4. 16-разрядный системный каталог. Нет функции, которая получает путь к этому каталогу, но выполняется поиск.
  5. Каталог Windows. Используйте функцию GetWindowsDirectory, чтобы получить путь к этому каталогу.
  6. Каталоги, перечисленные в переменной среды PATH.

So пока вы вызываете эту функцию перед вызовом функции, импортированной из DLL в первый раз, вы можете изменить путь поиска по умолчанию, используемый для поиска DLL. Разумеется, преимущество состоит в том, что вы можете передать значение dynamic для этой функции, которое вычисляется во время выполнения. Это невозможно с атрибутом DllImport, поэтому вы по-прежнему будете использовать относительный путь (только имя DLL) и полагаться на новый порядок поиска, чтобы найти его для вас.

Вам придется выполнить P / Invoke. Объявление выглядит следующим образом:

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
148
ответ дан Cody Gray 28 August 2018 в 01:11
поделиться

DllImport будет работать нормально, если не указан полный путь до тех пор, пока dll находится где-то на системном пути. Возможно, вы сможете временно добавить папку пользователя в путь.

0
ответ дан Mike W 28 August 2018 в 01:11
поделиться

Даже лучше, чем предложение Ran использовать GetProcAddress, просто вызовите LoadLibrary перед любыми вызовами функций DllImport (только с именем файла без пути), и они автоматически загружают загруженный модуль.

Я использовал этот метод для выбора во время выполнения, загружать ли 32-разрядную или 64-разрядную родную DLL без необходимости изменять кучу функций P / Invoke-d. Прикрепите код загрузки в статическом конструкторе для типа, который имеет импортированные функции, и все будет работать нормально.

27
ответ дан MikeP 28 August 2018 в 01:11
поделиться

Если вам нужен DLL-файл, который не находится на пути или в расположении приложения, то я не думаю, что вы можете сделать именно это, потому что DllImport - это атрибут, а атрибуты - это только метаданные, которые установлены по типам, элементам и другим языковым элементам.

Альтернатива, которая может помочь вам выполнить то, что, как я думаю, вы пытаетесь, - использовать native LoadLibrary через P / Invoke, чтобы загрузить a. dll из нужного вам пути, а затем используйте GetProcAddress, чтобы получить ссылку на нужную вам функцию из DLL. Затем используйте их для создания делегата, который вы можете вызвать.

Чтобы упростить его использование, вы можете установить этот делегат в поле своего класса, чтобы его использовать, как вызов метода-члена.

EDIT

Вот фрагмент кода, который работает, и показывает, что я имел в виду.

class Program
{
    static void Main(string[] args)
    {
        var a = new MyClass();
        var result = a.ShowMessage();
    }
}

class FunctionLoader
{
    [DllImport("Kernel32.dll")]
    private static extern IntPtr LoadLibrary(string path);

    [DllImport("Kernel32.dll")]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    public static Delegate LoadFunction<T>(string dllPath, string functionName)
    {
        var hModule = LoadLibrary(dllPath);
        var functionAddress = GetProcAddress(hModule, functionName);
        return Marshal.GetDelegateForFunctionPointer(functionAddress, typeof (T));
    }
}

public class MyClass
{
    static MyClass()
    {
        // Load functions and set them up as delegates
        // This is just an example - you could load the .dll from any path,
        // and you could even determine the file location at runtime.
        MessageBox = (MessageBoxDelegate) 
            FunctionLoader.LoadFunction<MessageBoxDelegate>(
                @"c:\windows\system32\user32.dll", "MessageBoxA");
    }

    private delegate int MessageBoxDelegate(
        IntPtr hwnd, string title, string message, int buttons); 

    /// <summary>
    /// This is the dynamic P/Invoke alternative
    /// </summary>
    static private MessageBoxDelegate MessageBox;

    /// <summary>
    /// Example for a method that uses the "dynamic P/Invoke"
    /// </summary>
    public int ShowMessage()
    {
        // 3 means "yes/no/cancel" buttons, just to show that it works...
        return MessageBox(IntPtr.Zero, "Hello world", "Loaded dynamically", 3);
    }
}

Примечание: я не удосужился использовать FreeLibrary , поэтому этот код не является полным. В реальном приложении вы должны позаботиться о выпуске загруженных модулей, чтобы избежать утечки памяти.

21
ответ дан Ran 28 August 2018 в 01:11
поделиться

Пока вы знаете каталог, где ваши библиотеки C ++ можно найти во время выполнения, это должно быть простым. Я ясно вижу, что это имеет место в вашем коде. Ваш myDll.dll будет присутствовать внутри каталога myLibFolder во временной папке текущего пользователя.

string str = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll"; 

Теперь вы можете продолжать использовать оператор DllImport, используя строку const, как показано ниже:

[DllImport("myDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);

Как раз во время выполнения, прежде чем вы вызовете функцию DLLFunction в библиотеке C ++) добавьте эту строку кода в код C #:

string assemblyProbeDirectory = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll"; 
Directory.SetCurrentDirectory(assemblyProbeDirectory);

Это просто указывает CLR на поиск неуправляемых библиотек C ++ по пути каталога, который вы получили во время выполнения вашей программы. Вызов Directory.SetCurrentDirectory устанавливает текущий рабочий каталог приложения в указанный каталог. Если ваш myDLL.dll присутствует на пути, представленном дорожкой assemblyProbeDirectory, он будет загружен, и желаемая функция будет вызвана через p / invoke.

2
ответ дан RBT 28 August 2018 в 01:11
поделиться

Если все не удается, просто поместите DLL в папку windows\system32. Компилятор найдет его. Укажите DLL для загрузки с помощью: DllImport("user32.dll"..., установите EntryPoint = "my_unmanaged_function", чтобы импортировать вашу неуправляемую функцию в ваше приложение C #:

 using System;
using System.Runtime.InteropServices;

class Example
{
   // Use DllImport to import the Win32 MessageBox function.

   [DllImport ("user32.dll", CharSet = CharSet.Auto)]
   public static extern int MessageBox 
      (IntPtr hWnd, String text, String caption, uint type);

   static void Main()
   {
      // Call the MessageBox function using platform invoke.
      MessageBox (new IntPtr(0), "Hello, World!", "Hello Dialog", 0);    
   }
}

Источник и даже больше DllImport примеров: http : //msdn.microsoft.com/en-us/library/aa288468 (v = vs.71) .aspx [/ д2]

-13
ответ дан Software_Designer 28 August 2018 в 01:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: