elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


Tema destacado: Guía actualizada para evitar que un ransomware ataque tu empresa


Páginas: [1] 2 3 4 5 6 7 8 9 10
 1 
 en: Hoy a las 12:24 
Iniciado por Novedades - Último mensaje por Novedades
Parches es actualizaciones ?

Y se pueden cambiar para tenerlo como antes ?

Saludos

 2 
 en: Hoy a las 08:12 
Iniciado por Novedades - Último mensaje por Mr.Byte
A mi tambien me pasa, creo qie se debe a las ultimos parches.

 3 
 en: Hoy a las 00:04 
Iniciado por El_Andaluz - Último mensaje por El_Andaluz


El episodio se registró durante una sesión del Parlamento Europeo en Estrasburgo, Francia, cuando el eurodiputado Anders Vistisen tomó la palabra para rechazar las aspiraciones de Donald Trump de adquirir Groenlandia, territorio autónomo que forma parte del Reino de Dinamarca.

En medio de su intervención, el político danés apuntó directamente contra el mandatario norteamericano y lanzó: "Váyase a la *****".

Tras el exabrupto, el vicepresidente del Parlamento Europeo, Nicolae Ștefănuță, interrumpió el discurso y le recordó al legislador que ese tipo de lenguaje no es apropiado en el ámbito institucional, dando por finalizada su exposición de manera abrupta.



 4 
 en: Ayer a las 18:16 
Iniciado por fary - Último mensaje por fary
Sigo intentando avanzar esto... Aquí algunas capturar con ejecutable x64... la calculadora de windows de ejemplo:



Secciones del ejecutable:



Un ojo a las funciones que importa:



Buscando funciones sospechosas:



Probando el  visor de Export Table en una DLL x64 (NTDLL.DLL):




El código practicamente esta ya ordenado en diferentes archivos en un proyecto en Code::Blocks, poco a poco lo iré avanzando segun tenga tiempo...

Si hay algún interesado en participar, ya sabeís. y para el que quiera probar esta versión tan primeriza dejo el ejecutable.


https://www.mediafire.com/file/3wqvx8h9acz8v5m/Visor_PE_compilado.rar/file

saludos.


 5 
 en: 20 Enero 2026, 16:14 pm 
Iniciado por fary - Último mensaje por fary
Bueno, pues retomando un poco el maravilloso formato PE  :rolleyes: Me estoy lanzando a crear un visor PE con GUI y con modo consola en C :)

Este es el código del modo consola  :D

Código
  1. // Sencillo Visor PE  Consola v0.1
  2. // codigo por Fary
  3. // foro.elhacker.net
  4.  
  5. #include <windows.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8.  
  9. int MostrarSecciones(void * Mapa); // Muestra los datos de las secciones
  10. int MostrarImportaciones(void * Mapa); //Muestra las imports
  11. int MostrarExportaciones(void * Mapa); // Muestra las exports
  12.  
  13. int RVAToOffset(int IDDVirtual, int ISHVirtual, int ISHRaw); // Convierte direccion virtual en offset fisico
  14. DWORD AltRVAToOffset(DWORD RVA, void *Mapa); // AltRVAToOffset -> Convierte direccion virtual en offset fisico, version mejorada.
  15.  
  16.  
  17. HANDLE Consola;
  18.  
  19. int main()
  20. {
  21.    HANDLE archivo;
  22.    HANDLE marchivo;
  23.    DWORD TamanoArchivo;
  24.    LPVOID MapaArchivo;
  25.    int Opcion = 0;
  26.    char ruta[MAX_PATH] = {0};
  27.  
  28.    Consola = GetStdHandle(STD_OUTPUT_HANDLE);
  29.    printf("Indica la ruta del archivo (La Ruta no puede tener espacios): \n");
  30.    scanf("%s", &ruta);
  31.  
  32.    archivo = CreateFile(ruta, GENERIC_READ | GENERIC_WRITE,  0,0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); // abrimos el archivo EXE
  33.  
  34.    if(archivo == INVALID_HANDLE_VALUE)
  35.    {
  36.        printf("Error: No se pudo abrir el archivo.\n");
  37.        return 1;
  38.    }
  39.  
  40.    TamanoArchivo = GetFileSize(archivo,0);
  41.  
  42.    marchivo = CreateFileMappingA(archivo, 0 ,PAGE_READWRITE, 0, TamanoArchivo,0);
  43.  
  44.    if (marchivo == NULL)
  45.    {
  46.        printf("No se puede abrir el mapeo del archivo\n");
  47.        CloseHandle(archivo);
  48.        return 1;
  49.    }
  50.  
  51.    MapaArchivo = MapViewOfFile(marchivo, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  52.  
  53.    IMAGE_DOS_HEADER  * idh = (IMAGE_DOS_HEADER*)&MapaArchivo[0]; // Rellenamos el IMAGE_DOS_HEADER
  54.  
  55.    if (idh->e_magic != IMAGE_DOS_SIGNATURE)
  56.    {
  57.        printf("No es un PE Valido\n");
  58.        CloseHandle(archivo);
  59.        CloseHandle(marchivo);
  60.        return 0;
  61.    }
  62.  
  63.    IMAGE_NT_HEADERS * INTH = (IMAGE_NT_HEADERS*)&MapaArchivo[idh->e_lfanew];
  64.  
  65.    while(1)
  66.    {
  67.    system("CLS");
  68.    if(INTH->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) // Mostrador el parametro machine
  69.    {
  70.        printf("FileHeader->Machine: x86\n");
  71.    }else if(INTH->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
  72.    {
  73.        printf("FileHeader->Machine: x64\n");
  74.    }
  75.  
  76.    if (INTH->FileHeader.Characteristics == IMAGE_FILE_EXECUTABLE_IMAGE) // Characteristics
  77.    {
  78.        printf("FileHeader->Characteristics: EXE");
  79.    }else if(INTH->FileHeader.Characteristics == IMAGE_FILE_DLL)
  80.    {
  81.        printf("FileHeader->Characteristics: DLL");
  82.    }else if(INTH->FileHeader.Characteristics == IMAGE_FILE_32BIT_MACHINE)
  83.    {
  84.        printf("FileHeader->Characteristics: 32-Bit\n");
  85.    }
  86.  
  87.    printf("FileHeader->NumberOfSections: 0x%x\n",INTH->FileHeader.NumberOfSections);
  88.  
  89.  
  90.    printf("OptionaHeader->AddressOfEntryPoint: 0x%x\n", INTH->OptionalHeader.AddressOfEntryPoint);
  91.    printf("OptionalHeader->ImageBase: 0x%x\n", INTH->OptionalHeader.ImageBase);
  92.    printf("OptionalHeader->SectionAlignment: 0x%x\n",INTH->OptionalHeader.SectionAlignment);
  93.    printf("OptionalHeader->FileAlignment: 0x%x\n",INTH->OptionalHeader.FileAlignment);
  94.    printf("OptionalHeader->SizeOfImage: 0x%x\n", INTH->OptionalHeader.SizeOfImage);
  95.    printf("OptionalHeader->SizeOfHeaders: 0x%x\n",INTH->OptionalHeader.SizeOfHeaders);
  96.  
  97.    printf("\nSelecciona que quieres hacer ahora: \n");
  98.    printf("1 - Ver secciones.\n");
  99.    printf("2 - Ver Import Table.\n");
  100.    printf("3 - Ver Export Table.\n");
  101.    printf("4 - Salir.\n->");
  102.    scanf("%i", &Opcion);
  103.  
  104.    switch(Opcion)
  105.    {
  106.        case 1:
  107.            system("CLS");
  108.            MostrarSecciones(MapaArchivo);
  109.            break;
  110.        case 2:
  111.            system("CLS");
  112.            MostrarImportaciones(MapaArchivo);
  113.            break;
  114.        case 3:
  115.            system("CLS");
  116.            MostrarExportaciones(MapaArchivo);
  117.            break;
  118.        case 4:
  119.            CloseHandle(archivo);
  120.            CloseHandle(marchivo);
  121.            return 0;
  122.    }
  123.    system("PAUSE");
  124.    }
  125.    return 0;
  126. }
  127.  
  128. int MostrarExportaciones(void * Mapa)
  129. {
  130.    IMAGE_DOS_HEADER * IDH = (IMAGE_DOS_HEADER*)&Mapa[0];
  131.    IMAGE_NT_HEADERS * INTH = (IMAGE_NT_HEADERS*)&Mapa[IDH->e_lfanew];
  132.    IMAGE_SECTION_HEADER * ISH;
  133.  
  134.    IMAGE_DATA_DIRECTORY * IDD = (IMAGE_DATA_DIRECTORY*)&(INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  135.  
  136.    if (IDD->VirtualAddress == 0)
  137.    {
  138.        printf("No hay ExportTable.\n");
  139.        return 1;
  140.    }
  141.  
  142.    int i;
  143.  
  144.  
  145.    DWORD exportRaw = AltRVAToOffset(IDD->VirtualAddress, Mapa);
  146.  
  147.    IMAGE_EXPORT_DIRECTORY *IED = (IMAGE_EXPORT_DIRECTORY *)&Mapa[exportRaw];
  148.  
  149.    int a = AltRVAToOffset(IED->AddressOfNames, Mapa);
  150.  
  151.    DWORD * NombreFuncion = &Mapa[a];
  152.  
  153.    int e = AltRVAToOffset(IED->AddressOfFunctions, Mapa);
  154.    DWORD * DirFuncion = &Mapa[e];
  155.  
  156.    int z = AltRVAToOffset(IED->AddressOfNameOrdinals, Mapa);
  157.    WORD * Ordinal = &Mapa[z];
  158.  
  159.    for (i = 0; i < IED->NumberOfNames; i++)
  160.    {
  161.        DWORD nameOffset = AltRVAToOffset(NombreFuncion[i], Mapa);
  162.        char * funcName = (char*)&Mapa[nameOffset];
  163.  
  164.        DWORD dirfun = DirFuncion[Ordinal[i]];
  165.  
  166.        printf("%s -> 0x%x\n",funcName, dirfun);
  167.    }
  168.  
  169.    return 0;
  170. }
  171.  
  172. int MostrarImportaciones(void * Mapa)
  173. {
  174.    system("CLS");
  175.  
  176.    IMAGE_DOS_HEADER * IDH = (IMAGE_DOS_HEADER*)&Mapa[0];
  177.    IMAGE_NT_HEADERS * INTH = (IMAGE_NT_HEADERS*)&Mapa[IDH->e_lfanew];
  178.    IMAGE_DATA_DIRECTORY * IDD = (IMAGE_DATA_DIRECTORY*)&(INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
  179.    IMAGE_SECTION_HEADER * ISH;
  180.  
  181.    if (IDD->VirtualAddress == 0)
  182.    {
  183.        printf("No se encontro tabla de importaciones.\n");
  184.        return 1;
  185.    }
  186.  
  187.  
  188.    int i;
  189.  
  190.    ISH = IMAGE_FIRST_SECTION(INTH);
  191.  
  192.    for (i = 0; i < INTH->FileHeader.NumberOfSections; i++)
  193.    {
  194.        //ISH = (IMAGE_SECTION_HEADER*)&Mapa[IDH->e_lfanew+sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)*i];
  195.  
  196.        if(IDD->VirtualAddress >= ISH[i].VirtualAddress && IDD->VirtualAddress < (ISH[i].VirtualAddress + ISH[i].Misc.VirtualSize))
  197.        {
  198.            break;
  199.        }
  200.    }
  201.  
  202.    DWORD Offset = AltRVAToOffset(IDD->VirtualAddress, Mapa);//DWORD Offset = RVAToOffset(IDD->VirtualAddress,ISH[i].VirtualAddress, ISH[i].PointerToRawData);//(IDD->VirtualAddress - ISH->VirtualAddress) + ISH->PointerToRawData;
  203.  
  204.    IMAGE_IMPORT_DESCRIPTOR * IID = (IMAGE_IMPORT_DESCRIPTOR*)&Mapa[Offset];
  205.  
  206.    while (IID->Name != NULL)
  207.    {
  208.        DWORD nameOffset = AltRVAToOffset(IID->Name, Mapa);//RVAToOffset(IID->Name, ISH[i].VirtualAddress, ISH[i].PointerToRawData);//(IID->Name - ISH->VirtualAddress) + ISH->PointerToRawData;
  209.        char *dllName = (char*)&Mapa[nameOffset];
  210.  
  211.        SetConsoleTextAttribute(Consola, FOREGROUND_RED);
  212.        printf("DLL: %s\n", dllName);
  213.        SetConsoleTextAttribute(Consola, 0x0F);
  214.  
  215.        DWORD ThunkOffset = AltRVAToOffset(IID->OriginalFirstThunk,Mapa);//RVAToOffset(IID->OriginalFirstThunk,ISH[i].VirtualAddress, ISH[i].PointerToRawData);
  216.        IMAGE_THUNK_DATA * ITD = (IMAGE_THUNK_DATA*)&Mapa[ThunkOffset];
  217.  
  218.        while (ITD->u1.AddressOfData != NULL)
  219.        {
  220.            DWORD dirNombreFuncion = AltRVAToOffset(ITD->u1.AddressOfData, Mapa);//RVAToOffset(ITD->u1.AddressOfData,ISH[i].VirtualAddress, ISH[i].PointerToRawData);
  221.            IMAGE_IMPORT_BY_NAME *IIBN = (IMAGE_IMPORT_BY_NAME*)&Mapa[dirNombreFuncion];
  222.            printf("Funcion: %s\n",IIBN->Name);
  223.            ITD++;
  224.        }
  225.  
  226.        IID++;
  227.    }
  228.    return 0;
  229.  
  230. }
  231.  
  232.  
  233. DWORD AltRVAToOffset(DWORD RVA, void *Mapa)
  234. {
  235.    BYTE *base = (BYTE *)Mapa;
  236.  
  237.    IMAGE_DOS_HEADER *IDH = (IMAGE_DOS_HEADER *)base;
  238.    IMAGE_NT_HEADERS *INTH =
  239.        (IMAGE_NT_HEADERS *)(base + IDH->e_lfanew);
  240.  
  241.    IMAGE_SECTION_HEADER *ISH =
  242.        IMAGE_FIRST_SECTION(INTH);
  243.  
  244.    // Caso: RVA en headers
  245.    if (RVA < INTH->OptionalHeader.SizeOfHeaders)
  246.        return RVA;
  247.  
  248.    for (WORD i = 0; i < INTH->FileHeader.NumberOfSections; i++)
  249.    {
  250.        DWORD va   = ISH[i].VirtualAddress;
  251.        DWORD size = max(ISH[i].Misc.VirtualSize,
  252.                          ISH[i].SizeOfRawData);
  253.  
  254.        if (RVA >= va && RVA < va + size)
  255.        {
  256.            return (RVA - va) + ISH[i].PointerToRawData;
  257.        }
  258.    }
  259.  
  260.    // No encontrado
  261.    return 0;
  262. }
  263.  
  264. int RVAToOffset(int IDDVirtual, int ISHVirtual, int ISHRaw)
  265. {
  266.    return ((IDDVirtual - ISHVirtual) +  ISHRaw);
  267. }
  268.  
  269. int MostrarSecciones(void * Mapa)
  270. {
  271.    IMAGE_DOS_HEADER * IDH = (IMAGE_DOS_HEADER*)&Mapa[0];
  272.    IMAGE_NT_HEADERS * INTH = (IMAGE_NT_HEADERS*)&Mapa[IDH->e_lfanew];
  273.  
  274.  
  275.    IMAGE_SECTION_HEADER * ISH = IMAGE_FIRST_SECTION(INTH);
  276.  
  277.    int i;
  278.    for (i = 0; i < INTH->FileHeader.NumberOfSections; i++)
  279.    {
  280.        SetConsoleTextAttribute(Consola, FOREGROUND_RED);
  281.        printf("Name: %.8s\n", ISH[i].Name);
  282.        SetConsoleTextAttribute(Consola, 0x0F);
  283.        printf("VirtualAddress: 0x%x\n", ISH[i].VirtualAddress);
  284.        printf("SizeOfRawData: 0x%x\n",ISH[i].SizeOfRawData);
  285.        printf("PointerToRawData: 0x%x\n",ISH[i].PointerToRawData);
  286.    }
  287.  
  288.    return 0;
  289. }
  290.  


Se aceptan sugerencias de mejora y gente que quiera aprender junto a mí.

saludos.

 6 
 en: 20 Enero 2026, 14:53 pm 
Iniciado por El_Andaluz - Último mensaje por Songoku
Pero joio si en la captura te lo dice bien claro, en tu caso la carpeta 'Default' se llama 'Profile 1'. En la imagen te lo indico:



Entra en esa carpeta 'Profile 1' (que está en C:\Users\Usuario\AppData\Local\Google\Chrome\User Data\) y allí tienes los marcadores y demás por si quieres guardarlos antes de borrar la carpeta 'Google'.
Saludos...

Songoku

 7 
 en: 19 Enero 2026, 23:40 pm 
Iniciado por El_Andaluz - Último mensaje por El_Andaluz
Esas imágenes que pones son apenas legibles, pero en fin tampoco hacen falta. En tu caso la carpeta 'Default' puede tener otro nombre si por ejemplo as renombrado el perfil o por otras causas, pero vamos el nombre que tenga da lo mismo pues tener la tienes SEGURO.
Para saber cual es nombre de esa carpeta en tu caso, solo escribe en la barra de direcciones (la barra de direcciones es la de ARRIBA DEL TODO, osea no confundir con la barra de búsqueda que está como al medio de la pantalla) del Chrome lo siguiente:

chrome://version/

Luego dale a Intro, y te saldrá algo como esto:



En donde como puedes ver en lo de 'Ruta del perfil' tienes la ruta exacta de la carpeta 'Default', que como ya digo puede tener otro nombre, vamos que en tu caso esa ruta en vez de terminar en la carpeta 'Default' puede terminar con otro nombre cualquiera.
Pero a efectos prácticos da igual como en tu caso se llame la carpeta 'Default', pues al borrar la carpeta 'Google' ya se borra todo su contenido, incluida dicha carpeta 'Default' o como quiera que se llame en tu caso. De modo que simplemente borra la carpeta 'Google' y así tendrás un perfil nuevo y limpio en el Chrome, con el cual ya no deberías experimentar mas problemas.
Saludos...

Songoku



He hecho lo que me has dicho y la maldita carpeta esa Default no aparece y no se con nombre podría ser fíjate bien en la captura a ver en que carpeta puede ser por lo menos, a ver si puedo salvar algunos marcadores si no lo mas sencillo es borrar directamente la carpeta google y tal como tu dice y no me complico mas pero ya por curiosidad de ver donde carajo están esos archivos que me dijiste.



 8 
 en: 18 Enero 2026, 22:14 pm 
Iniciado por Eleкtro - Último mensaje por Eleкtro
FlexibleSettingsProvider

Un proveedor de configuración que permite almacenar el archivo de configuración de usuario "user.config" en un directorio y nombre de archivo personalizables, asegurando que la ubicación de la configuración se mantenga fija y predecible.

Este proveedor nos permite - si así lo queremos - establecer el directorio base de nuestra aplicación, haciendo que podamos portabilizar nuestra aplicación junto al archivo de configuración de usuario.

Código
  1. #Region " Option Statements "
  2.  
  3. Option Explicit On
  4. Option Strict On
  5. Option Infer Off
  6.  
  7. #End Region
  8.  
  9. #Region " Imports "
  10.  
  11. Imports System.Collections.Specialized
  12. Imports System.ComponentModel
  13. Imports System.Configuration
  14. Imports System.IO
  15. Imports System.Reflection
  16. Imports System.Runtime.InteropServices
  17. Imports System.Security
  18. Imports System.Security.AccessControl
  19. Imports System.Security.Cryptography
  20. Imports System.Security.Principal
  21. Imports System.Text
  22.  
  23. #End Region
  24.  
  25. #Region " FlexibleSettingsProvider "
  26.  
  27. ''' <summary>
  28. ''' A settings provider that allows to store the application's user configuration file
  29. ''' in a user-defined directory path and file name, ensuring the configuration location remains
  30. ''' predictable across application updates.
  31. ''' </summary>
  32. '''
  33. ''' <example> This is a code example.
  34. ''' <code language="VB">
  35. ''' '------------------------------------------------------------------------------
  36. ''' ' <auto-generated>
  37. ''' '     This code was generated by a tool.
  38. ''' '     Runtime Version:4.0.30319.42000
  39. ''' '
  40. ''' '     Changes to this file may cause incorrect behavior and will be lost if
  41. ''' '     the code is regenerated.
  42. ''' ' </auto-generated>
  43. ''' '------------------------------------------------------------------------------
  44. ''' Namespace My
  45. '''    
  46. '''     &lt;Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(),  _
  47. '''      Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0"),  _
  48. '''      Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)&gt;  _
  49. '''     Partial Friend NotInheritable Class MySettings
  50. '''         Inherits Global.System.Configuration.ApplicationSettingsBase
  51. '''        
  52. '''         ' ...
  53. '''     End Class
  54. ''' End Namespace
  55. '''
  56. ''' ' &#9940; DO NOT MODIFY THE AUTO-GENERATED DESIGNER FILE ABOVE.
  57. ''' ' INSTEAD, PLACE THE FOLLOWING NAMESPACE IN A SEPARATE PART OF YOUR SOURCE CODE:
  58. '''
  59. ''' Namespace My
  60. '''
  61. '''     &lt;Global.System.Configuration.SettingsProvider(GetType(FlexibleSettingsProvider))&gt;
  62. '''     Partial Friend NotInheritable Class MySettings
  63. '''
  64. '''         Public Sub New()
  65. '''             FlexibleSettingsProvider.BaseDirectoryPath = ".\"
  66. '''             FlexibleSettingsProvider.DirectoryName = ""
  67. '''             FlexibleSettingsProvider.DirectoryNameFlags = SettingsDirectoryNameFlags.None
  68. '''             FlexibleSettingsProvider.FileName = "user.config"
  69. '''
  70. '''             Debug.WriteLine($"Effective config file path: {FlexibleSettingsProvider.EffectiveConfigFilePath}")
  71. '''         End Sub
  72. '''
  73. '''     End Class
  74. ''' End Namespace
  75. ''' </code>
  76. ''' </example>
  77. '''
  78. ''' <example> This is a code example.
  79. ''' <code language="CSharp">
  80. '''
  81. ''' //------------------------------------------------------------------------------
  82. ''' // <auto-generated>
  83. ''' //     This code was generated by a tool.
  84. ''' //     Runtime Version:4.0.30319.42000
  85. ''' //
  86. ''' //     Changes to this file may cause incorrect behavior and will be lost if
  87. ''' //     the code is regenerated.
  88. ''' // </auto-generated>
  89. ''' //------------------------------------------------------------------------------
  90. '''
  91. ''' namespace WindowsFormsApp1.Properties {
  92. '''    
  93. '''     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
  94. '''     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
  95. '''     internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
  96. '''         // ...
  97. '''     }
  98. ''' }
  99. '''
  100. ''' // &#9940; DO NOT MODIFY THE AUTO-GENERATED DESIGNER FILE ABOVE.
  101. ''' // INSTEAD, PLACE THE FOLLOWING NAMESPACE IN A SEPARATE PART OF YOUR SOURCE CODE:
  102. '''
  103. ''' namespace WindowsFormsApp1.Properties
  104. ''' {
  105. '''     [SettingsProvider(typeof(FlexibleSettingsProvider))]
  106. '''     internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
  107. '''     {
  108. '''         public Settings()
  109. '''         {
  110. '''             FlexibleSettingsProvider.BaseDirectoryPath = @".\";
  111. '''             FlexibleSettingsProvider.DirectoryName = string.Empty;
  112. '''             FlexibleSettingsProvider.DirectoryNameFlags = SettingsDirectoryNameFlags.None;
  113. '''             FlexibleSettingsProvider.FileName = "user.config";
  114. '''
  115. '''             Debug.WriteLine($"Effective config file path: {FlexibleSettingsProvider.EffectiveConfigFilePath}");
  116. '''         }
  117. '''     }
  118. ''' }
  119. ''' </code>
  120. ''' </example>
  121. Public Class FlexibleSettingsProvider : Inherits SettingsProvider
  122.  
  123. #Region " Private Fields "
  124.  
  125.    ''' <summary>
  126.    ''' The default base directory path to use when the path specified by
  127.    ''' <see cref="FlexibleSettingsProvider.BaseDirectoryPath"/> is null or cannot be accessed.
  128.    ''' </summary>
  129.    Private Shared ReadOnly DefaultBaseDirectoryPath As String =
  130.        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ' Note: THIS VALUE CANNOT BE NULL.
  131.  
  132.    ''' <summary>
  133.    ''' The default configuration file name to use when the name specified by
  134.    ''' <see cref="FlexibleSettingsProvider.FileName"/> is null.
  135.    ''' </summary>
  136.    Private Shared ReadOnly DefaultFileName As String = "user.config" ' Note: THIS VALUE CANNOT BE NULL.
  137.  
  138. #End Region
  139.  
  140. #Region " Public Properties "
  141.  
  142.    ''' <summary>
  143.    ''' Gets or sets the base directory path where the settings storage folder specified by
  144.    ''' <see cref="FlexibleSettingsProvider.DirectoryName"/> property will be created.
  145.    ''' </summary>
  146.    '''
  147.    ''' <remarks>
  148.    ''' This can be a relative path, for example <b>".\"</b>, which refers to the current application's base directory.
  149.    ''' <para></para>
  150.    ''' If this value is null or empty, <see cref="Environment.SpecialFolder.LocalApplicationData"/> directory path will be used.
  151.    ''' <para></para>
  152.    ''' Default value is <b>".\"</b>.
  153.    ''' </remarks>
  154.    Public Shared Property BaseDirectoryPath As String = ".\"
  155.  
  156.    ''' <summary>
  157.    ''' Gets or sets the name of the settings storage folder that will be created under the
  158.    ''' base directory path specified by <see cref="FlexibleSettingsProvider.BaseDirectoryPath"/> property;
  159.    ''' For example, <b>"My Application"</b>.
  160.    ''' </summary>
  161.    '''
  162.    ''' <remarks>
  163.    ''' This value can be null, in which case this folder will not be created at all.
  164.    ''' <para></para>
  165.    ''' Default value is null.
  166.    ''' </remarks>
  167.    Public Shared Property DirectoryName As String = Nothing
  168.  
  169.    ''' <summary>
  170.    ''' Gets or sets additional flags that allows to automatically append extra information to the
  171.    ''' settings storage folder name specified by <see cref="FlexibleSettingsProvider.DirectoryName"/> property.
  172.    ''' <para></para>
  173.    ''' Default value is <see cref="SettingsDirectoryNameFlags.None"/>.
  174.    ''' </summary>
  175.    Public Shared Property DirectoryNameFlags As SettingsDirectoryNameFlags = SettingsDirectoryNameFlags.None
  176.  
  177.    ''' <summary>
  178.    ''' Gets or sets the name of the user configuration file to create inside the
  179.    ''' settings storage folder specified by <see cref="FlexibleSettingsProvider.DirectoryName"/> property.
  180.    ''' <para></para>
  181.    ''' If this value is null or empty, <b>"user.config"</b> is used.
  182.    ''' <para></para>
  183.    ''' Default value is <b>"user.config"</b>.
  184.    ''' </summary>
  185.    Public Shared Property FileName As String = FlexibleSettingsProvider.DefaultFileName
  186.  
  187.    ''' <summary>
  188.    ''' Gets or sets the type of <see cref="HashAlgorithm"/> to use for appending the hash suffix to the
  189.    ''' settings storage folder name specified by <see cref="FlexibleSettingsProvider.DirectoryName"/> when
  190.    ''' <see cref="FlexibleSettingsProvider.DirectoryNameFlags"/> contains <see cref="SettingsDirectoryNameFlags.Hash"/> flag.
  191.    ''' <para></para>
  192.    ''' Default value is <see cref="MD5"/>.
  193.    ''' </summary>
  194.    Public Shared Property HashAlgorithmType As Type = GetType(MD5)
  195.  
  196.    ''' <summary>
  197.    ''' Gets or sets the maximum character length to use for appending the hash suffix to the
  198.    ''' settings storage folder name specified by <see cref="FlexibleSettingsProvider.DirectoryName"/> when
  199.    ''' <see cref="FlexibleSettingsProvider.DirectoryNameFlags"/> contains <see cref="SettingsDirectoryNameFlags.Hash"/> flag.
  200.    ''' <see cref="SettingsDirectoryNameFlags.Hash"/> flag.
  201.    ''' <para></para>
  202.    ''' Default value is <b>8</b>.
  203.    ''' </summary>
  204.    '''
  205.    ''' <remarks>
  206.    ''' Note: If the specified length exceeds the maximum length supported by the hash algorithm specified by
  207.    ''' <see cref="FlexibleSettingsProvider.HashAlgorithmType"/> property,
  208.    ''' the value is automatically truncated to the maximum allowed.
  209.    ''' </remarks>
  210.    Public Shared Property HashLength As Integer = 8
  211.  
  212.    ''' <summary>
  213.    ''' Gets the effective full path to the user configuration file
  214.    ''' using the current rules specified by
  215.    ''' <see cref="FlexibleSettingsProvider.BaseDirectoryPath"/>,
  216.    ''' <see cref="FlexibleSettingsProvider.DirectoryName"/> ,
  217.    ''' <see cref="FlexibleSettingsProvider.DirectoryNameFlags"/>,
  218.    ''' <see cref="FlexibleSettingsProvider.FileName"/>,
  219.    ''' <see cref="FlexibleSettingsProvider.HashAlgorithmType"/> and
  220.    ''' <see cref="FlexibleSettingsProvider.HashLength"/> properties;
  221.    ''' For example, <b>"C:\Users\{USERNAME}\AppData\Local\My Application\user.config"</b>
  222.    ''' </summary>
  223.    Public Shared ReadOnly Property EffectiveConfigFilePath As String
  224.        <DebuggerStepThrough>
  225.        Get
  226.            Return FlexibleSettingsProvider.GetEffectiveConfigFilePath()
  227.        End Get
  228.    End Property
  229.  
  230.    ''' <summary>
  231.    ''' Gets the name of the currently running application
  232.    ''' using the current rules specified by
  233.    ''' <see cref="FlexibleSettingsProvider.DirectoryName"/> ,
  234.    ''' <see cref="FlexibleSettingsProvider.DirectoryNameFlags"/>,
  235.    ''' <see cref="FlexibleSettingsProvider.HashAlgorithmType"/> and
  236.    ''' <see cref="FlexibleSettingsProvider.HashLength"/> properties;
  237.    ''' For example, <b>"My Application"</b>.
  238.    ''' </summary>
  239.    <EditorBrowsable(EditorBrowsableState.Never)>
  240.    Public Overrides Property ApplicationName As String
  241.        <DebuggerStepThrough>
  242.        Get
  243.            Return FlexibleSettingsProvider.GetEffectiveDirectoryName()
  244.        End Get
  245.        <DebuggerStepThrough>
  246.        Set(value As String)
  247.            ' Intentionally ignored, and required.
  248.        End Set
  249.    End Property
  250.  
  251.    ''' <summary>
  252.    ''' Gets a brief, friendly description of this <see cref="SettingsProvider"/>,
  253.    ''' suitable for display in administrative tools or other user interfaces (UIs).
  254.    ''' </summary>
  255.    <EditorBrowsable(EditorBrowsableState.Never)>
  256.    Public Overrides ReadOnly Property Description As String
  257.        <DebuggerStepThrough>
  258.        Get
  259.            Return If(Not String.IsNullOrEmpty(Me._Description), Me._Description, Me.Name)
  260.        End Get
  261.    End Property
  262.    ''' <summary>
  263.    ''' ( Backing field of <see cref="Description"/> property.)
  264.    ''' <para></para>
  265.    ''' A brief, friendly description of this <see cref="SettingsProvider"/>,
  266.    ''' suitable for display in administrative tools or other user interfaces (UIs).
  267.    ''' </summary>
  268.    Private ReadOnly _Description As String =
  269.        "A settings provider that allows to store the application's user configuration file in a user-defined directory path and file name."
  270.  
  271. #End Region
  272.  
  273. #Region " Constructors "
  274.  
  275.    ''' <summary>
  276.    ''' Initializes a new instance of the <see cref="FlexibleSettingsProvider"/> class.
  277.    ''' </summary>
  278.    <DebuggerNonUserCode>
  279.    Public Sub New()
  280.    End Sub
  281.  
  282. #End Region
  283.  
  284. #Region " Public Methods "
  285.  
  286.    ''' <summary>
  287.    ''' Initializes the configuration builder.
  288.    ''' </summary>
  289.    '''
  290.    ''' <param name="name">
  291.    ''' The friendly name of the provider.
  292.    ''' </param>
  293.    '''
  294.    ''' <param name="config">
  295.    ''' A collection of the name/value pairs representing the provider-specific attributes
  296.    ''' specified in the configuration for this provider.
  297.    ''' </param>
  298.    <DebuggerStepperBoundary>
  299.    Public Overrides Sub Initialize(name As String, config As NameValueCollection)
  300.  
  301.        If String.IsNullOrEmpty(name) Then
  302.            name = NameOf(FlexibleSettingsProvider)
  303.        End If
  304.        MyBase.Initialize(name, config)
  305.    End Sub
  306.  
  307.    ''' <summary>
  308.    ''' Returns the collection of settings property values for the specified application instance and settings property group.
  309.    ''' </summary>
  310.    '''
  311.    ''' <param name="context">
  312.    ''' A <see cref="SettingsContext"/> describing the current application use.
  313.    ''' </param>
  314.    '''
  315.    ''' <param name="properties">
  316.    ''' A <see cref="SettingsPropertyCollection"/> containing the settings property group whose values are to be retrieved.
  317.    ''' </param>
  318.    ''' <returns>
  319.    ''' A <see cref="SettingsPropertyValueCollection"/> containing the values for the specified settings property group.
  320.    ''' </returns>
  321.    <DebuggerStepperBoundary>
  322.    Public Overrides Function GetPropertyValues(context As SettingsContext, properties As SettingsPropertyCollection) As SettingsPropertyValueCollection
  323.  
  324.        Dim values As New SettingsPropertyValueCollection()
  325.  
  326.        Dim doc As XDocument = Nothing
  327.  
  328.        Dim effectiveConfigFilePath As String = FlexibleSettingsProvider.EffectiveConfigFilePath()
  329.  
  330.        If File.Exists(effectiveConfigFilePath) Then
  331.            Try
  332.                Using fs As New FileStream(effectiveConfigFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
  333.                    doc = XDocument.Load(fs)
  334.                End Using
  335.            Catch ex As Exception
  336.                ' If file is corrupt / unreadable, recreate a fresh doc.
  337.                doc = New XDocument(New XElement("settings"))
  338.            End Try
  339.        Else
  340.            doc = New XDocument(New XElement("settings"))
  341.        End If
  342.  
  343.        ' Ensure root exists.
  344.        If doc.Root Is Nothing Then
  345.            doc = New XDocument(New XElement("settings"))
  346.        End If
  347.  
  348.        For Each prop As SettingsProperty In properties
  349.            Dim el As XElement = doc.Root.Element(prop.Name)
  350.            Dim value As Object = If(el IsNot Nothing, el.Value, prop.DefaultValue)
  351.  
  352.            Dim spv As New SettingsPropertyValue(prop) With {
  353.                .SerializedValue = value
  354.            }
  355.            values.Add(spv)
  356.        Next
  357.  
  358.        Return values
  359.    End Function
  360.  
  361.    ''' <summary>
  362.    ''' Sets the values of the specified group of property settings.
  363.    ''' </summary>
  364.    '''
  365.    ''' <param name="context">
  366.    ''' A <see cref="SettingsContext"/> describing the current application use.
  367.    ''' </param>
  368.    '''
  369.    ''' <param name="values">
  370.    ''' A <see cref="SettingsPropertyValueCollection"/> representing the group of property settings to set.
  371.    ''' </param>
  372.    <DebuggerStepperBoundary>
  373.    Public Overrides Sub SetPropertyValues(context As SettingsContext, values As SettingsPropertyValueCollection)
  374.  
  375.        Dim effectiveConfigFilePath As String = FlexibleSettingsProvider.EffectiveConfigFilePath()
  376.        Dim directoryPath As String = Path.GetDirectoryName(effectiveConfigFilePath)
  377.        If Not Directory.Exists(directoryPath) Then
  378.            Directory.CreateDirectory(directoryPath)
  379.        End If
  380.  
  381.        Dim root As New XElement("settings")
  382.  
  383.        For Each val As SettingsPropertyValue In values
  384.            Dim nodeName As String = If(val.Property IsNot Nothing AndAlso Not String.IsNullOrEmpty(val.Property.Name),
  385.                                        val.Property.Name,
  386.                                        "unknown")
  387.  
  388.            Dim nodeValue As String = If(val.SerializedValue Is Nothing, "", val.SerializedValue.ToString())
  389.  
  390.            root.Add(New XElement(nodeName, nodeValue))
  391.        Next
  392.  
  393.        Dim doc As New XDocument(root)
  394.  
  395.        Using fs As New FileStream(effectiveConfigFilePath, FileMode.Create, FileAccess.Write, FileShare.Read)
  396.            doc.Save(fs)
  397.        End Using
  398.    End Sub
  399.  
  400. #End Region
  401.  
  402. #Region " Private Methods "
  403.  
  404.    ''' <summary>
  405.    ''' Resolves and returns the effective base directory path where the settings storage folder specified by
  406.    ''' <see cref="FlexibleSettingsProvider.DirectoryName"/> property will be created.
  407.    ''' </summary>
  408.    '''
  409.    ''' <remarks>
  410.    ''' This function determines the proper directory path by first using the value specified in
  411.    ''' <see cref="FlexibleSettingsProvider.BaseDirectoryPath"/> property.
  412.    ''' <para></para>
  413.    ''' If that value is null, empty, whitespace, or the directory cannot be created, the path specified by
  414.    ''' <see cref="FlexibleSettingsProvider.DefaultBaseDirectoryPath"/> property is used instead.
  415.    ''' </remarks>
  416.    '''
  417.    ''' <returns>
  418.    ''' A string representing the effective base directory path.
  419.    ''' </returns>
  420.    '''
  421.    ''' <exception cref="InvalidOperationException">
  422.    ''' Thrown when the provier is unable to resolve a base directory path that
  423.    ''' exists and can grant read/write access to the current application.
  424.    ''' <para></para>
  425.    ''' This exception indicates that neither the directory specified by <see cref="FlexibleSettingsProvider.DirectoryName"/> property
  426.    ''' nor the fallback specified by <see cref="FlexibleSettingsProvider.DefaultBaseDirectoryPath"/> property
  427.    ''' can be used to read from and write to the location.
  428.    ''' </exception>
  429.    <DebuggerStepThrough>
  430.    Private Shared Function GetEffectiveBaseDirectoryPath() As String
  431.  
  432.        Dim currentBaseDirectoryPath As String = FlexibleSettingsProvider.BaseDirectoryPath
  433.  
  434.        ' Expand to full path.
  435.        If Not String.IsNullOrWhiteSpace(currentBaseDirectoryPath) Then
  436.            currentBaseDirectoryPath = Path.GetFullPath(currentBaseDirectoryPath)
  437.        End If
  438.  
  439.        ' Ensure the directory path is set.
  440.        If String.IsNullOrWhiteSpace(currentBaseDirectoryPath) Then
  441.            currentBaseDirectoryPath = FlexibleSettingsProvider.DefaultBaseDirectoryPath
  442.        End If
  443.  
  444.        ' Try creating the directory.
  445.        Try
  446.            Directory.CreateDirectory(currentBaseDirectoryPath)
  447.  
  448.        Catch ' If failed, fallback to LocalAppData
  449.            currentBaseDirectoryPath = FlexibleSettingsProvider.DefaultBaseDirectoryPath
  450.            Try
  451.                Directory.CreateDirectory(currentBaseDirectoryPath)
  452.            Catch
  453.                ' Ignore: write check will catch this later.
  454.            End Try
  455.  
  456.        End Try
  457.  
  458.        ' Verify that we can read from and write to the directory path.
  459.        If Not FlexibleSettingsProvider.CanReadAndWriteToDirectory(currentBaseDirectoryPath) Then
  460.  
  461.            Dim previousDirectoryPath As String = currentBaseDirectoryPath
  462.  
  463.            ' Switch to default directory path if not already using it.
  464.            If currentBaseDirectoryPath <> FlexibleSettingsProvider.DefaultBaseDirectoryPath Then
  465.                currentBaseDirectoryPath = FlexibleSettingsProvider.DefaultBaseDirectoryPath
  466.            End If
  467.  
  468.            If currentBaseDirectoryPath <> previousDirectoryPath Then
  469.                ' Throw if directory still not writable.
  470.                If Not FlexibleSettingsProvider.CanReadAndWriteToDirectory(currentBaseDirectoryPath) Then
  471.                    Throw New InvalidOperationException(
  472.                        $"Cannot read from or write the user configuration file in directory: {currentBaseDirectoryPath}. Check user permissions.")
  473.                End If
  474.            End If
  475.        End If
  476.  
  477.        Return currentBaseDirectoryPath
  478.    End Function
  479.  
  480.    ''' <summary>
  481.    ''' Resolves and returns the effective name of the settings storage folder that will be created under the
  482.    ''' base directory path specified by <see cref="FlexibleSettingsProvider.BaseDirectoryPath"/> property,
  483.    ''' applying the rules specified by <see cref="FlexibleSettingsProvider.DirectoryNameFlags"/>.
  484.    ''' </summary>
  485.    '''
  486.    ''' <returns>
  487.    ''' A string representing the fully constructed directory name after applying all configured naming rules;
  488.    ''' For example, <b>"My Application"</b>.
  489.    ''' </returns>
  490.    <DebuggerStepThrough>
  491.    Private Shared Function GetEffectiveDirectoryName() As String
  492.  
  493.        Dim appendApplicationName As Boolean =
  494.            FlexibleSettingsProvider.DirectoryNameFlags.HasFlag(SettingsDirectoryNameFlags.ApplicationName)
  495.  
  496.        Dim appendAssemblyName As Boolean =
  497.            FlexibleSettingsProvider.DirectoryNameFlags.HasFlag(SettingsDirectoryNameFlags.AssemblyName)
  498.  
  499.        Dim appendVersion As Boolean =
  500.            FlexibleSettingsProvider.DirectoryNameFlags.HasFlag(SettingsDirectoryNameFlags.Version)
  501.  
  502.        Dim appendHash As Boolean =
  503.            FlexibleSettingsProvider.DirectoryNameFlags.HasFlag(SettingsDirectoryNameFlags.Hash)
  504.  
  505.        Dim appendUserName As Boolean =
  506.            FlexibleSettingsProvider.DirectoryNameFlags.HasFlag(SettingsDirectoryNameFlags.UserName)
  507.  
  508.        Dim name As String = FlexibleSettingsProvider.DirectoryName
  509.  
  510.        Dim sb As New StringBuilder(Math.Max(16, If(String.IsNullOrEmpty(name), 0, name.Length)))
  511.  
  512.        If Not String.IsNullOrWhiteSpace(name) Then
  513.            sb.Append(name)
  514.        End If
  515.  
  516.        If appendApplicationName Then
  517.            Dim applicationName As String = My.Application.Info.ProductName
  518.  
  519.            If Not String.IsNullOrWhiteSpace(applicationName) Then
  520.  
  521.                sb.Append($"{If(sb.Length <> 0, "_", "")}{applicationName}")
  522.            End If
  523.        End If
  524.  
  525.        If appendAssemblyName Then
  526.            Dim assemblyName As String = My.Application.Info.AssemblyName
  527.  
  528.            If Not String.IsNullOrWhiteSpace(assemblyName) Then
  529.                sb.Append($"{If(sb.Length <> 0, "_", "")}{assemblyName}")
  530.            End If
  531.        End If
  532.  
  533.        If appendVersion Then
  534.            Dim version As Version = My.Application.Info.Version
  535.  
  536.            If version IsNot Nothing Then
  537.                sb.Append($"{If(sb.Length <> 0, "_", "")}{version}")
  538.            End If
  539.        End If
  540.  
  541.        If appendHash Then
  542.            ' Derive a deterministic unique ID from the current assembly GUID.
  543.            Dim asm As Assembly = If(Assembly.GetEntryAssembly(), Assembly.GetExecutingAssembly())
  544.            If asm IsNot Nothing Then
  545.                Dim guidAttr As GuidAttribute = asm.GetCustomAttribute(Of GuidAttribute)()
  546.  
  547.                Dim guid As Guid =
  548.                    If(guidAttr IsNot Nothing,
  549.                        New Guid(guidAttr.Value),
  550.                        asm.ManifestModule.ModuleVersionId ' Fallback: Use the manifest module for the GUID extraction value.
  551.                    )
  552.  
  553.                Dim hashSeed As String =
  554.                    If(guid <> Guid.Empty,
  555.                        guid.ToString("N"),
  556.                        GetType(FlexibleSettingsProvider).FullName ' Fallback: Use the current type full name.
  557.                    )
  558.  
  559.                Using hasher As HashAlgorithm = HashAlgorithm.Create(FlexibleSettingsProvider.HashAlgorithmType.Name)
  560.                    Dim hashLength As Integer = Math.Min(FlexibleSettingsProvider.HashLength, (hasher.HashSize \ 4))
  561.                    Dim hashString As String = FlexibleSettingsProvider.ComputeDeterministicHashOfString(hasher, hashSeed, hashLength)
  562.  
  563.                    sb.Append($"{If(sb.Length <> 0, "_", "")}{hashString}")
  564.                End Using
  565.            End If
  566.        End If
  567.  
  568.        If appendUserName Then
  569.            Dim userName As String = Environment.UserName
  570.  
  571.            If Not String.IsNullOrWhiteSpace(userName) Then
  572.                sb.Append($"{If(sb.Length <> 0, "_", "")}{userName}")
  573.            End If
  574.        End If
  575.  
  576.        Return sb.ToString()
  577.    End Function
  578.  
  579.    ''' <summary>
  580.    ''' Resolves and returns the effective file name used for the user settings configuration file.
  581.    ''' </summary>
  582.    '''
  583.    ''' <returns>
  584.    ''' A string representing the effective file name; For example, <b>"user.config"</b>.
  585.    ''' </returns>
  586.    <DebuggerStepThrough>
  587.    Private Shared Function GetEffectiveFileName() As String
  588.  
  589.        Return If(Not String.IsNullOrWhiteSpace(FlexibleSettingsProvider.FileName),
  590.                  FlexibleSettingsProvider.FileName,
  591.                  FlexibleSettingsProvider.DefaultFileName)
  592.    End Function
  593.  
  594.    ''' <summary>
  595.    ''' Resolves and returns the effective full path to the user configuration file.
  596.    ''' </summary>
  597.    '''
  598.    ''' <returns>
  599.    ''' A string representing the full path to the user configuration file;
  600.    ''' For example, <b>"C:\Users\{USERNAME}\AppData\Local\My Application\user.config"</b>.
  601.    ''' </returns>
  602.    <DebuggerStepThrough>
  603.    Private Shared Function GetEffectiveConfigFilePath() As String
  604.  
  605.        Dim baseDirectoryPath As String = FlexibleSettingsProvider.GetEffectiveBaseDirectoryPath()
  606.        Dim directoryName As String = FlexibleSettingsProvider.GetEffectiveDirectoryName()
  607.        Dim fileName As String = FlexibleSettingsProvider.GetEffectiveFileName()
  608.  
  609.        Return Path.Combine(baseDirectoryPath, directoryName, fileName)
  610.    End Function
  611.  
  612.    ''' <summary>
  613.    ''' Checks whether the application has read and write permissions in the specified directory.
  614.    ''' </summary>
  615.    '''
  616.    ''' <param name="directoryPath">
  617.    ''' The directory path to check for read and write access.
  618.    ''' </param>
  619.    '''
  620.    ''' <returns>
  621.    ''' <see langword="True"/> if the application has read and write permissions in the directory;
  622.    ''' otherwise <see langword="False"/>.
  623.    ''' </returns>
  624.    <DebuggerStepThrough>
  625.    Private Shared Function CanReadAndWriteToDirectory(directoryPath As String) As Boolean
  626.  
  627.        If String.IsNullOrWhiteSpace(directoryPath) Then
  628.            Throw New ArgumentNullException(NameOf(directoryPath))
  629.        End If
  630.  
  631.        If Not Directory.Exists(directoryPath) Then
  632.            Throw New DirectoryNotFoundException($"Directory not found: {directoryPath}")
  633.        End If
  634.  
  635.        Try
  636.            Dim directoryInfo As New DirectoryInfo(directoryPath)
  637.            Dim acl As DirectorySecurity = directoryInfo.GetAccessControl()
  638.            Dim rules As AuthorizationRuleCollection =
  639.                acl.GetAccessRules(includeExplicit:=True, includeInherited:=True, targetType:=GetType(SecurityIdentifier))
  640.  
  641.            Dim identity As WindowsIdentity = WindowsIdentity.GetCurrent()
  642.            If identity Is Nothing Then
  643.                Return False
  644.            End If
  645.  
  646.            ' Collect SIDs for current user and groups.
  647.            Dim sids As New HashSet(Of SecurityIdentifier)()
  648.            If identity.User IsNot Nothing Then
  649.                sids.Add(identity.User)
  650.            End If
  651.            For Each grp As IdentityReference In identity.Groups
  652.                Dim sid As SecurityIdentifier = TryCast(grp, SecurityIdentifier)
  653.                If sid IsNot Nothing Then
  654.                    sids.Add(sid)
  655.                End If
  656.            Next
  657.  
  658.            ' Define the specific bits we require for read and write.
  659.            ' Note: We intentionally DO NOT include Delete/DeleteSubdirectoriesAndFiles here,
  660.            ' because a deny on Delete should not block basic read/write operations.
  661.            Dim requiredRead As FileSystemRights = FileSystemRights.ReadData Or FileSystemRights.ListDirectory Or FileSystemRights.Read
  662.            Dim requiredWrite As FileSystemRights = FileSystemRights.WriteData Or FileSystemRights.AppendData Or FileSystemRights.Write
  663.  
  664.            ' Accumulate allow and deny masks for relevant SIDs.
  665.            Dim accumulatedAllow As FileSystemRights = 0
  666.            Dim accumulatedDeny As FileSystemRights = 0
  667.  
  668.            For Each ruleObj As AuthorizationRule In rules
  669.                Dim rule As FileSystemAccessRule = TryCast(ruleObj, FileSystemAccessRule)
  670.                If rule Is Nothing Then
  671.                    Continue For
  672.                End If
  673.  
  674.                Dim sid As SecurityIdentifier = TryCast(rule.IdentityReference, SecurityIdentifier)
  675.                If sid Is Nothing OrElse Not sids.Contains(sid) Then
  676.                    Continue For
  677.                End If
  678.  
  679.                Dim rights As FileSystemRights = rule.FileSystemRights
  680.  
  681.                If rule.AccessControlType = AccessControlType.Deny Then
  682.                    accumulatedDeny = accumulatedDeny Or rights
  683.  
  684.                ElseIf rule.AccessControlType = AccessControlType.Allow Then
  685.                    accumulatedAllow = accumulatedAllow Or rights
  686.  
  687.                End If
  688.            Next
  689.  
  690.            ' If any required read/write bit is explicitly denied, cannot read/write.
  691.            If (accumulatedDeny And (requiredRead Or requiredWrite)) <> 0 Then
  692.                Return False
  693.            End If
  694.  
  695.            ' Check that all required read bits are allowed.
  696.            If (accumulatedAllow And requiredRead) <> requiredRead Then
  697.                Return False
  698.            End If
  699.  
  700.            ' Check that all required write bits are allowed.
  701.            Return (accumulatedAllow And requiredWrite) = requiredWrite
  702.  
  703.        Catch ex As UnauthorizedAccessException
  704.            ' Explicitly cannot access the directory.
  705.            Return False
  706.  
  707.        Catch ex As SecurityException
  708.            ' Security policy prevents access.
  709.            Return False
  710.  
  711.        Catch ex As Exception
  712.            ' Unexpected error.
  713.            Return False
  714.  
  715.        End Try
  716.    End Function
  717.  
  718.    ''' <summary>
  719.    ''' Computes a deterministic hash of the given input string using the specified hash algorithm type.
  720.    ''' </summary>
  721.    '''
  722.    ''' <param name="algorithm">
  723.    ''' The hash algorithm instance to use (e.g., <see cref="MD5"/>, <see cref="SHA256"/>).
  724.    ''' </param>
  725.    '''
  726.    ''' <param name="value">
  727.    ''' The input string to compute the hash from.
  728.    ''' </param>
  729.    '''
  730.    ''' <param name="length">
  731.    ''' The desired total length of the resulting hexadecimal string.
  732.    ''' <para></para>
  733.    ''' If the computed hash is shorter than this length, the result is padded with '0' characters.
  734.    ''' <para></para>
  735.    ''' If the length is not a multiple of two, the final nibble of the next byte is used for the extra character.
  736.    ''' </param>
  737.    '''
  738.    ''' <returns>
  739.    ''' A string of exactly <paramref name="length"/> hexadecimal characters representing the hash of the input string.
  740.    ''' <para></para>
  741.    ''' This is deterministic: the same input and algorithm always produce the same output.
  742.    ''' </returns>
  743.    <DebuggerStepThrough>
  744.    Private Shared Function ComputeDeterministicHashOfString(algorithm As HashAlgorithm,
  745.                                                             value As String,
  746.                                                             length As Integer) As String
  747.  
  748.        Dim bytes() As Byte = Encoding.UTF8.GetBytes(value)
  749.        Dim hash() As Byte = algorithm.ComputeHash(bytes)
  750.  
  751.        Dim sb As New StringBuilder(length)
  752.  
  753.        ' Convert full bytes to hex, up to requested length.
  754.        For i As Integer = 0 To Math.Min((length \ 2) - 1, hash.Length - 1)
  755.            sb.Append(hash(i).ToString("X2"))
  756.        Next
  757.  
  758.        ' If length is odd, append the high nibble of the next byte.
  759.        If length Mod 2 = 1 AndAlso hash.Length > (length \ 2) Then
  760.            sb.Append((hash(length \ 2) >> 4).ToString("X"))
  761.        End If
  762.  
  763.        ' Pad with zeros if the hash is shorter than requested length.
  764.        Dim remaining As Integer = length - sb.Length
  765.        If remaining > 0 Then
  766.            sb.Append(New String("0"c, remaining))
  767.        End If
  768.  
  769.        Return sb.ToString()
  770.    End Function
  771.  
  772. #End Region
  773.  
  774. End Class
  775.  
  776. #End Region
  777.  
  778. #Region " Enumerations "
  779.  
  780. ''' <summary>
  781. ''' Specifies flags that allows to automatically append extra information to the
  782. ''' settings storage folder name specified by <see cref="FlexibleSettingsProvider.DirectoryName"/> property.
  783. ''' </summary>
  784. <Flags>
  785. Public Enum SettingsDirectoryNameFlags
  786.  
  787.    ''' <summary>
  788.    ''' No additional information is appended to the directory name.
  789.    ''' </summary>
  790.    None = 0
  791.  
  792.    ''' <summary>
  793.    ''' Appends the current application name to the directory name.
  794.    ''' </summary>
  795.    ApplicationName = 1 << 0
  796.  
  797.    ''' <summary>
  798.    ''' Appends the current assembly name to the directory name.
  799.    ''' </summary>
  800.    AssemblyName = 1 << 1
  801.  
  802.    ''' <summary>
  803.    ''' Appends the current application version to the directory name.
  804.    ''' </summary>
  805.    Version = 1 << 2
  806.  
  807.    ''' <summary>
  808.    ''' Appends a deterministic hash to the directory name.
  809.    ''' </summary>
  810.    Hash = 1 << 3
  811.  
  812.    ''' <summary>
  813.    ''' Appends the current user name to the directory name.
  814.    ''' </summary>
  815.    UserName = 1 << 4
  816.  
  817. End Enum
  818.  
  819. #End Region

El modo de empleo es muy sencillo.

Por un lado, tenemos el siguiente namespace con código auto-generado por el diseñador de forms, bien, esto NO DEBEMOS TOCARLO PARA NADA:

Código
  1. '------------------------------------------------------------------------------
  2. ' <auto-generated>
  3. '     This code was generated by a tool.
  4. '     Runtime Version:4.0.30319.42000
  5. '
  6. '     Changes to this file may cause incorrect behavior and will be lost if
  7. '     the code is regenerated.
  8. ' </auto-generated>
  9. '------------------------------------------------------------------------------
  10. Namespace My
  11.  
  12.    <Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(),  _
  13.     Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0"),  _
  14.     Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)>  _
  15.    Partial Friend NotInheritable Class MySettings
  16.        Inherits Global.System.Configuration.ApplicationSettingsBase
  17.  
  18.        ' ...
  19.    End Class
  20. End Namespace

En lugar de eso, simplemente añadiremos el siguiente código en cualquier otra parte de nuestro código fuente, estableciendo la clase de atributo SettingsProvider para asignar nuestro proveedor de configuración, y aplicando el valor que queramos para las propiedades del proveedor:

Código
  1. Namespace My
  2.  
  3.    <Global.System.Configuration.SettingsProvider(GetType(FlexibleSettingsProvider))>
  4.    Partial Friend NotInheritable Class MySettings
  5.  
  6.        Public Sub New()
  7.            FlexibleSettingsProvider.BaseDirectoryPath = ".\"
  8.            FlexibleSettingsProvider.DirectoryName = Nothing
  9.            FlexibleSettingsProvider.DirectoryNameFlags = SettingsDirectoryNameFlags.None
  10.            FlexibleSettingsProvider.FileName = "user.config"
  11.  
  12.            Debug.WriteLine($"Effective config file path: {FlexibleSettingsProvider.EffectiveConfigFilePath}")
  13.        End Sub
  14.  
  15.    End Class
  16. End Namespace

Con este ejemplo en específico, el archivo "user.config" se guardará en el directorio base de nuestra aplicación.



En c#, podemos replicar el mismo procedimiento, pero con la clase Settings como en el siguiente ejemplo:

Código
  1. namespace WindowsFormsApp1.Properties
  2. {
  3.    [SettingsProvider(typeof(FlexibleSettingsProvider))]
  4.    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
  5.    {
  6.        public Settings()
  7.        {
  8.            FlexibleSettingsProvider.BaseDirectoryPath = @".\";
  9.            FlexibleSettingsProvider.DirectoryName = null;
  10.            FlexibleSettingsProvider.DirectoryNameFlags = SettingsDirectoryNameFlags.None;
  11.            FlexibleSettingsProvider.FileName = "user.config";
  12.  
  13.            Debug.WriteLine($"Effective config file path: {FlexibleSettingsProvider.EffectiveConfigFilePath}");
  14.        }
  15.    }
  16. }

Por si todavía no ha quedado claro, sí, este código hace magía, tan solo necesitamos configurar la ruta del directorio y el nombre del archivo, y todo lo demás funcionará exactamente igual (o casi, casi igual) que como si estuvieramos dejando que la infraestructura de Microsoft gestione el directorio y el archivo de configuración para leer y escribir en él, pero evitando que se generen mil y una carpetas tras cada pequeña actualización de nuestra aplicación.

 9 
 en: 18 Enero 2026, 15:04 pm 
Iniciado por Novedades - Último mensaje por Novedades
SI pulso las 3 teclas ctrl alt spr salen las opciones de siempre:

bloquear/cambiar usuario/cerrar sesion/cambiar contra/admin tareas...

pero desde hace 2 dias cuando hago esto el fondo con las opciones que menciono es negro, y antes salian las mismas opciones pero no con el fondo negro....alguien sabe si es normal o como puedo dejarlo como antes ?

Saludos

 10 
 en: 18 Enero 2026, 02:04 am 
Iniciado por El_Andaluz - Último mensaje por El_Andaluz


Trump se ríe de Europa por el envío de tropas a Groenlandia: “Su defensa son dos perros y un trineo”




¿Cuántas personas había a la 1:00 de la tarde, en la calle, a cero grados? Un análisis conservador sugiere entre 7.000 y 8.000. Posiblemente, más. Todos ellos, coreando repetidamente esta frase: "Kalaalit nunaaat kalaallit pigaat". O sea: "Groenlandia es de los groenlandeses". Todos, bajo un mar de banderas rojiblancas de ese territorio, y de pequeñas pancartas individuales, sobre todo con la leyenda 'Groenlandia no está en venta', aunque algunos dieron rienda suelta a su lado más creativo y se soltaron con frases como 'Hacer a Estados Unidos normal otra vez', 'Tu tierra no es donde tu avión aterriza".

Diversas pancartas con mensajes claros: 'Rutte, estás despedido', en referencia al Secretario General de la OTAN, el holandés Mark Rutte, que está adoptando una posición pública sorprendentemente ambivalente en relación a las ambiciones imperiales de Donald Trump.

Los manifestantes pasearon por calles empapeladas con pegatinas de la bandera de Groenlandia gracias a la alcaldesa de la ciudad, Avaaraq Olsen, que pertenece al partido de centroizquierda Inuit Ataqatigiit
("Solidaridad del Pueblo") y que se ha convertido súbitamente en la fuerza dominante en la isla gracias a un nacionalismo moderado y una posición de rechazo a los sueños expansionistas de Donald Trump.

La agresividad del presidente estadounidense no solo ha llevado al poder a partidos que mantienen una relación distante con Estados Unidos en Australia y en Canadá, sino incluso en Groenlandia. De hecho, la manifestación empezó con una proclama que hubiera hecho rechinar los dientes a Trump y, sobre todo, a su vicepresidente, JD Vance, que está obsesionado con la decadencia de Europa y considera al Reino Unido un país "musulmán". "Esta es una protesta pacífica. Cualquier acción violenta, racista o discriminatoria será denunciada a la policía", dijo en danés, groenlandés e inglés a una de las organizadoras del acto.

A continuación, se guardó un minuto de silencio, se leyó un poema, y se cantó el himno groenlandés. Un himno que pese al extendido sentimiento independentista en la isla, no parece que sea muy conocido por sus habitantes. De lo contrario, la organización no hubiera tenido que recordar a los miles de asistentes que podían encontrar la letra en la página de Facebook de la marcha.

Encima, Groenlandia tiene dos himnos nacionales: el establecido hace 110 años por Dinamarca, "Nunarput utoqqarsuanngoravit" ("Nuestra vieja Tierra") y el que llegó en 1979, con la cuasi-independencia, "Nuna Asiladooq" ("La Gran Tierra"), de carácter independentista y fuertemente pro-kalaalit, que es el nombre de la población aborigen de la isla. Evidentemente, el que se entonó ayer, sábado, fue el segundo.






Y que dice Rusia de todo esto:

Rusia se ríe de la intención de Europa de defender Dinamarca: "Se cagarán en los pantalones y entregarán Groenlandia"


El vicepresidente del consejo de Seguridad de Rusia, Dmitri Medvédev acaba de tuitear desde la red social X riéndose de Europa, de Francia y su presidente, Emmanuel Macron a raíz de su defensa de Groenlandia ante las aspiraciones anexionistas del presidente de Estados Unidos (EEUU), Donald Trump. Medvédev ha escrito que la UE no hará nada y que solo se "cagarán en los pantalones y entregarán Groenlandia".

"El gallo galo ha cantado que, si se afecta la soberanía de Dinamarca, las consecuencias serían sin precedentes. ¡Uy! ¿Qué harán? ¿Secuestrar al presidente? ¿Atacarlo nuclearmente? Claro que no. Se cagarán en los pantalones y entregarán Groenlandia. Y eso sería un gran precedente europeo", ha escrito Medvédev.

En la televisión más cercana al presidente ruso, Vladimir Putin, han dicho: "¿Estaríamos dispuestos a ayudar a Trump para liberar Groenlandia de la influencia de un agente extranjero? ¿Por qué no?". Estas son las palabras de un propagandista ruso que, directamente, abre un hipotético apoyo de Rusia a Trump para echar a Europa de Groenlandia.

Mientras, Putin observa este nuevo clima de tensión internacional. En caso de un enfrentamiento militar o una situación de tensión directa entre Dinamarca y Groenlandia con EEUU sería el fin de la OTAN, el sueño dorado de Putin, que vería desaparecer a su principal enemigo. Además, las presiones de Trump sobre Groenlandia están distrayendo la atención de la guerra de invasión que sigue llevando a cabo contra Ucrania, una guerra que se acerca ya a concluir su cuarto año.

Lo más relevante para el presidente ruso, sin embargo, es que quedaría claro que el mundo está dividido en dos mitades: una para Trump y otra mitad para Putin.




Páginas: [1] 2 3 4 5 6 7 8 9 10
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines