cli::interior_ptr
-
Hallo,
ich bin blutiger C++/CLI Anfänger und habe folgendes Problem:
Ich habe eine managed Klasse EditorForm:public ref class EditorForm : public System::Windows::Forms::Form { private: ID3D10Effect* effect;
und die besitzt einen Zeiger auf ID3D10Effect. ID3D10Effect ist ein DirectX Typ und kommt aus einer nativen C++ Biblithek.
Jetzt möchte ich im Ctor von EditorForm die Variable effect initialisieren:
D3DX10CreateEffectFromFile("shader/shader.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_DEBUG, 0, device, NULL, NULL, &effect, &error, NULL)
Die Funktion D3DX10CreateEffectFromFile erwartet als vorletzten Parameter ein ID3D10Effect **ppEffect.
Nur leider liefert der Funktionsaufruf diesen Fehler:
error C2664: 'D3DX10CreateEffectFromFileA' : cannot convert parameter 10 from 'cli::interior_ptr<Type>' to 'ID3D10Effect **'Kann mir wer sagen was der Fehler bedeutet und wie ich ihn behebe? Danke!
-
ref Klassen können vom GC "verschoben" werden, daher kannst du Adressen die "in" ein ref Objekt verweisen auch nicht in "unmanaged" Code verwenden, ohne das Objekt vorher zu pinnen.
Der einfachste Ausweg wäre wohl eine lokale Variable zu verwenden:if (effect) effect->Release(); effect = 0; ID3D10Effect* temp = 0; D3DX10CreateEffectFromFile("shader/shader.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_DEBUG, 0, device, NULL, NULL, &temp, &error, NULL) effect = temp;
-
Danke für die schnelle Antwort hustbaer.
Nur zum Verständnis: Nehmen wir mal an er würde die Übergabe zulassen. Wir sind also gerade in der Funktion D3DX10CreateEffectFromFile:
D3DX10CreateEffectFromFile( ... ) { ... // Zeile X *effect = ... }
Wenn das ginge, würde das bedeuten, dass z.B. zufällig in Zeile X der Thread gewechselt wird und der GC-Thread dran ist und er (warum auch immer), das Objekt EditorForm im Managed Heap an eine andere Adresse schiebt und damit die EditorForm Membervariable effect auf eine andere Adresse zeigt. Wäre das so? Mir fällt nur grad kein Fall ein, wo das ein Problem darstellen würde...
PS: Sollte man lieber eine temporäre lokale Variable nehmen oder pin_ptr?
-
Du würdest einen Zeiger auf die Membervariable "effect" übergeben, nicht einen Zeiger auf das auf was "effect" zeigt.
Angenommen die Form beginnt vor "Zeile X" an Adresse 1000, und angenommen "effect" hat einen Offset von 10, dann wäre die Adresse von effect 1010. Du übergibst also an die Funktion 1010.
Dann wird die Form verschoben, so dass sie nun ab Adresse 2000 liegt, die neue "effect" Variable hat nun die Adresse 2010.
Der Funktion hast du aber 1010 übergeben, und da dies keine "tracking reference" ist, sondern bloss eine "unmanaged" Adresse (=einfache Zahl wenn du so willst), wird die Funktion auch die Adresse 1010 überschreiben, und nicht 2010.
Es wäre also in jedem Fall ein Problem, da die Membervariable an der neuen Adresse nicht geschrieben wird. Und an Adresse 1010 könnte schon etwas ganz anderes liegen, das dann fälschlicherweise überschrieben wird. Das könnte zu ganz argen Fehlern führen.
PS: Sollte man lieber eine temporäre lokale Variable nehmen oder pin_ptr?
Pinnen immer nur dann wenn man muss. Ich würde hier also eine lokale Variable vorziehen, denn durch die lokale Variable hinderst du den GC nicht daran die Form zu verschieben.
-
Verstehe. Das heißt doch dann, dass wenn ich einen pinning pointer auf eine Membervariable eines Objekts X habe, das Objekt X so lange nicht verschoben werden kann, bis der pinning pointer zerstört wird (zb. scope verlässt), oder?