how to access the methods of non .net dll in .net in c#? which class is used to access the dll methods.
You do this with P/Invoke. An excellent resource is pinvoke.net.
A simple example would be GetTickCount:
[DllImport("kernel32.dll")]
static extern uint GetTickCount();
Something more complex, MessageBox:
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, int options);
Related
I am writing a C# binding for an unmanaged C dll.
The dll provides 5 hooks to return several data:
typedef void (*t_libpd_printhook)(const char *recv);
and exports a field like:
EXTERN t_libpd_printhook libpd_printhook;
now i was using Interop Assistant to generate the binding code, which gave me just a delegate definition:
public delegate void t_libpd_printhook([In] [MarshalAs(UnmanagedType.LPStr)] string recv);
So is there some magic Interop function call i can use, to set the t_libpd_printhook field in the DLL?
You can use LoadLibrary and GetProcAddress to obtain a pointer to the exported libpd_printhook variable. You can then use Marshal.WriteIntPtr and Marshal.GetFunctionPointerForDelegate to assign to the delegate.
[DllImport("kernel32", SetLastError=true, CharSet=CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true,
SetLastError=true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
.....
IntPtr lib = LoadLibrary(#"mydll.dll");
IntPtr plibpd_printhook = GetProcAddress(lib, "libpd_printhook");
Marshal.WriteIntPtr(plibpd_printhook,
Marshal.GetFunctionPointerForDelegate(mydelegate));
FreeLibrary(lib);
You will want to add the error checking that I excised in the interests of a concise example.
Now, if you are in control of the unmanaged library I would still recommend adding a function to encapsulate writing to this function pointer. That feels like a better interface to me.
PInvoke does not support exported variable. You need to create an unmanaged function which takes your delegate and copies it into the field.
I'm sure I'm missing something obvious in the documentation. I'm calling LoadLibrary from C# and passing in a DLL that isn't there. I'm getting back IntPtr.Zero as I would expect, but when I call Marshal.GetLastWin32Error I always get 0.
Here's the sample.
class Program {
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr hModule);
static void Main(string[] args) {
IntPtr pDll = LoadLibrary(#"c:\NotThere.dll");
int err = Marshal.GetLastWin32Error();
Console.WriteLine(err);
Console.ReadLine();
}
}
I'm adding code like this to a program that's already failing to load a DLL for no apparent reason. Any idea why I'm not getting an error message?
For errors to get logged so that they can be read by Marshal.GetLastWin32Error(), you need to have SetLastError=true on the DllImport attribute:
[DllImport("kernel32.dll", SetLastError=true)]
private static extern IntPtr LoadLibrary(string dllToLoad);
Your code doesn't set the DllImport.SetLastError attribute flag, which might be why GetLastWin32Error isn't returning anything:
[DllImport("kernel32.dll", SetLastError=true)]
private static extern IntPtr LoadLibrary(string dllToLoad);
To diagnose why modules aren't being loaded you should check Fusion logs (if the module is a managed assembly), and / or dependency walker.
Bear in mind that the load error might be caused because a dependent module could not be loaded (e.g. the VC9 redistributable, on which all C++ modules compiled with the VS2008 compiler depend on), and so even if the module is architecture compatible and located in a searchable directory (such as the application or system directory), the module may still fail to load - Dependency walker is very good at highlighting these sorts of issues.
You have to declare in your DllImport attribute that you want the last error to be captured using the SetLastError field. For example:
[DllImport("kernel32.dll", SetLastError=true)]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool FreeLibrary(IntPtr hModule);
Use the following DllImport:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(string dllToLoad);
try to add this attribute:
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
from msdn:
Returns the error code returned by the last unmanaged function that was called using platform invoke that has the DllImportAttribute.SetLastError flag set.
While working with WinAPI, I decided to implement a call to GetProcessAfinityMask in my C# application. However, I've seen two different signatures for this function.
One of them uses SafeProcessHandle for the handle:
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool GetProcessAffinityMask(SafeProcessHandle handle, out IntPtr processMask, out IntPtr systemMask);
The other possible version (on P/Invoke) uses IntPtr:
[DllImport("kernel32.dll",SetLastError = true)]
static extern bool GetProcessAffinityMask(IntPtr hProcess,
out UIntPtr lpProcessAffinityMask, out UIntPtr lpSystemAffinityMask);
Given that both functions return the same values, what is the difference between passing a SafeProcessHandle instance or IntPtr?
Safe Handles and Critical Finalization MSDN Article is describing this difference.
I saw a method called Control.FromHandle which (should) give you the access to it.
Now, I wanted to try it using this code
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
// Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern bool ReleaseDC(IntPtr hwnd, IntPtr hdc);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
IntPtr ptr = FindWindowByCaption(IntPtr.Zero, "Download");
Control f = Control.FromHandle(ptr);
f.Text = "Something";
}
but it won't, obviously, work.
I checked personally that the handle is correct... but the method returns a null control.
Any explaining?
This method only works if the handle you pass in actually is a Control in your application.
In your particular case, since you just want to set the text, call SetWindowText from user32.dll
For anyone else googling that found this answer and wondered why this behavior is the case this post http://www.codeguru.com/forum/showthread.php?t=443191 is particularly enlightening, specifically the last post from 'MadHatter':
well just from looking over what goes on in Control.FromHandle in reflector, it looks like as windows are added to the .net world, it stores a table of what handles it has loaded, the problem comes when you pass in a handle that is not listed in its tables. There may be some hack that would allow you to register the window through all the subsystems that are used when creating windows from within the .net app, but it would probably be better / more consistent to wrap whatever functionality you need directly through the windows api then try to hack in Control.FromHandle to allow you to access / manipulate the window of some other process.
Reading more into your question it seems like you are trying to do some automation or at very least manipulate the window in some way. Might I recommend looking at the Managed Windows API project on SourceForge. It is pretty well written and we've used it for the purposes you are describing.
I am using some native methods to bind to running objects in a COM-based application. One of the methods is the CreateBindCtx, which has the following signature (from MSDN)
WINOLEAPI CreateBindCtx(DWORD reserved, LPBC FAR * ppbc)
I have defined the wrapper to be
public static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
But FXCop is complaining about the void return type. What should the .Net/C# data type be?
[DllImport("ole32.dll")]
static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
One of the best places for pinvoke info is PInvoke.Net