简体   繁体   中英

C# Sending String Array to C++ DLL as SafeArray. Gets only first character

I have C# project and I have to use a C++ dll using DllImport. (I have source codes of c++ dll)

I'm importing a function from c++ dll like this :

[DllImport("Example.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int SendRequest([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] ref string[] fields);

I'm using this function in C# like this :

List<String> fields = new List<String>();

fields.Add("Test1");
fields.Add("Test2");
string[] fieldsArr = fields.ToArray();

int resultOfSendRequest = SendRequest(ref fieldsArr);

Problem is in c++ dll, it casts string to char* in somewhere and it reads the only first character, not entire string.

How can I solve this without touching c++ dll. (If I call this function from VB6 it works without any problem.)

C++ code is like this :

VARIANT vVar;

 __declspec( dllexport ) int _stdcall SendRequest  (SAFEARRAY**);

int _stdcall SendRequest ( SAFEARRAY** arrayFlds,                           
                           short NFlds)  
{   
    // *********** prepare O.i.d, fields name, values
    for (long iElem=0;  iElem < NFlds;  iElem++)
        if (LoadElement (&vVar, iElem, &flds[iElem], &pFlds[iElem],*arrayFlds)==-1)
            return -1;

    //...
}




int LoadElement( VARIANT*   vVar,                
                 long       iElem, 
                 S_FLDS*    flds,
                 char**     pFld, 
                 SAFEARRAY* arrayFlds)
{
    hRes = SafeArrayGetElement(arrayFlds, &iElem, pFld);   

    strcpy(flds->FieldName, *pFld);
    flds->bValLen = 0;

    char *Name = flds->FieldName;

    //....
}

The fieldName and char *Name at the end of the core only consists of first character of string. Not the full string.

In C Langues a string is a byte[] with each string terminated with a '\\0'. An array of strings the last item has two '\\0' at the end. So try following :

        [DllImport("Example.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int SendRequest(IntPtr fields);
        static void Main(string[] args)
        {
            List<String> fields = new List<String>();

            fields.Add("Test1");
            fields.Add("Test2");

            string fieldsArr = string.Join("\0", fields);
            IntPtr fieldsPtr = Marshal.StringToBSTR(fieldsArr);
            int results = SendRequest(fieldsPtr);

        }

If it is an array of pointers then use this

       public struct Pointers
        {
            public IntPtr[] pointers;
        }

        [DllImport("Example.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int SendRequest(IntPtr fields);
        static void Main(string[] args)
        {
            List<String> fields = new List<String>();

            fields.Add("Test1");
            fields.Add("Test2");

            List<IntPtr> pointers = new List<IntPtr>();

            foreach (string field in fields)
            {
                IntPtr intPtr = Marshal.StringToBSTR(field);
                pointers.Add(intPtr);
            }

            Pointers sPointers = new Pointers();
            sPointers.pointers = pointers.ToArray();

            IntPtr fieldsPtr = IntPtr.Zero;
            Marshal.StructureToPtr(sPointers, fieldsPtr, true);
            int results = SendRequest(fieldsPtr);
            Marshal.FreeHGlobal(fieldsPtr);

        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM