Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 245 Vote(s) - 3.48 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How can I specify a [DllImport] path at runtime?

#1
In fact, I got a C++ (working) DLL that I want to import into my C# project to call it's functions.

It does work when I specify the full path to the DLL, like this :

string str = "C:\\Users\\userName\\AppData\\Local\\myLibFolder\\myDLL.dll";
[DllImport(str, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);

The problem is that it's gonna be an installable project, so the user's folder will not be the same (ex : pierre, paul, jack, mum, dad, ...) depending computer/session where it'd be runned on.

So I'd like my code to be a little more generic, like this :

/*
goes right to the temp folder of the user
"C:\\Users\\userName\\AppData\\Local\\temp"
then go to parent folder
"C:\\Users\\userName\\AppData\\Local"
and finally go to the DLL's folder
"C:\\Users\\userName\\AppData\\Local\\temp\\myLibFolder"
*/

string str = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll";
[DllImport(str, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);

The big deal is that "DllImport" desire a "const string" parameter for the DLL's directory.

So my question is ::
What could be done in this case ?
Reply

#2
DllImport will work fine without the complete path specified as long as the dll is located somewhere on the system path. You may be able to temporarily add the user's folder to the path.
Reply

#3
If all fails, simply put the DLL in the `windows\system32` folder . The compiler will find it.
Specify the DLL to load from with: `DllImport("user32.dll"...`, set `EntryPoint = "my_unmanaged_function"` to import your desired unmanaged function to your C# app:


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);
}
}

Source and even more `DllImport` examples :

[To see links please register here]


Reply

#4
If you need a .dll file that is not on the path or on the application's location, then I don't think you can do just that, because `DllImport` is an attribute, and attributes are only metadata that is set on types, members and other language elements.

An alternative that can help you accomplish what I think you're trying, is to use the native `LoadLibrary` through P/Invoke, in order to load a .dll from the path you need, and then use `GetProcAddress` to get a reference to the function you need from that .dll. Then use these to create a delegate that you can invoke.

To make it easier to use, you can then set this delegate to a field in your class, so that using it looks like calling a member method.

**EDIT**

Here is a code snippet that works, and shows what I meant.


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);
}
}



Note: I did not bother to use `FreeLibrary`, so this code is not complete. In a real application, you should take care to release the loaded modules to avoid a memory leak.
Reply

#5
Contrary to the suggestions by some of the other answers, using the `DllImport` attribute is still the correct approach.

I honestly don't understand why you can't do just like everyone else in the world and specify a *relative* path to your DLL. Yes, the path in which your application will be installed differs on different people's computers, but that's basically a universal rule when it comes to deployment. The `DllImport` mechanism is designed with this in mind.

In fact, it isn't even `DllImport` that handles it. It's the native Win32 DLL loading rules that govern things, regardless of whether you're using the handy managed wrappers (the P/Invoke marshaller just calls [`LoadLibrary`][1]). Those rules are enumerated in great detail [here](

[To see links please register here]

), but the important ones are excerpted here:

> **Before the system searches for a DLL, it checks the following:**
>
> - If a DLL with the same module name is already loaded in memory, the system uses the loaded DLL, no matter which directory it is in. The system does not search for the DLL.
> - If the DLL is on the list of known DLLs for the version of Windows on which the application is running, the system uses its copy of the known DLL (and the known DLL's dependent DLLs, if any). The system does not search for the DLL.
>
> -----
> **If `SafeDllSearchMode` is enabled (the default), the search order is as follows:**
>
> 1. The directory from which the application loaded.
> 2. The system directory. Use the `GetSystemDirectory` function to get the path of this directory.
> 3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
> 4. The Windows directory. Use the `GetWindowsDirectory` function to get the path of this directory.
> 5. The current directory.
> 6. The directories that are listed in the `PATH` environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

So, unless you're naming your DLL the same thing as a system DLL (which you should obviously not be doing, ever, under any circumstances), the default search order will start looking in the directory from which your application was loaded. If you place the DLL there during the install, it will be found. All of the complicated problems go away if you just use relative paths.

Just write:

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

But if that *doesn't* work for whatever reason, and you need to force the application to look in a different directory for the DLL, you can modify the default search path using the [`SetDllDirectory` function][2].
Note that, as per the documentation:

> After calling `SetDllDirectory`, the standard DLL search path is:
>
> 1. The directory from which the application loaded.
> 2. The directory specified by the `lpPathName` parameter.
> 3. The system directory. Use the `GetSystemDirectory` function to get the path of this directory.
> 4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
> 5. The Windows directory. Use the `GetWindowsDirectory` function to get the path of this directory.
> 6. The directories that are listed in the `PATH` environment variable.

So as long as you call this function before you call the function imported from the DLL for the first time, you can modify the default search path used to locate DLLs. The benefit, of course, is that you can pass a *dynamic* value to this function that is computed at run-time. That isn't possible with the `DllImport` attribute, so you will still use a relative path (the name of the DLL only) there, and rely on the new search order to find it for you.

You'll have to P/Invoke this function. The declaration looks like this:

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#6
set the dll path in the config file

<add key="dllPath" value="C:\Users\UserName\YourApp\myLibFolder\myDLL.dll" />

before calling the dll in you app, do the following



string dllPath= ConfigurationManager.AppSettings["dllPath"];
string appDirectory = Path.GetDirectoryName(dllPath);
Directory.SetCurrentDirectory(appDirectory);


then call the dll and you can use like below



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




Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through