Hallo
ich habe ein Messprogramm programmiert. Das Programm besteht aus einer C++ und einem C#Teil. Die Kommunikation zwischen den beiden Teilen erfolgt über JSON String.
for (int i = 1; i <= anzahl_messungen; i++)
{
string messwerte = StringReturnAPI01();
Console.WriteLine("\nMessung: " + i);
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(messwerte);
Console.ResetColor();
// teil json string -> objekt
JsonString JsonObjekt = new JsonString(messwerte);
// ausgabe json objekt
foreach (var werte in JsonObjekt.MesswerteArray)
{
js_obj.Add(werte.ToString().Replace(Environment.NewLine, ""));
}
}
Nun bekomme ich aber in der Zeile JsonString JsonObjekt = new JsonString(messwerte); die Meldung: > Fehlermeldung:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Hier noch der DllInport:
class Messung
{
[DllImport(@"Pfad zu C++ dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string StringReturnAPI01();
[STAThread]
public static void Main()
An was könnte den der Fehler liegen?
PS: Ich verwende VS2008 und die JSON Library von http://json.codeplex.com/
Am besten auch gleich den betreffenden C++ Teil posten, zumindest die Methodensignatur und wie du den String erstellst und zurückgibst. So kann man nicht sagen, ob das zusammenpasst.
[return: MarshalAs(UnmanagedType.LPStr)] public static extern string StringReturnAPI01();
Nur mal so aus neugierde: Wie sorgst du dafür, dass der speicher für den LPStr wieder freigegeben wird? Wie allokierst du ihn?
Benutzt du json ausschließlich für interop? Ist eher ungewöhnlich aber ok.
Mein C++ Teil
extern "C" __declspec(dllexport) char* __stdcall StringReturnAPI01()
{
meas();
int laenge;
char *sc_temp = new char [2];
char *rscp_temp = new char [5];
//char *iscp_temp = new char [5];
strcpy(szSampleString,"{\"db\":{\"measurements\":[");
for(i;i<=messreihe-1;i++)
{
mw=true;
strcat(szSampleString,"{\"RSCP\":");
_gcvt(vecwerte[i].rscp , 5, rscp_temp);
strcat(szSampleString,rscp_temp);
rscp_temp[0]='\0';
strcat(szSampleString,",\"SC\":");
_itoa(vecwerte[i].sc, sc_temp,10);
strcat(szSampleString,sc_temp);
sc_temp[0]='\0';
strcat(szSampleString,"},");
}
ULONG ulSize = strlen(szSampleString) + sizeof(char);
char* pszReturn = NULL;
pszReturn = (char*)::GlobalAlloc(GMEM_FIXED, ulSize);
if(mw==true)
szSampleString[strlen(szSampleString)-1]='\0';
// Copy the contents of szSampleString
// to the memory pointed to by pszReturn.
strcpy(pszReturn, szSampleString);
strcat(pszReturn,"]}}");
return pszReturn;
}
Habe mich im bei meinem Programm an diesem Beispiel gehalten: Returning Strings from a C++ API to C#
Du schreibst, dass der Fehler in der Zeile
JsonString JsonObjekt = new JsonString(messwerte);
auftritt. Kannst du denn mit dem Debugger in den String reinschauen, ist er richtig?
Ich habe eine idee, wie dein fehler kommt.
1.) Deine bibliothek muss eine free-funktion zur verfügung stellen!
extern "C" __declspec(dllexport) char* __stdcall StringReturnAPI01()
{
....
}
extern "C" __declspec(dllexport) void __stdcall FreeString(char* string)
{
//todo
}
2.) char* in c++ ist immer Ansi und CharSet.Auto wird standardmäßig unicode. Unicodestrings werden mit 2 nullbytes beendet. Ansi-strings haben aber nur 1 nullbyte. Deshalb wird über das Ende hinaus gelesen und du kiregst ne Access Violation.
3.) Wenn du kein memoryleak haben willst musst du das mashalling eh selber machen.
[DllImport(@"Pfad zu C++ dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr StringReturnAPI01();
[DllImport(@"Pfad zu C++ dll", CallingConvention = CallingConvention.StdCall)]
public static extern void FreeString(IntPtr ptr);
IntPtr lpstr=StringReturnAPI01();
string result=Marshal.PtrToStringAnsi(lpstr);
FreeString( lpstr);
IntPtr lpstr=StringReturnAPI01(); string result=Marshal.PtrToStringAnsi(lpstr); FreeString( lpstr);
Hallo
Bin gerate am Testen,
eine frage die letzten drei Zeilen verstehe ich noch nicht ganz.
An welcher Stelle muss ich die drei Zeilen genau hinzufügen?
Kennst Dein eigenen Code nicht?
Vorher:
for (int i = 1; i <= anzahl_messungen; i++)
{
string messwerte = StringReturnAPI01();
Console.WriteLine("\nMessung: " + i);
nachher
for (int i = 1; i <= anzahl_messungen; i++)
{
IntPtr lpstr=StringReturnAPI01();
string messwerte=Marshal.PtrToStringAnsi(lpstr);
FreeString( lpstr);
Console.WriteLine("\nMessung: " + i);
würde ich mal stark vermuten...
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Das war auch mein erster Gedanke
allerdings kommt dann das StringReturnAPI01() unbekannt ist.
Hatte vielleicht vergessen zu sagen das das mein erstes C# Programm ist
und das ich noch nicht so bewandert in dieser Sprache bin.
Wenn du StringReturnAPI01 wie oben beschrieben per DllImport einbindest, sollte der Fehler verschwinden. Bitte beachte auch [Hinweis] Syntaxfehler selbst lösen (Compilerfehlermeldungen) und [Hinweis] Wie poste ich richtig? Punkt 1.1.1. In [FAQ] Wie finde ich den Einstieg in C#? findest du viele weitere nützliche Hinweise.