407 lines
9.6 KiB
C
407 lines
9.6 KiB
C
// Copyright (c) 1998-1999 Microsoft Corporation
|
|
/******************************************************************************
|
|
*
|
|
* ACREGL.C
|
|
*
|
|
* Application Compatibility Registry Lookup Helper Program
|
|
*
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
// #include <winreg.h>
|
|
|
|
#define MAXLEN 512
|
|
|
|
|
|
|
|
// Options
|
|
|
|
// The strip char option will strip the rightmost n instances
|
|
// of the specified character from the output. If the count
|
|
// is omitted, then a single instance is removed.
|
|
//
|
|
// Example: STRIPCHAR\3 will change
|
|
// C:\WINNT40\Profiles\All Users\Start Menu to
|
|
// C:\WINNT40
|
|
#define OPTION_STRIP_CHAR L"STRIPCHAR"
|
|
|
|
// The strip path option strips off the path.
|
|
//
|
|
// Example: STRIPPATH will change
|
|
// C:\WINNT40\Profiles\All Users\Start Menu to
|
|
// Start Menu
|
|
#define OPTION_STRIP_PATH L"STRIPPATH"
|
|
|
|
// The get path option gets the common paths
|
|
//
|
|
// Example: GETPATHS will return
|
|
//
|
|
#define OPTION_GET_PATHS L"GETPATHS"
|
|
|
|
// Define the strings used for setting the user/common paths
|
|
#define COMMON_STARTUP L"COMMON_STARTUP"
|
|
#define COMMON_START_MENU L"COMMON_START_MENU"
|
|
#define COMMON_PROGRAMS L"COMMON_PROGRAMS"
|
|
#define USER_START_MENU L"USER_START_MENU"
|
|
#define USER_STARTUP L"USER_STARTUP"
|
|
#define USER_PROGRAMS L"USER_PROGRAMS"
|
|
#define MY_DOCUMENTS L"MY_DOCUMENTS"
|
|
#define TEMPLATES L"TEMPLATES"
|
|
#define APP_DATA L"APP_DATA"
|
|
|
|
|
|
// Option Block.
|
|
// Scan Options will populate
|
|
// this struct.
|
|
|
|
typedef struct
|
|
{
|
|
WCHAR stripChar; // Character to strip.
|
|
int stripNthChar; // Strip nth occurrence from the right.
|
|
int stripPath; // Strip path.
|
|
int getPaths; // Get the common paths
|
|
} OptionBlock;
|
|
|
|
|
|
//
|
|
// Strip quotes from argument if they exist, convert to unicode, and expand
|
|
// environment variables.
|
|
//
|
|
|
|
int ParseArg(CHAR *inarg, WCHAR *outarg)
|
|
{
|
|
WCHAR T[MAXLEN+1], wcin[MAXLEN+1];
|
|
int retval;
|
|
|
|
// Convert to Ansi
|
|
OEM2ANSIA(inarg, (USHORT)strlen(inarg));
|
|
wsprintf(wcin, L"%S", inarg);
|
|
|
|
if (wcin[0] == L'"')
|
|
{
|
|
wcscpy(T, &wcin[1]);
|
|
if (T[wcslen(T)-1] == L'"')
|
|
T[wcslen(T)-1] = UNICODE_NULL;
|
|
else
|
|
return(-1); // Mismatched quotes
|
|
}
|
|
else
|
|
wcscpy(T, wcin);
|
|
|
|
retval = ExpandEnvironmentStrings(T, outarg, MAXLEN);
|
|
if ((retval == 0) || (retval > MAXLEN))
|
|
return(-1);
|
|
|
|
return(retval);
|
|
}
|
|
|
|
//
|
|
// See comment above OPTION_STRIP_CHAR definition.
|
|
//
|
|
|
|
void StripChar(WCHAR *s, WCHAR c, int num)
|
|
{
|
|
if(s)
|
|
{
|
|
WCHAR *p = s + wcslen(s) + 1;
|
|
|
|
while ((num != 0) && (p != s))
|
|
{
|
|
p--;
|
|
if (*p == c)
|
|
num--;
|
|
}
|
|
|
|
*p = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Strips the path from the
|
|
// specified string.
|
|
//
|
|
void StripPath(WCHAR *s)
|
|
{
|
|
|
|
WCHAR *p = wcsrchr(s, L'\\');
|
|
|
|
if (p != 0)
|
|
wcscpy(s, p+1);
|
|
|
|
}
|
|
|
|
//
|
|
// Populates option block.
|
|
//
|
|
int ScanOptions(WCHAR *optionString, OptionBlock* options)
|
|
{
|
|
WCHAR *curOption;
|
|
WCHAR temp[MAXLEN+1];
|
|
|
|
// Clear out option block.
|
|
memset(options, 0, sizeof(OptionBlock));
|
|
|
|
// Trivial Reject.
|
|
if (*optionString == 0)
|
|
return 0;
|
|
|
|
|
|
// Uppercase a copy of the option string.
|
|
wcscpy(temp, optionString);
|
|
_wcsupr(temp);
|
|
|
|
// Look for strip char option.
|
|
curOption = wcsstr(temp, OPTION_STRIP_CHAR);
|
|
|
|
if (curOption != 0)
|
|
{
|
|
// Change current option so it points into the original
|
|
// option, not the uppercased copy.
|
|
|
|
curOption = (WCHAR*)((INT_PTR)optionString + ((INT_PTR)curOption - (INT_PTR)temp));
|
|
|
|
|
|
// Get parameters after strip specifier.
|
|
// If there are not any then error.
|
|
curOption += (sizeof(OPTION_STRIP_CHAR)/sizeof(WCHAR)) - 1;
|
|
if (*curOption == UNICODE_NULL || *curOption == L' ')
|
|
return 1;
|
|
|
|
// Get the character to strip.
|
|
options->stripChar = *curOption++;
|
|
|
|
// Get the number of occurrrences.
|
|
// If not specified then assume 1.
|
|
if (*curOption == UNICODE_NULL || *curOption == L' ')
|
|
options->stripNthChar = 1;
|
|
else
|
|
options->stripNthChar = _wtoi(curOption);
|
|
}
|
|
|
|
|
|
// Look for leaf option.
|
|
curOption = wcsstr(temp, OPTION_STRIP_PATH);
|
|
if (curOption != UNICODE_NULL)
|
|
options->stripPath = 1;
|
|
|
|
|
|
// Look get paths option
|
|
curOption = wcsstr(temp, OPTION_GET_PATHS);
|
|
if (curOption != UNICODE_NULL)
|
|
options->getPaths = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Outputs the common directories into the temp file
|
|
// Input: file (input) pointer to open handle for the batch file
|
|
// Returns: 0 - success
|
|
// 1 - failure
|
|
//
|
|
int GetPaths(FILE *file)
|
|
{
|
|
WCHAR szPath[MAX_PATH+1];
|
|
|
|
if( !GetWindowsDirectory(szPath, MAX_PATH) ){
|
|
return (1);
|
|
}
|
|
|
|
if (SHGetFolderPath(NULL, CSIDL_COMMON_STARTMENU, NULL, 0, szPath) == S_OK) {
|
|
fwprintf(file, L"SET %s=%s\n", COMMON_START_MENU, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
if (SHGetFolderPath(NULL, CSIDL_COMMON_STARTUP, NULL, 0, szPath) == S_OK) {
|
|
fwprintf(file, L"SET %s=%s\n", COMMON_STARTUP, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
if (SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, szPath) == S_OK) {
|
|
fwprintf(file, L"SET %s=%s\n", COMMON_PROGRAMS, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
if (SHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, szPath) == S_OK) {
|
|
fwprintf(file, L"SET %s=%s\n", USER_START_MENU, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
if (SHGetFolderPath(NULL, CSIDL_STARTUP, NULL, 0, szPath) == S_OK) {
|
|
fwprintf(file, L"SET %s=%s\n", USER_STARTUP, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
if (SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, 0, szPath) == S_OK) {
|
|
fwprintf(file, L"SET %s=%s\n", USER_PROGRAMS, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
// MY_DOCUMENTS should only be the last component of the path
|
|
if (SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath) == S_OK) {
|
|
StripPath(szPath);
|
|
fwprintf(file, L"SET %s=%s\n", MY_DOCUMENTS, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
// TEMPLATES should only be the last component of the path
|
|
if (SHGetFolderPath(NULL, CSIDL_TEMPLATES, NULL, 0, szPath) == S_OK) {
|
|
StripPath(szPath);
|
|
fwprintf(file, L"SET %s=%s\n", TEMPLATES, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
// APP_DATA should only be the last component of the path
|
|
if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szPath) == S_OK) {
|
|
StripPath(szPath);
|
|
fwprintf(file, L"SET %s=%s\n", APP_DATA, szPath);
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
int __cdecl main(INT argc, CHAR **argv)
|
|
{
|
|
FILE *OutFP;
|
|
WCHAR OutFN[MAXLEN+1];
|
|
WCHAR EVName[MAXLEN+1];
|
|
WCHAR KeyName[MAXLEN+1];
|
|
WCHAR ValName[MAXLEN+1];
|
|
WCHAR Temp[MAXLEN+1];
|
|
WCHAR Opts[MAXLEN+1];
|
|
struct HKEY__ *Hive;
|
|
DWORD RetType, RetSize;
|
|
HKEY TargetKey;
|
|
LONG Ret;
|
|
OptionBlock options;
|
|
int rc=0;
|
|
|
|
//
|
|
// Process the command line arguments. We expect:
|
|
//
|
|
// acregl FileName EnvVarName KeyName ValueName Options
|
|
//
|
|
// The program uses exit code 0 to indicate success or
|
|
// exit code 1 for failure.
|
|
//
|
|
|
|
if (argc != 6)
|
|
return(1);
|
|
|
|
setlocale(LC_ALL, ".OCP");
|
|
|
|
if (ParseArg(argv[1], OutFN) <= 0)
|
|
return(1);
|
|
|
|
if (ParseArg(argv[2], EVName) <= 0)
|
|
return(1);
|
|
|
|
if (ParseArg(argv[3], Temp) <= 0)
|
|
return(1);
|
|
|
|
if (_wcsnicmp(L"HKLM\\", Temp, 5) == 0)
|
|
Hive = HKEY_LOCAL_MACHINE;
|
|
else if (_wcsnicmp(L"HKCU\\", Temp, 5) == 0)
|
|
Hive = HKEY_CURRENT_USER;
|
|
else
|
|
return(1);
|
|
wcscpy(KeyName,&Temp[5]);
|
|
|
|
if (ParseArg(argv[4], ValName) < 0) // Ok if 0 is returned
|
|
return(1);
|
|
|
|
if (ParseArg(argv[5], Opts) <= 0)
|
|
return(1);
|
|
|
|
if (ScanOptions(Opts, &options) != 0)
|
|
return 1;
|
|
|
|
// wprintf(L"OutFN <%ws>\n",OutFN);
|
|
// wprintf(L"EVName <%ws>\n",EVName);
|
|
// wprintf(L"KeyName <%ws>, Hive 0x%x\n",KeyName, Hive);
|
|
// wprintf(L"ValName <%ws>\n",ValName);
|
|
// wprintf(L"Opts <%ws>\n",Opts);
|
|
|
|
|
|
// If the GETPATHS option isn't specified, open the reg keys
|
|
if (options.getPaths == 0) {
|
|
|
|
//
|
|
// Read the specified key and value from the registry. The ANSI
|
|
// registry functions are used because the command line arguments
|
|
// are in ANSI and when we write the data out it also needs to be
|
|
// in ANSI.
|
|
//
|
|
|
|
Ret = RegOpenKeyEx(Hive, KeyName, 0, KEY_READ, &TargetKey);
|
|
if (Ret != ERROR_SUCCESS)
|
|
return(1);
|
|
|
|
RetSize = MAXLEN;
|
|
Ret = RegQueryValueEx(TargetKey, ValName, 0, &RetType, (LPBYTE) &Temp,
|
|
&RetSize);
|
|
if (Ret != ERROR_SUCCESS)
|
|
return(1);
|
|
|
|
//Now we need to procedd DWORDs too
|
|
if(RetType == REG_DWORD)
|
|
{
|
|
DWORD dwTmp = (DWORD)(*Temp);
|
|
_itow((int)dwTmp,Temp,10);
|
|
}
|
|
RegCloseKey(TargetKey);
|
|
}
|
|
|
|
//
|
|
// Process Options
|
|
//
|
|
|
|
//
|
|
// Write a SET statement to the specified file. The file can be
|
|
// executed from a script which will set the indicated environment
|
|
// variable. This is a round-about method, but there appears to be
|
|
// no easy method for setting environment variables in the parent's
|
|
// environment.
|
|
//
|
|
|
|
// wprintf(L"SET %s=%s\n",EVName,Temp);
|
|
|
|
OutFP = _wfopen(OutFN, L"w");
|
|
if (OutFP == NULL)
|
|
return(1);
|
|
|
|
if (options.stripNthChar != 0)
|
|
StripChar(Temp, options.stripChar, options.stripNthChar);
|
|
|
|
if (options.stripPath != 0)
|
|
StripPath(Temp);
|
|
|
|
if (options.getPaths != 0) {
|
|
if (GetPaths(OutFP)) {
|
|
rc = 1;
|
|
}
|
|
} else {
|
|
fwprintf(OutFP, L"SET %s=%s\n", EVName, Temp);
|
|
}
|
|
|
|
fclose(OutFP);
|
|
|
|
return(rc);
|
|
}
|