Hallo,
ich habe ein C# HauptProjekt mit C++ DLL UnterProjekt:
Im C# habe ich ein String[] Array Zeilen=6 und Feldbreite=6 Zeichen, die im C++ dll gefüllt wird und an C# zurückgegeben wird. Ich will den gesamten Array mit einem Zeiger übergeben.
Dabei kommt am C++ FunktionAufruf der Fehler > Fehlermeldung:
AccessViolationException und Array bleibt unverändert ?:
[DllImport("myDLL.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void Test(/*[MarshalAs(UnmanagedType.LPArray, SizeConst = 2*6)]*/ string[] s, int count);
private void button4_Click(object sender, EventArgs e)
{
/* C#: ArrayErgebnisAufbau:
string[] strings = new[6]:
strings [0]="00:01",
strings [1]="01:02",
strings [2]="02:03",
strings [3]="03:04",
strings [4]="04:05",
strings [5]="05:06";*/
string[] strings = new[6];
// Füllung/Ausgabe: VorÄnderung
for (int i = 0; i < 6; ++i)
{
strings[i] = String.Format("{0:00}:{1:00}", i, i+1);
ListViewItem item = new ListViewItem();
item.Text = i.ToString();
item.SubItems.Add(strings[i].ToString());
lv.Items.Add(item);
}
// Änderung
Test(strings, strings.Length);
// Ausgabe: NachÄnderung
for (int i = 0; i < strings.Length; ++i)
{
ListViewItem item = new ListViewItem();
item.Text = i.ToString();
item.SubItems.Add(strings[i].ToString());
lv.Items.Add(item);
}
}
C++:
void Test(wchar_t** s, int count)
{
wchar_t** wct = new wchar_t*[6*count];
for(int i=0; i < count; i++)
{
swprintf(wct[i], 6*sizeof(wchar_t), L"%02d:%02d\0", i+1, i+2);
}
}
MFG
Bist Du Dir sicher, dass Du mit StdCall und nicht mit Cdecl arbeitest?
Für die Deklaration fehlt dem Marshal der Arraytyp, der je nach Zugriffsrichtung auch mit In / Out versehen werden sollte, Zb
[In][Out][MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)]
Dem Code nach wäre es übrigens ein pures Schreiben, kein ändern; Du holst ja vorher nicht ein bestehendes Array, sondern übergibst nur eines.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich hab das vor einiger Zeit mal mit einer kleinen Struktur gelöst, als "Geht das überhaupt?"-Projekt. Vielleicht kannst du daraus was lesen, was dir weiterhilft.
static class Program
{
[DllImport("Unmanagedtest.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern int Modify(IntPtr taest);
[DllImport("Unmanagedtest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Multiply(int i, int j);
unsafe static void Main(string[] args)
{
testgedings tast = new testgedings();
tast.iArgh = 5;
tast.iBrgh = 10;
tast.strBla = "Sers";
arr[] ah = new arr[2];
ah[0] = new arr();
ah[1] = new arr();
ah[0].haha = 1;
ah[0].strInner = "Ich bin 1";
ah[1].haha = 2;
ah[1].strInner = "Ich bin 2";
tast.harr = ah;
int size = Marshal.SizeOf(typeof(testgedings));
for (int i = 0; i < tast.harr.Length; i++)
{
size += Marshal.SizeOf(tast.harr[i]);
}
IntPtr unmanagedAddr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(tast, unmanagedAddr, true);
Modify(unmanagedAddr);
Marshal.PtrToStructure(unmanagedAddr, tast);
Marshal.FreeHGlobal(unmanagedAddr);
unmanagedAddr = IntPtr.Zero;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class testgedings
{
public int iArgh;
public int iBrgh;
[MarshalAs(UnmanagedType.BStr, SizeConst = 100)]
public string strBla;
[MarshalAs(UnmanagedType.ByValArray)]
public arr[] harr;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class arr
{
public int haha;
[MarshalAs(UnmanagedType.BStr, SizeConst = 100)]
public string strInner;
}
Die C++ Methode sah bei mir so aus:
int __declspec(dllexport) Modify(teststruct * tst){
std::wstring sr (L"Harlow!");
tst->iArgh = 299;
tst->iBrgh = 999;
tst->strBla = SysAllocString(sr.c_str());
arraydings ha;
ha.hirgl = 9999;
std::wstring si(L"Ich bin innen");
ha.strInner = SysAllocString(si.c_str());
tst->arr = ha;
arraydings aha;
SafeArrayGetElement(tst->sfarr, 0, &aha);
std::wstring si1(L"Ich bin 1 NEU");
aha.strInner = SysAllocString(si1.c_str());
return 1;
};
Ich weiß, das ist furchtbar lesbar mit meinen Bezeichnern, aber ist jetzt halt rein aus unserem POC-Projekt rauskopiert.
String-Arrays aus C# haben wir auf C++ Seite immer als SAFEARRAY behandelt. Darin liegen BSTR-Objekte, mit denen man arbeiten kann.
Hallo, vielen dank
nun mekert er nicht mehr aber er liefert mir nur "0"'s dh nur das 1. Zeichen 1Zeichen zurück, wie kann ich nun alle Strings zurückgeben?:
void Test(wchar_t** s, int count)
{
for(int i=0; i < count; i++)
{
swprintf(s[i], 6*sizeof(wchar_t), L"%02d:%02d\0", i, i+1);
}
}
MFG
Beiträge zusammengefasst