I've got native DLL (without sources) with two extern methods: Init and DoSomeWork.
Here is my class-wrapper:
public class MyClass : IDisposable
{
[DllImport(#"myDLL.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi,
EntryPoint = "EntryPoint#1",
ExactSpelling = true)]
private static extern IntPtr InitNative();
[DllImport(#"myDLL.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi,
EntryPoint = "EntryPoint#2",
ExactSpelling = true)]
private static extern ushort DoSomeWorkN(byte[] arrayOut, [In] IntPtr initHandle);
private readonly IntPtr _initHandle;
public MyClass()
{
_initHandle = InitNative();
}
protected override byte[] DoSomeWork()
{
...
DoSomeWorkN(buffOut, _initHandle);
...
}
public override void Dispose()
{
//???
}
I've tried:
Marshal.FreeHGlobal(_initHandle); //throws exception: Invalid access to memory location. (Exception from HRESULT: 0x800703E6)"}
Marshal.FreeCoTaskMem(_initHandle); //throws Access violation exception
Marshal.FreeBSTR(_initHandle); //doesn't throw exception, but doesn't work (after calling that method IntPtr isn't IntPtr.Zero)
So, how to implement correct disposing of _initHandle?
Your library should/must give you a third method:
void Free(IntPtr handle);
You can't know how the memory was allocated. If the memory was allocated through C malloc you can't even easily free it. Even worse, if it is a C++ object, only C++ can correctly deallocate it (calling the correct destructors). It must be the library to give you a method to free its memory.
(technically you can't even know what the IntPtr is :-) Perhaps it isn't really a pointer. It could be a number and you don't have to free anything... or it could be an HANDLE returned by Win32 CreateFile)
Related
I have .NET DLL import library in my project, which functions I want to call taking its name from function table (List<string>).
Assuming all they has same return type and parameters.
I have functions_table[] with something like "Func1", "Func2" ....
I randomly select from that table (really it is like List) and call it in my program.
As I can understand C# delegate is not for this solution.
I want to randomly choose function with name Func1() (for example) be called from managed C# code with their parameters.
How can be that achieved?
Because you said that this functions must be called from managed code, I believe that functions DLL is native. So firstly, you need some native methods to load\free this library and call functions:
public static class NativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr LoadLibrary(string filename);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
}
Then use this code to load DLL:
var libHandle = NativeMethods.LoadLibrary(fileName);
if (libHandle == IntPtr.Zero)
{
var errorCode = Marshal.GetLastWin32Error();
// put error handling here if you need
}
And to free:
if (libHandle != IntPtr.Zero)
NativeMethods.FreeLibrary(libHandle);
You will also need the delegate to make the call . For example,
delegate int FuncDelegate(int arg1, bool arg2);
And then to call the function from DLL:
var func1Address = NativeMethods.GetProcAddress(libHandle, "Func1");
var func1 = (FuncDelegate)Marshal.GetDelegateForFunctionPointer(func1Address, typeof(FuncDelegate));
var result = func1(42, true);
And of course you can (and probably should) cache this functions:
private Dictionary<string, FuncDelegate> _functionsCache = new Dictionary<string,FuncDelegate>();
private int CallFunc(string funcName, int arg1, bool arg2)
{
if (!_functionsCache.ContainsKey(funcName))
{
var funcAddress = NativeMethods.GetProcAddress(libHandle, funcName);
var func = (FuncDelegate)Marshal.GetDelegateForFunctionPointer(funcAddress, typeof(FuncDelegate));
_functionsCache.Add(funcName, func);
}
return _functionsCache[funcName](arg1, arg2);
}
MethodInfo handler = GetType.GetMethod("NameMethod");
handler.Invoke(context, new object[] {parameters}
does the trick
I'm trying to use the WINAPI functions FindFirstFile and FindNextFile.
However, I'm experiencing some issues.
When I first call the function FindFirstFile it works fine. I've got a valid handler and the first folder/file name is properly populated inside the WIN32_FIND_DATA structure. No error is found with GetLastError.
Then, I call FindNextFile which returns true as there are more folders in the directory I'm scanning. But I can't retrieve the next folder/file name and GetLastError returns 123 (0x7B) ERROR_INVALID_NAME.
I'm a little confused as it says in the official documentation that if an error occurs it should return 0.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364428(v=vs.85).aspx
Return value
If the function succeeds, the return value is nonzero and the lpFindFileData parameter contains information about the next file or directory found.
If the function fails, the return value is zero and the contents of lpFindFileData are indeterminate. To get extended error information, call the GetLastError function.
If the function fails because no more matching files can be found, the GetLastError function returns ERROR_NO_MORE_FILES.
I'm using .NET 4.5.1 and Visual Studio 2013 on Windows 7 x64.
Here is a sample code.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WIN32_FIND_DATA
{
public uint dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
...
[DllImport("Kernel32.dll", EntryPoint = "FindFirstFile", SetLastError = true)]
public static extern IntPtr FindFirstFile(string lpFileName, ref WIN32_FIND_DATA lpFindFileData);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("Kernel32.dll", EntryPoint = "FindFirstFile", SetLastError = true)]
public static extern bool FindNextFile(IntPtr hFindFile, ref WIN32_FIND_DATA lpFindFileData);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("Kernel32.dll", EntryPoint = "FindClose", SetLastError = true)]
public static extern bool FindClose(IntPtr hFindFile);
...
public static void Test()
{
WIN32_FIND_DATA metaDataFile = new WIN32_FIND_DATA();
IntPtr nextHandle = FileScanner.FindFirstFile("C:\\*", ref metaDataFile);
Console.WriteLine(Marshal.GetLastWin32Error()); // This equals 0x0 ERROR_SUCCESS
Console.WriteLine(metaDataFile.cFileName); // This equals $Recycle.Bin
/* Check invalid handler */
if (nextHandle != new IntPtr(-1L))
{
bool moreFiles = true;
while (moreFiles)
{
moreFiles = FileScanner.FindNextFile(nextHandle, ref metaDataFile);
Console.WriteLine(Marshal.GetLastWin32Error()); // This equals 0x7B ERROR_INVALID_NAME
Console.WriteLine(metaDataFile.cFileName); // This equals $Recycle.Bin and this value never change.
}
FindClose(nextHandle);
}
}
For some reason, moreFiles is always true and GetLastError returns ERROR_INVALID_NAME ...
If you need any details please ask me.
Any help would really be appreciated !
Only call Marshal.GetLastWin32Error is the API call reports failure. In the case of FindNextFile it does so by returning false. You are checking the value returned by Marshal.GetLastWin32Error indiscriminately.
The documentation makes this clear when it tells you how the functions indicate failure. You even linked the text. But you said:
I'm a little confused as it says in the official documentation that if an error occurs it should return 0.
That's right. So check the return value against 0. In the case of a BOOL marshalled as C# bool, that means that the function returns false if it fails. But you simply ignored the return value and tested the value returned by Marshal.GetLastWin32Error(), something altogether different.
The code should be more like this:
public static void Test()
{
WIN32_FIND_DATA fd = new WIN32_FIND_DATA();
IntPtr findHandle = FileScanner.FindFirstFile("C:\\*", ref fd);
if (findHandle == INVALID_HANDLE_VALUE)
throw new Win32Exception();
do
{
Console.WriteLine(fd.cFileName);
} while (FileScanner.FindNextFile(findHandle, ref fd));
// you might check that Marshal.GetLastWin32Error() returns ERROR_NO_MORE_FILES
// at this point, otherwise the enumeration failed abnormally
if (!FindClose(findHandle))
throw new Win32Exception();
}
Your other problem, and it's what hurting you most, is your p/invoke declarations. Look closely at this one:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("Kernel32.dll", EntryPoint = "FindFirstFile", SetLastError = true)]
public static extern bool FindNextFile(IntPtr hFindFile,
ref WIN32_FIND_DATA lpFindFileData);
The EntryPoint is not correct. So you are actually calling FindFirstFile instead of FindNextFile and it's hardly surprising that fails.
Specifying the EntryPoint when you don't need to is simply asking for trouble. And you've fallen right into the trap. I'd declare these imports like so:
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr FindFirstFile(string lpFileName,
ref WIN32_FIND_DATA lpFindFileData);
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool FindNextFile(IntPtr hFindFile,
ref WIN32_FIND_DATA lpFindFileData);
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool FindClose(IntPtr hFindFile);
Note that there's no need for the return attribute since UnmanagedType.Bool is the default.
And then you'd need to change the CharSet on the struct to be CharSet.Unicode to match. There's no point at all in opting for ANSI here.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WIN32_FIND_DATA
{
....
}
Finally, all of this code seems to me to be pointless. What's wrong with Directory.EnumerateFiles and Directory.EnumerateDirectories?
I am having trouble implementing an answer I got here!, Can anyone help me access this private static class?
namespace VEParameterTool
{
class ProcessorPlugIn
{
private static class UnsafeNativeMethods
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", SetLastError = true)]
static extern bool FreeLibrary(IntPtr hModule);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ErrorCode ProcessorFunction(ref IntPtr pRx);
IntPtr hLib = UnsafeNativeMethods.LoadLibrary("Processor.dll");
}
}
When I try to LoadLibrary, I get the error about protection levels:
'VEParameterTool.ProcessorPlugIn.UnsafeNativeMethods.LoadLibrary(string)' is inaccessible due to its protection level
I have searched for the solution but cant see anything to do with static classes.
Any hep would be greatly appreciated.
Andy
Why are you attempting to declare a private static class? The only method I can think of potentially being able to access information within the class is if you were to make it a nested private static class with public methods - and based on the code posted that is not the case.
Private means just that - it cannot be accessed from outside. Read more about access modifiers here: http://msdn.microsoft.com/en-us/library/ms173121.aspx
See here for an example of a private static class implementation:
https://dotnetfiddle.net/Lyjlbr
using System;
public class Program
{
public static void Main()
{
Bar.DoStuff();
// Bar.DoOtherStuff(); // Cannot be done due to protection level
Bar.DoStuffAndOtherStuff(); // note that this public static method calls a private static method from the inner class
}
private static class Bar
{
public static void DoStuff()
{
Console.WriteLine("Test");
}
public static void DoStuffAndOtherStuff()
{
DoStuff();
DoOtherStuff();
}
private static void DoOtherStuff()
{
Console.WriteLine("other stuff");
}
}
}
EDIT: apparently you can also use reflection to access private classes/members/functions, but I don't know much about it. See here: Why can reflection access protected/private member of class in C#?
You can leave the inner class private, making it only accessible to the ProcessorPlugIn class, but you have to make the methods public.
private static class UnsafeNativeMethods
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
}
These methods will be only accessible from where their containing class can be accessed, in this example, ProcessorPlugIn.
I try use a dll created in c in c#, but I get the error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I see very topics here, but i'm not solve the problem. It's possible help me?
My C# code is:
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32")]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("lib.dll", EntryPoint = "LoadRes", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern SRes LoadRes([MarshalAs(UnmanagedType.LPStr)]string str, bool type);
SRes sres = new SRes();
string path="C:\\123456.fil";
System.IntPtr load = LoadLibrary("lib.dll");
System.IntPtr adress = GetProcAddress(load, "LoadRes");
sres = LoadRes(path, true);
My code to export in c is
__declspec(dllexport) SRes LoadRes( const char *filename, bool header_only );
Thank's for help!!
I have a buggy third-party DLL files that, after some time of execution, starts throwing the access violation exceptions. When that happens I want to reload that DLL file. How do I do that?
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);
Create a worker process that communicates via COM or another IPC mechanism. Then when the DLL dies, you can just restart the worker process.
Load the dll, call it, and then unload it till it's gone.
I've adapted the following code from the VB.Net example here.
[DllImport("powrprof.dll")]
static extern bool IsPwrHibernateAllowed();
[DllImport("kernel32.dll")]
static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll")]
static extern bool LoadLibraryA(string hModule);
[DllImport("kernel32.dll")]
static extern bool GetModuleHandleExA(int dwFlags, string ModuleName, ref IntPtr phModule);
static void Main(string[] args)
{
Console.WriteLine("Is Power Hibernate Allowed? " + DoIsPwrHibernateAllowed());
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
private static bool DoIsPwrHibernateAllowed()
{
LoadLibraryA("powrprof.dll");
var result = IsPwrHibernateAllowed();
var hMod = IntPtr.Zero;
if (GetModuleHandleExA(0, "powrprof", ref hMod))
{
while (FreeLibrary(hMod))
{ }
}
return result;
}