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