X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fwin32_specific.c;h=17af95b2cdb9c91bc29a197f7617c5e855158d23;hb=a46fb0e4e14d971e7482b010bb42c6bc93df66f7;hp=b5344340c3ed39a12d9b1a14aafb1446a230b5d7;hpb=4f08a70d2125a8ebcf05b82b73fcdb3a1d56cae3;p=vlc diff --git a/src/misc/win32_specific.c b/src/misc/win32_specific.c index b5344340c3..17af95b2cd 100644 --- a/src/misc/win32_specific.c +++ b/src/misc/win32_specific.c @@ -1,17 +1,17 @@ /***************************************************************************** - * win32_specific.c: Win32 specific features + * win32_specific.c: Win32 specific features ***************************************************************************** - * Copyright (C) 2001 VideoLAN - * $Id: win32_specific.c,v 1.6 2002/04/02 23:43:57 gbazin Exp $ + * Copyright (C) 2001-2004 the VideoLAN team + * $Id$ * * Authors: Samuel Hocevar - * Gildas Bazin + * Gildas Bazin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 @@ -19,63 +19,361 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#include /* ENOMEM */ -#include /* strdup() */ -#include /* free() */ -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define UNICODE +#include +#include "../libvlc.h" +#include +#include + +#include "../extras/getopt.h" -#include +#if !defined( UNDER_CE ) +# include +# include +# include +#endif + +#include /***************************************************************************** * system_Init: initialize winsock and misc other things. *****************************************************************************/ -void system_Init( int *pi_argc, char *ppsz_argv[], char *ppsz_env[] ) +void system_Init( libvlc_int_t *p_this, int *pi_argc, const char *ppsz_argv[] ) { WSADATA Data; - int i_err; - HINSTANCE hInstLib; - /* Allocate structure */ - p_main_sys = malloc( sizeof( main_sys_t ) ); - if( p_main_sys == NULL ) + /* Get our full path */ + char psz_path[MAX_PATH]; + char *psz_vlc; + + wchar_t psz_wpath[MAX_PATH]; + if( GetModuleFileName( NULL, psz_wpath, MAX_PATH ) ) + { + WideCharToMultiByte( CP_ACP, 0, psz_wpath, -1, + psz_path, MAX_PATH, NULL, NULL ); + } + else psz_path[0] = '\0'; + + if( (psz_vlc = strrchr( psz_path, '\\' )) ) *psz_vlc = '\0'; + +#ifndef HAVE_RELEASE { - intf_ErrMsg( "init error: can't create p_main_sys (%s)", - strerror(ENOMEM) ); - exit(-1); + /* remove trailing \.libs from executable dir path if seen, + we assume we are running vlc through libtool wrapper in build dir */ + int offset = strlen(psz_path)-sizeof("\\.libs")+1; + if( offset > 0 ) + { + psz_vlc = psz_path+offset; + if( ! strcmp(psz_vlc, "\\.libs") ) *psz_vlc = '\0'; + } } +#endif - /* dynamically get the address of SignalObjectAndWait */ - hInstLib = LoadLibrary( "kernel32" ); - p_main_sys->SignalObjectAndWait = - (SIGNALOBJECTANDWAIT)GetProcAddress( hInstLib, "SignalObjectAndWait" ); + vlc_global()->psz_vlcpath = strdup( psz_path ); + + /* Set the default file-translation mode */ +#if !defined( UNDER_CE ) + _fmode = _O_BINARY; + _setmode( _fileno( stdin ), _O_BINARY ); /* Needed for pipes */ + + timeBeginPeriod(5); +#endif + + /* Call mdate() once to make sure it is initialized properly */ + mdate(); /* WinSock Library Init. */ - i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data ); + if( !WSAStartup( MAKEWORD( 2, 2 ), &Data ) ) + { + /* Aah, pretty useless check, we should always have Winsock 2.2 + * since it appeared in Win98. */ + if( LOBYTE( Data.wVersion ) != 2 || HIBYTE( Data.wVersion ) != 2 ) + /* We could not find a suitable WinSock DLL. */ + WSACleanup( ); + else + /* Everything went ok. */ + return; + } - if( i_err ) + /* Let's try with WinSock 1.1 */ + if( !WSAStartup( MAKEWORD( 1, 1 ), &Data ) ) { - fprintf( stderr, "error: can't initiate WinSocks, error %i", i_err ); + /* Confirm that the WinSock DLL supports 1.1.*/ + if( LOBYTE( Data.wVersion ) != 1 || HIBYTE( Data.wVersion ) != 1 ) + /* We could not find a suitable WinSock DLL. */ + WSACleanup( ); + else + /* Everything went ok. */ + return; } - _fmode = _O_BINARY; /* sets the default file-translation mode */ + fprintf( stderr, "error: can't initialize WinSocks\n" ); } /***************************************************************************** * system_Configure: check for system specific configuration options. *****************************************************************************/ -void system_Configure( void ) +static void IPCHelperThread( vlc_object_t * ); +LRESULT CALLBACK WMCOPYWNDPROC( HWND, UINT, WPARAM, LPARAM ); +typedef struct +{ + int argc; + int enqueue; + char data[0]; +} vlc_ipc_data_t; + +void system_Configure( libvlc_int_t *p_this, int *pi_argc, const char *ppsz_argv[] ) +{ +#if !defined( UNDER_CE ) + /* Raise default priority of the current process */ +#ifndef ABOVE_NORMAL_PRIORITY_CLASS +# define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000 +#endif + if( config_GetInt( p_this, "high-priority" ) ) + { + if( SetPriorityClass( GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS ) + || SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) + { + msg_Dbg( p_this, "raised process priority" ); + } + else + { + msg_Dbg( p_this, "could not raise process priority" ); + } + } + + libvlc_priv (p_this)->ipc_helper = NULL; + + if( config_GetInt( p_this, "one-instance" ) + || ( config_GetInt( p_this, "one-instance-when-started-from-file" ) + && config_GetInt( p_this, "started-from-file" ) ) ) + { + HANDLE hmutex; + + msg_Info( p_this, "one instance mode ENABLED"); + + /* Use a named mutex to check if another instance is already running */ + if( !( hmutex = CreateMutex( 0, TRUE, L"VLC ipc "VERSION ) ) ) + { + /* Failed for some reason. Just ignore the option and go on as + * normal. */ + msg_Err( p_this, "one instance mode DISABLED " + "(mutex couldn't be created)" ); + return; + } + + if( GetLastError() != ERROR_ALREADY_EXISTS ) + { + /* We are the 1st instance. */ + static const char typename[] = "ipc helper"; + vlc_object_t *p_helper = + vlc_custom_create( p_this, sizeof(vlc_object_t), + VLC_OBJECT_GENERIC, typename ); + + /* Run the helper thread */ + if( vlc_thread_create( p_helper, "IPC helper", IPCHelperThread, + VLC_THREAD_PRIORITY_LOW, true ) ) + { + msg_Err( p_this, "one instance mode DISABLED " + "(IPC helper thread couldn't be created)" ); + vlc_object_release (p_helper); + } + else + libvlc_priv (p_this)->ipc_helper = p_helper; + + /* Initialization done. + * Release the mutex to unblock other instances */ + ReleaseMutex( hmutex ); + } + else + { + /* Another instance is running */ + + HWND ipcwindow; + + /* Wait until the 1st instance is initialized */ + WaitForSingleObject( hmutex, INFINITE ); + + /* Locate the window created by the IPC helper thread of the + * 1st instance */ + if( !( ipcwindow = FindWindow( 0, L"VLC ipc "VERSION ) ) ) + { + msg_Err( p_this, "one instance mode DISABLED " + "(couldn't find 1st instance of program)" ); + ReleaseMutex( hmutex ); + return; + } + + /* We assume that the remaining parameters are filenames + * and their input options */ + if( *pi_argc - 1 >= optind ) + { + COPYDATASTRUCT wm_data; + int i_opt; + vlc_ipc_data_t *p_data; + size_t i_data = sizeof (*p_data); + + for( i_opt = optind; i_opt < *pi_argc; i_opt++ ) + { + i_data += sizeof (size_t); + i_data += strlen( ppsz_argv[ i_opt ] ) + 1; + } + + p_data = malloc( i_data ); + p_data->argc = *pi_argc - optind; + p_data->enqueue = config_GetInt( p_this, "playlist-enqueue" ); + i_data = 0; + for( i_opt = optind; i_opt < *pi_argc; i_opt++ ) + { + size_t i_len = strlen( ppsz_argv[ i_opt ] ) + 1; + /* Windows will never switch to an architecture + * with stronger alignment requirements, right. */ + *((size_t *)(p_data->data + i_data)) = i_len; + i_data += sizeof (size_t); + memcpy( &p_data->data[i_data], ppsz_argv[ i_opt ], i_len ); + i_data += i_len; + } + i_data += sizeof (*p_data); + + /* Send our playlist items to the 1st instance */ + wm_data.dwData = 0; + wm_data.cbData = i_data; + wm_data.lpData = p_data; + SendMessage( ipcwindow, WM_COPYDATA, 0, (LPARAM)&wm_data ); + } + + /* Initialization done. + * Release the mutex to unblock other instances */ + ReleaseMutex( hmutex ); + + /* Bye bye */ + system_End( p_this ); + exit( 0 ); + } + } + +#endif +} + +static void IPCHelperThread( vlc_object_t *p_this ) { - p_main_sys->b_fast_pthread = config_GetIntVariable( "fast_pthread" ); + HWND ipcwindow; + MSG message; + + ipcwindow = + CreateWindow( L"STATIC", /* name of window class */ + L"VLC ipc "VERSION, /* window title bar text */ + 0, /* window style */ + 0, /* default X coordinate */ + 0, /* default Y coordinate */ + 0, /* window width */ + 0, /* window height */ + NULL, /* no parent window */ + NULL, /* no menu in this window */ + GetModuleHandle(NULL), /* handle of this program instance */ + NULL ); /* sent to WM_CREATE */ + + SetWindowLongPtr( ipcwindow, GWLP_WNDPROC, (LRESULT)WMCOPYWNDPROC ); + SetWindowLongPtr( ipcwindow, GWLP_USERDATA, (LONG_PTR)p_this ); + + /* Signal the creation of the thread and events queue */ + vlc_thread_ready( p_this ); + + while( GetMessage( &message, NULL, 0, 0 ) ) + { + TranslateMessage( &message ); + DispatchMessage( &message ); + } +} + +LRESULT CALLBACK WMCOPYWNDPROC( HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + if( uMsg == WM_COPYDATA ) + { + COPYDATASTRUCT *pwm_data = (COPYDATASTRUCT*)lParam; + vlc_object_t *p_this; + playlist_t *p_playlist; + + p_this = (vlc_object_t *) + (uintptr_t)GetWindowLongPtr( hwnd, GWLP_USERDATA ); + + if( !p_this ) return 0; + + /* Add files to the playlist */ + p_playlist = pl_Yield( p_this ); + if( !p_playlist ) return 0; + + if( pwm_data->lpData ) + { + char **ppsz_argv; + vlc_ipc_data_t *p_data = (vlc_ipc_data_t *)pwm_data->lpData; + size_t i_data = 0; + int i_argc = p_data->argc, i_opt, i_options; + + ppsz_argv = (char **)malloc( i_argc * sizeof(char *) ); + for( i_opt = 0; i_opt < i_argc; i_opt++ ) + { + ppsz_argv[i_opt] = p_data->data + i_data + sizeof(int); + i_data += sizeof(int) + *((int *)(p_data->data + i_data)); + } + + for( i_opt = 0; i_opt < i_argc; i_opt++ ) + { + i_options = 0; + + /* Count the input options */ + while( i_opt + i_options + 1 < i_argc && + *ppsz_argv[ i_opt + i_options + 1 ] == ':' ) + { + i_options++; + } + playlist_AddExt( p_playlist, ppsz_argv[i_opt], + NULL, PLAYLIST_APPEND | + ( ( i_opt || p_data->enqueue ) ? 0 : PLAYLIST_GO ), + PLAYLIST_END, -1, + (char const **)( i_options ? &ppsz_argv[i_opt+1] : NULL ), + i_options, true, pl_Unlocked ); + + i_opt += i_options; + } + + free( ppsz_argv ); + } + + vlc_object_release( p_playlist ); + } + + return DefWindowProc( hwnd, uMsg, wParam, lParam ); } /***************************************************************************** * system_End: terminate winsock. *****************************************************************************/ -void system_End( void ) +void system_End( libvlc_int_t *p_this ) { + if( p_this && vlc_global() ) + { + free( vlc_global()->psz_vlcpath ); + vlc_global()->psz_vlcpath = NULL; + } + vlc_object_t *obj = libvlc_priv (p_this)->ipc_helper; + if (obj) + { + vlc_thread_join (obj); + vlc_object_release (obj); + } + +#if !defined( UNDER_CE ) + timeEndPeriod(5); +#endif + WSACleanup(); }