[vlc-commits] [Git][videolan/vlc][master] service_discovery: Add winvolumes module

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Thu May 9 16:02:07 UTC 2024



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
f9d948ca by Prince Gupta at 2024-05-09T12:27:00+00:00
service_discovery: Add winvolumes module

implement SD_CAT_MYCOMPUTER based service discovery
module on Windows

allows to query volumes mounted on host computer
Ref #28597

- - - - -


3 changed files:

- modules/services_discovery/Makefile.am
- modules/services_discovery/meson.build
- + modules/services_discovery/winvolumes.c


Changes:

=====================================
modules/services_discovery/Makefile.am
=====================================
@@ -71,6 +71,11 @@ if HAVE_WIN32_DESKTOP
 sd_LTLIBRARIES += libwindrive_plugin.la
 endif
 
+libwinvolumes_plugin_la_SOURCES = services_discovery/winvolumes.c
+if HAVE_WIN32_DESKTOP
+sd_LTLIBRARIES += libwinvolumes_plugin.la
+endif
+
 libos2drive_plugin_la_SOURCES = services_discovery/os2drive.c
 if HAVE_OS2
 sd_LTLIBRARIES += libos2drive_plugin.la


=====================================
modules/services_discovery/meson.build
=====================================
@@ -89,6 +89,11 @@ if host_system == 'windows'
         'name' : 'windrive',
         'sources' : files('windrive.c')
     }
+
+    vlc_modules += {
+        'name' : 'winvolumes',
+        'sources' : files('winvolumes.c')
+    }
 endif
 
 # mDNS using libmicrodns


=====================================
modules/services_discovery/winvolumes.c
=====================================
@@ -0,0 +1,385 @@
+/*****************************************************************************
+ * Copyright © 2010 Rémi Denis-Courmont
+ * Copyright © 2024 Prince Gupta <prince at videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_services_discovery.h>
+#include <vlc_threads.h>
+
+#include <windows.h>
+#include <dbt.h>
+
+
+// max drives allowed because of letter assignment (A-Z)
+#define MAX_DRIVES 26
+
+// name and window title used for observer window
+static const char WindowClassName[] = "VLCWinVolumesDeviceObserver";
+
+typedef struct volumes_observer_t
+{
+    // observer thread
+    vlc_thread_t thread;
+
+    // signal to end the observer thread
+    HANDLE quit_signal;
+
+    input_item_t *items[MAX_DRIVES];
+} volumes_observer_t;
+
+
+/**
+ * @brief CreateInput
+ * @param letter - drive letter assosited with drive
+ * @return input item for the drive
+ */
+static input_item_t *CreateInput( const char letter )
+{
+    char mrl[12] = "file:///A:/", name[MAX_PATH] = {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 (GetDriveTypeA (path) == DRIVE_CDROM)
+        return input_item_NewDisc( mrl, name, INPUT_DURATION_INDEFINITE );
+    else
+        return input_item_NewDirectory( mrl, name, ITEM_LOCAL );
+}
+
+
+/**
+ * @brief RegisterWindowClass registers window class for window creation
+ * @param class_name
+ * @param proc - window procedure associated with window class
+ * @return ATOM (unique identifier) for the class on success otherwise 0
+ */
+static ATOM RegisterWindowClass( const char *class_name, WNDPROC proc )
+{
+    WNDCLASSEXA wcex =
+    {
+        .cbSize = sizeof(WNDCLASSEXA),
+        .lpfnWndProc = proc,
+        .hInstance = (HINSTANCE)GetModuleHandle(NULL),
+        .hbrBackground = (HBRUSH)(COLOR_WINDOW),
+        .lpszClassName = class_name
+    };
+
+    return RegisterClassExA(&wcex);
+}
+
+
+/**
+ * @brief StartWindow creates a hidden window, can be used to listen on OS events
+ * @param class_name name and title for window
+ * @param ctx will be passed as lpParam, can be used with CREATESTRUCT (see CreateWindowA docs)
+ * @return HANDLE to the created window on success otherwise NULL
+ */
+static HWND StartWindow(const char *class_name, void *ctx)
+{
+    HWND window = CreateWindowA(class_name, class_name, WS_ICONIC,
+                                0, 0, CW_USEDEFAULT, 0, NULL, NULL,
+                                (HINSTANCE)GetModuleHandle(NULL), ctx);
+
+    if (window == NULL)
+        return NULL;
+
+    ShowWindow(window, SW_HIDE);
+    return window;
+}
+
+
+static int Add( services_discovery_t *p_sd, const uint32_t disk_mask )
+{
+    volumes_observer_t *p_sys = p_sd->p_sys;
+
+    for (int i = 0; i < MAX_DRIVES; ++i)
+    {
+        const uint32_t mask = 1 << i;
+        if ( !(disk_mask & mask) )
+            continue;
+
+        input_item_t *item = CreateInput( 'A' + i );
+        if (unlikely( !item )) return VLC_ENOMEM;
+
+        if ( p_sys->items[i] )
+        {
+            services_discovery_RemoveItem( p_sd, p_sys->items[i] );
+            input_item_Release( p_sys->items[i] );
+        }
+
+        p_sys->items[i] = item;
+
+        // notify changes
+        services_discovery_AddItem( p_sd, item );
+    }
+
+    return VLC_SUCCESS;
+}
+
+
+static void Remove(services_discovery_t *p_sd, const uint32_t disk_mask)
+{
+    volumes_observer_t *p_sys = p_sd->p_sys;
+
+    for (int i = 0; i < MAX_DRIVES; ++i)
+    {
+        const uint32_t mask = (1 << i);
+        if ( !(disk_mask & mask) )
+            continue;
+
+        if ( p_sys->items[i] )
+        {
+            services_discovery_RemoveItem( p_sd, p_sys->items[i] );
+            input_item_Release( p_sys->items[i] );
+            p_sys->items[i] = NULL;
+        }
+    }
+}
+
+
+static int AddExistingDrives( services_discovery_t *p_sd )
+{
+    // find existing drives
+    const DWORD drives = GetLogicalDrives();
+    return Add( p_sd, drives );
+}
+
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    switch (message)
+    {
+    case WM_CREATE:
+    {
+        // store passed lParam as user data to use as context for handling other events
+        CREATESTRUCT *c = (CREATESTRUCT *)lParam;
+        SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)c->lpCreateParams );
+        return 0;
+    }
+
+    case WM_DEVICECHANGE:
+    {
+        if ((wParam != DBT_DEVICEARRIVAL) && (wParam != DBT_DEVICEREMOVECOMPLETE))
+            break;
+
+        DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *) lParam;
+        if (header->dbch_devicetype != DBT_DEVTYP_VOLUME)
+            break;
+
+        // get associated user data for the context
+        LONG_PTR user_data = GetWindowLongPtr( hWnd, GWLP_USERDATA );
+        if ( user_data == 0 )
+            break;
+
+        services_discovery_t *p_sd = (services_discovery_t *)user_data;
+        DEV_BROADCAST_VOLUME *node = (DEV_BROADCAST_VOLUME *)lParam;
+
+        switch (wParam)
+        {
+        case DBT_DEVICEARRIVAL:
+        {
+            Add( p_sd, node->dbcv_unitmask );
+            break;
+        }
+        case DBT_DEVICEREMOVECOMPLETE:
+        {
+            Remove( p_sd, node->dbcv_unitmask );
+            break;
+        }
+        default:
+            break;
+        }
+
+        break;
+    }
+
+    case WM_DESTROY:
+    {
+        PostQuitMessage(0);
+        return 0;
+    }
+
+    default:
+        break;
+    }
+
+    return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+static void *Run(void *ctx)
+{
+    services_discovery_t *p_sd = ctx;
+    volumes_observer_t *p_sys = p_sd->p_sys;
+
+    // register window class
+    ATOM registered_class = RegisterWindowClass( WindowClassName, WndProc );
+    DWORD error = GetLastError();
+    if ((registered_class == 0)
+            && (error != ERROR_CLASS_ALREADY_EXISTS))
+    {
+        msg_Err( p_sd, "failed to register window class %lu", error );
+        return NULL;
+    }
+
+    HWND window = StartWindow( WindowClassName, ctx );
+    if ( !window )
+    {
+        msg_Err( p_sd, "failed to start window %lu", GetLastError() );
+        return NULL;
+    }
+
+    // window message loop
+    for(;;)
+    {
+        // Wait for either a message or the quit event
+        DWORD wait_result = MsgWaitForMultipleObjects(1, &p_sys->quit_signal,
+                                                      FALSE, INFINITE, QS_ALLINPUT);
+
+        if (wait_result == WAIT_OBJECT_0)
+        {
+            // The close event is signaled, break out of the loop
+            break;
+        }
+        else if (wait_result == WAIT_OBJECT_0 + 1)
+        {
+            MSG msg;
+
+            // There are messages in the queue, process them
+            while (PeekMessage(&msg, window, 0, 0, PM_REMOVE))
+            {
+                if (msg.message == WM_QUIT)
+                {
+                    break;
+                }
+                else
+                {
+                    TranslateMessage(&msg);
+                    DispatchMessage(&msg);
+                }
+            }
+        }
+        else if (wait_result == WAIT_FAILED)
+        {
+            break;
+        }
+    }
+
+    DestroyWindow( window );
+    return NULL;
+}
+
+
+static void ReleaseItems( volumes_observer_t *p_sys )
+{
+    for (int i = 0; i < MAX_DRIVES; ++i)
+    {
+        if (p_sys->items[i])
+            input_item_Release( p_sys->items[i] );
+    }
+}
+
+
+// Module functions -
+static int Open (vlc_object_t *obj)
+{
+    services_discovery_t *p_sd = (services_discovery_t *)obj;
+
+    volumes_observer_t *p_sys = (volumes_observer_t *)calloc( 1, sizeof(volumes_observer_t) );
+    if ( !p_sys )
+        return VLC_ENOMEM;
+
+    p_sd->p_sys = p_sys;
+    p_sd->description = _("Lists volumes on host computer");
+
+    if ( AddExistingDrives( p_sd ) != VLC_SUCCESS)
+    {
+        msg_Err( p_sd, "failed to find existing drives" );
+        goto error;
+    }
+
+    p_sys->quit_signal = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if ( p_sys->quit_signal == NULL )
+    {
+        msg_Err( p_sd, "failed to create event, error: %lu", GetLastError());
+        goto error;
+    }
+
+    // start the thread for window handling
+    if ( vlc_clone( &p_sys->thread, Run, p_sd ) )
+    {
+        msg_Err( p_sd, "failed to start observer thread");
+        goto error;
+    }
+
+    return VLC_SUCCESS;
+
+error:
+    if ( p_sys->quit_signal )
+        CloseHandle( p_sys->quit_signal );
+
+    ReleaseItems( p_sys );
+    free( p_sys );
+    return VLC_EGENERIC;
+}
+
+
+static void Close( vlc_object_t * obj )
+{
+    services_discovery_t *p_sd = (services_discovery_t *)obj;
+    volumes_observer_t *p_sys = (volumes_observer_t *) p_sd->p_sys;
+
+    // signal window thread to quit
+    SetEvent( p_sys->quit_signal );
+
+    vlc_join( p_sys->thread, NULL );
+
+    // release resources
+    CloseHandle( p_sys->quit_signal );
+    ReleaseItems( p_sys );
+    free( p_sys );
+}
+
+
+VLC_SD_PROBE_HELPER("volume", N_("Volumes"), SD_CAT_MYCOMPUTER)
+
+/*
+ * Module descriptor
+ *
+ * list volumes on Windows
+ */
+vlc_module_begin ()
+    set_shortname (N_("Volumes"))
+    set_description (N_("Lists volumes on host computer"))
+    set_capability ("services_discovery", 0)
+    set_callbacks(Open, Close)
+    add_shortcut ("volume")
+
+    VLC_SD_PROBE_SUBMODULE
+vlc_module_end ()



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/f9d948ca036f641bf49e042b62632906d609d95e

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/f9d948ca036f641bf49e042b62632906d609d95e
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list