This question already has answers here:
PInvoke for C function that returns char *
(3 answers)
Closed 1 year ago.
I am trying to communicate with an NFC reader/writer on a raspberry pi 3 using dotnet core.
I have to say that the different libnfc command line tools I used are all working fine (aka I can read and poll my tags, no problem on this side).
The idea is to use dotnet core and C# to orchestrate the libnfc library and it seems to work fine except as soon as the function I call returns a string, I get the following error message:
*** Error in `./NfcTest': free(): invalid pointer: 0x6d4ebc00 ***
NfcTest being the name of my app of course.
Here is the pinvoke definition
[DllImport("libnfc", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string nfc_version();
Please note that after looking up on the web I did add the [return] attribute myself but it did not change anything to the result. Same error is raised.
The code of the nfc_version in libnfc is here: https://github.com/nfc-tools/libnfc/blob/c3f739dea339a71c59d7d53ab6b0ecc477c3ab73/libnfc/nfc.c#L1325
It seems to return a "constant" and no do any freeing of any kind. So my guess would be that I misconfigured one of the attributes.
Another example is that I call the following:
[DllImport("libnfc", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern string nfc_device_get_name(IntPtr pnd);
While I can perfectly call other methods (i.e. poll) using the pointer (pnd param) calling this one returns the same error as with the Version method. Both methods returning a string are making me wondering if the problem would not be in the DllImport but I'm not too sure how to fix that.
Link to lib code for that example: https://github.com/nfc-tools/libnfc/blob/c3f739dea339a71c59d7d53ab6b0ecc477c3ab73/libnfc/nfc.c#L1215
Any wisdom would be greatly appreciated.
The comment from Matthew Watson and the link he shared had the correct answer!
So I modified the pinvoke line like this:
[DllImport("libnfc", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr nfc_version();
Then I called it this way:
public string Version()
{
IntPtr ptr = Functions.nfc_version();
var str = Marshal.PtrToStringAuto(ptr);
return str;
}
And it works like a charm!
Thanks!
Related
Function in Delphi is -
FuncName: PAnsiChar (stdcall)
I don't know the rest of the function code, cause i can't open the Dll.
And i tried to implement it to C# like this -
[DllImport("Lib2-2-1.dll", EntryPoint = "FuncName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.AnsiBStr)]
public static extern string FuncName();
when i'm trying to call this C# function in code - everything just closes without an Error, and the code stops executing. Could someone help me please and explain how to write it properly.
And another thing. I tried to open this Dll in DotPeek but it won't open and it says - Not supported, could someone please explain how can i view the code inside it.
okey
so, here is the answer, i found it in this question thread
here is the importing from Dll
[DllImport("Lib2-2-1.dll", EntryPoint = "FuncName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[MethodImplAttribute(MethodImplOptions.PreserveSig)]
public static extern IntPtr FuncName();
And this how to call it
IntPtr ptr = FuncName();
string result = Marshal.PtrToStringAnsi(ptr);
I am building C# library (.dll), where some classes use native Windows API functions. To be specific, functions GetPrivateProfileString and WritePrivateProfileString, like:
static class NativeMethods
{
// external functions for working with ini files
[DllImport("kernel32.DLL", EntryPoint = "GetPrivateProfileStringW",
SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int GetPrivateProfileString(string lpAppName, string lpKeyName,
string lpDefault,
string lpReturnString,
int nSize,
string lpFilename);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool WritePrivateProfileString(string lpAppName,
string lpKeyName,
string lpString,
string lpFileName);
}
And using them:
NativeMethods.GetPrivateProfileString(section, key, "", result, 127, this.path);
NativeMethods.WritePrivateProfileString(section, key, " " + value, this.path);
When I am using this class directly in another project (without using it from dll), it works without problem. But when I build it into dll, then reference this dll in another project, then these functions aren't working. They simply do nothing.
Your pinvoke for GetPrivateProfileString is wrong as Matthew says. You need to use StringBuilder when passing string data back to the caller.
You are not checking for errors. So it's entirely plausible that the functions are failing without you knowing that.
In order to know why your calls are failing you'd first need to fix these issues. Then you can look at the return values. Knowledge also of the values of the parameters that you are using would help. But only you have the ability to do that, at present.
The bigger problem is that you are not meant to call these functions at all. The documentation says:
This function is provided only for compatibility with 16-bit Windows-based applications.
These functions contain numerous compatibility shims that make using them a complete minefield. Don't go there. Find a decent third party native C~ ini file class and pretend you never heard of GetPrivateProfileString and WritePrivateProfileString.
Oh, I found error. I forced to find ini file path in current directory (in my DLL class code). As I call it from DLL, it was automatically looking for file in C:\Windows. After using Directory.GetCurrentDirectory() + iniFile , it works.
I'm using a c++ dll in a Unity3D project. It`s important to use CharSet = CharSet.Ansi
[DllImport("Exchange3D", EntryPoint = "GetElementValue", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern double fnGetElementValue(int nType, int nNumber, string strPointName);
strPointName is sent to the dll. But the dll receives it in an incorrect format in the Unity Project!
But I created a C# Console Application with the same code and all is working!
Any ideas?
A string needs to be const char* on the c++ side, and not std::string. You might also consider defining the c++ functiona as a ansi-c function instead since that can be easier to map in c#.
Have a look at this piece of information to get an idea of how to map a simple function that works with a string.
https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx
I am wondering if someone could check my c# dllimport declaration for a dll compiled with Delphi XE2. Calling this dll from a ISAPI wrapper dll works fine but I am having no luck calling it from a c# asp.net app.
The Delphi procedure is defined as:
procedure ExecuteService(const RequestJSON :PWideChar; out ResponseJSON :Pointer; out ResponseJSONSize :Integer; out ResponseContent :Pointer; out ResponseContentSize :Integer); stdcall;
and the c# declaration is:
[DllImport("services.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern void BIExecuteService(
String requestJSON,
out IntPtr reposnseJSON,
out int reposnseJSONSize,
out IntPtr reposnseContent,
out int reposnseContentSize
);
Sometimes it works but mostly it gives a System.AccessViolationException.
I have been trying to solve this for days, do the declarations look correct?
Edit: Attaching to the IISExpress process in Delphi XE2 the error seems to occur in clr.dll. Maybe my library is corrupting something but I have no idea how to find out where!
Thanks,
AJ
Your p/invoke declaration is correct. Your problems lie elsewhere.
For some reason, whenever my C# .NET 2.0 application makes a call to GetProcAddress it always returns zero.
public class MyClass
{
internal static class UnsafeNativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
}
private void MyFunc()
{
IntPtr _dllHandle;
IntPtr _fptr;
string _fullPath = ".\\mydll.dll";
string _procName = "MyDllFunc";
_dllHandle = UnsafeNativeMethods.LoadLibrary(_fullPath);
_fptr = UnsafeNativeMethods.GetProcAddress(_dllHandle, _procName); // <-- Always returns zero.
}
}
I'm sure the function name is spelled correctly, and _fullPath is presumably correct because _dllHandle is always assigned a non-zero value. Any insight you may be able to provide is appreciated. Thanks.
GetProcAddress only comes in an ANSI flavor, hence we help the runtime by telling it to always use ANSI when marshalling the string parameter. We also prevent the runtime looking for a non-existent GetProcAddressA, because the default for C# is to set ExactSpelling to false.
http://www.pinvoke.net/default.aspx/kernel32.getprocaddress
You really need to add some error checking. At least verify if _dllHandle != IntPtr.Zero. Also, depending on the current working directory is dangerous, use Assembly.GetEntryAssembly().Location to get a full path name.
The function name is probably wrong. Exports tends to be decorated, like _MyDllFunc or _MyDllFunc#4. More wildly if it was compiled by a C++ compiler. Use Dumpbin.exe /exports on your DLL to see the real names.
Back to error handling, use SetLastWin32Error in the [DllImport] attribute. Throw Win32Exception if the function returns false or IntPtr.Zero.
Edit: I see the real problem. Using CharSet.Auto for GetProcAddress() is wrong. Very unlucky, it is just about the only Windows API function that only has an ANSI version. You have to use CharSet.Ansi. A good place to get proper [DllImport] declarations is pinvoke.net
You have not shown how you export the function from the DLL, but I suspect the problem is that the exported name is not what you thing it is. You can run dumpbin /exports mydll.dll to view the exports of the dll to verify the name.
If you show the a code snippet of the export, I could provide more direct advice. You can try decorate the exported function with extern "C" to eliminate the name mangling as a test.
Does your export in the .DEF file for the DLL match the input here? You can use dumpbin to find out what's exported, per other replies here.
What is the underlying Win32 error on GetProcAddress(), per GetLastError()?
You could try this in native code to work out the correct inputs first without the additional baggage of P/Invoke.