Laden...
A
AmpelB
myCSharp.de - Member
24
Themen
68
Beiträge
Letzte Aktivität
vor 2 Monaten
Dabei seit
02.04.2021
Erstellt vor 2 Monaten

Der Gegenpunkt ist ja ein USB Client Gerät, welches vom USB Stack des Windows PCs verwaltet wird. Mein Gerät meldet sich ja mit entsprechenden USB Dsscreptoren an. USB ist ja prinzipiell Full Duplex. Ich finde in den Descriptoren auch keine Einstellung, ob der Windows PC in seiner File-Interface-Implementierung gleichzeitiges Lesen/Schreiben unterstützen soll oder nicht.

Auf dem Gerät habe ich auch keine Probleme. Dort sind Senden und Empfangen quasi unabhängig. Wenn ich was schicke, muss ich halt nur auf die Benachrichtigung warten, dass es übertragen wurde, bevor ich was neues über diesen Endpunkt schicken kann.

Erstellt vor 2 Monaten

Ich benutze ja die CreateFileW Funktion. Auch wenn ich dort Read und Write Sharing angebe, funktioniert es nicht

                PortFileHandle = CreateFileW(idDescriptor.DevicePath, EFileAccess.Read | EFileAccess.Write, 
                                          EFileShare.Read | EFileShare.Write,
                                          IntPtr.Zero,   //Keine Security Attribute
                                          ECreationDisposition.OpenExisting,
                                          EFileAttributes.Device,
                                          IntPtr.Zero);  //keine Template Datei

In meinem Empfangsthread bin ich in

                    if (ReadFile(PortFileHandle!, RxBufferHandle.AddrOfPinnedObject(), ReportSize+1, out nByteRead, 0) == false)

und beim Senden hängt er dann im

                if (WriteFile(PortFileHandle, TxBufferHandle.AddrOfPinnedObject(), nBytes, out nByteWritten, 0) == false)

Es scheint für mich einfacher, meine Anwendung so umzustricken, dass mein Gerät immer exakt eine Antwort schickt, nachdem es eine Anfrage bekommen hat. Dann muss ich halt zwischen den normalen Kommandos ein "Hast du was für mich" Kommando schicken. Dann kann ich blockierend warten. Das noch mit einem Timer absichern, der beim Zuschlagen den Port schließt (dann komme ich ja hoffentlich aus ReadFile zurück, obwohl ich mir da im Moment nicht sicher bin).

Ich weiß aber nicht, was du mit "Flags selbst interpretieren" meinst.

Erstellt vor 2 Monaten

Ich steuere ein HID Gerät über die Windows ReadFile und WriteFile Funktionen

        [LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
       [return: MarshalAs(UnmanagedType.Bool)]
       private static partial bool ReadFile(IntPtr hFile, IntPtr lpBuffer, int nNumberOfBytesToRead,
           out int lpNumberOfBytesRead, int lpOverlapped);
       [LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
       [return: MarshalAs(UnmanagedType.Bool)]
       private static partial bool WriteFile(IntPtr hFile, IntPtr lpBuffer, int nNumberOfBytesToWrite,
           out int lpNumberOfBytesWritten, int lpOverlapped);

Den "Dateinamen" habe ich erfragt und das funktioniert an und für sich ganz gut.

Mit den Hid Funktionen habe ich Probleme.

        [LibraryImport("hid.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
       [return: MarshalAs(UnmanagedType.Bool)]
       protected static partial bool HidD_SetOutputReport(IntPtr DeviceHandle, IntPtr ReportBuffer, int ReportBufferLength);
       [LibraryImport("hid.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
       [return: MarshalAs(UnmanagedType.Bool)]
       protected static partial bool HidD_GetInputReport(IntPtr DeviceHandle, IntPtr ReportBuffer, int ReportBufferLength);

Also doch Read/Write.

Nun ist ReadFile aber ein blockierender Aufruf. Solange ich immer ordentlich was zum Gerät schicke und dann auf die Antwort warte, geht das auch gut. Nun möchte ich aber gerne permanent in einem Thread auf Daten vom Gerät warten. Da ich das Gerät auch selber programmiere, kann ich dort "einfach mal" Notifikationen schicken.

Wenn ich nun aber in meinem Empfangsthread in der ReadFile Funktion stecke, funktioniert WriteFile (aus dem Main Thread) nicht. Geht das überhaupt? Oder muss man da mit overlapped arbeiten? Dann komme ich ja direkt aus der ReadFile Funktion zurück. Ich bin mir aber nicht sicher, ob da nicht "intern" doch irgend etwas blockiert.

Hat da jemand einen Tip?

Erstellt vor 7 Monaten

Unter Anderem für eine Unterstützung von mehreren Sprachen habe ich folgendes implementiert:

  • Ein Interface, mit dem ich einen Text setzen kann
  • Mehrere Klassen, für die ich dann SetText aufrufen kann und die dann die Text Eigenschaft gemäß einem übergebenen Array setzen.

Nun muss ich aber für ganz viele GUI Klassen eine eigene Klasse implementieren, die praktisch alle gleich aussehen

    public interface ILanguageText
    {
        void SetText();
    }
    public class LanguageLabel(Label label, string[] texts) : ILanguageText
    {
        readonly Label label = label;
        readonly string[] texts = texts;

        public void SetText()
        {
            label.Text = texts[Language.Actual] + ExtraText;
        }
    }
    public class LanguageGroupBox(GroupBox groupBox, string[] texts) : ILanguageText
    {
        readonly GroupBox groupBox = groupBox;
        readonly string[] texts = texts;

        public void SetText()
        {
            groupBox.Text = texts[Language.Actual];
        }
    }
    public class LanguageMenuItem(ToolStripMenuItem menuItem, string[] texts) : ILanguageText
    {
        readonly ToolStripMenuItem menuItem = menuItem;
        readonly string[] texts = texts;

        public void SetText()
        {
            menuItem.Text = texts[Language.Actual];
        }
    }

Kann man so etwas nicht auch mit einem Template machen? Nach meinem aktuellen Wissen geht das nicht, da die Text Eigenschaft der einzelnen Klassen ja nicht in einem gemeinsamen Interface oder einer gemeinsamen Basisklasse definiert ist.

Prinzipiell könnte das so aussehen. Aber t.Text geht ja nicht

    public class LanguageItem<T>(T t, string[] texts) : ILanguageText
   {
       readonly T t = t;
       readonly string[] texts = texts;
       public void SetText()
       {
           t.Text = texts[Language.Actual];
       }
   }

Geht das vielleicht doch?

Erstellt vor 7 Monaten

Vielleicht dann noch mal eine Verständnisfrage:

Ich habe zuerst ja als Interface IEnumerable<IClass> angegeben. Visual Studio hat mir das meine ich so vorgeschlagen. Dann brauchte ich aber zwei Funktionen in meiner Implementierung

 public IEnumerator<IClass> GetEnumerator() {...}
 public IEnumerator GetEnumerator() {...}

Beide Funktionen hatten dann auch die gleiche Implementierung.

Ich habe es nun mal auf

public interface ISubClass : IEnumerable

geändert. Dann benötige ich auch nur noch die eine GetEnumerator Funktion.

Es funktioniert beides.

Kann es sein, dass eine "Vererbung" von IEnumberable<IClass> dann auch nur ein foreach für IClass zulässt? Ohne die Einschränkungen könnte ich aber auch noch über andere Typen enumerieren?

Da ich aber nur eine Liste in meiner Klasse habe, ist das ja ganz egal. Mit der Spezialisierung auf <IClass> musste ich ja auch noch eine "allgemeine Enumerator Funktion" (also IEnumerator GetEnumerator). Somit bringt es mir keine Vorteile, direkt das <IClass> anzugeben. Richtig?

Wenn ich allerdings in eine "Hyperklasse" zwei Listen mit unterschiedlichen Typen hätte, könnte ich IEnumerable<Typ1> und IEnumerable<Typ2> bei meiner Klasse als zu implementierende Interface angeben. Dann benötige ich zwei entsprechende GetEnumerator Funktionen, die verschiedene Enumeratoren zurückgeben würden. Somit könnte ich dann vom gleichen Objekt unterschiedlichen foreach mit unterschiedlichen Typen machen. Ein foreach (var x in objekt) dürfte dann aber nicht mehr funktionieren.

Erstellt vor 7 Monaten

Das ist ja noch besser.

Generell macht das sogar Sinn. Gut zu wissen.

Erstellt vor 7 Monaten

Danke.

Da hätte ich auch selber drauf kommen können.

Erstellt vor 7 Monaten

Hallo,

ich habe ein wirkliches Basisproblem. Ich habe gerade meinen ersten eigenen Enumerator implementiert. Das mache ich, damit ich foreach von meiner Klasse benutzten kann.

Es ist eine klassisches Item/SubItem Implementierung

    public interface IClass
    {
        public interface ISubClass : IEnumerable<IClass>
        {
            int Count { get; }
            IClass this[int index] { get; }
            void Add(string name);
            void remove(string name);
            void Clear();
        }
    }

	internal class MyClass : IClass
	{
		public class SubClassImpl : IClass.ISubClass
		{
   			public readonly List<MyClass> Items = []

           public IEnumerator<IClass> GetEnumerator()
           {
               return new MyClassEnumerator(Items);
           }

           IEnumerator IEnumerable.GetEnumerator()
           {
              return new MyClassEnumerator(Items);
           }
     }

        class MyClassEnumerator(List<MyClass> items) : IEnumerator<IClass>
        {
            readonly List<Class> items = items;
            int position = -1;

            public IClass Current => items[position];

            object IEnumerator.Current => items[position];

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (position >= items.Count) return false;
                position++;
                return true;
            }

            public void Reset()
            {
                position = -1;
            }
        }

Wenn ich aber nun eine leere Liste habe, bekomme ich in der forEach Schleife eine Excpetion, da im enumerator auf Index -1 (der Positions Wert) zugegriffen wird.

Bei diesem Code

            string[] x = [];
            string s = "";
            foreach (string xs in x)
                s += xs;

bekomme ich aber keine Exception.

Wenn ich das richtig verstehe, was ich so gelesen habe, muss man hier mit einem Empty Enumerator arbeiten. Das Verstehe ich aber nicht richtig.

Wie muss ich meine enumeratoren verändern, damit ein foreach bei einer leeren Liste auch funktioniert?

Erstellt vor 8 Monaten

Ich sehe gerade, bei dir sind die Bilder als byte[] drin. Wie hast du das denn gemacht?

Erstellt vor 8 Monaten

Ich kann auch einen Typ auswählen. Aber nur Image, kein Bitmap.

Unter Speichern als habe ich auch noch zwei Möglichkeiten. Beide funktionieren aber nicht.

Wenn ich nun ein png hinzufüge (wie im Bild), kommt keine Fehlermeldung aber die png Datei taucht nicht in meiner Liste der Resourcen auf.