Laden...

FillChar ?

Erstellt von STF-DIR vor 16 Jahren Letzter Beitrag vor 16 Jahren 2.840 Views
S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren
FillChar ?

Hallo,

kurze Frage :

Ich hab dieses Stück Quellcode aus Delphi Zeiten und brauch das jetzt in C#. Da gibts aber FillChar nicht .


    fillchar(tf.m_szdesc,$FF,0);
    if length(szFPLCaption) <= $FE then
      copymemory(@tf.m_szdesc,@szFPLCaption[1],length(szFPLCaption)+1);

Wie muß ich das in C# machen ?

Danke
Matthias

795 Beiträge seit 2006
vor 16 Jahren

Was macht das Fillchar denn?

Auf Anhieb würde ich mal auf String.PadLeft bzw String.PadRight tippen.

Gruß, Christian.

`There are 10 types of people in the world: Those, who think they understand the binary system Those who don't even have heard about it And those who understand "Every base is base 10"`
S
8.746 Beiträge seit 2005
vor 16 Jahren

Guckst du Hilfe unter "string class", Konstruktor.

string s = new string('x',100);

Aber bevor du sagst: "Ist ja kein Füllen!". Stimmt. Man kann Strings in .NET überhaupt nicht verändern. Das nennt man "immutable".

643 Beiträge seit 2006
vor 16 Jahren

mich würde intressieren was das nützen sollte.

3.511 Beiträge seit 2005
vor 16 Jahren

Wozu brauchst du das? In Delphi benutzt man sowas eigentlich nur um Records zu "leeren" um diese an WinAPI Methoden weiterzugeben, damit man keine unerwünschten Nebeneffekte hat. Oder wie in deinem Quelltext einen bestimmten Bereich im Speicher auf einen Wert zu bringen.

In c# benötigst du diese vorgehensweise im Prinzip nicht mehr.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

ja, ist so ein Überbleibsel aus Delphi.
Da hatte ich das gebraucht um ein bestimmtest Datei Format zu erstellen.
Da gabs drei Records drin und der letzte war mit so komischen zeichen gefüllt.
Wozu der programmierer das gemacht hatte weiß ich auch nicht.
Mal sehen ob ich das brauche in C#, keine Ahnung bis jetzt bin ich erst mal am probieren und die records aus Delphi in C# umzuwandeln.
Könnte sein ich brauch da vielleicht nochmal eure hilfe.

Danke erst mal
Matthias

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Ps.: So sah das ganze in Delphi aus :


unit u_FSN;

interface

// Records für den FSN Flightplan
type _tagFlightHeader = packed record
       m_uFileSize      : LongWord;
       m_cFileSignum1   : char;         // 'F'
       m_cFileSignum2   : char;         // 'P'
       m_wVersion       : WORD;         // 105
       m_uUnusedA       : LongWord;     // 0
       m_uUnusedB       : LongWord;     // 0


       m_szDesc         : array[0..255] of char;  // Name for the plan open dialogue box


       m_uOffsCraft     : LongWord;      // 0 or byte offset to the aircraft data
       m_uCountCraft    : LongWord;      // 0 or 1
       m_uOffsWaypoint  : LongWord;      // byte offset to the first waypoint
       m_uCountWaypoint : LongWord;     // count of waypoints


       m_uOffsOldData   : LongWord;    // 0
       m_uCountOldData  : LongWord;    // 0
       m_uOffsCruise    : LongWord;    // 0
       m_uCountCruise   : LongWord;    // 0


       m_uOffsManual    : LongWord;    // 0
       m_uCountManual   : LongWord;    // 0
       m_uUnused0       : LongWord;    // 0
       m_uUnused1       : LongWord;    // 0
    end;
    _tagAircraft = packed record
        m_szName        : array[0..30] of char;
        m_uFlags        : byte;    // bit 0 and 1 = FuelMeasure type; bit 2 = NotAsh
        m_nClimbSpeed   : LongWord;
        m_nClimbFuel    : LongWord;
        m_nClimbRate    : LongWord;
        m_nCruiseSpeed  : LongWord;
        m_nCruiseFuel   : LongWord;
        m_nCruiseAlt    : LongWord;
        m_nTDownSpeed   : LongWord;
        m_nDescentFuel  : LongWord;
        m_nDescentRate  : LongWord;
      end;
     _tagWaypoint = packed record
        m_wType : word;
        m_fLat  : single;
        m_fLon  : single;
      end;
      _tagFileEnd = packed record
        dummy : array [0..41] of char;
        something: array[0..11] of char;
      end;
      _TMyRec = packed record
      tF : _tagFlightHeader;
      tA : _tagAircraft;
      tW : _tagWaypoint;
      tE : _tagFileEnd;
     end;

const
	POINTTYPE_ISEC    = $0004;
	POINTTYPE_NDB	    =	$0008;
	POINTTYPE_VOR	    =	$0010;
	POINTTYPE_ILS	    =	$0020;
	POINTTYPE_AIRPORT	=	$0040;
	POINTTYPE_RUNWAY	=	$0080;
	POINTTYPE_FIX			= $8000;

implementation

end.

Das sind die Records.
Und so wurde so ein File erzeugt :


procedure TExportForm.SaveFSN;
var
  //MyRec : _TMyRec;
  tF : _tagFlightHeader;
  tA : _tagAircraft;
  tW : array of _tagWaypoint;
  tE : _tagFileEnd;
  iWpCount : dword;      // anzahl waypoints
  sLat, sLon : single;

  myfile: file of byte;  //of _TMyRec;
  x : integer;
  szFPLName, szFPLCaption : string;
begin
  szFPLCaption := 'STF PLAN '+szStartAp+' - '+szZielAp;

  dlgSaveFsn.FileName := szStartAp+'-'+szZielAp+'.FSN';
  dlgSaveFsn.Filter := 'FS Navigator Plan|*.FSN';
  dlgSaveFsn.DefaultExt := 'FSN';
  dlgSaveFsn.Title := 'FS Navigator Flugplan speichern';
  dlgSaveFsn.InitialDir := szFsPath+'\Modules\FSNavigator\Plan';

  if dlgSaveFsn.Execute then
  begin
    szFPLName := dlgSaveFsn.FileName;
  end else
    exit;

  iWpCount := Form1.lvFplan.Items.Count-1;

  setlength(tW,iWpCount);
  AssignFile(myfile, szFPLName);
  rewrite(myfile);

    tF.m_uFileSize     := SizeOf(_tagFlightHeader) +
                          SizeOf(_tagAirCraft) +
                          (sizeof(_tagwaypoint) * iWpCount) +
                          SizeOf(_tagFileEnd);
    tF.m_cFileSignum1  := 'F';
    tF.m_cFileSignum2  := 'P';
    tF.m_wVersion      := 105;
    tF.m_uUnusedA      := 0;
    tF.m_uUnusedB      := 0;

    fillchar(tf.m_szdesc,$FF,0);
    if length(szFPLCaption) <= $FE then
      copymemory(@tf.m_szdesc,@szFPLCaption[1],length(szFPLCaption)+1);

    tF.m_uOffsCraft    := SizeOf(_tagFlightHeader); // davor ist der Header
    tF.m_uCountCraft   := 1; // ein Flugzeug ist das wohl, oder... ;)
    tF.m_uOffsWaypoint := SizeOf(_tagFlightHeader)
                          +SizeOf(_tagAircraft); // nach Header und Aircraft
    tF.m_uCountWaypoint:= iWpCount; // ebenfalls ein Wegpunkt, eigentlich natürlich richtige Anzahl

    tF.m_uOffsOldData  := 0;
    tF.m_uCountOldData := 0;
    tF.m_uOffsCruise   := 0;
    tF.m_uCountCruise  := 0;


    tF.m_uOffsManual   := 0;
    tF.m_uUnused0      := 0;
    tF.m_uUnused1      := 0;

  blockwrite(myfile, tF, sizeof(_TagFlightHeader));

    tA.m_szName        := 'Airbus A320';
    tA.m_uFlags        := 0;
    tA.m_nClimbSpeed   := 0;
    tA.m_nClimbFuel    := 0;
    tA.m_nClimbRate    := 0;
    tA.m_nCruiseSpeed  := 0;
    tA.m_nCruiseFuel   := 0;
    tA.m_nCruiseAlt    := 0;
    tA.m_nTDownSpeed   := 0;
    tA.m_nDescentFuel  := 0;
    tA.m_nDescentFuel  := 0;
    tA.m_nDescentRate  := 0;

    blockwrite(myfile, tA, sizeof(_tagAircraft));

  for x := 0 to Form1.lvFplan.Items.Count-2 do
  begin
    //Debug('Add: '+RtoS(x)+' '+lvFplan.Items[x].Caption);
    //lvdetails.Items[i].SubItems.Strings[5]
    sLat := StoR( Form1.lvFplan.Items[x].SubItems.Strings[5] );
    sLon := StoR( Form1.lvFplan.Items[x].SubItems.Strings[6] );
    tW[x].m_fLat := sLat;
    tW[x].m_fLon := sLon;
    if Form1.lvFplan.Items[x].SubItems.Strings[0] = 'V' then
      tW[x].m_wType := POINTTYPE_VOR;
    if Form1.lvFplan.Items[x].SubItems.Strings[0] = 'I' then
      tW[x].m_wType := POINTTYPE_ISEC;
    if Form1.lvFplan.Items[x].SubItems.Strings[0] = 'F' then
      tW[x].m_wType := POINTTYPE_FIX;
    if Form1.lvFplan.Items[x].SubItems.Strings[0] = 'N' then
      tW[x].m_wType := POINTTYPE_NDB;
    if Form1.lvFplan.Items[x].SubItems.Strings[0] = 'A' then
      tw[x].m_wType := POINTTYPE_AIRPORT;
    if Form1.lvFplan.Items[x].SubItems.Strings[0] = 'R' then
      tw[x].m_wType := POINTTYPE_RUNWAY;

    blockwrite(myfile, tW[x], sizeof(_tagWaypoint));
  end;


    fillchar(tE.dummy,42,0);
    tE.something := #$22#1#0#0#0#$7d#0#0#0#$7d#0#0;


  blockwrite(myfile, tE, sizeof(_tagFileEnd));

  CloseFile(myfile);

  //MessageBox(0,PChar('Flugplan gespeichert unter: '+szFPLName),'STF Accars',mb_OK);
end;

Vielleicht hilft das ja ein bischen weiter

Matthias

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hmm,

das dachte ich mir...komm wohl doch nicht so ganz alleine weiter.
Ichhab jetzt die Records in C# in structs umgewandelt. Das sollte so stimmen oder ?


    public struct tagFlightHeader  
    {  
        public static uint m_uFileSize;
        public static char m_cFileSignum1;    // 'F'  
        public static char m_cFileSignum2;    // 'P'  
        public static ushort m_wVersion;    // 105  
        public static uint m_uUnusedA;    // 0  
        public static uint m_uUnusedB;    // 0  
        
        public static unsafe fixed char m_szDesc[256];    // Name for the plan open dialogue box  

        public static uint m_uOffsCraft;    // 0 or byte offset to the aircraft data  
        public static uint m_uCountCraft;    // 0 or 1  
        public static uint m_uOffsWaypoint;  // byte offset to the first waypoint  
        public static uint m_uCountWaypoint;  // count of waypoints 

        public static uint m_uOffsOldData;    // 0  
        public static uint m_uCountOldData;  // 0  
        public static uint m_uOffsCruise;    // 0  
        public static uint m_uCountCruise;    // 0  

        public static uint m_uOffsManual;    // 0  
        public static uint m_uCountManual;    // 0  
        public static uint m_uUnused0;    // 0  
        public static uint m_uUnused1;    // 0  
    } 

    public struct tagAircraft  
    {
        public static unsafe fixed char m_szName[31];
        public static byte m_uFlags;    // bit 0 and 1 = FuelMeasure type; bit 2 = NotAsh  
        public static int m_nClimbSpeed;
        public static int m_nClimbFuel;
        public static int m_nClimbRate;
        public static int m_nCruiseSpeed;
        public static int m_nCruiseFuel;
        public static int m_nCruiseAlt;
        public static int m_nTDownSpeed;
        public static int m_nDescentFuel;
        public static int m_nDescentRate;  
    }

    public struct tagWaypoint
    {
        public static ushort m_wType;
        public static float m_fLat;
        public static float m_fLon;
    };

Jetzt müsste man mal zum testen 2 Wegpunkte nehmen und die dann als eine *.FSN Datei speichern.

Das hab ich in Delphi mit blockwrite gemacht. Ich finde aber das pandant für C# nicht ?

Was ich mit diesem fillchar mgenau machen muß weiß ich leider auch noch nicht so genau.
Ein erster Versuch mit den Wegpunkten

SULED 51.161944 12.230000

TADUV 51.429906 12.548178

brachte mir einen Fehler im FS-Navigator " falsches Dateiformat "
Hmm, sher aufschlußreich 😦

Könnt ihr mir ein bischen weiterhelfen ?

Danke Euch
Matthias

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallöchen,

also irgendwie raf ich das nicht.
Ich hab jetzt folgendes :


using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

/*
 Speicherabbild der Packed Record-Struktur von Delphi für die .NET-Welt 
 deklarieren (System.Runtime.InteropServices über using einbinden).
 Zusätzlich zu den String-Einträgen wird jeweils ein Hilfseintrag für die
 Stringlänge benötigt. Die Strings werden als char-Array abgelegt. 
\*/
 
//[StructLayout(LayoutKind.Sequential,Pack=0,CharSet=CharSet.Ansi,Size=34)]
//[StructLayout(LayoutKind.Sequential, Pack = 1)]


namespace Test_4.STF.GRAPH
{
    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 320)]
    public struct tagFlightHeader  
    {  
        public static uint m_uFileSize;
        public static char m_cFileSignum1;    // 'F'  
        public static char m_cFileSignum2;    // 'P'  
        public static ushort m_wVersion;    // 105  
        public static uint m_uUnusedA;    // 0  
        public static uint m_uUnusedB;    // 0  
        
        //public unsafe fixed char m_szDesc[256];    // Name for the plan open dialogue box
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
        public static char[] m_szDesc;

        public static uint m_uOffsCraft;    // 0 or byte offset to the aircraft data  
        public static uint m_uCountCraft;    // 0 or 1  
        public static uint m_uOffsWaypoint;  // byte offset to the first waypoint  
        public static uint m_uCountWaypoint;  // count of waypoints 

        public static uint m_uOffsOldData;    // 0  
        public static uint m_uCountOldData;  // 0  
        public static uint m_uOffsCruise;    // 0  
        public static uint m_uCountCruise;    // 0  

        public static uint m_uOffsManual;    // 0  
        public static uint m_uCountManual;    // 0  
        public static uint m_uUnused0;    // 0  
        public static uint m_uUnused1;    // 0  
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 41)]
    public struct tagAircraft  
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)]
        public static char[] m_szName;// = new char[31];
        public static byte m_uFlags;    // bit 0 and 1 = FuelMeasure type; bit 2 = NotAsh  
        public static int m_nClimbSpeed;
        public static int m_nClimbFuel;
        public static int m_nClimbRate;
        public static int m_nCruiseSpeed;
        public static int m_nCruiseFuel;
        public static int m_nCruiseAlt;
        public static int m_nTDownSpeed;
        public static int m_nDescentFuel;
        public static int m_nDescentRate;  
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 10)]
    public struct tagWaypoint
    {
        public ushort m_wType;
        public float m_fLat;
        public float m_fLon;
    }

    public class SaveFSN
    {
        private tagFlightHeader _tf;
        private tagAircraft _ta;
        private tagWaypoint _tw;

        public tagFlightHeader TagFileHeader { get { return _tf; } set { _tf = value; } }
        public tagAircraft TagAircraft { get { return _ta; } set { _ta = value; } }
        public tagWaypoint TagWaypoint { get { return _tw; } set { _tw = value; } }
    }

    public struct WAVEFORMATEX
    {
        // als test um die Größen zu vergleichen
        public UInt16 wFormatTag; //2 bytes
        public UInt16 nChannels; //2 bytes
        public UInt32 nSamplesPerSec; //4 bytes
        public UInt32 nAvgBytesPerSec; //4 bytes
        public UInt16 nBlockAlign; //2 bytes
        public UInt16 wBitsPerSample; //2 bytes
        public UInt16 cbSize; //2 bytes
    }


    public class FSN
    {
        
        const int POINTTYPE_ISEC    = 0x0004;
	    const int POINTTYPE_NDB	    = 0x0008;
	    const int POINTTYPE_VOR	    = 0x0010;
	    const int POINTTYPE_ILS	    = 0x0020;
	    const int POINTTYPE_AIRPORT	= 0x0040;
	    const int POINTTYPE_RUNWAY	= 0x0080;
	    const int POINTTYPE_FIX		= 0x8000;

   
        /*
        public void ExportToFSN_1(string FileName)
        {
            tf = new _tagFlightHeader();
            ta = new _tagAircraft();
            tw = new _tagWaypoint();
            te = new _tagFileEnd();

            tf.m_uFileSize = (uint)(Marshal.SizeOf(tf) + (uint)Marshal.SizeOf(ta) + (Marshal.SizeOf(tw) * 2) +
                                     Marshal.SizeOf(te));
            tf.m_cFileSignum1 = 'F';
            tf.m_cFileSignum2 = 'P';
            tf.m_wVersion = 105;
            tf.m_uUnusedA = 0;
            tf.m_uUnusedB = 0;

            string m_szDesc = "m_szDesc";
            tf.m_szDesc = m_szDesc.ToCharArray();

            tf.m_uOffsCraft = (uint) Marshal.SizeOf(tf);
            tf.m_uCountCraft = 1;
            tf.m_uOffsWaypoint = (uint)Marshal.SizeOf(tf) + (uint)Marshal.SizeOf(ta);
            tf.m_uCountWaypoint = 2;

            tf.m_uOffsOldData = 0;
            tf.m_uCountOldData = 0;
            tf.m_uOffsCruise = 0;
            tf.m_uCountCruise = 0;

            tf.m_uOffsManual = 0;
            tf.m_uUnused0 = 0;
            tf.m_uUnused1 = 0;

            //blockwrite

            ta.m_szName        = "Airbus A320".ToCharArray();
            ta.m_uFlags        = 0;
            ta.m_nClimbSpeed   = 0;
            ta.m_nClimbFuel    = 0;
            ta.m_nClimbRate    = 0;
            ta.m_nCruiseSpeed  = 0;
            ta.m_nCruiseFuel   = 0;
            ta.m_nCruiseAlt    = 0;
            ta.m_nTDownSpeed   = 0;
            ta.m_nDescentFuel  = 0;
            ta.m_nDescentFuel  = 0;
            ta.m_nDescentRate  = 0;

            // blockwrite

            _atw = new _tagWaypoint[2]; // 2 Wegpunkte
            
            // TADUV	51.429906	12.548178
            _atw[0].m_fLat = 51.429906f;
            _atw[0].m_fLon = 12.548178f;
            _atw[0].m_wType = POINTTYPE_ISEC;

            // SULED	51.161944	12.230000
            _atw[0].m_fLat = 51.161944f;
            _atw[0].m_fLon = 12.230000f;
            _atw[0].m_wType = POINTTYPE_ISEC;

            te.dummy = new char[42];
            te.something = "#$22#1#0#0#0#$7d#0#0#0#$7d#0#0".ToCharArray();

            SaveFSN save = new SaveFSN();
            save.tf = tf;
            save._atw = _atw;
            save.ta = ta;
            save.te = te;
            save.tw = tw;

            BinaryFormatter formatter = new BinaryFormatter();
            StreamWriter writer = new StreamWriter(@"E:\Spiele\FS2004\Modules\FSNavigator\Plan\flugplan.fsn", false);
            formatter.Serialize(writer.BaseStream, save);
            writer.Close();
        }
        */
        public void ExportToFSN_2()
        {
            int iCountWaypoints = 2;

            tagFlightHeader.m_uFileSize =
                (uint)
                (Marshal.SizeOf(typeof(tagFlightHeader)) + (uint)Marshal.SizeOf(typeof(tagAircraft)) +
                 (Marshal.SizeOf(typeof(tagWaypoint)) * iCountWaypoints));

            Console.WriteLine(Marshal.SizeOf(typeof(tagFlightHeader)));
            Console.WriteLine(Marshal.SizeOf(typeof(tagAircraft)));
            Console.WriteLine(Marshal.SizeOf(typeof(tagWaypoint)));

            Console.WriteLine("byte: {0}", Marshal.SizeOf(typeof(byte)));
            Console.WriteLine("float: {0}", Marshal.SizeOf(typeof(float)));
            Console.ReadLine();

            tagFlightHeader.m_cFileSignum1 = 'F';
            tagFlightHeader.m_cFileSignum2 = 'P';
            tagFlightHeader.m_wVersion = 105;
            tagFlightHeader.m_uUnusedA = 0;
            tagFlightHeader.m_uUnusedB = 0;

            tagFlightHeader.m_szDesc = "Hallo".ToCharArray(0, "Hallo".Length);//"TEST".ToCharArray();

            tagFlightHeader.m_uOffsCraft = (uint)Marshal.SizeOf(typeof(tagFlightHeader));
            tagFlightHeader.m_uCountCraft = 1;
            tagFlightHeader.m_uOffsWaypoint = (uint)Marshal.SizeOf(typeof(tagFlightHeader)) + (uint)Marshal.SizeOf(typeof(tagAircraft));
            tagFlightHeader.m_uCountWaypoint = (uint)iCountWaypoints;

            tagFlightHeader.m_uOffsOldData = 0;
            tagFlightHeader.m_uCountOldData = 0;
            tagFlightHeader.m_uOffsCruise = 0;
            tagFlightHeader.m_uCountCruise = 0;

            tagFlightHeader.m_uOffsManual = 0;
            tagFlightHeader.m_uUnused0 = 0;
            tagFlightHeader.m_uUnused1 = 0;

            // Aircraft
            tagAircraft.m_szName = "Airbus A320".ToCharArray();
            tagAircraft.m_uFlags = 0;
            tagAircraft.m_nClimbSpeed = 0;
            tagAircraft.m_nClimbFuel = 0;
            tagAircraft.m_nClimbRate = 0;
            tagAircraft.m_nCruiseSpeed = 0;
            tagAircraft.m_nCruiseFuel = 0;
            tagAircraft.m_nCruiseAlt = 0;
            tagAircraft.m_nTDownSpeed = 0;
            tagAircraft.m_nDescentFuel = 0;
            tagAircraft.m_nDescentFuel = 0;
            tagAircraft.m_nDescentRate = 0;

            // Waypoint
            tagWaypoint[] tw = new tagWaypoint[0];
            Array.Resize(ref tw, tw.Length + 2);

            // TADUV	51.429906	12.548178
            tw[0].m_fLat = 51.429906f;
            tw[0].m_fLon = 12.548178f;
            tw[0].m_wType = POINTTYPE_ISEC;

            // SULED	51.161944	12.230000
            tw[0].m_fLat = 51.161944f;
            tw[0].m_fLon = 12.230000f;
            tw[0].m_wType = POINTTYPE_ISEC;

            // Daten schreiben

            File.Delete(@"E:\Spiele\FS2004\Modules\FSNavigator\Plan\flugplan.fsn");
            FileStream fs = new FileStream(@"E:\Spiele\FS2004\Modules\FSNavigator\Plan\flugplan.fsn", FileMode.CreateNew);
            BinaryWriter w = new BinaryWriter(fs);

            w.Seek(0, SeekOrigin.End);
            
            // tagFlightHeader
            w.Write(tagFlightHeader.m_uFileSize);
            w.Write(tagFlightHeader.m_cFileSignum1);
            w.Write(tagFlightHeader.m_cFileSignum2);
            w.Write(tagFlightHeader.m_wVersion);
            w.Write(tagFlightHeader.m_uUnusedA);
            w.Write(tagFlightHeader.m_uUnusedB);

            w.Write(tagFlightHeader.m_szDesc);

            w.Write(tagFlightHeader.m_uOffsCraft);
            w.Write(tagFlightHeader.m_uCountCraft);
            w.Write(tagFlightHeader.m_uOffsWaypoint);

            w.Write(tagFlightHeader.m_uOffsOldData);
            w.Write(tagFlightHeader.m_uCountOldData);
            w.Write(tagFlightHeader.m_uOffsCruise);
            w.Write(tagFlightHeader.m_uCountCruise);

            w.Write(tagFlightHeader.m_uOffsManual);
            w.Write(tagFlightHeader.m_uUnused0);
            w.Write(tagFlightHeader.m_uUnused1);

            //w.Write((byte)Marshal.SizeOf(typeof(tagFlightHeader)));

            // Aircraft
            w.Write(tagAircraft.m_szName);
            w.Write(tagAircraft.m_uFlags);
            w.Write(tagAircraft.m_nClimbSpeed);
            w.Write(tagAircraft.m_nClimbFuel);
            w.Write(tagAircraft.m_nClimbRate);
            w.Write(tagAircraft.m_nCruiseSpeed);
            w.Write(tagAircraft.m_nCruiseFuel);
            w.Write(tagAircraft.m_nCruiseAlt);
            w.Write(tagAircraft.m_nTDownSpeed);
            w.Write(tagAircraft.m_nDescentFuel);
            w.Write(tagAircraft.m_nDescentFuel);
            w.Write(tagAircraft.m_nDescentRate);

            //w.Write((byte)Marshal.SizeOf(typeof(tagAircraft)));
            
            
            // Waypoints
           
            foreach (tagWaypoint wpt in tw)
            {
                w.Write(wpt.m_wType);
                w.Write(wpt.m_fLat);
                w.Write(wpt.m_fLon);
            }
            

            //w.Write((byte)Marshal.SizeOf(typeof(tagWaypoint)));

            w.Close();
            fs.Close();

        }

    }


}

Is die komplette Datei. Als Werte für die beiden Testwegpunkte stehen SULED und TADUV zur Verfügung 🙂

// SULED 51.161944 12.230000
// TADUV 51.429906 12.548178

Ich hab das ganze dann mal laufen lassen und dabei kommt diese Datei raus.

flugplan.rar. Dannhab ich mal zum Vergleich mitdiesem FS-Navigator einen Flugplan erstellt der genau so aussieht wie der eigentlich aussehen soll, also nur die beiden Punkte, die nennt sich FSN.rar

Wenn Ihr Euch mal die Datei anschaut sieht man das da was nicht stimmen kann.
Was mach ich denn da falsch ?

Ich weiß mit diesem Blockwrite nictht ob das so richtig ist ?
Das gibts in .Net c# nicht.

Bin ein bischen Ratlos.

Matthias

3.511 Beiträge seit 2005
vor 16 Jahren

Also, das BlockWrite in Delphi hat nichts weiter gemacht, den kompletten Record so wie er im Speicher steht in einem Stream zu kloppen.
An sich ist das Gegenstück in c# nur ein Stream.Write. Sprich, du solltest das ganze struct auf einem Schlag in den entsprechenden Stream schreiben. Dazu musst du das Struct in ein byte[] bekommen.

Ich hab hier eben mal was zusammengeklatscht. Denke mal, es sollte dir weiterhelfen


using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public class TestStruct
		{
			public uint TestInt;
			public char TestChar1;
			public char TestChar2;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
			public string TestString;
		}

		public Form1()
		{
			InitializeComponent();
		}

		public static byte[] RawSerialize(object anything)
		{
			int rawsize = Marshal.SizeOf(anything);
			IntPtr buffer = Marshal.AllocHGlobal(rawsize);
			Marshal.StructureToPtr(anything, buffer, false);
			byte[] rawdatas = new byte[rawsize];
			Marshal.Copy(buffer, rawdatas, 0, rawsize);
			Marshal.FreeHGlobal(buffer);
			return rawdatas;
		}

		public static object RawDeserialize(byte[] rawdatas, Type anytype)
		{
			int rawsize = Marshal.SizeOf(anytype);
			if (rawsize > rawdatas.Length)
				return null;
			IntPtr buffer = Marshal.AllocHGlobal(rawsize);
			Marshal.Copy(rawdatas, 0, buffer, rawsize);
			object retobj = Marshal.PtrToStructure(buffer, anytype);
			Marshal.FreeHGlobal(buffer);
			return retobj;
		} 

		private void button1_Click(object sender, EventArgs e)
		{
			TestStruct ts = new TestStruct();
			ts.TestChar1 = 'A';
			ts.TestChar2 = 'B';
			ts.TestInt = 1000;
			ts.TestString = "Bla Bla Hallo";

			byte[] buffer = RawSerialize(ts);

			using (FileStream fs = new FileStream(@"d:\bla.txt", FileMode.Create, FileAccess.Write))
			{
				fs.Write(buffer, 0, buffer.Length);
				fs.Flush();
				fs.Close();
			}

			TestStruct ts2 = (TestStruct)RawDeserialize(buffer, typeof(TestStruct));
			Console.WriteLine(ts2.TestString);
		}

		private void button2_Click(object sender, EventArgs e)
		{
			using (FileStream fs = new FileStream(@"d:\bla.txt", FileMode.Open, FileAccess.Read))
			{
				byte[] buffer = new byte[fs.Length];
				fs.Read(buffer, 0, buffer.Length);

				TestStruct ts2 = (TestStruct)RawDeserialize(buffer, typeof(TestStruct));
				Console.WriteLine(ts2.TestString);

				fs.Close();
			}
		}
	}
}

Auf diese Art und Weise kannst du jedes struct in ein byte[] bekommen und zurück. Wenn du jetzt eine Liste von Structs hast, musst du die halt nur immer aneinander hängen. Um später die structs wieder auszulesen, müsstest du die Länge des structs ermitteln und dann die Gesamtgröße der Datei durch die Bytegröße des Structs teilen, um zu schauen wie viel da drinnen sind.

Hoffe es hilft dir weiter. Bei Fragen fragen...

EDIT: Achja, mach die ganzen statics in deinen structs weg. Macht keinen Sinn in dem Fall.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

erst mal ganz doll vielen Dank für deine Mühe !!!
Damit könnte es klappen denke und hoffe ich. Ich hab keine Ahnung warum der sich so ein kompliziertes Format einfallen lassen hat 😦

Ich habe jetzt in den Structs die statics weggenommen, dann meckert er aber beim feststellen der größe rum, also bei


            tf.m_uFileSize = (uint)(Marshal.SizeOf(typeof(tagFlightHeader)) + 
                (uint)Marshal.SizeOf(typeof(tagAircraft)) +
                 (Marshal.SizeOf(typeof(tagWaypoint)) * iCountWaypoints));

kommt ein Fehler :

Es kann keine sinnvolle Größe oder sinnvoller Offset berechnet werden, da der Typ Test_4.STF.GRAPH.tagFlightHeader nicht als nicht verwaltete Struktur gemarshallt werden kann.

ich bin grad mal noch am schauen was ich daraus schließen muss und wie ich das wegbekomme.

Danke nochmals !!!
Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

Mal ehrlich: Das hier ist ein wundervolles Beispiel für eine schlechte Portierung.

Einfach das Fileformat direkt mit dem BinaryWriter wegzuschreiben (einzelne Felder in der richtigen Reihenfolge) würde auch nicht mehr Code erfordern, wäre deutlich weniger fehleranfällig, besser lesbar und bräuchte keine PInvoke-Berechtigung.

Wenn es denn richtig elegant OO sein soll, könnte man auch einfach ISerializable implementieren, da das Fileformat reipacken und die Daten sauber in Klassen verkapseln.

Zudem: Man könnte so auch locker mehrere Speicherformate (alt, .NET-Formatter-Binary/XML, etc.) unterstützten, indem man die Interface-Implementierungen via Komposition in die Objekte hängt.

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

also ich finde eigentlich das das ein sehr gutes beispiel einer Hilfestellung ist !
Das Fileformat in dem dieses programm das File nunmal nur lesen kann ist eben so komisch.
Das mit dem Binary Writer hab ich auch schon getestet, das funktioniert nicht weil der eben mit irgendwelchen komischen offsets arbeitet usw.

Viel wichtiger und hilfreicher wäre eine Antwort auf die Frage mit dem Marshal.SizeOf gewesen !

Aber trotzdem Danke
Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

also ich finde eigentlich das das ein sehr gutes beispiel einer Hilfestellung ist !

Ja, es hilft dir gut, einen schlechten Weg zuende zu gehen.

Das Fileformat in dem dieses programm das File nunmal nur lesen kann ist eben so komisch.

Komisch ist da eigentlich gar nix. Es nur gibt deutlich bessere und elegantere Wege zu diesem Format zu kommen.

Das mit dem Binary Writer hab ich auch schon getestet, das funktioniert nicht weil der eben mit irgendwelchen komischen offsets arbeitet usw.

Vermutlich meinst du den String-Offset. Kannst du leicht umgehen, indem du BinaryWriter.Write(char[]) benutzt anstelle von Write(string). Schon hast du keine Offsets mehr (dafür feste Länge). Ggf. musst du noch mit Null-Zeichen auffüllen, wenn der String kürzer ist, bzw. abschneiden wenn länger.

Viel wichtiger und hilfreicher wäre eine Antwort auf die Frage mit dem Marshal.SizeOf gewesen !

Kannst du haben: StructLayoutAttribute fehlt.

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

ich verstehe jetzt nicht so genau warum du so angefressen bist ?
Ich bin froh wenn ich das überhaupt hinbekomme. Fummele da jetzt schon knap ne Woche dran und hab mir auch jetzt erst erlaubt zu fragen.

Dann hab ich mich doch nur bedankt das das andere Programm ( FS-Navigator ) schon mal das File als Flugplan akzeptiert. Er sagt zwar immer das er die beiden Wegpunkte die es geben soll nicht gefunden hat und diese deswegen aus dem Flugplan nimmt, aber ich denke das bekomme ich auch noch irgendwie hin.

Und das mit dem BinaryWriter habe ich wirklich schon proibiert, aber es fängt halt jeder mal an und ich versuche das halt gerade und bin für jede Hilfe dankbar, wie auch immer die aussieht. Und wenn das nahe an Delphi rankommt bin ich auch nicht böse wenn es erst mal funktioniert, denn daraus kann ich dann schlüsse ziehen und es dann eleganter versuchen zu lösen !
Jedoch muß es dazu erst mal funktionieren und das machts eben noch nicht.

So, soweit dazu. Das
mit dem

Kannst du haben: StructLayoutAttribute fehlt.

hab ich nicht verstanden, meinst Du das hier ?


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct tagAircraft
.
.

?
Das hab ich doch aber.

Ich glaube das liegt an den char[] Arrays in den Strukturen.

Wenn ich die so stehen lasse :


        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] 
        public string m_szName;

meckert er

Es kann keine sinnvolle Größe oder sinnvoller Offset berechnet werden, da der Typ Test_4.STF.GRAPH.tagFlightHeader nicht als nicht verwaltete Struktur gemarshallt werden kann.

ich weiß nicht so recht was ich da machen muß ?

Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

Hallo,
Und wenn das nahe an Delphi rankommt bin ich auch nicht böse wenn es erst mal funktioniert, denn daraus kann ich dann schlüsse ziehen und es dann eleganter versuchen zu lösen !
Jedoch muß es dazu erst mal funktionieren und das machts eben noch nicht.

Super, wenn das klappt. Meine erfahrung ist leider, dass die Leute es entweder gleich richtig machen oder nie....

Das hab ich doch aber.

Sorry, in der ersten Version nicht. Ansonsten compiliert dein Code bei mir tadellos (char[]-Variante). Läuft auch sauber durch.

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

ja genau das ist es, der Code compilierte zwar auch durch, aber das programm erkannte das FileFormat trotzdem nicht.
Ich hab aber rausgefunden warum nicht.
Das sind packed records in Delphi , also hab ich

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]

geändert und dann hatte ich noch einen kleinen Fehler selbs produziert. Bei der angabe des Types

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]

hatte ich nicht ByValTStr, sondern ByValArray, das war ein Denkfehler von mir.

Ich habs aber jetzt, danke Euch für die entscheidenden Hinweise nochmal !!

Und jetzt kann ich mich dran machen und das versuchen etwas eleganter zu lösen und das mach ich auch !!

Ein kleines Problem hab ich noch :

Ich wandele eine Zahl aus diesen Wegpunktdateien in float um :

BSP.: OBADI 51.323889 11.272222 25000

umwandlung :


lat = (float)Convert.ToDouble(split[1].Replace(".", ","));

da kommt dann blöderweise
51,233890680352 raus.
es muß aber unbedingt genau 51.323889 rauskommen damit der Wegpunkt gefunden wird.
Mal sehen wie ich das mache

Also Danke Euch nochmals !!!

Matthias

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

ich stell alles auf double um, das wird wohl das beste sein.

Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

es muß aber unbedingt genau 51.323889 rauskommen

Das wird ein Problem, den float (single) kann nicht so viele Stellen darstellen.

Aber fast:

float lat = float.Parse( split[1], CultureInfo.InvariantCulture );

Ergibt 51.32389

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

ja, auf double umstellen geht nicht weil das Wegpunktformat für das file aus 2 float und einem ushort bestehen MUß !


    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct tagWaypoint
    {
        public ushort m_wType;
        public float m_fLat;
        public float m_fLon;
    }

Wenn ich jetzt aber einen Wegpunkt habe der Latitude
51.323889 hat und ich den in float caste also einfach (float)wegpunkt.lat;
dann kommt da ja 51.32389 raus.
Dann findet der den blöden wegpunkt nicht.
Was mach ich denn da ?

Ich hab auch schon mit float.parse rumprobiert, ging aber auch nicht, war so wie du geschrieben hattest.

Gibts da noch ne andere Lösung vioelleicht ?

Danke
Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

ging aber auch nicht, war so wie du geschrieben hattest.

Bei solch aussagekräftigen Fehlermeldungen gehe ich jetzt lieber nach Hause.

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

was menst Du den damit ?

Ich habe das so probiert wie du dauch:


float lat = float.Parse( split[1], CultureInfo.InvariantCulture ); 

und es kam halt auch nur 51.32389 und nicht 51.323889
raus.
Was für eine Fehlermeldung meinst Du denn ?
Der sucht eben nach nem wegpunkt mit der Latitude 51.232889 und bei meinem Wegpunkt steht 51.23289 und deswegen findet der den nicht .

Ich weiß nicht wie ich dem das jetzt beibringe, denn ich kann in dem struct tagWaypoint den Datentyp nicht in double ändern da sich dann die größe des structes verändert und er das dateiformat wieder nicht mehr erkennt.
Das ist das problem.
Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

und es kam halt auch nur 51.32389 und nicht 51.3238:::

Gründlich lesen bitte:

Das wird ein Problem, denn float (single) kann nicht so viele Stellen darstellen.

Und die Hilfe sagt:

By default, a Single value contains only 7 decimal digits of precision

Das meint: 7 Ziffern in der Basis. Zähle mal selbst.

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Hallo,

jap, alles klar soweit, single ( float ) hat nunmal nur 7 stellen.

Die frage ist was ich nu machen könnte ?
An dem Dateiformat ist nicht zu rütteln, hab ich gerade probiert.

ich versteh nicht so ganz warum das in Delphi ging ( sorry das ich das wieder erwähne )
Da war der Record so definiert :


     _tagWaypoint = packed record
        m_wType : word;
        m_fLat  : single;
        m_fLon  : single;
      end;

da is das doch auch ein single. Hab das eben mit dem alten proigramm ausprobiert, und da geht das komischerweise.
Ist der Datentyp in Delphi anders , mehr stellen ?

Glaub ich eigentlich nicht oder ?

Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

Nein, single entspricht in beiden Plattformen der IEEE 754-Definition für 32-Bit-Gleitkommazahlen. Schon mal drüber nachgedacht, dass du einfach die überzähligen Stellen abschneiden musst, statt eine Rundung durchführen zu lassen?

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Ja, hab ich schon , geht aber leider auch nicht.

Also nochmal, das Programm ( FS Navigator ) hat eine Datenbank in der die ganzen Wegpunkte hinterlegt sind.
Dieses Programm erstellt Flugpläne für den FS2004 und kann diese auch speichern und laden. Dies erfolgt in dem oben besprochenen und festgelegten Format.
Nun habe ich selber , oder bin noch dabei , ein Programm geschrieben was die Flugpläne erstellt.
Man sagt also ich will von NewYork nach Leipzig meinetwegen. Dann sucht mein Programm , unter beachtung diverser Vorschriften und Luftstraßen, den besten Weg von Start zu Ziel.
Soweit so gut.
Nun um diesen Flugplan anzeigen zu lassen und den Flug verfolgen zu können und nicht jeden Punkt einzeln eingeben zu müssen ( wie das bei den meisten anderen Flugplanungsprogrammen ist ) soll mein Programm eben den Flugplan in diesem Format für den FS Navigator speichern können.

Machts nun auch erst mal.

Problem ist jetzt das wenn das Programm den Flugplan lädt schaut es in seiner eigenen Datenbank nach ob es den Punkt in dem Flugplan überhaupt gibt.
Wenn nun in meinem Flugplan ( datei ) ein Punkt hinterlegt ist mit falschen Koordinaten dann meckert das Programm natürlich das es diesen Punkt nicht finden kann.

Ich habe also keinen Einfluß auf die Vorgaben und kann icht einfach sagen ok, nehmen wir eben ne stelle weniger. Das geht eben wegen den Vorgaben nicht.

Ich hoffe das ist einigermaßen Verständlich rübergekommen ?

Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

Ja, aber die von dir gewünschte Zahl ist nunmal nicht als Single darstellbar.

Was ist denn m_wType?

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Ja, das ist ja das Problem.
Warum das in Delphi ging ist mir aber echt schleierhaft. In Delphi ist ein Single auch nur 7 Stellen lang, hab ich gerade nachgelesen.

m_wType beschreibt den Wegpunkt Type.
Da gibts VOR, NDB, ISEC, FIX

Sind so definiert:


        // WaypointType for FSN
        public const int POINTTYPE_ISEC = 0x0004;
        public const int POINTTYPE_NDB = 0x0008;
        public const int POINTTYPE_VOR = 0x0010;
        public const int POINTTYPE_ILS = 0x0020;
        public const int POINTTYPE_AIRPORT = 0x0040;
        public const int POINTTYPE_RUNWAY = 0x0080;
        public const int POINTTYPE_FIX = 0x8000;

und vom Datentyp "ushort"

Das is doch blöd....

Matthias

S
8.746 Beiträge seit 2005
vor 16 Jahren

Könnte es nicht sein, dass du einfach den falschen Point-Typ benutzt?

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Nee, leider nicht.
Ich hab das explizit mit genau diesem punkt ausprobiert und das ist eine Intersection , also Pointtype.Isec 0x0004.

Leider ...

Ich bräuchte sozusagen nen Datentyp der 4 byte lang ist wegen dem struct und trotzdem 8 oder besser 9 stellen hat, denn es gibt ja auch noch punkte wie z.b.
den hier : "WHALE 21.678611 116.661667"

hmm...

Matthias

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Also fragt mich bitte nicht warum , aber :

Das geht :


                //OBADI	 51.323889	  11.272222	15
                string lat = "51.323889";
                string lon = "11.272222";

                tagWaypoint tw = new tagWaypoint();
                tw.m_fLat = (float)Convert.ToDouble(lat.Replace(".", ",")); //51.323889f;// 51.429906f;
                tw.m_fLon = (float)Convert.ToDouble(lon.Replace(".", ",")); //11.272222f;// 12.548178f;
                tw.m_wType = POINTTYPE_ISEC;
                buffer = RawSerialize(tw);
                fs.Write(buffer, 0, buffer.Length);

hab ich gerade getestet.

Würd mich aber schon interessieren warum das geht ??

Matthias

Ps.: Witzig ist ja das das hier auf der Console auch nur 51.323589 anzeigt ???
Komisch oder ?


            float f = (float)Convert.ToDouble("51.323889".Replace(".", ","));
            Console.WriteLine(f.ToString());

S
8.746 Beiträge seit 2005
vor 16 Jahren

Das ist doch genau das gleiche wie vorhin...

S
STF-DIR Themenstarter:in
368 Beiträge seit 2006
vor 16 Jahren

Deswegen hab ich ja auch geschrieben das das witzig ist und ich nicht ganz nachvollziehen kann warum das so geht ?

Matthias