Added command line tool to access the registry.
This commit is contained in:
parent
0dd1b5b239
commit
1bb0e66fa2
|
@ -4643,6 +4643,7 @@ programs/avitools/Makefile
|
||||||
programs/notepad/Makefile
|
programs/notepad/Makefile
|
||||||
programs/progman/Makefile
|
programs/progman/Makefile
|
||||||
programs/regtest/Makefile
|
programs/regtest/Makefile
|
||||||
|
programs/regapi/Makefile
|
||||||
programs/view/Makefile
|
programs/view/Makefile
|
||||||
programs/winhelp/Makefile
|
programs/winhelp/Makefile
|
||||||
programs/winver/Makefile
|
programs/winver/Makefile
|
||||||
|
@ -4806,6 +4807,7 @@ programs/avitools/Makefile
|
||||||
programs/notepad/Makefile
|
programs/notepad/Makefile
|
||||||
programs/progman/Makefile
|
programs/progman/Makefile
|
||||||
programs/regtest/Makefile
|
programs/regtest/Makefile
|
||||||
|
programs/regapi/Makefile
|
||||||
programs/view/Makefile
|
programs/view/Makefile
|
||||||
programs/winhelp/Makefile
|
programs/winhelp/Makefile
|
||||||
programs/winver/Makefile
|
programs/winver/Makefile
|
||||||
|
|
|
@ -668,6 +668,7 @@ programs/avitools/Makefile
|
||||||
programs/notepad/Makefile
|
programs/notepad/Makefile
|
||||||
programs/progman/Makefile
|
programs/progman/Makefile
|
||||||
programs/regtest/Makefile
|
programs/regtest/Makefile
|
||||||
|
programs/regapi/Makefile
|
||||||
programs/view/Makefile
|
programs/view/Makefile
|
||||||
programs/winhelp/Makefile
|
programs/winhelp/Makefile
|
||||||
programs/winver/Makefile
|
programs/winver/Makefile
|
||||||
|
|
|
@ -5,6 +5,7 @@ SUBDIRS = \
|
||||||
control \
|
control \
|
||||||
notepad \
|
notepad \
|
||||||
progman \
|
progman \
|
||||||
|
regapi \
|
||||||
regtest \
|
regtest \
|
||||||
view \
|
view \
|
||||||
winhelp \
|
winhelp \
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Makefile
|
||||||
|
regapi
|
|
@ -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:
|
|
@ -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.
|
|
@ -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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,983 @@
|
||||||
|
/*
|
||||||
|
* Command line Registry implementation
|
||||||
|
*
|
||||||
|
* Copyright 1999 Sylvain St-Germain
|
||||||
|
*
|
||||||
|
* Note: Please consult the README file for more information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winreg.h>
|
||||||
|
#include <winerror.h>
|
||||||
|
#include <winnt.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <shell.h>
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* 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<SET_VALUE_MAX_ARGS; counter++)
|
||||||
|
argv[counter]=NULL;
|
||||||
|
|
||||||
|
while( (token = strsep(&cmdline, setValueDelim[argCounter])) != NULL )
|
||||||
|
{
|
||||||
|
argv[argCounter++] = getArg(token);
|
||||||
|
|
||||||
|
if (argCounter == SET_VALUE_MAX_ARGS)
|
||||||
|
break; /* Stop processing args no matter what */
|
||||||
|
}
|
||||||
|
|
||||||
|
hRes = setValue(argv);
|
||||||
|
if ( hRes == ERROR_SUCCESS )
|
||||||
|
printf(
|
||||||
|
"regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n",
|
||||||
|
argv[0],
|
||||||
|
argv[1],
|
||||||
|
currentKeyName);
|
||||||
|
|
||||||
|
else if ( hRes == KEY_VALUE_ALREADY_SET )
|
||||||
|
printf(
|
||||||
|
"regapi: Value \"%s\" already set to \"%s\" in key [%s]\n",
|
||||||
|
argv[0],
|
||||||
|
argv[1],
|
||||||
|
currentKeyName);
|
||||||
|
|
||||||
|
else
|
||||||
|
printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
|
||||||
|
currentKeyName,
|
||||||
|
argv[0],
|
||||||
|
argv[1]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do some cleanup
|
||||||
|
*/
|
||||||
|
for (counter=0; counter<argCounter; counter++)
|
||||||
|
if (argv[counter] != NULL)
|
||||||
|
HeapFree(GetProcessHeap(), 0, argv[counter]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This function is a wrapper arround the queryValue function. It prepares the
|
||||||
|
* land and clean the area once completed.
|
||||||
|
*/
|
||||||
|
static void processQueryValue(LPSTR cmdline)
|
||||||
|
{
|
||||||
|
LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */
|
||||||
|
LPSTR token = NULL; /* current token analized */
|
||||||
|
ULONG argCounter = 0; /* counter of args */
|
||||||
|
INT counter;
|
||||||
|
HRESULT hRes = NULL;
|
||||||
|
LPSTR keyValue = NULL;
|
||||||
|
LPSTR lpsRes = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init storage and parse the line
|
||||||
|
*/
|
||||||
|
for (counter=0; counter<QUERY_VALUE_MAX_ARGS; counter++)
|
||||||
|
argv[counter]=NULL;
|
||||||
|
|
||||||
|
while( (token = strsep(&cmdline, queryValueDelim[argCounter])) != NULL )
|
||||||
|
{
|
||||||
|
argv[argCounter++] = getArg(token);
|
||||||
|
|
||||||
|
if (argCounter == QUERY_VALUE_MAX_ARGS)
|
||||||
|
break; /* Stop processing args no matter what */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The value we look for is the first token on the line */
|
||||||
|
if ( argv[0] == NULL )
|
||||||
|
return; /* SHOULD NOT OCCURS */
|
||||||
|
else
|
||||||
|
keyValue = argv[0];
|
||||||
|
|
||||||
|
if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
|
||||||
|
{
|
||||||
|
LONG lLen = KEY_MAX_LEN;
|
||||||
|
CHAR lpsData[KEY_MAX_LEN];
|
||||||
|
/*
|
||||||
|
* We need to query the key default value
|
||||||
|
*/
|
||||||
|
hRes = RegQueryValue(
|
||||||
|
currentKeyHandle,
|
||||||
|
currentKeyName,
|
||||||
|
(LPBYTE)lpsData,
|
||||||
|
&lLen);
|
||||||
|
|
||||||
|
if (hRes == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
lpsRes = HeapAlloc( GetProcessHeap(), 0, lLen);
|
||||||
|
strncpy(lpsRes, lpsData, lLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD dwLen = KEY_MAX_LEN;
|
||||||
|
BYTE lpbData[KEY_MAX_LEN];
|
||||||
|
DWORD dwType;
|
||||||
|
/*
|
||||||
|
* We need to query a specific value for the key
|
||||||
|
*/
|
||||||
|
hRes = RegQueryValueEx(
|
||||||
|
currentKeyHandle,
|
||||||
|
keyValue,
|
||||||
|
0,
|
||||||
|
&dwType,
|
||||||
|
(LPBYTE)lpbData,
|
||||||
|
&dwLen);
|
||||||
|
|
||||||
|
if (hRes == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Convert the returned data to a displayable format
|
||||||
|
*/
|
||||||
|
switch ( dwType )
|
||||||
|
{
|
||||||
|
case REG_SZ:
|
||||||
|
{
|
||||||
|
lpsRes = HeapAlloc( GetProcessHeap(), 0, dwLen);
|
||||||
|
strncpy(lpsRes, lpbData, dwLen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REG_DWORD:
|
||||||
|
{
|
||||||
|
lpsRes = convertHexToDWORDStr(lpbData, dwLen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
lpsRes = convertHexToHexCSV(lpbData, dwLen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ( hRes == ERROR_SUCCESS )
|
||||||
|
printf(
|
||||||
|
"regapi: Value \"%s\" = \"%s\" in key [%s]\n",
|
||||||
|
keyValue,
|
||||||
|
lpsRes,
|
||||||
|
currentKeyName);
|
||||||
|
|
||||||
|
else
|
||||||
|
printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
|
||||||
|
keyValue,
|
||||||
|
currentKeyName);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do some cleanup
|
||||||
|
*/
|
||||||
|
for (counter=0; counter<argCounter; counter++)
|
||||||
|
if (argv[counter] != NULL)
|
||||||
|
HeapFree(GetProcessHeap(), 0, argv[counter]);
|
||||||
|
|
||||||
|
if (lpsRes != NULL)
|
||||||
|
HeapFree(GetProcessHeap(), 0, lpsRes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Close the currently opened key.
|
||||||
|
*/
|
||||||
|
static void closeKey()
|
||||||
|
{
|
||||||
|
RegCloseKey(currentKeyHandle);
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
|
||||||
|
|
||||||
|
bTheKeyIsOpen = FALSE;
|
||||||
|
|
||||||
|
currentKeyName = NULL;
|
||||||
|
currentKeyClass = NULL;
|
||||||
|
currentKeyHandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This funtion is the main entry point to the setValue type of action. It
|
||||||
|
* receives the currently read line and dispatch the work depending on the
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
static void doSetValue(LPSTR stdInput)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We encoutered the end of the file, make sure we
|
||||||
|
* close the opened key and exit
|
||||||
|
*/
|
||||||
|
if (stdInput == NULL)
|
||||||
|
{
|
||||||
|
if (bTheKeyIsOpen != FALSE)
|
||||||
|
closeKey();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( stdInput[0] == '[') /* We are reading a new key */
|
||||||
|
{
|
||||||
|
if ( bTheKeyIsOpen != FALSE )
|
||||||
|
closeKey(); /* Close the previous key before */
|
||||||
|
|
||||||
|
if ( openKey(stdInput) != ERROR_SUCCESS )
|
||||||
|
printf ("regapi: doSetValue failed to open key %s\n", stdInput);
|
||||||
|
}
|
||||||
|
else if( ( bTheKeyIsOpen ) &&
|
||||||
|
(( stdInput[0] == '@') || /* reading a default @=data pair */
|
||||||
|
( stdInput[0] == '\"'))) /* reading a new value=data pair */
|
||||||
|
{
|
||||||
|
processSetValue(stdInput);
|
||||||
|
}
|
||||||
|
else /* since we are assuming that the */
|
||||||
|
{ /* file format is valid we must */
|
||||||
|
if ( bTheKeyIsOpen ) /* be reading a blank line which */
|
||||||
|
closeKey(); /* indicate end of this key processing */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This funtion is the main entry point to the queryValue type of action. It
|
||||||
|
* receives the currently read line and dispatch the work depending on the
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
static void doQueryValue(LPSTR stdInput) {
|
||||||
|
/*
|
||||||
|
* We encoutered the end of the file, make sure we
|
||||||
|
* close the opened key and exit
|
||||||
|
*/
|
||||||
|
if (stdInput == NULL)
|
||||||
|
{
|
||||||
|
if (bTheKeyIsOpen != FALSE)
|
||||||
|
closeKey();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( stdInput[0] == '[') /* We are reading a new key */
|
||||||
|
{
|
||||||
|
if ( bTheKeyIsOpen != FALSE )
|
||||||
|
closeKey(); /* Close the previous key before */
|
||||||
|
|
||||||
|
if ( openKey(stdInput) != ERROR_SUCCESS )
|
||||||
|
printf ("regapi: doSetValue failed to open key %s\n", stdInput);
|
||||||
|
}
|
||||||
|
else if( ( bTheKeyIsOpen ) &&
|
||||||
|
(( stdInput[0] == '@') || /* reading a default @=data pair */
|
||||||
|
( stdInput[0] == '\"'))) /* reading a new value=data pair */
|
||||||
|
{
|
||||||
|
processQueryValue(stdInput);
|
||||||
|
}
|
||||||
|
else /* since we are assuming that the */
|
||||||
|
{ /* file format is valid we must */
|
||||||
|
if ( bTheKeyIsOpen ) /* be reading a blank line which */
|
||||||
|
closeKey(); /* indicate end of this key processing */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This funtion is the main entry point to the deletetValue type of action. It
|
||||||
|
* receives the currently read line and dispatch the work depending on the
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
static void doDeleteValue(LPSTR line) {
|
||||||
|
printf ("regapi: deleteValue not yet implemented\n");
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* This funtion is the main entry point to the deleteKey type of action. It
|
||||||
|
* receives the currently read line and dispatch the work depending on the
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
static void doDeleteKey(LPSTR line) {
|
||||||
|
printf ("regapi: deleteKey not yet implemented\n");
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* This funtion is the main entry point to the createKey type of action. It
|
||||||
|
* receives the currently read line and dispatch the work depending on the
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
static void doCreateKey(LPSTR line) {
|
||||||
|
printf ("regapi: createKey not yet implemented\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* MAIN - The main simply validate the first parameter (command to perform)
|
||||||
|
* It then read the STDIN lines by lines forwarding their processing
|
||||||
|
* to the appropriate method.
|
||||||
|
*/
|
||||||
|
int PASCAL WinMain (HANDLE inst, HANDLE prev, LPSTR cmdline, int show)
|
||||||
|
{
|
||||||
|
LPSTR token = NULL; /* current token analized */
|
||||||
|
LPSTR stdInput = NULL; /* line read from stdin */
|
||||||
|
INT cmdIndex = -1; /* index of the command in array */
|
||||||
|
|
||||||
|
stdInput = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
|
||||||
|
if (stdInput == NULL)
|
||||||
|
return NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the command, should be the first arg (modify cmdLine)
|
||||||
|
*/
|
||||||
|
token = strsep(&cmdline, " ");
|
||||||
|
if (token != NULL)
|
||||||
|
{
|
||||||
|
cmdIndex = getCommand(token);
|
||||||
|
if (cmdIndex == COMMAND_NOT_FOUND)
|
||||||
|
{
|
||||||
|
printf("regapi: Command \"%s\" is not supported.\n", token);
|
||||||
|
printf(helpText);
|
||||||
|
return COMMAND_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"regapi: The first item on the command line must be the command name.\n");
|
||||||
|
printf(helpText);
|
||||||
|
return COMMAND_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check to see weather we force the action
|
||||||
|
* (meaning differ depending on the command performed)
|
||||||
|
*/
|
||||||
|
if ( cmdline != NULL ) /* will be NULL if '-force' is not provided */
|
||||||
|
if ( strstr(cmdline, "-force") != NULL )
|
||||||
|
bForce = TRUE;
|
||||||
|
|
||||||
|
printf("Processing stdin...\n");
|
||||||
|
|
||||||
|
while ( TRUE )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* read a line
|
||||||
|
*/
|
||||||
|
stdInput = fgets(stdInput, STDIN_MAX_LEN, stdin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make some handy generic stuff here...
|
||||||
|
*/
|
||||||
|
if ( stdInput != NULL )
|
||||||
|
{
|
||||||
|
stdInput[strlen(stdInput) -1] = NULL; /* get rid of new line */
|
||||||
|
|
||||||
|
if( stdInput[0] == '#' ) /* this is a comment, skip */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We process every lines even the NULL (last) line, to indicate the
|
||||||
|
* end of the processing to the specific process.
|
||||||
|
*/
|
||||||
|
commandAPIs[cmdIndex](stdInput);
|
||||||
|
|
||||||
|
if (stdInput == NULL) /* EOF encountered */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the registry only if it was modified
|
||||||
|
*/
|
||||||
|
if ( commandSaveRegistry[cmdIndex] != FALSE )
|
||||||
|
SHELL_SaveRegistry();
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, stdInput);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue