I am trying to call some functions from a C++ DLL file in my C# program. But I got stuck when it comes to pointers. Could somebody point me to the right direction?
Here's the C++ header file with the target functions:
#pragma once
#ifdef STCL_DEVICES_DLL
#define STCL_DEVICES_EXPORT extern "C" _declspec(dllexport)
#else
#define STCL_DEVICES_EXPORT extern "C" _declspec(dllimport)
#endif
enum SD_ERR
{
SD_ERR_OK = 0,
SD_ERR_FAIL,
SD_ERR_DLL_NOT_OPEN,
SD_ERR_INVALID_DEVICE, //device with such index doesn't exist
SD_ERR_FRAME_NOT_SENT,
};
#pragma pack (1)
struct LaserPoint
{
WORD x;
WORD y;
byte colors[6];
};
struct DeviceInfo
{
DWORD maxScanrate;
DWORD minScanrate;
DWORD maxNumOfPoints;
char type[32];
};
//////////////////////////////////////////////////////////////////////////
///Must be called when starting to use
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int OpenDll();
//////////////////////////////////////////////////////////////////////////
///Search for .NET devices (Moncha.NET now)
///Must be called after OpenDll, but before CreateDeviceList!
///In pNumOfFoundDevs can return number of found devices (optional)
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int SearchForNETDevices(DWORD* pNumOfFoundDevs);
//////////////////////////////////////////////////////////////////////////
///All devices will be closed and all resources deleted
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT void CloseDll();
//////////////////////////////////////////////////////////////////////////
///Creates new list of devices - previous devices will be closed
///pDeviceCount returns device count
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int CreateDeviceList(DWORD* pDeviceCount);
//////////////////////////////////////////////////////////////////////////
///Returns unique device name
///deviceIndex is zero based device index
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int GetDeviceIdentifier(DWORD deviceIndex, WCHAR** ppDeviceName);
//////////////////////////////////////////////////////////////////////////
///Send frame to device, frame is in following format:
///WORD x
///WORD y
///byte colors[6]
///so it's 10B point (=> dataSize must be numOfPoints * 10)
///scanrate is in Points Per Second (pps)
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int SendFrame(DWORD deviceIndex, byte* pData, DWORD numOfPoints, DWORD scanrate);
//////////////////////////////////////////////////////////////////////////
///Returns true in pCanSend if device is ready to send next frame
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int CanSendNextFrame(DWORD deviceIndex, bool* pCanSend);
//////////////////////////////////////////////////////////////////////////
///Send DMX if device supports it - pDMX must be (!!!) 512B long
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int SendDMX(DWORD deviceIndex, byte* pDMX);
//////////////////////////////////////////////////////////////////////////
///Send blank point to position x, y
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int SendBlank(DWORD deviceIndex, WORD x, WORD y);
//////////////////////////////////////////////////////////////////////////
///Get device info
//////////////////////////////////////////////////////////////////////////
STCL_DEVICES_EXPORT int GetDeviceInfo(DWORD deviceIndex, DeviceInfo* pDeviceInfo);
This is my C# test class so far:
#region Usings
using System;
using System.Runtime.InteropServices;
#endregion
namespace MonchaTestSDK {
class Program {
[DllImport("..\\..\\dll\\StclDevices.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int OpenDll();
[DllImport("..\\..\\dll\\StclDevices.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SearchForNETDevices(DWORD* pNumOfFoundDevs);
[DllImport("..\\..\\dll\\StclDevices.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void CloseDll();
public static void Main(string[] args) {
OpenDll();
CloseDll();
}
}
}
OpenDll()
and CloseDll()
works fine. But the first problem occurs on the DWORD*
parameter of SearchForNETDevices
function:
The type or namespace name 'DWORD' could not be found (are you missing a using directive or an assembly reference?
Pointers and fixed size buffers may only be used in an unsafe context.
Cannot take the address of, get the size of, or declare a pointer to a managed type ('DWORD').
Moreover, how do I have to handle the other function parameters, such as WCHAR** and the structs DeviceInfo
and LaserPoint
?
DWORD*
isref uint
. – Disorderedout uint
. You'll have trouble with GetDeviceIdentifier(), the string it returns must not be released by the pinvoke marshaller. You needout IntPtr
and recover the string with Marshal.PtrToStringUni(). – Nagalandout uint
forDWORD*
works fine. I updated my the original post. – DemottMarschal.PtrToStringUni()
solution works great. I will update my post with the complete solution once it's working. – Demott