]> git.sesse.net Git - vlc/blob - activex/main.cpp
lastest -> latest
[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         WideCharToMultiByte(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         // ToolboxBitmap32 key value
190         hSubKey = keyCreate(hClassKey, TEXT("ToolboxBitmap32"));
191         strcpy(DllPath+DllPathLen, ",1");
192         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
193                 (const BYTE*)DllPath, DllPathLen+2);
194         DllPath[DllPathLen] = '\0';
195         RegCloseKey(hSubKey);
196
197 #ifdef BUILD_LOCALSERVER
198         // LocalServer32 key value
199         hSubKey = keyCreate(hClassKey, TEXT("LocalServer32"));
200         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
201                 (const BYTE*)DllPath, DllPathLen);
202         RegCloseKey(hSubKey);
203 #else
204         // InprocServer32 key value
205         hSubKey = keyCreate(hClassKey, TEXT("InprocServer32"));
206         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
207                 (const BYTE*)DllPath, DllPathLen);
208         RegSetValueEx(hSubKey, TEXT("ThreadingModel"), 0, REG_SZ,
209                 (const BYTE*)THREADING_MODEL, sizeof(THREADING_MODEL));
210         RegCloseKey(hSubKey);
211 #endif
212
213         // MiscStatus key value
214         hSubKey = keyCreate(hClassKey, TEXT("MiscStatus\\1"));
215         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, (const BYTE*)MISC_STATUS, sizeof(MISC_STATUS));
216         RegCloseKey(hSubKey);
217
218         // Programmable key value
219         hSubKey = keyCreate(hClassKey, TEXT("Programmable"));
220         RegCloseKey(hSubKey);
221
222         // ProgID key value
223         hSubKey = keyCreate(hClassKey, TEXT("ProgID"));
224         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, 
225                 (const BYTE*)VERS_PROGID_STR, sizeof(VERS_PROGID_STR));
226         RegCloseKey(hSubKey);
227
228         // VersionIndependentProgID key value
229         hSubKey = keyCreate(hClassKey, TEXT("VersionIndependentProgID"));
230         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, 
231                 (const BYTE*)PROGID_STR, sizeof(PROGID_STR));
232         RegCloseKey(hSubKey);
233
234         // Version key value
235         hSubKey = keyCreate(hClassKey, TEXT("Version"));
236         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
237                 (const BYTE*)VERSION_STR, sizeof(VERSION_STR));
238         RegCloseKey(hSubKey);
239
240         // TypeLib key value
241         LPCTSTR psz_LIBID = TStrFromGUID(LIBID_AXVLC);
242         if( NULL != psz_LIBID )
243         {
244             hSubKey = keyCreate(hClassKey, TEXT("TypeLib"));
245             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
246                     (const BYTE*)psz_LIBID, sizeof(TCHAR)*GUID_STRLEN);
247             RegCloseKey(hSubKey);
248         }
249         RegCloseKey(hClassKey);
250     }
251     RegCloseKey(hBaseKey);
252
253     hBaseKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
254     if( NULL != hBaseKey )
255     {
256         // default key value
257         RegSetValueEx(hBaseKey, NULL, 0, REG_SZ,
258                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
259
260         HKEY hSubKey = keyCreate(hBaseKey, TEXT("CLSID"));
261         if( NULL != hSubKey )
262         {
263             // default key value
264             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
265                     (const BYTE*)psz_CLSID, sizeof(TCHAR)*GUID_STRLEN);
266
267             RegCloseKey(hSubKey);
268         }
269         hSubKey = keyCreate(hBaseKey, TEXT("CurVer"));
270         if( NULL != hSubKey )
271         {
272             // default key value
273             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
274                     (const BYTE*)VERS_PROGID_STR, sizeof(VERS_PROGID_STR));
275
276             RegCloseKey(hSubKey);
277         }
278         RegCloseKey(hBaseKey);
279     }
280
281     hBaseKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(VERS_PROGID_STR));
282     if( NULL != hBaseKey )
283     {
284         // default key value
285         RegSetValueEx(hBaseKey, NULL, 0, REG_SZ,
286                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
287
288         HKEY hSubKey = keyCreate(hBaseKey, TEXT("CLSID"));
289         if( NULL != hSubKey )
290         {
291             // default key value
292             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
293                     (const BYTE*)psz_CLSID, sizeof(TCHAR)*GUID_STRLEN);
294
295             RegCloseKey(hSubKey);
296         }
297         RegCloseKey(hBaseKey);
298     }
299
300     // indicate which component categories we support
301     ICatRegister *pcr;
302     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
303             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
304         CATID implCategories[] = {
305             CATID_Control,
306             CATID_PersistsToPropertyBag,
307             CATID_SafeForInitializing,
308             CATID_SafeForScripting,
309         };
310
311         pcr->RegisterClassImplCategories(CLSID_VLCPlugin,
312                 sizeof(implCategories)/sizeof(CATID), implCategories);
313         pcr->Release();
314     }
315
316     // register type lib into the registry
317     ITypeLib *typeLib;
318
319 #ifdef BUILD_LOCALSERVER
320     // replace .exe by .tlb
321     strcpy(DllPath+DllPathLen-4, ".tlb");
322 #endif
323     
324 #ifndef OLE2ANSI
325     size_t typeLibPathLen = MultiByteToWideChar(CP_ACP, 0, DllPath, -1, NULL, 0);
326     if( typeLibPathLen > 0 )
327     {
328         LPOLESTR typeLibPath = (LPOLESTR)CoTaskMemAlloc(typeLibPathLen*sizeof(wchar_t));
329         MultiByteToWideChar(CP_ACP, 0, DllPath, DllPathLen, typeLibPath, typeLibPathLen);
330         if( FAILED(LoadTypeLibEx(typeLibPath, REGKIND_REGISTER, &typeLib)) )
331 #ifndef BUILD_LOCALSERVER
332             return SELFREG_E_TYPELIB;
333         typeLib->Release();
334 #endif
335         CoTaskMemFree((void *)typeLibPath);
336     }
337 #else
338     if( FAILED(LoadTypeLibEx((LPOLESTR)DllPath, REGKIND_REGISTER, &typeLib)) )
339         return SELFREG_E_TYPELIB;
340     typeLib->Release();
341 #endif
342
343     CoTaskMemFree((void *)psz_CLSID);
344
345     return S_OK;
346 };
347
348 #ifdef BUILD_LOCALSERVER
349
350 /*
351 ** easier to debug an application than a DLL on cygwin GDB :)
352 */
353 #include <iostream>
354
355 STDAPI_(int) WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
356 {
357     MSG msg;
358
359     if( FAILED(OleInitialize(NULL)) )
360     {
361         cerr << "cannot initialize OLE" << endl;
362         return 1;
363     }
364
365     h_instance = hInst;
366
367     if( FAILED(DllRegisterServer()) )
368     {
369         cerr << "cannot register Local Server" << endl;
370         return 1;
371     }
372
373     IUnknown *classProc = NULL;
374
375     if( FAILED(DllGetClassObject(CLSID_VLCPlugin, IID_IUnknown, (LPVOID *)&classProc)) )
376         return 0;
377  
378     DWORD dwRegisterClassObject;
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     classProc->Release();
391
392     /*
393     * Polling messages from event queue
394     */
395     while( S_FALSE == DllCanUnloadNow() )
396     {
397         while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
398         {
399             if( msg.message == WM_QUIT )
400                 break;  // Leave the PeekMessage while() loop
401
402             /*if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
403                 continue;*/
404
405             TranslateMessage(&msg);
406             DispatchMessage(&msg);
407         }
408
409         if(msg.message == WM_QUIT)
410             break;  // Leave the for() loop
411
412         WaitMessage();
413     }
414
415     if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject, NULL)) )
416         CoRevokeClassObject(dwRegisterClassObject);
417
418     // Reached on WM_QUIT message
419     CoUninitialize();
420     return ((int) msg.wParam);
421 };
422
423 #else
424
425 STDAPI_(BOOL) DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
426 {
427     switch( fdwReason )
428     {
429         case DLL_PROCESS_ATTACH:
430             h_instance = (HINSTANCE)hModule;
431             break;
432
433         default:
434             break;
435     }
436     return TRUE;
437 };
438
439 #endif
440