Open and close the disc tray with F#

Category: visual studio fsharp

Question

Metaconta on Thu, 16 Nov 2017 18:34:13


Good:

I want to pass this code in C # console, VB .net or C ++ CLR to F #.What the code does is if you press A or the letter C opens or closes the disc reader tray.Apart from C #, it is also in C ++ CLR and VB .net in case you understand it better.What the code does is open and close the disk tray of the reader, either IDE or SATA.
Code C#
:

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Lector_teclado_consola_cs
{
    class Program
    {
        [DllImport("winmm.dll")]
        public static extern Int32 mciSendString(string lpstrCommand, StringBuilder lpstrReturnString,
        int uReturnLength, IntPtr hwndCallback);

        public static StringBuilder rt = new StringBuilder(127);

        public static void DoEvents()
        {
            // Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
            Console.SetCursorPosition(0, 6);
            Console.Write("Abriendo...");
        }

        public static void DoEvents2()
        {
            // Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
            Console.SetCursorPosition(0, 6);
            Console.Write("Cerrando...");
        }

        static void Main(string[] args)
        {
            // Título de la ventana.
            Console.Title = "Control lector de bandeja. C#";

            // Tamaño ventana consola.
            Console.WindowWidth = 29; // X. Ancho.
            Console.WindowHeight = 8; // Y. Alto.

            // Cursor invisible.
            Console.CursorVisible = false;

            // Posición del mansaje en la ventana.
            Console.SetCursorPosition(0, 0);
            Console.Write(@"Control bandeja del lector:

A - Abrir bandeja.
C - Cerrar bandeja.
===========================");



            ConsoleKey key;
            //Console.CursorVisible = false;
            do
            {
                key = Console.ReadKey(true).Key;

                string mensaje = string.Empty;

                //Asignamos la tecla presionada por el usuario
                switch (key)
                {
                    case ConsoleKey.A:
                        // mensaje = "Abriendo...";
                        Console.SetCursorPosition(0, 6);
                        DoEvents();
                        mciSendString("set CDAudio door open", rt, 127, IntPtr.Zero);
                        mensaje = "Abierto.";
                        break;

                    case ConsoleKey.C:
                        // mensaje = "Cerrando...";
                        Console.SetCursorPosition(0, 6);
                        DoEvents2();
                        mciSendString("set CDAudio door closed", rt, 127, IntPtr.Zero);
                        mensaje = "Cerrado.";
                        break;
                }

                Console.SetCursorPosition(0, 6);
                Console.Write("           ");
                Console.SetCursorPosition(0, 6);
                Console.Write(mensaje);

            }
            while (key != ConsoleKey.Escape);
        }
    }
}

Code VB .net:
Imports System.Runtime.InteropServices
Imports System.Text

Module Module1
    <DllImport("winmm.dll")>
    Public Function mciSendString(lpstrCommand As String, lpstrReturnString As StringBuilder, uReturnLength As Integer, hwndCallback As IntPtr) As Int32
    End Function

    Public rt As New StringBuilder(127)

    Public Sub DoEvents()
        ' Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
        Console.SetCursorPosition(0, 6)
        Console.Write("Abriendo...")
    End Sub

    Public Sub DoEvents2()
        ' Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
        Console.SetCursorPosition(0, 6)
        Console.Write("Cerrando...")
    End Sub

    Sub Main()
        ' Título de la ventana.
        Console.Title = "Control lector de bandeja. Visual Basic"

        ' Tamaño ventana consola.
        Console.WindowWidth = 29 ' X. Ancho.
        Console.WindowHeight = 8 ' Y. Alto.
        ' Cursor invisible.
        Console.CursorVisible = False

        ' Posición del mansaje en la ventana.
        Console.SetCursorPosition(0, 0)
        Console.Write("Control bandeja del lector:" & vbCr & vbLf & vbCr & vbLf &
                      "A - Abrir bandeja." & vbCr & vbLf &
                      "C - Cerrar bandeja." & vbCr & vbLf &
                      "===========================")

        Dim key As ConsoleKey
        'Console.CursorVisible = false;
        Do
            key = Console.ReadKey(True).Key

            Dim mensaje As String = String.Empty

            'Asignamos la tecla presionada por el usuario
            Select Case key
                Case ConsoleKey.A
                    ' mensaje = "Abriendo...";
                    Console.SetCursorPosition(0, 6)
                    DoEvents()
                    mciSendString("set CDAudio door open", rt, 127, IntPtr.Zero)
                    mensaje = "Abierto."
                    Exit Select

                Case ConsoleKey.C
                    ' mensaje = "Cerrando...";
                    Console.SetCursorPosition(0, 6)
                    DoEvents2()
                    mciSendString("set CDAudio door closed", rt, 127, IntPtr.Zero)
                    mensaje = "Cerrado."
                    Exit Select
            End Select

            Console.SetCursorPosition(0, 6)
            Console.Write("           ")
            Console.SetCursorPosition(0, 6)

            Console.Write(mensaje)
        Loop While key <> ConsoleKey.Escape
    End Sub

End Module

Code C++ CLR:
#include "stdafx.h"

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Text;

[DllImport("winmm.dll")]
extern Int32 mciSendString(String^ lpstrCommand, StringBuilder^ lpstrReturnString,
   int uReturnLength, IntPtr hwndCallback);

static void DoEvents()
{
   Console::SetCursorPosition(0, 6);
   Console::Write("Abriendo...");
}

static void DoEvents2()
{
   Console::SetCursorPosition(0, 6);
   Console::Write("Cerrando...");
}

int main(array<System::String ^> ^args)
{
   StringBuilder^ rt = gcnew StringBuilder(127);

   // Título de la ventana.
   Console::Title = "Control lector de bandeja. C++ CLR";

   // Tamaño ventana consola.
   Console::WindowWidth = 29; // X. Ancho.
   Console::WindowHeight = 8; // Y. Alto.

                       // Cursor invisible.
   Console::CursorVisible = false;

   // Posición del mansaje en la ventana.
   Console::SetCursorPosition(0, 0);
   Console::WriteLine("Control bandeja del lector : \n\n" +
      "A - Abrir bandeja. \n" +
      "C - Cerrar bandeja. \n" +
      "========================== \n");
   //Console::WriteLine("A - Abrir bandeja.");
   //Console::WriteLine("C - Cerrar bandeja.");
   //Console::Write("==========================");

   ConsoleKey key;
   //Console::CursorVisible = false;
   do
   {
      key = Console::ReadKey(true).Key;

      String^ mensaje = "";

      //Asignamos la tecla presionada por el usuario
      switch (key)
      {
      case ConsoleKey::A:
         mensaje = "Abriendo...";
         Console::SetCursorPosition(0, 6);
         DoEvents();
         mciSendString("set CDAudio door open", rt, 127, IntPtr::Zero);
         mensaje = "Abierto.";
         break;

      case ConsoleKey::C:
         mensaje = "Cerrando...";
         Console::SetCursorPosition(0, 6);
         DoEvents2();
         mciSendString("set CDAudio door closed", rt, 127, IntPtr::Zero);
         mensaje = "Cerrado.";
         break;
      }

      Console::SetCursorPosition(0, 6);
      Console::Write("           ");
      Console::SetCursorPosition(0, 6);
      Console::Write(mensaje);

   } while (key != ConsoleKey::Escape);
    return 0;
}

Of the .net I am missing F # and I finish this curiosity and retillo that I have pending since I do know.

Any daring to be able to open and close the reader tray using the F # language?

You have to have initiative to start and convinced to finish it.

Greetings to all and to all. ;)


http://electronica-pic.blogspot.com

Replies

Mr. Tines on Sat, 18 Nov 2017 17:53:22


It was simplest to do a bit of refactoring of the common code while converting, with an end result that looks like

open System
open System.Runtime.InteropServices
open System.Text;

[<DllImport("winmm.dll")>]
extern int mciSendString(string lpstrCommand, StringBuilder lpstrReturnString,
        int uReturnLength, IntPtr hwndCallback)

let rt = StringBuilder(127)

let DoEvents (transition:string) =
    Console.SetCursorPosition(0, 6)
    Console.Write transition

let action state transition (mensaje:string) = 
    Console.SetCursorPosition(0, 6);
    DoEvents transition;
    mciSendString(state, rt, 127, IntPtr.Zero) |> ignore
    Console.SetCursorPosition(0, 6)
    Console.Write("           ")
    Console.SetCursorPosition(0, 6)
    Console.Write(mensaje)

let rec loop() =
    match Console.ReadKey(true).Key with
    | ConsoleKey.Escape -> ()
    | ConsoleKey.A -> action "set CDAudio door open" "Abriendo..." "Abierto."
                      loop()
    | ConsoleKey.C -> action "set CDAudio door closed" "Cerrando..." "Cerrado."
                      loop()
    | _ -> loop()

[<EntryPoint>]
let main argv = 
    // Título de la ventana.
    Console.Title <- "Control lector de bandeja. C#"

    // Tamaño ventana consola.
    Console.WindowWidth <- 29 // X. Ancho.
    Console.WindowHeight <- 8 // Y. Alto.

    // Cursor invisible.
    Console.CursorVisible <- false

    // Posición del mansaje en la ventana.
    Console.SetCursorPosition(0, 0)
    Console.Write(@"Control bandeja del lector:

A - Abrir bandeja.
C - Cerrar bandeja.
===========================")
    loop()
    0 // return an integer exit code
The major change is that the do...while construct gets replaced by a tail-recursive loop

Metaconta on Sun, 19 Nov 2017 00:23:10


Fantastic!!!

It works the first time Thank you very much for the great help.

Good job. ;)

Mr. Tines on Sun, 19 Nov 2017 08:41:35


And we can simplify further, noting that DoEvents starts by doing a cursor reset that has just been done on the previous line.  Inline DoEvents, drop the duplicate cursor move and then factor the move-then-write operation into a helper function, and the code that actually does stuff looks like

let action state transition (mensaje:string) = let reset (text : string) = Console.SetCursorPosition(0, 6)
Console.Write text reset transition mciSendString(state, rt, 127, IntPtr.Zero) |> ignore reset " " // or replace this and the next line with just the one
reset mensaje // write + clear like `reset (mensaje + " ")`

While the tail-recursion to replace the do...while is an F# thing, all the other refactorings, the ones to remove code duplication, could be back-ported to the other languages.


Metaconta on Sun, 19 Nov 2017 12:23:08


Thank you very much.

I have completed the code.

Microsoft calls it Visual F #. I see it Console F #.

Is there the possibility of creating forms with F #?

PowerShell can create form with codes. Here it facilitates code generator for formulates with cootes and labels.

https://poshgui.com/#

Microsoft must make a GUI for PowerShell and F #. Here is a list of third parties.

http://tianit.cloudapp.net/blog/index.php/2015/11/04/crear-formularios-con-powershell/

;)

Mr. Tines on Sun, 19 Nov 2017 17:09:47


There is a tacit assumption that F# will be used mostly by specialists writing libraries and the UI will be done by regular coders doing C#.  You can write UI programs in F#, but because much of the Visual Studio designer support includes code generation, you only get use of the parts which don't include that.

This means that you can use the XAML designer for WPF, though you have to wire it up to the code yourself (there are XAML type providers which do much of the heavy lifting for you), but that WinForms all has to be done manually.  And in each case you have to manually edit the .fsproj file to make the output a WinExe rather than a plain Exe.

On the one occasion I've written UI for F#, I used GTK# and the Glade designer, though I made that choice because the TextView widget natively supported the line+column based indexing for formatting operations I wanted to use, so I didn't have to write that myself.

Metaconta on Sun, 19 Nov 2017 19:37:08


Hi:

Is there hope that Microsoft will put a GUI in the future for F # and PowerShell?

Do you know a GUI of F #?

Greetings.




Mr. Tines on Mon, 20 Nov 2017 19:50:22


 In F# you can do this out of the box

  • Create a new console application
  • Change the output type to
<OutputType>WinExe</OutputType>


  • Add references to the WPF assemblies PresentationFramework, PresentationCore, ReachFramework, WindowsBase and System.Xaml
  • Add a new XML file, renaming it to have a .xaml extension.
  • Add the following text to it
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  
</Window>

And design away.

Assuming your file is called XMLFile1.xaml, then if you make it look like this in the designer

<?xml version="1.0" encoding="utf-8" ?>
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF example">
    <StackPanel HorizontalAlignment="Left" Height="500" Margin="0,0,0,0" VerticalAlignment="Top" Width="765">
        <Label x:Name="Label" Content="0" HorizontalAlignment="Left" Height="80" Margin="76,0,0,0" Width="522"/>
        <Button x:Name="Click" Content="Click me!"/>
    </StackPanel>
</Window>

you have the UI for a simple counter application, and can drive it like

module MainApp

open System
open System.Reflection
open System.Windows
open System.Windows.Controls

let assemblyName = Assembly.GetExecutingAssembly().GetName().Name

// Create the View and bind it to the View Model
let mainWindow = Application.LoadComponent( // assembly name ... xaml name
                             new System.Uri("/"+assemblyName+";component/XMLFile1.xaml", UriKind.Relative)) :?> Window

// Application Entry point
[<STAThread>]
[<EntryPoint>]
let main(_) = 
  let click = mainWindow.FindName("Click") :?> Button
  let label = mainWindow.FindName("Label") :?> Label
  click.Click |> Event.add (fun _ -> let num = Int32.Parse(string label.Content)
                                     label.Content <- string (num + 1)
                           )
  (new Application()).Run(mainWindow)
Or use something like the Empty WPF application template from the extensions marketplace to skip the manual set-up steps.

PowerShell wouldn't play so well with WPF because of its use of resources compiled into the application assembly.  You'd have to build an assembly on the fly with the XAML in and then keep referring to that.



Metaconta on Mon, 20 Nov 2017 23:28:20


Good:

Installed but nothing new appears in F #.




Mr. Tines on Wed, 22 Nov 2017 07:44:50


Somewhat surprisingly, that extension hasn't yet been updated for VS2017.  In VS2015, it looks like this:-

meaning that there is a gap in the market here.

Metaconta on Wed, 22 Nov 2017 09:50:36


I installed it and it does not appear in Visual Studio Community 2017 version 1.4.4 or changing the FrameWork 4.5.2.

Mr. Tines on Fri, 24 Nov 2017 16:26:18


A I noted above, that extension hasn't yet been updated for VS2017; so will not install into it.

For example, when I install the extension on a machine with all of VS 2012, 2013, 2015 and 2017 installed, the choice I get is

with VS 2017 being noticeable by its absence.

It needs at least a new .vsix bundle that speaks 2017.

Or you can install it to VS2015, create an empty project as a prototype, and then keep on cloning that one.

Metaconta on Tue, 28 Nov 2017 16:17:50


If you do not have it installed in 2017, then do not expect it to be installed.