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