2009-04-29 12 views
2

je la suite de la signature du code C dans un dll:marshalling code C dll en C#

extern __declspec(dllexport) unsigned char * 
funct_name (int *w, int *h, char **enc, int len, unsigned char *text, int *lp, int *mp, int *ep) 

La fonction C peut modifier w, h, enc, lp, point de fusion, et ep (bien que ce dernier trois peut être nul et il ne fera rien.

J'utilise ce qui suit dans C#

[DllImport("iec16022ecc200.dll", EntryPoint = "iec16022ecc200", ExactSpelling = false, CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.Cdecl)] 
      static extern IntPtr CallEncode(
      [In,Out,MarshalAs(UnmanagedType.LPArray)] Int32[] width, 
      [In,Out,MarshalAs(UnmanagedType.LPArray)] Int32[] height, 
      [In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding, 
      int barcodeLen, 
      [MarshalAs(UnmanagedType.LPStr)] StringBuilder barcode, 
      IntPtr lenp, 
      IntPtr maxp, 
      IntPtr eccp 
      ); 


public void Foo (string textToEncode,out int width, out int height) { 
      StringBuilder text = new StringBuilder(textToEncode); 
      StringBuilder encoding = new StringBuilder(new string('a', text.Length)); 

      Int32[] w = new Int32[1]; 
      Int32[] h = new Int32[1]; 


      string encodedStr = Marshal.PtrToStringAnsi(CallEncode(w, h, ref encoding, text.Length, text, (IntPtr)0, (IntPtr)0, (IntPtr)0)); 
      width = w[0]; 
      height = h[0]; 
} 

Je reçois un SystemAccessViolation et je ne suis pas tout à fait sûr que mon problème.

Répondre

3

Ne passez pas une référence StringBuilder à une méthode non managée prenant un caractère *. Le contenu StringBuilder est unicode (wchar). À la place, remplacez le paramètre StringBuilder par le paramètre et IntPtr et allouez un tampon de taille approprié à l'aide de Marshal.AllocHGlobal.

Aussi je ne pense pas que passer un StringBuilder au code non managé en utilisant "ref" est supporté par le marshaller .Net.

1

Vous avez mentionné que le paramètre 'char ** enc' peut être modifié par l'appelé, cela pourrait provoquer l'erreur 'SystemAccessViolation'. Un StringBuilder peut être déréférencé et modifié par l'appelé, à condition qu'il ne dépasse pas la capacité de StringBuilders.

0

J'essayais de passer une chaîne de C++ à C# dans Unity. Et tout ce que j'ai eu, c'était du charabia. Finalement après avoir vu votre commentaire @popcatalin j'ai découvert la solution en utilisant AllocHGlobal de C# pour allouer de la mémoire pour la chaîne.

Ceci est mon C++ fonction:

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API TestString(char* str, int len) 
{ 
    strcpy_s(str, len, "C++ String!!! UniversalCpp"); 
    return; 
} 

Ceci est en haut du script C# dans l'unité:

#if WRCCPP 
    [DllImport("UniversalWRCCpp", CallingConvention = CallingConvention.Cdecl)] 
#else 
    [DllImport("UniversalCpp", CallingConvention=CallingConvention.Cdecl)] 
#endif 
    private static extern void TestString(IntPtr str, int len); 

private IntPtr myPtr = IntPtr.Zero; // Pointer to allocated memory 

Et voici mon script C# dans l'unité appelant cette fonction:

int sizeInBytes = 100; 
myPtr = Marshal.AllocHGlobal(new IntPtr(sizeInBytes)); 
TestString(myPtr, sizeInBytes); 
Debug.Log("ANSI " + Marshal.PtrToStringAnsi(myPtr)); // This prints the correct format