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