How to Call C++ Dll in C#

Calling C DLL from C#

I found the reason for my failed attempts by utilising a tool called;
Microsoft(R) P/Invoke Interop Assistant as suggested by an answer on this thread.

I utilised this tool to input some of the C function prototypes and get it to generate the required C# prototype on my behalf. The C prototype looked like the following;

long __stdcall TransProjPt(LPSTR psGridFile, long lDirection, double dEasting, double
dNorthing, long lZone, double* pdEastNew, double* pdNorthNew, double* pdEastAcc,
double* pdNorthAcc)

When entering this into the Interop assistant tool, it showed that rather than using longs (as I had done in my original question), these should be declared as an int. It produced the following output that meant my code above now worked as I'd hoped. Yay.

    /// Return Type: int
///psGridFile: LPSTR->CHAR*
///lDirection: int
///dEasting: double
///dNorthing: double
///lZone: int
///pdEastNew: double*
///pdNorthNew: double*
///pdEastAcc: double*
///pdNorthAcc: double*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="TransProjPt", CallingConvention=System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern int TransProjPt([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] System.Text.StringBuilder psGridFile, int lDirection, double dEasting, double dNorthing, int lZone, ref double pdEastNew, ref double pdNorthNew, ref double pdEastAcc, ref double pdNorthAcc) ;

Thanks for everyones help with this.

How to call C++ DLL in C#

The following code in VS 2012 worked fine:

#include <Windows.h>
extern "C"
{
__declspec(dllexport) void HelloWorld ()
{
MessageBox (0, L"Hello World from DLL!\n", L"Hi",MB_ICONINFORMATION);
}
__declspec(dllexport) void ShowMe()
{
MessageBox (0, L"How are u?", L"Hi", MB_ICONINFORMATION);
}
}

NOTE: If I remove the extern "C" I get exception.

Using C dll in C#

You can use PInvoke

Platform Invocation Services (PInvoke)
allows managed code to call unmanaged
functions that are implemented in a
DLL.

Here is a great tutorial by the NAG (Numerical Algorithms Group) group

Call C dll function from C#

You have a number of issues with your PInvoke declarations

  • You need to make sure to free your HGlobal memory, otherwise it will leak.
  • The strings are declared as fixed size char arrays in C, so need to be CharSet.Ansi...
  • ... and they need to be declared [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 127)] so they have fixed nested size.
  • The parameters to the function need to be ref, possibly with [In] attribute also.
  • You need CallingConvention = CallingConvention.Cdecl
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CredPair
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 127)]
public string usr;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 127)]
public string pas;
}

public enum CredType
{
PAIR,
KEY
}

public enum EndpointType
{
DIRECT
}

public struct CredData
{
public CredType credType;
public IntPtr credVal;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct EndpointDirect
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 127)]
public string url;
}

public struct EndpointData
{
public EndpointType endpointType;
public IntPtr endpointVal;
}
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern MyErrCode CheckUser([In] ref CredData cred_Data, [In] ref EndpointData endpoint_data);
IntPtr pnt;
IntPtr urlptr;
try
{
CredPair objPair = new CredPair
{
usr = "abc@xyz.com"
pas = "admin@1234",
};
pnt = Marshal.AllocHGlobal(Marshal.SizeOf(objPair));
Marshal.StructureToPtr(objPair, pnt, false);
CredData objCredData = new CredData
{
credType = CredType.PAIR,
credVal = pnt,
};

endpointValue = new EndpointDirect
{
url = "example.com",
};
urlptr = Marshal.AllocHGlobal(Marshal.SizeOf(epd));
Marshal.StructureToPtr(epd, urlptr, false);
EndpointData objData = new EndpointData
{
endpointType = EndpointType.DIRECT,
endpointValue = urlptr,
};

error_code = CheckUser(ref objCredData, ref objData);
}
finally
{
Marshal.FreeHGlobal(pnt);
Marshal.FreeHGlobal(urlptr);
}

Call c++ DLL from C# application

Thanks for the answers.
I resolved the issue by making one extra class(Wrapper class) that contains the managed code. This wrapper class is called by the c# classes in the same way as I mentioned in the question. This wrapper class than call the c++ class and return the result to the UI.

Calling C dll from C#, return types slightly different

Pointers in an unmanaged language do not map to managed arrays as you have done, this is why it is complaining. char is (almost always, with very limited exceptions) an 8 bit value that maps well to byte in C# as you've noticed, but you need to make them pointers in the managed struct as well:

unsafe struct Envelope
{
public byte* Payload;
public byte* Signature;
}


Related Topics



Leave a reply



Submit