wine/programs/explorer/hal.c
Rob Shearman a82f4dd9b7 Don't use GetExceptionCode and GetExceptionInformation in exception filter functions.
When using native compiler exceptions, it isn't valid to use 
GetExceptionCode and GetExceptionInformation anywhere other than in the 
filter or handler blocks since it would be very hard for the compiler to 
work out where to retrieve the exception information from on the stack.

Therefore, remove the WINE_EXCEPTION_FILTER and WINE_FINALLY_FUNC macros 
which enabled GetExceptionCode, GetExceptionInformation and 
AbnormalTermination to be used inside of the functions they declared and 
fix up all callers to access the information directly.
2008-02-16 14:57:44 +01:00

250 lines
7.1 KiB
C

/*
* HAL devices support
*
* Copyright 2006 Alexandre Julliard
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/time.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winuser.h"
#include "excpt.h"
#include "wine/library.h"
#include "wine/exception.h"
#include "wine/debug.h"
#include "explorer_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(explorer);
#ifdef SONAME_LIBHAL
#include <dbus/dbus.h>
#include <hal/libhal.h>
#define DBUS_FUNCS \
DO_FUNC(dbus_bus_get); \
DO_FUNC(dbus_connection_close); \
DO_FUNC(dbus_connection_read_write_dispatch); \
DO_FUNC(dbus_error_init); \
DO_FUNC(dbus_error_free); \
DO_FUNC(dbus_error_is_set)
#define HAL_FUNCS \
DO_FUNC(libhal_ctx_free); \
DO_FUNC(libhal_ctx_init); \
DO_FUNC(libhal_ctx_new); \
DO_FUNC(libhal_ctx_set_dbus_connection); \
DO_FUNC(libhal_ctx_set_device_added); \
DO_FUNC(libhal_ctx_set_device_property_modified); \
DO_FUNC(libhal_ctx_set_device_removed); \
DO_FUNC(libhal_ctx_shutdown); \
DO_FUNC(libhal_device_get_property_bool); \
DO_FUNC(libhal_device_get_property_string); \
DO_FUNC(libhal_device_add_property_watch); \
DO_FUNC(libhal_device_remove_property_watch); \
DO_FUNC(libhal_free_string); \
DO_FUNC(libhal_free_string_array); \
DO_FUNC(libhal_get_all_devices)
#define DO_FUNC(f) static typeof(f) * p_##f
DBUS_FUNCS;
HAL_FUNCS;
#undef DO_FUNC
static BOOL load_functions(void)
{
void *hal_handle;
char error[128];
/* Load libhal with RTLD_GLOBAL so that the dbus symbols are available.
* We can't load libdbus directly since libhal may have been built against a
* different version but with the same soname. Binary compatibility is for wimps. */
if (!(hal_handle = wine_dlopen(SONAME_LIBHAL, RTLD_NOW|RTLD_GLOBAL, error, sizeof(error))))
goto failed;
#define DO_FUNC(f) if (!(p_##f = wine_dlsym( RTLD_DEFAULT, #f, error, sizeof(error) ))) goto failed
DBUS_FUNCS;
#undef DO_FUNC
#define DO_FUNC(f) if (!(p_##f = wine_dlsym( hal_handle, #f, error, sizeof(error) ))) goto failed
HAL_FUNCS;
#undef DO_FUNC
return TRUE;
failed:
WINE_WARN( "failed to load HAL support: %s\n", error );
return FALSE;
}
static LONG WINAPI assert_fault(EXCEPTION_POINTERS *eptr)
{
if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_ASSERTION)
return EXCEPTION_EXECUTE_HANDLER;
return EXCEPTION_CONTINUE_SEARCH;
}
/* HAL callback for new device */
static void new_device( LibHalContext *ctx, const char *udi )
{
DBusError error;
char *parent = NULL;
char *mount_point = NULL;
char *device = NULL;
char *type = NULL;
p_dbus_error_init( &error );
if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error )))
goto done;
if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error )))
goto done;
if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error )))
goto done;
if (!p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error ))
goto done;
if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error )))
p_dbus_error_free( &error ); /* ignore error */
add_dos_device( udi, device, mount_point, type );
/* add property watch for mount point */
p_libhal_device_add_property_watch( ctx, udi, &error );
done:
if (type) p_libhal_free_string( type );
if (parent) p_libhal_free_string( parent );
if (device) p_libhal_free_string( device );
if (mount_point) p_libhal_free_string( mount_point );
p_dbus_error_free( &error );
}
/* HAL callback for removed device */
static void removed_device( LibHalContext *ctx, const char *udi )
{
DBusError error;
WINE_TRACE( "removed %s\n", wine_dbgstr_a(udi) );
if (remove_dos_device( udi ))
{
p_dbus_error_init( &error );
p_libhal_device_remove_property_watch( ctx, udi, &error );
p_dbus_error_free( &error );
}
}
/* HAL callback for property changes */
static void property_modified (LibHalContext *ctx, const char *udi,
const char *key, dbus_bool_t is_removed, dbus_bool_t is_added)
{
WINE_TRACE( "udi %s key %s %s\n", wine_dbgstr_a(udi), wine_dbgstr_a(key),
is_added ? "added" : is_removed ? "removed" : "modified" );
if (!strcmp( key, "volume.mount_point" )) new_device( ctx, udi );
}
static DWORD WINAPI hal_thread( void *arg )
{
DBusError error;
DBusConnection *dbc;
LibHalContext *ctx;
int i, num;
char **list;
if (!(ctx = p_libhal_ctx_new())) return 1;
p_dbus_error_init( &error );
if (!(dbc = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error )))
{
WINE_WARN( "failed to get system dbus connection: %s\n", error.message );
p_dbus_error_free( &error );
return 1;
}
p_libhal_ctx_set_dbus_connection( ctx, dbc );
p_libhal_ctx_set_device_added( ctx, new_device );
p_libhal_ctx_set_device_removed( ctx, removed_device );
p_libhal_ctx_set_device_property_modified( ctx, property_modified );
if (!p_libhal_ctx_init( ctx, &error ))
{
WINE_WARN( "HAL context init failed: %s\n", error.message );
p_dbus_error_free( &error );
return 1;
}
/* retrieve all existing devices */
if (!(list = p_libhal_get_all_devices( ctx, &num, &error ))) p_dbus_error_free( &error );
else
{
for (i = 0; i < num; i++) new_device( ctx, list[i] );
p_libhal_free_string_array( list );
}
__TRY
{
while (p_dbus_connection_read_write_dispatch( dbc, -1 )) /* nothing */ ;
}
__EXCEPT( assert_fault )
{
WINE_WARN( "dbus assertion failure, disabling HAL support\n" );
return 1;
}
__ENDTRY;
p_libhal_ctx_shutdown( ctx, &error );
p_dbus_error_free( &error ); /* just in case */
p_dbus_connection_close( dbc );
p_libhal_ctx_free( ctx );
return 0;
}
void initialize_hal(void)
{
HANDLE handle;
if (!load_functions()) return;
if (!(handle = CreateThread( NULL, 0, hal_thread, NULL, 0, NULL ))) return;
CloseHandle( handle );
}
#else /* SONAME_LIBHAL */
void initialize_hal(void)
{
WINE_TRACE( "Skipping, HAL support not compiled in\n" );
}
#endif /* SONAME_LIBHAL */