I'm trying to call some functions and struct from a compiled C++ dll in a C# program.
Compiled C++ function and Structs :
struct RET_DATA
{
int type;
unsigned int num;
// time_t timestamp;
union {
char Char[1];
bool Bool[1];
unsigned char Byte[1];
short Short[1];
int Int[1];
float Float[1];
double Double[1];
__int64 Int64[1];
};
};
struct DATA_INFO
{
int type;
unsigned char* addr;
// time_t timestamp;
union {
char& Char;
bool& Bool;
unsigned char& Byte;
short& Short;
int& Int;
float& Float;
double& Double;
__int64& Int64;
};
double _var;
DATA_INFO() : Char(*(char*)&_var),Bool(*(bool*)&_var),Byte(*(unsigned char*)&_var),Short(*(short*)&_var),Int(*(int*)&_var),Float(*(float*)&_var),Double(*(double*)&_var),Int64(*(__int64*)&_var){}
};
extern "C" {
__declspec(dllexport) void* GETVARINFO(char* var, DATA_INFO *&pData);
__declspec(dllexport) int RetrieveData(char *dir, char *var, RET_DATA *&pData, char* type);
};
int RetrieveData(char *dir, char *var, RET_DATA *&pData, char* type)
{
return g_EDT_Historian.pfnRetrieveData(dir, var, pData, type);
}
void* GETVARINFO(char* VAR, DATA_INFO *&pData)
{
bool cm;
char *s, *e, *d, idx=0, var[32];
int dl[7],dim,c;
memset(dl, 0x00, sizeof(dl)); d = 0;
STRING word;
strcpy(var, VAR); _strupr(var);
s = var; s = strchr(s, '('); if (s) { *s++ = 0; d = s; }
strcpy((char*)word, var);
tagsvrDATA svrData;
if (g_pEDTDatabase->search(word, svrData))
{
pData = (DATA_INFO*)malloc(sizeof(DATA_INFO));
pData->type = svrData.type;
dim = 0;
if (d)
{ s = d; while (*s) { s += strspn(s, " \t"); e = s; e += strcspn(e, ",)"); if (*e) { cm = *e == ','; *e++ = 0; dl[idx++] = atoi(s); if (!cm) break; s = e; } }
if (svrData.nDim > 0) { for (int i = svrData.nDim; i >= 2; i--) { c = (dl[i - 1] - 1); for (int j = 1; j <= (i - 1); j++) c = c * svrData.dims[j - 1]; dim += c; } dim += dl[0] - 1; } }
switch (svrData.type)
{
case TYPE_CHAR: pData->addr = (unsigned char*)((char*)svrData.addr + dim); break;
case TYPE_BOOL: pData->addr = (unsigned char*)((char*)svrData.addr + dim); break;
case TYPE_BYTE: pData->addr = (unsigned char*)((char*)svrData.addr + dim); break;
case TYPE_SHORT: pData->addr = (unsigned char*)((short*)svrData.addr + dim); break;
case TYPE_INT: pData->addr = (unsigned char*)((int*)svrData.addr + dim); break;
case TYPE_FLOAT: pData->addr = (unsigned char*)((float*)svrData.addr + dim); break;
case TYPE_DOUBLE:pData->addr = (unsigned char*)((double*)svrData.addr + dim); break;
case TYPE_INT64: pData->addr = (unsigned char*)((__int64*)svrData.addr + dim); break;
default: pData->addr = (unsigned char*)((char*)svrData.addr + dim); break;
}
*(void**)((int)&pData->_var - 4) = pData->addr;
return svrData.addr;
}
else
{
pData = NULL;
return NULL;
}
}
C# implementation :
[StructLayout(LayoutKind.Sequential)]
public struct DATA_INFO
{
public int type;
public byte[] addr;
public sbyte Char;//IntPtr??
public bool Bool;
public byte Byte;
public short Short;
public int Int;
public float Float;
public double Double;
public long Int64;
public double _var;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct RET_DATA
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public uint addr;
[FieldOffset(8)]
public sbyte Char;
[FieldOffset(9)]
public bool Bool;
[FieldOffset(10)]
public byte Byte;
[FieldOffset(11)]
public short Short;
[FieldOffset(13)]
public int Int;
[FieldOffset(17)]
public float Float;
[FieldOffset(21)]
public double Double;
[FieldOffset(29)]
public long Int64;
}
[DllImport("EDT_Database.dll", CharSet=CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GETVARINFO(char[] var, ref DATA_INFO pData);
[DllImport("EDT_Database.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern int RetrieveData(StringBuilder dir, StringBuilder var, ref RET_DATA pData, StringBuilder type);
public string Read_SM(string strName)
{
IntPtr nResult = new IntPtr();
string strResult = "";
char[] uchars = strName.ToCharArray();
DATA_INFO pDat = new DATA_INFO();
IntPtr nDataInfo = new IntPtr();
StringBuilder sb = new StringBuilder();
sb.Append(strName);
//float *ptr = (float*)GETVARINFO(testChar, pDat);
nResult = GETVARINFO(uchars, ref pDat);
// nResult = GETVARINFO(uchars, ref nDataInfo);
// Marshal.PtrToStructure(nDataInfo, pDat);
switch (pDat.type)
{
case Constants.TYPE_CHAR: strResult = pDat.Char.ToString(); break;
case Constants.TYPE_BOOL: strResult = pDat.Bool.ToString(); break;
case Constants.TYPE_BYTE: strResult = pDat.Byte.ToString(); break;
case Constants.TYPE_SHORT: strResult = pDat.Short.ToString(); break;
case Constants.TYPE_INT: strResult = pDat.Int.ToString(); break;
case Constants.TYPE_FLOAT: strResult = pDat.Float.ToString(); break;
case Constants.TYPE_DOUBLE: strResult = pDat.Double.ToString(); break;
case Constants.TYPE_INT64: strResult = pDat.Int64.ToString(); break;
default: strResult = pDat.Char.ToString(); break;
}
return strResult;
}
}
In C++ test code, it works well. But in C# test code, GETVARINFO() function returns always 0.
I think C# structure definition has problem and calling GETVARINFO() method is wrong. How can I get the result from C++ dll.
Any idea?