licensing cleanup (GPLv2)
[org.ibex.wildebeest.git] / src / org / xwt / plat / Win32-dll.cc
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the GNU General Public License version 2 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 //
6 // A simple DLL to invoke xwt.exe and pass it any arguments found in the <object/> tag
7 //
8
9 #include <windows.h>
10 #include <initguid.h>
11 #include <objbase.h>
12 #include <oaidl.h>
13 #include <oleauto.h>
14 #include <olectl.h>
15 #include <unknwn.h>
16
17
18 // Globals ////////////////////////////////////////////////////////////////////////
19
20 using namespace std;
21
22 #define CLSID_STRING_SIZE 39
23
24 const char XWT_friendlyName[] = "XWT ActiveX Control (build " BUILDID ")";
25 const char XWT_versionIndependantProgramID[] = "XWT.ActiveX";
26 const char XWT_programID[] = "XWT.ActiveX (build " BUILDID ")";
27 extern "C" const CLSID XWT_clsid = CLSID_STRUCT;
28 static HMODULE g_hModule = NULL;    //DLL handle
29
30
31
32
33 // Superclasses ////////////////////////////////////////////////////////////////////////
34
35 // Option bit definitions for IObjectSafety:
36 #define INTERFACESAFE_FOR_UNTRUSTED_CALLER  0x00000001  // Caller of interface may be untrusted
37 #define INTERFACESAFE_FOR_UNTRUSTED_DATA    0x00000002  // Data passed into interface may be untrusted
38
39 // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
40 //DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);
41 extern "C" const CLSID IID_IObjectSafety;
42
43 interface IObjectSafety : public IUnknown {
44  public:
45     virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) = 0;
46     virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) = 0;
47 };
48
49 interface IShoeHorn : IPersistPropertyBag, IObjectSafety { };
50
51
52
53 // Entry Points ////////////////////////////////////////////////////////////////////////
54
55 // to get mingw to stop nagging me
56 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { }
57
58 // determines whether or not the DLL can be unloaded; always allow this since we don't do too much
59 STDAPI __declspec(dllexport) DllCanUnloadNow(void) { return S_OK; }
60
61 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID /*lpReserved*/) {
62     if (dwReason == DLL_PROCESS_ATTACH) g_hModule = (HINSTANCE)hModule;
63     return TRUE;
64 }
65
66
67
68 // Other ///////////////////////////////////////////////////////////////////////////////////
69
70 // simple assert() replacement that pops open a message box if there are errors
71 void check(int val, char* message) {
72     if (!val) {
73         MessageBox (NULL, message, "XWT Critical Abort", MB_OK | MB_ICONEXCLAMATION  | MB_TASKMODAL | MB_SETFOREGROUND);
74         exit(-1);
75     }
76 }
77
78 void clsidToString(const CLSID& clsid, char* str, int length) {
79     check(length >= CLSID_STRING_SIZE, "clsidToString(): string too short");
80         LPOLESTR wide_str = NULL;
81         HRESULT hr = StringFromCLSID(clsid, &wide_str);
82         check(SUCCEEDED(hr), "StringFromCLSID() failed in clsidToString()");
83         wcstombs(str, wide_str, length);
84         CoTaskMemFree(wide_str);
85 }
86
87 void setRegistryKey(const char* key, const char* subkey, const char* value) {
88         HKEY hKey;
89         char keyBuf[1024];
90         strcpy(keyBuf, key);
91         if (subkey != NULL) {
92                 strcat(keyBuf, "\\");
93                 strcat(keyBuf, subkey );
94         }
95         long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
96         if (value != NULL)
97         check(RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, strlen(value) + 1) == ERROR_SUCCESS,
98               "RegSetValueEx() failed in setRegistryKey()");
99         RegCloseKey(hKey);
100 }
101
102 void deleteRegistryKey(HKEY parent, const char* target) {
103         HKEY hKeyChild;
104         RegOpenKeyEx(parent, target, 0, KEY_ALL_ACCESS, &hKeyChild);
105
106         // Iterate over children, deleting them
107         FILETIME time;
108         char szBuffer[256];
109         DWORD dwSize = 256;
110         while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) {
111                 deleteRegistryKey(hKeyChild, szBuffer);
112                 dwSize = 256;
113         }
114
115         RegCloseKey(hKeyChild);
116         RegDeleteKey(parent, target);
117 }
118
119 STDAPI __declspec(dllexport) DllRegisterServer(void) {
120         char moduleName[512];
121     HRESULT result = GetModuleFileName(g_hModule, moduleName, sizeof(moduleName)/sizeof(char));
122         check(result, "GetModuleFileName() failed in RegisterServer()");
123
124         char clsidString[CLSID_STRING_SIZE];
125         clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
126
127         // build the key
128         char key[64];
129         strcpy(key, "CLSID\\");
130         strcat(key, clsidString);
131   
132         setRegistryKey(key, NULL, XWT_friendlyName);
133         setRegistryKey(key, "InprocServer32", moduleName);
134         setRegistryKey(key, "ProgID", XWT_programID);
135         setRegistryKey(key, "VersionIndependentProgID", XWT_versionIndependantProgramID);
136         setRegistryKey(XWT_versionIndependantProgramID, NULL, XWT_friendlyName); 
137         setRegistryKey(XWT_versionIndependantProgramID, "CLSID", clsidString);
138         setRegistryKey(XWT_versionIndependantProgramID, "CurVer", XWT_programID);
139         setRegistryKey(XWT_programID, NULL, XWT_friendlyName); 
140         setRegistryKey(XWT_programID, "CLSID", clsidString);
141         return S_OK;
142 }
143
144 STDAPI __declspec(dllexport) DllUnregisterServer(void) {
145         char clsidString[CLSID_STRING_SIZE];
146         clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
147
148         // build the key
149         char key[64];
150         strcpy(key, "CLSID\\");
151         strcat(key, clsidString);
152
153         deleteRegistryKey(HKEY_CLASSES_ROOT, key);
154         deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_versionIndependantProgramID);
155         deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_programID);
156         return S_OK;
157 }
158
159
160
161 // ShoeHorn //////////////////////////////////////////////////////////////////////////////////
162
163 class ShoeHorn : public IShoeHorn {
164     public:
165     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
166         if(iid == IID_IUnknown) *ppv = static_cast<IShoeHorn*>(this);
167         else if(iid == XWT_clsid) *ppv = static_cast<IShoeHorn*>(this);
168         else if(iid == IID_IPersistPropertyBag) *ppv = static_cast<IPersistPropertyBag*>(this);
169         else if(iid == IID_IObjectSafety) *ppv = static_cast<IObjectSafety*>(this);
170         else { *ppv = NULL; return E_NOINTERFACE; }
171         reinterpret_cast<IUnknown*>(*ppv)->AddRef();
172         return S_OK;
173     }
174     virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
175     virtual ULONG __stdcall Release() {
176         if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; }
177         return m_cRef;
178     }
179     virtual HRESULT __stdcall GetClassID(CLSID*) { return S_OK; }
180     virtual HRESULT __stdcall InitNew() { return S_OK; }
181     virtual HRESULT __stdcall Save(IPropertyBag*, int, int) { return S_OK; }
182     virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions) { return S_OK; }
183     virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions) {
184         if (pdwSupportedOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
185         if (pdwEnabledOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
186         return S_OK;
187     }
188
189     virtual HRESULT __stdcall Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) {
190         VARIANT v;
191         v.vt = VT_BSTR;
192         HRESULT hrRead;
193         
194         WCHAR wc[100];
195         char url[100];
196         
197         MultiByteToWideChar(CP_ACP, 0, "xwar", -1, wc, 100);
198         pPropBag->Read(wc, &v, pErrorLog);
199         check(WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, url, 100, NULL, NULL),
200               "WideCharToMultiByte() failed in ShoeHorn::Load()");
201         
202         HKEY hkey;
203         LONG result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache", &hkey);
204         check(result == ERROR_SUCCESS, "RegOpenKey() failed in ShoeHorn::Load()");
205         
206         // iterate over all the activex cache locations until we find ourselves
207         for(int i=0; i<9; i++) {
208             DWORD buflen = 999;
209             char buf[1000];
210             VALENT valents[20];
211             DWORD type;
212             char which[2];
213
214             which[0] = '0' + i;
215             which[1] = '\0';
216             result = RegQueryValueEx(hkey, which, NULL, &type, (BYTE*)buf, &buflen);
217             if (result != ERROR_SUCCESS)
218                 if (i == 0) {
219                     check(0, "RegQueryValueEx() failed in ShoeHorn::Load()");
220                 } else {
221                     break;
222                 }
223             buf[buflen] = '\0';
224             
225             char cmdline[200];
226             for(int i=0; i<200; i++) cmdline[i] = '\0';
227             strncpy(cmdline, buf, 200);
228             strncpy(cmdline + strlen(cmdline), "\\xwt-" BUILDID ".exe", 200 - strlen(cmdline));
229             strncpy(cmdline + strlen(cmdline), " ", 200 - strlen(cmdline));
230             strncpy(cmdline + strlen(cmdline), url, 200 - strlen(cmdline));
231             
232             PROCESS_INFORMATION pInfo;
233             STARTUPINFO sInfo;
234             sInfo.cb = sizeof(STARTUPINFO);
235             sInfo.lpReserved = NULL;
236             sInfo.lpReserved2 = NULL;
237             sInfo.cbReserved2 = 0;
238             sInfo.lpDesktop = NULL;
239             sInfo.lpTitle = NULL;
240             sInfo.dwFlags = 0;
241             sInfo.dwX = 0;
242             sInfo.dwY = 0;
243             sInfo.dwFillAttribute = 0;
244             sInfo.wShowWindow = SW_SHOW;
245             BOOL b = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo);
246             if (b) return S_OK;
247         }
248
249         check(0, "unable to locate xwt-" BUILDID ".exe in ActiveX cache folders");
250     }
251
252     ShoeHorn() : m_cRef(1) { };
253     ~ShoeHorn() { };
254     private: long m_cRef;
255 };
256
257
258
259
260 // ClassFactory //////////////////////////////////////////////////////////////////////////
261
262 class ClassFactory : public IClassFactory {
263     public:
264     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
265         if(iid == IID_IUnknown) *ppv = static_cast<IClassFactory*>(this);
266         else if(iid == IID_IClassFactory) *ppv = static_cast<IClassFactory*>(this);
267         else {
268             *ppv = NULL;
269             return E_NOINTERFACE;
270         }
271         reinterpret_cast<IUnknown*>(*ppv)->AddRef();
272         return S_OK;
273     }
274
275     ClassFactory() : m_cRef(1) { }
276     ~ClassFactory() { }
277     virtual HRESULT __stdcall LockServer(BOOL bLock) { return S_OK; }
278     virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
279     virtual ULONG __stdcall Release() {
280         if(InterlockedDecrement(&m_cRef) == 0) {
281             delete this;
282             return 0;
283         }
284         return m_cRef;
285     }
286
287     virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
288         if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
289         ShoeHorn* s = new ShoeHorn;
290         if(s == NULL) return E_OUTOFMEMORY;
291         HRESULT hr = s->QueryInterface(iid, ppv);
292         s->Release();
293         return hr;
294     }
295     
296     private: long m_cRef;
297 };
298
299
300 extern "C" __stdcall HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) {
301     if(clsid != XWT_clsid) return CLASS_E_CLASSNOTAVAILABLE;
302     ClassFactory* pFactory = new ClassFactory; 
303     if(pFactory == NULL) return E_OUTOFMEMORY;
304     HRESULT hr = pFactory->QueryInterface(iid, ppv);
305     pFactory->Release();
306     return hr;
307 }
308
309