Laden...

uint[] to void* ?

Erstellt von Kalleberlin vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.587 Views
K
Kalleberlin Themenstarter:in
165 Beiträge seit 2007
vor 15 Jahren
uint[] to void* ?

Hallo Ihr 🙂,

nach langer Zeit hab ich mal wieder eine Frage an euch 😛.

Ich bin gerade dabei ein c++ libary nach c# zu portieren.
Diese lib ist "nur" ein Addon für ein grösseres Project, welches auch in c++ geschrieben is. Wie auch immer, dafür gibts einen Wrapper (für das grosse Project (aka Mogre)).

Lange rede kurzer Sinn:

Die Methode die Ich aufrufen möchte, hat folgende Parameter:


void writeData(uint offset, uint length, void* pSource,
					bool discardWholeBuffer) ;

In meinem fall ist pSource ein uint[] Array.

Ich hab jetzt schon einige Zeit gegoogled, hier im Forum gesucht, aber irgendwie komme ich partou nicht drauf wie ich mein Array nach void* casten kann. Ich hab Marshal.bla versucht.

Ich hab auch Varianten alla:


void Foo([MarshalAs(UnmanagedType.LPArray)] uint[] Arr);

versucht. Leider vergeblich 😦.

Ich wär euch sehr verbunden wenn Ihr mir hier weiterhelfen könntet 🙂

Gruß Kalleberlin

If u want to finish first, u have to finish first.
K
36 Beiträge seit 2008
vor 15 Jahren

So zB:


void* voiPtr;
uint[] intArray = new uint[5] {1, 2, 3, 4, 5};

fixed (uint* intPtr = intArray)
{
     voiPtr = intPtr;
}

Zum zurückkonvertieren musst du dann natürlich die Länge des Arrays wissen!

EDIT: Natürlich kannst du jetzt nicht einfach hergehen und den void-Zeiger übergeben, weil der Garbage Collector das Array nach verlassen des fixed-Blocks wieder im Speicher hin und her schieben wird.

Wenn du das Objekt dauerhaft Pinnen willst, schau dir die GCHandle Klasse an!

K
Kalleberlin Themenstarter:in
165 Beiträge seit 2007
vor 15 Jahren

Hallo kyoko12,

vielen Dank für diesen Hinweis 🙂.

Gruß Kalleberlin.

If u want to finish first, u have to finish first.
M
194 Beiträge seit 2008
vor 15 Jahren

Wäre dann eine dauerhafte Nutzung des Pointers (pinnen) nicht auch unter Verwendung von stackalloc gewährleistet? Also in folgender Form:


void* voiPtr;
uint* intPtr =  stackalloc uint[5];
intPtr[0] = 1;
intPtr[1] = 2;
intPtr[2] = 3;
intPtr[3] = 4;
intPtr[4] = 5;

voiPtr = intPtr;

"Indem Sie über dieses ernste Thema lachen disqualifizieren Sie sich selbst."
mrleeh.de

K
36 Beiträge seit 2008
vor 15 Jahren

@MrLeeh:

Ja, wäre es natürlich. Aber Kalleberlin sagte ja expizit, er habe ein uint-Array. stackalloc erzeugt kein Array in dem Sinn, sondern nur eine Reihe von Elementen auf dem Stack.

1.361 Beiträge seit 2007
vor 15 Jahren

Der Vorteil von dem pinning mittels GCHandle sollte zudem sein, dass man kein unsafe verwenden muss.
(der so ermittelbare IntPtr sollte automatisch in void* marshallbar sein)

beste Grüße
zommi

K
36 Beiträge seit 2008
vor 15 Jahren

@zommi:

Wie meinst du das?

Folgender Code kompiliert bei mir nicht:


class Program
{
    static void Main(string[] args)
    {
        GCHandle objHandle;
        uint[] intArray = new uint[5] { 1, 2, 3, 4, 5 };

        objHandle = GCHandle.Alloc(intArray, GCHandleType.Pinned);

        Test.TestMethod(intArray.Length,
objHandle.AddrOfPinnedObject().ToPointer());
    }
}

unsafe class Test
{
    public static unsafe void TestMethod(int intLength, void* voiPtr)
    {
        for (int i = 0; i < intLength; i++)
        {
            Console.WriteLine(*(((uint*)voiPtr) + i));
        }
    }
}

Ich bekomme:

Zeiger und Puffer fester Größe können nur in einem unsicheren Kontext verwendet werden.

Und das leuchtet mir auch ein: Ich kann ja keinen void* übergeben, wenn ein void* im aktuellen Kontext gar nicht zulässig ist!

Oder habe ich dich falsch verstanden?

1.361 Beiträge seit 2007
vor 15 Jahren

Hallo kyoko12,

ok, dann hab ich dich wohl falsch verstanden.
Wenn diese Funktion "writeData" selbst in C# implementiert wird, dann hat sie ja als Parameter ein void* und demzufolge musst du eh im Unsafe-Context arbeiten.

Also bietet GCHandle selbst dort keinen sooo großen nutzen.
(Sobald du den Pointer nicht mehr brauchst, solltest du im Übrigen auch die fixierung aufheben mittels GCHandle.Free)
Denn so musst du die Umwandlung ...ToPointer() ja auch in nen unsafe-Block einbetten.

Ich dachte zuerst, deine writeData funktion wäre in ner externen DLL,
demzufolge dachte ich eher, folgendes geht:


[DllImport(...)]
static extern void writeData(uint offset, uint length, IntPtr pSource, bool discardWholeBuffer);
...
writeData(0, 10, objHandle.AddrOfPinnedObject(), false);

best Grüße
zommi

S
8.746 Beiträge seit 2005
vor 15 Jahren

Was bewirkt denn discardWholeBuffer?

Ansonsten kannst du void* ganz simpel durch byte[] abbilden. Es braucht weder unsafe noch GCHandle-Kram. Letzteres nur dann, wenn die Funktion den Buffer asynchron schreibt, also auch nach Rückkehr noch benutzt.