Index

Calling native C++ DLL by a C# applications

Interoperable types are:

  • int (and all integral types, like short, long, ushort, uint and ulong)
  • float (and all other floating point types, like double)
  • byte (it’s an unsigned integral type actually)
  • * (pointer, only in unsafe mode)
  • void (not really a type though)

There might be some others which look like they are interoperable, but in fact they are not:
  • char (C-style char is one byte, .Net char is two bytes (unicode))
  • bool (C-style bool is actually an integral type)
  • enum (C-style enum is an integral type, .Net style can have many types)

So, for any type that is not interoperable, you’ll need to manually convert them in order to use them. Also, for sake of usefulness, you should convert a regular pointer (*) to the IntPtr type. That way the code that uses your wrapper-class does not have to use the keyword “unsafe”.

C# Code

namespace DllAccess
{
public partial class CConsole : Form
{
private string m_strDisplay;

public CConsole()
{
InitializeComponent();
}

/// ///////////////////////////////////////////////////////////////////

[DllImport("DllInterface.dll")]
unsafe public static extern int TestVoid();

private void btnTestVoid_Click(object sender, EventArgs e)
{
int i = TestVoid();
MessageBox.Show(i.ToString());
}

/// ///////////////////////////////////////////////////////////////////

[DllImport("DllInterface.dll")]
unsafe public static extern void TestCharPtr(char* pStr);

private char m_strMsg;
unsafe private void btnCharPtr_Click(object sender, EventArgs e)
{
fixed (char* out_ptr = &m_strMsg)
TestCharPtr(out_ptr);
MessageBox.Show(m_strMsg.ToString());
}
/// ///////////////////////////////////////////////////////////////////

[DllImport("DllInterface.dll", CharSet = CharSet.Auto)]
unsafe public static extern void GetString(
[MarshalAs(UnmanagedType.LPStr)] StringBuilder stream, int nSize);

unsafe private void btnCharDoublePtr_Click(object sender, EventArgs e)
{
StringBuilder stream = new StringBuilder(26);
GetString(stream, 26);

MessageBox.Show(stream.ToString());
}

/// /// ///////////////////////////////////////////////////////////////////
[DllImport("DllInterface.dll")]
unsafe public static extern void TestFloatPtr(float* pStr, int nSize);

private float[] m_pData = new float[8];
unsafe private void btnFloatPtr_Click(object sender, EventArgs e)
{
fixed (float* out_ptr = &m_pData[0])
TestFloatPtr(out_ptr, 8);

for (int i = 0; i < 8; i++)
{
m_strDisplay += m_pData[i].ToString() + "; ";
}
MessageBox.Show(m_strDisplay);
m_strDisplay = String.Empty;
}

/// /// Return Int Ptr and convert to Char
/// Marshalling: Using native DLLs in .NET
[DllImport("DllInterface.dl")]
unsafe private static extern IntPtr GetMacAddress(out int length);

private void btnGetMacAddr_Click(object sender, EventArgs e)
{
try
{
int length;
IntPtr array = GetMacAddress(out length);
byte[] mArray = new byte[length];
Marshal.Copy(array, mArray, 0, length);
string str = String.Empty;
for (int i = 0; i < length; i++)
{
str += Convert.ToChar(mArray[i]);
}
MessageBox.Show(str);
//Marshal.FreeHGlobal(array); //Free the unmanaged array
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

/// /// Send a string to C++ DLL
[DllImport("DllInterface.dll", EntryPoint = "CheckCode")]
unsafe public static extern int CheckCode(void* strCode, void* strInfo);

unsafe public static void checkCode(string strCode)
{
IntPtr pCode = IntPtr.Zero;
IntPtr pInfo = IntPtr.Zero;

try
{
//convert from string to pointers
pCode = Marshal.StringToHGlobalAnsi(strCode);

//alloc mem for system pointer
pInfo = Marshal.AllocHGlobal(IntPtr.Size);

//call external method
int nResult = CheckCode(pCode.ToPointer(), pInfo.ToPointer());

string msg = nResult.ToString();
//check for errors
if (nResult != 0)
{
//unreference system pointer
Marshal.ReadIntPtr(pInfo);
string msg1 = Marshal.PtrToStringAnsi(pInfo);
//foreach (
msg += "; Code was incorrect:" + msg1;
}
MessageBox.Show(msg);
}
finally
{
//clean up memory
if (pInfo != IntPtr.Zero)
Marshal.FreeHGlobal(pInfo);
if (pCode != IntPtr.Zero)
Marshal.FreeHGlobal(pCode);
}
}

private void btnVerifyCode_Click(object sender, EventArgs e)
{
if (txtCode.Text.Length <= 0)
{
MessageBox.Show("Please enter the filename");
return;
}
checkCode(txtCode.Text);
}

/// /// // ** Documentation for Win32 GetShortPathName() API Function
[DllImport("DllInterface.dll", CharSet = CharSet.Auto)]
static extern Int32 String2CharPtr(string path,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder shortPath,
Int32 shortPathLength);

private void btnBrowse_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
dlg.Title = "Select a text file";
if (dlg.ShowDialog() == DialogResult.OK) {
StringBuilder shortPath = new StringBuilder();
Int32 shortPathLength = 32;
Int32 nResult = String2CharPtr(dlg.FileName, shortPath, shortPathLength);
MessageBox.Show(shortPath.ToString());
}
}
}
}

C++ DLL Code

#ifdef __cplusplus
extern "C"
{
#endif

DLL_EXPORT_API int TestVoid(void);
DLL_EXPORT_API void TestCharPtr(char*);
DLL_EXPORT_API char* GetMacAddress(int& nLen);
DLL_EXPORT_API void TestFloatPtr(float*, int);
DLL_EXPORT_API int CheckCode(void* strCode, void* strInfo);
DLL_EXPORT_API void GetString(LPTSTR, int);
DLL_EXPORT_API DWORD String2CharPtr(
LPCTSTR lpszLongPath, // file for which to get short path
LPTSTR lpszShortPath, // short path name (output)
DWORD cchBuffer // size of output buffer
);

#ifdef __cplusplus
}

// DllInterface.cpp : Defines the exported functions for the DLL application.

#include "stdafx.h"
#include "DllInterface.h"

DLL_EXPORT_API int TestVoid(void)
{
return 10;
}

DLL_EXPORT_API void TestCharPtr(char* pStr)
{
pStr[0] = 'A';
}
DLL_EXPORT_API char* GetMacAddress(int& nLen)
{
nLen = 12;
char* str = new char[12];
strcpy(str, "MAC ADDRESS");
return str;
}
DLL_EXPORT_API void SetString(char* buffer, int* bufferSize)
{
//strcpy(buffer
}
DLL_EXPORT_API void TestFloatPtr(float* pData, int nSize)
{
for(int i = 0; i < nSize; i++) {
pData[i] = 22/7.0f * i;
}
}
DLL_EXPORT_API int CheckCode(void* strCode, void* strInfo)
{
if (0 == strcmp((char*)strCode, "ABC"))
return 0;
else {
strcpy((char*)strInfo, (char*)strCode);
return 1;
}
}
DLL_EXPORT_API DWORD String2CharPtr(LPCTSTR lpszLongPath, LPTSTR lpszShortPath,
DWORD chBuffer)
{ strcpy(lpszShortPath, "_BLANK_");
return GetShortPathName(lpszLongPath, lpszShortPath, chBuffer);
}
DLL_EXPORT_API void GetString(LPTSTR stream, int nSize)
{
for(int i = 0; i < nSize; i++) {
stream[i] = 'A' + i;
}
}
Index