Probleme beim Laden einer unmanaged DLL



  • Hallihallo,

    bin gerade dabei eine unmanaged DLL in mein Projekt einzubinden. Ich habe dazu C und VB Beispiele bekommen und stolpere nun über die Funktionsparametertypen.

    Der typedef in C sieht folgendermaßen aus:

    typedef void (__stdcall *fp_SETUPdllTYPE)(long &,char*,char*,char*,long &,char*,long ,long ,long ,long );
    

    Der Aufruf in C++ sieht folgendermaßen aus:

    long i, ierr;
    char hf[5100], hrf[4], herr[256], hfmix[256];
    ...
    SETUPdll(i, hf, hfmix, hrf, ierr, herr, 5100, 255, 3, 255);
    

    in VB sieht das Ganze so aus (witzigerweise sind die ganzen Übergabeparameter für die Funktion SETUPdll ohne irgendwelche ByRefs usw. gekennzeichnet):

    Public Declare Sub SETUPdll Lib "Mylib.DLL" (i As Long, ByVal hfld As String, ByVal hfmix As String, ByVal hrf As String, ierr As Long, ByVal herr As String, ln1 As Long, ln2 As Long, ln3 As Long, ln4 As Long)
    
    ...
    
    Public herr As String * 255, hfmix As String * 255
    Public hrf As String * 3
    Public hfld As String * 10000, nc As Long
    Public ierr As Long
    
    Call SETUPdll(nc, hfld, hfmix, hrf, ierr, herr, 10000&, 255&, 3&, 255&)
    

    mein C# Code sieht so aus:

    public class CMyClass
    {
        #region P/Invoke DLL imports
        [DllImport(@".\DLL\mylib.dll", EntryPoint = "SETUPdll", ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
        private static extern void SETUPdll(ref int i, [MarshalAs(UnmanagedType.LPStr)] ref string hfld, [MarshalAs(UnmanagedType.LPStr)] ref string hfmix, [MarshalAs(UnmanagedType.LPStr)] ref string hrf, ref int ierr, [MarshalAs(UnmanagedType.LPStr)] ref string herr, int ln1, int ln2, int ln3, int ln4);
        #endregion
    
        public CMyClass()
        {
        }
    
        public void Setup(string[] saComponents, string sCoefficients, string sRefState)
        {
            int iCountComponents = saComponents.Length;
            string sComponents = string.Join("|", saComponents);
    
            int iError = 0;
            string sError = string.Empty;
    
            SETUPdll(ref iCountComponents, ref sComponents, ref sCoefficients, ref sRefState, ref iError, ref sError, 10000, 255, 3, 255);
        }
    }
    

    Die C++ Einbindung funktioniert soweit ganz gut.

    Mein Problem ist nun, dass in der C Typedeklaration die Übergabeparameter mit & und * (Referenzen, Pointer) definiert sind und speziell in den Parametern ierr, herr Fehlercodes bzw. Fehlermeldungen zurückkommen. In C# habe ich die Variablen deswegen mit ref gekennzeichnet.

    Der C# Code wird nun bis SETUPdll(...) ausgeführt und beendet ohne Exception sofort meine Anwendung. 😕

    Ändere ich den Code wie folgt ("ref" vor iCountComponents weg):

    public class CMyClass
    {
        #region P/Invoke DLL imports
        [DllImport(@".\DLL\mylib.dll", EntryPoint = "SETUPdll", ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
        private static extern void SETUPdll(int i, [MarshalAs(UnmanagedType.LPStr)] ref string hfld, [MarshalAs(UnmanagedType.LPStr)] ref string hfmix, [MarshalAs(UnmanagedType.LPStr)] ref string hrf, ref int ierr, [MarshalAs(UnmanagedType.LPStr)] ref string herr, int ln1, int ln2, int ln3, int ln4);
        #endregion
    
        public CMyClass()
        {
        }
    
        public void Setup(string[] saComponents, string sCoefficients, string sRefState)
        {
            int iCountComponents = saComponents.Length;
            string sComponents = string.Join("|", saComponents);
    
            int iError = 0;
            string sError = string.Empty;
    
            SETUPdll(iCountComponents, ref sComponents, ref sCoefficients, ref sRefState, ref iError, ref sError, 10000, 255, 3, 255);
        }
    }
    

    erscheint folgende Exception:

    {"Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist."}

    Genau die selbe Exception erscheint, wenn ich den Code ähnlich wie im VB-Beispiel ohne refs schreibe.

    Was genau mache ich bei den Übergabeparametern falsch?



  • Probier mal mit folgendem Tool die extern Signaturen zu generieren:
    http://www.codeplex.com/clrinterop



  • Wenn ich das Tool ausführe, auf Start klicke (monitoring) und dann meine Anwendung ausführe, passiert außer der Exception in meiner Anwendung nichts.



  • Ok, habs gelöst. Der Hinweis zu der o.g. Seite hat mich zu dem Tool "P/Invoke Interop Assistant" gebracht. Vom Prinzip her macht es genau das umgekehrte, wie dass, was ich wollte. 😃 Es liefert mir zu P/Invoke C#-Code das C-Pendant und noch Bewertungen der verwendeten Datentypen dazu.

    In diesem Zusammenhang kam der Hinweis, das man für in/out Parameter vom Typ char* doch lieber StringBuilder verwenden soll.

    public class CMyClass
    {
        #region P/Invoke DLL imports
        [DllImport(@".\DLL\mylib.dll", EntryPoint = "SETUPdll", ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
        private static extern void SETUPdll(ref int i, StringBuilder hfld, StringBuilder hfmix, StringBuilder hrf, ref int ierr, StringBuilder herr, int ln1, int ln2, int ln3, int ln4);
        #endregion
    
        public CMyClass()
        {
        }
    
        public void Setup(string[] saComponents, string sCoefficients, string sRefState)
        {
            int iCountComponents = saComponents.Length;
            StringBuilder sbComponents = new StringBuilder(string.Join("|", saComponents), 10000);
            StringBuilder sbCoefficients = new StringBuilder(sCoefficients, 256);
            StringBuilder sbRefState = new StringBuilder(sRefState, 256);
            StringBuilder sbError = new StringBuilder(256);
    
            int iError = 0;
    
            SETUPdll(ref iCountComponents, sbComponents, sbCoefficients, sbRefState, ref iError, sbError, 10000, 255, 3, 255);
        }
    }
    

    Sehr wichtig ist in diesem Zusammenhang auch die Tatsache, dass man die StringBuilder Objekte mit Werten für die festen Längen initialisieren muss.


Anmelden zum Antworten