Windows Mobile 10 als Media Center

Ich hab habe einen HTPC mit Windows 10 und Kodi an meinen Hauptfernseher. Der Zweitfernseher wurde bisher von einer XBox 360 betrieben. Auf dieser hab ich nie gespielt, sonder nur Musik (Groove) und Filme geschaut (XBox Video und Netflix). Da die XBox für diese Zwecke etwas überdimensioniert ist und ein haufen Strom verbraucht, dazu die Lüfter nicht unbedingt die leisesten sind, war ich auf der Suche nach einer Alternative.

Continuum
Als Ersatz erschien mir Continuum, welches mit Windows Mobile 10 kommt, eine sehr gute Lösung. Das Display-Dock HD-500 hatte ich noch von meinen ersten Tests mit Continuum herumliegen. Alle Apps welche ich auf der XBox verwendet habe, gibt es auch für Windows Mobile und der Stromverbrauch/Geräuschpegel sollte damit auch gelöst und im letzten Fall sogar komplett abgeschafft sein.

Erste Versuche
Die ersten Versuchen waren sehr vielversprechend. Dock an den Fernseher angeschlossen und das Handy angedockt. Tastatur ran und Groove gestartet. Alles super, klappt. Auch die „Filme & TV“ App läuft wunderbar. Nur Netflix macht leider noch Probleme. Die App ist leider noch nicht Continuum fähig. Da bin ich aber zuversichtlich, dass dies noch in naher Zukunft kommt.

Steuerung
Gesteuert hab ich alles mit dem All-in-One Media Keyboard von Microsoft. Für die ersten Tests super, auf Dauer wäre eine Fernbedienung o. ä. aber wünschenswert. Also hab ich testhalber einfach mal einen IR-6 Empfänger (MCE Remote) angeschlossen, funktioniert leider nicht. Gerät wird nicht erkannt. Auch die Medien-Tasten auf der Tastatur (Play, Stop, Pause, etc.) klappen nicht. Die Einstellungs-Taste interessanterweise schon.

Ganz zufällig ist mir dann eingefallen, dass ich ja die Musik meines Lumias beim Sport bequem über mein Microsoft Band 2 steuern kann. Also schnell mal ausprobiert, und ja es klappt. Damit ist das Fernbedienungsproblem auch gelöst, den das Band hab ich ja sowieso ständig am Handgelenk.

Alternative: Miracast
Als Alternative zu Continuum gibt es natürlich noch Miracast. Damit wäre auch das Netflix Problem gelöst. Jedoch gibt es ein paar Einschränkungen und Unschönheiten, welche mit Continuum nicht existieren:

  • Der Bildschirminhalt wird gespiegelt, sprich, auf dem Lumia läuft auch das Video. Ich find es etwas nervig und störend, wenn ich im Augenwinkel ein ständiges flackern habe. Auch dass der Raum bis auf den Fernseher dunkel ist mach es in diesem Fall nicht besser: eine zweite, und dazu noch blinkende Lichtquelle.
  • Kein Arbeiten mit dem Smartphone möglich. Mal kurz E-Mails gelesen, eine Nachricht geschrieben oder im Internet etwas gesucht klappt leider nicht. Der Film würde unterbrochen werden. Bei Continuum kann ich das Smartphone ganz normal weiter verwenden und damit arbeiten.
  • USB Festplatten und Sticks. Das Dock hat drei USB Anschlüsse, an welche ich auch USB Festplatten mit Inhalten (Videos, Bilder, Musik, etc.) problemlos anschließen und verwenden kann. Nicht alltäglich, aber ab und zu ganz nützlich.

Fazit
Das ganze ist noch etwas sehr experimentell und auch noch nicht zu 100% alltagstauglich. Dennoch wird ich weiter dran bleiben und auch das Setup so weiterhin benutzten. Ich hoffe, dass Netflix in naher Zukunft Continuum fähig wird und sich dieses Problem dadurch lösen lässt.

S/MIME Reader

S/MIME Reader Outlook für Windows Mobile 10 kann ja leider noch immer keine verschlüsselten E-Mails von nicht Exchange Konten anzeigen. Daher hab ich mich des Problems angenommen und eine Reader App für genau diese Problematik erstellt.

S/MIME Reader kann die .p7m Dateianhänge von verschlüsselten E-Mails öffnen und die eigentliche E-Mail darstellen. Außerdem überprüft diese auf Wunsch auch, wenn vorhanden, die digitale Signatur. Des weiteren sind noch eine Zertifikatsverwaltung für mehrere Accounts und historische Zertifikate enthalten und die App informiert über ablaufende Zertifikate.

Die App gibt es kostenlos über den Windows Store. Weitere Infos auch auf meiner S/MIME Reader Projektseite.

Error : DEP6200 : Bootstrapping ‚Device‘ failed. Device cannot be found

Ich habe sowohl einen Fehler DEP6100 als auch DEP6200 erhalten, als ich meine Windows Universal App auf mein Windows Phone zum Debuggen veröffentlichen wollte. Treiber, SDK, etc. waren alles aktuell. Einige Leute berichten, es haben geholfen die USB-Treiber des Smartphones zu Deinstallieren und neu zu installieren. Bei mir leider nicht.

Lösung war, die Windows Phone 8.1 Tools zu installieren. Auch, wenn es eine Windows 10 App ist. Ohne diese scheint Visual Studio Probleme zu haben für ARM Geräte zu kompilieren und zu veröffentlichen.

Hier nochmal meine Fehlermeldungen:

Error : DEP6100 : The following unexpected error occurred during bootstrapping stage 'Connecting to the device 'xxx'.': SmartDeviceException - Deployment failed because no Windows Phone was detected. Make sure a phone is connected and powered on.

Error : DEP6200 : Bootstrapping 'Device' failed. Device cannot be found. Deployment failed because no Windows Phone was detected. Make sure

Prozess in den Vordergrund bringen

Die Problemstellung war, nach einem CMD Job welcher den Fokus von einem Fenster genommen hat, diesen wieder auf das Fenster zu setzten und es in den Vordergrund zu bringen. Dazu hab ich mir per C# ein kleines Konsolenprogramm geschrieben welche genau diese Aufgabe übernimmt. Die Verwendung ist ganz einfach:

pf.exe "Name des Prozesses"

Wer Interesse hat dem Programm hat, kann es sich hier direkt als ausführbare Datei herunterladen. Oder mit folgendem Quellcode selber kompilieren:

/// <summary>
/// Try to find process by name and brings the main window to front
/// </summary>
public class Program
{
    #region Constants

    /// <summary>
    /// Restore Mode
    /// </summary>
    const int SwRestore = 9;

    #endregion

    /// <summary>
    /// Try to find process and bring to front
    /// </summary>
    /// <param name="args"></param>
    public static void Main(string[] args)
    {
        // check process name is given as argument
        if (args == null || args.Length < 1)
        {
            Console.WriteLine();
            Console.WriteLine("Syntax: pf.exe Processname");
            Console.WriteLine();
            return;
        }

        // try to find process by name
        Process[] localByName = Process.GetProcessesByName(args[0]);
        // process not found
        if (localByName.Length <= 0)
        {
            Console.WriteLine("ERROR: No process found");
            return;
        }

        // get handle of first process
        var handle = localByName[0].MainWindowHandle;
            
        // check iconic status
        if (IsIconic(handle))
            // show window
            ShowWindow(handle, SwRestore);
        // bring to front
        SetForegroundWindow(handle);
    }

    /// <summary>
    /// Brings window to foreground
    /// </summary>
    /// <param name="hWnd"></param>
    /// <returns></returns>
    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    /// <summary>
    /// Shows ionic given window
    /// </summary>
    /// <param name="handle"></param>
    /// <param name="nCmdShow"></param>
    /// <returns></returns>
    [DllImport("User32.dll")]
    private static extern bool ShowWindow(IntPtr handle, int nCmdShow);

    /// <summary>
    /// Check, given window is ionic
    /// </summary>
    /// <param name="handle"></param>
    /// <returns></returns>
    [DllImport("User32.dll")]
    private static extern bool IsIconic(IntPtr handle);
}

Remote Desktop von einen High-DPI Monitor

Ich besitze einen Laptop mit einem High-DPI Monitor. Dank der DPI-Skalierung von Windows haben alle Elemente die gewünschte und gewohnte Größe und es lässt sich prima damit arbeiten. Zusätzlich ist alles deutlich schärfer und gerade Text lässt sich besser lesen.

Probleme gibt es jedoch wenn man per Remote Desktop auf einen Server zugreifen muss, welcher das ganze nicht unterstützt. Dann muss man mit der Lupe irgendwelche winzige Buttons und Texte versuchen zu entziffern, den die Auflösung wird zwar an die lokale angepasst, jedoch nicht die Skalierung.

Abhilfe schafft hier der Remote Desktop Connection Manager von Microsoft.

  • Remote Desktop Connection Manager herunterladen
  • Installieren und anschließend starten
  • File-> New
  • Der Servergruppe einen beliebigen Namen geben, z. B. „MeineServer.grp“
  • Speicherort wählen und mit Speichern bestätigen
  • Im der Linken Liste das Kontext-Menü öffnen und „Add Server“ auswählen. Sollte eine Hinweisbox erscheinen, diese mit Ja bestätigen
  • Servername und Displayname vergeben und evtl. die Logon-Credentials eintragen
  • Danach den „Remote Desktop Settings“ Tab öffnen, den Haken „Inherhit from parent“ entfernen und bei der Remote Desktop Size „Full Screen“ auswählen.
Remote Desktop Settings

Remote Desktop Connection Manager – Remote Desktop Settings

  • Mittels „Add“ den Server hinzufügen
  • Der Server sollte nun als Eintrag unter der Gruppe in der linken Spalte aufgelistet sein. Doppelklicken um eine Verbindung zum Server aufzubauen.
  • Session -> Fullscreen um in die gewohnte Remote-Desktop Ansicht zu wechseln.

CSS Puns & Css Jokes

Mal was witziges für zwischendurch: CSS Puns & Css Jokes

dynamic Parameter in MVC5 Action

Ich hatte das Problem, bei einer Action einen Parameter vom Typ „dynamic“ übergeben zu müssen, da die übergebenen Daten unterschiedlich waren. Für alle Möglichkeiten ein eigenes Model anzulegen war meiner Meinung nach zu unpraktisch. Leider hat das nicht auf anhieb funktioniert. Es wurde immer ein leeres Objekt vom Typ „object“ übergeben. Abhilfe schafft ein eigener ModelBinder:

public class DynamicModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return null;

        controllerContext.HttpContext.Request.InputStream.Position = 0;
        using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream))
        {
            // read in
            var json = reader.ReadToEnd();
            if (string.IsNullOrEmpty(json))
                return null;

            // deserialize json string to dynamic object
            return JsonConvert.DeserializeObject<dynamic>(json);
        }
    }
}

Anschließend noch im Application_Start registrieren

ModelBinders.Binders.Add(typeof(object), new DynamicModelBinder());

Und schon werden dynamic-Parameter richtig angenommen.

Eigene Fehlerseiten in MVC5

Man findet im Netz viele Fragen und auch viele Lösungen zu eigenen 404 Fehlerseiten mit MVC5. Soviel Antworten wie es gibt, soviel Fehlschläge gibt es jedoch auch. Ich hatte bisher keine Lösung gefunden die mich wirklich zufrieden gestellt hat. Entweder war sie super kompliziert und aufwendig, hat nicht alle Fälle abgedeckt oder komische URLs sind dabei herausgekommen. Eine sehr gute Hilfe für mich war der Beitrag von Ben Foster welcher mich auch zu meiner Lösung geführt hat.

Als erstes legt man einen neuen Controller mit einer Action für den 404 Fehler an. Namen können beliebig gewählt werden.

/// <summary>
/// Handles error pages
/// </summary>
public class ErrorController : Controller
{
	/// <summary>
	/// 404 - Not Found
	/// </summary>
	/// <returns></returns>
	public ActionResult NotFound()
	{
		// set status code
		Response.StatusCode = 404;
		// show view
		return View();
	}
}

Anschließend muss noch in der Web.config unter der System.webServer Sektion das Error Handling eingetragen werden.

<httpErrors errorMode="Custom" existingResponse="Replace">
	<remove statusCode="404" />
	<error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL" />
</httpErrors>

Unter Path muss der entsprechende Controller und Action Name verwendet werden.

SQL Server: Anzahl der Rows aller Tabellen

Oft benötigt man die gesamte Anzahl an Rows einer Tabelle. Wenn diese sehr Groß ist, kann ein SELECT COUNT(*) problematisch werden. Zum einen dauert dieser dann sehr lang und erzeugt auch eine gewisse Last auf dem Server. Als Alternative bietet sich hier die dynamische View „sys.dm_db_partition_stats“ des SQL Servers an, welche diese Information bereithält.

Um die Anzahl der Rows aller Tabelle anzuzeigen reicht folgendes SQL Statement:

SELECT so.name as TableName, ddps.row_count as [RowCount]
FROM sys.objects AS so
	JOIN sys.indexes AS si ON si.OBJECT_ID = so.OBJECT_ID
	JOIN sys.dm_db_partition_stats AS ddps ON si.OBJECT_ID = ddps.OBJECT_ID  AND si.index_id = ddps.index_id
WHERE si.index_id < 2  AND so.is_ms_shipped = 0
ORDER BY ddps.row_count DESC

Linktipp: X to Close

Interessanter Artikel über den Ursprung des „X“ zum schließen eines Fensters. X to Close – The origins of the use of [x] in UI design