2009-04-29 10 views
2

Ich habe folgende C-Code-Signatur in einer DLL:Rangierung C dll-Code in 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) 

die C-Funktion w, h ändern, ENC, lp, mp und EP (obwohl die letzteren drei kann null sein, und es wird nichts tun.

ich folgend in 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]; 
} 

ich bin mit einem SystemAccessViolation bin immer und ich bin nicht ganz sicher, wenn mein Problem ist.

Antwort

3

Übergeben Sie keinen StringBuilder-Verweis an eine nicht verwaltete Methode, die char * akzeptiert. StringBuilder-Inhalt ist Unicode (wchar).

Stattdessen ersetzen den Stringparameter mit und IntPtr Parameter und zuteilen Marshal.AllocHGlobal einen entsprechenden Größenpuffer.

Außerdem glaube ich, keinen String auf nicht verwalteten Code „ref“ von .NET Einweiser unterstützt wird vorbei.

1

Sie haben erwähnt, dass die ‚char ** enc‘ Parameter durch den Angerufenen modifiziert werden kann, dieser Fehler die ‚SystemAccessViolation‘ verursachen könnte. Ein StringBuilder kann vom Aufrufer dereferenziert und modifiziert werden, sofern er nicht die Kapazität von StringBuilders überschreitet.

0

Ich habe versucht, eine Zeichenfolge von C++ zu C# in der Einheit zu übergeben. Und alles, was ich bekam, war Kauderwelsch. Schließlich, nachdem ich deinen Kommentar @popcatalin gesehen habe, habe ich die Lösung entdeckt, die AllocHGlobal von C# verwendet, um Speicher für die Zeichenfolge zuzuweisen.

Dies ist meine C++ Funktion:

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

Dies ist an der Spitze des C# Skript in Unity:

#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 

Und das ist mein C# Skript in Unity Aufruf dieser Funktion:

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