PythonScript
PythonScript copied to clipboard
ShellExecuteA and charset in PythonScript
Hi,
In Issue 10071 - open file via double click I got the hint to call ShellExecuteA:
# -*- coding: utf-8 -*-
import ctypes
SW_SHOW = 5
ctypes.windll.Shell32.ShellExecuteA(None, 'open', r'file:///C:\tmp\anchor-test-file.html#part3', None, None, SW_SHOW)
Doing so works fine for almost all file names. But when the file name contains some special characters (like ä - U+00E4 or en dash - U+2013) ShellExecuteA will fail with "file not found" error.
To approach this issue I wrote a C# program:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program
{
// see https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.charset
const CharSet cs = CharSet.Ansi; // work
// const CharSet cs = CharSet.Auto; // error
// const CharSet cs = CharSet.None; // work
// const CharSet cs = CharSet.Unicode; // error
//ShellExecuteA declaration
[System.Runtime.InteropServices.DllImport("Shell32.dll", CharSet = cs)]
public static extern Int32 ShellExecuteA(int hwnd, string lpOperation,
string lpFile, int lpParameters, int lpDirecotry, int nShowCmd);
public static void Main(string[] args)
{
// string url = args[0];
string url = @"file:///C:\tmp\Notepad++ALT-Click-Dateiname\test-ää.txt";
Console.WriteLine("url = '{0}'", url);
System.Diagnostics.Process.Start(url); // this work fine
Int32 ret = 0;
try
{
Console.WriteLine("cs = {0}", cs);
ret = ShellExecuteA(0, "open", url, 0, 0, 1);
Console.WriteLine("ret = {0}", ret);
}
catch (Exception e)
{
Console.Error.WriteLine("{0}\n", e);
}
Console.Write("press any key ");
Console.ReadKey(true);
}
}
Running the C# program shows that the correct function depends on the charset (constant cs) which is used for in the declaration.
Based on this experience i wonder if there is a similar possibility in PythonScript.
Does anyone have an idea how to make ShellExecuteA handle special characters correctly?
Regards Thomas
@tho-gru Maybe https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew could be used which takes UTF-16 as input.
Hi,
The version of my Python Script is:
Thanks for your tip. I did some investigation within the Python Script console interactively:
>>> import ctypes
>>> file = u'file:///C:\\tmp\\Notepad++ALT-Click-Dateiname\\test-Ä.txt'
>>> ctypes.windll.Shell32.ShellExecuteA(None, 'open', file, None, None, 5)
2
>>> file_cp1252 = file.encode('cp1252')
>>> ctypes.windll.Shell32.ShellExecuteA(None, 'open', file_cp1252, None, None, 5)
42
>>> file_utf16 = file.encode('utf-16le')
>>> ctypes.windll.Shell32.ShellExecuteW(None, 'open', file_utf16, None, None, 5)
31
Calling ShellExecuteA with a UTF-8 encoded file name does not work. This is expected. Calling ShellExecuteA with a ANSI (cp1252) encoded file name work. Nice. Calling ShellExecuteW with a UTF-16 encoded file name does not work. This is not expected.
Any ideas?