Extend and improve w32-shell-execute on MS-Windows.
src/w32fns.c (Fw32_shell_execute) [!CYGWIN]: Use ShellExecuteEx, to support more "verbs".
This commit is contained in:
parent
f58269c4b2
commit
6d731d4183
2 changed files with 146 additions and 99 deletions
|
@ -1,3 +1,8 @@
|
|||
2014-03-21 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* w32fns.c (Fw32_shell_execute) [!CYGWIN]: Use ShellExecuteEx, to
|
||||
support more "verbs".
|
||||
|
||||
2014-03-21 Daniel Colascione <dancol@dancol.org>
|
||||
|
||||
Always prohibit dumping a dumped Emacs.
|
||||
|
|
240
src/w32fns.c
240
src/w32fns.c
|
@ -6868,24 +6868,33 @@ handler application, but typically it is one of the following common
|
|||
specified DOCUMENT.
|
||||
\"find\" - initiate search starting from DOCUMENT, which must specify
|
||||
a directory.
|
||||
\"delete\" - move DOCUMENT, a file or a directory, to Recycle Bin.
|
||||
\"copy\" - copy DOCUMENT, which must be a file or a directory, into
|
||||
the clipboard.
|
||||
\"cut\" - move DOCUMENT, a file or a directory, into the clipboard.
|
||||
\"paste\" - paste the file whose name is in the clipboard into DOCUMENT,
|
||||
which must be a directory.
|
||||
\"pastelink\"
|
||||
- create a shortcut in DOCUMENT (which must be a directory)
|
||||
the file or directory whose name is in the clipboard.
|
||||
\"runas\" - run DOCUMENT, which must be an excutable file, with
|
||||
elevated privileges (a.k.a. \"as Administrator\").
|
||||
\"properties\"
|
||||
- open the the property sheet dialog for DOCUMENT; works
|
||||
for *.lnk desktop shortcuts, and little or nothing else.
|
||||
- open the the property sheet dialog for DOCUMENT.
|
||||
nil - invoke the default OPERATION, or \"open\" if default is
|
||||
not defined or unavailable.
|
||||
|
||||
DOCUMENT is typically the name of a document file or a URL, but can
|
||||
also be an executable program to run, or a directory to open in the
|
||||
Windows Explorer. If it is a file, it must be a local one; this
|
||||
function does not support remote file names.
|
||||
Windows Explorer. If it is a file or a directory, it must be a local
|
||||
one; this function does not support remote file names.
|
||||
|
||||
If DOCUMENT is an executable program, the optional third arg PARAMETERS
|
||||
can be a string containing command line parameters that will be passed
|
||||
to the program. Some values of OPERATION also require parameters (e.g.,
|
||||
\"printto\" requires the printer address). Otherwise, PARAMETERS should
|
||||
be nil or unspecified.
|
||||
can be a string containing command line parameters, separated by blanks,
|
||||
that will be passed to the program. Some values of OPERATION also require
|
||||
parameters (e.g., \"printto\" requires the printer address). Otherwise,
|
||||
PARAMETERS should be nil or unspecified. Note that double quote characters
|
||||
in PARAMETERS must each be enclosed in 2 additional quotes, as in \"\"\".
|
||||
|
||||
Optional fourth argument SHOW-FLAG can be used to control how the
|
||||
application will be displayed when it is invoked. If SHOW-FLAG is nil
|
||||
|
@ -6908,6 +6917,7 @@ a ShowWindow flag:
|
|||
int use_unicode = w32_unicode_filenames;
|
||||
char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
|
||||
Lisp_Object absdoc, handler;
|
||||
BOOL success;
|
||||
struct gcpro gcpro1;
|
||||
#endif
|
||||
|
||||
|
@ -6935,97 +6945,6 @@ a ShowWindow flag:
|
|||
GUI_SDATA (current_dir),
|
||||
(INTEGERP (show_flag)
|
||||
? XINT (show_flag) : SW_SHOWDEFAULT));
|
||||
#else /* !CYGWIN */
|
||||
current_dir = ENCODE_FILE (current_dir);
|
||||
/* We have a situation here. If DOCUMENT is a relative file name,
|
||||
but its name includes leading directories, i.e. it lives not in
|
||||
CURRENT_DIR, but in its subdirectory, then ShellExecute below
|
||||
will fail to find it. So we need to make the file name is
|
||||
absolute. But DOCUMENT does not have to be a file, it can be a
|
||||
URL, for example. So we make it absolute only if it is an
|
||||
existing file; if it is a file that does not exist, tough. */
|
||||
GCPRO1 (absdoc);
|
||||
absdoc = Fexpand_file_name (document, Qnil);
|
||||
/* Don't call file handlers for file-exists-p, since they might
|
||||
attempt to access the file, which could fail or produce undesired
|
||||
consequences, see bug#16558 for an example. */
|
||||
handler = Ffind_file_name_handler (absdoc, Qfile_exists_p);
|
||||
if (NILP (handler))
|
||||
{
|
||||
Lisp_Object absdoc_encoded = ENCODE_FILE (absdoc);
|
||||
|
||||
if (faccessat (AT_FDCWD, SSDATA (absdoc_encoded), F_OK, AT_EACCESS) == 0)
|
||||
document = absdoc_encoded;
|
||||
else
|
||||
document = ENCODE_FILE (document);
|
||||
}
|
||||
else
|
||||
document = ENCODE_FILE (document);
|
||||
UNGCPRO;
|
||||
if (use_unicode)
|
||||
{
|
||||
wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
|
||||
|
||||
/* Encode filename, current directory and parameters, and
|
||||
convert operation to UTF-16. */
|
||||
filename_to_utf16 (SSDATA (current_dir), current_dir_w);
|
||||
filename_to_utf16 (SSDATA (document), document_w);
|
||||
doc_w = document_w;
|
||||
if (STRINGP (parameters))
|
||||
{
|
||||
int len;
|
||||
|
||||
parameters = ENCODE_SYSTEM (parameters);
|
||||
len = pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
|
||||
SSDATA (parameters), -1, NULL, 0);
|
||||
if (len > 32768)
|
||||
len = 32768;
|
||||
params_w = alloca (len * sizeof (wchar_t));
|
||||
pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
|
||||
SSDATA (parameters), -1, params_w, len);
|
||||
}
|
||||
if (STRINGP (operation))
|
||||
{
|
||||
/* Assume OPERATION is pure ASCII. */
|
||||
const char *s = SSDATA (operation);
|
||||
wchar_t *d;
|
||||
int len = SBYTES (operation) + 1;
|
||||
|
||||
if (len > 32768)
|
||||
len = 32768;
|
||||
d = ops_w = alloca (len * sizeof (wchar_t));
|
||||
while (d < ops_w + len - 1)
|
||||
*d++ = *s++;
|
||||
*d = 0;
|
||||
}
|
||||
result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
|
||||
current_dir_w,
|
||||
(INTEGERP (show_flag)
|
||||
? XINT (show_flag) : SW_SHOWDEFAULT));
|
||||
}
|
||||
else
|
||||
{
|
||||
char document_a[MAX_PATH], current_dir_a[MAX_PATH];
|
||||
|
||||
filename_to_ansi (SSDATA (current_dir), current_dir_a);
|
||||
filename_to_ansi (SSDATA (document), document_a);
|
||||
doc_a = document_a;
|
||||
if (STRINGP (parameters))
|
||||
{
|
||||
parameters = ENCODE_SYSTEM (parameters);
|
||||
params_a = SSDATA (parameters);
|
||||
}
|
||||
if (STRINGP (operation))
|
||||
{
|
||||
/* Assume OPERATION is pure ASCII. */
|
||||
ops_a = SSDATA (operation);
|
||||
}
|
||||
result = (intptr_t) ShellExecuteA (NULL, ops_a, doc_a, params_a,
|
||||
current_dir_a,
|
||||
(INTEGERP (show_flag)
|
||||
? XINT (show_flag) : SW_SHOWDEFAULT));
|
||||
}
|
||||
#endif /* !CYGWIN */
|
||||
|
||||
if (result > 32)
|
||||
return Qt;
|
||||
|
@ -7065,6 +6984,129 @@ a ShowWindow flag:
|
|||
errstr = w32_strerror (0);
|
||||
break;
|
||||
}
|
||||
|
||||
#else /* !CYGWIN */
|
||||
|
||||
current_dir = ENCODE_FILE (current_dir);
|
||||
/* We have a situation here. If DOCUMENT is a relative file name,
|
||||
but its name includes leading directories, i.e. it lives not in
|
||||
CURRENT_DIR, but in its subdirectory, then ShellExecute below
|
||||
will fail to find it. So we need to make the file name is
|
||||
absolute. But DOCUMENT does not have to be a file, it can be a
|
||||
URL, for example. So we make it absolute only if it is an
|
||||
existing file; if it is a file that does not exist, tough. */
|
||||
GCPRO1 (absdoc);
|
||||
absdoc = Fexpand_file_name (document, Qnil);
|
||||
/* Don't call file handlers for file-exists-p, since they might
|
||||
attempt to access the file, which could fail or produce undesired
|
||||
consequences, see bug#16558 for an example. */
|
||||
handler = Ffind_file_name_handler (absdoc, Qfile_exists_p);
|
||||
if (NILP (handler))
|
||||
{
|
||||
Lisp_Object absdoc_encoded = ENCODE_FILE (absdoc);
|
||||
|
||||
if (faccessat (AT_FDCWD, SSDATA (absdoc_encoded), F_OK, AT_EACCESS) == 0)
|
||||
document = absdoc_encoded;
|
||||
else
|
||||
document = ENCODE_FILE (document);
|
||||
}
|
||||
else
|
||||
document = ENCODE_FILE (document);
|
||||
UNGCPRO;
|
||||
if (use_unicode)
|
||||
{
|
||||
wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
|
||||
SHELLEXECUTEINFOW shexinfo_w;
|
||||
|
||||
/* Encode filename, current directory and parameters, and
|
||||
convert operation to UTF-16. */
|
||||
filename_to_utf16 (SSDATA (current_dir), current_dir_w);
|
||||
filename_to_utf16 (SSDATA (document), document_w);
|
||||
doc_w = document_w;
|
||||
if (STRINGP (parameters))
|
||||
{
|
||||
int len;
|
||||
|
||||
parameters = ENCODE_SYSTEM (parameters);
|
||||
len = pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
|
||||
SSDATA (parameters), -1, NULL, 0);
|
||||
if (len > 32768)
|
||||
len = 32768;
|
||||
params_w = alloca (len * sizeof (wchar_t));
|
||||
pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
|
||||
SSDATA (parameters), -1, params_w, len);
|
||||
}
|
||||
if (STRINGP (operation))
|
||||
{
|
||||
/* Assume OPERATION is pure ASCII. */
|
||||
const char *s = SSDATA (operation);
|
||||
wchar_t *d;
|
||||
int len = SBYTES (operation) + 1;
|
||||
|
||||
if (len > 32768)
|
||||
len = 32768;
|
||||
d = ops_w = alloca (len * sizeof (wchar_t));
|
||||
while (d < ops_w + len - 1)
|
||||
*d++ = *s++;
|
||||
*d = 0;
|
||||
}
|
||||
|
||||
/* Using ShellExecuteEx and setting the SEE_MASK_INVOKEIDLIST
|
||||
flag succeeds with more OPERATIONs (a.k.a. "verbs"), as it is
|
||||
able to invoke verbs from shortcut menu extensions, not just
|
||||
static verbs listed in the Registry. */
|
||||
memset (&shexinfo_w, 0, sizeof (shexinfo_w));
|
||||
shexinfo_w.cbSize = sizeof (shexinfo_w);
|
||||
shexinfo_w.fMask =
|
||||
SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
|
||||
shexinfo_w.hwnd = NULL;
|
||||
shexinfo_w.lpVerb = ops_w;
|
||||
shexinfo_w.lpFile = doc_w;
|
||||
shexinfo_w.lpParameters = params_w;
|
||||
shexinfo_w.lpDirectory = current_dir_w;
|
||||
shexinfo_w.nShow =
|
||||
(INTEGERP (show_flag) ? XINT (show_flag) : SW_SHOWDEFAULT);
|
||||
success = ShellExecuteExW (&shexinfo_w);
|
||||
}
|
||||
else
|
||||
{
|
||||
char document_a[MAX_PATH], current_dir_a[MAX_PATH];
|
||||
SHELLEXECUTEINFOA shexinfo_a;
|
||||
|
||||
filename_to_ansi (SSDATA (current_dir), current_dir_a);
|
||||
filename_to_ansi (SSDATA (document), document_a);
|
||||
doc_a = document_a;
|
||||
if (STRINGP (parameters))
|
||||
{
|
||||
parameters = ENCODE_SYSTEM (parameters);
|
||||
params_a = SSDATA (parameters);
|
||||
}
|
||||
if (STRINGP (operation))
|
||||
{
|
||||
/* Assume OPERATION is pure ASCII. */
|
||||
ops_a = SSDATA (operation);
|
||||
}
|
||||
memset (&shexinfo_a, 0, sizeof (shexinfo_a));
|
||||
shexinfo_a.cbSize = sizeof (shexinfo_a);
|
||||
shexinfo_a.fMask =
|
||||
SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
|
||||
shexinfo_a.hwnd = NULL;
|
||||
shexinfo_a.lpVerb = ops_a;
|
||||
shexinfo_a.lpFile = doc_a;
|
||||
shexinfo_a.lpParameters = params_a;
|
||||
shexinfo_a.lpDirectory = current_dir_a;
|
||||
shexinfo_a.nShow =
|
||||
(INTEGERP (show_flag) ? XINT (show_flag) : SW_SHOWDEFAULT);
|
||||
success = ShellExecuteExA (&shexinfo_a);
|
||||
}
|
||||
|
||||
if (success)
|
||||
return Qt;
|
||||
|
||||
errstr = w32_strerror (0);
|
||||
|
||||
#endif /* !CYGWIN */
|
||||
|
||||
/* The error string might be encoded in the locale's encoding. */
|
||||
if (!NILP (Vlocale_coding_system))
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue