diff --git a/configure b/configure index a83b473ed5f..79d4c8bda86 100755 --- a/configure +++ b/configure @@ -4643,6 +4643,7 @@ programs/avitools/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regtest/Makefile +programs/regapi/Makefile programs/view/Makefile programs/winhelp/Makefile programs/winver/Makefile @@ -4806,6 +4807,7 @@ programs/avitools/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regtest/Makefile +programs/regapi/Makefile programs/view/Makefile programs/winhelp/Makefile programs/winver/Makefile diff --git a/configure.in b/configure.in index e2fa92353b9..536f2fad76b 100644 --- a/configure.in +++ b/configure.in @@ -668,6 +668,7 @@ programs/avitools/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regtest/Makefile +programs/regapi/Makefile programs/view/Makefile programs/winhelp/Makefile programs/winver/Makefile diff --git a/programs/Makefile.in b/programs/Makefile.in index aa0b4f2b36c..a6b80b6668e 100644 --- a/programs/Makefile.in +++ b/programs/Makefile.in @@ -5,6 +5,7 @@ SUBDIRS = \ control \ notepad \ progman \ + regapi \ regtest \ view \ winhelp \ diff --git a/programs/regapi/.cvsignore b/programs/regapi/.cvsignore new file mode 100644 index 00000000000..be405f53ac6 --- /dev/null +++ b/programs/regapi/.cvsignore @@ -0,0 +1,2 @@ +Makefile +regapi diff --git a/programs/regapi/Makefile.in b/programs/regapi/Makefile.in new file mode 100644 index 00000000000..885a01396b6 --- /dev/null +++ b/programs/regapi/Makefile.in @@ -0,0 +1,32 @@ +DEFS = -DWINELIB +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = none +PROGRAMS = regapi +ALL_LIBS = $(WINELIB) $(X_LIBS) $(XLIB) $(LIBS) +RCFLAGS = -w32 -h +WRCEXTRA = -A -p $* + +C_SRCS = \ + regapi.c + +all: $(PROGRAMS) + +depend:: + +@MAKE_RULES@ + +regapi: $(OBJS) + $(CC) -o regapi $(OBJS) $(LDOPTIONS) $(ALL_LIBS) + +install: dummy + $(INSTALL_PROGRAM) regapi $(bindir)/regapi + +uninstall: dummy + $(RM) $(bindir)/regapi + +dummy: + +### Dependencies: diff --git a/programs/regapi/README b/programs/regapi/README new file mode 100644 index 00000000000..2c82fe02679 --- /dev/null +++ b/programs/regapi/README @@ -0,0 +1,89 @@ + +Registry Command Line API Tool +------------------------------ + + This progam is intended to fill a particular need. I needed to make the + wine registry look like it would have been if my application would have + been installed by its installation program. Since this was not possible I + took the following approach. + + 1 - Use regedit to export my full Windows registry before I install my + application. + + 2 - Use regedit to export my full Windows registry after I had install my + application. + + 3 - Generate the differences between the two image. What I obtain from the + diff is what I need to apply to the wine registry. + + Obvisouly the process is not that straight forward to solve, first, + you don't get the diff between two Windows regedit exported .reg file by + doing a simple diff. What I had to do is a little more complex, but not + that much... + + (Assuming that the registry picture files are + named ./before.reg and ./after.reg) + + 1 - Parse the before.reg and after.reg file into regFixer.pl, in order to + obtain lines in the form [HKEY\Sub1\Sub2\...\Subn]"Value"="Data" + (where "Data" can be prefixed by the type identifyer : hex:, hex(0000000?) + or dword:) + + 2 - Generate the diff between the before.reg.fix and after.reg.fix + into app.diff + + Now we have a app.reg file that contain what has been done by installing the + application. To this we extract the part's that we are interested in using + grep (and fix it with sed) and put that into app.added by example + ( let say we keep the added values only ). + + At this point we know which registry entry to add to the wine registry. It + only remains to take the format we have and reset it into a format similar + to the one we get from regedit. + + I say "similar" because there is a tiny difference between Windows regedit + export format and the format actualy required by the tool. + + The problem with this (and it is not a big one) is that regedit export long + data streams onto many lines, and since I dont have tons of time I setup + another Perl script (regRestorer.pl) that fixes this (this could easily + be done in C obviously) (left as excercise ;-) ). + + So, once you parsed app.added into regRestorer.pl you get a app.reg ready to + process by regapi. + + So, this package comes with a few pieces: + + regFixer.pl - Will convert the export of regedit + into something "diff-able" + + regRestorer.pl - Will convert "cleaned" diff file into + something "regapi-able" + + regSet - Will do the procedure explained herein + for the added key only. + + +FAQ +--- + + Quick Start Guide + ----------------- + 1 - Get a snapshot of your windows registry in before.reg, (regedit/export) + 2 - Install you're application, + 3 - Get a snapshot of your windows registry in after.reg. + 4 - Invoke ./regSet.sh before.reg after.reg + + + Adding key I have in a regedit export file (nothing to diff with...) + ------------------------------------------ + 1 - Invoke ./regSet.sh /dev/null myRegistry.reg + + regapi help + ----------- + 1 - regapi has some sort of "man page like" help in it, simply invoke it + without any arguments. + +Hope this is of any use to you. + +Sylvain St-Germain. diff --git a/programs/regapi/regFixer.pl b/programs/regapi/regFixer.pl new file mode 100755 index 00000000000..62a030bfaa7 --- /dev/null +++ b/programs/regapi/regFixer.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +# This script takes as STDIN an output from the Registry +# (export from regedit.exe) and prefixes every subkey-value +# pair by their hkey,key data member +# +# Copyright 1999 Sylvain St-Germain +# + +${prefix} = ""; +${line} = ""; + +LINE: while(<>) { + chomp; # Get rid of 0x0a + chop; # Get rid of 0x0d + + next LINE if(/^$/); # This is an empty line + + if( /^\[/ ) { + ${prefix} = ${_}; # assign the prefix for the forthcomming section + next LINE; + } + s/\\\\/\\/g; # Still some more substitutions... To fix paths... + + s/^ //; # Get rid of the stupid two spaces at the begining + # they are there in the case of a multi-line thing + + if (/\\$/) { # The line ends with '\', it means it is a multi + s/\\$//; # line thing, remove it. + + ${line} = "${line}${_}";# Add the current line to the line to output + next LINE; # process the next line + } + + ${line} = "${line}${_}"; # Set line to the multi line thing+the current line + + print "${prefix}${line}\n"; + ${line} = ""; # start over... +} + + + diff --git a/programs/regapi/regRestorer.pl b/programs/regapi/regRestorer.pl new file mode 100755 index 00000000000..02525e43761 --- /dev/null +++ b/programs/regapi/regRestorer.pl @@ -0,0 +1,51 @@ +#!/usr/bin/perl + +# This script takes as STDIN an output from the regFixer.pl +# and reformat the file as if it would have been exported from the registry +# +# Note: the output file is not exactly the one we get when exporting from +# regedit, the tiny difference is that multilines (which were +# single-linized by regFixer.pl) values are not re-multi-linized by +# this script. +# +# Copyright 1999 Sylvain St-Germain +# + +${newkey} = ""; +${key} = ""; +${data} = ""; + +# I do not validate the integrity of the file, I am assuming that +# the input file comes from the output of regFixer.pl, therefore things +# should be ok, if they are not, investigate and send me an email... + +LINE: while(<>) { + chomp; # get rid of new line + + next LINE if(/^$/); # This is an empty line + + (${key}, ${data}, ${rest})= split /]/,$_ ; # Extract the values from the line + + ${key} = "${key}]"; # put the ']' back there... + + if (${rest} ne "") # concat we had more than 1 ']' + { # on the line + ${data} = "${data}]${rest}"; + } + + if (${key} eq ${newkey}) + { + print "${data}\n"; + } + else + { + ${newkey} = ${key}; # assign it + + print "\n"; + print "${key}\n"; + print "${data}\n"; + } +} + + + diff --git a/programs/regapi/regSet.sh b/programs/regapi/regSet.sh new file mode 100755 index 00000000000..a4e26ae98b3 --- /dev/null +++ b/programs/regapi/regSet.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# This script is the receipe to generate the key that have to be created like +# if an applicaiton was installed by its installer. It processes using a +# registry based on the picture of the registry before the application is +# installed and the picture of the registry after the application is installed. +# +# Copyright 1999 Sylvain St-Germain +# + +if [ $# -ne 2 ]; then + echo "$0 Usage: " + echo " You must provide 2 arguments." + echo " 1 - Registry output before the application's installation." + echo " 2 - Registry output after the application's installation." + echo + exit 1 +fi + +echo "Assuming that $1 is the \"before\" file..." +echo "Assuming that $2 is the \"after\" file..." + +# +# do not attempt to regFix.pl /dev/null ... +# +echo "Fixing exported registry files..." +if [ $1 != "/dev/null" ]; then + cat $1 | ./regFixer.pl > $1.fix +fi + +cat $2 | ./regFixer.pl > $2.fix + +# +# diff accordingly depending on /dev/null +# +echo "Diffing..." +if [ $1 != "/dev/null" ]; then + diff $1.fix $2.fix > $2.diff +else + diff /dev/null $2.fix > $2.diff +fi +# +# Keep only added lines +# +echo "Grepping keys to add and generating cleaned fixed registry file." +cat $2.diff | grep '^> ' | sed -e 's/^> //' > $2.toAdd + +# +# Restore the file format to the regedit export 'like' format +# +echo "Restoring key's in the regedit export format..." +cat $2.toAdd | ./regRestorer.pl > $2.toAdd.final + +echo "Cleaning..." +rm $1.fix $2.fix >/dev/null 2>&1 +rm $2.diff >/dev/null 2>&1 +rm $2.toAdd >/dev/null 2>&1 +mv $2.toAdd.final $2.toAdd + +echo "Operation completed, result file is $2.toAdd" + +exit 0 diff --git a/programs/regapi/regapi.c b/programs/regapi/regapi.c new file mode 100644 index 00000000000..59c74d36df4 --- /dev/null +++ b/programs/regapi/regapi.c @@ -0,0 +1,983 @@ +/* + * Command line Registry implementation + * + * Copyright 1999 Sylvain St-Germain + * + * Note: Please consult the README file for more information. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines and consts + */ +#define IDENTICAL 0 +#define COMMAND_COUNT 5 + +#define KEY_MAX_LEN 1024 +#define STDIN_MAX_LEN 2048 + +/* Return values */ +#define COMMAND_NOT_FOUND -1 +#define SUCCESS 0 +#define NOT_ENOUGH_MEMORY 1 +#define KEY_VALUE_ALREADY_SET 2 +#define COMMAND_NOT_SUPPORTED 3 + +/* Generic global */ +static BOOL bForce = FALSE; /* Is set to TRUE when -force is + passed on the command line */ + +/* Globals used by the api setValue, queryValue */ +static LPSTR currentKeyName = NULL; +static HKEY currentKeyClass = NULL; +static HKEY currentKeyHandle = NULL; +static BOOL bTheKeyIsOpen = FALSE; + +/* Delimitors used to parse the "value"="data" pair for setValue*/ +#define SET_VALUE_MAX_ARGS 2 +/* Delimitors used to parse the "value" to query queryValue*/ +#define QUERY_VALUE_MAX_ARGS 1 + +static const char *setValueDelim[SET_VALUE_MAX_ARGS] = {"=", ""}; +static const char *queryValueDelim[QUERY_VALUE_MAX_ARGS] = {""}; + +/* Array used to extract the data type from a string in getDataType. */ +typedef struct tagDataTypeMap +{ + char mask[15]; + DWORD dataType; +} dataTypeMap; + +static const dataTypeMap typeMap[] = +{ + {"hex:", REG_BINARY},/* could be REG_NONE (?) */ + {"dword:", REG_DWORD}, + {"hex(0):", REG_NONE}, + {"hex(1):", REG_SZ}, + {"hex(2):", REG_EXPAND_SZ}, + {"hex(3):", REG_BINARY}, + {"hex(4):", REG_DWORD}, + {"hex(5):", REG_DWORD_BIG_ENDIAN}, + {"hex(6):", REG_LINK}, + {"hex(7):", REG_MULTI_SZ}, + {"hex(8):", REG_RESOURCE_LIST}, + {"hex(9):", REG_FULL_RESOURCE_DESCRIPTOR}, + {"hex(80000000):", REG_NONE}, + {"hex(80000001):", REG_SZ}, + {"hex(80000002):", REG_EXPAND_SZ}, + {"hex(80000003):", REG_BINARY}, + {"hex(80000004):", REG_DWORD}, + {"hex(80000005):", REG_DWORD_BIG_ENDIAN}, + {"hex(80000006):", REG_LINK}, + {"hex(80000007):", REG_MULTI_SZ}, + {"hex(80000008):", REG_RESOURCE_LIST}, + {"hex(80000009):", REG_FULL_RESOURCE_DESCRIPTOR}, + {"hex(8000000a):", REG_BINARY}, /* REG_RESOURCE_REQUIREMENTS_LIST}, !Exist */ + {"hex(8000000A):", REG_BINARY}, /* REG_RESOURCE_REQUIREMENTS_LIST}, !Exist */ +}; +const static int LAST_TYPE_MAP = sizeof(typeMap)/sizeof(dataTypeMap); + + +/* + * Forward declaration + */ +typedef void (*commandAPI)(LPSTR lpsLine); + +static void doSetValue(LPSTR lpsLine); +static void doDeleteValue(LPSTR lpsLine); +static void doCreateKey(LPSTR lpsLine); +static void doDeleteKey(LPSTR lpsLine); +static void doQueryValue(LPSTR lpsLine); + +/* + * current suuported api + */ +static const char* commandNames[COMMAND_COUNT] = { + "setValue", + "deleteValue", + "createKey", + "deleteKey", + "queryValue" +}; + +/* + * Pointers to processing entry points + */ +static const commandAPI commandAPIs[COMMAND_COUNT] = { + doSetValue, + doDeleteValue, + doCreateKey, + doDeleteKey, + doQueryValue +}; + +/* + * This array controls the registry saving needs at the end of the process + */ +static const BOOL commandSaveRegistry[COMMAND_COUNT] = { + TRUE, + TRUE, + TRUE, + TRUE, + FALSE +}; + +/* + * Generic prototyes + */ +static HKEY getDataType(LPSTR *lpValue); +static LPSTR getRegKeyName(LPSTR lpLine); +static HKEY getRegClass(LPSTR lpLine); +static LPSTR getArg(LPSTR arg); +static INT getCommand(LPSTR commandName); +static DWORD convertHexToDWord(char *str, BYTE *buf); +static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen); +static LPSTR convertHexToHexCSV( BYTE *buf, ULONG len); +static LPSTR convertHexToDWORDStr( BYTE *buf, ULONG len); +static HRESULT openKey(LPSTR stdInput); +static void closeKey(); + +/* + * api setValue prototypes + */ +static void processSetValue(LPSTR cmdline); +static HRESULT setValue(LPSTR *argv); + +/* + * api queryValue prototypes + */ +static void processQueryValue(LPSTR cmdline); + +/* + * Help Text displyed when invalid parameters are provided + */ +static char helpText[] = " +NAME + regapi - provide a command line interface to the wine registry. + +SYNOPSYS + regapi commandName [-force] < file + +DESCRIPTION + regapi allows editing the wine resgistry. It processes the given + commandName for every line in the stdin data stream. Input data + format may vary depending on the commandName see INPUT FILE FORMAT. + +OPTIONS + commandName + Instruct regapi about what action to perform on the data stream. + Currently, only setValue and queryValue are supported and + implemented. + + -force + When provided the action will be performed anyway. This may + have a different meaning depending on the context. For example, + when providing -force to setValue, the value is set even if it + was previously set to another value. + + < file + STDIN chanel, provide a file name with line of the appropriate + format. + +INPUT FILE FORMAT + + setValue + The input file format required by the setValue command is similar + to the one obtained from regedit.exe export option. The only + difference is that multi line values are not supported, the + value data must be on a single line. + + [KEY_CLASS\\Some\\Path\\For\\A\\Key] + \"Value1\"=\"Data1\" + \"Value2\"=\"Data2\" + \"Valuen\"=\"Datan\" + ... + + queryValue + The input file format required by the queryValue command is + similar to the one required by setValue. The only + difference is that you only provide the value name. + + [KEY_CLASS\\Some\\Path\\For\\A\\Key] + \"Value1\" + \"Value2\" + \"Valuen\" + ... + February 1999. +"; + + +/****************************************************************************** + * This funtion returns the HKEY associated with the data type encoded in the + * value. It modify the input parameter (key value) in order to skip this + * "now useless" data type information. + */ +HKEY getDataType(LPSTR *lpValue) +{ + INT counter = 0; + DWORD dwReturn = REG_SZ; + + for (; counter < LAST_TYPE_MAP; counter++) + { + LONG len = strlen(typeMap[counter].mask); + if ( strncmp( *lpValue, typeMap[counter].mask, len) == IDENTICAL) + { + /* + * We found it, modify the value's pointer in order to skip the data + * type identifier, set the return value and exit the loop. + */ + (*lpValue) += len; + dwReturn = typeMap[counter].dataType; + break; + } + } + + return dwReturn; +} +/****************************************************************************** + * Extracts from a [HKEY\some\key\path] type of line the key name (what starts + * after the first '\' and end before the ']' + */ +LPSTR getRegKeyName(LPSTR lpLine) +{ + LPSTR keyNameBeg = NULL; + LPSTR keyNameEnd = NULL; + char lpLineCopy[KEY_MAX_LEN]; + + if (lpLine == NULL) + return NULL; + + strcpy(lpLineCopy, lpLine); + + keyNameBeg = strstr(lpLineCopy, "\\"); /* The key name start by '\' */ + keyNameBeg++; /* but is not part of the key name */ + keyNameEnd = strstr(lpLineCopy, "]"); /* The key name end by ']' */ + *keyNameEnd = NULL; /* Isolate the key name */ + + currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(keyNameBeg)+1); + if (currentKeyName != NULL) + strcpy(currentKeyName, keyNameBeg); + + return currentKeyName; +} + +/****************************************************************************** + * Extracts from a [HKEY/some/key/path] type of line the key class (what + * starts after the '[' and end before the first '\' + */ +static HKEY getRegClass(LPSTR lpClass) +{ + LPSTR classNameEnd; + LPSTR classNameBeg; + + char lpClassCopy[KEY_MAX_LEN]; + + if (lpClass == NULL) + return ERROR_INVALID_PARAMETER; + + strcpy(lpClassCopy, lpClass); + + classNameEnd = strstr(lpClassCopy, "\\"); /* The class name end by '\' */ + *classNameEnd = NULL; /* Isolate the class name */ + classNameBeg = &lpClassCopy[1]; /* Skip the '[' */ + + if (strcmp( classNameBeg, "HKEY_LOCAL_MACHINE") == IDENTICAL ) + return HKEY_LOCAL_MACHINE; + else if (strcmp( classNameBeg, "HKEY_USERS") == IDENTICAL ) + return HKEY_USERS; + else if (strcmp( classNameBeg, "HKEY_CLASSES_ROOT") == IDENTICAL ) + return HKEY_CLASSES_ROOT; + else if (strcmp( classNameBeg, "HKEY_CURRENT_CONFIG") == IDENTICAL ) + return HKEY_CURRENT_CONFIG; + else if (strcmp( classNameBeg, "HKEY_CURRENT_USER") == IDENTICAL ) + return HKEY_CURRENT_USER; + else + return ERROR_INVALID_PARAMETER; +} + +/****************************************************************************** + * Returns an allocated buffer with a cleaned copy (removed the surrounding + * dbl quotes) of the passed value. + */ +static LPSTR getArg( LPSTR arg) +{ + LPSTR tmp = NULL; + ULONG len; + + if (arg == NULL) + return NULL; + + /* + * Get rid of surrounding quotes + */ + len = strlen(arg); + + if( arg[len-1] == '\"' ) arg[len-1] = NULL; + if( arg[0] == '\"' ) arg++; + + tmp = HeapAlloc(GetProcessHeap(), 0, strlen(arg)+1); + strcpy(tmp, arg); + + return tmp; +} + +/****************************************************************************** + * Returns the index in the commands array of the command to process. + */ +static INT getCommand(LPSTR commandName) +{ + INT count; + for (count=0; count < COMMAND_COUNT; count++) + if ( strcmp(commandName, commandNames[count]) == IDENTICAL) + return count; + + return COMMAND_NOT_FOUND; +} + +/****************************************************************************** + * Converts a hex representation of a DWORD into a DWORD. + */ +static DWORD convertHexToDWord(char *str, BYTE *buf) +{ + char *s = str; /* Pointer to current */ + char *b = buf; /* Pointer to result */ + ULONG strPos = 0; + + memset(buf, 0, 4); + + while (strPos < 4) /* 8 byte in a DWORD */ + { + char xbuf[3]; + char wc; + + memcpy(xbuf,s,2); xbuf[2]='\0'; + sscanf(xbuf,"%02x",(UINT*)&wc); + *b++ =(unsigned char)wc; + + s+=2; + strPos+=1; + } + + return 4; /* always 4 byte for the word */ +} + +/****************************************************************************** + * Converts a hex buffer into a hex coma separated values + */ +static char* convertHexToHexCSV(BYTE *buf, ULONG bufLen) +{ + char* str; + char* ptrStr; + BYTE* ptrBuf; + + ULONG current = 0; + + str = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2); + memset(str, 0, (bufLen+1)*2); + ptrStr = str; /* Pointer to result */ + ptrBuf = buf; /* Pointer to current */ + + while (current < bufLen) + { + BYTE bCur = ptrBuf[current++]; + char res[3]; + + sprintf(res, "%02x", (unsigned int)*&bCur); + strcat(str, res); + strcat(str, ","); + } + + /* Get rid of the last coma */ + str[strlen(str)-1] = NULL; + return str; +} + +/****************************************************************************** + * Converts a hex buffer into a DWORD string + */ +static char* convertHexToDWORDStr(BYTE *buf, ULONG bufLen) +{ + char* str; + char* ptrStr; + BYTE* ptrBuf; + + ULONG current = 0; + + str = HeapAlloc(GetProcessHeap(), 0, (bufLen*2)+1); + memset(str, 0, (bufLen*2)+1); + ptrStr = str; /* Pointer to result */ + ptrBuf = buf; /* Pointer to current */ + + while (current < bufLen) + { + BYTE bCur = ptrBuf[current++]; + char res[3]; + + sprintf(res, "%02x", (unsigned int)*&bCur); + strcat(str, res); + } + + /* Get rid of the last coma */ + return str; +} +/****************************************************************************** + * Converts a hex coma separated values list into a hex list. + */ +static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen) +{ + char *s = str; /* Pointer to current */ + char *b = buf; /* Pointer to result */ + + ULONG strLen = strlen(str); + ULONG strPos = 0; + DWORD byteCount = 0; + + memset(buf, 0, bufLen); + + /* + * warn the user if we are here with a string longer than 2 bytes that does + * not contains ",". It is more likely because the data is invalid. + */ + if ( ( strlen(str) > 2) && ( strstr(str, ",") == NULL) ) + printf("regapi: WARNING converting CSV hex stream with no coma, " + "input data seems invalid.\n"); + + while (strPos < strLen) + { + char xbuf[3]; + char wc; + + memcpy(xbuf,s,2); xbuf[3]='\0'; + sscanf(xbuf,"%02x",(UINT*)&wc); + *b++ =(unsigned char)wc; + + s+=3; + strPos+=3; + byteCount++; + } + + return byteCount; +} + + +/****************************************************************************** + * Sets the value in argv[0] to the data in argv[1] for the currently + * opened key. + */ +static HRESULT setValue(LPSTR *argv) +{ + HRESULT hRes; + DWORD dwSize = KEY_MAX_LEN; + DWORD dwType = NULL; + DWORD dwDataType; + + CHAR lpsCurrentValue[KEY_MAX_LEN]; + + LPSTR keyValue = argv[0]; + LPSTR keyData = argv[1]; + + /* Make some checks */ + if ( (keyValue == NULL) || (keyData == NULL) ) + return ERROR_INVALID_PARAMETER; + + /* + * Default registry values are encoded in the input stream as '@' but as + * blank in the wine registry. + */ + if( (keyValue[0] == '@') && (strlen(keyValue) == 1) ) + keyValue[0] = NULL; + + /* Get the data type stored into the value field */ + dwDataType = getDataType(&keyData); + + memset(lpsCurrentValue, 0, KEY_MAX_LEN); + hRes = RegQueryValueExA( + currentKeyHandle, + keyValue, + NULL, + &dwType, + (LPBYTE)lpsCurrentValue, + &dwSize); + + if( ( strlen(lpsCurrentValue) == 0 ) || /* The value is not existing */ + ( bForce )) /* -force option */ + { + LPBYTE lpbData; + BYTE convert[KEY_MAX_LEN]; + DWORD dwLen; + + if ( dwDataType == REG_SZ ) /* no convertion for string */ + { + dwLen = strlen(keyData); + lpbData = keyData; + } + else if (dwDataType == REG_DWORD) /* Convert the dword types */ + { + dwLen = convertHexToDWord(keyData, convert); + lpbData = convert; + } + else /* Convert the hexadecimal types */ + { + dwLen = convertHexCSVToHex(keyData, convert, KEY_MAX_LEN); + lpbData = convert; + } + + hRes = RegSetValueEx( + currentKeyHandle, + keyValue, + 0, /* Reserved */ + dwDataType, + lpbData, + dwLen); + } + else + { + /* return the current value data into argv[1] */ + if (argv[1] != NULL) + { + HeapFree(GetProcessHeap(), 0, argv[1]); + argv[1] = HeapAlloc(GetProcessHeap(), 0, dwSize+1); + + if ( argv[1] != NULL ) + strncpy(argv[1], lpsCurrentValue, dwSize); + } + + return KEY_VALUE_ALREADY_SET; + } + return hRes; +} + + +/****************************************************************************** + * Open the key + */ +static HRESULT openKey( LPSTR stdInput) +{ + DWORD dwDisp; + HRESULT hRes; + + /* Sanity checks */ + if (stdInput == NULL) + return ERROR_INVALID_PARAMETER; + + /* Get the registry class */ + currentKeyClass = getRegClass(stdInput); /* Sets global variable */ + if (currentKeyClass == ERROR_INVALID_PARAMETER) + return ERROR_INVALID_PARAMETER; + + /* Get the key name */ + currentKeyName = getRegKeyName(stdInput); /* Sets global variable */ + if (currentKeyName == NULL) + return ERROR_INVALID_PARAMETER; + + hRes = RegCreateKeyEx( + currentKeyClass, /* Class */ + currentKeyName, /* Sub Key */ + 0, /* MUST BE 0 */ + NULL, /* object type */ + REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */ + KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */ + NULL, /* security attribute */ + ¤tKeyHandle, /* result */ + &dwDisp); /* disposition, REG_CREATED_NEW_KEY or + REG_OPENED_EXISTING_KEY */ + + if (hRes == ERROR_SUCCESS) + bTheKeyIsOpen = TRUE; + + return hRes; + +} +/****************************************************************************** + * This function is a wrapper arround the setValue function. It prepares the + * land and clean the area once completed. + */ +static void processSetValue(LPSTR cmdline) +{ + LPSTR argv[SET_VALUE_MAX_ARGS]; /* args storage */ + + LPSTR token = NULL; /* current token analized */ + ULONG argCounter = 0; /* counter of args */ + INT counter; + HRESULT hRes = NULL; + + /* + * Init storage and parse the line + */ + for (counter=0; counter