das out ist nicht nötig, da .NET den Zeiger auf das erste Array-Element übergibt und die Daten direkt in dieses geschrieben werden (genau das, was vorher manuell mit unsafe erreicht werden sollte).
Wenn ich mir die Funktion so ansehe, gehe ich einmal davon aus, dass Parameter "Buff" ein Buffer ist in den etwas geschrieben wird, welcher die Länge "BuffLen" hat.
Das ganze funktioniert auch ganz ohne unsafe code:
[DllImport("CANAPI2.dll", EntryPoint = "CAN_GetHwParam")]
public static extern uint GetHwParam(byte hHw, ushort Param, byte[] Buff, ushort BuffLen);
...
const int buffLength = 1024;
byte[] buffer = new buffer[buffLength];
uint result = GetHwParam(0, 0, buffer, buffLength);
...
Ob die Funktion bytes, shorts, ect erwartet musst du der API entnehmen.
zum ersten ist ein long in .NET 64 Bit groß (int wäre 32 falls du das eigentlich wolltest).
Du könntest das so realisieren:
public static int GetInt32(BitArray array)
{
int[] value = new int[1];
array.CopyTo(value, 0);
return value[0];
}
public static BitArray GetBitArray(int value)
{
return new BitArray(BitConverter.GetBytes(value));
}
vermutlich ist diese dll für 32bit compiliert. Die .NET Anwendung passt sich allerdings dem OS an und läuft nun als 64bit, was so nicht funktionieren kann, da Pointer unter 32bit und 64bit unterschiedlich groß sind.
Entweder das .NET Programm fest für 32 bit compilieren oder eine 64bit Version der dll verwenden.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Assembly a = Assembly.GetEntryAssembly(); // Hier ist die gelandene Assembly
// Der exakte Name incl. Namespace
Type t = a.GetType("ConsoleApplication1.Hallodll");
// Instanz erzeugen, da Hallo() nicht statisch ist
object o = Activator.CreateInstance(t);
// Auf der Instanz die Methode aufrufen
t.InvokeMember("Hallo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, o, null);
// Ohne Instanz die statische Methode aufrufen
t.InvokeMember("HalloStatic", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);
}
}
class Hallodll
{
public void Hallo()
{
Console.WriteLine("Hallo");
}
public static void HalloStatic()
{
Console.WriteLine("Hallo");
}
}
}
ich habe eben die Version 1.3 herunter geladen und mal getestet.
Du musst einen Verweis auf die Datei "DevIL.NET2.dll" in dein Project einfügen.
Danach kannst du mit der Klasse "DevIL.DevIL" Bilddateien laden.
Nur würde ich mal behaupten, dass es keinen Unterschied macht, ob eine Methode statisch ist oder nicht, sobald ich mindestens eine Instanz erstellt habe.
static T[] Factorize<T>(T value) where T : struct
{
Type type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("value");
List<T> result = new List<T>(64);
ulong bitField = Convert.ToUInt64(value);
ulong bit = 1;
for (int i = 0; i < 64; i++, bit <≤ 1)
{
ulong u = (bitField & bit);
if (u != 0)
{
result.Add((T)Enum.ToObject(type, u));
}
}
return result.ToArray();
}
die C# Definitionen sollten so aussehen unter der Annahme, dass UCHAR ein 8-bit unsigned integer ist. Wenn nicht diesen einfach anpassen:
[Serializable, StructLayout(LayoutKind.Sequential)]
public sealed class eeprom_prodid
{
public UInt16 sn;
public UInt16 prodcode;
public SByte hwrel;
public SByte hwver;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public SByte[] signature;
}
public class Native
{
[DllImport("name_meiner_dll", EntryPoint = "funktionsname_in_der_dll")]
public static extern int ExternalEepromRead(eeprom_prodid prodid, UInt32 addr, SByte count);
}
Das Array beginnt nicht mit dem Index 0. Daher kannst du es nicht nach string[] casten.
Um auf das Array zugreifen zu können caste es in die Klasse "Array" und benutze die dort angebotenen Methoden.
Hier ein Beispiel:
// Hier kommt dein Objekt rein
Array array = Array.CreateInstance(typeof(string), new int[] { 10 }, new int[] { 1 });
for (int i = array.GetLowerBound(0), j = array.GetUpperBound(0); i < j; i++)
{
// Mache etwas mit dem Wert
array.GetValue(i);
}
Wenn du wieder eine Methode erstellen willst, ist es am einfachsten die Methode zu implementieren und denn vie Reflector sich die OpCodes anzeigen zu lassen.
Also ist eine Übergabe byValue nur Scheinbar byValue, weil in Wirklichkeit nur die Referenz des Objekts übergeben wird
Eine Übergabe "By Value" heisst, dass der Inhalt der Variablen kopiert wird (Value => Inhalt). "By Reference" heisst, dass ein Zeiger auf die lokale Variable übergeben wird.
Beispiel:
string str = "Hallo"; // str ist 4 bytes groß (auf 32 bit System) und könnte nun zB 0x85AB5038 sein
Test(str);
int i = 5; // i ist 4 Bytes groß und beinhaltet 0x00000005
Test(i);
//
void Test(string s)
{
// s ist 0x85AB5038
}
void Test(int t)
{
// i ist 0x00000005
}
Sowohl bei Verweistypen als auch bei Werttypen wird der Wert der Variablen kopiert (was bei Werttypen logischerweise der Wert selber ist bei Referenztypen die Referenz).
Was man nicht vergessen darf ist, dass C# bei der Benutzung von "ref" oder "out" für uns automatisch die aus C/C++ bekannte Dereferenzierung macht und vor dem Programmierer versteckt (was man schön sieht, wenn man sich Code zB im Reflector in IL anschaut).
Das Problem ist, dass die aufrufende AppDomain die Assembly ebenfalls finden muss. Da sie aber nur im eigenen Ordner sucht, kann sie diese nicht finden.
ich möchte eine C-Struct in C# verwenden. Bisher hat dies auch immer ohne Probleme geklappt jedoch ist es diesmal die erste Struct, die ein embedded Array beinhaltet.
Die Struct sieht folgendermaßen aus (Beispiel):
typedef struct
{
int ID;
char* Name;
double Data[6];
int Reserved;
} TestStruct;
Die Struct wird mit folgender Beispielfunktion gefüllt:
void* DLL_EXPORT GetData(TestStruct* ptr)
{
int i;
if (ptr)
{
ptr->ID = 1;
ptr->Name = "Dies ist ein Teststring";
for(i=0;i<6;i++)
ptr->Data[i]=(double)(i+100);
ptr->Reserved = -1;
}
return ptr;
}
In C# habe ich diese so eingebunden:
[DllImport("library.dll")]
public static extern IntPtr GetData(out TestStruct t);
Wenn ich nun die Struct wie folgt in C# deklariere, wird der String automatisch gemarshalt, so wie man es erwartet. Die beiden Ints sind ebenfalls gesetzt. Jedoch wird im embedded Array nur der erste Eintrag gesetzt, die anderen sind 0.
unsafe struct TestStruct
{
int ID;
string Name;
fixed double Data[6];
int Reserved;
}
Deklariere ich die Struct um, so dass der String nicht gemarshalt werden muss, wird das embedded Array normal gefüllt:
unsafe struct TestStruct
{
int ID;
char* Name;
fixed double Data[6];
int Reserved;
}
Wie es scheint, wird das embedded Array nicht korrekt kopiert, sobald der Marshaler eine Kopie der Struct erstellen muss (was er für den String in der ersten Implementierungsvariante muss).
Kennt jemand eine Möglichkeit den char-Pointer elegant als String zu marshalen und gleichzeitig ein embedded Array zu nehmen?
sagt nicht aus, dass T mit dem Attribut markiert ist sondern, dass es davon ableitet.
Die Bedingung die du ausdrücken möchtest ist so denke ich nicht möglich, aber vielleicht kennt sich da noch jemand besser aus.
du könntest die Datei zeilenweise mit Hilfe des StreamReaders einlesen und die jeweils eingelesene Zeile direkt verarbeiten. So bleibt der Speicherverbraucht niedrig.