unmanaged c++ Projekt mit managed GUI
-
so jetzt ist ne Menge Zeit vergangen und ich habe den Umbau soweit fertig. Natürlich tauchen jetzt neue Probleme auf. Vielleicht hat ja jemand nen Tip?
direct Video (unmanaged) funktioniert mit dem handle eines WPF Windows. Problem ist, dass das main menu durch directX überschrieben wird. Leider gibt es in WPF nur ein handle für das gesamte Fenster und nicht für einen UI-Block wie einem Grid. Wie zum Geier kann ich nun direct video mitteilen, das seine Zeichenfläche unter dem main menu beginnen soll?
-
ich habe es mittels HwndHost gelöst bekommen. Wer das gleiche Problem hat, hier
eine Beispiel Klasse. Eine Instanz dieser Klasse muss dann einem wpf UI Element zugewiesen werden. z.b. ControlHostElement ist eine Border in meinem XAML code.Am Ende bekommt man über den getter in der Klasse das hwnd des WinApi Fensters, welches sich in dem entsprechenden WPF Element befindet. Dieses wiederum kann man frei positionieren.
ControlHost chost = new ControlHost(height, width);
mainwindow.ControlHostElement.Child = chost;
hwndHandle = chost.hwndHostBox;using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Windows.Interop; namespace project { class ControlHost : HwndHost { [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)] internal static extern IntPtr CreateWindowEx(int dwExStyle, string lpszClassName, string lpszWindowName, int style, int x, int y, int width, int height, IntPtr hwndParent, IntPtr hMenu, IntPtr hInst, [MarshalAs(UnmanagedType.AsAny)] object pvParam); [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)] internal static extern bool DestroyWindow(IntPtr hwnd); internal const int WS_CHILD = 0x40000000, WS_VISIBLE = 0x10000000, LBS_NOTIFY = 0x00000001, HOST_ID = 0x00000002, LISTBOX_ID = 0x00000001, WS_VSCROLL = 0x00200000, WS_BORDER = 0x00800000; IntPtr hwndControl; IntPtr hwndHost; int hostHeight, hostWidth; public ControlHost(double height, double width) { hostHeight = (int)height; hostWidth = (int)width; } public IntPtr hwndHostBox { get { return hwndHost; } } protected override HandleRef BuildWindowCore(HandleRef hwndParent) { hwndHost = IntPtr.Zero; hwndHost = CreateWindowEx(0, "static", "", WS_CHILD | WS_VISIBLE, 0, 0, hostWidth, hostHeight, hwndParent.Handle, (IntPtr)HOST_ID, IntPtr.Zero, 0); return new HandleRef(this, hwndHost); } protected override void DestroyWindowCore(HandleRef hwnd) { DestroyWindow(hwnd.Handle); } } }
-
und das nächste Problem: fatalexecutionengineerror
die app ruft 60 mal pro sekunde die unmanaged dll auf. Sporadisch kommt es vor, dass der managed heap vorn Baum geht. Das lustige ist, ich kann es allein durch die Mausbewegung beeinflussen. Bewege ich die Maus nicht oder um das Fenster der Anwendung gibt es kein Problem. Bewege ich die Maus länger über das Fenster der Anwendung wird der heap nach ein paar Sekunden korrupiert, aber auch nur wenn die app die unmanaged dll pollt.
Die unmanaged dll verursacht mit einem unmanaged Test Programm keine Probleme. Dieses Testprogramm ist eine stark abgespeckte Test Gui, erstellt mit der Winapi.
edit: habe gerade herausgefunden, dass wenn ich nach ca. 5-10 Sekunden erst anfange die Maus über den Bildschirm zu bewegen, kann ich den heap nicht mehr korrupieren. Das gilt auch, wenn ich die unmanaged dll nach obige Zeit in action versetze. Was ist da nur los, brauch .net ein paar Sekunden um dann sauber zu laufen?
-
Wie bindest Du die unmanaged Aufrufe denn ein? Has Du einen C++/CLI Wrapper oder nutzt Du PInvoke?
-
[DllImport(@"Core.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "setHwnd")] static extern void _SetHwnd(IntPtr wih);
hmm, wenn ich in der unmanaged dll sofort nach dem Einsprung ein return setze, gibt es keine Probleme. Also scheint schon irgendwas in der dll das Problem zu verursachen.
-
Schau Dir mal das Thema Pinning genauer an:
http://msdn.microsoft.com/en-us/23acw07k.aspx
Pinning temporarily locks the data in its current memory location, thus keeping it from being relocated by the common language runtime's garbage collector. The marshaler pins data to reduce the overhead of copying and enhance performance. The type of the data determines whether it is copied or pinned during the marshaling process. Pinning is automatically performed during marshaling for objects such as String, however you can also manually pin memory using the GCHandle class.
-
hmm bin mir nicht sicher ob das was mit pinning zu tun hat, aber ich denke ich hab das Problem gefunden, jedoch noch nicht gelöst.
ich reservire Speicher ( byte[] ) im managed Bereich. An den unmanaged Bereich übergebe ich darauf einen pointer ( char* ).
Der unmanaged Bereich schreibt und liest ständig in diesem Speicher. Kommentiere ich das aus, gibt es keinen Absturz mehr. Ich habe mehrfach überprüft ob ich außerhalb des reservierten Bereichs schreibe. Dem ist nicht so.
ok lege ich den Speicher direkt im unamanged Bereich an, funzt es. Der Grund warum ich es nicht gleich dort angelegt habe, ist das ich so schnell die Änderungen im managed Bereich speichern kann.
-
PiCiJi schrieb:
Der unmanaged Bereich schreibt und liest ständig in diesem Speicher.
Und war dieser managed Speicher auch über die ganze Zeit, wo jemand die Finger drin hatte, gepinned?
-
Und war dieser managed Speicher auch über die ganze Zeit, wo jemand die Finger drin hatte, gepinned?
Nein. Ich werde das mal nachrüsten. Wenn ich das richtig verstehe, besteht bei nicht pinning die Gefahr, dass der garbage collector den Speicherbereich umschiebt und mein unwissender pointer im unmanaged Bereich davon nix mitkriegt. Das erklärts natürlich. Danke für die info.
-
Exakt. Wenns nicht gepinned ist, dann muss das früher oder später eigentlich crashen