Announcement

Collapse
No announcement yet.

Webcam

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Webcam

    Hallo!

    Ich habe in VB.NET ein Programm zum Aufnehmen von Webcambildern geschrieben.
    Leider funktionert das Programm nicht in C#, wenn ich es übersetze.

    Das Problem sind ewige ladezeiten oder der Fehler, dass auf geschützten Speicher zugegriffen wird...

    VB.NET:

    Code:
    Declare Function SendMessage2 Lib "user32" Alias "SendMessageA" _
      (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Short, _
      ByRef lParam As CAPTUREPARMS) As Integer
    Und der Aufruf:

    Code:
     Dim caprams As New CAPTUREPARMS
    
            With caprams
                .AVStreamMaster = 1 'maybe 1?
                .dwAudioBufferSize = 10
                .dwIndexSize = 34952
                .dwMCIStartTime = 0
                .dwMCIStopTime = 0
                .dwRequestMicroSecPerFrame = 16667
                .fAbortLeftMouse = False
                .fAbortRightMouse = False
                .fCaptureAudio = False
                .fDisableWriteCache = False
                .fLimitEnabled = True
                .fMakeUserHitOKToCapture = False
                .fMCIControl = False
                .fStepCaptureAt2x = False
                .fStepMCIDevice = False
                .fUsingDOSMemory = False
                .fYield = True
                .vKeyAbort = Nothing
                .wChunkGranularity = 0
                .wNumAudioRequested = 10
                .wNumVideoRequested = 32
                .wPercentDropForError = 0
                .wStepCaptureAverageFrames = 0
                .wTimeLimit = 4   '# of seconds of video to caputre!!
    
            End With
    
    
    
    
            SendMessage2(lwndC, WM_CAP_SET_SEQUENCE_SETUP, Len(caprams), caprams)
            SendMessage(lwndC, WM_CAP_FILE_SET_CAPTURE_FILEA, 0, "c:\swing.avi")
            SendMessage(lwndC, WM_CAP_SEQUENCE, 0, CType(0, String))
    In C# habe ich funktioniert das nicht, egal ob ich SendMessage mit Short, long, Int oder Byte deklariere. Das Programm hängt sich auf sobald die oben angezeigte Sub Aufgerufen wird, und aufgenommen werden soll... Den Befehl "LEN(...)" gibt es ja "direkt" nicht in C#. .Length kann ich bei der Structur CAPTUREPARMS nicht verwenden. Weiß jemand Rat?

    MfG Flo
    Zuletzt editiert von Jürgen Thomas; 23.12.2009, 09:56. Reason: Zeilenumbruch macht Code lesbarer
    Die Taschenlampe!

    Die perfekte Taschenlampe für Ihr Windows Phone!

    - Die APP steuert die echte Blitz-LED an und versorgt Sie mit 100% Leistung!
    - Zudem zeigt die Live-Kachel den aktuellen Akkustand des Telefons an!


    Hier gehts zu APP!

  • #2
    nimm mal SizeOf als "Operator" der gibt dann die binäre Länge dieser Struktur auf deinem System zurück ...
    Unsere Jugend ist unerträglich, unverantwortlich und entsetzlich anzusehen! - Aristoteles

    Comment


    • #3
      Hallo,

      wie deklariere ich den in der SendMessage? Marshal.SizeOf meinst du, oder? Das wäre so ein Fall wo er sich Aufhängt...

      MfG
      Die Taschenlampe!

      Die perfekte Taschenlampe für Ihr Windows Phone!

      - Die APP steuert die echte Blitz-LED an und versorgt Sie mit 100% Leistung!
      - Zudem zeigt die Live-Kachel den aktuellen Akkustand des Telefons an!


      Hier gehts zu APP!

      Comment


      • #4
        nein statt len() SizeOf(caprams) ... nichts weiter
        Unsere Jugend ist unerträglich, unverantwortlich und entsetzlich anzusehen! - Aristoteles

        Comment


        • #5
          Hallo,

          ich habs versucht. Nun kommt keine Fehlermeldung mehr. Aber die Videodatei bleibt leer (0 Byte) WM_CAP_SEQUENCE gibt auch 0 zurück, wo aber 1 (also True) sein sollte...

          Vielleich kann mir wer helfen?

          Code:
          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          using System.Windows;
          using System.Windows.Controls;
          using System.Windows.Data;
          using System.Windows.Documents;
          using System.Windows.Input;
          using System.Windows.Media;
          using System.Windows.Media.Imaging;
          using System.Windows.Navigation;
          using System.Windows.Shapes;
          using System.Windows.Interop;
          using System.Runtime.InteropServices;
          using System.Timers;
          using Microsoft.Win32;
          using Microsoft.VisualBasic;
          
          namespace WpfApplication2
          {
              /// <summary>
              /// Interaktionslogik für Window1.xaml
              /// </summary>
              public partial class Window1 : Window
              {
                  int mCapHwnd;
                  public Timer timer1;
          
                  public const int WS_CHILD = 0x40000000;
                  public const int WS_VISIBLE = 0x10000000;
                  public const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52;
          
                  private const int WM_CAP_SEQUENCE = (WM_CAP_START + 62);
                  private const int WM_CAP_SET_SEQUENCE_SETUP = (WM_CAP_START + 64);
                  private const int WM_CAP_GET_SEQUENCE_SETUP = (WM_CAP_START + 65);
                  private const int WM_CAP_FILE_SET_CAPTURE_FILEA = (WM_CAP_START + 20); 
          
                  public const int WM_USER = 1024;
          
                  public const int WM_CAP_CONNECT = 1034;
                  public const int WM_CAP_DISCONNECT = 1035;
                  public const int WM_CAP_GET_FRAME = 1084;
                  public const int WM_CAP_COPY = 1054;
          
                  public const int WM_CAP_START = WM_USER;
          
                  public const int WM_CAP_DLG_VIDEOFORMAT = WM_CAP_START + 41;
                  public const int WM_CAP_DLG_VIDEOSOURCE = WM_CAP_START + 42;
                  public const int WM_CAP_DLG_VIDEODISPLAY = WM_CAP_START + 43;
                  public const int WM_CAP_GET_VIDEOFORMAT = WM_CAP_START + 44;
                  public const int WM_CAP_SET_VIDEOFORMAT = WM_CAP_START + 45;
                  public const int WM_CAP_DLG_VIDEOCOMPRESSION = WM_CAP_START + 46;
                  public const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
          
                  public struct CAPTUREPARMS
                  {
                      public long dwRequestMicroSecPerFrame;
                      public bool fMakeUserHitOKToCapture;
                      public int wPercentDropForError;
                      public bool fYield;
                      public long dwIndexSize;
                      public int wChunkGranularity;
                      public bool fUsingDOSMemory;
                      public int wNumVideoRequested;
                      public bool fCaptureAudio;
                      public int wNumAudioRequested;
                      public int vKeyAbort;
                      public bool fAbortLeftMouse;
                      public bool fAbortRightMouse;
                      public bool fLimitEnabled;
                      public int wTimeLimit;
                      public bool fMCIControl;
                      public bool fStepMCIDevice;
                      public long dwMCIStartTime;
                      public long dwMCIStopTime;
                      public bool fStepCaptureAt2x;
                      public int wStepCaptureAverageFrames;
                      public long dwAudioBufferSize;
                      public bool fDisableWriteCache;
                      public int AVStreamMaster;
          
                  } 
          
          
          
          
          
          
                  [DllImport("user32", EntryPoint = "SendMessage")]
                  public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
          
                  [DllImport("user32", EntryPoint = "SendMessage")]
                  public static extern int SendMessage(int hWnd, uint Msg, int wParam, long lParam);
          
                  [DllImport("user32", EntryPoint = "SendMessage")]
                  public static extern int SendMessage(int hWnd, uint Msg, int wParam, string lParam);
          
                  [DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindowA")]
                  public static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);
          
                  [DllImport("user32", EntryPoint = "OpenClipboard")]
                  public static extern int OpenClipboard(int hWnd);
          
                  [DllImport("user32", EntryPoint = "EmptyClipboard")]
                  public static extern int EmptyClipboard();
          
                  [DllImport("user32", EntryPoint = "CloseClipboard")]
                  public static extern int CloseClipboard();
                  
                  [DllImport("User32", EntryPoint="SendMessage")]
                 public static extern int SendMessage2(int hWnd, uint Msg, int wParam, CAPTUREPARMS lParam);
            
                  public Window1()
                  {
                      InitializeComponent();
                  }
          
                  private void button1_Click(object sender, RoutedEventArgs e)
                  {
                      try
                      {
                          // for safety, call stop, just in case we are already running
                          this.Stop();
          
                          // setup a capture window
          
                          HwndSource hwndSource = PresentationSource.FromVisual(ImageBox) as HwndSource;
          
                          mCapHwnd = capCreateCaptureWindowA("WebCap", WS_CHILD | WS_VISIBLE, 0, 0, 320, 160, (int)hwndSource.Handle, 0);
          
                          // connect to the capture device
                          //Application.DoEvents();
                          if (SendMessage(mCapHwnd, WM_CAP_CONNECT, 0, 0) > 0)
                          {
                              SendMessage(mCapHwnd, WM_CAP_SET_PREVIEWRATE, 25, 0);
                              SendMessage(mCapHwnd, WM_CAP_SET_PREVIEW, 1, 0);
                             
                          }
                     
                      }
          
                      catch (Exception excep)
                      {
                          MessageBox.Show("An error ocurred while starting the video capture. Check that your webcamera is connected properly and turned on.\r\n\n" + excep.Message);
                          this.Stop();
                      }
                  }
          
                  public void Stop()
                  {
                      try
                      {
                          // stop the timer
                          //bStopped = true;
                          //this.timer1.Stop();
          
                          //// disconnect from the video source
                          //Application.DoEvents();
                          SendMessage(mCapHwnd, WM_CAP_DISCONNECT, 0, 0);
                      }
          
                      catch (Exception excep)
                      { // don't raise an error here.
                      }
          
                  }
          
                  public void Record()
                  {
                      CAPTUREPARMS caprams = new CAPTUREPARMS();
          
                          caprams.AVStreamMaster = 1;
                          //maybe 1? 
                          caprams.dwAudioBufferSize = 10;
                          caprams.dwIndexSize = 34952;
                          caprams.dwMCIStartTime = 0;
                          caprams.dwRequestMicroSecPerFrame = 16667;
                          caprams.dwMCIStopTime = 0;
                          caprams.fAbortLeftMouse = false;
                          caprams.fAbortRightMouse = false;
                          caprams.fCaptureAudio = false;
                          caprams.fDisableWriteCache = false;
                          caprams.fLimitEnabled = true;
                          caprams.fMakeUserHitOKToCapture = false;
                          caprams.fMCIControl = false;
                          caprams.fStepCaptureAt2x = false;
                          caprams.fStepMCIDevice = false;
                          caprams.fUsingDOSMemory = false;
                          caprams.fYield = true;
                          //caprams.vKeyAbort = 0;
                          caprams.wChunkGranularity = 0;
                          caprams.wNumAudioRequested = 10;
                          caprams.wNumVideoRequested = 16;
                          caprams.wPercentDropForError = 0;
                          caprams.wStepCaptureAverageFrames = 0;
                          //# of seconds of video to caputre!! 
                          caprams.wTimeLimit = 4;
                      
          
                          short K = (short)Microsoft.VisualBasic.Strings.Len(caprams);
          
                      SendMessage2(mCapHwnd, WM_CAP_SET_SEQUENCE_SETUP,Marshal.SizeOf(caprams), caprams);
                      SendMessage(mCapHwnd, WM_CAP_FILE_SET_CAPTURE_FILEA, 0, "c:\\avitest.avi");
                      SendMessage(mCapHwnd, WM_CAP_SEQUENCE, (int)0, (long)0L);
                     
                  }
          
              
          
                  static byte[] StructureToByteArray(object obj)
                  {
          
                      int len = Marshal.SizeOf(obj);
          
                      byte[] arr = new byte[len];
          
                      IntPtr ptr = Marshal.AllocHGlobal(len);
          
                      Marshal.StructureToPtr(obj, ptr, true);
          
                      Marshal.Copy(ptr, arr, 0, len);
          
                      Marshal.FreeHGlobal(ptr);
          
                      return arr;
          
                  }
          
          
                  private void button2_Click(object sender, RoutedEventArgs e)
                  {
                      Record();
                  } 
          
              }
          }
          Ist übrignes in WPF, nicht WinForms.

          MfG und tausend Dank im vorraus!
          Die Taschenlampe!

          Die perfekte Taschenlampe für Ihr Windows Phone!

          - Die APP steuert die echte Blitz-LED an und versorgt Sie mit 100% Leistung!
          - Zudem zeigt die Live-Kachel den aktuellen Akkustand des Telefons an!


          Hier gehts zu APP!

          Comment


          • #6
            Hallo,

            wenns in VB.net funktioniert kann eine DLL erstellt werden und diese in C# verwendet werden. Somit erstellst du einen VB.net-Wrapper anstatt eine Übersetzung.

            mfG Gü
            "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

            Comment


            • #7
              Hallo,

              ok, kann ich auch versuchen, aber sollte das nicht so oder so in C# gehen? Ich möchte ungern eine nötlösung draus machen!

              Um an ein anderes Thema zu schweifen... Ich bin sowieso am Überlegen welche Sprache ich zukünftig wähle. VB.NET oder C#. Leider hört man nur zu oft das VB.NET irgendwann aussterben könnte. Ist dies korrekt?

              MfG
              Die Taschenlampe!

              Die perfekte Taschenlampe für Ihr Windows Phone!

              - Die APP steuert die echte Blitz-LED an und versorgt Sie mit 100% Leistung!
              - Zudem zeigt die Live-Kachel den aktuellen Akkustand des Telefons an!


              Hier gehts zu APP!

              Comment


              • #8
                Hallo,

                prinzipiell sollte die Sprache egal sein da alle .net-Sprachen in IL kompiliert werden. Mein Vorschlag ist nicht unbedingt unsauber denn die Ansteuerung der Webcam sollte so oder so als eigenständige Komponente ausgelagert werden. Da es mit VB.net funktioniert ist das Problem somit schon gelöst.

                Leider hört man nur zu oft das VB.NET irgendwann aussterben könnte. Ist dies korrekt?
                Hab ich noch nie gehört und kann ich mir auch nicht vorstellen. Dennoch empfehle ich C# zu verwenden. Auf das nennen von Gründen verzichte ich hier damit keine Diskussion C# vs. VB.net entsteht.

                mfG Gü
                "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                Comment


                • #9
                  So, ich nochmal..

                  Da mir sowas keine Ruhe lässt und es manchmal Wunder gibt hab ich es irgendwie geschafft dass ich den Code zum laufen bringe. Und da ich im ganzen Netz keinen funktionierenden Code gefunden habe, poste ich ihn hier. Sei dahingestellt ob ich nur zu doof bin, oder ob es sonst noch keiner gemacht hat...

                  Code:
                  using System;
                  using System.Collections.Generic;
                  using System.Linq;
                  using System.Text;
                  using System.Windows;
                  using System.Windows.Controls;
                  using System.Windows.Data;
                  using System.Windows.Documents;
                  using System.Windows.Input;
                  using System.Windows.Media;
                  using System.Windows.Media.Imaging;
                  using System.Windows.Navigation;
                  using System.Windows.Shapes;
                  using System.Windows.Interop;
                  using System.Runtime.InteropServices;
                  using System.Timers;
                  using Microsoft.Win32;
                  using Microsoft.VisualBasic;
                  
                  namespace WpfApplication2
                  {
                      /// <summary>
                      /// Interaktionslogik für Window1.xaml
                      /// </summary>
                      public partial class Window1 : Window
                      {
                          int mCapHwnd;
                          public Timer timer1;
                  
                          public const int WS_CHILD = 0x40000000;
                          public const int WS_VISIBLE = 0x10000000;
                          public const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52;
                  
                          private const int WM_CAP_SEQUENCE = 0x400 + 62;
                          private const int WM_CAP_SET_SEQUENCE_SETUP = (WM_CAP_START + 64);
                          private const int WM_CAP_GET_SEQUENCE_SETUP = (WM_CAP_START + 65);
                          private const int WM_CAP_FILE_SET_CAPTURE_FILEA = (WM_CAP_START + 20);
                  
                          public const short WM_USER = 0x400; 
                  
                          public const int WM_CAP_CONNECT = 1034;
                          public const int WM_CAP_DISCONNECT = 1035;
                          public const int WM_CAP_GET_FRAME = 1084;
                          public const int WM_CAP_COPY = 1054;
                  
                          public const int WM_CAP_START = WM_USER;
                  
                          public const int WM_CAP_DLG_VIDEOFORMAT = WM_CAP_START + 41;
                          public const int WM_CAP_DLG_VIDEOSOURCE = WM_CAP_START + 42;
                          public const int WM_CAP_DLG_VIDEODISPLAY = WM_CAP_START + 43;
                          public const int WM_CAP_GET_VIDEOFORMAT = WM_CAP_START + 44;
                          public const int WM_CAP_SET_VIDEOFORMAT = WM_CAP_START + 45;
                          public const int WM_CAP_DLG_VIDEOCOMPRESSION = WM_CAP_START + 46;
                          public const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
                  
                          public const int WM_CAP_SET_CALLBACK_ERROR = WM_CAP_START + 2;
                  
                          public struct CAPTUREPARMS
                          {
                              public int dwRequestMicroSecPerFrame;
                              public bool fMakeUserHitOKToCapture;
                              public int wPercentDropForError;
                              public bool fYield;
                              public int dwIndexSize;
                              public int wChunkGranularity;
                              public bool fUsingDOSMemory;
                              public int wNumVideoRequested;
                              public bool fCaptureAudio;
                              public int wNumAudioRequested;
                              public int vKeyAbort;
                              public bool fAbortLeftMouse;
                              public bool fAbortRightMouse;
                              public bool fLimitEnabled;
                              public int wTimeLimit;
                              public bool fMCIControl;
                              public bool fStepMCIDevice;
                              public int dwMCIStartTime;
                              public int dwMCIStopTime;
                              public bool fStepCaptureAt2x;
                              public int wStepCaptureAverageFrames;
                              public int dwAudioBufferSize;
                              public bool fDisableWriteCache;
                              public int AVStreamMaster;
                  
                          } 
                  
                  
                  
                  
                  
                  
                          [DllImport("user32", EntryPoint = "SendMessageA")]
                          public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
                  
                          [DllImport("user32", EntryPoint = "SendMessageA")]
                          public static extern int SendMessage(int hWnd, uint Msg, int wParam, long lParam);
                  
                          [DllImport("user32", EntryPoint = "SendMessageA")]
                          public static extern int SendMessage(int hWnd, uint Msg, int wParam, string lParam);
                  
                          [DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindowA")]
                          public static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);
                  
                          [DllImport("user32", EntryPoint = "OpenClipboard")]
                          public static extern int OpenClipboard(int hWnd);
                  
                          [DllImport("user32", EntryPoint = "EmptyClipboard")]
                          public static extern int EmptyClipboard();
                  
                          [DllImport("user32", EntryPoint = "CloseClipboard")]
                          public static extern int CloseClipboard();
                          
                          [DllImport("User32", EntryPoint="SendMessageA")]
                         public static extern int SendMessage2(int hWnd, uint Msg, int wParam,ref  CAPTUREPARMS lParam);
                    
                  
                          public Window1()
                          {
                              InitializeComponent();
                          }
                  
                          private void button1_Click(object sender, RoutedEventArgs e)
                          {
                              try
                              {
                                  // for safety, call stop, just in case we are already running
                                   // setup a capture window
                  
                                  HwndSource hwndSource = PresentationSource.FromVisual(ImageBox) as HwndSource;
                  
                                  mCapHwnd = capCreateCaptureWindowA("CamCap", WS_CHILD | WS_VISIBLE, 0, 0, 480,360, (int)hwndSource.Handle, 0);
                  
                                  // connect to the capture device
                                  //Application.DoEvents();
                                  SendMessage(mCapHwnd, WM_CAP_CONNECT, 0, 0);
                                  
                                      SendMessage(mCapHwnd, WM_CAP_SET_PREVIEWRATE, 17, 0);
                                      SendMessage(mCapHwnd, WM_CAP_SET_PREVIEW, 1, 0);
                                     
                                  
                             
                              }
                  
                              catch (Exception excep)
                              {
                                  MessageBox.Show("An error ocurred while starting the video capture. Check that your webcamera is connected properly and turned on.\r\n\n" + excep.Message);
                                  this.Stop();
                              }
                          }
                  
                          public void Stop()
                          {
                              try
                              {
                                  // stop the timer
                                  //bStopped = true;
                                  //this.timer1.Stop();
                  
                                  //// disconnect from the video source
                                  //Application.DoEvents();
                                  SendMessage(mCapHwnd, WM_CAP_DISCONNECT, 0, 0);
                              }
                  
                              catch (Exception excep)
                              { // don't raise an error here.
                              }
                  
                          }
                  
                          public void Record()
                          {
                              CAPTUREPARMS caprams = new CAPTUREPARMS();
                  
                              {
                                  caprams.AVStreamMaster = 1;
                                  //maybe 1? 
                                  caprams.dwAudioBufferSize = 10;
                                  caprams.dwIndexSize = 34952;
                                  caprams.dwMCIStartTime = 0;
                                  caprams.dwMCIStopTime = 0;
                                  caprams.dwRequestMicroSecPerFrame = 16667;
                                  caprams.fAbortLeftMouse = false;
                                  caprams.fAbortRightMouse = false;
                                  caprams.fCaptureAudio = false;
                                  caprams.fDisableWriteCache = false;
                                  caprams.fLimitEnabled = true;
                                  caprams.fMakeUserHitOKToCapture = false;
                                  caprams.fMCIControl = false;
                                  caprams.fStepCaptureAt2x = false;
                                  caprams.fStepMCIDevice = false;
                                  caprams.fUsingDOSMemory = false;
                                  caprams.fYield = true;
                                  caprams.vKeyAbort = 0;
                                  caprams.wChunkGranularity = 0;
                                  caprams.wNumAudioRequested = 10;
                                  caprams.wNumVideoRequested = 32;
                                  caprams.wPercentDropForError = 0;
                                  caprams.wStepCaptureAverageFrames = 0;
                                  //# of seconds of video to caputre!! 
                                  caprams.wTimeLimit = 4;
                              }
                  
                  
                  
                              
                  
                              SendMessage2(mCapHwnd, WM_CAP_SET_SEQUENCE_SETUP, Marshal.SizeOf(caprams),ref  caprams);
                              SendMessage(mCapHwnd, WM_CAP_FILE_SET_CAPTURE_FILEA, 0, "c:\\swing.avi");
                              SendMessage(mCapHwnd, WM_CAP_SEQUENCE, 0, Convert.ToString(0)); 
                  
                             
                          }
                  
                          private void button2_Click(object sender, RoutedEventArgs e)
                          {
                              Record();
                          } 
                  
                      }
                  }
                  So läuft er optimal.

                  Danke nochmal für euer Bemühungen!
                  Die Taschenlampe!

                  Die perfekte Taschenlampe für Ihr Windows Phone!

                  - Die APP steuert die echte Blitz-LED an und versorgt Sie mit 100% Leistung!
                  - Zudem zeigt die Live-Kachel den aktuellen Akkustand des Telefons an!


                  Hier gehts zu APP!

                  Comment


                  • #10
                    Ich würde Dir auch raten die Ansteuerung der WebCam in eine separate Assembly zu packen. Bei der ist es dann vollkommen egal ob die in VB oder C# geschrieben ist.

                    Ich persönlich ziehe C# vor, weil ich aus der C++-Ecke komme und ich mich dort beim Schreiben einfach leichter tue.

                    Aber wie Gfoidl schon schreibt: Ich denke es wird immer beides geben und beides hat seine Vor- und Nachteile

                    Comment

                    Working...
                    X