[vlc-commits] [Git][videolan/vlc][master] 14 commits: win32/spawn: use Wide Windows API

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Apr 29 04:30:41 UTC 2026



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
ed2d7bc9 by Steve Lhomme at 2026-04-29T03:58:40+00:00
win32/spawn: use Wide Windows API

The path or command line may contain unicode characters.

- - - - -
8ed4b481 by Steve Lhomme at 2026-04-29T03:58:40+00:00
win32/spawn: support long application path

We look first with a path of MAX_PATH. If the path exceeds, we use
the proper buffer size.

- - - - -
9b674b13 by Steve Lhomme at 2026-04-29T03:58:40+00:00
winvlc: use SHGetKnownFolderPath() to get the roaming folder path

So we don't need to know the max size beforehand.

SHGetKnownFolderPath() is already what we use to get platform folders.

- - - - -
60529d70 by Steve Lhomme at 2026-04-29T03:58:40+00:00
freetype: use SHGetKnownFolderPath() to get the fonts folder path

So we don't need to know the max size beforehand.

SHGetKnownFolderPath() is already what we use to get platform folders.

- - - - -
0cd536f5 by Steve Lhomme at 2026-04-29T03:58:40+00:00
update: use ToWide to get the path to execute

No need to know/limit the path length.

- - - - -
d300839b by Steve Lhomme at 2026-04-29T03:58:40+00:00
realpath: do not pass an abitrary maxLength to _wfullpath()

>From the documentation [^1] it's ignored when absPath is NULL.

[^1]: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fullpath-wfullpath?#remarks

- - - - -
514a71fe by Steve Lhomme at 2026-04-29T03:58:40+00:00
ntservice: use the ANSI version of GetModuleFileName()

We use CreateServiceA() since be719e08c1aeafd7f426608a910719b2511af572.
We can't call a wide char path.

Also vlc_memstream() cannot output wide chars.

- - - - -
bb19f6e3 by Steve Lhomme at 2026-04-29T03:58:40+00:00
ntservice: check the GetModuleFileName result

If the buffer is too small to receive the string, the buffer size is returned
and the last error is set to ERROR_INSUFFICIENT_BUFFER [^1].

[^1]: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea#return-value

- - - - -
28a8b086 by Steve Lhomme at 2026-04-29T03:58:40+00:00
vout: win32: check the GetModuleFileName result

The local buffer may not be big enough to receive the path.
If the buffer is too small to receive the string, the buffer size is returned
and the last error is set to ERROR_INSUFFICIENT_BUFFER [^1].

[^1]: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea#return-value

- - - - -
9294fc66 by Steve Lhomme at 2026-04-29T03:58:40+00:00
win32: dirs: check the GetModuleFileName result

The local buffer may not be big enough to receive the path.
If the buffer is too small to receive the string, the buffer size is returned
and the last error is set to ERROR_INSUFFICIENT_BUFFER [^1].

[^1]: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea#return-value

- - - - -
a8a732aa by Steve Lhomme at 2026-04-29T03:58:40+00:00
winvolumes: check the GetVolumeInformationA() error

We should not use the path if it's not initialized.

And the maximum size that GetVolumeInformationA() can output is MAX_PATH+1 [^1].

[^1]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#parameters

- - - - -
4f5bb3cc by Steve Lhomme at 2026-04-29T03:58:40+00:00
freetype: check the result of GetWindowsDirectoryW()

And allocate the wide directory name dynamically.

- - - - -
6d5d6564 by Steve Lhomme at 2026-04-29T03:58:40+00:00
vout: win32: handle large ICC profile pathes

- - - - -
36419dd0 by Peter Gaal at 2026-04-29T03:58:40+00:00
win32: Update manifest to enable long path support

Update manifest to enable Windows 10 (build 1607) long path support.

- - - - -


15 changed files:

- bin/Makefile.am
- bin/meson.build
- bin/winvlc.c
- compat/realpath.c
- extras/package/win32/vlc.exe.manifest
- modules/control/ntservice.c
- modules/services_discovery/winvolumes.c
- modules/text_renderer/Makefile.am
- modules/text_renderer/freetype/fonts/win32.c
- modules/text_renderer/meson.build
- modules/video_output/win32/window.c
- src/misc/update.c
- src/win32/dirs-common.c
- src/win32/dirs.c
- src/win32/spawn.c


Changes:

=====================================
bin/Makefile.am
=====================================
@@ -35,7 +35,7 @@ else
 vlc_SOURCES = winvlc.c
 EXTRA_vlc_DEPENDENCIES = vlc_win32_rc.$(OBJEXT)
 vlc_LDFLAGS = -mwindows -Wc,-static
-vlc_LDADD += vlc_win32_rc.$(OBJEXT)
+vlc_LDADD += -lole32 vlc_win32_rc.$(OBJEXT)
 libbreakpad_wrapper_la_SOURCES = breakpad.cpp
 libbreakpad_wrapper_la_LIBADD = $(BREAKPAD_LIBS)
 libbreakpad_wrapper_la_LDFLAGS = -static


=====================================
bin/meson.build
=====================================
@@ -14,6 +14,7 @@ if build_vlc and (host_system != 'darwin' or have_osx) and not have_win_store an
         endif
     elif host_system == 'windows'
         vlc_sources += ['winvlc.c']
+        vlc_deps += cc.find_library('ole32', required: true)
     else
         vlc_sources += ['vlc.c', 'override.c']
         if x11_dep.found()


=====================================
bin/winvlc.c
=====================================
@@ -162,14 +162,22 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
     void* eh = NULL;
     if(crash_handling)
     {
-        wchar_t path[MAX_PATH];
-        if( S_OK != SHGetFolderPathW( NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
-                    NULL, SHGFP_TYPE_CURRENT, path ) )
+        PWSTR copath;
+        if( S_OK != SHGetKnownFolderPath(&FOLDERID_RoamingAppData, KF_FLAG_CREATE, 0, &copath) )
             fprintf( stderr, "Can't open the vlc conf PATH\n" );
-        else if ( !wcscat_s( path, MAX_PATH, L"\\vlc\\crashdump" ) )
+        else
         {
-            CheckCrashDump( path );
-            eh = InstallCrashHandler( path );
+            const size_t pathlen = wcslen( copath );
+            wchar_t *path = malloc( ( pathlen + wcslen(L"\\vlc\\crashdump") + 1 ) * sizeof(*path) );
+            if ( path != NULL)
+            {
+                memcpy( path, copath, pathlen * sizeof(*path) );
+                memcpy( &path[pathlen], L"\\vlc\\crashdump", (wcslen(L"\\vlc\\crashdump") + 1)  * sizeof(*path) );
+                CheckCrashDump( path );
+                eh = InstallCrashHandler( path );
+                free( path );
+            }
+            CoTaskMemFree( copath );
         }
     }
 #else


=====================================
compat/realpath.c
=====================================
@@ -47,7 +47,7 @@ char *realpath(const char * restrict relpath, char * restrict resolved_path)
 
     MultiByteToWideChar( CP_UTF8, 0, relpath, -1, wrelpath, len );
 
-    wchar_t *wfullpath = _wfullpath( NULL, wrelpath, _MAX_PATH );
+    wchar_t *wfullpath = _wfullpath( NULL, wrelpath, 0 );
     free(wrelpath);
     if (wfullpath != NULL)
     {


=====================================
extras/package/win32/vlc.exe.manifest
=====================================
@@ -6,6 +6,11 @@
         name="VideoLAN.VLC"
         type="win32"
     />
+    <asmv3:application>
+        <asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+            <ws2:longPathAware>true</ws2:longPathAware>
+        </asmv3:windowsSettings>
+    </asmv3:application>
     <description>see https://www.videolan.org/</description>
     <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
         <security>


=====================================
modules/control/ntservice.c
=====================================
@@ -186,7 +186,7 @@ static int NTServiceInstall( intf_thread_t *p_intf )
     intf_sys_t *p_sys  = p_intf->p_sys;
     char *psz_extra;
     struct vlc_memstream path_stream;
-    WCHAR psz_pathtmp[MAX_PATH];
+    char psz_pathtmp[MAX_PATH];
 
     SC_HANDLE handle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
     if( handle == NULL )
@@ -204,8 +204,13 @@ static int NTServiceInstall( intf_thread_t *p_intf )
 
     /* Find out the filename of ourselves so we can install it to the
      * service control manager */
-    GetModuleFileName( NULL, psz_pathtmp, MAX_PATH );
-    vlc_memstream_printf( &path_stream, "\"%ls\" -I ntservice", psz_pathtmp );
+    DWORD read = GetModuleFileNameA( NULL, psz_pathtmp, ARRAY_SIZE(psz_pathtmp) );
+    if ( read == 0 || read == ARRAY_SIZE(psz_pathtmp) )
+    {
+        CloseServiceHandle( handle );
+        return VLC_ENOMEM;
+    }
+    vlc_memstream_printf( &path_stream, "\"%s\" -I ntservice", psz_pathtmp );
 
     psz_extra = var_InheritString( p_intf, "ntservice-extraintf" );
     if( psz_extra && *psz_extra )


=====================================
modules/services_discovery/winvolumes.c
=====================================
@@ -56,15 +56,15 @@ typedef struct volumes_observer_t
  */
 static input_item_t *CreateInput( const char letter )
 {
-    char mrl[12] = "file:///A:/", name[MAX_PATH] = {0};
+    char mrl[12] = "file:///A:/", name[MAX_PATH+1] = {0};
     char path[4] = "A:\\";
 
     path[0] = letter;
     mrl[8] = letter;
 
-    // ignore the error, this information is not important
-    GetVolumeInformationA(path, name, sizeof(name),
-                          NULL, NULL, NULL, NULL, 0);
+    if (GetVolumeInformationA(path, name, sizeof(name),
+                              NULL, NULL, NULL, NULL, 0) == 0)
+        return NULL;
 
     if (GetDriveTypeA (path) == DRIVE_CDROM)
         return input_item_NewDisc( mrl, name, INPUT_DURATION_INDEFINITE );


=====================================
modules/text_renderer/Makefile.am
=====================================
@@ -34,7 +34,7 @@ libfreetype_plugin_la_LINK = $(CXXLINK)
 libfreetype_plugin_la_LIBADD += -ldwrite -luuid
 if HAVE_WIN32_DESKTOP
 libfreetype_plugin_la_SOURCES += text_renderer/freetype/fonts/win32.c
-libfreetype_plugin_la_LIBADD += -liconv -lz -lusp10 -lgdi32
+libfreetype_plugin_la_LIBADD += -liconv -lz -lusp10 -lgdi32 -lole32
 endif
 else
 libfreetype_plugin_la_LINK = $(LINK)


=====================================
modules/text_renderer/freetype/fonts/win32.c
=====================================
@@ -167,13 +167,27 @@ static int GetFileFontByName( const WCHAR * font_name, char **psz_filename, int
 
 static char* GetWindowsFontPath(void)
 {
-    wchar_t wdir[MAX_PATH];
-    if( S_OK != SHGetFolderPathW( NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, wdir ) )
+    char* res = NULL;
+    PWSTR copath;
+    if( S_OK == SHGetKnownFolderPath( &FOLDERID_Fonts, KF_FLAG_DEFAULT, NULL, &copath) )
     {
-        GetWindowsDirectoryW( wdir, MAX_PATH );
-        wcscat_s( wdir, MAX_PATH, L"\\fonts" );
+        res = FromWide( copath );
+        CoTaskMemFree( copath );
     }
-    return FromWide( wdir );
+    if ( unlikely( res == NULL ) )
+    {
+        wchar_t wdir;
+        DWORD path_len = GetWindowsDirectoryW( &wdir, 1 );
+        wchar_t *pwindir = NULL;
+        if (path_len != 0 && (pwindir = malloc((path_len * sizeof(*pwindir)) + sizeof(L"\\fonts") )))
+        {
+            path_len = GetWindowsDirectoryW( pwindir, path_len );
+            memcpy( &pwindir[path_len], L"\\fonts", sizeof(L"\\fonts") );
+            res = FromWide( pwindir );
+            free( pwindir );
+        }
+    }
+    return res;
 }
 
 /**


=====================================
modules/text_renderer/meson.build
=====================================
@@ -23,7 +23,7 @@ if host_system == 'windows'
     freetype_cppargs += libcom_cppflags
     # TODO: Don't add this file for UWP builds
     freetype_srcs += files('freetype/fonts/win32.c')
-    freetype_deps += [ cc.find_library('dwrite', required: true) ]
+    freetype_deps += [ cc.find_library('dwrite', required: true), cc.find_library('ole32', required: true) ]
 elif host_system == 'darwin'
     freetype_srcs += files('freetype/fonts/darwin.c')
     freetype_deps += [corefoundation_dep, coretext_dep]
@@ -98,4 +98,3 @@ vlc_modules += {
     'cpp_args' : libcom_cppflags,
     'enabled' : have_sapi,
 }
-


=====================================
modules/video_output/win32/window.c
=====================================
@@ -315,6 +315,13 @@ static void MonitorChanged(vlc_window_t *wnd, HMONITOR monitor)
     DWORD iccw_len = ARRAY_SIZE(iccw);
     if (GetICMProfileW(ic, &iccw_len, iccw)) {
         UpdateICCProfile(wnd, iccw);
+    } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+        wchar_t *piccw = malloc( iccw_len * sizeof(*piccw) );
+        if (piccw != NULL && GetICMProfileW(ic, &iccw_len, piccw))
+            UpdateICCProfile(wnd, piccw);
+        else
+            UpdateICCProfile(wnd, NULL);
+        free(piccw);
     } else {
         UpdateICCProfile(wnd, NULL);
     }
@@ -806,8 +813,11 @@ static int Open(vlc_window_t *wnd)
     HINSTANCE hInstance = GetModuleHandle(NULL);
 
     WCHAR app_path[MAX_PATH];
-    if( GetModuleFileName( NULL, app_path, MAX_PATH ) )
-        sys->vlc_icon = ExtractIcon( hInstance, app_path    , 0 );
+    DWORD read = GetModuleFileNameW( NULL, app_path, ARRAY_SIZE(app_path) );
+    if (read != 0 && read != ARRAY_SIZE(app_path))
+        sys->vlc_icon = ExtractIconW( hInstance, app_path, 0 );
+    else
+        sys->vlc_icon = NULL;
 
     sys->button_pressed = 0;
     sys->is_cursor_hidden = false;


=====================================
src/misc/update.c
=====================================
@@ -47,6 +47,7 @@
 #include <vlc_fs.h>
 #include <vlc_dialog.h>
 #include <vlc_interface.h>
+#include <vlc_charset.h>
 
 #include <gcrypt.h>
 #include <vlc_gcrypt.h>
@@ -738,10 +739,13 @@ static void* update_DownloadReal( void *obj )
     if(answer == 1)
     {
 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-        wchar_t psz_wdestfile[MAX_PATH];
-        MultiByteToWideChar( CP_UTF8, 0, psz_destfile, -1, psz_wdestfile, MAX_PATH );
-        if((intptr_t)(void*)ShellExecuteW( NULL, L"open", psz_wdestfile, NULL, NULL, SW_SHOW) > 32)
-            libvlc_Quit(vlc_object_instance(p_udt));
+        wchar_t *psz_wdestfile = ToWide( psz_destfile );
+        if (likely(psz_wdestfile != NULL))
+        {
+            if((intptr_t)(void*)ShellExecuteW( NULL, L"open", psz_wdestfile, NULL, NULL, SW_SHOW) > 32)
+                libvlc_Quit(vlc_object_instance(p_udt));
+            free(psz_wdestfile);
+        }
 #endif
     }
 #endif


=====================================
src/win32/dirs-common.c
=====================================
@@ -41,7 +41,8 @@ char *config_GetLibDir (void)
         goto error;
 
     wchar_t wpath[MAX_PATH];
-    if (!GetModuleFileNameW ((HMODULE) mbi.AllocationBase, wpath, MAX_PATH))
+    DWORD read = GetModuleFileNameW ((HMODULE) mbi.AllocationBase, wpath, ARRAY_SIZE(wpath));
+    if (read == 0 || read == ARRAY_SIZE(wpath))
         goto error;
 
     wchar_t *file = wcsrchr (wpath, L'\\');
@@ -57,7 +58,8 @@ error:
 static char *config_GetLibexecDir (void)
 {
     wchar_t wpath[MAX_PATH];
-    if (!GetModuleFileNameW (NULL, wpath, MAX_PATH))
+    DWORD read = GetModuleFileNameW (NULL, wpath, ARRAY_SIZE(wpath));
+    if (read == 0 || read == ARRAY_SIZE(wpath))
         goto error;
 
     wchar_t *file = wcsrchr (wpath, L'\\');


=====================================
src/win32/dirs.c
=====================================
@@ -54,7 +54,8 @@ static char *config_GetAppDir (void)
 {
     /* if portable directory exists, use it */
     WCHAR path[MAX_PATH];
-    if (GetModuleFileNameW (NULL, path, MAX_PATH))
+    DWORD read = GetModuleFileNameW (NULL, path, ARRAY_SIZE(path));
+    if (read != 0 && read != ARRAY_SIZE(path))
     {
         WCHAR *lastDir = wcsrchr (path, L'\\');
         if (lastDir)


=====================================
src/win32/spawn.c
=====================================
@@ -30,6 +30,7 @@
 #include <vlc_fs.h>
 #include <vlc_spawn.h>
 #include <vlc_memstream.h>
+#include <vlc_charset.h>
 
 static LPPROC_THREAD_ATTRIBUTE_LIST allow_hstd_inherit(HANDLE *handles)
 {
@@ -102,7 +103,7 @@ static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
     int nulfd = -1;
     HANDLE nul_handle = INVALID_HANDLE_VALUE;
     PROCESS_INFORMATION pi = {0};
-    STARTUPINFOEXA siEx = {
+    STARTUPINFOEXW siEx = {
         .StartupInfo = {
             .cb         = sizeof(siEx),
             .hStdInput  = INVALID_HANDLE_VALUE,
@@ -112,8 +113,11 @@ static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
         }
     };
 
-    const char *application_name = NULL;
-    char *cmdline = NULL;
+    wchar_t *application_name = NULL;
+    wchar_t *wide_path = ToWide(path);
+    if (unlikely(wide_path == NULL))
+        return ret;
+    wchar_t *cmdline = NULL;
 
     if (fdv[0] == -1 || fdv[1] == -1) {
         nulfd = _open("\\\\.\\NUL", O_RDWR);
@@ -156,22 +160,28 @@ static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
         goto error;
 
     if (search) {
+        wchar_t short_path[MAX_PATH];
         if (!SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE))
             goto error;
 
-        char *const application_path = malloc(MAX_PATH);
-        if (unlikely(!application_path))
-            goto error;
-
-        if (!SearchPathA(NULL, path, NULL, MAX_PATH, application_path, NULL)) {
-            free(application_path);
+        DWORD path_size = SearchPathW(NULL, wide_path, NULL, ARRAY_SIZE(short_path), short_path, NULL);
+        if (path_size == 0)
             goto error;
+        if (path_size <= ARRAY_SIZE(short_path)) {
+            application_name = _wcsdup(short_path);
+            if (unlikely(!application_name))
+                goto error;
+        } else {
+            application_name = malloc(path_size * sizeof(*application_name));
+            if (unlikely(!application_name))
+                goto error;
+
+            DWORD full_path_size = SearchPathW(NULL, wide_path, NULL, path_size, application_name, NULL);
+            if (unlikely(path_size < full_path_size))
+                goto error;
         }
-
-        application_name = application_path;
-
     } else {
-        application_name = path;
+        application_name = wide_path;
     }
 
     if (likely(argv[0])) {
@@ -183,10 +193,13 @@ static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
             vlc_memstream_printf(&cmdline_s, " %s", argv[argc]);
         if (vlc_memstream_close(&cmdline_s) != 0)
             goto error;
-        cmdline = cmdline_s.ptr;
+        cmdline = ToWide(cmdline_s.ptr);
+        free(cmdline_s.ptr);
+        if (unlikely(cmdline == NULL))
+            goto error;
     }
 
-    BOOL bSuccess = CreateProcessA(application_name, cmdline, NULL,
+    BOOL bSuccess = CreateProcessW(application_name, cmdline, NULL,
                                    NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
                                    NULL, NULL, &siEx.StartupInfo, &pi);
     if (!bSuccess)
@@ -220,8 +233,9 @@ error:
         free(siEx.lpAttributeList);
     }
 
-    if (application_name != path)
-        free((char*)application_name);
+    if (application_name != wide_path)
+        free(application_name);
+    free(wide_path);
     free(cmdline);
 
     return ret;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/149b9b79cb04bd5a042a52ba86ea7e508da1c07d...36419dd0775c7d4b20c0f0dda8ab742c4e5a2a7a

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/149b9b79cb04bd5a042a52ba86ea7e508da1c07d...36419dd0775c7d4b20c0f0dda8ab742c4e5a2a7a
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list