calling c++ dll functions and struct from c#

763 views Asked by At

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?

0

There are 0 answers