[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