Explorando la API de Windows en C++: Mi primer Valor de Registro utilizando las funciones RegCreateKeyEx y RegSetValueEx

TechDays-Figure-with-Laptop_7A06897A

Hace un tiempo empecé un pequeño proyecto personal en cuanto al contenido adicional en el blog referente a la API de Windows, iniciando por ahora en la exploración de las funciones referentes al Registro de Windows y el primer artículo tocó la de RegCreateKeyEx, mostrando cómo utilizarla en C++ para crear una simple clave de Registro. Todo esto con el fin de empezar a conocer un poco más cómo funciona realmente Windows y sacar provecho de esto.

Hoy me concentraré en otra de las funciones más utilizadas, la de RegSetValueEx, agregando que como verla sola queda un poco incompleto el proceso, la uniré con la de RegCreateKeyEx para dar un poco más de valor al post.

*Nota: Cabe aclarar que el siguiente contenido lo estoy haciendo bajo una perspectiva de novato y aprendiz, por lo que tal vez puedan encontrar errores; pero la intención, como dije en el post pasado, es generar mi propia biblioteca de contenido en español y de la forma más clara que pueda.

La función RegSetValueEx

Si nos vamos atrás, y recordamos La Estructura del Registro de Windows como nos indica la documentación oficial, la información está dividida o estructura en un formato de árbol, y cada uno de los nodos que lo componen (HKCR, HKCU, HKLM, HKU, HKCC) se les conoce como Claves (Keys); cada Clave a su vez, contiene toda una estructura interna que se les referencia como Sub-claves (Subkeys), que pueden contener entradas de datos reconocidas como Valores (Values). Éstos últimos pueden ser creados por la función RegSetValueEx, y por lo general pueden tener diferentes tipos de contenidos, como por ejemplo: Binarios, Cadenas, de tipo DWORD, entre otros. El tipo de valor a crear dependerá del objetivo de la operación o información que Windows vaya a tomar de él. Por lo general, uno de los más famosos y comunes es el valor de tipo entero de 32 bits DWORD.

La documentación oficial de esta función nos dice que debemos crear las siguientes variables de entrada o salida que serán utilizadas:

HKEY hKey: Como en la mayoría de las funciones de Registro, es solo un apuntador a una clave abierta, aunque en este caso, es necesario tener en cuenta que deben genera derechos de acceso de KEY_SET_VALUE si es que se retorna con la función de RegCreateKeyEx.

Por supuesto, podemos utilizar también las Claves predefinidas que pertenecen al árbol de Registro:

HKEY_CLASSES_ROOT

HKEY_CURRENT_CONFIG

HKEY_CURRENT_USER

HKE_LOCAL_MACHINE

HKEY_USERS 

LPCTSTR lpValueName: No es más que el nombre del valor que se desea establecer.

DWORD Reserved: Como en la anterior función, es un parámetro reservado y siempre debe ser cero ( 0 ).

DWORD dwType: Es el tipo de valor que se va a generar. Toda la lista disponible está en este artículo de MSDN:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx

const BYTE *lpData: En términos básicos, aquí va el contenido que se va a establecer, y por eso hace referencia a un arreglo de BYTES. Suele ser –por lo menos en mi propio caso- la variable más difícil de interpretar, sobre todo si se crea y declara desde el principio como arreglo.

*Nota: Tengamos en cuenta que la declaración de lpData puede variar mucho dependiendo del tipo de valor que vamos a crear. Por ejemplo, si fuese un DWORD, podríamos simplemente declararlo como tal y referenciarlo en la función, o como en este caso, un valor de tipo REG_SZ, tendríamos que enviarle el contenido creando un array de tipo TCHAR, etc, etc.

DWORD cbData: Es el tamaño de la información pasado por la variable lpData. Lo normal aquí es utilizar la función sizeof para que Windows se encargue del trabajo.

*Importante: Para tener más claridad sobre la declaración general de la función RegSetValueEx, pueden ver el siguiente artículo de Juan Carlos Ruiz (Technical Evangelist, Microsoft Colombia) que muy amablemente me aclaró muchísimas dudas mientras pasaba por el primer enfrentamiento:

http://blogs.msdn.com/b/juank/archive/2013/07/27/un-vistazo-a-la-funcion-de-regsetvalueex-de-la-api-de-windows.aspx?v=2

Teniendo todo lo anterior presente, si en mi proyecto de C++ fuese a crear un Valor llamado DemoValue,  tipo DWORD 32 bits, de contenido “1” y en la clave HKEY_CURRENT_USER, la declaración sería algo así:

//Declaración de variables necesarias para RegSetValueEx

    HKEY hKey = HKEY_CURRENT_USER;
    LPCTSTR lpValueName = L"DemoValue";
    DWORD Reserved = 0;
    DWORD dwType = REG_DWORD;
    DWORD lpData = 1;
    DWORD cbData = sizeof(lpData);

En la función después, bastaría con indicar cada variable declarada en su lugar, por ejemplo, para el mismo Valor anterior, quedaría así:

long R = RegSetValueEx(hKey, lpValueName, Reserved,
                  dwType, (const BYTE *)&lpData, cbData);

Todo se devuelve a un valor llamado “R” de tipo long, con el objetivo de poder trabajar sobre el resultado de la operación, pues si no hay problema, el valor retornante sería: ERROR_SUCCESS y con esto podría proceder con otras especificaciones dentro del código.

Ahora, el único problema, es que si sólo utilizamos la función RegSetValueEx, no habrá forma de crear el Valor por fuera de las Claves predefinidas, por ejemplo, si el valor DemoValue no se quiere escribir en HKCU, sino en HKEY_CURRENT_USERDemoKey, sería imposible, pues la función sólo aceptará las predefinidas, o bien, un apuntador a alguna clave abierta por la función RegCreateKeyEx. Para hacerlo más interesante, y suplir la necesidad primordial de escribir en las Sub-claves veamos cómo podemos combinar la función RegCreateKeyEx vista en el primer post de esta serie, con RegSetValueEx:

RegCreateKeyEx y RegSetValueEx, mejor juntas

Pues bien, lo que haremos será simplemente tomar ventaja de lo aprendido con la función RegCreateKeyEx para crear una sub-clave de registro, y en esa sub-clave, escribir el respectivo Valor y contenido con la función de este post, RegSetValueEx.

Primero, recordemos que todo proyecto de Win32 debe tener como cabecera <Windows.h>, y como función principal WinMain, siguiendo esta declaración:

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow){
};

A continuación, y para estar todos en el mismo contexto, crearemos como ejemplo una nueva sub-clave llamada DemoKey, dentro de InsideWindows, que se creará con la misma función en la clave de HKEY_CURRENT_USER. En una línea, sería:

HKEY_CURRENT_USERInsideWindowsDemoKey

En la sub-clave DemoKey, crearemos nuestro valor llamado DemoValue, de tipo REG_SZ (Para variar un poco el ejemplo dado por Juan Carlos), es decir, String y le daremos como contenido %SystemDrive%UsersDemo para simular un directorio real de Windows. La línea completa, con la sub-clave, quedaría:

HKEY_CURRENT_USERInsideWindowsDemoKeyDemoValue

Para no repetir lo mismo del artículo anterior, pasemos directamente a la declaración de las primeras variables necesarias para RegCreateKeyEx, que con la información anterior sería:

HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = L"InsideWindows\DemoKey";
DWORD Reserved = 0;
LPTSTR lpClass = NULL;
DWORD dwOptions = REG_OPTION_NON_VOLATILE;
REGSAM samDesired = KEY_SET_VALUE;
LPSECURITY_ATTRIBUTES lpSecurityAtrributes = NULL;
HKEY phkResult;
DWORD lpdwDisposition;

Pasando a la declaración necesaria para RegSetValueEx, con la información anterior, sería:

LPCTSTR lpValueName = L"DemoValue";
DWORD dwType = REG_SZ;
TCHAR lpData[]=TEXT("%SystemDrive%\Users\Demo");
DWORD cbData = sizeof(lpData);

*Nota: Pueden notar que falta hKey y Reserved para la segunda declaración, pero como es el mismo contenido de los que se necesitan para RegCreateKeyEx, sobra volverlos a declarar, así que basta con usarlos nuevamente en la segunda función.

Procedemos entonces a crear la sub-clave referenciando todas las variables declaradas:

//Declarando la función "RegCreateKeyEx".
    RegCreateKeyEx(hKey,
        lpSubKey, Reserved, lpClass,
        dwOptions, samDesired, lpSecurityAtrributes,
        &phkResult, &lpdwDisposition);

Teniendo presente que lpdwDisposition devuelve el resultado de la sub-clave que se creó o se abrió, lo ideal es utilizar esto para dar paso a que Windows escriba el respectivo valor utilizando una sencilla, pero útil sentencia de condición: If. Debemos controlar REG_CREATED_NEW_KEY y REG_OPENED_EXISTING_KEY en una misma pregunta, pues en ambos casos el valor se crea. La condición sería:

if (lpdwDisposition == REG_CREATED_NEW_KEY ||
        lpdwDisposition == REG_OPENED_EXISTING_KEY){

Dado esto, generamos el valor con la siguiente función, referenciando también todas las variables ya declaradas dentro del condicional:

long R = RegSetValueEx(phkResult, lpValueName, Reserved,
                          dwType, (const BYTE *)&lpData, cbData);

*Nota: Como ven, el primer parámetro, que debe ser de tipo HKEY, le estoy enviando phkResult, que contiene el apuntador a la clave que se creó o se abrió, para que el valor se escriba donde debe ser.

Después, si queremos darle un poco de más interés a la mini aplicación, según el resultado que entrega RegSetValueEx, podremos mostrar un Mensaje que nos confirme o deniegue la creación del valor y cerrar el primer If:

if (R == ERROR_SUCCESS){

            MessageBox(NULL, L"El valor se creó correctamente.",
                L"Explorando la API", MB_ICONINFORMATION);
        }
        else{

            MessageBox(NULL, L"Error creando el valor.",
                L"Explorando la API", MB_ICONERROR);

        }

    } //Cierra primer "If".

Por último, debemos controlar –aunque sea en principio con un error genérico- el hecho de que la sub-clave en principio podría no crearse con un “else”:

else //Condicional "Sino" para el primer "If".
    {
        MessageBox(NULL, L"Error creando la clave",
L"Explorando la API", MB_ICONERROR); }

Recordemos además que todo trabajo que se hace sobre una clave o sub-clave debe cerrarse con la función RegCloseKey, utilizando la misma variable de phkResult, así:

RegCloseKey(phkResult); //Cierra la clave

Los que deseen, pueden descargar todo el proyecto listo de Visual Studio desde aquí:

Enlace de SkyDrive: http://sdrv.ms/13R6Kyz

El resultado

Probando todo el código anterior, en caso de ser satisfactoria la creación de la clave y el respectivo valor, podríamos ver el siguiente mensaje al ejecutar el programa:

image

En el Registro de Windows, este sería el resultado:

image

Process Monitor nos confirmaría toda la operación en caso de que siguiéramos la ejecución de la aplicación:

image

Espero les sea de utilidad. ¡Comentarios bienvenidos!

Saludos,

Checho

Una respuesta a “Explorando la API de Windows en C++: Mi primer Valor de Registro utilizando las funciones RegCreateKeyEx y RegSetValueEx”

Responder a anonymous Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *