Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Struct von C++ nach C#
clever
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

Struct von C++ nach C#

beantworten | zitieren | melden

Hi,

Hab ein C++ header file, dass ich nach C# exportieren muß.

// C++

typedef struct {
	LVBoolean error;
	long code;
	LStrHandle source;
	} TD1;

typedef struct {
	LStrHandle sourceValue;
	LStrHandle measureValue;
	LStrHandle delayValueSec;
	LStrHandle timeValueSec;
	} TD3;

typedef struct {
	long dimSize;
	TD3 elt[1];
	} TD2;
typedef TD2 **TD2Hdl;


void __stdcall ReadMeasurement(char GPIBAddress[], TD1 *errorIn, 
	double *suppressionValue, char selectedFunction[], TD2Hdl *display, 
	TD1 *errorOut, long len);

Habs versucht jedoch noch ohne Erfolg

// C#

[StructLayout(LayoutKind.Sequential)]
public struct TD1
{
    public ushort error;
    public long code;
    public string source;
};


[StructLayout(LayoutKind.Sequential)]
public struct TD3
{
    public string sourceValue;
    public string measureValue;
    public string delayValueSec;
    public string timeValueSec;
};


[StructLayout(LayoutKind.Sequential)]
public struct TD2
{
    public long dimSize;
    public TD3 elt;
};


[DllImport("Read_Measurement.dll", EntryPoint = "ReadMeasurement",
    ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
    public static extern int ReadMeasurement(string GPIBAddress, ref TD1 errorIn, 
	                                                 ref double suppressionValue, string selectedFunction, 
                                                     ref TD2 display, ref TD1 errorOut, long len);



private void button1_Click(object sender, EventArgs e)
{
   errorIn = new TD1();
   errorOut = new TD1();
   display = new TD2();

error =ReadMeasurement(16, ref errorIn, ref suppresionValue, "", ref display, ref errorOut, 1);
}


Das Objekt display (TD3 sctruct) zeigt immer null Werte.

Wahrscheinlich liegt es an dem struct, dass ich nicht korrekt in C# umwandeln kann.
typedef struct {
	long dimSize;
	TD3 elt[1];
	} TD2;
typedef TD2 **TD2Hdl;


Weiß jemand Rat?

Vielen Dank im Vorraus.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von clever am .
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1.361
Herkunft: Berlin

beantworten | zitieren | melden

Hi,

da in deinen C/C++ Strukturen spezielle Datentypen verwendet werden, musst du auch beim Umwandeln besonders aufpassen. C# kann das ja nicht ahnen.

Aus den Namen schließe ich, dass du was mit LabVIEW zu tun hast.
Da musst du dich dann über die LabVIEW Datentypen schlau machen und das Standardmäßige Marschalling-Verhalten in .Net entsprechend anpassen.

Zu LVBoolean:
LVBoolean 	8-bit integer, 0 if FALSE, 1 if TRUE
erforder:
UnmanagedType.U1       1-Byte-Ganzzahl, wobei der Wert 1 für true und der Wert 0 für false steht.
LVBoolean 	8-bit integer, 0 if FALSE, 1 if TRUE
erforder:
UnmanagedType.U1       1-Byte-Ganzzahl, wobei der Wert 1 für true und der Wert 0 für false steht.

Zu LStrHandle:
typedef struct {

    int32 cnt;

    /* number of bytes that follow */

    uChar str[1];

    /* cnt bytes */

    } LStr, *LStrPtr, **LStrHandle;

Ist also im Prinzip ein char-Array mit vorgestellter Länge. Aber dein LStrHandle ist ein Pointer auf einen Pointer auf solch ein Objekt. Das kannst du nicht direkt marshallen lassen.
Dafür gibts nichts entsprechendes in .Net.
Entweder du schreibst dir selbe nen Marshaller, oder du machst das per Hand.
Du erwartest also nen IntPtr. Liest dort wieder den IntPtr aus und daraus dann die LStr-entsprechende Struktur.

Alles nicht so einfach :-)

beste Grüße
zommi
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 244
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

Hallo,

auch den Datentyp long solltest du genauer anschauen, da dieser normalerweile 4 byte groß ist, welches ein int in .NET wäre.

Spooky
private Nachricht | Beiträge des Benutzers
clever
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

beantworten | zitieren | melden

Danke für die Antworten.

Hast du ein Beispiel, dass zeigt wie man einen IntPtr ausliest?

Danke.
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1.361
Herkunft: Berlin

beantworten | zitieren | melden

Hi clever,

beispielsweise könntest du für deine TD1-Struktur folgendes nehmen:

    [StructLayout(LayoutKind.Sequential)]
    struct TD1
    {
        [MarshalAs(UnmanagedType.U1)]
	    public bool Error;

	    public int Code;

	    private IntPtr sourcePtr;

        public string Source
        {
            get
            {
                if (sourcePtr == IntPtr.Zero)
                    return null;

                IntPtr plstr = Marshal.ReadIntPtr(sourcePtr);
                if (plstr == IntPtr.Zero)
                    return null;

                int strLength = Marshal.ReadInt32(plstr);
                IntPtr strData = new IntPtr(plstr.ToInt32() + 4);
                return Marshal.PtrToStringAnsi(strData, strLength);
            }
        }
	}

Habs zwar jetzt nicht getestet, aber im Prinzip so.

beste Grüße
zommi
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von zommi am .
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 244
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

IntPtr strData = new IntPtr(plstr.ToInt32() + 4);

sollte noch in

IntPtr strData = new IntPtr(unchecked(plstr.ToInt64() + 4));

geändert werden um auch unter 64bit zu funktionieren. Ggf könnte man die Offset Operation noch in eine sperate Methode mit Over-/Underflow Check auslagern.

Spooky
private Nachricht | Beiträge des Benutzers
clever
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

beantworten | zitieren | melden

Danke. Ich werds mal ausprobieren und dann berichten obs ging.
private Nachricht | Beiträge des Benutzers
clever
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

beantworten | zitieren | melden

Die Struktur TD1 funktioniert soweit in C#.


Nur werde ich nicht schlau, wie man die nächtsten Zeilen nach C# konvertiert.

typedef struct {
	LStrHandle sourceValue;
	LStrHandle measureValue;
	LStrHandle delayValueSec;
	LStrHandle timeValueSec;
	} TD3;

typedef struct {
	long dimSize;
	TD3 elt[1];
	} TD2;

typedef TD2 **TD2Hdl;


void __stdcall ReadMeasurement(char GPIBAddress[], TD1 *errorIn, 
	double *suppressionValue, char selectedFunction[], TD2Hdl *display, 
	TD1 *errorOut, long len);

[DllImport("Keith_236_Read_Measurement.dll", EntryPoint = "Keith236ReadMeasurement",
    ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
    public static extern int ReadMeasurement(string GPIBAddress, ref TD1 errorIn, 
	                                                 ref double suppressionValue, string selectedFunction, 
                                                     ref TD2 display, ref TD1 errorOut, int len);

[StructLayout(LayoutKind.Sequential)]
public struct TD3
{
    //public string sourceValue;


    private IntPtr sourcePtr;

    public string sourceValue
    {
        get
        {
            if (sourcePtr == IntPtr.Zero)
                return null;

            IntPtr plstr = Marshal.ReadIntPtr(sourcePtr);
            if (plstr == IntPtr.Zero)
                return null;

            int strLength = Marshal.ReadInt32(plstr);
            //IntPtr strData = new IntPtr(plstr.ToInt32() + 4);
            IntPtr strData = new IntPtr(unchecked(plstr.ToInt64() + 4));
            return Marshal.PtrToStringAnsi(strData, strLength);
        }
    }


    public string measureValue;
    public string delayValueSec;
    public string timeValueSec;
};

[StructLayout(LayoutKind.Sequential)]
public struct TD2
{
    public int dimSize;
    public TD3 elt;
};


Hab da mal reingeschaut
http://msdn.microsoft.com/de-de/library/eshywdt7.aspx]Marshallen von Klassen, Strukturen und Unions

aber konnte nicht wirklich was ableiten.


Könnt ihr mir da weiterhelfen?
private Nachricht | Beiträge des Benutzers
R3dNeXX
myCSharp.de - Member

Avatar #avatar-2926.gif


Dabei seit:
Beiträge: 44

beantworten | zitieren | melden

Ich würde dir empfehlen, mal das PInovke Signature Toolkit anzuschauen:
http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120
Trage dort einfach deine C++ struct ein und erhältst als Output die struct in C#.

Probiers mal aus.
Vielleicht hilft es dir.
private Nachricht | Beiträge des Benutzers
clever
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

beantworten | zitieren | melden

Funktinioniert nicht.

Das Tool kennt leider kein LStrHandle und andere Namen aus meinem Header file.

Beim Versuch eine Dll Datei zu laden, sagt das Tool

Could not load file or assemly ... The module was expected to contain an assembly manifest.

Die Dll Dateien habe ich aus LabView exportiert.

Vielleicht gibts eine Möglichkeit das assembly manifest nachträglich einzufügen?
private Nachricht | Beiträge des Benutzers