There are P4GL functions for setting and getting registry information. I am not familiar with those P4GL functions so it may be silly to use Windows functions instead.
One thing the P4GL can not do is accessing (hexa)decimal data.
Before you try to access the registry directly you should try to find some specialized API call for the requested information type.
For example:
You can read a list of available printers from the registry, but you can also use the EnumPrinters API function for this task. It is generally speaking better to use the API function, because these are documented while the exact registry-locations are not. The EnumPrinters example is only one example. I don't know, but I guess there are documented functions for everything in the registry.
The point is, I think you should try to find an API function before you start digging in the registry directly. Unless of course you are writing and reading in your own key.
Suppose there is a registry key
HKEY_LOCAL_MACHINE\Software\Nerdware\Test
and suppose it contains a DWORD value, named "count".
This source example will read the value of "count", identifies the datatype, and increment the value of "count" by one.
{windows.i} /* March 28, 1998 or later */ DEFINE VARIABLE key-hdl AS INTEGER NO-UNDO. DEFINE VARIABLE lpBuffer AS MEMPTR NO-UNDO. DEFINE VARIABLE lth AS INTEGER NO-UNDO. DEFINE VARIABLE reslt AS INTEGER NO-UNDO. DEFINE VARIABLE datatype AS INTEGER NO-UNDO. DEFINE VARIABLE icount AS INTEGER NO-UNDO. RUN RegOpenKeyA IN hpApi ( {&HKEY_LOCAL_MACHINE}, "Software\Nerdware\Test", OUTPUT key-hdl, OUTPUT reslt). IF reslt NE {&ERROR_SUCCESS} THEN DO: MESSAGE "key not found in registry" VIEW-AS ALERT-BOX. RETURN. END. /* read value of "count" into lpBuffer */ /* make buffer large, because we don't know for sure if it is really a DWORD. The maximum size is supposed to be MAX_PATH + 1 */ ASSIGN lth = {&MAX_PATH} + 1 SET-SIZE(lpBuffer) = lth. RUN RegQueryValueExA IN hpApi (key-hdl, "count", 0, /* reserved, must be 0 */ OUTPUT datatype, GET-POINTER-VALUE(lpBuffer), INPUT-OUTPUT lth, OUTPUT reslt). IF reslt NE {&ERROR_SUCCESS} THEN MESSAGE "value not found in registry" VIEW-AS ALERT-BOX. ELSE DO: CASE datatype : WHEN 1 THEN MESSAGE "datatype=STRING" SKIP "value=" GET-STRING(lpBuffer,1) VIEW-AS ALERT-BOX. WHEN 4 THEN MESSAGE "datatype=DWORD" SKIP "value=" GET-LONG(lpBuffer,1) VIEW-AS ALERT-BOX. OTHERWISE MESSAGE "unexpected datatype:" SKIP "datatype=" datatype SKIP VIEW-AS ALERT-BOX. END CASE. /* if it is a DWORD, then increment the value */ IF datatype=4 THEN DO: icount = GET-LONG(lpBuffer,1). SET-SIZE(lpBuffer) = 4. /* =sizeof(DWORD) */ PUT-LONG(lpBuffer,1) = icount + 1. RUN RegSetValueExA IN hpApi (key-hdl, "count", INPUT 0, /* reserved, must be 0 */ INPUT 4, /* = REG_DWORD */ INPUT GET-POINTER-VALUE(lpBuffer), INPUT 4, /* = get-size(lpBuffer) */ OUTPUT reslt). IF reslt NE {&ERROR_SUCCESS} THEN MESSAGE "can not write value in registry" VIEW-AS ALERT-BOX. END. END. SET-SIZE(lpBuffer)=0. RUN RegCloseKey IN hpApi (key-hdl,OUTPUT reslt).
function RegSetValueEx will create the value "count" if it did not exist yet. So even if RegQueryValue did not find the value, you can still set one. Of course you will have to change the logic of this source example to allow that.
There are more datatypes than just REG_SZ (=1) and REG_DWORD (=4). Check your API documentation for a complete list.
This example enumerates all values in a given registry key.
In this case, it will return a list of all installed printers (with their names and ports), so it actually does the same as the EnumPrinters function.
As explained in the registry introduction you should prefer to use the EnumPrinters function instead of this RegEnumA stuff, because Microsoft may decide to store the printers info elsewhere in the future, while the EnumPrinters API will be maintained.
{windows.i} /* March 28, 1998 or later */ DEFINE VARIABLE hKey AS INTEGER NO-UNDO. DEFINE VARIABLE hPrinterkey AS INTEGER NO-UNDO. DEFINE VARIABLE subkey AS CHARACTER NO-UNDO. DEFINE VARIABLE port AS MEMPTR NO-UNDO. DEFINE VARIABLE lth AS INTEGER NO-UNDO. DEFINE VARIABLE reslt AS INTEGER NO-UNDO. DEFINE VARIABLE datatype AS INTEGER NO-UNDO. DEFINE VARIABLE ITEM AS INTEGER NO-UNDO. RUN RegOpenKeyA IN hpApi( {&HKEY_LOCAL_MACHINE}, "System\CurrentControlSet\control\Print\Printers", OUTPUT hKey, OUTPUT reslt). ASSIGN ITEM = 0 reslt = 0. DO WHILE reslt NE {&ERROR_NO_MORE_ITEMS} : ASSIGN lth = {&MAX_PATH} + 1 subkey = FILL("x", lth). RUN RegEnumKeyA IN hpApi (hKey, ITEM, OUTPUT subkey, INPUT LENGTH(subkey), OUTPUT reslt). IF reslt NE {&ERROR_NO_MORE_ITEMS} THEN DO: /* get the printer port (or description..) */ RUN RegOpenKeyA IN hpApi ( hKey, subkey, OUTPUT hPrinterkey, OUTPUT reslt). lth = {&MAX_PATH} + 1. SET-SIZE(port) = lth. RUN RegQueryValueExA IN hpApi (hPrinterkey, "port", 0, /* reserved, must be 0 */ OUTPUT datatype, GET-POINTER-VALUE(port), INPUT-OUTPUT lth, OUTPUT reslt). RUN RegCloseKey IN hpApi (hPrinterkey,OUTPUT reslt). MESSAGE "printer name=" subkey SKIP "port=" GET-STRING(port,1) VIEW-AS ALERT-BOX. END. ITEM = ITEM + 1. END. /* do while not ERROR_NO_MORE_ITEMS */ SET-SIZE(port)=0. RUN RegCloseKey IN hpApi (hKey,OUTPUT reslt).
Obviously a (sub)key may contain values with different datatypes, like strings and numbers. You should test the 'datatype' parameter before you interpret a value. For an example of this, see RegQueryValueEx
Function RegCreateKeyEx creates a registry key and opens it. If the key already exists, the function will just open it.
{windows.i} &SCOPED-DEFINE KEY_ALL_ACCESS 983103 &SCOPED-DEFINE REG_OPTION_NON_VOLATILE 0 &SCOPED-DEFINE REG_OPTION_VOLATILE 1 &SCOPED-DEFINE REG_CREATED_NEW_KEY 1 &SCOPED-DEFINE REG_OPENED_EXISTING_KEY 2 PROCEDURE RegCreateKeyEx{&A} EXTERNAL {&ADVAPI} : DEFINE INPUT PARAMETER hkey AS LONG. DEFINE INPUT PARAMETER lpszSubKey AS CHARACTER. DEFINE INPUT PARAMETER dwReserved AS LONG. DEFINE INPUT PARAMETER plszClass AS CHARACTER. DEFINE INPUT PARAMETER dwOptions AS LONG. DEFINE INPUT PARAMETER samDesired AS LONG. DEFINE INPUT PARAMETER lpSecurityAttributes AS LONG. DEFINE OUTPUT PARAMETER phkResult AS LONG. DEFINE OUTPUT PARAMETER lpdwDisposition AS LONG. DEFINE RETURN PARAMETER lpResult AS LONG. END PROCEDURE. /* example : */ DEFINE VARIABLE key-hdl AS INTEGER NO-UNDO. DEFINE VARIABLE dwDisposition AS INTEGER NO-UNDO. DEFINE VARIABLE reslt AS INTEGER NO-UNDO. RUN RegCreateKeyEx{&A} IN /* hpApi */ THIS-PROCEDURE ( {&HKEY_CLASSES_ROOT}, "SoftWare\MyCompany", 0, '':U, {®_OPTION_NON_VOLATILE}, {&KEY_ALL_ACCESS}, 0, OUTPUT key-hdl, OUTPUT dwDisposition, OUTPUT reslt). IF reslt NE 0 THEN MESSAGE "function RegCreateKeyEx failed" VIEW-AS ALERT-BOX. ELSE CASE dwDisposition : WHEN {®_CREATED_NEW_KEY} THEN MESSAGE "created new key" VIEW-AS ALERT-BOX. WHEN {®_OPENED_EXISTING_KEY} THEN MESSAGE "opened existing key" VIEW-AS ALERT-BOX. END. /* use the key */ .... /* close it */ RUN RegCloseKey IN hpApi (key-hdl, OUTPUT reslt).
The example creates key "Software\MyCompany" or opens it if the key already exists.
Variable key-hdl returns a handle to the open key. This handle can be used in subsequent functions and must eventually be closed by function RegCloseKey.