Added command line tool to access the registry.
This commit is contained in:
parent
0dd1b5b239
commit
1bb0e66fa2
2
configure
vendored
2
configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -5,6 +5,7 @@ SUBDIRS = \
|
||||
control \
|
||||
notepad \
|
||||
progman \
|
||||
regapi \
|
||||
regtest \
|
||||
view \
|
||||
winhelp \
|
||||
|
2
programs/regapi/.cvsignore
Normal file
2
programs/regapi/.cvsignore
Normal file
@ -0,0 +1,2 @@
|
||||
Makefile
|
||||
regapi
|
32
programs/regapi/Makefile.in
Normal file
32
programs/regapi/Makefile.in
Normal file
@ -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:
|
89
programs/regapi/README
Normal file
89
programs/regapi/README
Normal file
@ -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.
|
42
programs/regapi/regFixer.pl
Executable file
42
programs/regapi/regFixer.pl
Executable file
@ -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...
|
||||
}
|
||||
|
||||
|
||||
|
51
programs/regapi/regRestorer.pl
Executable file
51
programs/regapi/regRestorer.pl
Executable file
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
62
programs/regapi/regSet.sh
Executable file
62
programs/regapi/regSet.sh
Executable file
@ -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
|
983
programs/regapi/regapi.c
Normal file
983
programs/regapi/regapi.c
Normal file
@ -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…
x
Reference in New Issue
Block a user