| /* | |
| * Command line Registry implementation | |
| * | |
| * Copyright 1999 Sylvain St-Germain | |
| * | |
| * Note: Please consult the README file for more information. | |
| * | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <windows.h> | |
| #include <winreg.h> | |
| #include <winerror.h> | |
| #include <winnt.h> | |
| #include <string.h> | |
| /****************************************************************************** | |
| * Defines and consts | |
| */ | |
| #define IDENTICAL 0 | |
| #define COMMAND_COUNT 7 | |
| #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 = 0; | |
| static HKEY currentKeyHandle = 0; | |
| static BOOL bTheKeyIsOpen = FALSE; | |
| /* Delimiters used to parse the "value"="data" pair for setValue*/ | |
| #define SET_VALUE_MAX_ARGS 2 | |
| /* Delimiters 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(10):", REG_RESOURCE_REQUIREMENTS_LIST}, | |
| {"hex(80000000):", 0x80000000}, | |
| {"hex(80000001):", 0x80000001}, | |
| {"hex(80000002):", 0x80000002}, | |
| {"hex(80000003):", 0x80000003}, | |
| {"hex(80000004):", 0x80000004}, | |
| {"hex(80000005):", 0x80000005}, | |
| {"hex(80000006):", 0x80000006}, | |
| {"hex(80000007):", 0x80000007}, | |
| {"hex(80000008):", 0x80000008}, | |
| {"hex(80000009):", 0x80000000}, | |
| {"hex(8000000a):", 0x8000000A} | |
| }; | |
| 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); | |
| static void doRegisterDLL(LPSTR lpsLine); | |
| static void doUnregisterDLL(LPSTR lpsLine); | |
| /* | |
| * Currently supported api | |
| */ | |
| static const char* commandNames[COMMAND_COUNT] = { | |
| "setValue", | |
| "deleteValue", | |
| "createKey", | |
| "deleteKey", | |
| "queryValue", | |
| "registerDLL", | |
| "unregisterDLL" | |
| }; | |
| /* | |
| * Pointers to processing entry points | |
| */ | |
| static const commandAPI commandAPIs[COMMAND_COUNT] = { | |
| doSetValue, | |
| doDeleteValue, | |
| doCreateKey, | |
| doDeleteKey, | |
| doQueryValue, | |
| doRegisterDLL, | |
| doUnregisterDLL | |
| }; | |
| /* | |
| * This array controls the registry saving needs at the end of the process | |
| */ | |
| static const BOOL commandSaveRegistry[COMMAND_COUNT] = { | |
| TRUE, | |
| TRUE, | |
| TRUE, | |
| TRUE, | |
| FALSE, | |
| TRUE, | |
| TRUE | |
| }; | |
| /* | |
| * Generic prototypes | |
| */ | |
| static DWORD 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 displayed when invalid parameters are provided | |
| */ | |
| static char helpText[] = | |
| "NAME\n" | |
| " regapi - perform certain actions on the wine registry.\n" | |
| "\n" | |
| "SYNOPSIS\n" | |
| " regapi commandName [-force] < file\n" | |
| "\n" | |
| "DESCRIPTION\n" | |
| " regapi modifies settings in the wine registry. It processes\n" | |
| " the given commandName for every line in the stdin data stream.\n" | |
| " Input data format may vary depending on the commandName\n" | |
| " (see INPUT FILE FORMAT).\n" | |
| "\n" | |
| "OPTIONS\n" | |
| " commandName\n" | |
| " Instruct regapi about what action to perform on the data stream.\n" | |
| " Currently, only setValue and queryValue are supported and\n" | |
| " implemented.\n" | |
| "\n" | |
| " -force\n" | |
| " When provided the action will be performed anyway. This may\n" | |
| " have a different meaning depending on the context. For example,\n" | |
| " when providing -force to setValue, the value is set even if it\n" | |
| " was previously set to another value.\n" | |
| "\n" | |
| " < file\n" | |
| " STDIN channel, provide a file name with line of the appropriate\n" | |
| " format.\n" | |
| "\n" | |
| "INPUT FILE FORMAT\n" | |
| "\n" | |
| " setValue\n" | |
| " The input file format required by the setValue command is similar\n" | |
| " to the one obtained from regedit.exe export option. The only\n" | |
| " difference is that multi line values are not supported, the\n" | |
| " value data must be on a single line.\n" | |
| "\n" | |
| " [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n" | |
| " \"Value1\"=\"Data1\"\n" | |
| " \"Value2\"=\"Data2\"\n" | |
| " \"Valuen\"=\"Datan\"\n" | |
| " ...\n" | |
| "\n" | |
| " queryValue\n" | |
| " The input file format required by the queryValue command is\n" | |
| " similar to the one required by setValue. The only\n" | |
| " difference is that you only provide the value name.\n" | |
| "\n" | |
| " [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n" | |
| " \"Value1\"\n" | |
| " \"Value2\"\n" | |
| " \"Valuen\"\n" | |
| " ...\n" | |
| " registerDLL\n" | |
| " The input file format is a list of DLLs to register\n" | |
| "\n" | |
| " unregisterDLL\n" | |
| " The input file format is a list of DLLs to unregister\n" | |
| " February 1999.\n" | |
| ; | |
| /****************************************************************************** | |
| * This function returns the HKEY associated with the data type encoded in the | |
| * value. It modifies the input parameter (key value) in order to skip this | |
| * "now useless" data type information. | |
| */ | |
| DWORD getDataType(LPSTR *lpValue) | |
| { | |
| INT counter = 0; | |
| DWORD dwReturn = REG_SZ; | |
| for (; counter < LAST_TYPE_MAP; counter++) | |
| { | |
| LONG len = strlen(typeMap[counter].mask); | |
| if ( strncasecmp( *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 = '\0'; /* 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 ends before the first '\' | |
| */ | |
| static HKEY getRegClass(LPSTR lpClass) | |
| { | |
| LPSTR classNameEnd; | |
| LPSTR classNameBeg; | |
| char lpClassCopy[KEY_MAX_LEN]; | |
| if (lpClass == NULL) | |
| return (HKEY)ERROR_INVALID_PARAMETER; | |
| strcpy(lpClassCopy, lpClass); | |
| classNameEnd = strstr(lpClassCopy, "\\"); /* The class name end by '\' */ | |
| *classNameEnd = '\0'; /* 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 (HKEY)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] = '\0'; | |
| 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 comma 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 comma */ | |
| str[strlen(str)-1] = '\0'; | |
| 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 comma */ | |
| return str; | |
| } | |
| /****************************************************************************** | |
| * Converts a hex comma 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 comma, " | |
| "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 = 0; | |
| DWORD dwDataType; | |
| LPSTR lpsCurrentValue; | |
| LPSTR keyValue = argv[0]; | |
| LPSTR keyData = argv[1]; | |
| /* Make some checks */ | |
| if ( (keyValue == NULL) || (keyData == NULL) ) | |
| return ERROR_INVALID_PARAMETER; | |
| lpsCurrentValue=HeapAlloc(GetProcessHeap(), 0,KEY_MAX_LEN); | |
| /* | |
| * 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] = '\0'; | |
| /* 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); | |
| while(hRes==ERROR_MORE_DATA){ | |
| dwSize+=KEY_MAX_LEN; | |
| lpsCurrentValue=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsCurrentValue,dwSize); | |
| 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); | |
| argv[1][dwSize]='\0'; | |
| } | |
| } | |
| 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 == (HKEY)ERROR_INVALID_PARAMETER) | |
| return (HRESULT)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 for 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 = 0; | |
| /* | |
| * 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 for 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 = 0; | |
| 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=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN); | |
| /* | |
| * We need to query the key default value | |
| */ | |
| hRes = RegQueryValue( | |
| currentKeyHandle, | |
| currentKeyName, | |
| (LPBYTE)lpsData, | |
| &lLen); | |
| if (hRes==ERROR_MORE_DATA) { | |
| lpsData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsData,lLen); | |
| hRes = RegQueryValue(currentKeyHandle,currentKeyName,(LPBYTE)lpsData,&lLen); | |
| } | |
| if (hRes == ERROR_SUCCESS) | |
| { | |
| lpsRes = HeapAlloc( GetProcessHeap(), 0, lLen); | |
| strncpy(lpsRes, lpsData, lLen); | |
| lpsRes[lLen-1]='\0'; | |
| } | |
| } | |
| else | |
| { | |
| DWORD dwLen = KEY_MAX_LEN; | |
| BYTE* lpbData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,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_MORE_DATA) { | |
| lpbData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpbData,dwLen); | |
| hRes = RegQueryValueEx(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpbData,&dwLen); | |
| } | |
| if (hRes == ERROR_SUCCESS) | |
| { | |
| /* | |
| * Convert the returned data to a displayable format | |
| */ | |
| switch ( dwType ) | |
| { | |
| case REG_SZ: | |
| case REG_EXPAND_SZ: | |
| { | |
| lpsRes = HeapAlloc( GetProcessHeap(), 0, dwLen); | |
| strncpy(lpsRes, lpbData, dwLen); | |
| lpsRes[dwLen-1]='\0'; | |
| break; | |
| } | |
| case REG_DWORD: | |
| { | |
| lpsRes = convertHexToDWORDStr(lpbData, dwLen); | |
| break; | |
| } | |
| default: | |
| { | |
| lpsRes = convertHexToHexCSV(lpbData, dwLen); | |
| break; | |
| } | |
| } | |
| } | |
| HeapFree(GetProcessHeap(), 0, lpbData); | |
| } | |
| 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 = 0; | |
| currentKeyHandle = 0; | |
| } | |
| /****************************************************************************** | |
| * 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"); | |
| } | |
| /****************************************************************************** | |
| * This funtion is the main entry point to the registerDLL action. It | |
| * receives the currently read line, then loads and registers the requested DLLs | |
| */ | |
| static void doRegisterDLL(LPSTR stdInput) { | |
| HMODULE theLib = 0; | |
| UINT retVal = 0; | |
| /* Check for valid input */ | |
| if (stdInput == NULL) | |
| return; | |
| /* Load and register the library, then free it */ | |
| theLib = LoadLibrary(stdInput); | |
| if (theLib) | |
| { | |
| FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer"); | |
| if (lpfnDLLRegProc) | |
| retVal = (*lpfnDLLRegProc)(); | |
| else | |
| printf("regapi: Couldn't find DllRegisterServer proc in '%s'.\n", stdInput); | |
| if (retVal != S_OK) | |
| printf("regapi: DLLRegisterServer error 0x%x in '%s'.\n", retVal, stdInput); | |
| FreeLibrary(theLib); | |
| } | |
| else | |
| { | |
| printf("regapi: Could not load DLL '%s'.\n", stdInput); | |
| } | |
| } | |
| /****************************************************************************** | |
| * This funtion is the main entry point to the unregisterDLL action. It | |
| * receives the currently read line, then loads and unregisters the requested DLLs | |
| */ | |
| static void doUnregisterDLL(LPSTR stdInput) { | |
| HMODULE theLib = 0; | |
| UINT retVal = 0; | |
| /* Check for valid input */ | |
| if (stdInput == NULL) | |
| return; | |
| /* Load and unregister the library, then free it */ | |
| theLib = LoadLibrary(stdInput); | |
| if (theLib) | |
| { | |
| FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer"); | |
| if (lpfnDLLRegProc) | |
| retVal = (*lpfnDLLRegProc)(); | |
| else | |
| printf("regapi: Couldn't find DllUnregisterServer proc in '%s'.\n", stdInput); | |
| if (retVal != S_OK) | |
| printf("regapi: DLLUnregisterServer error 0x%x in '%s'.\n", retVal, stdInput); | |
| FreeLibrary(theLib); | |
| } | |
| else | |
| { | |
| printf("regapi: Could not load DLL '%s'.\n", stdInput); | |
| } | |
| } | |
| /****************************************************************************** | |
| * MAIN - WinMain simply validates the first parameter (command to perform) | |
| * It then reads the STDIN lines by lines forwarding their processing | |
| * to the appropriate method. | |
| */ | |
| int PASCAL WinMain (HINSTANCE inst, HINSTANCE 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 */ | |
| LPSTR nextLine = NULL; | |
| ULONG currentSize = STDIN_MAX_LEN; | |
| stdInput = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN); | |
| nextLine = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN); | |
| if (stdInput == NULL || nextLine== 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 | |
| */ | |
| ULONG curSize=STDIN_MAX_LEN; | |
| char* s=NULL; | |
| while((NULL!=(stdInput=fgets(stdInput,curSize,stdin))) && (NULL==(s=strchr(stdInput,'\n'))) ){ | |
| fseek(stdin,-curSize,SEEK_CUR+1); | |
| stdInput=HeapReAlloc(GetProcessHeap(), 0,stdInput,curSize+=STDIN_MAX_LEN); | |
| } | |
| /* | |
| * Make some handy generic stuff here... | |
| */ | |
| if ( stdInput != NULL ) | |
| { | |
| stdInput[strlen(stdInput) -1] = '\0'; /* get rid of new line */ | |
| if( stdInput[0] == '#' ) /* this is a comment, skip */ | |
| continue; | |
| while( stdInput[strlen(stdInput) -1] == '\\' ){ /* a '\' char in the end of the current line means */ | |
| /* that this line is not complete and we have to get */ | |
| stdInput[strlen(stdInput) -1]= '\0'; /* the rest in the next lines */ | |
| nextLine = fgets(nextLine, STDIN_MAX_LEN, stdin); | |
| nextLine[strlen(nextLine)-1] = '\0'; | |
| if ( (strlen(stdInput)+strlen(nextLine)) > currentSize){ | |
| stdInput=HeapReAlloc(GetProcessHeap(),0,stdInput,strlen(stdInput)+STDIN_MAX_LEN); | |
| currentSize+=STDIN_MAX_LEN; | |
| } | |
| strcat(stdInput,nextLine+2); | |
| } | |
| } | |
| /* | |
| * 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; | |
| } | |
| #if 0 | |
| /* | |
| * Save the registry only if it was modified | |
| */ | |
| if ( commandSaveRegistry[cmdIndex] != FALSE ) | |
| SHELL_SaveRegistry(); | |
| #endif | |
| HeapFree(GetProcessHeap(), 0, nextLine); | |
| HeapFree(GetProcessHeap(), 0, stdInput); | |
| return SUCCESS; | |
| } |