Delphi dll and c# pinvoke declaration - c#

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.

Related

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.

C/C++ DLL failing after .NET framework upgrade from 3.5 to 4.6

I have application called as Agent which have 2 projects :
C# project
C/C++ DLL
Whole application was running fine with .NET 3.5 which we use to build with vs2008.
Due to some requirement we upgraded the .Net Framework to 4.6 and vs 2019 to build this up.
Now my application service runs but looks like C/C++ dll exports are failing somewhere.
What I have tried:
C# side
TAgtLib.TAStartAgent(mServerPort, mName, mBinDir, mPath, mDebug,
mStdout, mDefaultLogDays, mEncryptOnly);
where TAgtLib is wrapper class which declares these C/C++ function like this
[DllImport("ccplusplus.dll", CharSet = CharSet.Ansi)]
public static extern int TAStartAgent(int port, string name, string bindir, string rundir, string debugOption, string stdoutOption, int mDefaultLogDays, int encryptonly);
C++ definition :
extern "C" int _stdcall TAStartAgent(int PortNum, char *Name, char *binDir, char *runDir, char *debugOption, char *stdoutOption, int mDefaultLogDays, int encryptonly);
Whenever debugging is hitting on this function from c# it goes into memory violation.
When we changed to binDir.ToArray() and changed the dllexport declaration as char[] binDir ,simmilary for runDir,it didnt gave access violation but it went inside the dll.
Though C dll still giving issues.
Can someone please guide me off what is that must be effecting the c/c++ dll after this migration from 3.5 to 4.6?
I am novice wrt C#.
Thanks
This is likely happening because .Net 4 changed the way that it corrects incorrect P/Invoke calling conventions.
From https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ee941656(v=vs.100):
To improve performance in interoperability with unmanaged code,
incorrect calling conventions in a platform invoke now cause the
application to fail. In previous versions, the marshaling layer
resolved these errors up the stack.
To solve this, you must specify the correct calling convention in the P/Invoke declaration, e.g.
DllImport("ccplusplus.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int TAStartAgent(int port, string name, string bindir, string rundir, string debugOption, string stdoutOption, int mDefaultLogDays, int encryptonly);
Although you will of course need to specify the correct calling convention for your DLL.

Unity3d CharSet.Ansi

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

C++ function exported in dll and loaded from C#

I have in C++:
void __declspec(dllexport) foo(HWND wnd)
And in C#
[DllImport("MyDll.dll", CharSet = CharSet.Ansi)]
public static extern void foo(IntPtr wnd);
When I'm trying to call it I have this error - Additional information: Unable to find an entry point named 'foo' in DLL. I tried to inspect the dll and I have the function with the fallowing definition:
Undecorated C++ Function:
void cdecl foo(struct HWND *)
I searched on several forums and is seems that this is the right way to do this... Do you know why I have this run time error?
You need to disable C++ name mangling. Declare your native function like this:
extern "C" __declspec(dllexport) void foo(HWND wnd)
You can use the dumpbin.exe utility to see DLL exports as well.

"Unable to find an entry point named [function] in dll" (c++ to c# type conversion)

I have a dll which comes from a third party, which was written in C++.
Here is some information that comes from the dll documentation:
//start documentation
RECO_DATA{
wchar_t Surname[200];
wchar_t Firstname[200];
}
Description:
Data structure for receiving the function result. All function result will be
stored as Unicode (UTF-8).
Method:
bool recoCHN_P_Name(char *imgPath,RECO_DATA *o_data);
Input:
char * imgPath
the full path of the image location for this
function to recognize
RECO_DATA * o_data
data object for receiving the function
result.
Function return:
True if Success, otherwise false will return.
//end documentation
I am trying to call the recoCHN_P_Name from my C# application. To this end, I came up with this code:
The code to import the dll:
public class cnOCRsdk
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECO_DATA{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=200)]
public string FirstName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
public string Surname;
}
[DllImport(#"cnOCRsdk.dll", EntryPoint="recoCHN_P_Name")]
public static extern bool recoCHN_P_Name(byte[] imgPath, RECO_DATA o_data);
}
The code to call the function:
cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA();
string path = #"C:\WINDOWS\twain_32\twainrgb.bmp";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] bytes = encoding.GetBytes(path);
bool res = cnOCRsdk.recoCHN_P_Name(bytes, recoData);
And the error I'm getting is
""Unable to find an entry point named 'recoCHN_P_Name' in DLL 'cnOCRsdk.dll'."
I'm suspecting that I'm having an error in converting a type from C++ to C#. But where exactly ... ?
First make sure the function is actually exported:
In the Visual Studio Command Prompt, use dumpbin /exports whatever.dll
C# doesn't support C++ name mangling and you either need to declare the C++ functions with
extern "C" {...}
(may not an option if they're from a third party), or call the mangled name directly if you can get it to work. It may be easier to get the third party to provide a non-mangled interface to the functionality.
Solved - at least to the point where the program does not break and actually returns me a bool value.
The key, I guess, was to specify the entry point as the 'mangled' name
[DllImport(#"cnOCRsdk.dll", EntryPoint="?recoCHN_P_Name#CcnOCRsdk##QAE_NPADPAURECO_DATA###Z")]
public static extern bool recoCHN_P_Name(ref string imgPath, ref RECO_DATA o_data);
After that I got some other errors but the 'unable to find entry point' went away.
I solved the same problem in these steps:
step 1) If you program your custom DLL in C++ using Visual studio,then at the property page of your project set the Common Language Runtime Support (/clr)parameter to Common Language Runtime Support (/clr).
step 2) To function deceleration in .h file use __declspec(dllexport) keyword like below:
__declspec(dllexport) double Sum(int a,int b);
step 3) Build and export DLL file, then use the Dependency Walker software to get your function EntryPoint.
step4) Import DLL file In the C# project and set EntryPoint and CallingConvention variable like below:
[DllImport("custom.dll", EntryPoint = "?Sum##YAXHHHHHHNNN#Z", CallingConvention = CallingConvention.Cdecl)]
public static extern double Sum(int a,int b);
I'd write a wrapper using C++/CLI. This wrapper will be able to include the .h files and link to the .lib files you got from the third party vendor. Then it is both easy and safe to write a managed interface for your C# program.
Correct EntryPoint string could be found in ".lib" file that comes along with main unmanaged dll.
We had this problem when we want to access to DB and solved it by changing EF core to EF 6.4.4
It may be you have a problem like this and need to change or downgrade your version of EF (If you used EF)
We had this problem .we change EntityFramework.core to EntityFrameWork 6.4.4 and after that the program worked fine. you most change you're Framework Version.
you may get this error due to string marshalling mismatch between DLL and your application . for example, one is using ANSI and the other is unicode.
you can try something like this:
[DllImport("yourDLL.dll", CharSet = CharSet.Unicode )]
public static extern String YourFunction(String name);
checkout HERE for a list of other possible reasons.
You could try using the unmangled name while specifying a CallingConvention in the DllImport

Categories

Resources