Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Delphi DLL in C# verwenden


Bronstein - Fr 23.01.15 15:19
Titel: Delphi DLL in C# verwenden
Hallo ich habe eine Delphi Dll die folgendermaßen deklariert ist:

Delphi-Quelltext
1:
2:
function GetInfosN(PW, Benutzer, Auftrag, Variante, werk, stueliHerkunft,strError, strLog, strTimes, strResult: PAnsichar;
  aPlan, stueli, matVerw, aNetz, klassfz: Boolean; NoXML: Boolean): Boolean; stdcall;


In Delphi rufe ich diese folgendermaßen auf:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function GetInfosN(PW,Benutzer,Auftrag,Variante,werk,stueliHerkunft,strError,strLog,strTimes,strResult:PAnsichar;
  aPlan,stueli,matVerw,aNetz,klassfz: Boolean;NoXML: Boolean): Boolean; stdcallexternal 'SAP_STUELI.dll' name 'GetInfosN';
...
const
  MAX_RESSTR_LEN = 6048576;
  MAX_LOGSTR_LEN = 100000;
var
  tmpData,tmpTimes,tmpError,tmpLog:PAnsiChar;
begin
tmpData:=AnsiStrAlloc(MAX_RESSTR_LEN);
tmpTimes:=AnsiStrAlloc(MAX_LOGSTR_LEN);
tmpError:=AnsiStrAlloc(MAX_LOGSTR_LEN);
tmpLog:=AnsiStrAlloc(MAX_LOGSTR_LEN);

FErg:=GetInfosN(PAnsiChar(AnsiString('XXXXX')),PAnsiChar(AnsiString('Name')),
                                         PAnsiChar(AnsiString('')),PAnsiChar(AnsiString('12354')),
                                         PAnsiChar(AnsiString('55')),PAnsiChar(AnsiString('S')),tmpError,tmpLog,tmpTimes,tmpData,
                                         false,true, false,false, false, false);



Jetzt dachte ich mir ich rufe die Funktion folgendermaßen auf:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
 [DllImport("Meine.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool GetInfosN(string PW, string Benutzer, string Auftrag, string Variante, string werk, string stueliHerkunft, ref string strError, ref string strLog, ref string strTimes, ref string strResult, bool aPlan, bool stueli, bool matVerw, bool aNetz, bool klassfz, bool NoXML);

private void button16_Click(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            bool ergebnis;
            const int sMAX_RESSTR_LEN = 6048580;
            const int sMAX_LOGSTR_LEN = 99005;

            var strError = new String('\x00', sMAX_LOGSTR_LEN);
            var strLog = new String('\x00', sMAX_LOGSTR_LEN);
            var strTimes = new String('\x00', sMAX_LOGSTR_LEN);
            var strResult = new String('\x00', sMAX_RESSTR_LEN);


            ergebnis = GetInfosN("XXXXX""Name""""12354""55""S"ref strError, ref strLog, ref strTimes, ref strResult, falsetruetruefalsefalsefalse);

            if (ergebnis == true)
                GroupBox1.Text = strResult;
        }


Jedoch ist strResult immer leer, hat jemand einen Tipp was ich anderst im C# Code machen muss, die DLL möchte ich nicht ändern da ich diese noch in X anderen Programmen (mit Delphi) geschrieben verwendet

Die DLL habe ich mit Delphi XE2 compiliert.


Ralf Jansen - Fr 23.01.15 16:14

Versuch mal auf C# Seite anstatt "ref string", "StringBuilder" in der Signatur der Methode zu verwenden.


Bronstein - Fr 23.01.15 16:36


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
[DllImport("SAP_STUELI.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool GetInfosN(string PW, string Benutzer, string Auftrag, string Variante, string werk, string stueliHerkunft, ref string strError, ref string strLog, ref string strTimes, StringBuilder strResult, bool aPlan, bool stueli, bool matVerw, bool aNetz, bool klassfz, bool NoXML);
          
StringBuilder strResult = new StringBuilder(sMAX_RESSTR_LEN);
ergebnis = GetInfosN("XXXXX""Name""""12354""55""S"ref strError, ref strLog, ref strTimes, strResult, falsetruetruefalsefalsefalse);

if (ergebnis == false)
  MessageBox.Show(strResult.ToString());


Leider immernoch leer


Ralf Jansen - Fr 23.01.15 16:54

Dann gibts vielleicht Probleme beim interpretieren des PAnsiChar. Versuch mal den unmanaged Typ per Attribut zu deklarieren.
Etwa so

C#-Quelltext
1:
blah ... ref string strTimes, [MarshalAs(UnmanagedType.AnsiBStr)] StringBuilder strResult, bool aPlan, ... blah                    

Das AnsiBStr auf PAnsiChar mappt ist jetzt aber nur geraten.


Bronstein - Fr 23.01.15 17:38

Da bekomme ich einen Error:

C#-Quelltext
1:
..., [MarshalAs(UnmanagedType.AnsiBStr)] StringBuilder strResult, ...                    

"parameter #10" kann nicht gemarshallt werden: Ungültige verwaltete/nicht verwaltete Typenkombination (StringBuilders muss mit LPStr, LPWStr oder LPTStr kombiniert werden)..

Hier bekomme ich wieder nur einen Leerstring zurück:

C#-Quelltext
1:
2:
3:
4:
StringBuilder strResult = new StringBuilder(sMAX_RESSTR_LEN);
..., [MarshalAs(UnmanagedType.LPStr)] StringBuilder strResult, ...
..., [MarshalAs(UnmanagedType.LPWStr)] StringBuilder strResult, ...
..., [MarshalAs(UnmanagedType.LPTStr)] StringBuilder strResult, ...


Martok - Mo 26.01.15 05:16

Anderswo [https://github.com/cgommel/sdrsharp/blob/master/RTLSDR/NativeMethods.cs] verwendet man einfach StringBuilder, ohne Einstellung als was die gemarshallt werden sollen. Die Delphiseite dazu sieht so [https://git.ccs-baumann.de/Martok/sdr/blob/master/src/hardware/librtlsdr.inc] aus.

Ob das so überhaupt stimmt kann ich dir allerdings auch nicht sagen, ich habs nur von C# nach Delphi übersetzt (mit dem C-Header als Spickzettel).