0

I need to create a C++ dll that will be called from another program through stdcall.

What is needed : the caller program will pass an array of string to the dll and the dll should change the string values in the array. The caller program will then continue to work with these string values that came from the dll.

I made a simple test project and I am obviously missing something...

Here is my test C++ dll :

#ifndef _DLL_H_
#define _DLL_H_

#include <string>
#include <iostream>

struct strStruct
{
    int len;
    char* string;
};

__declspec (dllexport) int __stdcall TestFunction(strStruct* s)
{
   std::cout << "Just got in dll" << std::endl;

   std::cout << s[0].string << std::endl;
   //////std::cout << s[1].string << std::endl;

   /*
   char str1[] = "foo";
   strcpy(s[0].string, str1);
   s[0].len = 3;

   char str2[] = "foobar";
   strcpy(s[1].string, str2);
   s[1].len = 6;
   */

   //std::cout << s[0].string << std::endl;
   //std::cout << s[1].string << std::endl;

   std::cout << "Getting out of dll" << std::endl;

   return 1;
}

#endif

and here is a simple C# program that I am using to test my test dll :

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Runtime.InteropServices;

 namespace TestStr
 {
     class Program
     {
         [DllImport("TestStrLib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
         public static extern int TestFunction(string[] s);

         static void Main(string[] args)
         {
             string[] test = new string[2] { "a1a1a1a1a1", "b2b2b2b2b2" };

             Console.WriteLine(test[0]);
             Console.WriteLine(test[1]);

             TestFunction(test);

             Console.WriteLine(test[0]);
             Console.WriteLine(test[1]);

             Console.ReadLine();
         }
     }
 }

And here is the output produced :

a1a1a1a1a1
b2b2b2b2b2
Just got in dll
b2b2b2b2b2
Getting out of dll
a1a1a1a1a1
b2b2b2b2b2

I have some questions :

1) Why is it outputting the element in the second position of the array rather than in the first position??

2) If I uncomment the line commented with ////// in the dll file, the program crashes. Why?

3) Obviously I wanted to do more things in the dll (the parts in /* */) than what it does right now, but I am blocked by the first 2 questions...

Thanks for all your help

Deanie
  • 2,316
  • 2
  • 19
  • 35
Bruno
  • 4,685
  • 7
  • 54
  • 105

1 Answers1

1

You cannot marshal a string[] as a native struct

    [DllImport("TestStrLib.dll", CharSet = CharSet.Ansi, 
             CallingConvention = CallingConvention.StdCall)]
             public static extern int TestFunction(string[] s);

      struct strStruct
        {
            int len;
            char* string;
        }

    __declspec (dllexport) int __stdcall TestFunction(strStruct* s);

Please read http://msdn.microsoft.com/en-us/library/fzhhdwae.aspx for marshalling of various types.

In C#

    [DllImport( "TestStrLib.dll" )]
    public static extern int TestFunction([In, Out] string[] stringArray
    , int size);

In C++

__declspec(dllexport) int TestFunction( char* ppStrArray[], int size)
   {
       return 0;
   }
parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
  • Thanks, well I took that pattern from another working program...I do not understand why it should not work with my test, but what would you suggest using instead? – Bruno Nov 16 '11 at 01:43
  • In fact, the real caller will not be a C# program but rather a MQL4 program...see http://forum.mql4.com/35537, this is where I got the current implementation of passing strings to a c++ dll with a struct and it is working according to other people – Bruno Nov 16 '11 at 01:48
  • I am not sure MQL4 is.. but for C# I have given your the right answer – parapura rajkumar Nov 16 '11 at 01:53
  • I made it to work partly with your answer, but since I am passing an array of two strings and not a single string, I used public static extern int TestFunction(strStruct[] p); rather than passing a ref to a struct – Bruno Nov 16 '11 at 01:55
  • I uncommented the /* */ code in the dll and now it is changing correctly the string values (checked with cout after the strcpy, in the dll). However the 2 last Console.WriteLine in the C# program (after the dll call) are outputting the same string values as before the call (a1a1a1a1a1 and b2b2b2b2b2), so it is like if the changes made from the dll were not aknowledged by the caller? – Bruno Nov 16 '11 at 01:57
  • Marshalling is a complicated matter. My MSDN link in the answer talks about various types and how to marshall them – parapura rajkumar Nov 16 '11 at 02:05
  • But can you help me figure out why the changes made to the values in the c++ dll (succesfully) are not available anymore on the caller side after the call to the dll function..? – Bruno Nov 16 '11 at 02:08
  • What you are trying to marshall array of strings or a struct with string in it ? – parapura rajkumar Nov 16 '11 at 02:15