Laden...

Es wurde versucht, im geschützten Speicher zu lesen...

Erstellt von f.ritz vor 16 Jahren Letzter Beitrag vor 15 Jahren 28.140 Views
f.ritz Themenstarter:in
341 Beiträge seit 2004
vor 16 Jahren
Es wurde versucht, im geschützten Speicher zu lesen...

Hallo zusammen,
ich habe ein Problem beim Aufruf einen externen C++-Funktion. Die Signatur der Funktion sieht so aus:

int execCommand(char *,char *,char *,int,char *,int)

Der Aufruf findet, wie folgt, statt:

class Programm
{
[DllImport("nsuitesigAPIDLL.dll", EntryPoint = "#1")]
public static extern int execCommandExt(string arg1, string arg2, byte[] importData, int importSize, byte[] exportData, int exportSize);
...
void eineFunktion()
{
  ...
  execCommandExt("...", "...", importDataBytes, importDataBytes.Length, exportDataBytes, exportDataBytes.Length);
}
}

Wenn ich versuche die Funktion zwei mal hintereinander aufzurufen, bekomme ich beim zweiten Aufruf die AccesViolationException:
Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben...

Wenn ich es richtig verstehe, schreibt die externe Funktion in den selben Speicherbereich wie vorhin und dann kommt die Exception. Ich habe aber kein Plan was ich hier machen könnte!?!? X(

Gelöschter Account
vor 16 Jahren

nein diese fehlermeldung besagt, das etwas mit deinen zeigern nciht stimmt.

K
236 Beiträge seit 2007
vor 15 Jahren

Hallo f.ritz,

hast du schon ne Lösung gefunden? Ich steh grad vor dem gleichen Problem...
Katja

Gelöschter Account
vor 15 Jahren

wie schaut denn bei dir in c die funktion aus und wie bindest du diese in c# ein?

K
236 Beiträge seit 2007
vor 15 Jahren

Ja so:


[DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetParameter")]
public static extern int GetParameter(StringBuilder sServerIP, StringBuilder sServicePath, StringBuilder sUserName, StringBuilder sPassword, StringBuilder sTransferDir, StringBuilder sProtocolDir, StringBuilder sIPAdresse);


Das ganze lief sauber, als die Anwendung unter .NET 1.1 geschrieben wurde. Jetzt habe ich auf 2.0 upgedated, und seitdem krieg ich die Meldung
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Die C++ dll habe ich nicht geschrieben, wurde mir von einem externen Entwickler bereitgestellt.

Katja

K
236 Beiträge seit 2007
vor 15 Jahren

Kann auch sein, dass .NET 2.0 ausgefeiltere Security Features hat, und das deshalb nicht mehr funktioniert.

katja

Gelöschter Account
vor 15 Jahren

und wie schaut die c signatur aus?

5.742 Beiträge seit 2007
vor 15 Jahren

Hallo kat_2403,

eine sehr häufige Ursache im Bezug auf DllImport und StringBuilder: man muss sicherstellen, dass die Kapazität der als Parameter übergebenen StringBuilder ausreichend dimensioniert ist.

K
236 Beiträge seit 2007
vor 15 Jahren

Ja, das hab ich schon bedacht, und mit 256 initialisiert. Von der Seite her kann der Fehler nicht kommen.

K
236 Beiträge seit 2007
vor 15 Jahren

Ich bin jetzt ein Stückchen weiter, obwohl das Problem nicht gelöst ist.
Ich habe mir eine TestApp geschrieben, die die eine Funktion aus der dll aufruft.

ganz simple, beim Klick auf n Button:


private void button1_Click(object sender, EventArgs e)
{
    try
    {
        StringBuilder sServerIP = new StringBuilder(256);
        StringBuilder sIPAdresse = new StringBuilder(256);
        StringBuilder sServicePath = new StringBuilder(256);
        StringBuilder sUserName = new StringBuilder(256);
        StringBuilder sDateiName = new StringBuilder(256);
        StringBuilder sPassword = new StringBuilder(256);
        StringBuilder sTransferDir = new StringBuilder(256);
        StringBuilder sProtocolDir = new StringBuilder(256);

        GetParameter(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir, sIPAdresse);

        anzeige =  "ServerIP: " + sServerIP.ToString() + "\r\n";
        anzeige += "lokale IP: " + sIPAdresse.ToString() + "\r\n";
        anzeige += "Service Pfad: " + sServicePath.ToString() + "\r\n";
        anzeige += "User: " + sUserName.ToString() + "\r\n";
        anzeige += "FileName: " + sDateiName.ToString() + "\r\n";
        anzeige += "PW: " + sPassword.ToString() + "\r\n";
        anzeige += "Transfer Dir: " + sTransferDir.ToString() + "\r\n";
        anzeige += "Protokoll Dir: " + sProtocolDir.ToString();
    }
    catch (Exception ex)
    {
        anzeige = "Exception Source: " + ex.Source.ToString() + "\r\n";
        anzeige += "Message: " + ex.Message.ToString();
    }
     finally
    {
        textBox1.Text = anzeige;
    }
}

Interessant ist, dass bei
Klick Nr. 1: eine AccessViolation geworfen wird
Klick Nr. 2: die Variablen mit einem Leerstring gefüllt sind
Klick Nr. 3: die GetParameter Funktion ihre Aufgabe erfüllt und die korrekten Werte zurückgibt.

Warum versteh ich das nicht?
Hat jemand einen Tipp??
Danke.
Katja

Gelöschter Account
vor 15 Jahren

versuche es mal mit:


[DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetParameter")]
public static extern int GetParameter([Out] StringBuilder sServerIP,[Out] StringBuilder sServicePath,[Out] StringBuilder sUserName,[Out] StringBuilder sPassword,[Out] StringBuilder sTransferDir,[Out] StringBuilder sProtocolDir,[Out] StringBuilder sIPAdresse); 

S
8.746 Beiträge seit 2005
vor 15 Jahren

Zeige uns doch mal die C-Definition der Funktion, bzw. die genaue Beschreibung der Funktion.

K
236 Beiträge seit 2007
vor 15 Jahren

Hi,
das ist der Source der c++ Funktion:


extern "C"
int __stdcall GetParameter(	char * sServerIP,
							char * sServicePath,
							char * sUserName,
							char * sPassword,
							char * sTransferDir,
							char * sProtocolDir) {
#ifndef NO_PROT
	ACFunctionCallTrace func("GetParameter()");
#endif

	if(!sServerIP || !sServicePath || !sUserName || !sPassword || !sTransferDir || !sProtocolDir) {
		if(ACProtocol::IsValid()) {
			PROTOCOL(0, "Ubergabeparameter inkorrekt!");
		}
		return -1;
	}

	// Evtl. wieder auf "Internet" zurückstellen...
	Global::CheckAndResetErrors();

#ifndef NO_PROT
	if(ACProtocol::IsValid()) {
		PROTOCOL(ACProtocol::ProgFlow, "SOA Verbindungsparameter werden geladen...");
	}
#endif

	CSoaParams params;
	if(!params.Load()) {
#ifndef NO_PROT
		if(ACProtocol::IsValid()) {
			PROTOCOL(ACProtocol::Warning, "Die Parameter konnten nicht geladen werden.");
		}
#endif

		return -1;
	}

	strcpy(sServerIP, params.ServerIP());
	strcpy(sServicePath, params.ServerPath());
	strcpy(sUserName, params.Username());
	strcpy(sPassword, params.Password());
	strcpy(sTransferDir, params.TransferDir());
	strcpy(sProtocolDir, params.ProtocolDir());

	return 0;
}

Grüße
Katja

Gelöschter Account
vor 15 Jahren

hast du meine version schon ausprobiert?

K
236 Beiträge seit 2007
vor 15 Jahren

Jo, aber leider unverändert.
Ist echt zum verrückt werden, wie gesagt, klick ich das 3. Mal auf den Button, also ruf ich das 3. mal die Funktion auf, macht ers korrekt. Ich verstehs net...

S
8.746 Beiträge seit 2005
vor 15 Jahren

Schreibe mal vor dem Aufruf in jeden StringBuilder an die erste Position ein Nullzeichen. Wenn das nicht hilft, ist wohl die Länge tatsächlich zu kurz.

K
236 Beiträge seit 2007
vor 15 Jahren

wie meinst du das?
so?


StringBuilder sServerIP = new StringBuilder("0",64);

4.942 Beiträge seit 2008
vor 15 Jahren

Die C-Funktion hat aber nur 6 Parameter, du übergibst aber 7 (IPAdresse zu viel). Dadurch wird intern der Stack zerstört...

S
8.746 Beiträge seit 2005
vor 15 Jahren

Was lernt uns das: Funktionen mit mehr als 4 Prametern sind evil.

K
236 Beiträge seit 2007
vor 15 Jahren

Au weia, das ist ja jetzt peinlich ...
Stimmt ...

Jetzt hab ich das mal umgepopelt:


[DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetParameter")]

        public static extern int GetParameter(StringBuilder sServerIP, 
                                              StringBuilder sServicePath, 
                                              StringBuilder sUserName, 
                                              StringBuilder sPassword, 
                                              StringBuilder sTransferDir, 
                                              StringBuilder sProtocolDir 
                                              );

        string anzeige;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                StringBuilder sServerIP = new StringBuilder(512);

                StringBuilder sServicePath = new StringBuilder(512);
                StringBuilder sUserName = new StringBuilder(512);

                StringBuilder sPassword = new StringBuilder(512);
                StringBuilder sTransferDir = new StringBuilder(512);
                StringBuilder sProtocolDir = new StringBuilder(512);

                GetParameter(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);

                anzeige =  "ServerIP: " + sServerIP.ToString() + "\r\n";
                
                anzeige += "Service Pfad: " + sServicePath.ToString() + "\r\n";
                anzeige += "User: " + sUserName.ToString() + "\r\n";
                
                anzeige += "PW: " + sPassword.ToString() + "\r\n";
                anzeige += "Transfer Dir: " + sTransferDir.ToString() + "\r\n";
                anzeige += "Protokoll Dir: " + sProtocolDir.ToString();


            }
            catch (AccessViolationException ex)
            {
                anzeige = "AccessViolation:\r\n";
                anzeige += "Exception Source: " + ex.Source.ToString() + "\r\n";
                anzeige += "StackTrace: " + ex.StackTrace.ToString();
                anzeige += "Message: " + ex.Message.ToString();
            }
            catch (Exception ex)
            {
                anzeige = "Allg:\r\n";
                anzeige += "Exception Source: " + ex.Source.ToString() + "\r\n";
                anzeige += "StackTrace: " + ex.StackTrace.ToString();
                anzeige += "Message: " + ex.Message.ToString();
            }
            finally
            {
                textBox1.Text = anzeige;

            }
            
        }
    }

Krieg aber jetzt die Meldung:

AccessViolation:
Exception Source: TestGetParameter
StackTrace: at TestGetParameter.Form1.GetParameter(StringBuilder sServerIP, StringBuilder sServicePath, StringBuilder sUserName, StringBuilder sPassword, StringBuilder sTransferDir, StringBuilder sProtocolDir)
at TestGetParameter.Form1.button1_Click(Object sender, EventArgs e)Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt

Entweder hasst er mich jetzt (?), oder kann das dann nur noch sein, dass die Stringbuilder net vorinitialisiert sind, dann probier ich das jetzt noch mal..

Aber erst mal tausend Dank, das war mir echt ne Lehre!!!

Katja

S
8.746 Beiträge seit 2005
vor 15 Jahren

Versuch nochmal an die erste Position jedes StringBuilder ein Nullzeichen zu schreiben:

sServerIP[0] = "\0";
K
236 Beiträge seit 2007
vor 15 Jahren

🙁 Na wenn ich das so mach, krieg ich einen Konvertierungsfehler:
string kann ich nicht in char konvertieren.

Konvertiere ich den obigen Ausdruck sServerIP[0]=Convert.ToChar("\n");
Stimmt das dann ja auch nicht. Und die Meldung:

Allg:
Exception Source: mscorlib
StackTrace: at System.String.SetChar(Int32 index, Char value)
at System.Text.StringBuilder.set_Chars(Int32 index, Char value)
at TestGetParameter.Form1.button1_Click(Object sender, EventArgs e)Message: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

kommt.

K
236 Beiträge seit 2007
vor 15 Jahren

und so


StringBuilder sServerIP = new StringBuilder("\0",256);

bringt er auch nix ... gleicher Fehler

K
236 Beiträge seit 2007
vor 15 Jahren

So, ich lass nicht locker.
Ich habe den Code etwas zu Testzwecken geändert:

Unterschied zu vorher:

  • Stringbuildervariablen als Member der Klasse (nicht private Variablen innerhalb der Methode

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TestGetParameter
{
    public partial class Form1 : Form
    {
        StringBuilder sServerIP = new StringBuilder("xyz", 512);
        StringBuilder sServicePath = new StringBuilder("xyz", 512);
        StringBuilder sUserName = new StringBuilder("xyz", 512);
        StringBuilder sPassword = new StringBuilder("xyz", 512);
        StringBuilder sTransferDir = new StringBuilder("xyz", 512);
        StringBuilder sProtocolDir = new StringBuilder("xyz", 512);

        /// <summary>
        /// Funktion GetParameter(StringBuilder sServerIP, StringBuilder sServicePath, 
        /// StringBuilder sUserName, StringBuilder sPassword, StringBuilder sTransferDir, 
        /// StringBuilder sProtocolDir) aus ASP_Soa.dll
        /// </summary>
        /// <param name="sServerIP"></param>
        /// <param name="sServicePath"></param>
        /// <param name="sUserName"></param>
        /// <param name="sPassword"></param>
        /// <param name="sTransferDir"></param>
        /// <param name="sProtocolDir"></param>
        
        [DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "GetParameter")]
        public static extern int GetParameter( StringBuilder sServerIP,
                                               StringBuilder sServicePath,
                                               StringBuilder sUserName,
                                               StringBuilder sPassword,
                                               StringBuilder sTransferDir,
                                               StringBuilder sProtocolDir); 

        string anzeige;
        public Form1()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {


            try
            {
                GetParameter(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);

                anzeige = "ServerIP: " + sServerIP.ToString() + "\r\n";

                anzeige += "Service Pfad: " + sServicePath.ToString() + "\r\n";
                anzeige += "User: " + sUserName.ToString() + "\r\n";

                anzeige += "PW: " + sPassword.ToString() + "\r\n";
                anzeige += "Transfer Dir: " + sTransferDir.ToString() + "\r\n";
                anzeige += "Protokoll Dir: " + sProtocolDir.ToString();


            }
            catch (AccessViolationException ex)
            {
                anzeige = "1.\r\n";
                anzeige += ex.ToString();
                DoItAgain(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);
            }
            finally
            {
                textBox1.Text = anzeige;
            }
            

        }

        private void DoItAgain(StringBuilder sServerIP,
                                               StringBuilder sServicePath,
                                               StringBuilder sUserName,
                                               StringBuilder sPassword,
                                               StringBuilder sTransferDir,
                                               StringBuilder sProtocolDir)
        {
            try
            {
                GetParameter(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);
                anzeige = "ServerIP: " + sServerIP.ToString() + "\r\n";

                anzeige += "Service Pfad: " + sServicePath.ToString() + "\r\n";
                anzeige += "User: " + sUserName.ToString() + "\r\n";

                anzeige += "PW: " + sPassword.ToString() + "\r\n";
                anzeige += "Transfer Dir: " + sTransferDir.ToString() + "\r\n";
                anzeige += "Protokoll Dir: " + sProtocolDir.ToString();
            }
            catch(Exception ex)
            {
                anzeige = "2.\r\n";
                anzeige+=ex.ToString();
                DoItAnotherTime(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);
            }
            finally
            {
                textBox1.Text = anzeige;
            }
        
        }

        private void DoItAnotherTime(StringBuilder sServerIP,
                                               StringBuilder sServicePath,
                                               StringBuilder sUserName,
                                               StringBuilder sPassword,
                                               StringBuilder sTransferDir,
                                               StringBuilder sProtocolDir)
        {
            try
            {
                GetParameter(sServerIP, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);
            }
            catch(Exception ex)
            {
                anzeige = "3.\r\n";
                anzeige += ex.ToString();
            }
            finally
            {
                textBox1.Text = anzeige;
            }


        }
    }
}

Und wie ist die Bildschirmausgabe?

---->1. Klick

ServerIP: xyz
Service Pfad: xyz
User: xyz
PW: xyz
Transfer Dir: xyz
Protokoll Dir: xyz

---->2. Klick
ServerIP: 192.168.34.6
Service Pfad: /src/soap/server.php
User: 12345
PW: 4563
Transfer Dir: d:\Database\Applications\SOA
Protokoll Dir: d:\s3000\Protokolle

Das sieht doch schon viel besser aus!

D.h., jetzt schmeisst er gar keine Exception mehr!
Diese DoItAgain(..) Methoden in den Exceptionhandler Blocks hatte ich gebraucht, um nachvollziehen zu können, nach wie vielen Klicks er keine Ausnahme mehr schmeißt (verstehen tu ichs immer noch nicht), mit der Verschiebung der Membervariablen hat sich das aber erledigt.

Danke euch allen.

467 Beiträge seit 2007
vor 15 Jahren

sry, dass ich den Kram noch mal ausgrabe, aber ich habe den selben Fehler, nach neustart gehts immer wieder bis zum nächsten Mal(kommt öfffters bei unerschiedlichen Projects) ich benutze werder unsafe code, noch DLL-import, nicht mal den IO Namespace. Woran kann denn das liegen?

K
236 Beiträge seit 2007
vor 15 Jahren

Hi,
meine Problematik bezog sich auf unmanaged code ... Wenn du damit nicht arbeitest, dann ist das wohl ein anderes Problem.

Ich habe jetzt das Problem nicht lösen können, ich habe alle Varianten ausprobiert, was Marshalling/PInvoke bietet. Immer das gleiche Resultat. Ich glaube langsam, es ist ein .NET bug.

Microsoft verspricht, Stringbuilder by dll Aufruf in einen Zeiger auf char* umzuwandeln, mag schon sein, nur wenn innerhalb der externen Funktion noch ein strcpy passiert, dann schießt er sich weg, nicht immer, aber immer öfter.

Ich lass jetzt Stresstest laufen, weil nach dem 3 Aufruf hat er ja die Parameter ...

Sorry ,ist keine Antwort auf deine Frage, aber meine Problematik ist wie gesagt handling un/managed code....

S
8.746 Beiträge seit 2005
vor 15 Jahren

Hi,
Ich glaube langsam, es ist ein .NET bug.

Das ist es ganz sicher nicht...ich mache schon seit Jahren PInvoke und mir ist noch nicht ein Bug über den Weg gelaufen. Und diese String-Nummer ist wirklich 0815.

Kleiner Tipp: Mache doch mal statt StringBuilder ein IntPtr aus den Parametern. Allokiere entsprechenden Speicher via Marshal.AllocHGlobal(). Übergebe dann und schau dir mit dem Debugger den Speicher hinter der Adresse nach dem Aufruf an. Dann schau mal was da drin ist.

K
236 Beiträge seit 2007
vor 15 Jahren

Danke für den Tipp, ich habe alle Varianten durch mit IntPtr, LPTR ...
Immer wieder das gleiche Ergebnis... auch selbst alloziert...
Beim ersten Aufruf AccessViolationException, beim 2.Aufruf Leere Strings zurück, beim dritten Aufruf stehen die Werte drin ...
Aber ich bin hab die Hoffnung noch nicht aufgegeben und versuchs nun doch noch mal... Ich weiß, ich bin nicht die erste, die so was aufruft.
Die Stringnummer ist für mich net 0815 sondern wirklich nervenzehrend im Moment..

K
236 Beiträge seit 2007
vor 15 Jahren

Hi,
ich nochmal...
Entweder bin ich jetzt komplett bekloppt, oder ... keine Ahnung...
Was stimmt an diesem Code nicht.


[DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true, EntryPoint = "GetParameter")]
        public static extern int GetParameter(IntPtr sServerIP, IntPtr sServicePath2, IntPtr sUserName2, IntPtr sPassword2, IntPtr sTransferDir2, IntPtr sProtocolDir2); 
        static void Main(string[] args)
        {
            int i = 0;
            try
            {
                IntPtr sService = Marshal.AllocHGlobal(new IntPtr(1028));
                IntPtr sServicePath = Marshal.AllocHGlobal(new IntPtr(1028));
                IntPtr sUserName = Marshal.AllocHGlobal(new IntPtr(1028));
                IntPtr sPassword = Marshal.AllocHGlobal(new IntPtr(1028));
                IntPtr sTransferDir = Marshal.AllocHGlobal(new IntPtr(1028));
                IntPtr sProtocolDir = Marshal.AllocHGlobal(new IntPtr(1028));

                i = GetParameter(sService, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);
                IntPtr bService = Marshal.AllocHGlobal(1024);

                Marshal.StructureToPtr(sService, bService, false);

                byte[] serviceData = new byte[1024];

                Marshal.Copy(bService, serviceData, 0, 1024);
                Marshal.FreeHGlobal(bService);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            } 

Immer noch AccessViolation...
Danke für jeden Tipp.
Katja

630 Beiträge seit 2007
vor 15 Jahren

Hallo,

wenn ich mich richtig erinnere Marshalled .NET ref Parameter automatisch zu einem Pointer.

Demnach müsste es eigentlich reichen die Funktion so zu definieren:


public static extern int GetParameter( ref StringBuilder sServerIP,
                                               ref StringBuilder sServicePath,
                                               ref StringBuilder sUserName,
                                               ref StringBuilder sPassword,
                                               ref StringBuilder sTransferDir,
                                               ref StringBuilder sProtocolDir);

Alternativ vieleicht auch so:


public static extern int GetParameter( ref string sServerIP,ref string sUserName, ...)

Das müsste er mit ziemlicher Sicherheit in ein char* marshallen.

Edit:
Probier auch mal CallingConvetion.Cdecl aus.

Gruss
tscherno

To understand recursion you must first understand recursion

http://www.ilja-neumann.com
C# Gruppe bei last.fm

K
236 Beiträge seit 2007
vor 15 Jahren

Hi,
das hab ich auch probiert, aber immer noch die AccessException ...
das ist echt zum Haare raufen ...
als die Anwendung unter 1.1 lief, war alles super, ohne Probleme, und jetzt das ...
Ich hab auch ziemlich viele Artikel dazu gelesen, und Stringbuilder scheint das richtige zu sein .. nur renn ich da permanent rein.

Katja

S
8.746 Beiträge seit 2005
vor 15 Jahren

Wenn die IntPtr-Nummer nicht klappt, dann liegt der Fehler in der DLL oder die Funktion sieht anders aus als von dir gepostet. Da die Pointer aus params vor dem strcpy() nicht geprüft werden, schätze ich mal, da liegt der Hase im Pfeffer.

K
236 Beiträge seit 2007
vor 15 Jahren

wo der Hase liegt, ist genau der Punkt ... die Anwendung läiuft seit Jahren ...
ich kam, sah und fiel.. keine Ahnung .. es läuft ja schon seit ewig unter 1.1 ...

S
8.746 Beiträge seit 2005
vor 15 Jahren

Ach, meist liegt das dann an Kleinigkeiten. Da liegen z.B. zwei (nicht identische) Versionen der DLL irgendwo auf der Platte. Auf einmal wird die falsche geladen. Oder die Doku entpuppt sich als alt. Oder irgendeine schwachsinniges C-Marko definiert mal locker __stdcall auf __cdecl um.

Ebenfalls beliebtes Problem: Die DLL lädt dynamisch weitere DLLs nach. Findet diese Dann nicht, versucht aber trotzdem den Code anzuspringen (das Tracing wäre für mich so ein Kandidat: ACFunctionCallTrace func("GetParameter()"); ). Diesen Fall würde ich mal mit dem FileMon von SysInternals prüfen.

Ich kann dir nur sagen: Die IntPtr-Variante schließt in deinem Falle jegliches Marshalling-Problem aus. Du übergibst jetzt Pointer mit jeweils 1KB allokierten Speicher. Da kann einfach nix mehr schiefgehen, soweit der Rückgabeparameter ok ist.

Suche den Fehler nicht im .NET-Code. Suche ihn an der Umgebung.

K
236 Beiträge seit 2007
vor 15 Jahren

Danke dir ... ich beiss mich durch ...

K
236 Beiträge seit 2007
vor 15 Jahren

Jetzt bin ich schon mal so weit:


[DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true, EntryPoint = "GetParameter")]
        public static extern int GetParameter(out IntPtr sService, out IntPtr sServicePath2,
                   out IntPtr sUserName2, out IntPtr sPassword2, out IntPtr sTransferDir2, out IntPtr sProtocolDir2);
        static void Main(string[] args)
        {
            int i = 0;
            try
            {
                IntPtr sService = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sServicePath = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sUserName = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sPassword = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sTransferDir = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sProtocolDir = Marshal.AllocHGlobal(new IntPtr(4));

                //string sService = null; 

                i = GetParameter(out  sService, out sServicePath, out sUserName, out sPassword,
                                    out sTransferDir, out sProtocolDir);

                //sService.GetType().Name; 
                //string y = Marshal.PtrToStringAuto(sService).TrimStart(); 

                //StringBuilder me = new StringBuilder(); 
                //me =         (StringBuilder) sService; 
                IntPtr bService = Marshal.AllocHGlobal(1024);

                Marshal.StructureToPtr(sService, bService, false);

                byte[] serviceData = new byte[1024];

                Marshal.Copy(bService, serviceData, 0, 1024);
                Marshal.FreeHGlobal(bService);

                string str = "t";//sService.ToPointer(); 
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                str = enc.GetString(serviceData);
                Console.WriteLine(str.ToString());
                
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            } 





        }

Ausser, dass ich noch nicht den korrekten Wert in der Ausgabe habe, da steht noch Kokoloris drin ....
Katja

K
236 Beiträge seit 2007
vor 15 Jahren

So ... ich fass es nicht, wieso ich so lange hier rumgurke ...
Jetzt aber hab ichs ... meine Güte ...
Danke für die Tipps.


 [DllImport(@"ASP_Soa.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true, EntryPoint = "GetParameter")]
        public static extern int GetParameter(IntPtr sServerIP, IntPtr sServicePath2, IntPtr sUserName2, IntPtr sPassword2, IntPtr sTransferDir2, IntPtr sProtocolDir2); 
        static void Main(string[] args)
        {
            int i = 0;
            try
            {
                IntPtr sService = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sServicePath = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sUserName = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sPassword = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sTransferDir = Marshal.AllocHGlobal(new IntPtr(4));
                IntPtr sProtocolDir = Marshal.AllocHGlobal(new IntPtr(4));

                i = GetParameter(sService, sServicePath, sUserName, sPassword, sTransferDir, sProtocolDir);
                
                string sIP = Marshal.PtrToStringAnsi(sService);
                string sPath = Marshal.PtrToStringAnsi(sServicePath);
                string sUser = Marshal.PtrToStringAnsi(sUserName);
                string sPass = Marshal.PtrToStringAnsi(sPassword);
                string sTransfer = Marshal.PtrToStringAnsi(sTransferDir);
                string sProtocol = Marshal.PtrToStringAnsi(sProtocolDir);
                
                Marshal.FreeHGlobal(sService);
                Marshal.FreeHGlobal(sPassword);
                Marshal.FreeHGlobal(sServicePath);
                Marshal.FreeHGlobal(sUserName);
                Marshal.FreeHGlobal(sTransferDir);
                Marshal.FreeHGlobal(sProtocolDir);

                Console.WriteLine("ServerIP: " + sIP);
                Console.WriteLine("ServicePath: " + sPath);
                Console.WriteLine("User: " + sUser);
                Console.WriteLine("Passwort: " + sPass);
                Console.WriteLine("Transfer: " + sTransfer);
                Console.WriteLine("Protkoll: " + sProtocol);


                
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            } 

Thema gott sei Dank abgeschlossen!
Katja

K
236 Beiträge seit 2007
vor 15 Jahren

Hm
... doch ne Fehlanzeige, auf dem Live-Rechner renn ich wieder in eine AccessViolationException....