]> git.sesse.net Git - vlc/blob - activex/main.cpp
* modules/audio_output/directx.c: backported directx audio output fix from trunk...
[vlc] / activex / main.cpp
1 /*****************************************************************************
2  * main.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24
25 #include <comcat.h>
26 #include <windows.h>
27 #include <shlwapi.h>
28
29 using namespace std;
30
31 #define COMPANY_STR "VideoLAN"
32 #define PROGRAM_STR "VLCPlugin"
33 #define VERSION_MAJOR_STR "1"
34 #define VERSION_MINOR_STR "0"
35 #define DESCRIPTION "VideoLAN VLC ActiveX Plugin"
36
37 #define THREADING_MODEL "Apartment"
38 #define MISC_STATUS     "131473"
39
40 #define PROGID_STR COMPANY_STR"."PROGRAM_STR
41 #define VERS_PROGID_STR COMPANY_STR"."PROGRAM_STR"."VERSION_MAJOR_STR
42 #define VERSION_STR VERSION_MAJOR_STR"."VERSION_MINOR_STR
43
44 #define GUID_STRLEN 39
45
46 /*
47 ** MingW headers do not declare those
48 */
49 extern const CATID CATID_SafeForInitializing;
50 extern const CATID CATID_SafeForScripting;
51
52 static LONG i_class_ref= 0;
53 static HINSTANCE h_instance= 0;
54
55 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
56 {
57     HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
58
59     *ppv = NULL;
60
61     if( CLSID_VLCPlugin == rclsid )
62     {
63         VLCPluginClass *plugin = new VLCPluginClass(&i_class_ref, h_instance);
64         hr = plugin->QueryInterface(riid, ppv);
65         plugin->Release();
66     }
67     return hr;
68 };
69
70 STDAPI DllCanUnloadNow(VOID)
71 {
72     return (0 == i_class_ref) ? S_OK: S_FALSE;
73 };
74
75 static LPCTSTR TStrFromGUID(REFGUID clsid)
76 {
77     LPOLESTR oleStr;
78
79     if( FAILED(StringFromIID(clsid, &oleStr)) )
80         return NULL;
81
82     //check whether TCHAR and OLECHAR are both either ANSI or UNICODE
83     if( sizeof(TCHAR) == sizeof(OLECHAR) )
84         return (LPCTSTR)oleStr;
85
86     LPTSTR pct_CLSID = NULL;
87 #ifndef OLE2ANSI
88     size_t len = WideCharToMultiByte(CP_ACP, 0, oleStr, -1, NULL, 0, NULL, NULL);
89     if( len > 0 )
90     {
91         pct_CLSID = (char *)CoTaskMemAlloc(len);
92         WideCharToMultiByte(CP_ACP, 0, oleStr, -1, pct_CLSID, len, NULL, NULL);
93     }
94 #else
95     size_t len = MutiByteToWideChar(CP_ACP, 0, oleStr, -1, NULL, 0);
96     if( len > 0 )
97     {
98         clsidStr = (wchar_t *)CoTaskMemAlloc(len*sizeof(wchar_t));
99         MultiByteToWideChar(CP_ACP, 0, oleStr, -1, pct_CLSID, len);
100     }
101 #endif
102     CoTaskMemFree(oleStr);
103     return pct_CLSID;
104 };
105
106 static HKEY keyCreate(HKEY parentKey, LPCTSTR keyName)
107 {
108     HKEY childKey;
109     if( ERROR_SUCCESS == RegCreateKeyEx(parentKey, keyName, 0, NULL,
110                 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &childKey, NULL) )
111     {
112         return childKey;
113     }
114     return NULL;
115 };
116
117 STDAPI DllUnregisterServer(VOID)
118 {
119     // unregister type lib from the registry
120     UnRegisterTypeLib(LIBID_AXVLC, 1, 0, LOCALE_NEUTRAL, SYS_WIN32);
121
122     // remove component categories we supports
123     ICatRegister *pcr;
124     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
125             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
126         CATID implCategories[] = {
127             CATID_Control,
128             CATID_PersistsToPropertyBag,
129             CATID_SafeForInitializing,
130             CATID_SafeForScripting,
131         };
132
133         pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin,
134                 sizeof(implCategories)/sizeof(CATID), implCategories);
135         pcr->Release();
136     }
137
138     SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(VERS_PROGID_STR));
139     SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
140
141     LPCTSTR psz_CLSID = TStrFromGUID(CLSID_VLCPlugin);
142
143     if( NULL == psz_CLSID )
144         return E_OUTOFMEMORY;
145
146     HKEY hClsIDKey;
147     if( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_WRITE, &hClsIDKey) )
148     {
149         SHDeleteKey(hClsIDKey, psz_CLSID);
150         RegCloseKey(hClsIDKey);
151     }
152     CoTaskMemFree((void *)psz_CLSID);
153
154     return S_OK;
155 };
156
157 STDAPI DllRegisterServer(VOID)
158 {
159     DllUnregisterServer();
160
161     char DllPath[MAX_PATH];
162     DWORD DllPathLen= GetModuleFileName(h_instance, DllPath, sizeof(DllPath)) ;
163         if( 0 == DllPathLen )
164         return E_UNEXPECTED;
165
166     LPCTSTR psz_CLSID = TStrFromGUID(CLSID_VLCPlugin);
167
168     if( NULL == psz_CLSID )
169         return E_OUTOFMEMORY;
170
171     HKEY hBaseKey;
172
173     if( ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_CREATE_SUB_KEY, &hBaseKey) )
174         return SELFREG_E_CLASS;
175
176     HKEY hClassKey = keyCreate(hBaseKey, psz_CLSID);
177     if( NULL != hClassKey )
178     {
179         HKEY hSubKey;
180
181         // default key value
182         RegSetValueEx(hClassKey, NULL, 0, REG_SZ,
183                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
184
185         // Control key value
186         hSubKey = keyCreate(hClassKey, TEXT("Control"));
187         RegCloseKey(hSubKey);
188
189         // Insertable key value
190         //hSubKey = keyCreate(hClassKey, TEXT("Insertable"));
191         //RegCloseKey(hSubKey);
192
193         // ToolboxBitmap32 key value
194         hSubKey = keyCreate(hClassKey, TEXT("ToolboxBitmap32"));
195         strcpy(DllPath+DllPathLen, ",1");
196         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
197                 (const BYTE*)DllPath, DllPathLen+2);
198         DllPath[DllPathLen] = '\0';
199         RegCloseKey(hSubKey);
200
201 #ifdef BUILD_LOCALSERVER
202         // LocalServer32 key value
203         hSubKey = keyCreate(hClassKey, TEXT("LocalServer32"));
204         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
205                 (const BYTE*)DllPath, DllPathLen);
206         RegCloseKey(hSubKey);
207 #else
208         // InprocServer32 key value
209         hSubKey = keyCreate(hClassKey, TEXT("InprocServer32"));
210         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
211                 (const BYTE*)DllPath, DllPathLen);
212         RegSetValueEx(hSubKey, TEXT("ThreadingModel"), 0, REG_SZ,
213                 (const BYTE*)THREADING_MODEL, sizeof(THREADING_MODEL));
214         RegCloseKey(hSubKey);
215 #endif
216
217         // MiscStatus key value
218         hSubKey = keyCreate(hClassKey, TEXT("MiscStatus\\1"));
219         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, (const BYTE*)MISC_STATUS, sizeof(MISC_STATUS));
220         RegCloseKey(hSubKey);
221
222         // Programmable key value
223         hSubKey = keyCreate(hClassKey, TEXT("Programmable"));
224         RegCloseKey(hSubKey);
225
226         // ProgID key value
227         hSubKey = keyCreate(hClassKey, TEXT("ProgID"));
228         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, 
229                 (const BYTE*)VERS_PROGID_STR, sizeof(VERS_PROGID_STR));
230         RegCloseKey(hSubKey);
231
232         // VersionIndependentProgID key value
233         hSubKey = keyCreate(hClassKey, TEXT("VersionIndependentProgID"));
234         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, 
235                 (const BYTE*)PROGID_STR, sizeof(PROGID_STR));
236         RegCloseKey(hSubKey);
237
238         // Version key value
239         hSubKey = keyCreate(hClassKey, TEXT("Version"));
240         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
241                 (const BYTE*)VERSION_STR, sizeof(VERSION_STR));
242         RegCloseKey(hSubKey);
243
244         // TypeLib key value
245         LPCTSTR psz_LIBID = TStrFromGUID(LIBID_AXVLC);
246         if( NULL != psz_LIBID )
247         {
248             hSubKey = keyCreate(hClassKey, TEXT("TypeLib"));
249             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
250                     (const BYTE*)psz_LIBID, sizeof(TCHAR)*GUID_STRLEN);
251             RegCloseKey(hSubKey);
252         }
253         RegCloseKey(hClassKey);
254     }
255     RegCloseKey(hBaseKey);
256
257     hBaseKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
258     if( NULL != hBaseKey )
259     {
260         // default key value
261         RegSetValueEx(hBaseKey, NULL, 0, REG_SZ,
262                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
263
264         HKEY hSubKey = keyCreate(hBaseKey, TEXT("CLSID"));
265         if( NULL != hSubKey )
266         {
267             // default key value
268             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
269                     (const BYTE*)psz_CLSID, sizeof(TCHAR)*GUID_STRLEN);
270
271             RegCloseKey(hSubKey);
272         }
273         hSubKey = keyCreate(hBaseKey, TEXT("CurVer"));
274         if( NULL != hSubKey )
275         {
276             // default key value
277             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
278                     (const BYTE*)VERS_PROGID_STR, sizeof(VERS_PROGID_STR));
279
280             RegCloseKey(hSubKey);
281         }
282         RegCloseKey(hBaseKey);
283     }
284
285     hBaseKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(VERS_PROGID_STR));
286     if( NULL != hBaseKey )
287     {
288         // default key value
289         RegSetValueEx(hBaseKey, NULL, 0, REG_SZ,
290                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
291
292         HKEY hSubKey = keyCreate(hBaseKey, TEXT("CLSID"));
293         if( NULL != hSubKey )
294         {
295             // default key value
296             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
297                     (const BYTE*)psz_CLSID, sizeof(TCHAR)*GUID_STRLEN);
298
299             RegCloseKey(hSubKey);
300         }
301         //hSubKey = keyCreate(hBaseKey, TEXT("Insertable"));
302         //RegCloseKey(hSubKey);
303  
304         RegCloseKey(hBaseKey);
305     }
306
307     // indicate which component categories we support
308     ICatRegister *pcr;
309     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
310             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
311         CATID implCategories[] = {
312             CATID_Control,
313             CATID_PersistsToPropertyBag,
314             CATID_SafeForInitializing,
315             CATID_SafeForScripting,
316         };
317
318         pcr->RegisterClassImplCategories(CLSID_VLCPlugin,
319                 sizeof(implCategories)/sizeof(CATID), implCategories);
320         pcr->Release();
321     }
322
323     // register type lib into the registry
324     ITypeLib *typeLib;
325
326 #ifdef BUILD_LOCALSERVER
327     // replace .exe by .tlb
328     strcpy(DllPath+DllPathLen-4, ".tlb");
329 #endif
330     
331 #ifndef OLE2ANSI
332     size_t typeLibPathLen = MultiByteToWideChar(CP_ACP, 0, DllPath, -1, NULL, 0);
333     if( typeLibPathLen > 0 )
334     {
335         LPOLESTR typeLibPath = (LPOLESTR)CoTaskMemAlloc(typeLibPathLen*sizeof(wchar_t));
336         MultiByteToWideChar(CP_ACP, 0, DllPath, DllPathLen, typeLibPath, typeLibPathLen);
337         if( FAILED(LoadTypeLibEx(typeLibPath, REGKIND_REGISTER, &typeLib)) )
338 #ifndef BUILD_LOCALSERVER
339             return SELFREG_E_TYPELIB;
340         typeLib->Release();
341 #endif
342         CoTaskMemFree((void *)typeLibPath);
343     }
344 #else
345     if( FAILED(LoadTypeLibEx((LPOLESTR)DllPath, REGKIND_REGISTER, &typeLib)) )
346         return SELFREG_E_TYPELIB;
347     typeLib->Release();
348 #endif
349
350     CoTaskMemFree((void *)psz_CLSID);
351
352     return S_OK;
353 };
354
355 #ifdef BUILD_LOCALSERVER
356
357 /*
358 ** easier to debug an application than a DLL on cygwin GDB :)
359 */
360 #include <iostream>
361
362 STDAPI_(int) WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
363 {
364     MSG msg;
365
366     if( FAILED(OleInitialize(NULL)) )
367     {
368         cerr << "cannot initialize OLE" << endl;
369         return 1;
370     }
371
372     h_instance = hInst;
373
374     if( FAILED(DllRegisterServer()) )
375     {
376         cerr << "cannot register Local Server" << endl;
377         return 1;
378     }
379
380     IUnknown *classProc = NULL;
381
382     if( FAILED(DllGetClassObject(CLSID_VLCPlugin, IID_IUnknown, (LPVOID *)&classProc)) )
383         return 0;
384  
385     DWORD dwRegisterClassObject;
386
387     if( FAILED(CoRegisterClassObject(CLSID_VLCPlugin, classProc,
388         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegisterClassObject)) )
389         return 0;
390
391     DWORD dwRegisterActiveObject;
392
393     if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin,
394                     ACTIVEOBJECT_WEAK, &dwRegisterActiveObject)) )
395         return 0;
396
397     classProc->Release();
398
399     /*
400     * Polling messages from event queue
401     */
402     while( S_FALSE == DllCanUnloadNow() )
403     {
404         while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
405         {
406             if( msg.message == WM_QUIT )
407                 break;  // Leave the PeekMessage while() loop
408
409             /*if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
410                 continue;*/
411
412             TranslateMessage(&msg);
413             DispatchMessage(&msg);
414         }
415
416         if(msg.message == WM_QUIT)
417             break;  // Leave the for() loop
418
419         WaitMessage();
420     }
421
422     if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject, NULL)) )
423         CoRevokeClassObject(dwRegisterClassObject);
424
425     // Reached on WM_QUIT message
426     CoUninitialize();
427     return ((int) msg.wParam);
428 };
429
430 #else
431
432 STDAPI_(BOOL) DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
433 {
434     switch( fdwReason )
435     {
436         case DLL_PROCESS_ATTACH:
437             h_instance = (HINSTANCE)hModule;
438             break;
439
440         default:
441             break;
442     }
443     return TRUE;
444 };
445
446 #endif
447