C# - вызов из библиотеки по полному пути
От: Garris  
Дата: 19.02.11 21:51
Оценка:
Когда в C# вызываем функцию из DLL, то выглядит это, например, так:
[DllImport("NameDLL.dll")]
public static extern bool Func (string str, int param);
Всё работает без проблем, но непонятно, как вызывать функцию, если вместо конкретной "NameDLL.dll" из каталога программы нужно будет передать полный путь к библиотеке (например,если библиотека находится в подкаталоге программы), но не заранее заданнный, а тот, который определится в момент вызова (путь к приложению + подкаталог с заданным именем + имя библиотеки). В C# можно получить путь к приложению, однако это будет string, а не const string, который и нужно передать внутрь DllImport. Преобразовать string в const string средствами C# вроде возможным не представляется (да и это, наверное, не совсем правильный путь).
Так каким образом можно динамически получить и передать полный путь к библиотеке в виде const string?
Re: C# - вызов из библиотеки по полному пути
От: Igor Vyatkin  
Дата: 19.02.11 22:24
Оценка: 1 (1)
Здравствуйте, Garris, Вы писали:

G>Когда в C# вызываем функцию из DLL, то выглядит это, например, так:

G>[DllImport("NameDLL.dll")]
G>public static extern bool Func (string str, int param);
G>Всё работает без проблем, но непонятно, как вызывать функцию, если вместо конкретной "NameDLL.dll" из каталога программы нужно будет передать полный путь к библиотеке (например,если библиотека находится в подкаталоге программы), но не заранее заданнный, а тот, который определится в момент вызова (путь к приложению + подкаталог с заданным именем + имя библиотеки). В C# можно получить путь к приложению, однако это будет string, а не const string, который и нужно передать внутрь DllImport. Преобразовать string в const string средствами C# вроде возможным не представляется (да и это, наверное, не совсем правильный путь).
G>Так каким образом можно динамически получить и передать полный путь к библиотеке в виде const string?

LoadLibrary (PInvoke) + GetProcAddress (PInvoke)+ Marshal.GetDelegateForFunctionPointer.
Ы?
Re: C# - вызов из библиотеки по полному пути
От: MozgC США http://nightcoder.livejournal.com
Дата: 19.02.11 22:43
Оценка: 3 (3)
Пусть dll имеет такой исходник:

/* LibraryC.h */
extern "C" /* force compiler to use our actual function name */ __declspec(dllexport) int DoubleIt(int value);

/* LibraryC.cpp */
#include "LibraryC.h"

int DoubleIt(int value)
{
    return value * 2;
}


Тогда из C# вызовем это так:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

namespace LibraryClient
{
    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate int DoubleIt(int value);

        static void Main(string[] args)
        {
            IntPtr pDll = NativeMethods.LoadLibrary("LibraryC.dll");
            if(pDll == IntPtr.Zero)
                throw new Win32Exception();

            IntPtr pProc = NativeMethods.GetProcAddress(pDll, "DoubleIt");
            if(pProc == IntPtr.Zero)
                throw new Win32Exception();

            var doubleDelegate = (DoubleIt)Marshal.GetDelegateForFunctionPointer(pProc, typeof(DoubleIt));

            int arg = 2;
            int result = doubleDelegate(arg);

            bool isFreed = NativeMethods.FreeLibrary(pDll);

            Console.WriteLine("If we double {0} we get {1}", arg, result);
            
            if(!isFreed)
                Console.WriteLine("Library could not be freed.");

            Console.ReadLine();
        }
    }

    static class NativeMethods
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [ResourceExposure(ResourceScope.Process)]
        public static extern IntPtr LoadLibrary(string libFilename);

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
        static internal extern IntPtr GetProcAddress(IntPtr HModule, [MarshalAs(UnmanagedType.LPStr), In] string funcName/*lpcstr*/);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [ResourceExposure(ResourceScope.Process)]
        public static extern bool FreeLibrary(IntPtr hModule);
    }
}

Компилировать клиента на C# пришлось под Win32, если компилировалось под AnyCPU/x64, то получалась мало понятная ошибка "%1 is not a valid Win32 application".
Re[2]: C# - вызов из библиотеки по полному пути
От: MozgC США http://nightcoder.livejournal.com
Дата: 19.02.11 22:45
Оценка:
Уточню на всякий случай, что в LoadLibrary() можно теперь любой путь к dll указать динамически, а то вдруг не понятно Просто в моем примере библиотека находилась в той же директории, что и клиент.
Re[3]: C# - вызов из библиотеки по полному пути
От: Аноним  
Дата: 20.02.11 16:33
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Уточню на всякий случай, что в LoadLibrary() можно теперь любой путь к dll указать динамически, а то вдруг не понятно Просто в моем примере библиотека находилась в той же директории, что и клиент.


Спасибо, вроде всё понятно...
Re[2]: C# - вызов из библиотеки по полному пути
От: Jolly Roger  
Дата: 20.02.11 16:46
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Компилировать клиента на C# пришлось под Win32, если компилировалось под AnyCPU/x64, то получалась мало понятная ошибка "%1 is not a valid Win32 application".


Видимо, LibraryC.dll собрали как x86, 32-битную.
"Нормальные герои всегда идут в обход!"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.