How to Disable Aero Snap in an Application

How can I specify a [DllImport] path at runtime?

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). Those rules are enumerated in great detail 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.

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

Setting dllimport programmatically in C#

You can probably achieve this with the #if keyword. If you define a conditional compiler symbol called win32, the following code will use the win32-block, if you remove it it will use the other block:

#if win32
private static class ccf_32
{
[DllImport(myDllName32)]
public static extern int func1();
}
#else
private static class ccf_64
{
[DllImport(myDllName64)]
public static extern int func1();
}
#endif

This probably means that you can remove the class wrapping that you have now:

    private static class ccf
{
#if win32
[DllImport(myDllName32)]
public static extern int func1();
#else
[DllImport(myDllName64)]
public static extern int func1();
#endif
}

For convenience, I guess you could create build configurations for controlling the compilation symbol.

Specify the search path for DllImport in .NET

Call SetDllDirectory with your additional DLL paths before you call into the imported function for the first time.

P/Invoke signature:

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

To set more than one additional DLL search path, modify the PATH environment variable, e.g.:

static void AddEnvironmentPaths(string[] paths)
{
string path = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
path += ";" + string.Join(";", paths);

Environment.SetEnvironmentVariable("PATH", path);
}

There's more info about the DLL search order here on MSDN.


Updated 2013/07/30:

Updated version of the above using Path.PathSeparator:

static void AddEnvironmentPaths(IEnumerable<string> paths)
{
var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty };

string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths));

Environment.SetEnvironmentVariable("PATH", newPath);
}

C#: One attribute for multiple declarations (DLLImport)

No, there's no way to reduce the Attributes to a single declaration. You'll need to apply the Attribute to all methods.

But you can at least shorten your Attribute declarations to [DllImport(DLL_Path)], because the values you are specifying for CallingConvention and CharSet are the same as the default values.

How to dynamically load and unload a native DLL file?

Try this

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string libname);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool FreeLibrary(IntPtr hModule);

//Load
IntPtr Handle = LoadLibrary(fileName);
if (Handle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Exception(string.Format("Failed to load library (ErrorCode: {0})",errorCode));
}

//Free
if(Handle != IntPtr.Zero)
FreeLibrary(Handle);

If you want to call functions first you must create delegate that matches this function and then use WinApi GetProcAddress

[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

IntPtr funcaddr = GetProcAddress(Handle,functionName);
YourFunctionDelegate function = Marshal.GetDelegateForFunctionPointer(funcaddr,typeof(YourFunctionDelegate )) as YourFunctionDelegate ;
function.Invoke(pass here your parameters);


Related Topics



Leave a reply



Submit