]> git.sesse.net Git - vlc/blob - activex/main.cpp
- revert 16847, this breaks the activex and mozilla plugins, and passing a argv[0...
[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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24 #include "utils.h"
25
26 #include <stdio.h>
27
28 #include <comcat.h>
29 #include <windows.h>
30 #include <shlwapi.h>
31
32 using namespace std;
33
34 #define COMPANY_STR "VideoLAN"
35 #define PROGRAM_STR "VLCPlugin"
36 #define DESCRIPTION "VideoLAN VLC ActiveX Plugin"
37
38 #define THREADING_MODEL "Apartment"
39 #define MISC_STATUS     "131473"
40
41 #define PROGID_STR COMPANY_STR"."PROGRAM_STR
42
43 #define GUID_STRLEN 39
44
45 /*
46 ** MingW headers do not declare those
47 */
48 extern const CATID CATID_SafeForInitializing;
49 extern const CATID CATID_SafeForScripting;
50
51 static LONG i_class_ref= 0;
52 static HINSTANCE h_instance= 0;
53
54 HMODULE DllGetModule()
55 {
56     return h_instance;
57 };
58
59 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
60 {
61     HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
62
63     *ppv = NULL;
64
65     if( (CLSID_VLCPlugin == rclsid )
66      || ( CLSID_VLCPlugin2 == rclsid) )
67     {
68         VLCPluginClass *plugin = new VLCPluginClass(&i_class_ref, h_instance, rclsid);
69         hr = plugin->QueryInterface(riid, ppv);
70         plugin->Release();
71     }
72     return hr;
73 };
74
75 STDAPI DllCanUnloadNow(VOID)
76 {
77     return (0 == i_class_ref) ? S_OK: S_FALSE;
78 };
79
80 static inline HKEY keyCreate(HKEY parentKey, LPCSTR keyName)
81 {
82     HKEY childKey;
83     if( ERROR_SUCCESS == RegCreateKeyExA(parentKey, keyName, 0, NULL,
84                 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &childKey, NULL) )
85     {
86         return childKey;
87     }
88     return NULL;
89 };
90
91 static inline HKEY keySet(HKEY hKey, LPCSTR valueName, const void *s, size_t len)
92 {
93     if( NULL != hKey )
94     {
95         RegSetValueExA(hKey, valueName, 0, REG_SZ,
96             (const BYTE*)s, len);
97     }
98     return hKey;
99 };
100
101 static inline HKEY keySetDef(HKEY hKey, const void *s, size_t len)
102 {
103     return keySet(hKey, NULL, s, len);
104 };
105
106 static inline HKEY keySetDef(HKEY hKey, LPCSTR s)
107 {
108     return keySetDef(hKey, s, strlen(s)+1);
109 };
110
111 static inline HKEY keyClose(HKEY hKey)
112 {
113     if( NULL != hKey )
114     {
115         RegCloseKey(hKey);
116     }
117     return NULL;
118 };
119
120 static HRESULT UnregisterProgID(REFCLSID rclsid, unsigned int version)
121 {
122     LPCSTR psz_CLSID = CStrFromGUID(rclsid);
123
124     if( NULL == psz_CLSID )
125         return E_OUTOFMEMORY;
126
127     char progId[sizeof(PROGID_STR)+16];
128     sprintf(progId, "%s.%u", PROGID_STR, version);
129
130     SHDeleteKeyA(HKEY_CLASSES_ROOT, progId);
131
132     HKEY hClsIDKey;
133     if( ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_WRITE, &hClsIDKey) )
134     {
135         SHDeleteKey(hClsIDKey, psz_CLSID);
136         RegCloseKey(hClsIDKey);
137     }
138     CoTaskMemFree((void *)psz_CLSID);
139 };
140
141 STDAPI DllUnregisterServer(VOID)
142 {
143     // unregister type lib from the registry
144     UnRegisterTypeLib(LIBID_AXVLC, 1, 0, LOCALE_NEUTRAL, SYS_WIN32);
145
146     // remove component categories we supports
147     ICatRegister *pcr;
148     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
149             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
150         CATID implCategories[] = {
151             CATID_Control,
152             CATID_PersistsToPropertyBag,
153             CATID_SafeForInitializing,
154             CATID_SafeForScripting,
155         };
156
157         pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin,
158                 sizeof(implCategories)/sizeof(CATID), implCategories);
159         pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin2,
160                 sizeof(implCategories)/sizeof(CATID), implCategories);
161         pcr->Release();
162     }
163
164     SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
165
166     UnregisterProgID(CLSID_VLCPlugin, 2);
167     UnregisterProgID(CLSID_VLCPlugin2, 1);
168
169     return S_OK;
170 };
171
172 static HRESULT RegisterClassID(HKEY hParent, REFCLSID rclsid, unsigned int version, BOOL isDefault, const char *path, size_t pathLen)
173 {
174     char progId[sizeof(PROGID_STR)+16];
175     sprintf(progId, "%s.%u", PROGID_STR, version);
176
177     char description[sizeof(DESCRIPTION)+16];
178     sprintf(description, "%s v%u", DESCRIPTION, version);
179
180     HKEY hClassKey;
181     {
182         LPCSTR psz_CLSID = CStrFromGUID(rclsid);
183
184         if( NULL == psz_CLSID )
185             return E_OUTOFMEMORY;
186
187         HKEY hProgKey = keyCreate(HKEY_CLASSES_ROOT, progId);
188         if( NULL != hProgKey )
189         {
190             // default key value
191             keySetDef(hProgKey, description);
192
193             keyClose(keySetDef(keyCreate(hProgKey, "CLSID"),
194                 psz_CLSID,
195                 GUID_STRLEN));
196      
197             //hSubKey = keyClose(keyCreate(hBaseKey, "Insertable"));
198      
199             RegCloseKey(hProgKey);
200         }
201         if( isDefault )
202         {
203             hProgKey = keyCreate(HKEY_CLASSES_ROOT, PROGID_STR);
204             if( NULL != hProgKey )
205             {
206                 // default key value
207                 keySetDef(hProgKey, description);
208
209                 keyClose(keySetDef(keyCreate(hProgKey, "CLSID"),
210                     psz_CLSID,
211                     GUID_STRLEN));
212          
213                 keyClose(keySetDef(keyCreate(hProgKey, "CurVer"),
214                     progId));
215             }
216         }
217         hClassKey = keyCreate(hParent, psz_CLSID);
218         CoTaskMemFree((void *)psz_CLSID);
219     }
220     if( NULL != hClassKey )
221     {
222         // default key value
223         keySetDef(hClassKey, description);
224
225         // Control key value
226         keyClose(keyCreate(hClassKey, "Control"));
227
228         // Insertable key value
229         //keyClose(keyCreate(hClassKey, "Insertable"));
230
231         // ToolboxBitmap32 key value
232         {
233             char iconPath[pathLen+3];
234             memcpy(iconPath, path, pathLen);
235             strcpy(iconPath+pathLen, ",1");
236             keyClose(keySetDef(keyCreate(hClassKey,
237                 "ToolboxBitmap32"),
238                 iconPath, sizeof(iconPath)));
239         }
240
241 #ifdef BUILD_LOCALSERVER
242         // LocalServer32 key value
243         keyClose(keySetDef(keyCreate(hClassKey,
244             "LocalServer32", path, pathLen+1)));
245 #else
246         // InprocServer32 key value
247         {
248             HKEY hSubKey = keySetDef(keyCreate(hClassKey,
249                 "InprocServer32"),
250                 path, pathLen+1);
251             keySet(hSubKey,
252                 "ThreadingModel",
253                 THREADING_MODEL, sizeof(THREADING_MODEL));
254             keyClose(hSubKey);
255         }
256 #endif
257
258         // MiscStatus key value
259         keyClose(keySetDef(keyCreate(hClassKey,
260             "MiscStatus\\1"),
261             MISC_STATUS, sizeof(MISC_STATUS)));
262
263         // Programmable key value
264         keyClose(keyCreate(hClassKey, "Programmable"));
265
266         // ProgID key value
267         keyClose(keySetDef(keyCreate(hClassKey,
268             TEXT("ProgID")),
269             progId));
270
271         // VersionIndependentProgID key value
272         keyClose(keySetDef(keyCreate(hClassKey,
273             "VersionIndependentProgID"),
274             PROGID_STR, sizeof(PROGID_STR)));
275
276         // Version key value
277         keyClose(keySetDef(keyCreate(hClassKey,
278             "Version"),
279             "1.0"));
280
281         // TypeLib key value
282         LPCSTR psz_LIBID = CStrFromGUID(LIBID_AXVLC);
283         if( NULL != psz_LIBID )
284         {
285             keyClose(keySetDef(keyCreate(hClassKey,
286                     "TypeLib"),
287                     psz_LIBID, GUID_STRLEN));
288             CoTaskMemFree((void *)psz_LIBID);
289         }
290         RegCloseKey(hClassKey);
291     }
292     return S_OK;
293 }
294
295 STDAPI DllRegisterServer(VOID)
296 {
297     DllUnregisterServer();
298
299     char DllPath[MAX_PATH];
300     DWORD DllPathLen=GetModuleFileNameA(h_instance, DllPath, sizeof(DllPath)) ;
301         if( 0 == DllPathLen )
302         return E_UNEXPECTED;
303
304     HKEY hBaseKey;
305
306     if( ERROR_SUCCESS != RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_CREATE_SUB_KEY, &hBaseKey) )
307         return SELFREG_E_CLASS;
308     
309     RegisterClassID(hBaseKey, CLSID_VLCPlugin, 1, FALSE, DllPath, DllPathLen);
310     RegisterClassID(hBaseKey, CLSID_VLCPlugin2, 2, TRUE, DllPath, DllPathLen);
311
312     RegCloseKey(hBaseKey);
313
314     // indicate which component categories we support
315     ICatRegister *pcr;
316     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
317             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
318         CATID implCategories[] = {
319             CATID_Control,
320             CATID_PersistsToPropertyBag,
321             CATID_SafeForInitializing,
322             CATID_SafeForScripting,
323         };
324
325         pcr->RegisterClassImplCategories(CLSID_VLCPlugin,
326                 sizeof(implCategories)/sizeof(CATID), implCategories);
327         pcr->RegisterClassImplCategories(CLSID_VLCPlugin2,
328                 sizeof(implCategories)/sizeof(CATID), implCategories);
329         pcr->Release();
330     }
331
332     // register type lib into the registry
333     ITypeLib *typeLib;
334
335 #ifdef BUILD_LOCALSERVER
336     // replace .exe by .tlb
337     strcpy(DllPath+DllPathLen-4, ".tlb");
338 #endif
339     
340 #ifndef OLE2ANSI
341     size_t typeLibPathLen = MultiByteToWideChar(CP_ACP, 0, DllPath, -1, NULL, 0);
342     if( typeLibPathLen > 0 )
343     {
344         LPOLESTR typeLibPath = (LPOLESTR)CoTaskMemAlloc(typeLibPathLen*sizeof(wchar_t));
345         MultiByteToWideChar(CP_ACP, 0, DllPath, DllPathLen, typeLibPath, typeLibPathLen);
346         if( FAILED(LoadTypeLibEx(typeLibPath, REGKIND_REGISTER, &typeLib)) )
347 #ifndef BUILD_LOCALSERVER
348             return SELFREG_E_TYPELIB;
349         typeLib->Release();
350 #endif
351         CoTaskMemFree((void *)typeLibPath);
352     }
353 #else
354     if( FAILED(LoadTypeLibEx((LPOLESTR)DllPath, REGKIND_REGISTER, &typeLib)) )
355         return SELFREG_E_TYPELIB;
356     typeLib->Release();
357 #endif
358
359     return S_OK;
360 };
361
362 #ifdef BUILD_LOCALSERVER
363
364 /*
365 ** easier to debug an application than a DLL on cygwin GDB :)
366 */
367 #include <iostream>
368
369 STDAPI_(int) WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
370 {
371     MSG msg;
372
373     if( FAILED(OleInitialize(NULL)) )
374     {
375         cerr << "cannot initialize OLE" << endl;
376         return 1;
377     }
378
379     h_instance = hInst;
380
381     if( FAILED(DllRegisterServer()) )
382     {
383         cerr << "cannot register Local Server" << endl;
384         return 1;
385     }
386
387     IUnknown *classProc = NULL;
388
389     if( FAILED(DllGetClassObject(CLSID_VLCPlugin, IID_IUnknown, (LPVOID *)&classProc)) )
390         return 0;
391  
392     DWORD dwRegisterClassObject;
393     DWORD dwRegisterClassObject2;
394
395     if( FAILED(CoRegisterClassObject(CLSID_VLCPlugin, classProc,
396         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegisterClassObject)) )
397         return 0;
398
399     DWORD dwRegisterActiveObject;
400
401     if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin,
402                     ACTIVEOBJECT_WEAK, &dwRegisterActiveObject)) )
403         return 0;
404
405     if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin2,
406                     ACTIVEOBJECT_WEAK, &dwRegisterActiveObject2)) )
407         return 0;
408
409     classProc->Release();
410
411     /*
412     * Polling messages from event queue
413     */
414     while( S_FALSE == DllCanUnloadNow() )
415     {
416         while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
417         {
418             if( msg.message == WM_QUIT )
419                 break;  // break out PeekMessage loop
420
421             /*if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
422                 continue;*/
423
424             TranslateMessage(&msg);
425             DispatchMessage(&msg);
426         }
427
428         if(msg.message == WM_QUIT)
429             break;  // break out main loop
430
431         WaitMessage();
432     }
433
434     if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject, NULL)) )
435         CoRevokeClassObject(dwRegisterClassObject);
436
437     if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject2, NULL)) )
438         CoRevokeClassObject(dwRegisterClassObject2);
439
440     // Reached on WM_QUIT message
441     OleUninitialize();
442     return ((int) msg.wParam);
443 };
444
445 #else
446
447 STDAPI_(BOOL) DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
448 {
449     switch( fdwReason )
450     {
451         case DLL_PROCESS_ATTACH:
452             h_instance = (HINSTANCE)hModule;
453             break;
454
455         default:
456             break;
457     }
458     return TRUE;
459 };
460
461 #endif
462