2002/04/28 04:36:08
[org.ibex.core.git] / src / org / xwt / plat / Win32.cc
1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
2
3 // kinda ugly; we use -DCOMPILE_DLL to combine two .cc files into one
4 #ifndef COMPILE_DLL
5
6 // this has to precede the others so we don't get collisions on min/max
7 #include <org/xwt/Box.h>
8
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #include <windows.h>
14 #include <mmsystem.h>
15 #undef STRICT
16
17 #include <gcj/cni.h>
18
19 #include <java/lang/Integer.h>
20 #include <java/util/Hashtable.h>
21 #include <org/xwt/Box.h>
22 #include <org/xwt/Surface.h>
23 #include <org/xwt/DoubleBuffer.h>
24 #include <org/xwt/Picture.h>
25 #include <org/xwt/Platform.h>
26 #include <org/xwt/Platform$ParsedFont.h>
27 #include <org/xwt/plat/Win32.h>
28 #include <org/xwt/plat/Win32$Win32Font.h>
29 #include <org/xwt/plat/Win32$Win32Surface.h>
30 #include <org/xwt/plat/Win32$Win32DoubleBuffer.h>
31 #include <org/xwt/plat/Win32$Win32Picture.h>
32 #include <org/xwt/util/Semaphore.h>
33
34 // for debugging
35 #include <java/lang/System.h>
36 #include <java/io/PrintStream.h>
37
38 #define WM_USER_SETCURSOR WM_USER
39 #define WM_USER_DISPOSE (WM_USER + 1)
40 #define WM_USER_CREATEWINDOW (WM_USER + 2)
41 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
42
43 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
44 //          a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
45
46 // Callbacks ////////////////////////////////////////////////////////////////////
47
48 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
49     org::xwt::plat::Win32$Win32Surface* surface =
50         (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
51
52     if (surface != NULL) {
53         return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
54
55     } else {
56         java::lang::System::out->print(JvNewStringLatin1("miss on hwnd "));
57         java::lang::System::out->println((jint)hwnd);
58         // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
59         return DefWindowProc(hwnd, iMsg, wParam, lParam);
60     }
61 }
62
63 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
64 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
65
66     if (lparam == 0) {
67         LOGFONT lf;
68         lf.lfCharSet = ANSI_CHARSET;
69         strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
70         lf.lfPitchAndFamily = 0;
71         EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
72
73     } else {
74         org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
75                                        ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
76                                        tm->tmItalic == 0 ? 0 : 1, 
77                                        tm->tmWeight <= 400 ? 0 : 1);
78     }
79     return 1;
80 }
81
82
83 // Initialization ////////////////////////////////////////////////////////////////////
84
85 static int window_class_counter = 0;
86
87 jstring org::xwt::plat::Win32::getTempPath() {
88     char buf[1024];
89     DWORD ret = GetTempPath(1024, buf);
90     if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
91     return JvNewStringLatin1(buf);
92 }
93
94 // XOR mask for the hand cursor
95 static unsigned char hand_cursor_xor[32 * 4] = {
96   0x00, 0x00, 0x00, 0x00,
97   0x00, 0x0C, 0x00, 0x00,
98   0x00, 0x0C, 0x00, 0x00,
99   0x00, 0x0C, 0x00, 0x00,
100   0x00, 0x0C, 0x00, 0x00,
101   0x00, 0x0C, 0x00, 0x00,
102   0x00, 0x0D, 0x80, 0x00,
103   0x00, 0x0D, 0xB0, 0x00,
104   0x00, 0x0D, 0xB4, 0x00,
105   0x00, 0x0D, 0xB6, 0x00,
106   0x00, 0xCF, 0xF6, 0x00,
107   0x00, 0xEF, 0xFE, 0x00,
108   0x00, 0x6F, 0xFE, 0x00,
109   0x00, 0x2F, 0xFE, 0x00,
110   0x00, 0x3F, 0xFE, 0x00,
111   0x00, 0x1F, 0xFE, 0x00,
112   0x00, 0x1F, 0xFC, 0x00,
113   0x00, 0x0F, 0xFC, 0x00,
114   0x00, 0x0F, 0xFC, 0x00,
115   0x00, 0x07, 0xF8, 0x00,
116   0x00, 0x07, 0xF8, 0x00,
117   0x00, 0x00, 0x00, 0x00,
118   0x00, 0x00, 0x00, 0x00,
119   0x00, 0x00, 0x00, 0x00,
120   0x00, 0x00, 0x00, 0x00,
121   0x00, 0x00, 0x00, 0x00,
122   0x00, 0x00, 0x00, 0x00,
123   0x00, 0x00, 0x00, 0x00,
124   0x00, 0x00, 0x00, 0x00,
125   0x00, 0x00, 0x00, 0x00,
126   0x00, 0x00, 0x00, 0x00,
127   0x00, 0x00, 0x00, 0x00
128 };
129
130 // AND mask for the hand cursor
131 static unsigned char hand_cursor_and[32 * 4] = {
132   0xFF, 0xF3, 0xFF, 0xFF,
133   0xFF, 0xE1, 0xFF, 0xFF,
134   0xFF, 0xE1, 0xFF, 0xFF,
135   0xFF, 0xE1, 0xFF, 0xFF,
136   0xFF, 0xE1, 0xFF, 0xFF,
137   0xFF, 0xE0, 0x7F, 0xFF,
138   0xFF, 0xE0, 0x0F, 0xFF,
139   0xFF, 0xE0, 0x03, 0xFF,
140   0xFF, 0xE0, 0x01, 0xFF,
141   0xFF, 0x20, 0x00, 0xFF,
142   0xFE, 0x00, 0x00, 0xFF,
143   0xFE, 0x00, 0x00, 0xFF,
144   0xFF, 0x00, 0x00, 0xFF,
145   0xFF, 0x80, 0x00, 0xFF,
146   0xFF, 0x80, 0x00, 0xFF,
147   0xFF, 0xC0, 0x00, 0xFF,
148   0xFF, 0xC0, 0x01, 0xFF,
149   0xFF, 0xE0, 0x01, 0xFF,
150   0xFF, 0xE0, 0x01, 0xFF,
151   0xFF, 0xF0, 0x03, 0xFF,
152   0xFF, 0xF0, 0x03, 0xFF,
153   0xFF, 0xF0, 0x03, 0xFF,
154   0xFF, 0xFF, 0xFF, 0xFF,
155   0xFF, 0xFF, 0xFF, 0xFF,
156   0xFF, 0xFF, 0xFF, 0xFF,
157   0xFF, 0xFF, 0xFF, 0xFF,
158   0xFF, 0xFF, 0xFF, 0xFF,
159   0xFF, 0xFF, 0xFF, 0xFF,
160   0xFF, 0xFF, 0xFF, 0xFF,
161   0xFF, 0xFF, 0xFF, 0xFF,
162   0xFF, 0xFF, 0xFF, 0xFF,
163   0xFF, 0xFF, 0xFF, 0xFF
164 };
165
166 void org::xwt::plat::Win32::natInit() {
167
168     // grab desktop dc/handle
169     desktop_handle = (jint)GetDesktopWindow();
170     desktop_dc = (jint)GetDC((HWND)desktop_handle);
171
172     // create cursors
173     org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
174     org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
175     org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
176     org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
177     org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
178     org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
179     org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
180     org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
181     org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
182     org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
183
184     // enumerate fonts
185     LOGFONT lf;
186     lf.lfCharSet = ANSI_CHARSET;
187     lf.lfFaceName[0] = 0;
188     lf.lfPitchAndFamily = 0;
189     EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
190
191     messagePumpThread = (jint)GetCurrentThreadId();
192     messagePumpStarted->release();
193
194     MSG msg;
195     while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
196
197         if (msg.message == WM_USER_CREATEWINDOW) {
198             org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
199
200             // we must create a unique window class name for each
201             // window so that minimization icons can be set independantly
202             char buf[255];
203             sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
204
205             WNDCLASSEX wc;
206             wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
207             wc.lpfnWndProc = WndProc;
208             wc.cbClsExtra = 0;
209             wc.cbSize = sizeof(WNDCLASSEX);
210             wc.cbWndExtra = 0;
211             wc.hInstance = GetModuleHandle(NULL);
212             wc.hIcon = NULL;
213             wc.hIconSm = NULL;
214             wc.hCursor = NULL;
215             wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
216             wc.lpszMenuName = NULL;
217             wc.lpszClassName = buf;
218             RegisterClassEx(&wc);
219             
220             surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
221                                                (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
222             SetFocus((HWND)surface->hwnd);
223             surface->hwndCreated->release();
224             
225         } else {
226             TranslateMessage(&msg);
227             if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
228             DispatchMessage(&msg);
229         }
230
231     }
232     java::lang::System::exit(-1);
233 }
234
235
236 // Platform Methods ///////////////////////////////////////////////////////////////////
237
238 jstring org::xwt::plat::Win32::_getClipBoard() {
239     OpenClipboard((HWND)desktop_handle);
240     HGLOBAL hmem = GetClipboardData(CF_TEXT);
241     if (hmem == NULL) return NULL;
242     char* buf = (char*)GlobalLock(hmem);
243     if (buf == NULL) return NULL;
244     jstring ret = JvNewStringLatin1(buf);
245     GlobalUnlock(hmem);
246     CloseClipboard();
247     return ret;
248 }
249
250 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
251     OpenClipboard((HWND)desktop_handle);
252     HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
253     if (hmem == NULL) return;
254     char* buf = (char*)GlobalLock(hmem);
255     if (buf == NULL) return;
256     JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
257     buf[JvGetStringUTFLength(s)] = '\0';
258     GlobalUnlock(hmem);
259     SetClipboardData(CF_TEXT, hmem);
260     CloseClipboard();
261 }
262
263 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
264     char buf[JvGetStringUTFLength(message) + 1];
265     buf[JvGetStringUTFLength(message)] = '\0';
266     JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
267     MessageBox (NULL, buf, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
268     java::lang::System::exit(-1);
269 }
270
271 jint org::xwt::plat::Win32::_getScreenWidth() {
272     RECT rect;
273     SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
274     return rect.right - rect.left;
275 }
276
277 jint org::xwt::plat::Win32::_getScreenHeight() {
278     RECT rect;
279     SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
280     return rect.bottom - rect.top;
281 }
282
283 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
284     org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
285     LOGFONT logfont;
286     memset(&logfont, 0, sizeof(LOGFONT));
287     logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
288     if (pf->italic) logfont.lfItalic = 1;
289     if (pf->bold) logfont.lfWeight = FW_BOLD;
290     logfont.lfCharSet = ANSI_CHARSET;
291
292     JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
293     logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
294
295     ret->hfont = (jint)CreateFontIndirect(&logfont);
296     SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
297
298     TEXTMETRIC tm;
299     GetTextMetrics((HDC)desktop_dc, &tm);
300     POINT p;
301     p.x = 0; p.y = tm.tmAscent;
302     LPtoDP((HDC)desktop_dc, &p, 1); 
303     ret->maxAscent = p.y;
304
305     p.x = 0; p.y = tm.tmDescent;
306     LPtoDP((HDC)desktop_dc, &p, 1);
307     ret->maxDescent = p.y;
308
309     return ret;
310 }
311
312 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
313
314     HFONT hfont = (HFONT)(getFont(font)->hfont);
315     SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
316
317     int len = min(1024, JvGetStringUTFLength(text));
318     char buf[len + 1];
319     buf[len] = '\0';
320     JvGetStringUTFRegion(text, 0, len, buf);
321     
322     SIZE size;
323     GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
324     return size.cx;
325 }
326
327 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
328
329     int len = min(2048, JvGetStringUTFLength(url));
330     char buf[len + 1];
331     JvGetStringUTFRegion(url, 0, len, buf);
332     buf[len] = '\0';
333
334     SHELLEXECUTEINFO ei;
335     memset(&ei, 0, sizeof(ei));
336     ei.cbSize = sizeof(ei);
337     ei.lpVerb = "open";
338     ei.lpFile = buf;
339     ei.fMask  = SEE_MASK_NOCLOSEPROCESS;
340     ei.nShow  = SW_SHOWDEFAULT;
341     return (ShellExecuteEx(&ei) == 0);
342
343 }
344
345
346 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
347
348 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
349 // Since all drawing operations are single-threaded, it's safe to use a global here.
350 static HBITMAP scratch = NULL;
351 static HDC scratch_dc = NULL;
352 static jint* scratch_bits = NULL;
353 static jint scratch_w = 0;
354 static jint scratch_h = 0;
355
356 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op)                                   \
357     if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1))                                        \
358         BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op);                             \
359     else                                                                                             \
360         StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
361         
362 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
363                                                           jint dx1, jint dy1, jint dx2, jint dy2,
364                                                           jint sx1, jint sy1, jint sx2, jint sy2) {
365
366     org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
367
368     if (source->hasalpha) {
369
370         if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
371             if (scratch_dc != NULL) DeleteDC(scratch_dc);
372             if (scratch != NULL) DeleteObject(scratch);
373             scratch_w = max(dx2 - dx1, scratch_w);
374             scratch_h = max(dy2 - dy1, scratch_h);
375
376             BITMAPINFO bitmapinfo;
377             memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
378             bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
379             bitmapinfo.bmiHeader.biWidth = scratch_w;
380             bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
381             bitmapinfo.bmiHeader.biPlanes = 1;
382             bitmapinfo.bmiHeader.biBitCount = 32;
383             bitmapinfo.bmiHeader.biCompression = BI_RGB;
384
385             // create section DIB
386             scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
387             scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
388             SelectObject(scratch_dc, scratch);
389         }
390
391         // copy from screen to scratch
392         BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
393
394         // apply alpha-blending to scratch
395         jint* dat = elements(source->data);
396
397         for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
398             for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
399                 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
400                 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
401                 jint dst = scratch_bits[y * scratch_w + x];
402                 jint src = dat[sy * source->getWidth() + sx];
403                 jint alpha = (src & 0xFF000000) >> 24;
404                 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
405                 jint g = (((src & 0x0000FF00) >> 8)  * alpha + ((dst & 0x0000FF00) >> 8)  * (0xFF - alpha)) / 0xFF;
406                 jint b = (((src & 0x000000FF))       * alpha + ((dst & 0x000000FF))       * (0xFF - alpha)) / 0xFF;
407                 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
408             }
409
410         // copy back from scratch to screen
411         BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
412
413     } else {
414         if (source->hasmask) {
415             BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
416             BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
417         } else {
418             BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
419         }
420
421     }
422
423 }
424
425 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
426
427     org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
428     SelectObject((HDC)hdc, (HFONT)(wf->hfont));
429
430     // Platform API passes us the y-pos of the bottom of the text; we need the top
431     y -= wf->maxAscent;
432
433     int len = min(1024, JvGetStringUTFLength(text));
434     char buf[len + 1];
435     buf[len] = '\0';
436     JvGetStringUTFRegion(text, 0, len, buf);
437
438     SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
439     TextOut((HDC)hdc, x, y, buf, len);
440 }
441
442 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
443     jint w = x2 - x;
444     jint h = y2 - y;
445
446     // sadly, the ability to change the color of a brush didn't arrive until Win2k...
447     HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
448     if (!brush) return;
449     RECT rect = { x, y, x + w, y + h };
450     FillRect((HDC)hdc, &rect, brush);
451     DeleteObject(brush);
452 }
453
454 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
455     BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
456 }
457
458 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
459     hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
460     hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
461     SetBkMode((HDC)hdc, TRANSPARENT);
462     SelectObject((HDC)hdc, (HBITMAP)hbitmap);
463 }
464
465 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
466     clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
467     HRGN hrgn = CreateRectRgn(x, y, x2, y2);
468     SelectClipRgn((HDC)hdc, hrgn);
469     DeleteObject(hrgn);
470 }
471
472 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
473     DeleteObject((void*)hdc);
474     DeleteObject((void*)hbitmap);
475 }
476
477
478
479 // Win32Picture /////////////////////////////////////////////////////////////////////////
480
481 void org::xwt::plat::Win32$Win32Picture::natInit() {
482
483     BITMAPINFO bitmapinfo;
484     memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
485     bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
486     bitmapinfo.bmiHeader.biWidth = w;
487     bitmapinfo.bmiHeader.biHeight = -1 * h;
488     bitmapinfo.bmiHeader.biPlanes = 1;
489     bitmapinfo.bmiHeader.biBitCount = 32;
490     bitmapinfo.bmiHeader.biCompression = BI_RGB;
491
492     hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
493     hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
494     SelectObject((HDC)hdc, (HBITMAP)hbitmap);
495     uint32_t* dat = (uint32_t*)elements(data);
496     for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
497     StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
498
499     jint _copy[min(1024, data->length)];
500     jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
501
502     memcpy(copy, elements(data), data->length * 4);
503     for(int i=0; i<data->length; i++)
504         if ((copy[i] & 0xFF000000) == 0x00000000) {
505             hasmask = 1;
506             copy[i] = 0x00FFFFFF;
507         } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
508             copy[i] = 0x00000000;
509         } else {
510             hasalpha = 1;
511             hasmask = 0;
512             if (data->length > 1024) free(copy);
513             return;
514         }
515
516     if (!hasmask) {
517         if (data->length > 1024) free(copy);
518         return;
519     }
520
521     //    hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
522     hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
523     maskdc = (jint)CreateCompatibleDC(NULL);
524     SelectObject((HDC)maskdc, (HBITMAP)hmask);
525     StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
526     if (data->length > 1024) free(copy);
527 }
528
529
530
531 // Win32Surface /////////////////////////////////////////////////////////////////////////////
532
533 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
534
535     // Ask the message-handling thread to create a window for us
536     PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
537     hwndCreated->block();
538
539     // turn on incremental GC now that we have a user-visible interface
540     // [[this is causing segfaults; enable it later...]]
541     // GC_enable_incremental();
542
543     ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
544     hdc = (jint)GetDC((HWND)hwnd);
545 }
546
547 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
548 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
549 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
550 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
551 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
552 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
553 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
554 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
555
556 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
557     POINT point;
558     RECT rect;
559     point.x = 0;
560     point.y = 0;
561     ClientToScreen((HWND)hwnd, &point);
562     GetWindowRect((HWND)hwnd, &rect);
563     SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
564 }
565
566 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
567     RECT client_rect, window_rect;
568     GetClientRect((HWND)hwnd, &client_rect);
569     GetWindowRect((HWND)hwnd, &window_rect);
570     int addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
571     int addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
572     SetWindowPos((HWND)hwnd, NULL, 0, 0, w + addwidth, h + addheight, SWP_NOZORDER | SWP_NOMOVE);
573 }
574
575 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
576     int len = min(1024, JvGetStringUTFLength(title));
577     char buf[len + 1];
578     buf[len] = '\0';
579     JvGetStringUTFRegion(title, 0, len, buf);
580     SetWindowText((HWND)hwnd, buf);
581 }
582
583 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
584
585     org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
586     int icon_width = GetSystemMetrics(SM_CXSMICON);
587     int icon_height = GetSystemMetrics(SM_CYSMICON);
588
589     // create the bitmap
590     HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
591     HDC memdc = CreateCompatibleDC((HDC)hdc);
592     SelectObject(memdc, bit);
593     BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
594
595     // create the mask
596     jint* dat = elements(p->data);
597     HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
598     SelectObject(memdc, bit_mask);
599     for(int x=0; x<icon_width; x++)
600         for(int y=0; y<icon_height; y++) {
601             int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
602             if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
603             else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
604         }
605
606     // instantiate the icon and assign it to the window class
607     ICONINFO ici;
608     ici.fIcon = 1;
609     ici.hbmMask = bit_mask;
610     ici.hbmColor = bit;
611     HICON hicon = CreateIconIndirect(&ici);
612     HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
613     if (oldicon != NULL) DestroyIcon(oldicon);
614     DeleteObject(memdc);
615 }
616
617 static jstring keyToString(WPARAM wParam);
618 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
619
620     UINT iMsg = (UINT)_iMsg;
621     WPARAM wParam = (WPARAM)_wParam;
622     LPARAM lParam = (LPARAM)_lParam;
623     int oldmousex, oldmousey;
624     MINMAXINFO* mmi;
625     POINT point;
626     HWND hwnd2;
627     RECT rect, rect2;
628     jboolean newinside;
629     int16_t mouse_x;
630     int16_t mouse_y;
631
632     switch(iMsg) {
633     case WM_DEVMODECHANGE: break;    // FEATURE: color depth changed
634     case WM_DISPLAYCHANGE: break;    // FEATURE: screen size changed
635     case WM_FONTCHANGE: break;       // FEATURE: set of fonts changed
636     case WM_MOUSEWHEEL: break;       // FEATURE: Mouse Wheel
637
638     case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
639     case WM_KEYDOWN:
640         KeyPressed(keyToString(wParam));
641         return 0;
642
643     case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
644     case WM_KEYUP:
645         KeyReleased(keyToString(wParam));
646         return 0;
647
648     case WM_SETFOCUS: Focused(true); return 0;
649     case WM_KILLFOCUS: Focused(false); return 0;
650     case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
651     case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
652     case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
653     case WM_LBUTTONDOWN: Press(1); return 0;
654     case WM_RBUTTONDOWN: Press(2); return 0;
655     case WM_MBUTTONDOWN: Press(3); return 0;
656     case WM_CLOSE: Close(); return 0;
657     case WM_ERASEBKGND: return 0;
658
659     case WM_LBUTTONUP:
660     case WM_RBUTTONUP:
661     case WM_MBUTTONUP:
662         Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
663         if (captured && !inside) {
664             ReleaseCapture();
665             SetCursor((HCURSOR)previous_cursor);
666         }
667         return 0;
668
669     case WM_MOVING:
670         GetClientRect((HWND)hwnd, &rect);
671         PosChange(rect.left, rect.top);
672         return 0;
673
674     case WM_SIZE:
675         if (wParam == SIZE_MINIMIZED) {
676             if (maximized) Maximized(false);
677             Minimized(true);
678         } else if (wParam == SIZE_MAXIMIZED) {
679             if (minimized) Minimized(false); 
680             Maximized(true);
681         } else {
682             if (minimized) Minimized(false); 
683             if (maximized) Maximized(false);
684         }
685         // deliberately fall through to WM_SIZING
686
687     case WM_SIZING:
688         GetClientRect((HWND)hwnd, &rect);
689         SizeChange(rect.right - rect.left, rect.bottom - rect.top);
690         return 0;
691
692     case WM_MOUSEMOVE:
693         if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
694
695         GetClientRect((HWND)hwnd, &rect);
696         point.x = mouse_x = lParam & 0xFFFF;
697         point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
698         ClientToScreen((HWND)hwnd, &point);
699         hwnd2 = WindowFromPoint(point);
700
701         newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
702
703         Move(mouse_x, mouse_y);
704
705         if (newinside && !inside) {
706             inside = 1;
707             SetCapture((HWND)hwnd);
708             captured = 1;
709             previous_cursor = (jint)GetCursor();
710             PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
711
712         } else if (!newinside && inside) {
713             inside = 0;
714             if (!button1 && !button2 && !button3) {
715                 ReleaseCapture();
716                 captured = 0;
717                 SetCursor((HCURSOR)previous_cursor);
718             }
719         }
720
721         return 0;
722
723     case WM_USER_SETCURSOR:
724         // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
725         // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
726         // return from WndProc (ie the completion of the processing of some event).  Hence, we use WM_USER to indicate that the screen
727         // cursor should be re-set to "current_cursor".
728         SetCursor((HCURSOR)current_cursor);
729         return 0;
730
731     case WM_USER_DISPOSE:
732         // used to signal that we should destroy ourselves
733         DestroyWindow((HWND)hwnd);
734         return 0;
735
736     case WM_GETMINMAXINFO:
737         mmi = (MINMAXINFO*)lParam;
738         mmi->ptMinTrackSize.x = root->dmin(0);
739         mmi->ptMinTrackSize.y = root->dmin(1);
740         mmi->ptMaxTrackSize.x = root->dmax(0);
741         mmi->ptMaxTrackSize.y = root->dmax(1);
742         return 0;
743         
744     case WM_PAINT: 
745         PAINTSTRUCT ps;
746         BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
747         Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
748         Refresh();
749         EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
750         return 0;
751
752     default: break;
753     }  
754
755     return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
756 }
757
758
759 // Key Translator Helper /////////////////////////////////////////////////////////////////////
760
761 static char keyarr [256] = { 0 };
762 static jstring keyToString(WPARAM wParam) {
763     char arr[4];
764     keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
765     keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
766     keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
767     keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
768     
769     if (ToAscii(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0) == 1) {
770         switch (arr[0]) {
771         case '\t': return JvNewStringLatin1("tab");
772         case 0x1b: return JvNewStringLatin1("escape");
773         case '\n': return JvNewStringLatin1("enter");
774         case '\r': return JvNewStringLatin1("enter");
775         case 0x08: return JvNewStringLatin1("back_space");
776         default: return JvNewStringLatin1(arr, 1);
777         }
778         
779     } else switch (wParam) {
780     case VK_CLEAR: return JvNewStringLatin1("clear");
781     case VK_SHIFT: return JvNewStringLatin1("shift");
782     case VK_CONTROL: return JvNewStringLatin1("control");
783     case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
784     case VK_MENU: return JvNewStringLatin1("alt");
785     case VK_PAUSE: return JvNewStringLatin1("pause");
786     case VK_PRIOR: return JvNewStringLatin1("page_up");
787     case VK_NEXT: return JvNewStringLatin1("page_down");
788     case VK_END: return JvNewStringLatin1("end");
789     case VK_HOME: return JvNewStringLatin1("home");
790     case VK_LEFT: return JvNewStringLatin1("left");
791     case VK_UP: return JvNewStringLatin1("up");
792     case VK_RIGHT: return JvNewStringLatin1("right");
793     case VK_DOWN: return JvNewStringLatin1("down");
794     case VK_INSERT: return JvNewStringLatin1("insert");
795     case VK_DELETE: return JvNewStringLatin1("delete");
796     case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
797     case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
798     case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
799     case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
800     case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
801     case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
802     case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
803     case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
804     case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
805     case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
806     case VK_F1: return JvNewStringLatin1("f1");
807     case VK_F2: return JvNewStringLatin1("f2");
808     case VK_F3: return JvNewStringLatin1("f3");
809     case VK_F4: return JvNewStringLatin1("f4");
810     case VK_F5: return JvNewStringLatin1("f5");
811     case VK_F6: return JvNewStringLatin1("f6");
812     case VK_F7: return JvNewStringLatin1("f7");
813     case VK_F8: return JvNewStringLatin1("f8");
814     case VK_F9: return JvNewStringLatin1("f9");
815     case VK_F10: return JvNewStringLatin1("f10");
816     case VK_F11: return JvNewStringLatin1("f11");
817     case VK_F12: return JvNewStringLatin1("f12");
818     case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
819     case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
820     case VK_LSHIFT: return JvNewStringLatin1("shift");
821     case VK_RSHIFT: return JvNewStringLatin1("shift");
822     case VK_LCONTROL: return JvNewStringLatin1("control");
823     case VK_RCONTROL: return JvNewStringLatin1("control");
824     }
825     return NULL;
826 }
827
828
829
830
831 ///////////////////////////////////////////////////////////////////////////////////////
832 ///////////////////////////////////////////////////////////////////////////////////////
833 ///////////////////////////////////////////////////////////////////////////////////////
834
835 #else /* COMPILE_DLL */
836
837
838 //
839 // A simple DLL to invoke xwt.exe and pass it any arguments found in the <object/> tag
840 //
841
842 #include <windows.h>
843 #include <initguid.h>
844 #include <objbase.h>
845 #include <oaidl.h>
846 #include <oleauto.h>
847 #include <olectl.h>
848
849
850 // Globals ////////////////////////////////////////////////////////////////////////
851
852 using namespace std;
853
854 #define CLSID_STRING_SIZE 39
855
856 const char XWT_friendlyName[] = "XWT ActiveX Control (build " BUILDID ")";
857 const char XWT_versionIndependantProgramID[] = "XWT.ActiveX";
858 const char XWT_programID[] = "XWT.ActiveX (build " BUILDID ")";
859 extern "C" const CLSID XWT_clsid = CLSID_STRUCT;
860 static HMODULE g_hModule = NULL;    //DLL handle
861
862
863
864
865 // Superclasses ////////////////////////////////////////////////////////////////////////
866
867 // Option bit definitions for IObjectSafety:
868 #define INTERFACESAFE_FOR_UNTRUSTED_CALLER  0x00000001  // Caller of interface may be untrusted
869 #define INTERFACESAFE_FOR_UNTRUSTED_DATA    0x00000002  // Data passed into interface may be untrusted
870
871 // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
872 DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);
873
874 interface IObjectSafety : public IUnknown {
875  public:
876     virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) = 0;
877     virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) = 0;
878 };
879
880 interface IShoeHorn : IPersistPropertyBag, IObjectSafety { };
881
882
883
884 // Entry Points ////////////////////////////////////////////////////////////////////////
885
886 // to get mingw to stop nagging me
887 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { }
888
889 // determines whether or not the DLL can be unloaded; always allow this since we don't do too much
890 STDAPI __declspec(dllexport) DllCanUnloadNow(void) { return S_OK; }
891
892 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID /*lpReserved*/) {
893     if (dwReason == DLL_PROCESS_ATTACH) g_hModule = (HINSTANCE)hModule;
894     return TRUE;
895 }
896
897
898
899 // Other ///////////////////////////////////////////////////////////////////////////////////
900
901 // simple assert() replacement that pops open a message box if there are errors
902 void check(int val, char* message) {
903     if (!val) {
904         MessageBox (NULL, message, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
905         exit(-1);
906     }
907 }
908
909 void clsidToString(const CLSID& clsid, char* str, int length) {
910     check(length >= CLSID_STRING_SIZE, "clsidToString(): string too short");
911         LPOLESTR wide_str = NULL;
912         HRESULT hr = StringFromCLSID(clsid, &wide_str);
913         check(SUCCEEDED(hr), "StringFromCLSID() failed in clsidToString()");
914         wcstombs(str, wide_str, length);
915         CoTaskMemFree(wide_str);
916 }
917
918 void setRegistryKey(const char* key, const char* subkey, const char* value) {
919         HKEY hKey;
920         char keyBuf[1024];
921         strcpy(keyBuf, key);
922         if (subkey != NULL) {
923                 strcat(keyBuf, "\\");
924                 strcat(keyBuf, subkey );
925         }
926         long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
927         if (value != NULL)
928         check(RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, strlen(value) + 1) == ERROR_SUCCESS,
929               "RegSetValueEx() failed in setRegistryKey()");
930         RegCloseKey(hKey);
931 }
932
933 void deleteRegistryKey(HKEY parent, const char* target) {
934         HKEY hKeyChild;
935         RegOpenKeyEx(parent, target, 0, KEY_ALL_ACCESS, &hKeyChild);
936
937         // Iterate over children, deleting them
938         FILETIME time;
939         char szBuffer[256];
940         DWORD dwSize = 256;
941         while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) {
942                 deleteRegistryKey(hKeyChild, szBuffer);
943                 dwSize = 256;
944         }
945
946         RegCloseKey(hKeyChild);
947         RegDeleteKey(parent, target);
948 }
949
950 STDAPI __declspec(dllexport) DllRegisterServer(void) {
951         char moduleName[512];
952     HRESULT result = GetModuleFileName(g_hModule, moduleName, sizeof(moduleName)/sizeof(char));
953         check(result, "GetModuleFileName() failed in RegisterServer()");
954
955         char clsidString[CLSID_STRING_SIZE];
956         clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
957
958         // build the key
959         char key[64];
960         strcpy(key, "CLSID\\");
961         strcat(key, clsidString);
962   
963         setRegistryKey(key, NULL, XWT_friendlyName);
964         setRegistryKey(key, "InprocServer32", moduleName);
965         setRegistryKey(key, "ProgID", XWT_programID);
966         setRegistryKey(key, "VersionIndependentProgID", XWT_versionIndependantProgramID);
967         setRegistryKey(XWT_versionIndependantProgramID, NULL, XWT_friendlyName); 
968         setRegistryKey(XWT_versionIndependantProgramID, "CLSID", clsidString);
969         setRegistryKey(XWT_versionIndependantProgramID, "CurVer", XWT_programID);
970         setRegistryKey(XWT_programID, NULL, XWT_friendlyName); 
971         setRegistryKey(XWT_programID, "CLSID", clsidString);
972         return S_OK;
973 }
974
975 STDAPI __declspec(dllexport) DllUnregisterServer(void) {
976         char clsidString[CLSID_STRING_SIZE];
977         clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
978
979         // build the key
980         char key[64];
981         strcpy(key, "CLSID\\");
982         strcat(key, clsidString);
983
984         deleteRegistryKey(HKEY_CLASSES_ROOT, key);
985         deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_versionIndependantProgramID);
986         deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_programID);
987         return S_OK;
988 }
989
990
991
992 // ShoeHorn //////////////////////////////////////////////////////////////////////////////////
993
994 class ShoeHorn : public IShoeHorn {
995     public:
996     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
997         if(iid == IID_IUnknown) *ppv = static_cast<IShoeHorn*>(this);
998         else if(iid == XWT_clsid) *ppv = static_cast<IShoeHorn*>(this);
999         else if(iid == IID_IPersistPropertyBag) *ppv = static_cast<IPersistPropertyBag*>(this);
1000         else if(iid == IID_IObjectSafety) *ppv = static_cast<IObjectSafety*>(this);
1001         else { *ppv = NULL; return E_NOINTERFACE; }
1002         reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1003         return S_OK;
1004     }
1005     virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1006     virtual ULONG __stdcall Release() {
1007         if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; }
1008         return m_cRef;
1009     }
1010     virtual HRESULT __stdcall GetClassID(CLSID*) { return S_OK; }
1011     virtual HRESULT __stdcall InitNew() { return S_OK; }
1012     virtual HRESULT __stdcall Save(IPropertyBag*, int, int) { return S_OK; }
1013     virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions) { return S_OK; }
1014     virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions) {
1015         if (pdwSupportedOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1016         if (pdwEnabledOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1017         return S_OK;
1018     }
1019
1020     virtual HRESULT __stdcall Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) {
1021         VARIANT v;
1022         v.vt = VT_BSTR;
1023         HRESULT hrRead;
1024         
1025         WCHAR wc[100];
1026         char url[100];
1027         
1028         MultiByteToWideChar(CP_ACP, 0, "initial-xwar-url", -1, wc, 100);
1029         pPropBag->Read(wc, &v, pErrorLog);
1030         check(WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, url, 100, NULL, NULL),
1031               "WideCharToMultiByte() failed in ShoeHorn::Load()");
1032         
1033         HKEY hkey;
1034         LONG result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache", &hkey);
1035         check(result == ERROR_SUCCESS, "RegOpenKey() failed in ShoeHorn::Load()");
1036         
1037         // iterate over all the activex cache locations until we find ourselves
1038         for(int i=0; i<9; i++) {
1039             DWORD buflen = 999;
1040             char buf[1000];
1041             VALENT valents[20];
1042             DWORD type;
1043             char which[2];
1044
1045             which[0] = '0' + i;
1046             which[1] = '\0';
1047             result = RegQueryValueEx(hkey, which, NULL, &type, (BYTE*)buf, &buflen);
1048             if (result != ERROR_SUCCESS)
1049                 if (i == 0) {
1050                     check(0, "RegQueryValueEx() failed in ShoeHorn::Load()");
1051                 } else {
1052                     break;
1053                 }
1054             buf[buflen] = '\0';
1055             
1056             char cmdline[200];
1057             for(int i=0; i<200; i++) cmdline[i] = '\0';
1058             strncpy(cmdline, buf, 200);
1059             strncpy(cmdline + strlen(cmdline), "\\xwt-" BUILDID ".exe", 200 - strlen(cmdline));
1060             strncpy(cmdline + strlen(cmdline), " ", 200 - strlen(cmdline));
1061             strncpy(cmdline + strlen(cmdline), url, 200 - strlen(cmdline));
1062             
1063             PROCESS_INFORMATION pInfo;
1064             STARTUPINFO sInfo;
1065             sInfo.cb = sizeof(STARTUPINFO);
1066             sInfo.lpReserved = NULL;
1067             sInfo.lpReserved2 = NULL;
1068             sInfo.cbReserved2 = 0;
1069             sInfo.lpDesktop = NULL;
1070             sInfo.lpTitle = NULL;
1071             sInfo.dwFlags = 0;
1072             sInfo.dwX = 0;
1073             sInfo.dwY = 0;
1074             sInfo.dwFillAttribute = 0;
1075             sInfo.wShowWindow = SW_SHOW;
1076             BOOL b = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo);
1077             if (b) return S_OK;
1078         }
1079
1080         check(0, "unable to locate xwt-" BUILDID ".exe in ActiveX cache folders");
1081     }
1082
1083     ShoeHorn() : m_cRef(1) { };
1084     ~ShoeHorn() { };
1085     private: long m_cRef;
1086 };
1087
1088
1089
1090
1091 // ClassFactory //////////////////////////////////////////////////////////////////////////
1092
1093 class ClassFactory : public IClassFactory {
1094     public:
1095     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
1096         if(iid == IID_IUnknown) *ppv = static_cast<IClassFactory*>(this);
1097         else if(iid == IID_IClassFactory) *ppv = static_cast<IClassFactory*>(this);
1098         else {
1099             *ppv = NULL;
1100             return E_NOINTERFACE;
1101         }
1102         reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1103         return S_OK;
1104     }
1105
1106     ClassFactory() : m_cRef(1) { }
1107     ~ClassFactory() { }
1108     virtual HRESULT __stdcall LockServer(BOOL bLock) { return S_OK; }
1109     virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1110     virtual ULONG __stdcall Release() {
1111         if(InterlockedDecrement(&m_cRef) == 0) {
1112             delete this;
1113             return 0;
1114         }
1115         return m_cRef;
1116     }
1117
1118     virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
1119         if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
1120         ShoeHorn* s = new ShoeHorn;
1121         if(s == NULL) return E_OUTOFMEMORY;
1122         HRESULT hr = s->QueryInterface(iid, ppv);
1123         s->Release();
1124         return hr;
1125     }
1126     
1127     private: long m_cRef;
1128 };
1129
1130
1131 extern "C" __stdcall HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) {
1132     if(clsid != XWT_clsid) return CLASS_E_CLASSNOTAVAILABLE;
1133     ClassFactory* pFactory = new ClassFactory; 
1134     if(pFactory == NULL) return E_OUTOFMEMORY;
1135     HRESULT hr = pFactory->QueryInterface(iid, ppv);
1136     pFactory->Release();
1137     return hr;
1138 }
1139
1140 #endif