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