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