MemBrain und C#

Sie haben ein bestimmtes Projekt zu bearbeiten und wissen nicht, wie Sie an die Aufgabe heran gehen sollen? Sie sind sich nicht sicher, ob Ihr Netzentwurf zu Ihrem Problem passt oder ob es da Optimierungsmöglichkeiten gibt? Ist es überhaupt sinnvoll an Ihre Daten mit einem NN basierten Ansatz heranzugehen? Ist MemBrain das richtige Werkzeug für Ihr Problem und Ihre Infrastruktur?

Hier ist der richtige Platz für diese Art von Fragen.
Post Reply
HoMi12
Posts: 2
Joined: Wed 25. Mar 2009, 19:24

MemBrain und C#

Post by HoMi12 »

Hallo MemBrainErInnen,

ich arbeite an einem Projekt, in dem MemBrain im Rahen eines Excel 2007-AddIn zum Einsatz kommen soll. Die MemBrain-Funktionalität wird eingebunden über ein Modul, das den DLLImport übernimmt.

In Übertragung des VB-Aufrufs

Code: Select all

        Private Declare Function MB_GetVersionInfo Lib "MEMBRAINDLL.dll" _
        Alias "__MB_GetVersionInfo@8" (ByVal infoStr As String, ByVal maxLen As Long) As Long
wird der DLLImport in einer C#-Klasse wie folgt eingebunden

Code: Select all

        using System.Runtime.InteropServices;
        namespace MemBrainConnector
        {
           public partial class MemBrainConnector
            {
                [DllImport("MemBrainDll.dll", EntryPoint = "__MB_GetVersionInfo@8")]
                public static extern long MB_GetVersionInfo(ref string infoStr, long maxLen);
        
                /// ...
            }
        }
Der Aufruf von MB_GetVersionInfo erfolgt mit Hilfe von

Code: Select all

        public void ButShowDllVersion_Click()
        {
            long result = 0;
            long strLength = 50;
            string myVersion = "\0";
            try
            {
                result = MB_GetVersionInfo(ref myVersion, strLength);
            }
            catch (Exception e)
            {
                Console.WriteLine("{0} Exception caught.", e);
            }
            if (result == 0)
                Console.WriteLine(myVersion.ToString()); 
            else
                HandleDllError(); 
        }
So weit - so gut (?) ...

Das Problem:

Bei der Ausführung endet das Programm mit der Abarbeitung der Zeile

Code: Select all

        result = MB_GetVersionInfo(ref myVersion, strLength);
Excel wird ohne weitere Aktivität geschlossen. Die Ausnahmebehandlung mit try wird ebenfalls nicht mehr ausgeführt.

Der Aufruf mit dem ref-Schlüsselwort ist aus meiner Sicht notwendig, weil die Funktion die Versions-Information in myVersion schreibt, was nur erfolgt, wenn das Argument als Verweis übergeben wird.

Wird "ref" im Code gelöscht, wird die Funtion zwar abgearbeitet (?), aber myVersion enthält keine Versionsinformation. Als result wird der Wert "11602252854722560" - als ein Fehler - zurückgegeben.

Der analog realisierte Aufruf von MB_GetNetCount() scheint ordnungsgemäß zu funktionieren, was wohl daran liegt, dass diese keine Argumente benutzt.

Wenn ich die gleiche Funktion in der Musteranwendung MBInputQualify_Excel_2007.xlsm aufrufe gibt MB_GetVersionInfo eine richtige Information zurück.

Was läuft da falsch???

Danke für hilfreiche Anmerkungen.

Gruß HoMi12
User avatar
Admin
Site Admin
Posts: 438
Joined: Sun 16. Nov 2008, 18:21

Re: MemBrain und C#

Post by Admin »

Hallo HoMi12,

leider kenne ich mich in C# so gar nicht aus, allerdings hört sich Dein Problem ganz stark nach einer falschen 'Calling Convention' an. Die Calling Convention gibt an, wie Parameter beim Aufruf einer Funktion auf dem Stack abgelegt werden und wer den Stack nach Rückkehr aus der Funktion wieder aufzuräumen hat (entweder der Aufrufer oder die aufgerufene Funktion).

Wird die falsche calling convention verwendet, dann korrumpiert das den Stack und das führt typischerweise zu solchen Abstürzen, wie Du es beschreibst.

Wie man unter C# die Calling Convention festlegt findest Du hier:

http://msdn.microsoft.com/de-de/library ... S.80).aspx

Versuch es mal mit CDecl und Stdcall, eines davon sollte hinhauen. Lass uns wissen, ob es geklappt hat, ja?

Viele Grüße
Thomas Jetter
User avatar
Admin
Site Admin
Posts: 438
Joined: Sun 16. Nov 2008, 18:21

Re: MemBrain und C#

Post by Admin »

Hallo nochmal,

die Sache mit 'ref' scheint außerdem doch nicht ganz richtig zu sein, siehe u.a. hier:

http://www.spotlight-wissen.de/archiv/m ... 43906.html

Man findet sehr viele Beispiele im Netz, alle arbeiten aber ohne 'ref'. Da die Herangehensweise bei VB auch mit 'ByVal' sein musste, vermute ich, dass das 'ref' überall in Deinem Code wegfallen sollte. Ist aber nur geraten, muss ich zugeben, kenne mich wie gesagt in C# leider nicht aus.

Ich denke außerdem, dass Du Deinen String vor dem dll Aufruf auf eine gewisse Länge bringen musst, damit die dll gefahrlos reinschreiben kann. Gibt es da in C# so eine Art 'resize' Methode für strings oder so?

Viele Grüße
Thomas Jetter
User avatar
Admin
Site Admin
Posts: 438
Joined: Sun 16. Nov 2008, 18:21

Re: MemBrain und C#

Post by Admin »

Und noch ein letztes Mal:

Du musst anscheinend 'StringBuilder' anstatt von 'String' verwenden, wenn es ein Rückgabewert sein soll, siehe hier:

http://www.c-plusplus.de/forum/viewtopi ... 92725.html

Ganz unten auf der Seite

http://msdn.microsoft.com/en-us/library/s9ts558h.aspx

ist ein konkretes Beispiel mit einem StringBuilder, inklusive Längenangabe, so sollte es funktionieren, vorausgesetzt, dass die CallingConvention korrekt eingestellt ist. Bei dieser würde ich es erst einmal mit StdCall versuchen.

Viele Grüße
Thomas Jetter
HoMi12
Posts: 2
Joined: Wed 25. Mar 2009, 19:24

Re: MemBrain und C#

Post by HoMi12 »

Hallo Thomas Jetter,

vielen Dank für die Unterstützung. Die Lösung mit dem StringBuilder funktioniert und gibt das zutreffende Ergebnis zurück. Die Lösung sieht wie folgt aus.

MemBrainConnector.cs:

Code: Select all

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace MemBrainConnector
{
    public partial class MemBrainConnector
    {
        [DllImport("MemBrainDll.dll", EntryPoint = "__MB_GetVersionInfo@8")]
        public static extern long MB_GetVersionInfo(StringBuilder infoStr, long maxLen);

        ....
    }
}
Aufrufende Datei:

Code: Select all

....
StringBuilder myVersion = new StringBuilder("", 50);
long result = 0;
long strLength = 50;
result = MB_GetVersionInfo(myVersion, strLength);
....
Obwohl der Weg funktioniert scheint er mir nicht sauber - kann ich aber nicht näher begründen.
Mir schiene eine Lösung mit einem Funktionsaufruf der nicht long result sondern string myVersion zurückgibt besser.
Wäre vielleicht ein Hinweis für eine künftige Version.

Unabhängig davon vielen Dank für die Hilfe.

Gruß HoMi12
User avatar
Admin
Site Admin
Posts: 438
Joined: Sun 16. Nov 2008, 18:21

Re: MemBrain und C#

Post by Admin »

Hallo HoMi12,

freut mich, dass es klappt, vielen Dank auch für die Rückmeldung!
Obwohl der Weg funktioniert scheint er mir nicht sauber - kann ich aber nicht näher begründen.
Mir schiene eine Lösung mit einem Funktionsaufruf der nicht long result sondern string myVersion zurückgibt besser.
Wäre vielleicht ein Hinweis für eine künftige Version.
Aus Sicht einer Programmiersprache, die strings als nativen Datentyp unterstützt (wie z.B. C#), mag das sonderbar erscheinen. Da reines 'C' (und das dll-Interface ist in 'C' gehalten) aber nun mal keine Strings kennt, sondern nur Character-Arrays, ist das die einzig sinnvolle Weise, einen String zurückzuliefern. Die einzige Alternative wäre ein (const-) Pointer, was aber bedeuten würde, dass das eigentliche Array im Speicherbereich der dll verebleiben müsste und diese die Gültigkeit der entsprechenden Speicheradresse und der Daten aufrecht erhalten müsste. Die dll kann aber nicht wissen, wie lange die Daten durch den Aufrufenden benötigt werden. Durch die Übergabe in ein char Array werden die Daten wirklich in den Speicherbereich des Aufrufenden kopiert, es entsteht eine echte Kopie der Daten. Aus diesem Grund muss auch die Größe des Buffers durch die aufrufende Funktion angegeben werden, so dass ein Schreiben in ungültige Bereiche durch die dll verhindert wird.

Viele Grüße
Thomas Jetter
Skyflipper
Posts: 4
Joined: Fri 16. Jan 2009, 16:15

Re: MemBrain und C#

Post by Skyflipper »

Hallo,

bin mir nicht sicher, ob das hier irgendwo schon mal beantwortet wurde.

Wie ist es möglich, (mithilfe von VBA) eine Excel Funktion zu definieren, die den Output eines zuvor trainierten NN als Resultat liefert?

Stehen z.B. die Input Daten in den Zellen A1:C1 könnte der Aufruf so aussehen:
=Mein_NN(A1:C1)
oder besser - um mehrere NNs zu vergleichen:
=Membrain("C:\Membrain\Netz1.dll";A1:C1)

Man könnte auf diese Art und Weise z.B. sehr schnell eine Topografische Karte der Outputs bei unterschiedlichen Parametern bekommen. (z.B. X-Achse: Input1 von 1..10 // Y-Achse: Input2 von 0..1 // Z-Achse: Output)

Von anderen Spielereien mit Excel ganz zu schweigen ;-)

Bin gespannt...

Liebe Grüße
Sky
Post Reply