Implementación de Registro de Software en WinForms: Solucionando Problemas de Acceso al Registro y Cierre Automático de Formularios

  1. Creación de la clase SoftRegister
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

/*
 * Se requiere agregar la referencia System.Management
 */
namespace ImplementacionRegistroSoftware
{
    /// <summary>
    /// Clase para manejar el registro del software
    /// </summary>
    class GestorRegistro
    {

        #region Paso 1: Obtener etiqueta de volumen y CPU para generar código máquina
        
        ///<summary>
        /// Obtiene el número de serie del volumen del disco
        ///</summary>
        ///<returns></returns>
        public string ObtenerNumeroSerieDisco()
        {
            ManagementClass mc = new ManagementClass("win32_NetworkAdapterConfiguration");
            ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"c:\"");
            disk.Get();
            return disk.GetPropertyValue("VolumeSerialNumber").ToString();
        }

        ///<summary>
        /// Obtiene el número de serie de la CPU
        ///</summary>
        ///<returns></returns>
        public string ObtenerNumeroCPU()
        {
            string strCpu = null;
            ManagementClass miCpu = new ManagementClass("win32_Processor");
            ManagementObjectCollection coleccionCpu = miCpu.GetInstances();
            foreach (ManagementObject objeto in coleccionCpu)
            {
                strCpu = objeto.Properties["Processorid"].Value.ToString();
            }
            return strCpu;
        }

        ///<summary>
        /// Genera código máquina (combina CPU y disco)
        ///</summary>
        ///<returns></returns>
        public string ObtenerCodigoMaquina()
        {
            string strNum = ObtenerNumeroCPU() + ObtenerNumeroSerieDisco();
            string strCodigoMaquina = strNum.Substring(0, 24); // Tomar primeros 24 caracteres
            return strCodigoMaquina;
        }

        public int[] clavesNumericas = new int[127]; // Almacena claves de cifrado
        public char[] caracteresASCII = new char[25]; // Almacena caracteres ASCII
        public int[] valoresASCII = new int[25]; // Almacena valores ASCII

        /// <summary>
        /// Inicializa las claves de cifrado
        /// </summary>
        public void InicializarClavesNumericas()
        {
            for (int i = 1; i < clavesNumericas.Length; i++)
            {
                clavesNumericas[i] = i % 9; // Secuencia: 0,1,2,3,4,5,6,7,8,0,1,2,3...
            }
        }

        #endregion

        #region Paso 2: Generar código de registro basado en el código máquina

        ///<summary>
        /// Genera código de registro a partir del código máquina
        ///</summary>
        ///<returns></returns>
        public string GenerarCodigoRegistro()
        {
            InicializarClavesNumericas();
            string strCodigoMaquina = ObtenerCodigoMaquina();
            for (int i = 1; i < caracteresASCII.Length; i++) // Almacenar código máquina
            {
                caracteresASCII[i] = Convert.ToChar(strCodigoMaquina.Substring(i - 1, 1));
            }
            for (int j = 1; j < valoresASCII.Length; j++) // Modificar valores ASCII
            {
                valoresASCII[j] = Convert.ToInt32(caracteresASCII[j]) + clavesNumericas[Convert.ToInt32(caracteresASCII[j])];
            }
            string strNombreAscii = ""; // Código de registro
            for (int k = 1; k < valoresASCII.Length; k++) // Generar código de registro
            {
                if ((valoresASCII[k] >= 48 && valoresASCII[k] <= 57) || 
                    (valoresASCII[k] >= 65 && valoresASCII[k] <= 90) || 
                    (valoresASCII[k] >= 97 && valoresASCII[k] <= 122)) // Rango: 0-9, A-Z, a-z
                {
                    strNombreAscii += Convert.ToChar(valoresASCII[k]).ToString();
                }
                else if (valoresASCII[k] > 122) // Mayor que 'z'
                {
                    strNombreAscii += Convert.ToChar(valoresASCII[k] - 10).ToString();
                }
                else
                {
                    strNombreAscii += Convert.ToChar(valoresASCII[k] - 9).ToString();
                }
            }
            return strNombreAscii;
        }

        #endregion

    }
}

  1. Agregar evento Load en el formulario principal
        private void MainForm_Load(object sender, EventArgs e)
        {
            #region Verificación de registro del software
            GestorRegistro gestorReg = new GestorRegistro();

            // Verificar si el software está registrado
            RegistryKey llaveRegistro = Registry.CurrentUser.OpenSubKey("SOFTWARE", true)
                .CreateSubKey("miSoftware").CreateSubKey("Configuracion");
            
            // Recorrer todos los subelementos
            foreach (string strCodigoRegistro in llaveRegistro.GetSubKeyNames())
            {
                if (strCodigoRegistro == gestorReg.GenerarCodigoRegistro()) // Comparar con código generado
                {
                    this.lblEstadoRegistro.Text = "Software registrado!";
                    this.btnRegistrar.Enabled = false;
                    return;
                }
            }
            
            this.Text = "Software no registrado!";
            this.btnRegistrar.Enabled = true;
            MessageBox.Show("Está usando la versión de prueba. Puede usarla gratuitamente 30 veces!", 
                "Información", MessageBoxButtons.OK, MessageBoxIcon.Information);
            
            Int32 contadorUso; // Contador de usos
            try
            {
                // Obtener valor del registro o usar valor por defecto
                contadorUso = (Int32)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\miSoftware", 
                    "ContadorUso", 0);
                MessageBox.Show("Ha usado el software " + contadorUso + " veces!", 
                    "Información", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch
            {
                MessageBox.Show("Bienvenido al software!", "Información", 
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\miSoftware", 
                    "ContadorUso", 0, RegistryValueKind.DWord);
            }
            
            // Verificar si se puede continuar usando
            contadorUso = (Int32)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\miSoftware", 
                "ContadorUso", 0);
            if (contadorUso < 30)
            {
                int nuevoContador = contadorUso + 1;
                Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\miSoftware", 
                    "ContadorUso", nuevoContador);
            }
            else
            {
                DialogResult resultado = MessageBox.Show("¡Se ha agotado el período de prueba! ¿Desea registrar el software?", 
                    "Información", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                if (resultado == DialogResult.Yes)
                {
                    FormularioRegistro.estado = false;
                    this.btnRegistrar_Click(sender, e);
                }
                else
                {
                    Application.Exit();
                }
            }
            #endregion
        }

  1. Agregar un botón y una etiqueta en el formulario principal

Código para el botón de registro:

        private void btnRegistrar_Click(object sender, EventArgs e)
        {
            FormularioRegistro formularioRegistro = new FormularioRegistro() { };
            // formularioRegistro.ShowDialog(); // 【Importante】 sin 'this', el formulario de registro se cierra automáticamente
            formularioRegistro.ShowDialog(this);
        }

  1. Solución a problemas de acceso al registro

Solución 1: Modificar propiedades del archivo del programa

Haga clic derecho en el archivo del programa, en el cuadro de diálogo de propiedades, en la pestaña "Compatibilidad":

Marque "Ejecutar este programa como administrador".

Solución 2: Usar System.Diagnostics.Process.Start() (no se puede depurar)

Modifique el código generado por defecto en Program:

    static class Program
    {
        /// <summary>
        /// Punto de entrada principal de la aplicación.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new MainForm());

            #region Reemplazar Application.Run(new MainForm()); con lo siguiente
            
            /**
             * Si el usuario actual es administrador, inicia la aplicación directamente
             * Si no es administrador, usa un objeto de inicio para asegurar que se ejecute con privilegios de administrador
             */
            // Obtener la identidad del usuario de Windows actual
            System.Security.Principal.WindowsIdentity identidad = System.Security.Principal.WindowsIdentity.GetCurrent();
            System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identidad);
            // Verificar si el usuario actual es administrador
            if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
            {
                // Si es administrador, ejecutar directamente
                Application.Run(new MainForm());
            }
            else
            {
                // Crear objeto de inicio
                System.Diagnostics.ProcessStartInfo infoInicio = new System.Diagnostics.ProcessStartInfo();
                infoInicio.UseShellExecute = true;
                infoInicio.WorkingDirectory = Environment.CurrentDirectory;
                infoInicio.FileName = Application.ExecutablePath;
                // Establecer acción de inicio para asegurar ejecución como administrador
                infoInicio.Verb = "runas";
                try
                {
                    System.Diagnostics.Process.Start(infoInicio); // 【Nota】 este método inicia externamente, no se puede depurar con puntos de interrupción
                }
                catch
                {
                    return;
                }
                // Salir
                Application.Exit();
            }
            #endregion

        }
    }

Solución 3: Solucionar el problema de depuración

En el proyecto, agregue un nuevo elemento: "Archivo de manifiesto de aplicación". Haga clic en "Agregar".

Después de agregar, se abrirá el archivo app.manifest de forma predeterminada. Cambie:

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

a:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

Luego, abra las propiedades del proyecto, en la pestaña "Aplicación", en "Recursos", cambie "Manifiesto" al app.manifest recién creado.

Vuelva a generar el proyecto. Al abrir el programa, solicitará permisos de administrador.

Nota: Si inicia la depuración en Visual Studio, se mostrará un mensaje que dice: "Esta tarea requiere que la aplicación tenga privilegios elevados". Seleccione "Reiniciar con otras credenciales".

Etiquetas: WinForms Registro de Software Acceso al Registro C# .NET Formularios

Publicado el 6-18 18:30