c0793dd0e63a0f31a1f07e67df9511533238bab6
[vlc.git] / src / misc / win32_specific.c
1 /*****************************************************************************
2  * win32_specific.c: Win32 specific features
3  *****************************************************************************
4  * Copyright (C) 2001-2004 VideoLAN
5  * $Id: win32_specific.c,v 1.31 2004/01/09 12:23:46 gbazin Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Gildas Bazin <gbazin@netcourrier.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24 #include <string.h>                                              /* strdup() */
25 #include <stdlib.h>                                                /* free() */
26
27 #include <vlc/vlc.h>
28 #include "vlc_playlist.h"
29
30 #ifdef WIN32                       /* optind, getopt(), included in unistd.h */
31 #   include "../extras/getopt.h"
32 #endif
33
34 #if !defined( UNDER_CE )
35 #   include <io.h>
36 #   include <fcntl.h>
37 #   include <winsock2.h>
38 #endif
39
40 /*****************************************************************************
41  * system_Init: initialize winsock and misc other things.
42  *****************************************************************************/
43 void system_Init( vlc_t *p_this, int *pi_argc, char *ppsz_argv[] )
44 {
45 #if !defined( UNDER_CE )
46     WSADATA Data;
47
48     /* Get our full path */
49     if( ppsz_argv[0] )
50     {
51         char psz_path[MAX_PATH];
52         char *psz_vlc;
53
54         GetFullPathName( ppsz_argv[0], MAX_PATH, psz_path, &psz_vlc );
55
56         if( psz_vlc > psz_path && psz_vlc[-1] == '\\' )
57         {
58             psz_vlc[-1] = '\0';
59             p_this->p_libvlc->psz_vlcpath = strdup( psz_path );
60         }
61         else
62         {
63             p_this->p_libvlc->psz_vlcpath = strdup( "" );
64         }
65     }
66     else
67     {
68         p_this->p_libvlc->psz_vlcpath = strdup( "" );
69     }
70
71     /* Set the default file-translation mode */
72     _fmode = _O_BINARY;
73     _setmode( _fileno( stdin ), _O_BINARY ); /* Needed for pipes */
74
75     /* Call mdate() once to make sure it is initialized properly */
76     mdate();
77
78     /* WinSock Library Init. */
79     if( !WSAStartup( MAKEWORD( 2, 0 ), &Data ) )
80     {
81         /* Confirm that the WinSock DLL supports 2.0.*/
82         if( LOBYTE( Data.wVersion ) != 2 || HIBYTE( Data.wVersion ) != 0 )
83         {
84             /* We could not find a suitable WinSock DLL. */
85             WSACleanup( );
86         }
87         else
88         {
89             /* Everything went ok. */
90             return;
91         }
92     }
93
94     /* Let's try with WinSock 1.1 */
95     if( !WSAStartup( MAKEWORD( 1, 1 ), &Data ) )
96     {
97         /* Confirm that the WinSock DLL supports 1.1.*/
98         if( LOBYTE( Data.wVersion ) != 1 || HIBYTE( Data.wVersion ) != 1 )
99         {
100             /* We could not find a suitable WinSock DLL. */
101             WSACleanup( );
102         }
103         else
104         {
105             /* Everything went ok. */
106             return;
107         }
108     }
109
110     fprintf( stderr, "error: can't initialize WinSocks\n" );
111
112     return; 
113
114 #endif
115 }
116
117 /*****************************************************************************
118  * system_Configure: check for system specific configuration options.
119  *****************************************************************************/
120 static void IPCHelperThread( vlc_object_t * );
121 LRESULT CALLBACK WMCOPYWNDPROC( HWND, UINT, WPARAM, LPARAM );
122
123 void system_Configure( vlc_t *p_this, int *pi_argc, char *ppsz_argv[] )
124 {
125 #if !defined( UNDER_CE )
126     p_this->p_libvlc->b_fast_mutex = config_GetInt( p_this, "fast-mutex" );
127     p_this->p_libvlc->i_win9x_cv = config_GetInt( p_this, "win9x-cv-method" );
128
129     /* Raise default priority of the current process */
130 #ifndef ABOVE_NORMAL_PRIORITY_CLASS
131 #   define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
132 #endif
133     if( config_GetInt( p_this, "high-priority" ) )
134     {
135         if( SetPriorityClass( GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS )
136              || SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
137         {
138             msg_Dbg( p_this, "raised process priority" );
139         }
140         else
141         {
142             msg_Dbg( p_this, "could not raise process priority" );
143         }
144     }
145
146     if( config_GetInt( p_this, "one-instance" ) )
147     {
148         HANDLE hmutex;
149
150         msg_Info( p_this, "One instance mode ENABLED");
151
152         /* Use a named mutex to check if another instance is already running */
153         if( ( hmutex = CreateMutex( NULL, TRUE, "VLC ipc "VERSION ) ) == NULL )
154         {
155             /* Failed for some reason. Just ignore the option and go on as
156              * normal. */
157             msg_Err( p_this, "One instance mode DISABLED "
158                      "(mutex couldn't be created)" );
159             return;
160         }
161
162         if( GetLastError() != ERROR_ALREADY_EXISTS )
163         {
164             /* We are the 1st instance. */
165             vlc_object_t *p_helper =
166              (vlc_object_t *)vlc_object_create( p_this, sizeof(vlc_object_t) );
167
168             /* Run the helper thread */
169             if( vlc_thread_create( p_helper, "IPC helper", IPCHelperThread,
170                                    VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
171             {
172                 msg_Err( p_this, "One instance mode DISABLED "
173                          "(IPC helper thread couldn't be created)" );
174
175             }
176
177             /* Initialization done.
178              * Release the mutex to unblock other instances */
179             ReleaseMutex( hmutex );
180         }
181         else
182         {
183             /* Another instance is running */
184
185             HWND ipcwindow;
186
187             /* Wait until the 1st instance is initialized */
188             WaitForSingleObject( hmutex, INFINITE );
189
190             /* Locate the window created by the IPC helper thread of the
191              * 1st instance */
192             if( ( ipcwindow = FindWindow( NULL, "VLC ipc "VERSION ) )
193                 == NULL )
194             {
195                 msg_Err( p_this, "One instance mode DISABLED "
196                          "(couldn't find 1st instance of program)" );
197                 ReleaseMutex( hmutex );
198                 return;
199             }
200
201             /* We assume that the remaining parameters are filenames
202              * and their input options */
203             if( *pi_argc - 1 >= optind )
204             {
205                 COPYDATASTRUCT wm_data;
206                 int i_opt, i_data;
207                 char *p_data;
208
209                 i_data = sizeof(int);
210                 for( i_opt = optind; i_opt < *pi_argc; i_opt++ )
211                 {
212                     i_data += sizeof(int);
213                     i_data += strlen( ppsz_argv[ i_opt ] ) + 1;
214                 }
215
216                 p_data = (char *)malloc( i_data );
217                 *((int *)&p_data[0]) = *pi_argc - optind;
218                 i_data = sizeof(int);
219                 for( i_opt = optind; i_opt < *pi_argc; i_opt++ )
220                 {
221                     int i_len = strlen( ppsz_argv[ i_opt ] ) + 1;
222                     *((int *)&p_data[i_data]) = i_len;
223                     i_data += sizeof(int);
224                     memcpy( &p_data[i_data], ppsz_argv[ i_opt ], i_len );
225                     i_data += i_len;
226                 }
227
228                 /* Send our playlist items to the 1st instance */
229                 wm_data.dwData = 0;
230                 wm_data.cbData = i_data;
231                 wm_data.lpData = p_data;
232                 SendMessage( ipcwindow, WM_COPYDATA, 0, (LPARAM)&wm_data );
233             }
234
235             /* Initialization done.
236              * Release the mutex to unblock other instances */
237             ReleaseMutex( hmutex );
238
239             /* Bye bye */
240             system_End( p_this );
241             exit( 0 );
242         }
243     }
244
245 #endif
246 }
247
248 static void IPCHelperThread( vlc_object_t *p_this )
249 {
250     HWND ipcwindow;
251     MSG message;
252
253     ipcwindow =
254         CreateWindow( "STATIC",                      /* name of window class */
255                   "VLC ipc "VERSION,                /* window title bar text */
256                   0,                                         /* window style */
257                   0,                                 /* default X coordinate */
258                   0,                                 /* default Y coordinate */
259                   0,                                         /* window width */
260                   0,                                        /* window height */
261                   NULL,                                  /* no parent window */
262                   NULL,                            /* no menu in this window */
263                   GetModuleHandle(NULL),  /* handle of this program instance */
264                   NULL );                               /* sent to WM_CREATE */
265
266     SetWindowLong( ipcwindow, GWL_WNDPROC, (LONG)WMCOPYWNDPROC );
267     SetWindowLong( ipcwindow, GWL_USERDATA, (LONG)p_this );
268
269     /* Signal the creation of the thread and events queue */
270     vlc_thread_ready( p_this );
271
272     while( GetMessage( &message, NULL, 0, 0 ) )
273     {
274         TranslateMessage( &message );
275         DispatchMessage( &message );
276     }
277 }
278
279 LRESULT CALLBACK WMCOPYWNDPROC( HWND hwnd, UINT uMsg, WPARAM wParam,
280                                 LPARAM lParam )
281 {
282     if( uMsg == WM_COPYDATA )
283     {
284         COPYDATASTRUCT *pwm_data = (COPYDATASTRUCT*)lParam;
285         vlc_object_t *p_this;
286         playlist_t *p_playlist;
287
288         p_this = (vlc_object_t *)GetWindowLong( hwnd, GWL_USERDATA );
289
290         if( !p_this ) return 0;
291
292         /* Add files to the playlist */
293         p_playlist = (playlist_t *)vlc_object_find( p_this,
294                                                     VLC_OBJECT_PLAYLIST,
295                                                     FIND_ANYWHERE );
296         if( !p_playlist ) return 0;
297
298         if( pwm_data->lpData )
299         {
300             int i_argc, i_data, i_opt, i_options,i_id,i_pos,j;
301             char **ppsz_argv;
302             char *p_data = (char *)pwm_data->lpData;
303
304             i_argc = *((int *)&p_data[0]);
305             ppsz_argv = (char **)malloc( i_argc * sizeof(char *) );
306             i_data = sizeof(int);
307             for( i_opt = 0; i_opt < i_argc; i_opt++ )
308             {
309                 ppsz_argv[i_opt] = &p_data[i_data + sizeof(int)];
310                 i_data += *((int *)&p_data[i_data]);
311                 i_data += sizeof(int);
312             }
313
314             for( i_opt = 0; i_opt < i_argc; i_opt++ )
315             {
316                 i_options = 0;
317
318                 /* Count the input options */
319                 while( i_opt + i_options + 1 < i_argc &&
320                        *ppsz_argv[ i_opt + i_options + 1 ] == ':' )
321                 {
322                     i_options++;
323                 }
324                 i_id = playlist_Add( p_playlist, ppsz_argv[ i_opt ],
325                               ppsz_argv[ i_opt ],
326                               PLAYLIST_APPEND | (i_opt? 0 : PLAYLIST_GO),
327                               PLAYLIST_END );
328                 i_pos = playlist_GetPositionById( p_playlist, i_id );
329                 for( j = 0 ; j < i_options ; j++ )
330                 {
331                     playlist_AddOption( p_playlist, i_pos ,
332                                         ppsz_argv[i_opt+1+j] );
333                 }
334                 i_opt += i_options;
335             }
336
337             free( ppsz_argv );
338         }
339
340         vlc_object_release( p_playlist );
341     }
342
343     return DefWindowProc( hwnd, uMsg, wParam, lParam );
344 }
345
346 /*****************************************************************************
347  * system_End: terminate winsock.
348  *****************************************************************************/
349 void system_End( vlc_t *p_this )
350 {
351 #if !defined( UNDER_CE )
352     WSACleanup();
353 #endif
354 }