PythonScript icon indicating copy to clipboard operation
PythonScript copied to clipboard

ShellExecuteA and charset in PythonScript

Open tho-gru opened this issue 2 years ago • 2 comments

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 avatar Jul 23 '22 20:07 tho-gru

@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.

chcg avatar Jul 26 '22 05:07 chcg

Hi,

The version of my Python Script is: About Python Script

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?

tho-gru avatar Aug 03 '22 16:08 tho-gru