WPF – Cómo generar un acceso directo por código.
WPF – Cómo ejecutar un programa al iniciar Windows 11

Descripción general:

Pequeño apunte que muestra como se puede generar un acceso directo a través de código, y como se puede usar la carpeta [inicio] parea obligar a un programa a que se ejecute cuando se arranca Windows


↑↑↑

Como crear accesos directos

Para hacer un programa, he necesitado crear por código un acceso directo y después hacer que el programa se inicie cuando se inicie Windows.

Como es natural he buscado por internet como se hace y he encontrado la solución, pero en el caso de crear un acceso directo, me ha costado bastante porque el código que he encontrado era realmente viejo, y ademas, estaba hecho con funciones “viejunas” de Formularios Windows.

Como estoy trabajando con WPF, he tenido que adaptar el codigo, y al final, ha funcionado.

A modo de bibliografía

↑↑↑

Cómo ejecutar un programa al iniciar Windows 11

En esta pagina [ de genbeta ]

He encontrado una solución aceptable que consiste en guardar ( o mas bien copiar) un acceso directo que pone en programa en marcha, en la carpeta Inicio. Windows cuenta con una carpeta dentro del sistema llamada Inicio en la cual todos los programas que se almacenan pasan a iniciarse automáticamente al ejecutar Windows.

La carpeta Inicio, esta en la ruta  Este equipo> Disco Local> ProgramData> Microsoft> Windows> Menú Inicio> Programas> Inicio .

Alternativamente se puede usar la ruta directa  C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp.

A modo de bibliografía

↑↑↑

Código Visual Basic .Net


'---------------------------------------------------------- 
' Formulario WPF para estudiar como se crea un acceso directo por código 
' para probar este formulario se necesitan dos botones 
' un botón aceptar  con el x:name = "ButtonEjecutar" 
' un botón Terminar con el x:name = "ButtonTerminar" 
'---------------------------------------------------------- 

'---------------------------------------------------------------------- 
' Añadir una referencia a Windows Script Host Object Model 
' Se necesita para trabajar con [IWshShell_Class] y con [IWshShortcut_Class] 
Imports IWshRuntimeLibrary 
'---------------------------------------------------------------------- 

Class MainWindow 

    Private Sub ButtonEjecutar_Click(sender As Object, e As RoutedEventArgs) 

        Dim resultadoCreacion As System.Windows.Controls.ValidationResult 
        ' llamar a la función que crea el acceso directo 
        resultadoCreacion = CrearAccesoDirecto() 

        If resultadoCreacion.IsValid = True Then 
            ' copiar el acceso directo en la carpeta Inicio 
            ' Ahora lo copio en la carpeta de Inicio 
            resultadoCreacion = CopiarAccesoDirectoEnCarpetaInicio(resultadoCreacion.ErrorContent) 
            ' Error en la copia en al carpeta Inicio 
            If resultadoCreacion.IsValid = False Then 
                MessageBox.Show(resultadoCreacion.ErrorContent, 
                         "Copia de un [Acceso Directo] en la carpeta de [Inicio]", 
                         MessageBoxButton.OKCancel, 
                         MessageBoxImage.Error) 
            End If 
        Else 
            'Error en la creación del Acceso Directo 
            MessageBox.Show(resultadoCreacion.ErrorContent, 
                            "Creación de un [Acceso Directo]", 
                            MessageBoxButton.OKCancel, 
                            MessageBoxImage.Error) 
        End If 

    End Sub 

    Private Sub ButtonTerminar_Click(sender As Object, e As RoutedEventArgs) 
        ' Salir del programa 
        Me.Close() 
    End Sub 

    ''' <summary> 
    '''   Crea un acceso directo  del ejecutable 
    '''   en el directorio donde esta el ejecutable (exe) 
    ''' </summary> 
    ''' <returns> 
    '''   Valor [System.Windows.Controls.ValidationResult] 
    '''   Valor [System.Windows.Controls.ValidationResult] 
    '''   Todo correcto         - True  Mas el nombre completo del fichero  (Acceso directo) 
    '''   Ha habido algún error - False Mas el texto que describe el error 
    ''' </returns> 
    ''' <remarks> 
    '''   ---------------------------------------------------------------- 
    '''    Esta función esta creada para estudiar el código necesario para crear un acceso directo. 
    '''   ---------------------------------------------------------------- 
    '''   Básicamente la forma de crear los accesos directos es 
    '''   a) Crear una referencia al objeto Shell del Scripting Host: 
    '''        Set wshShell = CreateObject("WScript.Shell") 
    '''   b) Llamar al método CreateShorcut: 
    '''        Set vLnk = wshShell.CreateShortcut(sLnkPath) 
    '''   c)Asignar el path de destino 
    '''        vLnk.Targetpath = sAppPath 
    '''   d) y guardar los datos... 
    '''        vLnk.Save 
    '''   ---------------------------------------------------------------- 
    '''    Necesito conocer: 
    '''    a) El nombre completo del Ejecutable (del fichero exe) 
    '''    b) y el nombre completo del Acceso Directo (el fichero [lnk]) 
    '''    c) el nombre completo del icono asociado al programa (Opcional) 
    '''   ---------------------------------------------------------------- 
    '''    IMPORTANTE 
    '''    Hay que añadir una referencia a [Windows Script Host Object Model] 
    '''    Se necesita para trabajar con [IWshShell_Class] y con [IWshShortcut_Class] 
    '''    Imports IWshRuntimeLibrary 
    '''   ---------------------------------------------------------------- 
    '''</remarks> 
    ''' <example> 
    '''   Bibliografía 
    '''   <code> 
    '''   https://www.elguille.info/vb/ejemplos/crear_links.htm 
    '''   https://entredesarrolladores.com/973/creaci%C3%B3n-de-acceso-directo-en-vb-net 
    '''   </code> 
    ''' </example> 
    ''' <dcterms.created> 
    '''    <scheme>dcterms.ISO8601</scheme> 
    '''    <content>2023-09-20T22:28:38Z</content> 
    ''' </dcterms.created> 
    Private Function CrearAccesoDirecto() As System.Windows.Controls.ValidationResult 

        '-------------------------------------- 
        ' El valor de retorno 
        Dim resultadoCreacion As System.Windows.Controls.ValidationResult 

        '---------------------------------------------------------------- 
        ' Necesito conocer: 
        ' a) El nombre completo del Ejecutable (del fichero exe) 
        ' b) y el nombre completo del Acceso Directo (el fichero [lnk]) 
        ' c) el nombre completo del icono asociado al programa (Opcional 
        '---------------------------------------------------------------- 
        ' En este ejemplo Voy a crear un acceso directo del ejecutable [EXE] 
        ' en la carpeta donde esta el ejecutable 
        '---------------------------------------------------------------- 

        '------------------------------------- 
        'Obtener el nombre del ensamblado 
        Dim NombreCompletoDelEnsamblado As String = System.Reflection.Assembly.GetExecutingAssembly().Location ' esto obtiene la DLL 
        Dim RutaDelEnsamblado As String = System.IO.Path.GetDirectoryName(NombreCompletoDelEnsamblado) 
        Dim SoloNombreEnsambladoSinExtension = System.IO.Path.GetFileNameWithoutExtension(NombreCompletoDelEnsamblado) 

        '------------------------------------- 
        'Paso A) Nombre completo del ejecutable (El fichero exe) 
        ' (ruta + nombre + extensión) 
        Dim nombreCompletoDelEjecutable As String = System.IO.Path.Combine(RutaDelEnsamblado, SoloNombreEnsambladoSinExtension & ".exe") 

        '------------------------------------- 
        'Paso B) Nombre completo del Acceso Directo (el fichero [lnk]) 
        '(ruta + nombre + extensión) 
        Dim NombreCompletoAccesoDirecto As String = System.IO.Path.Combine(RutaDelEnsamblado, SoloNombreEnsambladoSinExtension & ".lnk") 

        '------------------------------------- 
        ' ATENCIÓN 
        ' Hay que añadir una referencia a [Windows Script Host Object Model] 
        ' Se necesita para trabajar con [IWshShell_Class] y con [IWshShortcut_Class] 
        ' Imports IWshRuntimeLibrary 
        '------------------------------------- 

        'Crear una referencia al objeto Shell: 
        Dim oShell As IWshShell_Class = Nothing 
        Dim oShortcut As IWshShortcut_Class = Nothing 

        Try 
            oShell = CreateObject("WScript.Shell") 
            oShortcut = oShell.CreateShortcut(NombreCompletoAccesoDirecto) 

            oShortcut.TargetPath = nombreCompletoDelEjecutable 
            oShortcut.WindowStyle = 1 

            ' ESTE FUNCIONA 
            oShortcut.IconLocation = "D:\NET\VS2010 ImageLibrary\Annotations_Buttons\ico_format\WinVista\New.ico" 
            ' ESTE NO 
            'oShortcut.IconLocation = "PruebasAccesoDirecto.exe, 0" 

            oShortcut.Description = String.Format("Acceso directo al programa [{0}]", SoloNombreEnsambladoSinExtension) 

            '------------------------------------------ 
            ' Antes de grabar el acceso directo 
            ' compruebo que no haya una version previa 
            ' si existe previamente se borra para evitar problemas tontos 
            If System.IO.File.Exists(NombreCompletoAccesoDirecto) = True Then 
                System.IO.File.Delete(NombreCompletoAccesoDirecto) 
            End If 

            '--------------------------- 
            ' Ahora grabo el nuevo acceso directo 
            oShortcut.Save() 

            '--------------------------- 
            ' el informe del resultado de la copia 
            resultadoCreacion = New System.Windows.Controls.ValidationResult(True, NombreCompletoAccesoDirecto) 

        Catch ex As Exception 

            '--------------------------- 
            ' el informe del resultado de la copia 
            Dim TextoMensajeError As String 
            Using sw As New System.IO.StringWriter 
                sw.WriteLine("PROBLEMA - No se puede crear el [Acceso Directo]") 
                sw.WriteLine("del programa ejecutable [EXE]") 
                sw.WriteLine("[{0}]", SoloNombreEnsambladoSinExtension) 
                sw.WriteLine("en la carpeta donde esta el programa ejecutable ") 
                sw.WriteLine("------------------------") 
                sw.WriteLine("Valores de las variables") 
                sw.WriteLine("Nombre fichero inicial [{0}]", NombreCompletoDelEnsamblado) 
                sw.WriteLine("Nombre fichero inicial [{0}]", RutaDelEnsamblado) 
                sw.WriteLine("Nombre fichero inicial [{0}]", SoloNombreEnsambladoSinExtension) 
                sw.WriteLine("Nombre fichero inicial [{0}]", nombreCompletoDelEjecutable) 
                sw.WriteLine("Nombre fichero inicial [{0}]", NombreCompletoAccesoDirecto) 
                sw.WriteLine("------------------------") 
                sw.WriteLine(ex.Message) 
                TextoMensajeError = sw.ToString 
            End Using 
            resultadoCreacion = New System.Windows.Controls.ValidationResult(False, TextoMensajeError) 

        Finally 
            ' Destruir los objetos usados 
            If oShell IsNot Nothing Then 
                oShell = Nothing 
            End If 
            If oShortcut IsNot Nothing Then 
                oShortcut = Nothing 
            End If 

        End Try 
        ' Devolver el resultado 
        Return resultadoCreacion 

    End Function 

    ''' <summary> 
    '''   Copia el acceso directo que recibe por parámetro en la carpeta inicio 
    ''' </summary> 
    ''' <param name = "paramNombreCompletoAccesoDirecto"> 
    '''       Una cadena con el nombre completo del fichero (Acceso directo) [Ruta + Nombre + Extension (.lnk)] 
    ''' </param> 
    ''' <returns> 
    '''   Valor [System.Windows.Controls.ValidationResult] 
    '''   Todo correcto         - True  Mas el nombre completo del fichero  (Acceso directo) 
    '''   Ha habido algún error - False Mas el texto que describe el error 
    ''' </returns> 
    ''' <remarks> 
    '''    Cómo ejecutar un programa al iniciar Windows 11 
    '''    Solamente hay que guardar (copiar) el acceso directo en la carpeta Inicio 
    '''    Windows cuenta con una carpeta dentro del sistema llamada Inicio en la cual todos 
    '''    los programas que se almacenan pasan a iniciarse automáticamente al ejecutar Windows. 
    '''    Para ello, lo primero es que tengas un acceso directo creado en tu 
    '''    escritorio de esa aplicación que deseas ejecutar. 
    ''' 
    '''    Seguidamente, deberás acceder a esta carpeta siguiendo la ruta 
    '''    Este equipo > Disco Local > ProgramData > Microsoft > Windows > Menú Inicio > Programas > Inicio. 
    '''    Igualmente, también puedes entrar en Ejecutar e introducir la ruta directa 
    '''    C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp. 
    ''' 
    ''' </remarks> 
    ''' <example> 
    '''   Bibliografía 
    '''   <code> 
    '''   https://www.genbeta.com/paso-a-paso/como-ejecutar-programa-al-iniciar-windows-11 
    '''   </code> 
    ''' </example> 
    ''' <dcterms.created> 
    '''    <scheme>dcterms.ISO8601</scheme> 
    '''    <content>2023-09-20T22:28:38Z</content> 
    ''' </dcterms.created> 
    Private Function CopiarAccesoDirectoEnCarpetaInicio(ByVal paramNombreCompletoAccesoDirecto As String) As System.Windows.Controls.ValidationResult 
        ' 
        '-------------------------------------- 
        ' El valor de retorno 
        Dim ResultadoDeLaCopia As System.Windows.Controls.ValidationResult 

        '--------------------------- 
        ' Generar el nombre completo del acceso directo en la carpeta Inicio 
        ' a) La ruta 
        Dim CarpetaDestino As String = Environment.GetFolderPath(Environment.SpecialFolder.Startup) ' "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp" 
        ' b) El nombre de fichero (acceso directo( 
        Dim SoloNombreMasExtensionAccesoDirecto As String = System.IO.Path.GetFileName(paramNombreCompletoAccesoDirecto) 
        'Dim SoloNombreSinExtensionAccesoDirecto As String = System.IO.Path.GetFileNameWithoutExtension(paramNombreCompletoAccesoDirecto) 
        ' c) el nombre completo acceso directo, Ruta + nombre + extension) 
        Dim NombreCompletoFicheroDestino As String = System.IO.Path.Combine(CarpetaDestino, SoloNombreMasExtensionAccesoDirecto) 

        Try 
            '--------------------------- 
            ' si existe previamente se borra para evitar problemas tontos 
            If System.IO.File.Exists(NombreCompletoFicheroDestino) = True Then 
                System.IO.File.Delete(NombreCompletoFicheroDestino) 
            End If 
            '--------------------------- 
            ' La copia 
            System.IO.File.Copy(paramNombreCompletoAccesoDirecto, NombreCompletoFicheroDestino, True) 
            '--------------------------- 
            ' el informe del resultado de la copia 
            ResultadoDeLaCopia = New System.Windows.Controls.ValidationResult(True, NombreCompletoFicheroDestino) 

        Catch ex As Exception 
            Dim TextoMensajeError As String 
            Using sw As New System.IO.StringWriter 
                sw.WriteLine("PROBLEMA - No se puede copiar el [Acceso Directo] en la carpeta Inicio") 
                sw.WriteLine("Nombre fichero inicial [{0}]", paramNombreCompletoAccesoDirecto) 
                sw.WriteLine("Nombre fichero destino [{0}]", NombreCompletoFicheroDestino) 
                sw.WriteLine(ex.Message) 
                TextoMensajeError = sw.ToString 
            End Using 

            ResultadoDeLaCopia = New System.Windows.Controls.ValidationResult(False, TextoMensajeError) 

        End Try 

        ' Devolver el resultado de la copia 
        Return ResultadoDeLaCopia 
    End Function 

End Class 


↑↑↑

Código Xaml


<Window  x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PruebasAccesoDirecto"
        mc:Ignorable="d"
        Title="Pruebas con Accesos directos " Height="150" Width="300">
    <Grid>
        <Button  x:Name="ButtonEjecutar"  Content="Ejecutar" 
                HorizontalAlignment="Left" VerticalAlignment="Top"  
                Margin="34,39,0,0" Click="ButtonEjecutar_Click"/>
        <Button  x:Name="ButtonTerminar" Content="Terminar" 
                HorizontalAlignment="Left"  VerticalAlignment="Top" 
                Margin="110,39,0,0" Click="ButtonTerminar_Click"/>

    </Grid>
</Window>