Unity3d CharSet.Ansi - c#

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

Related

How to import Delphi function (that returns PAnsiChar) from DLL in C#

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

DllImport with non-exported functions. Why is it working?

I just encountered with strange behaviour of DllImport in C#, which I can't explain. I want to know how It is possible and where I can read about It. Case is that via DllImport one can call function that doesn't really exported form dll. In my case It is kernel32.dll and function ZeroMemory (but with Copy/Move/Fill memory such behavior). So, my code:
[DllImport("kernel32", EntryPoint = "LoadLibraryW", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string libName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr module, string procName);
//WTF???
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ZeroMemory(IntPtr address, int size);
static void TestMemory()
{
IntPtr mem = Marshal.AllocHGlobal(100); //Allocate memory block of 100 bytes size
Marshal.WriteByte(mem, 55); //Write some value in the first byte
ZeroMemory(mem, 100); //Clearing block of memory
byte firstByte = Marshal.ReadByte(mem); //Read the first byte of memory block
Console.WriteLine(firstByte); //Output 0 (not 55) - ZeroMemory is working
//Getting address of ZeroMemory from kernel32.dll
IntPtr kernelHandle = LoadLibrary("kernel32.dll");
IntPtr address = GetProcAddress(kernelHandle, "ZeroMemory");
Console.WriteLine(address.ToString("X")); //Output 0 - Library kernel32.dll DOESN'T export function ZeroMemory!!!
//Testing GetProcAddress via getting address of some exported function
Console.WriteLine(GetProcAddress(kernelHandle, "AllocConsole").ToString("X")); //Output some address value - all is OK.
}
No EntryPointNotFoundException is thrown - code works fine. If change name of ZeroMemory to ZeroMemory1 or something like that - exception will be thrown. But in export table of kernel32.dll we see:
There is NO ZeroMemory function at all!
If we look in msdn, we read that ZeroMemory is just a macro in WinBase.h header file for C++. Inside that we see:
#define RtlMoveMemory memmove
#define RtlCopyMemory memcpy
#define RtlFillMemory(d,l,f) memset((d), (f), (l))
#define RtlZeroMemory(d,l) RtlFillMemory((d),(l),0)
#define MoveMemory RtlMoveMemory
#define CopyMemory RtlCopyMemory
#define FillMemory RtlFillMemory
#define ZeroMemory RtlZeroMemory
Obviously, that in C++ ZeroMemory actually works through RtlFillMemory from ntdll.dll. But it is in C++!!! Why is it work in C#?? On official documentation for DllImport attribute here we can read the next:
As a minimum requirement, you must supply the name of the DLL
containing the entry point.
But in that case kernel32.dll CANNOT contating entry point for ZeroMemory. What is going on?? Help, please.
The OP is correct in that kernel32.dll has no export ZeroMemory export, yet the C# DllImport somehow succeeds to magically resolve the ZeroMemory reference to the correct RtlZeroMemory export in .NET apps targeted at the Framework (but not at Core).
Turns out that a handful of Win32 APIs documented as inlines/macros (MoveMemory, CopyMemory FillMemory, ZeroMemory) are specifically checked by the Framework code and internally rerouted to the correct exports. While not formally documented, this was acknowledged in a MS-sanctioned comment under a .NET Runtime issue.
As an FYI, there were a few special cased P/Invoke names in .NET Framework: MoveMemory, CopyMemory, FillMemory, and ZeroMemory. All of these will work when pointing at kernel32 on .NET Framework, but will fail on .NET Core. Please use the EntryPoint property in the DllImport attribute to get the desired behavior. The proper export names can be found using dumpbin /exports kernel32.dll from a Visual Studio command prompt.
The above suggests adding an explicit EntryPoint for the declaration to work in both Framework and Core, for example:
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static extern void ZeroMemory(IntPtr address, IntPtr count);
The magic name remapping happens outside the open-sourced .NET code, but can be clearly seen in the disassembly contributed by Simon Mourier in a comment.

Invalid pointer exception using pinvoke on libnfc for string values [duplicate]

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!

Making C# library using native Windows API

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.

Delphi dll and c# pinvoke declaration

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.

Categories

Resources