/* * 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; }