I am totally new to C++ programming. I need to call a C++ function from C#.
C++ function is:
BOOL Usb_Init(HWND hwnd);
I've tried:
[DllImport("UsbComm.dll", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool Usb_Init( out IntPtr hwnd);
I got the Error message:
PInvoke signature does not match the unmanaged target signature.
How to call the above C++ method?
I see the following mistakes in the code in the question:
The C++ code uses cdecl and the C# code uses stdcall. That does not match.
The C++ code is passed an HWND by value. The C# code has an IntPtr passed as an out parameter. That does not match.
There are multiple spurious arguments to the DllImport attribute.
The correct C# declaration is:
[DllImport("UsbComm.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool Usb_Init(IntPtr hwnd);
You could set ExactSpelling to true but I see no compelling reason to do so. Feel free to add that if you prefer. There's no point in specifying CharSet since there is no text involved. And SetLastError = true is probably a mistake. It's unlikely in my judgement that the unmanaged function calls SetLastError. My expectation is that you added SetLastError = true whilst trying to get rid of the error.
BOOL is defined as int in <windef.h>
You'll need to use int in the export declaration in C#. Reminder: a value of 0 equals false; anything else is true.
public static extern int Usb_Init(out IntPtr hwnd);
But also, your calling convention could also be wrong. Try each enum of CallingConvention
EDIT: The working signature is
[DllImport("UsbComm.dll", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int Usb_Init(out IntPtr hwnd);
C++ code: Make sure definition of Usb_Init should look as shown below:
extern "C" __declspec(dllexport) BOOL __stdcall Usb_Init(HWND hwnd)
{
return TRUE;
}
C# code:
using System;
using System.Runtime.InteropServices;
namespace Win32DllClient
{
class Program
{
[DllImport("UsbComm.dll", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern bool Usb_Init(out IntPtr hwnd);
static void Main(string[] args)
{
IntPtr hwnd = new IntPtr(0);
var ret = Usb_Init(out hwnd);
}
}
}
Related
I am trying to use EasyHook to detect native LoadLibrary calls.
It indeed detects the loading of libraries, however the process results in freezing.
This is because the LoadLibrary_Hook method below cannot load the dll or library since It returns 0 IntPtr (Probably can't find the library.).
I even tried setting the events to a "void" type but then the process simply crashes, this is probably because EasyHook expects me to return a value to overwrite the function.
Is there a way for me to return the exactly needed library to be loaded, or just simply get the name of the library that is being loaded without me having to load the library manually?
(There are also names like this which are loading in the process: 瑮汤汤l邐邐讐嗿謘ౕ㍓四襗ﱝ嶉觬嶉觰嶉㯨࿓トă謀ࡅ쌻萏Ͽ䶋㬔瓋㤉ᡝ萏ϯ팻Ѵ᪉ᢉ疋㬐ă㬀瓋謇ᡅᦉᢉ綋㬜 which is kinda odd...)
private static LocalHook hook;
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(IntPtr handle, string varormethodname);
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
public delegate IntPtr LoadLibraryDelegate(string lpFileName);
public TestHook()
{
IntPtr kernel32 = GetModuleHandle("kernel32.dll");
Logger.Log("Kernel: " + kernel32);
IntPtr address = GetProcAddress(kernel32, "LoadLibraryA");
Logger.Log("Address: " + address);
hook = LocalHook.Create(address,
new LoadLibraryDelegate(LoadLibrary_Hook),
null);
hook.ThreadACL.SetExclusiveACL(new Int32[] {0});
//RemoteHooking.WakeUpProcess();
}
public IntPtr LoadLibrary_Hook(string lpFileName)
{
Logger.Log("File load: " + lpFileName);
return LoadLibrary(lpFileName);
}
Solution was to call the original method using the original function address:
public IntPtr LoadLibrary_Hook(string lpFileName)
{
Logger.Log("File load: " + lpFileName);
LoadLibraryDelegate origMethod = (LoadLibraryDelegate)Marshal.GetDelegateForFunctionPointer(LoadLibraryAddress, typeof(LoadLibraryDelegate));
return origMethod(lpFileName);
}
I have C++ DLL.
When call method from this DLL in C# AccessViolation was been throwing.
What in my code is wrong? Can someone help me?
C++ Header part:
typedef PVOID X_HANDLE;
XREADER_API BOOL ReaderOpen(X_HANDLE *pxHandle);
XREADER_API BOOL ReaderReceiveW26(X_HANDLE xHandle, LPVOID pBuffer, DWORD nBufferSize);
Working Example part C++:
X_HANDLE hReader;
unsigned char xKeyBuffer[3];
ReaderOpen(&hReader);
ReaderReceiveW26(hReader,xKeyBuffer,sizeof(xKeyBuffer));
My C# Code:
[DllImport("reader.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool ReaderOpen(IntPtr reference);
[DllImport("reader.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool ReaderReceiveW26(IntPtr hReader, IntPtr pBuffer, uint xKeyBuffer);
static void Main(string[] args)
{
byte[] received = new byte[3];
IntPtr unmanagedPointer = Marshal.AllocHGlobal(received.Length);
Marshal.Copy(received, 0, unmanagedPointer, received.Length);
IntPtr hReader = Marshal.AllocHGlobal(sizeof(uint));
var qqq = uint.Parse((Marshal.SizeOf(typeof(byte)) * received.Length).ToString());
ReaderOpen(hReader);
while (true)
{
if (ReaderReceiveW26(hReader, unmanagedPointer, qqq))
{
Console.WriteLine("!");
}
}
}
AccessViolation throwing at ReaderReceiveW26(hReader, unmanagedPointer, qqq)
Thanks for your patience!
Thanks to Hast Passant comment!
If we want use IntPtr or smth which edited by unmanaged code we need use
out paramName
For PVOID we can pass real c# type.
Working example:
[DllImport("reader.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool ReaderOpen(out IntPtr reference);
[DllImport("reader.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool ReaderReceiveW26(IntPtr hReader, byte[] pBuffer, uint xKeyBuffer);
For now I'm using below definition in the C# side
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(IntPtr handle,float[] obj);
to send a float array to C space in a c++ dll as in below definition
__declspec(dllexport)
void bufferWrite(OpenClBuffer * handle, void * ptr)
{
...
}
and it works(or seems like working). Now I need to support double, long and byte arrays too. Also I dont want to rewrite additional functions in c++ dll because it is already using a void pointer and size of buffer is handled by some other parameters inside.
Is it legal to use "ref object obj" instead of "float[] obj" or "long [] obj" in the C# space for all platforms(32 bit, 64 bit, xp,7,8.1,10) as in below
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(IntPtr handle,ref object obj);
or do I need to add extra functions to c++ such as
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWriteFloat(...);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWriteInt(...);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWriteLong(...);
and make them call same old function with a casting to (void *)? Maybe just overloading the function in C# is enough and workds 100% of time?
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrit(..., float[] obj);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(..., long[] obj);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(..., double[] obj);
I'm assuming a void pointer is always same size as an array pointer when C#-C++ interop is used.
Is there a way to call "IsWow64Process" function from kernel32 capitalized? Like "ISWOW64PROCESS"? Or completely lowered like "iswow64process"?
And if no, are there any hack-arrounds to achieve this task? Thanks!
C# is a case sensitive language, but you can define the pinvoke call any way you like, you just need to be consistent. You can map the EntryPoint in your PInvoke call and define the function to be all uppercase like this:
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi, EntryPoint = "IsWow64Process")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ISWOW64PROCESS([In] IntPtr processHandle,
[Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process);
private void button1_Click_2(object sender, EventArgs e)
{
bool is64;
ISWOW64PROCESS(Process.GetCurrentProcess().Handle, out is64);
MessageBox.Show(is64.ToString());
}
The DllImportAttribute.EntryPoint field allows you to specify the real name of the imported function.
Directly from the example at that link are two lines that show how you can rename the MessageBox function:
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "MessageBox")]
public static extern int MyNewMessageBoxMethod(IntPtr hWnd, String text, String caption, uint type);
I have a C dll with exported functions
I can use the command-line tool dumpbin.exe /EXPORTS to extract the list of exported functions, and then use them in my C# code to (successfully) call these functions.
Is there a way to get this exported-functions-list directly from .NET, without having to use an external command-line tool?
Thanks
As far as I know there is no class in the .Net Framework that
provides the information you need.
However you can use the platform invocation services (PInvoke) of the .Net platform to
use the functions of the Win32 dbghelp.dll DLL. This DLL is part of
the Debugging Tools for the Windows platform. The dbghelp DLL provides
a function called SymEnumerateSymbols64 which allows you to enumerate all
exported symbols of a dynamic link library. There is also a
newer function called SymEnumSymbols which also allows to enumerate
exported symbols.
The code below shows a simple example on how to use the SymEnumerateSymbols64
function.
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, [MarshalAs(UnmanagedType.Bool)]bool fInvadeProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymCleanup(IntPtr hProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile,
string ImageName, string ModuleName, long BaseOfDll, int DllSize, IntPtr Data, int Flags);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymEnumerateSymbols64(IntPtr hProcess,
ulong BaseOfDll, SymEnumerateSymbolsProc64 EnumSymbolsCallback, IntPtr UserContext);
public delegate bool SymEnumerateSymbolsProc64(string SymbolName,
ulong SymbolAddress, uint SymbolSize, IntPtr UserContext);
public static bool EnumSyms(string name, ulong address, uint size, IntPtr context)
{
Console.Out.WriteLine(name);
return true;
}
static void Main(string[] args)
{
IntPtr hCurrentProcess = Process.GetCurrentProcess().Handle;
ulong baseOfDll;
bool status;
// Initialize sym.
// Please read the remarks on MSDN for the hProcess
// parameter.
status = SymInitialize(hCurrentProcess, null, false);
if (status == false)
{
Console.Out.WriteLine("Failed to initialize sym.");
return;
}
// Load dll.
baseOfDll = SymLoadModuleEx(hCurrentProcess,
IntPtr.Zero,
"c:\\windows\\system32\\user32.dll",
null,
0,
0,
IntPtr.Zero,
0);
if (baseOfDll == 0)
{
Console.Out.WriteLine("Failed to load module.");
SymCleanup(hCurrentProcess);
return;
}
// Enumerate symbols. For every symbol the
// callback method EnumSyms is called.
if (SymEnumerateSymbols64(hCurrentProcess,
BaseOfDll, EnumSyms, IntPtr.Zero) == false)
{
Console.Out.WriteLine("Failed to enum symbols.");
}
// Cleanup.
SymCleanup(hCurrentProcess);
}
In order to keep the example simple I did not use the
SymEnumSymbols function. I've also did the example
without using such classes as the SafeHandle class of
the .Net framework. If you need a example for the
SymEnumSymbols function, just let me know.