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