C#

Cuterdio – 1.5.0

Das 1.4.0 Feature-Update hab ich wieder verplant hier zu erwähnen. Aber das könnt Ihr alles im Changelog nachlesen.
Auf das Update 1.5.0 bin ich besonders stolz, da endlich Carplay verfügbar ist. War ein ziemlicher Kampf… Aber eigentlich nur mit Bugs vom xCode Simulator:

  1. Es gab einen Bug der keine Verbindung zu Carplay machte
  2. Im Simulator sind einige Funktionen anders als im Auto (z.B. „Now Playing“)

Aus diesem Grund hab ich dann einige Zeit im Auto verbracht um das Feature zu programmieren 🤦‍♂️
Ich Hoffe Euch gefällt die neue Funktion!

Von |2020-06-02T07:33:49+02:002020-06-02|C#, Cuterdio, Projekte, Xamarin|

Cuterdio – 1.3.2

Vieles ist bereits passiert…
Hab das irgendwie verplant das hier zu posten.

Die 1.3 ist aber ein großer Meilenstein, denn die Beta für macOS ist fertig zum download.
Bin gespannt über eure Rückmeldungen!

Dazu hab ich das App Icon nun auf blauen Hintergrund gesetzt… Ist nicht mehr ganz so krass.

Viele Rückmeldungen gab es auch zum Icon… Entweder lieben es die Leute oder wünschen sich was anderes. Auf lange Sicht werde ich mal ne Alternative bereitstellen. Wer Lust hat kann gerne Vorschläge hier posten.

Von |2020-01-29T08:55:27+01:002020-01-29|C#, Cuterdio, Projekte|

Cuterdio – 1.0

Meine App fürs Internetradio hören Radium wird leider nicht mehr weiterentwickelt.
Aus diesem Grund bin ich auf die Suche gegangen. Folgende Vorraussetzungen hatte ich:

  • MacOS & iOS
  • Coverart
  • Band & Titel Anzeige
  • Einfaches Userinterface

Leider (oder zum Glück) gab es so eine App nicht. Darum hab ich mich entschlossen selbst eine App zu schreiben. Gesagt getan (naja so schnell ging es nicht)…
Daraus entstand Cuterdio. Der Name setzt sich zusammen aus den Wörtern „cuter Radio“ und der Tatsache dass ich die Musik von Ronnie James Dio liebe.
Bei 99designs.com hab ich mir noch ein zuckersüßes Icon erstellen lassen und die App als erstes für iOS veröffentlicht. Läuft auf iPhone & iPad.

Mac folgt als nächstes. Dann wahrscheinlich Android. Ich will auch versuchen für tvOS das ganze zu bauen. Ist aber mit Xamarin nicht so einfach.
Dazu hab ich noch ne Website gebaut: cuterdio.com.

Features:

  • Coverart
  • Album Information
  • In Spotify anzeigen
  • Große Radio Sender Datenbank mit über 25000 Einträgen
  • Keine Werbung
  • Kein Login / Registrieren

Über Feedback & Bewertungen freue ich mich sehr. Anbei ein paar Impressionen:

Von |2019-12-10T08:03:58+01:002019-12-06|C#, Cuterdio, Projekte|

Alternative zu Fuslogvw Fusion++

EPLAN Signierung & Ich… eine traurige Geschichte…
Darum bin ich des öfteren gezwungen Fuslogvw zu nutzen um mal die Bindungen und das Laden der DLLs zu betrachten. Das Tool bzw. die UI ist einfach schlimm…

Als ich nun wieder Stunden mit Fuslogvw verbracht habe, suchte ich (erneut) nach einer Alternative. Und jetzt gibt es eine: Fusion++.
Frei, OpenSource, was will man mehr!

Von |2019-09-20T11:24:01+02:002019-09-20|C#, EPLAN|

NamedPipeStream InOut Async

Ich habe gerade nen Anwendungsfall da müssen sich auf nem Rechner zwei Applikationen austauschen.
Microsoft hat dafür die Named Pipes oder die Anonymous Pipes.

Die Anonymous Pipes haben paar Nachteile, diese hab ich dann mal nicht verwendet:

  • Bidirektional nicht möglich (InOut)
  • Async nicht möglich

Stackoverflow & Google hat irgendwie nicht das passende für mich, somit hab ich mir mal ne kleine Klasse geschrieben welche mir dann den Server & Client bereitstellt. Derzeit geht das dann nur lokal und nicht mit einem Netzwerkprozess. Aber ggf. pass ich das noch an. Angewendet wird das ganze wie folgt:

var pipeServer = new PipeBidirectional(PipeType.Server);
pipeServer.PipeMessage += PipeServerOnPipeMessage;
pipeServer.Start("MyPipe";
pipeServer.ListenAsync();
pipeServer.WriteAsync("Hello from Server");

private void PipeServerOnPipeMessage(string args)
{
  // Do stuff
}

 

var pipeClient = new PipeBidirectional(PipeType.Client);
pipeClient.PipeMessage += PipeServerOnPipeMessage;
pipeClient.Start("MyPipe");
pipeClient.ListenAsync();
pipeClient.WriteAsync("Hello from Client");

private static void PipeServerOnPipeMessage(string args)
{
  // Do stuff
}

 

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;

namespace Suplanus.NamedPipes
{
  public class PipeBidirectional : IDisposable
  {
    public int MaxNumberOfServerInstances { get; set; } = 1;
    public int InBufferSize { get; set; } = 4096;
    public int OutBufferSize { get; set; } = 4096;

    public event DelegateMessage PipeMessage;

    private readonly PipeType _pipeType;
    private NamedPipeServerStream _serverPipe;
    private NamedPipeClientStream _clientPipe;
    private Process _clientProcess;
    private StreamWriter _streamWriter;
    private StreamReader _streamReader;

    public PipeBidirectional(PipeType pipeType)
    {
      _pipeType = pipeType;
    }

    public void Start(string pipeName, string clientProcessPath = null)
    {
      switch (_pipeType)
      {
        case PipeType.Server:
          _serverPipe = new NamedPipeServerStream(pipeName, PipeDirection.InOut,
                                                  MaxNumberOfServerInstances,
                                                  PipeTransmissionMode.Message, PipeOptions.Asynchronous, InBufferSize,
                                                  OutBufferSize);

          // Start client process
          if (!string.IsNullOrEmpty(clientProcessPath))
          {
            _clientProcess = Process.GetProcesses()
                                    .FirstOrDefault(obj => clientProcessPath.Contains(obj.ProcessName) &&
                                                           obj.MainModule != null &&
                                                           obj.MainModule.FileName.Equals(clientProcessPath));
            if (_clientProcess == null)
            {
              _clientProcess = Process.Start(new ProcessStartInfo
              {
                CreateNoWindow = true,
                FileName = clientProcessPath,
                UseShellExecute = false,
              });
            }
          }
      
          // Start server
          _serverPipe.WaitForConnection();
          _streamWriter = new StreamWriter(_serverPipe);
          _streamWriter.AutoFlush = true;
          _streamReader = new StreamReader(_serverPipe);
          break;

        // Start client
        case PipeType.Client:
          _clientPipe = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut,
                                                  PipeOptions.Asynchronous);
          _clientPipe.Connect();
          _streamWriter = new StreamWriter(_clientPipe);
          _streamWriter.AutoFlush = true;
          _streamReader = new StreamReader(_clientPipe);
          break;
      }
    }

    public async void ListenAsync()
    {
      do
      {
        if (_streamReader != null)
        {
          string line = await _streamReader.ReadLineAsync();
          if (!string.IsNullOrEmpty(line))
          {
            PipeMessage?.Invoke(line);
          }
        }
      }
      while (true);

      // ReSharper disable once FunctionNeverReturns
    }

    public async void WriteAsync(string message)
    {
      await _streamWriter.WriteLineAsync(message);
    }

    public void Dispose()
    {
      _streamWriter?.Dispose();
      _streamReader?.Dispose();

      if (_serverPipe != null && _serverPipe.IsConnected)
      {
        _serverPipe?.Disconnect();  
      }
      
      _serverPipe?.Dispose();
      _clientPipe?.Dispose();
      _clientProcess?.Kill();
      _clientProcess?.Dispose();
    }
  }

  public delegate void DelegateMessage(string args);
}

Ich hab das hier mal als Gist gespeichert. Paar Sachen sind noch nicht so schön, wie z.B. dass der optionale Process einfach so gekillt wird. Hier könnte man diese per Message einfach schön runterfahren. In meinem Fall ist das aber so OK 🦄

Von |2019-08-28T08:11:19+02:002019-08-28|C#|