]> git.sesse.net Git - vlc/blob - activex/main.cpp
Avoid \r\n problems between platforms
[vlc] / activex / main.cpp
1 /*****************************************************************************
2  * main.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2005 VideoLAN
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 THREADING_MODEL "Both"
32 #define COMPANY_STR "VideoLAN"
33 #define PROGRAM_STR "VLCPlugin"
34 #define VERSION_MAJOR_STR "1"
35 #define VERSION_MINOR_STR "0"
36 #define DESCRIPTION "VideoLAN VLC ActiveX Plugin"
37
38 #define PROGID_STR COMPANY_STR"."PROGRAM_STR
39 #define VERS_PROGID_STR COMPANY_STR"."PROGRAM_STR"."VERSION_MAJOR_STR
40 #define VERSION_STR VERSION_MAJOR_STR"."VERSION_MINOR_STR
41
42 #define GUID_STRLEN 39
43
44 /*
45 ** MingW headers do not declare those
46 */
47 extern const CATID CATID_SafeForInitializing;
48 extern const CATID CATID_SafeForScripting;
49
50 static LONG i_class_ref= 0;
51 static HINSTANCE h_instance= 0;
52
53 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
54 {
55     HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
56
57     *ppv = NULL;
58
59     if( CLSID_VLCPlugin == rclsid )
60     {
61         VLCPluginClass *plugin = new VLCPluginClass(&i_class_ref, h_instance);
62         hr = plugin->QueryInterface(riid, ppv);
63         plugin->Release();
64     }
65     return hr;
66 };
67
68 STDAPI DllCanUnloadNow(VOID)
69 {
70     return (0 == i_class_ref) ? S_OK: S_FALSE;
71 };
72
73 static LPCTSTR TStrFromGUID(REFGUID clsid) {
74     LPOLESTR oleStr;
75
76     if( FAILED(StringFromIID(clsid, &oleStr)) )
77         return NULL;
78
79     //check whether TCHAR and OLECHAR are both either ANSI or UNICODE
80     if( sizeof(TCHAR) == sizeof(OLECHAR) )
81         return (LPCTSTR)oleStr;
82
83     LPTSTR pct_CLSID = NULL;
84 #ifndef OLE2ANSI
85     size_t len = WideCharToMultiByte(CP_ACP, 0, oleStr, -1, NULL, 0, NULL, NULL);
86     if( len > 0 )
87     {
88         pct_CLSID = (char *)CoTaskMemAlloc(len);
89         WideCharToMultiByte(CP_ACP, 0, oleStr, -1, pct_CLSID, len, NULL, NULL);
90     }
91 #else
92     size_t len = MutiByteToWideChar(CP_ACP, 0, oleStr, -1, NULL, 0);
93     if( len > 0 )
94     {
95         clsidStr = (wchar_t *)CoTaskMemAlloc(len*sizeof(wchar_t));
96         WideCharToMultiByte(CP_ACP, 0, oleStr, -1, pct_CLSID, len);
97     }
98 #endif
99     CoTaskMemFree(oleStr);
100     return pct_CLSID;
101 };
102
103 static HKEY keyCreate(HKEY parentKey, LPCTSTR keyName)
104 {
105     HKEY childKey;
106     if( ERROR_SUCCESS == RegCreateKeyEx(parentKey, keyName, 0, NULL,
107                 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &childKey, NULL) )
108     {
109         return childKey;
110     }
111     return NULL;
112 };
113
114 STDAPI DllUnregisterServer(VOID)
115 {
116     // unregister type lib from the registry
117     UnRegisterTypeLib(LIBID_AXVLC, 1, 0, LOCALE_NEUTRAL, SYS_WIN32);
118
119     // remove component categories we supports
120     ICatRegister *pcr;
121     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
122             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
123         CATID implCategories[] = {
124             CATID_Control,
125             CATID_PersistsToPropertyBag,
126             CATID_SafeForInitializing,
127             CATID_SafeForScripting,
128         };
129
130         pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin,
131                 sizeof(implCategories)/sizeof(CATID), implCategories);
132         pcr->Release();
133     }
134
135     SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(VERS_PROGID_STR));
136     SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
137
138     LPCTSTR psz_CLSID = TStrFromGUID(CLSID_VLCPlugin);
139
140     if( NULL == psz_CLSID )
141         return E_OUTOFMEMORY;
142
143     HKEY hClsIDKey;
144     if( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_WRITE, &hClsIDKey) )
145     {
146         SHDeleteKey(hClsIDKey, psz_CLSID);
147         RegCloseKey(hClsIDKey);
148     }
149     CoTaskMemFree((void *)psz_CLSID);
150
151     return S_OK;
152 };
153
154 STDAPI DllRegisterServer(VOID)
155 {
156     DllUnregisterServer();
157
158     char DllPath[MAX_PATH];
159     DWORD DllPathLen= GetModuleFileName(h_instance, DllPath, sizeof(DllPath)) ;
160         if( 0 == DllPathLen )
161         return E_FAIL;
162
163     LPCTSTR psz_CLSID = TStrFromGUID(CLSID_VLCPlugin);
164
165     if( NULL == psz_CLSID )
166         return E_OUTOFMEMORY;
167
168     HKEY hBaseKey;
169
170     if( ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_CREATE_SUB_KEY, &hBaseKey) )
171         return E_FAIL;
172
173     HKEY hClassKey = keyCreate(hBaseKey, psz_CLSID);
174     if( NULL != hClassKey )
175     {
176         HKEY hSubKey;
177
178         // default key value
179         RegSetValueEx(hClassKey, NULL, 0, REG_SZ,
180                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
181
182         // Control key value
183         hSubKey = keyCreate(hClassKey, TEXT("Control"));
184         RegCloseKey(hSubKey);
185
186         // InprocServer32 key value
187         hSubKey = keyCreate(hClassKey, TEXT("InprocServer32"));
188         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
189                 (const BYTE*)DllPath, DllPathLen);
190         RegSetValueEx(hSubKey, TEXT("ThreadingModel"), 0, REG_SZ,
191                 (const BYTE*)THREADING_MODEL, sizeof(THREADING_MODEL));
192         RegCloseKey(hSubKey);
193
194         // MiscStatus key value
195         hSubKey = keyCreate(hClassKey, TEXT("MiscStatus\\1"));
196         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, (const BYTE*)"131473", sizeof("131473"));
197         RegCloseKey(hSubKey);
198
199         // Programmable key value
200         hSubKey = keyCreate(hClassKey, TEXT("Programmable"));
201         RegCloseKey(hSubKey);
202
203         // ProgID key value
204         hSubKey = keyCreate(hClassKey, TEXT("ProgID"));
205         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, 
206                 (const BYTE*)VERS_PROGID_STR, sizeof(VERS_PROGID_STR));
207         RegCloseKey(hSubKey);
208
209         // VersionIndependentProgID key value
210         hSubKey = keyCreate(hClassKey, TEXT("VersionIndependentProgID"));
211         RegSetValueEx(hSubKey, NULL, 0, REG_SZ, 
212                 (const BYTE*)PROGID_STR, sizeof(PROGID_STR));
213         RegCloseKey(hSubKey);
214
215         // Version key value
216         hSubKey = keyCreate(hClassKey, TEXT("Version"));
217         RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
218                 (const BYTE*)VERSION_STR, sizeof(VERSION_STR));
219         RegCloseKey(hSubKey);
220
221         // TypeLib key value
222         LPCTSTR psz_LIBID = TStrFromGUID(LIBID_AXVLC);
223         if( NULL != psz_LIBID )
224         {
225             hSubKey = keyCreate(hClassKey, TEXT("TypeLib"));
226             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
227                     (const BYTE*)psz_LIBID, sizeof(TCHAR)*GUID_STRLEN);
228             RegCloseKey(hSubKey);
229         }
230         RegCloseKey(hClassKey);
231     }
232     RegCloseKey(hBaseKey);
233
234     hBaseKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
235     if( NULL != hBaseKey )
236     {
237         // default key value
238         RegSetValueEx(hBaseKey, NULL, 0, REG_SZ,
239                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
240
241         HKEY hSubKey = keyCreate(hBaseKey, TEXT("CLSID"));
242         if( NULL != hSubKey )
243         {
244             // default key value
245             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
246                     (const BYTE*)psz_CLSID, sizeof(TCHAR)*GUID_STRLEN);
247
248             RegCloseKey(hSubKey);
249         }
250         hSubKey = keyCreate(hBaseKey, TEXT("CurVer"));
251         if( NULL != hSubKey )
252         {
253             // default key value
254             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
255                     (const BYTE*)VERS_PROGID_STR, sizeof(VERS_PROGID_STR));
256
257             RegCloseKey(hSubKey);
258         }
259         RegCloseKey(hBaseKey);
260     }
261
262     hBaseKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(VERS_PROGID_STR));
263     if( NULL != hBaseKey )
264     {
265         // default key value
266         RegSetValueEx(hBaseKey, NULL, 0, REG_SZ,
267                 (const BYTE*)DESCRIPTION, sizeof(DESCRIPTION));
268
269         HKEY hSubKey = keyCreate(hBaseKey, TEXT("CLSID"));
270         if( NULL != hSubKey )
271         {
272             // default key value
273             RegSetValueEx(hSubKey, NULL, 0, REG_SZ,
274                     (const BYTE*)psz_CLSID, sizeof(TCHAR)*GUID_STRLEN);
275
276             RegCloseKey(hSubKey);
277         }
278         RegCloseKey(hBaseKey);
279     }
280
281     // indicate which component categories we support
282     ICatRegister *pcr;
283     if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
284             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
285         CATID implCategories[] = {
286             CATID_Control,
287             CATID_PersistsToPropertyBag,
288             CATID_SafeForInitializing,
289             CATID_SafeForScripting,
290         };
291
292         pcr->RegisterClassImplCategories(CLSID_VLCPlugin,
293                 sizeof(implCategories)/sizeof(CATID), implCategories);
294         pcr->Release();
295     }
296
297     // register type lib into the registry
298     ITypeLib *typeLib;
299 #ifndef OLE2ANSI
300     size_t typeLibPathLen = MultiByteToWideChar(CP_ACP, 0, DllPath, DllPathLen, NULL, 0);
301     if( typeLibPathLen > 0 )
302     {
303         LPOLESTR typeLibPath = (LPOLESTR)CoTaskMemAlloc(typeLibPathLen*sizeof(wchar_t));
304         MultiByteToWideChar(CP_ACP, 0, DllPath, DllPathLen, typeLibPath, typeLibPathLen);
305         if( SUCCEEDED(LoadTypeLibEx(typeLibPath, REGKIND_REGISTER, &typeLib)) )
306             typeLib->Release();
307         CoTaskMemFree((void *)typeLibPath);
308     }
309 #else
310     if( SUCCEEDED(LoadTypeLibEx((LPOLESTR)DllPath, REGKIND_REGISTER, &typeLib)) )
311         typeLib->Release();
312 #endif
313
314     CoTaskMemFree((void *)psz_CLSID);
315
316     return S_OK;
317 };
318
319 #ifdef BUILD_LOCALSERVER
320
321 /*
322 ** easier to debug an application than a DLL on cygwin GDB :)
323 */
324 #include <iostream>
325
326 STDAPI_(int) WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
327 {
328     MSG msg;
329
330     if( FAILED(OleInitialize(NULL)) )
331     {
332         cerr << "cannot initialize OLE" << endl;
333         return 1;
334     }
335
336     IUnknown *classProc = NULL;
337
338     if( FAILED(DllGetClassObject(CLSID_VLCPlugin, IID_IUnknown, (LPVOID *)&classProc)) )
339         return 0;
340  
341     DWORD dwRegisterClassObject;
342
343     if( FAILED(CoRegisterClassObject(CLSID_VLCPlugin, classProc,
344         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegisterClassObject)) )
345         return 0;
346
347     DWORD dwRegisterActiveObject;
348
349     if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin,
350                     ACTIVEOBJECT_WEAK, &dwRegisterActiveObject)) )
351         return 0;
352
353     classProc->Release();
354
355     /*
356     * Polling messages from event queue
357     */
358     while( S_FALSE == DllCanUnloadNow() )
359     {
360         while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
361         {
362             if( msg.message == WM_QUIT )
363                 break;  // Leave the PeekMessage while() loop
364
365             /*if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
366                 continue;*/
367
368             TranslateMessage(&msg);
369             DispatchMessage(&msg);
370         }
371
372         if(msg.message == WM_QUIT)
373             break;  // Leave the for() loop
374
375         WaitMessage();
376     }
377
378     if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject, NULL)) )
379         CoRevokeClassObject(dwRegisterClassObject);
380
381     // Reached on WM_QUIT message
382     CoUninitialize();
383     return ((int) msg.wParam);
384 };
385
386 #else
387
388 STDAPI_(BOOL) DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
389 {
390     switch( fdwReason )
391     {
392         case DLL_PROCESS_ATTACH:
393             h_instance = (HINSTANCE)hModule;
394             break;
395
396         default:
397             break;
398     }
399     return TRUE;
400 };
401
402 #endif
403