diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:14:06 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:14:06 +0000 |
commit | eee068778cb28ecf3c14e1bf843a95547d72c42d (patch) | |
tree | 0e07b30ddc5ea579d682d5dbe57998200d1c9ab7 /build-aux/speedo/w32/g4wihelp.c | |
parent | Initial commit. (diff) | |
download | gnupg2-eee068778cb28ecf3c14e1bf843a95547d72c42d.tar.xz gnupg2-eee068778cb28ecf3c14e1bf843a95547d72c42d.zip |
Adding upstream version 2.2.40.upstream/2.2.40upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | build-aux/speedo/w32/g4wihelp.c | 1175 |
1 files changed, 1175 insertions, 0 deletions
diff --git a/build-aux/speedo/w32/g4wihelp.c b/build-aux/speedo/w32/g4wihelp.c new file mode 100644 index 0000000..626f3f1 --- /dev/null +++ b/build-aux/speedo/w32/g4wihelp.c @@ -0,0 +1,1175 @@ +/* g4wihelp.c - NSIS Helper DLL used with gpg4win. -*- coding: latin-1; -*- + * Copyright (C) 2005 g10 Code GmbH + * Copyright (C) 2001 Justin Frankel + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ************************************************************ + * The code for the splash screen has been taken from the Splash + * plugin of the NSIS 2.04 distribution. That code comes without + * explicit copyright notices in the source files or author names, it + * seems that it has been written by Justin Frankel; not sure about + * the year, though. [wk 2005-11-28] + * + * Fixed some compiler warnings. [wk 2014-02-24]. + */ + +#include <stdio.h> +#include <windows.h> +#include "exdll.h" + +static HINSTANCE g_hInstance; /* Our Instance. */ +static HWND g_hwndParent; /* Handle of parent window or NULL. */ +static HBITMAP g_hbm; /* Handle of the splash image. */ +static int sleepint; /* Milliseconds to show the spals image. */ + + +/* Standard entry point for DLLs. */ +int WINAPI +DllMain (HANDLE hinst, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + g_hInstance = hinst; + return TRUE; +} + + + +/* Dummy function for testing. */ +void __declspec(dllexport) +dummy (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + g_hwndParent = hwndParent; + + EXDLL_INIT(); + + // note if you want parameters from the stack, pop them off in order. + // i.e. if you are called via exdll::myFunction file.dat poop.dat + // calling popstring() the first time would give you file.dat, + // and the second time would give you poop.dat. + // you should empty the stack of your parameters, and ONLY your + // parameters. + + // do your stuff here + { + char buf[1024]; + snprintf (buf, sizeof buf, "$R0=%s\r\n$R1=%s\r\n", + getuservariable(INST_R0), + getuservariable(INST_R1)); + MessageBox (g_hwndParent,buf,0,MB_OK); + + snprintf (buf, sizeof buf, + "autoclose =%d\r\n" + "all_user_var =%d\r\n" + "exec_error =%d\r\n" + "abort =%d\r\n" + "exec_reboot =%d\r\n" + "reboot_called=%d\r\n" + "silent =%d\r\n" + "instdir_error=%d\r\n" + "rtl =%d\r\n" + "errlvl =%d\r\n", + extra->exec_flags->autoclose, + extra->exec_flags->all_user_var, + extra->exec_flags->exec_error, + extra->exec_flags->abort, + extra->exec_flags->exec_reboot, + extra->exec_flags->reboot_called, + extra->exec_flags->silent, + extra->exec_flags->instdir_error, + extra->exec_flags->rtl, + extra->exec_flags->errlvl); + MessageBox(g_hwndParent,buf,0,MB_OK); + } +} + + +void __declspec(dllexport) +runonce (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + const char *result; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + CreateMutexA (NULL, 0, getuservariable(INST_R0)); + result = GetLastError ()? "1":"0"; + setuservariable (INST_R0, result); +} + + +void __declspec(dllexport) +playsound (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + char fname[MAX_PATH]; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + if (popstring(fname, sizeof fname)) + return; + PlaySound (fname, NULL, SND_ASYNC|SND_FILENAME|SND_NODEFAULT); +} + + +void __declspec(dllexport) +stopsound (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + g_hwndParent = hwndParent; + EXDLL_INIT(); + PlaySound (NULL, NULL, 0); +} + + +/* Windows procedure to control the splashimage. This one pauses the + execution until the sleep time is over or the user closes this + windows. */ +static LRESULT CALLBACK +splash_wndproc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result = 0; + + switch (uMsg) + { + case WM_CREATE: + { + BITMAP bm; + RECT vp; + + GetObject(g_hbm, sizeof(bm), (LPSTR)&bm); + SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0); + SetWindowLong(hwnd,GWL_STYLE,0); + SetWindowPos(hwnd,NULL, + vp.left+(vp.right-vp.left-bm.bmWidth)/2, + vp.top+(vp.bottom-vp.top-bm.bmHeight)/2, + bm.bmWidth,bm.bmHeight, + SWP_NOZORDER); + ShowWindow(hwnd,SW_SHOW); + SetTimer(hwnd,1,sleepint,NULL); + } + break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + RECT r; + HDC curdc=BeginPaint(hwnd,&ps); + HDC hdc=CreateCompatibleDC(curdc); + HBITMAP oldbm; + GetClientRect(hwnd,&r); + oldbm=(HBITMAP)SelectObject(hdc,g_hbm); + BitBlt(curdc,r.left,r.top,r.right-r.left,r.bottom-r.top, + hdc,0,0,SRCCOPY); + SelectObject(hdc,oldbm); + DeleteDC(hdc); + EndPaint(hwnd,&ps); + } + break; + + case WM_CLOSE: + break; + + case WM_TIMER: + case WM_LBUTTONDOWN: + DestroyWindow(hwnd); + /*(fall through)*/ + default: + result = DefWindowProc (hwnd, uMsg, wParam, lParam); + } + + return result; +} + + +/* Display a splash screen. Call as + + g4wihelp::showsplash SLEEP FNAME + + With SLEEP being the time in milliseconds to show the splashscreen + and FNAME the complete filename of the image. As of now only BMP + is supported. +*/ +void __declspec(dllexport) +showsplash (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + static WNDCLASS wc; + char sleepstr[30]; + char fname[MAX_PATH]; + int err = 0; + char *p; + char classname[] = "_sp"; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + if (popstring(sleepstr, sizeof sleepstr)) + err = 1; + if (popstring(fname, sizeof fname)) + err = 1; + if (err) + return; + + if (!*fname) + return; /* Nothing to do. */ + + for (sleepint=0, p=sleepstr; *p >= '0' && *p <= '9'; p++) + { + sleepint *= 10; + sleepint += *p - '0'; + } + if (sleepint <= 0) + return; /* Nothing to do. */ + + wc.lpfnWndProc = splash_wndproc; + wc.hInstance = g_hInstance; + wc.hCursor = LoadCursor(NULL,IDC_ARROW); + wc.lpszClassName = classname; + if (!RegisterClass(&wc)) + return; /* Error. */ + + g_hbm = LoadImage (NULL, fname, IMAGE_BITMAP, + 0, 0 , LR_CREATEDIBSECTION|LR_LOADFROMFILE); + if (g_hbm) + { + MSG msg; + HWND hwnd; + + hwnd = CreateWindowEx (WS_EX_TOOLWINDOW, classname, classname, + 0, 0, 0, 0, 0, (HWND)hwndParent, NULL, + g_hInstance, NULL); + + while (IsWindow(hwnd) && GetMessage ( &msg, hwnd, 0, 0)) + { + DispatchMessage (&msg); + } + + DeleteObject (g_hbm); + g_hbm = NULL; + } + UnregisterClass (classname, g_hInstance); +} + + +/* Service Management. */ + +/* Use this to report unexpected errors. FIXME: This is really not + very descriptive. */ +void +service_error (const char *str) +{ + char buf[1024]; + snprintf (buf, sizeof (buf), "error: %s: ec=%d\r\n", str, + GetLastError ()); + MessageBox(g_hwndParent, buf, 0, MB_OK); + + setuservariable (INST_R0, "1"); +} + + +void __declspec(dllexport) +service_create (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + SC_HANDLE sc; + SC_HANDLE service; + const char *result = NULL; + char service_name[256]; + char display_name[256]; + char program[256]; + int err = 0; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: service_name, display_name, program. */ + if (popstring (service_name, sizeof (service_name))) + err = 1; + if (!err && popstring (display_name, sizeof (display_name))) + err = 1; + if (!err && popstring (program, sizeof (program))) + err = 1; + if (err) + { + setuservariable (INST_R0, "1"); + return; + } + + sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (sc == NULL) + { + service_error ("OpenSCManager"); + return; + } + + service = CreateService (sc, service_name, display_name, + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, + /* Use SERVICE_DEMAND_START for testing. + FIXME: Currently not configurable by caller. */ + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, program, + NULL, NULL, NULL, + /* FIXME: Currently not configurable by caller. */ + /* FIXME: LocalService or NetworkService + don't work for dirmngr right now. NOTE! + If you change it here, you also should + adjust make-msi.pl for the msi + installer. In the future, this should + be an argument to the function and then + the make-msi.pl script can extract it + from the invocation. */ + NULL /* "NT AUTHORITY\\LocalService" */, + NULL); + if (service == NULL) + { + service_error ("CreateService"); + CloseServiceHandle (sc); + return; + } + CloseServiceHandle (service); + + result = GetLastError () ? "1":"0"; + setuservariable (INST_R0, result); + return; +} + + +/* Requires g_hwndParent to be set! */ +SC_HANDLE +service_lookup (char *service_name) +{ + SC_HANDLE sc; + SC_HANDLE service; + + sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (sc == NULL) + { + service_error ("OpenSCManager"); + return NULL; + } + service = OpenService (sc, service_name, SC_MANAGER_ALL_ACCESS); + if (service == NULL) + { + /* Fail silently here. */ + CloseServiceHandle (sc); + return NULL; + } + CloseServiceHandle (sc); + return service; +} + + +/* Returns status. */ +void __declspec(dllexport) +service_query (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + SC_HANDLE service; + const char *result = NULL; + char service_name[256]; + int err = 0; + SERVICE_STATUS status; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: service_name argc [argv]. */ + if (popstring (service_name, sizeof (service_name))) + err = 1; + if (err) + { + setuservariable (INST_R0, "ERROR"); + return; + } + + service = service_lookup (service_name); + if (service == NULL) + if (err == 0) + { + setuservariable (INST_R0, "MISSING"); + return; + } + + err = QueryServiceStatus (service, &status); + if (err == 0) + { + setuservariable (INST_R0, "ERROR"); + CloseServiceHandle (service); + return; + } + CloseServiceHandle (service); + + switch (status.dwCurrentState) + { + case SERVICE_START_PENDING: + result = "START_PENDING"; + break; + case SERVICE_RUNNING: + result = "RUNNING"; + break; + case SERVICE_PAUSE_PENDING: + result = "PAUSE_PENDING"; + break; + case SERVICE_PAUSED: + result = "PAUSED"; + break; + case SERVICE_CONTINUE_PENDING: + result = "CONTINUE_PENDING"; + break; + case SERVICE_STOP_PENDING: + result = "STOP_PENDING"; + break; + case SERVICE_STOPPED: + result = "STOPPED"; + break; + default: + result = "UNKNOWN"; + } + setuservariable (INST_R0, result); + return; +} + + +void __declspec(dllexport) +service_start (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + SC_HANDLE service; + const char *result = NULL; + char service_name[256]; + char argc_str[256]; +#define NR_ARGS 10 +#define ARG_MAX 256 + char argv_str[NR_ARGS][ARG_MAX]; + const char *argv[NR_ARGS + 1]; + int argc; + int i; + int err = 0; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: service_name argc [argv]. */ + if (popstring (service_name, sizeof (service_name))) + err = 1; + if (!err && popstring (argc_str, sizeof (argc_str))) + err = 1; + if (!err) + { + argc = atoi (argc_str); + for (i = 0; i < argc; i++) + { + if (popstring (argv_str[i], ARG_MAX)) + { + err = 1; + break; + } + argv[i] = argv_str[i]; + } + argv[i] = NULL; + } + if (err) + { + setuservariable (INST_R0, "1"); + return; + } + + service = service_lookup (service_name); + if (service == NULL) + return; + + err = StartService (service, argc, argc == 0 ? NULL : argv); + if (err == 0) + { + service_error ("StartService"); + CloseServiceHandle (service); + return; + } + CloseServiceHandle (service); + + setuservariable (INST_R0, "0"); + return; +} + + +void __declspec(dllexport) +service_stop (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + SC_HANDLE service; + const char *result = NULL; + char service_name[256]; + int err = 0; + SERVICE_STATUS status; + DWORD timeout = 10000; /* 10 seconds. */ + DWORD start_time; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: service_name argc [argv]. */ + if (popstring (service_name, sizeof (service_name))) + err = 1; + if (err) + { + setuservariable (INST_R0, "1"); + return; + } + + service = service_lookup (service_name); + if (service == NULL) + return; + + err = QueryServiceStatus (service, &status); + if (err == 0) + { + service_error ("QueryService"); + CloseServiceHandle (service); + return; + } + + if (status.dwCurrentState != SERVICE_STOPPED + && status.dwCurrentState != SERVICE_STOP_PENDING) + { + err = ControlService (service, SERVICE_CONTROL_STOP, &status); + if (err == 0) + { + service_error ("ControlService"); + CloseServiceHandle (service); + return; + } + } + + start_time = GetTickCount (); + while (status.dwCurrentState != SERVICE_STOPPED) + { + Sleep (1000); /* One second. */ + if (!QueryServiceStatus (service, &status)) + { + service_error ("QueryService"); + CloseServiceHandle (service); + return; + } + if (status.dwCurrentState == SERVICE_STOPPED) + break; + + if (GetTickCount () - start_time > timeout) + { + char buf[1024]; + snprintf (buf, sizeof (buf), + "time out waiting for service %s to stop\r\n", + service_name); + MessageBox (g_hwndParent, buf, 0, MB_OK); + setuservariable (INST_R0, "1"); + return; + } + } + CloseServiceHandle (service); + setuservariable (INST_R0, "0"); + return; +} + + +void __declspec(dllexport) +service_delete (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + SC_HANDLE service; + const char *result = NULL; + char service_name[256]; + int err = 0; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: service_name argc [argv]. */ + if (popstring (service_name, sizeof (service_name))) + err = 1; + if (err) + { + setuservariable (INST_R0, "1"); + return; + } + + service = service_lookup (service_name); + if (service == NULL) + return; + + err = DeleteService (service); + if (err == 0) + { + service_error ("DeleteService"); + CloseServiceHandle (service); + return; + } + CloseServiceHandle (service); + + setuservariable (INST_R0, "0"); + return; +} + + +#include <stdio.h> + +/* Extract config file parameters. FIXME: Not particularly robust. + We expect some reasonable formatting. The parser below is very + limited. It expects a command line option /c=FILE or /C=FILE, + where FILE must be enclosed in double-quotes if it contains spaces. + That file should contain a single section [gpg4win] and KEY=VALUE + pairs for each additional configuration file to install. Comments + are supported only on lines by themselves. VALUE can be quoted in + double-quotes, but does not need to be, unless it has whitespace at + the beginning or end. KEY can, for example, be "gpg.conf" (without + the quotes). */ +void +config_init (char **keys, char **values, int max) +{ + /* First, parse the command line. */ + char *cmdline; + char *begin = NULL; + char *end = NULL; + char mark; + char *fname; + char *ptr; + FILE *conf; + + *keys = NULL; + *values = NULL; + + cmdline = getuservariable (INST_CMDLINE); + + mark = (*cmdline == '"') ? (cmdline++, '"') : ' '; + while (*cmdline && *cmdline != mark) + cmdline++; + if (mark == '"' && *cmdline) + cmdline++; + while (*cmdline && *cmdline == ' ') + cmdline++; + + while (*cmdline) + { + /* We are at the beginning of a new argument. */ + if (cmdline[0] == '/' && (cmdline[1] == 'C' || cmdline[1] == 'c') + && cmdline[2] == '=') + { + cmdline += 3; + begin = cmdline; + } + + while (*cmdline && *cmdline != ' ') + { + /* Skip over quoted parts. */ + if (*cmdline == '"') + { + cmdline++; + while (*cmdline && *cmdline != '"') + cmdline++; + if (*cmdline) + cmdline++; + } + else + cmdline++; + } + if (begin && !end) + { + end = cmdline - 1; + break; + } + while (*cmdline && *cmdline == ' ') + cmdline++; + } + + if (!begin || begin > end) + return; + + /* Strip quotes. */ + if (*begin == '"' && *end == '"') + { + begin++; + end--; + } + if (begin > end) + return; + + fname = malloc (end - begin + 2); + if (!fname) + return; + + ptr = fname; + while (begin <= end) + *(ptr++) = *(begin++); + *ptr = '\0'; + + conf = fopen (fname, "r"); + free (fname); + if (!conf) + return; + + while (max - 1 > 0) + { + char line[256]; + char *ptr2; + + if (fgets (line, sizeof (line), conf) == NULL) + break; + ptr = &line[strlen (line)]; + while (ptr > line && (ptr[-1] == '\n' || ptr[-1] == '\r' + || ptr[-1] == ' ' || ptr[-1] == '\t')) + ptr--; + *ptr = '\0'; + + ptr = line; + while (*ptr && (*ptr == ' ' || *ptr == '\t')) + ptr++; + /* Ignore comment lines. */ + /* FIXME: Ignore section markers. */ + if (*ptr == '\0' || *ptr == ';' || *ptr == '[') + continue; + begin = ptr; + while (*ptr && *ptr != '=' && *ptr != ' ' && *ptr != '\t') + ptr++; + end = ptr - 1; + while (*ptr && (*ptr == ' ' || *ptr == '\t')) + ptr++; + if (*ptr != '=') + continue; + ptr++; + + if (begin > end) + continue; + + /* We found a key. */ + *keys = malloc (end - begin + 2); + if (!keys) + return; + ptr2 = *keys; + while (begin <= end) + *(ptr2++) = *(begin++); + *ptr2 = '\0'; + + *values = NULL; + + while (*ptr && (*ptr == ' ' || *ptr == '\t')) + ptr++; + begin = ptr; + /* In this case, end points to the byte after the value, which + is OK because that is '\0'. */ + end = &line[strlen (line)]; + if (begin > end) + begin = end; + + /* Strip quotes. */ + if (*begin == '"' && end[-1] == '"') + { + begin++; + end--; + *end = '\0'; + } + if (begin > end) + return; + + *values = malloc (end - begin + 1); + ptr2 = *values; + while (begin <= end) + *(ptr2++) = *(begin++); + + keys++; + values++; + max--; + } + + fclose (conf); + *keys = NULL; + *values = NULL; +} + + +char * +config_lookup (char *key) +{ +#define MAX_KEYS 128 + static int initialised = 0; + static char *keys[MAX_KEYS]; + static char *values[MAX_KEYS]; + int i; + + if (initialised == 0) + { + initialised = 1; + config_init (keys, values, MAX_KEYS); + +#if 0 + MessageBox(g_hwndParent, "Configuration File:", 0, MB_OK); + i = 0; + while (keys[i]) + { + char buf[256]; + sprintf (buf, "%s=%s\r\n", keys[i], values[i]); + MessageBox (g_hwndParent, buf, 0, MB_OK); + i++; + } +#endif + } + + i = 0; + while (keys[i]) + { + if (!strcmp (keys[i], key)) + return values[i]; + i++; + } + + return NULL; +} + + +void __declspec(dllexport) +config_fetch (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + char key[256]; + int err = 0; + char *value; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: key. */ + if (popstring (key, sizeof (key))) + err = 1; + if (err) + { + setuservariable (INST_R0, ""); + return; + } + + value = config_lookup (key); + + setuservariable (INST_R0, value == NULL ? "" : value); + return; +} + + +void __declspec(dllexport) +config_fetch_bool (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + char key[256]; + int err = 0; + char *value; + int result; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + /* The expected stack layout: key. */ + if (popstring (key, sizeof (key))) + err = 1; + if (err) + { + setuservariable (INST_R0, ""); + return; + } + + value = config_lookup (key); + if (value == NULL || *value == '\0') + { + setuservariable (INST_R0, ""); + return; + } + + result = 0; + if (!strcasecmp (value, "true") + || !strcasecmp (value, "yes") + || atoi (value) != 0) + result = 1; + + setuservariable (INST_R0, result == 0 ? "0" : "1"); + return; +} + + +/* Return a string from the Win32 Registry or NULL in case of error. + Caller must release the return value. A NULL for root is an alias + for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */ +char * +read_w32_registry_string (HKEY root, const char *dir, const char *name) +{ + HKEY root_key; + HKEY key_handle; + DWORD n1, nbytes, type; + char *result = NULL; + + root_key = root; + if (! root_key) + root_key = HKEY_CURRENT_USER; + + if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) ) + { + if (root) + return NULL; /* no need for a RegClose, so return direct */ + /* It seems to be common practise to fall back to HKLM. */ + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) + return NULL; /* still no need for a RegClose, so return direct */ + } + + nbytes = 1; + if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) { + if (root) + goto leave; + /* Try to fallback to HKLM also vor a missing value. */ + RegCloseKey (key_handle); + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) + return NULL; /* Nope. */ + if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes)) + goto leave; + } + + result = malloc( (n1=nbytes+1) ); + + if( !result ) + goto leave; + if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) { + free(result); result = NULL; + goto leave; + } + result[nbytes] = 0; /* make sure it is really a string */ + + leave: + RegCloseKey( key_handle ); + return result; +} + + +#define ENV_HK HKEY_LOCAL_MACHINE +#define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \ + "Session Manager\\Environment" + /* The following setting can be used for a per-user setting. */ +#define ENV_HK_USER HKEY_CURRENT_USER +#define ENV_REG_USER "Environment" +/* Due to a bug in Windows7 (kb 2685893) we better put a lower limit + than 8191 on the maximum length of the PATH variable. Note, that + depending on the used toolchain we used to had a 259 byte limit in + the past. */ +#define PATH_LENGTH_LIMIT 2047 + +void __declspec(dllexport) +path_add (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + char dir[PATH_LENGTH_LIMIT]; + char is_user_install[2]; + char *path; + char *path_new; + int path_new_size; + char *comp; + const char delims[] = ";"; + int is_user; + HKEY key_handle = 0; + HKEY root_key; + const char *env_reg; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + setuservariable (INST_R0, "0"); + +/* MessageBox (g_hwndParent, "XXX 1", 0, MB_OK); */ + + /* The expected stack layout: path component. */ + if (popstring (dir, sizeof (dir))) + return; + + /* The expected stack layout: HKEY component. */ + if (popstring (is_user_install, sizeof (is_user_install))) + return; + + if (!strcmp(is_user_install, "1")) + { + root_key = ENV_HK_USER; + env_reg = ENV_REG_USER; + } + else + { + root_key = ENV_HK; + env_reg = ENV_REG; + } + + path = read_w32_registry_string (root_key, env_reg, "Path"); + + if (! path) + { + path = strdup (""); + } + +/* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */ + + /* Old path plus semicolon plus dir plus terminating nul. */ + path_new_size = strlen (path) + 1 + strlen (dir) + 1; + if (path_new_size > PATH_LENGTH_LIMIT) + { + MessageBox (g_hwndParent, "PATH env variable too big", 0, MB_OK); + free (path); + return; + } + +/* MessageBox (g_hwndParent, "XXX 4", 0, MB_OK); */ + + path_new = malloc (path_new_size); + if (!path_new) + { + free (path); + return; + } + +/* MessageBox (g_hwndParent, "XXX 5", 0, MB_OK); */ + + strcpy (path_new, path); + strcat (path_new, ";"); + strcat (path_new, dir); + +/* MessageBox (g_hwndParent, "XXX 6", 0, MB_OK); */ +/* MessageBox (g_hwndParent, dir, 0, MB_OK); */ +/* MessageBox (g_hwndParent, "XXX 7", 0, MB_OK); */ + + /* Check if the directory already exists in the path. */ + comp = strtok (path, delims); + do + { +/* MessageBox (g_hwndParent, comp, 0, MB_OK); */ + if (!comp) + break; + + if (!strcmp (comp, dir)) + { + free (path); + free (path_new); + return; + } + comp = strtok (NULL, delims); + } + while (comp); + free (path); + + /* Update the path key. */ + RegCreateKey (root_key, env_reg, &key_handle); + RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, + path_new, path_new_size); + RegCloseKey (key_handle); + SetEnvironmentVariable("PATH", path_new); + free (path_new); + +/* MessageBox (g_hwndParent, "XXX 9", 0, MB_OK); */ + + setuservariable (INST_R0, "1"); +} + + +void __declspec(dllexport) +path_remove (HWND hwndParent, int string_size, char *variables, + stack_t **stacktop, extra_parameters_t *extra) +{ + char dir[PATH_LENGTH_LIMIT]; + char is_user_install[2]; + char *path; + char *path_new; + int path_new_size; + char *comp; + const char delims[] = ";"; + HKEY key_handle = 0; + int changed = 0; + int count = 0; + HKEY root_key; + const char *env_reg; + + g_hwndParent = hwndParent; + EXDLL_INIT(); + + setuservariable (INST_R0, "0"); + + /* The expected stack layout: path component. */ + if (popstring (dir, sizeof (dir))) + return; + + /* The expected stack layout: HKEY component. */ + if (popstring (is_user_install, sizeof (is_user_install))) + return; + + if (!strcmp(is_user_install, "1")) + { + root_key = ENV_HK_USER; + env_reg = ENV_REG_USER; + } + else + { + root_key = ENV_HK; + env_reg = ENV_REG; + } + + path = read_w32_registry_string (root_key, env_reg, "Path"); + + if (!path) + return; + /* Old path plus semicolon plus dir plus terminating nul. */ + path_new_size = strlen (path) + 1; + path_new = malloc (path_new_size); + if (!path_new) + { + free (path); + return; + } + path_new[0] = '\0'; + + /* Compose the new path. */ + comp = strtok (path, delims); + do + { + if (strcmp (comp, dir)) + { + if (count != 0) + strcat (path_new, ";"); + strcat (path_new, comp); + count++; + } + else + changed = 1; + + comp = strtok (NULL, delims); + } + while (comp); + free (path); + + if (! changed) + { + free (path_new); + return; + } + + /* Set a key for our CLSID. */ + RegCreateKey (root_key, env_reg, &key_handle); + RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, + path_new, path_new_size); + RegCloseKey (key_handle); + free (path_new); + + setuservariable (INST_R0, "1"); +} |