aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2018-05-29 20:52:17 +0300
committerEli Zaretskii2018-05-29 20:52:17 +0300
commit5be83e343f9f0f3487793b54ff95bc89ee6b824a (patch)
treede6c30ce8ef10deb795a9d391a9769acda6c92f0
parentfd6f08840eb095465dfe555785eee228306ab876 (diff)
downloademacs-5be83e343f9f0f3487793b54ff95bc89ee6b824a.tar.gz
emacs-5be83e343f9f0f3487793b54ff95bc89ee6b824a.zip
Allow access to MS-Windows Registry from Lisp programs
* src/w32.c (g_b_init_reg_open_key_ex_w) (g_b_init_reg_query_value_ex_w) (g_b_init_expand_environment_strings_w): New init flags. (globals_of_w32): Initialize them at startup. (RegOpenKeyExW_Proc, RegQueryValueExW_Proc) (ExpandEnvironmentStringsW_Proc): New function typedefs. (reg_open_key_ex_w, reg_query_value_ex_w) (expand_environment_strings_w): New wrapper function. (w32_read_registry): New function. * src/w32fns.c (Fw32_read_registry) [WINDOWSNT]: New primitive. (syms_of_w32fns) [WINDOWSNT]: Defsubr it. DEFSYM "HKLM", "HKCU", etc. root keys. * etc/NEWS: Mention the new primitive.
-rw-r--r--etc/NEWS7
-rw-r--r--src/w32.c291
-rw-r--r--src/w32.h2
-rw-r--r--src/w32fns.c81
4 files changed, 381 insertions, 0 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 5ac803eec4b..ea4a657cba9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -682,6 +682,13 @@ to 't' would enable the macOS proxy icon has been replaced with a
682separate variable, 'ns-use-proxy-icon'. 'frame-title-format' will now 682separate variable, 'ns-use-proxy-icon'. 'frame-title-format' will now
683work as on other platforms. 683work as on other platforms.
684 684
685---
686** New primitive 'w32-read-registry'.
687This primitive lets Lisp programs access the MS-Windows Registry by
688retrieving values stored under a given key. It is intended to be used
689for supporting features such as XDG-like location of important files
690and directories.
691
685 692
686---------------------------------------------------------------------- 693----------------------------------------------------------------------
687This file is part of GNU Emacs. 694This file is part of GNU Emacs.
diff --git a/src/w32.c b/src/w32.c
index 5ac66181403..e93aaab9ca1 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -326,6 +326,9 @@ static BOOL g_b_init_set_file_security_a;
326static BOOL g_b_init_set_named_security_info_w; 326static BOOL g_b_init_set_named_security_info_w;
327static BOOL g_b_init_set_named_security_info_a; 327static BOOL g_b_init_set_named_security_info_a;
328static BOOL g_b_init_get_adapters_info; 328static BOOL g_b_init_get_adapters_info;
329static BOOL g_b_init_reg_open_key_ex_w;
330static BOOL g_b_init_reg_query_value_ex_w;
331static BOOL g_b_init_expand_environment_strings_w;
329 332
330BOOL g_b_init_compare_string_w; 333BOOL g_b_init_compare_string_w;
331BOOL g_b_init_debug_break_process; 334BOOL g_b_init_debug_break_process;
@@ -504,6 +507,9 @@ typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
504int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int); 507int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
505int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); 508int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
506DWORD multiByteToWideCharFlags; 509DWORD multiByteToWideCharFlags;
510typedef LONG (WINAPI *RegOpenKeyExW_Proc) (HKEY,LPCWSTR,DWORD,REGSAM,PHKEY);
511typedef LONG (WINAPI *RegQueryValueExW_Proc) (HKEY,LPCWSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD);
512typedef DWORD (WINAPI *ExpandEnvironmentStringsW_Proc) (LPCWSTR,LPWSTR,DWORD);
507 513
508 /* ** A utility function ** */ 514 /* ** A utility function ** */
509static BOOL 515static BOOL
@@ -1376,6 +1382,79 @@ get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1376 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen); 1382 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1377} 1383}
1378 1384
1385static LONG WINAPI
1386reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions,
1387 REGSAM samDesired, PHKEY phkResult)
1388{
1389 static RegOpenKeyExW_Proc s_pfn_Reg_Open_Key_Ex_w = NULL;
1390 HMODULE hm_advapi32 = NULL;
1391
1392 if (is_windows_9x () == TRUE)
1393 return ERROR_NOT_SUPPORTED;
1394
1395 if (g_b_init_reg_open_key_ex_w == 0)
1396 {
1397 g_b_init_reg_open_key_ex_w = 1;
1398 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1399 if (hm_advapi32)
1400 s_pfn_Reg_Open_Key_Ex_w = (RegOpenKeyExW_Proc)
1401 GetProcAddress (hm_advapi32, "RegOpenKeyExW");
1402 }
1403 if (s_pfn_Reg_Open_Key_Ex_w == NULL)
1404 return ERROR_NOT_SUPPORTED;
1405 return s_pfn_Reg_Open_Key_Ex_w (hkey, lpSubKey, ulOptions,
1406 samDesired, phkResult);
1407}
1408
1409static LONG WINAPI
1410reg_query_value_ex_w (HKEY hkey, LPCWSTR lpValueName, LPDWORD lpReserved,
1411 LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
1412{
1413 static RegQueryValueExW_Proc s_pfn_Reg_Query_Value_Ex_w = NULL;
1414 HMODULE hm_advapi32 = NULL;
1415
1416 if (is_windows_9x () == TRUE)
1417 return ERROR_NOT_SUPPORTED;
1418
1419 if (g_b_init_reg_query_value_ex_w == 0)
1420 {
1421 g_b_init_reg_query_value_ex_w = 1;
1422 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1423 if (hm_advapi32)
1424 s_pfn_Reg_Query_Value_Ex_w = (RegQueryValueExW_Proc)
1425 GetProcAddress (hm_advapi32, "RegQueryValueExW");
1426 }
1427 if (s_pfn_Reg_Query_Value_Ex_w == NULL)
1428 return ERROR_NOT_SUPPORTED;
1429 return s_pfn_Reg_Query_Value_Ex_w (hkey, lpValueName, lpReserved,
1430 lpType, lpData, lpcbData);
1431}
1432
1433static DWORD WINAPI
1434expand_environment_strings_w (LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
1435{
1436 static ExpandEnvironmentStringsW_Proc s_pfn_Expand_Environment_Strings_w = NULL;
1437 HMODULE hm_kernel32 = NULL;
1438
1439 if (is_windows_9x () == TRUE)
1440 return ERROR_NOT_SUPPORTED;
1441
1442 if (g_b_init_expand_environment_strings_w == 0)
1443 {
1444 g_b_init_expand_environment_strings_w = 1;
1445 hm_kernel32 = LoadLibrary ("Kernel32.dll");
1446 if (hm_kernel32)
1447 s_pfn_Expand_Environment_Strings_w = (ExpandEnvironmentStringsW_Proc)
1448 GetProcAddress (hm_kernel32, "ExpandEnvironmentStringsW");
1449 }
1450 if (s_pfn_Expand_Environment_Strings_w == NULL)
1451 {
1452 errno = ENOSYS;
1453 return FALSE;
1454 }
1455 return s_pfn_Expand_Environment_Strings_w (lpSrc, lpDst, nSize);
1456}
1457
1379 1458
1380 1459
1381/* Return 1 if P is a valid pointer to an object of size SIZE. Return 1460/* Return 1 if P is a valid pointer to an object of size SIZE. Return
@@ -9269,6 +9348,215 @@ network_interface_info (Lisp_Object ifname)
9269} 9348}
9270 9349
9271 9350
9351/* Workhorse for w32-read-registry, which see. */
9352Lisp_Object
9353w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
9354{
9355 HKEY hkey = NULL;
9356 LONG status;
9357 DWORD vsize, vtype;
9358 LPBYTE pvalue;
9359 Lisp_Object val, retval;
9360 const char *key, *value_name;
9361 /* The following sizes are according to size limitations
9362 documented in MSDN. */
9363 wchar_t key_w[255+1];
9364 wchar_t value_w[16*1024+1];
9365 bool use_unicode = is_windows_9x () == 0;
9366
9367 if (use_unicode)
9368 {
9369 Lisp_Object encoded_key, encoded_vname;
9370
9371 /* Convert input strings to UTF-16. */
9372 encoded_key = code_convert_string_norecord (lkey, Qutf_16le, 1);
9373 memcpy (key_w, SSDATA (encoded_key), SBYTES (encoded_key));
9374 /* wchar_t strings need to be terminated by 2 null bytes. */
9375 key_w [SBYTES (encoded_key)/2] = L'\0';
9376 encoded_vname = code_convert_string_norecord (lname, Qutf_16le, 1);
9377 memcpy (value_w, SSDATA (encoded_vname), SBYTES (encoded_vname));
9378 value_w[SBYTES (encoded_vname)/2] = L'\0';
9379
9380 /* Mirror the slashes, if required. */
9381 for (int i = 0; i < SBYTES (encoded_key)/2; i++)
9382 {
9383 if (key_w[i] == L'/')
9384 key_w[i] = L'\\';
9385 }
9386 if ((status = reg_open_key_ex_w (rootkey, key_w, 0,
9387 KEY_READ, &hkey)) == ERROR_NOT_SUPPORTED
9388 || (status = reg_query_value_ex_w (hkey, value_w, NULL, NULL, NULL,
9389 &vsize)) == ERROR_NOT_SUPPORTED
9390 || status != ERROR_SUCCESS)
9391 {
9392 if (hkey)
9393 RegCloseKey (hkey);
9394 if (status != ERROR_NOT_SUPPORTED)
9395 return Qnil;
9396 use_unicode = 0; /* fall back to non-Unicode calls */
9397 }
9398 }
9399 if (!use_unicode)
9400 {
9401 /* Need to copy LKEY because we are going to modify it. */
9402 Lisp_Object local_lkey = Fcopy_sequence (lkey);
9403
9404 /* Mirror the slashes. Note: this has to be done before
9405 encoding, because after encoding we cannot guarantee that a
9406 slash '/' always stands for itself, it could be part of some
9407 multibyte sequence. */
9408 for (int i = 0; i < SBYTES (local_lkey); i++)
9409 {
9410 if (SSDATA (local_lkey)[i] == '/')
9411 SSDATA (local_lkey)[i] = '\\';
9412 }
9413
9414 key = SSDATA (ENCODE_SYSTEM (local_lkey));
9415 value_name = SSDATA (ENCODE_SYSTEM (lname));
9416
9417 if ((status = RegOpenKeyEx (rootkey, key, 0,
9418 KEY_READ, &hkey)) != ERROR_SUCCESS
9419 || (status = RegQueryValueEx (hkey, value_name, NULL,
9420 NULL, NULL, &vsize)) != ERROR_SUCCESS)
9421 {
9422 if (hkey)
9423 RegCloseKey (hkey);
9424 return Qnil;
9425 }
9426 }
9427
9428 pvalue = xzalloc (vsize);
9429 if (use_unicode)
9430 status = reg_query_value_ex_w (hkey, value_w, NULL, &vtype, pvalue, &vsize);
9431 else
9432 status = RegQueryValueEx (hkey, value_name, NULL, &vtype, pvalue, &vsize);
9433 if (status != ERROR_SUCCESS)
9434 {
9435 xfree (pvalue);
9436 RegCloseKey (hkey);
9437 return Qnil;
9438 }
9439
9440 switch (vtype)
9441 {
9442 case REG_NONE:
9443 retval = Qt;
9444 break;
9445 case REG_DWORD:
9446 retval = INTEGER_TO_CONS (*((DWORD *)pvalue));
9447 break;
9448 case REG_QWORD:
9449 retval = INTEGER_TO_CONS (*((long long *)pvalue));
9450 break;
9451 case REG_BINARY:
9452 {
9453 int i;
9454 unsigned char *dbuf = (unsigned char *)pvalue;
9455
9456 val = make_uninit_vector (vsize);
9457 for (i = 0; i < vsize; i++)
9458 ASET (val, i, make_number (dbuf[i]));
9459
9460 retval = val;
9461 break;
9462 }
9463 case REG_SZ:
9464 if (use_unicode)
9465 {
9466 /* pvalue ends with 2 null bytes, but we need only one,
9467 and AUTO_STRING_WITH_LEN will add it. */
9468 if (pvalue[vsize - 1] == '\0')
9469 vsize -= 2;
9470 AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
9471 retval = from_unicode (sval);
9472 }
9473 else
9474 {
9475 /* Don't waste a byte on the terminating null character,
9476 since make_unibyte_string will add one anyway. */
9477 if (pvalue[vsize - 1] == '\0')
9478 vsize--;
9479 retval = DECODE_SYSTEM (make_unibyte_string (pvalue, vsize));
9480 }
9481 break;
9482 case REG_EXPAND_SZ:
9483 if (use_unicode)
9484 {
9485 wchar_t expanded_w[32*1024];
9486 DWORD dsize = sizeof (expanded_w) / 2;
9487 DWORD produced = expand_environment_strings_w ((wchar_t *)pvalue,
9488 expanded_w,
9489 dsize);
9490 if (produced > 0 && produced < dsize)
9491 {
9492 AUTO_STRING_WITH_LEN (sval, (char *)expanded_w,
9493 produced * 2 - 2);
9494 retval = from_unicode (sval);
9495 }
9496 else
9497 {
9498 if (pvalue[vsize - 1] == '\0')
9499 vsize -= 2;
9500 AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
9501 retval = from_unicode (sval);
9502 }
9503 }
9504 else
9505 {
9506 char expanded[32*1024]; /* size limitation according to MSDN */
9507 DWORD produced = ExpandEnvironmentStrings ((char *)pvalue,
9508 expanded,
9509 sizeof (expanded));
9510 if (produced > 0 && produced < sizeof (expanded))
9511 retval = make_unibyte_string (expanded, produced - 1);
9512 else
9513 {
9514 if (pvalue[vsize - 1] == '\0')
9515 vsize--;
9516 retval = make_unibyte_string (pvalue, vsize);
9517 }
9518
9519 retval = DECODE_SYSTEM (retval);
9520 }
9521 break;
9522 case REG_MULTI_SZ:
9523 if (use_unicode)
9524 {
9525 wchar_t *wp = (wchar_t *)pvalue;
9526
9527 val = Qnil;
9528 do {
9529 size_t wslen = wcslen (wp);
9530 AUTO_STRING_WITH_LEN (sval, (char *)wp, wslen * 2);
9531 val = Fcons (from_unicode (sval), val);
9532 wp += wslen + 1;
9533 } while (*wp);
9534 }
9535 else
9536 {
9537 char *p = (char *)pvalue;
9538
9539 val = Qnil;
9540 do {
9541 size_t slen = strlen (p);
9542
9543 val = Fcons (DECODE_SYSTEM (make_unibyte_string (p, slen)), val);
9544 p += slen + 1;
9545 } while (*p);
9546 }
9547
9548 retval = Fnreverse (val);
9549 break;
9550 default:
9551 error ("unsupported registry data type: %d", (int)vtype);
9552 }
9553
9554 xfree (pvalue);
9555 RegCloseKey (hkey);
9556 return retval;
9557}
9558
9559
9272/* The Windows CRT functions are "optimized for speed", so they don't 9560/* The Windows CRT functions are "optimized for speed", so they don't
9273 check for timezone and DST changes if they were last called less 9561 check for timezone and DST changes if they were last called less
9274 than 1 minute ago (see http://support.microsoft.com/kb/821231). So 9562 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
@@ -9699,6 +9987,9 @@ globals_of_w32 (void)
9699 g_b_init_set_named_security_info_w = 0; 9987 g_b_init_set_named_security_info_w = 0;
9700 g_b_init_set_named_security_info_a = 0; 9988 g_b_init_set_named_security_info_a = 0;
9701 g_b_init_get_adapters_info = 0; 9989 g_b_init_get_adapters_info = 0;
9990 g_b_init_reg_open_key_ex_w = 0;
9991 g_b_init_reg_query_value_ex_w = 0;
9992 g_b_init_expand_environment_strings_w = 0;
9702 g_b_init_compare_string_w = 0; 9993 g_b_init_compare_string_w = 0;
9703 g_b_init_debug_break_process = 0; 9994 g_b_init_debug_break_process = 0;
9704 num_of_processors = 0; 9995 num_of_processors = 0;
diff --git a/src/w32.h b/src/w32.h
index 1e416ceead7..fe8689a07b4 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -227,6 +227,8 @@ extern int w32_compare_strings (const char *, const char *, char *, int);
227/* Return a cryptographically secure seed for PRNG. */ 227/* Return a cryptographically secure seed for PRNG. */
228extern int w32_init_random (void *, ptrdiff_t); 228extern int w32_init_random (void *, ptrdiff_t);
229 229
230extern Lisp_Object w32_read_registry (HKEY, Lisp_Object, Lisp_Object);
231
230#ifdef HAVE_GNUTLS 232#ifdef HAVE_GNUTLS
231#include <gnutls/gnutls.h> 233#include <gnutls/gnutls.h>
232 234
diff --git a/src/w32fns.c b/src/w32fns.c
index 2b920f29c65..5d1c3c84c67 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10059,6 +10059,78 @@ DEFUN ("w32-notification-close",
10059#endif /* WINDOWSNT && !HAVE_DBUS */ 10059#endif /* WINDOWSNT && !HAVE_DBUS */
10060 10060
10061 10061
10062#ifdef WINDOWSNT
10063/***********************************************************************
10064 Reading Registry
10065 ***********************************************************************/
10066DEFUN ("w32-read-registry",
10067 Fw32_read_registry, Sw32_read_registry,
10068 3, 3, 0,
10069 doc: /* Return the value stored in MS-Windows Registry under ROOT/KEY/NAME.
10070
10071ROOT is a symbol, one of `HKCR', `HKCU', `HKLM', `HKU', or `HKCC'.
10072It can also be nil, which means try `HKCU', and if that fails, try `HKLM'.
10073
10074KEY and NAME must be strings, and NAME must not include slashes.
10075KEY can use either forward- or back-slashes.
10076
10077If the the named KEY or its subkey called NAME don't exist, or cannot
10078be accessed by the current user, the function returns nil. Otherwise,
10079the return value depends on the type of the data stored in Registry:
10080
10081 If the data type is REG_NONE, the function returns t.
10082 If the data type is REG_DWORD or REG_QWORD, the function returns
10083 its integer value. If the value is too large for a Lisp integer,
10084 the function returns a cons (HIGH . LOW) of 2 integers, with LOW
10085 the low 16 bits and HIGH the high bits. If HIGH is too large for
10086 a Lisp integer, the function returns (HIGH MIDDLE . LOW), first
10087 the high bits, then the middle 24 bits, and finally the low 16 bits.
10088 If the data type is REG_BINARY, the function returns a vector whose
10089 elements are individual bytes of the value.
10090 If the data type is REG_SZ, the function returns a string.
10091 If the data type REG_EXPAND_SZ, the function returns a string with
10092 all the %..% references to environment variables replaced by the
10093 values of those variables. If the expansion fails, or some
10094 variables are not defined in the environment, some or all of
10095 the environment variables will remain unexpanded.
10096 If the data type is REG_MULTI_SZ, the function returns a list whose
10097 elements are the individual strings.
10098
10099Note that this function doesn't know whether a string value is a file
10100name, so file names will be returned with backslashes, which may need
10101to be converted to forward slashes by the caller. */)
10102 (Lisp_Object root, Lisp_Object key, Lisp_Object name)
10103{
10104 CHECK_SYMBOL (root);
10105 CHECK_STRING (key);
10106 CHECK_STRING (name);
10107
10108 HKEY rootkey;
10109 if (EQ (root, QHKCR))
10110 rootkey = HKEY_CLASSES_ROOT;
10111 else if (EQ (root, QHKCU))
10112 rootkey = HKEY_CURRENT_USER;
10113 else if (EQ (root, QHKLM))
10114 rootkey = HKEY_LOCAL_MACHINE;
10115 else if (EQ (root, QHKU))
10116 rootkey = HKEY_USERS;
10117 else if (EQ (root, QHKCC))
10118 rootkey = HKEY_CURRENT_CONFIG;
10119 else if (!NILP (root))
10120 error ("unknown root key: %s", SDATA (SYMBOL_NAME (root)));
10121
10122 Lisp_Object val = w32_read_registry (NILP (root)
10123 ? HKEY_CURRENT_USER
10124 : rootkey,
10125 key, name);
10126 if (NILP (val) && NILP (root))
10127 val = w32_read_registry (HKEY_LOCAL_MACHINE, key, name);
10128
10129 return val;
10130}
10131
10132#endif /* WINDOWSNT */
10133
10062/*********************************************************************** 10134/***********************************************************************
10063 Initialization 10135 Initialization
10064 ***********************************************************************/ 10136 ***********************************************************************/
@@ -10151,6 +10223,14 @@ syms_of_w32fns (void)
10151 DEFSYM (QCbody, ":body"); 10223 DEFSYM (QCbody, ":body");
10152#endif 10224#endif
10153 10225
10226#ifdef WINDOWSNT
10227 DEFSYM (QHKCR, "HKCR");
10228 DEFSYM (QHKCU, "HKCU");
10229 DEFSYM (QHKLM, "HKLM");
10230 DEFSYM (QHKU, "HKU");
10231 DEFSYM (QHKCC, "HKCC");
10232#endif
10233
10154 /* Symbols used elsewhere, but only in MS-Windows-specific code. */ 10234 /* Symbols used elsewhere, but only in MS-Windows-specific code. */
10155 DEFSYM (Qgnutls, "gnutls"); 10235 DEFSYM (Qgnutls, "gnutls");
10156 DEFSYM (Qlibxml2, "libxml2"); 10236 DEFSYM (Qlibxml2, "libxml2");
@@ -10508,6 +10588,7 @@ tip frame. */);
10508#endif 10588#endif
10509 10589
10510#ifdef WINDOWSNT 10590#ifdef WINDOWSNT
10591 defsubr (&Sw32_read_registry);
10511 defsubr (&Sfile_system_info); 10592 defsubr (&Sfile_system_info);
10512 defsubr (&Sdefault_printer_name); 10593 defsubr (&Sdefault_printer_name);
10513#endif 10594#endif