1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
3 // kinda ugly; we use -DCOMPILE_DLL to combine two .cc files into one
6 // this has to precede the others so we don't get collisions on min/max
7 #include <org/xwt/Box.h>
22 #include <java/lang/Integer.h>
23 #include <java/util/Hashtable.h>
24 #include <org/xwt/Box.h>
25 #include <org/xwt/Surface.h>
26 #include <org/xwt/DoubleBuffer.h>
27 #include <org/xwt/Picture.h>
28 #include <org/xwt/Platform.h>
29 #include <org/xwt/Platform$ParsedFont.h>
30 #include <org/xwt/plat/Win32.h>
31 #include <org/xwt/plat/Win32$Win32Font.h>
32 #include <org/xwt/plat/Win32$Win32Surface.h>
33 #include <org/xwt/plat/Win32$Win32DoubleBuffer.h>
34 #include <org/xwt/plat/Win32$Win32Picture.h>
35 #include <org/xwt/util/Semaphore.h>
38 #include <java/lang/System.h>
39 #include <java/io/PrintStream.h>
41 #define WM_USER_SETCURSOR WM_USER
42 #define WM_USER_DISPOSE (WM_USER + 1)
43 #define WM_USER_CREATEWINDOW (WM_USER + 2)
44 #define WS_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
46 // FEATURE: there are lots of places where HANDLE's get casted to jint's -- this will break on Win64
47 // a clean way to do this would be to '#define jraw (gnu::gcj::RawData*)'
49 // Callbacks ////////////////////////////////////////////////////////////////////
51 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
52 org::xwt::plat::Win32$Win32Surface* surface =
53 (org::xwt::plat::Win32$Win32Surface*)org::xwt::plat::Win32::hwndToWin32SurfaceMap->get(new java::lang::Integer((jint)hwnd));
55 if (surface != NULL) {
56 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
59 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
60 return DefWindowProc(hwnd, iMsg, wParam, lParam);
64 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
65 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
69 lf.lfCharSet = ANSI_CHARSET;
70 strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
71 lf.lfPitchAndFamily = 0;
72 EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
75 org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
76 ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
77 tm->tmItalic == 0 ? 0 : 1,
78 tm->tmWeight <= 400 ? 0 : 1);
84 // Initialization ////////////////////////////////////////////////////////////////////
86 static int window_class_counter = 0;
88 jstring org::xwt::plat::Win32::getTempPath() {
90 DWORD ret = GetTempPath(1024, buf);
91 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
92 return JvNewStringLatin1(buf);
95 // XOR mask for the hand cursor
96 static unsigned char hand_cursor_xor[32 * 4] = {
97 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x0C, 0x00, 0x00,
99 0x00, 0x0C, 0x00, 0x00,
100 0x00, 0x0C, 0x00, 0x00,
101 0x00, 0x0C, 0x00, 0x00,
102 0x00, 0x0C, 0x00, 0x00,
103 0x00, 0x0D, 0x80, 0x00,
104 0x00, 0x0D, 0xB0, 0x00,
105 0x00, 0x0D, 0xB4, 0x00,
106 0x00, 0x0D, 0xB6, 0x00,
107 0x00, 0xCF, 0xF6, 0x00,
108 0x00, 0xEF, 0xFE, 0x00,
109 0x00, 0x6F, 0xFE, 0x00,
110 0x00, 0x2F, 0xFE, 0x00,
111 0x00, 0x3F, 0xFE, 0x00,
112 0x00, 0x1F, 0xFE, 0x00,
113 0x00, 0x1F, 0xFC, 0x00,
114 0x00, 0x0F, 0xFC, 0x00,
115 0x00, 0x0F, 0xFC, 0x00,
116 0x00, 0x07, 0xF8, 0x00,
117 0x00, 0x07, 0xF8, 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 0x00, 0x00, 0x00, 0x00
131 // AND mask for the hand cursor
132 static unsigned char hand_cursor_and[32 * 4] = {
133 0xFF, 0xF3, 0xFF, 0xFF,
134 0xFF, 0xE1, 0xFF, 0xFF,
135 0xFF, 0xE1, 0xFF, 0xFF,
136 0xFF, 0xE1, 0xFF, 0xFF,
137 0xFF, 0xE1, 0xFF, 0xFF,
138 0xFF, 0xE0, 0x7F, 0xFF,
139 0xFF, 0xE0, 0x0F, 0xFF,
140 0xFF, 0xE0, 0x03, 0xFF,
141 0xFF, 0xE0, 0x01, 0xFF,
142 0xFF, 0x20, 0x00, 0xFF,
143 0xFE, 0x00, 0x00, 0xFF,
144 0xFE, 0x00, 0x00, 0xFF,
145 0xFF, 0x00, 0x00, 0xFF,
146 0xFF, 0x80, 0x00, 0xFF,
147 0xFF, 0x80, 0x00, 0xFF,
148 0xFF, 0xC0, 0x00, 0xFF,
149 0xFF, 0xC0, 0x01, 0xFF,
150 0xFF, 0xE0, 0x01, 0xFF,
151 0xFF, 0xE0, 0x01, 0xFF,
152 0xFF, 0xF0, 0x03, 0xFF,
153 0xFF, 0xF0, 0x03, 0xFF,
154 0xFF, 0xF0, 0x03, 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 0xFF, 0xFF, 0xFF, 0xFF
168 void org::xwt::plat::Win32::natInit() {
170 // grab desktop dc/handle
171 desktop_handle = (jint)GetDesktopWindow();
172 desktop_dc = (jint)GetDC((HWND)desktop_handle);
175 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
176 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
177 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
178 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
179 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
180 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
181 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
182 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
183 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
184 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
188 lf.lfCharSet = ANSI_CHARSET;
189 lf.lfFaceName[0] = 0;
190 lf.lfPitchAndFamily = 0;
191 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
193 messagePumpThread = (jint)GetCurrentThreadId();
194 messagePumpStarted->release();
197 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
199 if (msg.message == WM_USER_CREATEWINDOW) {
200 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
202 // we must create a unique window class name for each
203 // window so that minimization icons can be set independantly
205 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
208 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
209 wc.lpfnWndProc = WndProc;
211 wc.cbSize = sizeof(WNDCLASSEX);
213 wc.hInstance = GetModuleHandle(NULL);
217 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
218 wc.lpszMenuName = NULL;
219 wc.lpszClassName = buf;
220 RegisterClassEx(&wc);
222 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
223 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
224 SetFocus((HWND)surface->hwnd);
225 surface->hwndCreated->release();
228 TranslateMessage(&msg);
229 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
230 DispatchMessage(&msg);
234 java::lang::System::exit(-1);
238 // Platform Methods ///////////////////////////////////////////////////////////////////
240 void org::xwt::plat::Win32::__detectProxy(JArray<jstring>* container) {
246 LONG result = RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
247 if (result != ERROR_SUCCESS) return;
252 result = RegQueryValueEx(hkey, "AutoConfigURL", NULL, &type, (LPBYTE)buf, &buflen);
254 if (result == ERROR_SUCCESS) elements(container)[2] = JvNewStringLatin1(buf);
258 RegQueryValueEx(hkey, "ProxyEnable", NULL, &type, (LPBYTE)buf, &buflen);
259 if (buf[0] != 1) return;
264 RegQueryValueEx(hkey, "ProxyServer", NULL, &type, (LPBYTE)buf, &buflen);
266 elements(container)[0] = JvNewStringLatin1(buf);
270 RegQueryValueEx(hkey, "ProxyOverride", NULL, &type, (LPBYTE)buf, &buflen);
272 elements(container)[1] = JvNewStringLatin1(buf);
275 jstring org::xwt::plat::Win32::_getClipBoard() {
276 OpenClipboard((HWND)desktop_handle);
277 HGLOBAL hmem = GetClipboardData(CF_TEXT);
278 if (hmem == NULL) return NULL;
279 char* buf = (char*)GlobalLock(hmem);
280 if (buf == NULL) return NULL;
281 jstring ret = JvNewStringLatin1(buf);
287 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
288 OpenClipboard((HWND)desktop_handle);
289 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
290 if (hmem == NULL) return;
291 char* buf = (char*)GlobalLock(hmem);
292 if (buf == NULL) return;
293 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
294 buf[JvGetStringUTFLength(s)] = '\0';
296 SetClipboardData(CF_TEXT, hmem);
300 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
301 char buf[JvGetStringUTFLength(message) + 1];
302 buf[JvGetStringUTFLength(message)] = '\0';
303 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
304 MessageBox (NULL, buf, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
305 java::lang::System::exit(-1);
308 jint org::xwt::plat::Win32::_getScreenWidth() {
310 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
311 return rect.right - rect.left;
314 jint org::xwt::plat::Win32::_getScreenHeight() {
316 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
317 return rect.bottom - rect.top;
320 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
321 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
323 memset(&logfont, 0, sizeof(LOGFONT));
324 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
325 if (pf->italic) logfont.lfItalic = 1;
326 if (pf->bold) logfont.lfWeight = FW_BOLD;
327 logfont.lfCharSet = ANSI_CHARSET;
329 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
330 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
332 ret->hfont = (jint)CreateFontIndirect(&logfont);
333 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
336 GetTextMetrics((HDC)desktop_dc, &tm);
338 p.x = 0; p.y = tm.tmAscent;
339 LPtoDP((HDC)desktop_dc, &p, 1);
340 ret->maxAscent = p.y;
342 p.x = 0; p.y = tm.tmDescent;
343 LPtoDP((HDC)desktop_dc, &p, 1);
344 ret->maxDescent = p.y;
349 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
351 HFONT hfont = (HFONT)(getFont(font)->hfont);
352 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
354 int len = min(1024, JvGetStringUTFLength(text));
357 JvGetStringUTFRegion(text, 0, len, buf);
360 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
364 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
366 int len = min(2048, JvGetStringUTFLength(url));
368 JvGetStringUTFRegion(url, 0, len, buf);
372 memset(&ei, 0, sizeof(ei));
373 ei.cbSize = sizeof(ei);
376 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
377 ei.nShow = SW_SHOWDEFAULT;
378 return (ShellExecuteEx(&ei) == 0);
383 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
385 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
386 // Since all drawing operations are single-threaded, it's safe to use a global here.
387 static HBITMAP scratch = NULL;
388 static HDC scratch_dc = NULL;
389 static jint* scratch_bits = NULL;
390 static jint scratch_w = 0;
391 static jint scratch_h = 0;
393 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
394 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
395 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
397 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
399 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
400 jint dx1, jint dy1, jint dx2, jint dy2,
401 jint sx1, jint sy1, jint sx2, jint sy2) {
403 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
405 if (source->hasalpha) {
407 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
408 if (scratch_dc != NULL) DeleteDC(scratch_dc);
409 if (scratch != NULL) DeleteObject(scratch);
410 scratch_w = max(dx2 - dx1, scratch_w);
411 scratch_h = max(dy2 - dy1, scratch_h);
413 BITMAPINFO bitmapinfo;
414 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
415 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
416 bitmapinfo.bmiHeader.biWidth = scratch_w;
417 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
418 bitmapinfo.bmiHeader.biPlanes = 1;
419 bitmapinfo.bmiHeader.biBitCount = 32;
420 bitmapinfo.bmiHeader.biCompression = BI_RGB;
422 // create section DIB
423 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
424 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
425 SelectObject(scratch_dc, scratch);
428 // copy from screen to scratch
429 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
431 // apply alpha-blending to scratch
432 jint* dat = elements(source->data);
434 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
435 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
436 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
437 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
438 jint dst = scratch_bits[y * scratch_w + x];
439 jint src = dat[sy * source->getWidth() + sx];
440 jint alpha = (src & 0xFF000000) >> 24;
441 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
442 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
443 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
444 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
447 // copy back from scratch to screen
448 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
451 if (source->hasmask) {
452 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
453 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
455 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
462 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
464 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
465 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
467 // Platform API passes us the y-pos of the bottom of the text; we need the top
470 int len = min(1024, JvGetStringUTFLength(text));
473 JvGetStringUTFRegion(text, 0, len, buf);
475 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
476 TextOut((HDC)hdc, x, y, buf, len);
479 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
483 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
484 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
486 RECT rect = { x, y, x + w, y + h };
487 FillRect((HDC)hdc, &rect, brush);
491 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
492 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
495 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
496 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
497 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
498 SetBkMode((HDC)hdc, TRANSPARENT);
499 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
502 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
503 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
504 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
505 SelectClipRgn((HDC)hdc, hrgn);
509 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
510 DeleteObject((void*)hdc);
511 DeleteObject((void*)hbitmap);
516 // Win32Picture /////////////////////////////////////////////////////////////////////////
518 void org::xwt::plat::Win32$Win32Picture::natInit() {
520 BITMAPINFO bitmapinfo;
521 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
522 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
523 bitmapinfo.bmiHeader.biWidth = w;
524 bitmapinfo.bmiHeader.biHeight = -1 * h;
525 bitmapinfo.bmiHeader.biPlanes = 1;
526 bitmapinfo.bmiHeader.biBitCount = 32;
527 bitmapinfo.bmiHeader.biCompression = BI_RGB;
529 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
530 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
531 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
532 uint32_t* dat = (uint32_t*)elements(data);
533 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
534 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
536 jint _copy[min(1024, data->length)];
537 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
539 memcpy(copy, elements(data), data->length * 4);
540 for(int i=0; i<data->length; i++)
541 if ((copy[i] & 0xFF000000) == 0x00000000) {
543 copy[i] = 0x00FFFFFF;
544 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
545 copy[i] = 0x00000000;
549 if (data->length > 1024) free(copy);
554 if (data->length > 1024) free(copy);
558 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
559 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
560 maskdc = (jint)CreateCompatibleDC(NULL);
561 SelectObject((HDC)maskdc, (HBITMAP)hmask);
562 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
563 if (data->length > 1024) free(copy);
568 // Win32Surface /////////////////////////////////////////////////////////////////////////////
570 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
572 // Ask the message-handling thread to create a window for us
573 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
574 hwndCreated->block();
576 // turn on incremental GC now that we have a user-visible interface
577 // [[this is causing segfaults; enable it later...]]
578 // GC_enable_incremental();
580 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
581 hdc = (jint)GetDC((HWND)hwnd);
584 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
585 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
586 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
587 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
588 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
589 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
590 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
591 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
593 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
598 ClientToScreen((HWND)hwnd, &point);
599 GetWindowRect((HWND)hwnd, &rect);
600 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
603 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
604 RECT client_rect, window_rect;
605 GetClientRect((HWND)hwnd, &client_rect);
606 GetWindowRect((HWND)hwnd, &window_rect);
607 int addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
608 int addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
609 SetWindowPos((HWND)hwnd, NULL, 0, 0, w + addwidth, h + addheight, SWP_NOZORDER | SWP_NOMOVE);
612 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
613 int len = min(1024, JvGetStringUTFLength(title));
616 JvGetStringUTFRegion(title, 0, len, buf);
617 SetWindowText((HWND)hwnd, buf);
620 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
622 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
623 int icon_width = GetSystemMetrics(SM_CXSMICON);
624 int icon_height = GetSystemMetrics(SM_CYSMICON);
627 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
628 HDC memdc = CreateCompatibleDC((HDC)hdc);
629 SelectObject(memdc, bit);
630 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
633 jint* dat = elements(p->data);
634 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
635 SelectObject(memdc, bit_mask);
636 for(int x=0; x<icon_width; x++)
637 for(int y=0; y<icon_height; y++) {
638 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
639 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
640 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
643 // instantiate the icon and assign it to the window class
646 ici.hbmMask = bit_mask;
648 HICON hicon = CreateIconIndirect(&ici);
649 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
650 if (oldicon != NULL) DestroyIcon(oldicon);
654 static jstring keyToString(WPARAM wParam);
655 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
657 UINT iMsg = (UINT)_iMsg;
658 WPARAM wParam = (WPARAM)_wParam;
659 LPARAM lParam = (LPARAM)_lParam;
661 int oldmousex, oldmousey;
671 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
672 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
673 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
674 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
676 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
678 KeyPressed(keyToString(wParam));
681 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
683 KeyReleased(keyToString(wParam));
686 case WM_SETFOCUS: Focused(true); return 0;
687 case WM_KILLFOCUS: Focused(false); return 0;
688 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
689 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
690 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
691 case WM_LBUTTONDOWN: Press(1); return 0;
692 case WM_RBUTTONDOWN: Press(2); return 0;
693 case WM_MBUTTONDOWN: Press(3); return 0;
694 case WM_CLOSE: Close(); return 0;
695 case WM_ERASEBKGND: return 0;
700 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
701 if (captured && !inside) {
703 SetCursor((HCURSOR)previous_cursor);
708 GetClientRect((HWND)hwnd, &rect);
709 PosChange(rect.left, rect.top);
713 if (wParam == SIZE_MINIMIZED) {
714 if (maximized) Maximized(false);
716 } else if (wParam == SIZE_MAXIMIZED) {
717 if (minimized) Minimized(false);
720 if (minimized) Minimized(false);
721 if (maximized) Maximized(false);
723 // deliberately fall through to WM_SIZING
726 GetClientRect((HWND)hwnd, &rect);
727 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
731 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
733 GetClientRect((HWND)hwnd, &rect);
734 point.x = mouse_x = lParam & 0xFFFF;
735 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
736 ClientToScreen((HWND)hwnd, &point);
737 hwnd2 = WindowFromPoint(point);
739 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
741 Move(mouse_x, mouse_y);
743 if (newinside && !inside) {
745 SetCapture((HWND)hwnd);
747 previous_cursor = (jint)GetCursor();
748 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
750 } else if (!newinside && inside) {
752 if (!button1 && !button2 && !button3) {
755 SetCursor((HCURSOR)previous_cursor);
761 case WM_USER_SETCURSOR:
762 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
763 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
764 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
765 // cursor should be re-set to "current_cursor".
766 SetCursor((HCURSOR)current_cursor);
769 case WM_USER_DISPOSE:
770 // used to signal that we should destroy ourselves
771 DestroyWindow((HWND)hwnd);
774 case WM_GETMINMAXINFO:
775 mmi = (MINMAXINFO*)lParam;
776 mmi->ptMinTrackSize.x = root->dmin(0);
777 mmi->ptMinTrackSize.y = root->dmin(1);
778 mmi->ptMaxTrackSize.x = root->dmax(0);
779 mmi->ptMaxTrackSize.y = root->dmax(1);
784 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
785 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
786 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
792 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
796 // Key Translator Helper /////////////////////////////////////////////////////////////////////
798 static char keyarr [256] = { 0 };
799 static jstring keyToString(WPARAM wParam) {
801 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
802 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
803 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
804 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
806 if (ToAscii(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0) == 1) {
808 case '\t': return JvNewStringLatin1("tab");
809 case 0x1b: return JvNewStringLatin1("escape");
810 case '\n': return JvNewStringLatin1("enter");
811 case '\r': return JvNewStringLatin1("enter");
812 case 0x08: return JvNewStringLatin1("back_space");
813 default: return JvNewStringLatin1(arr, 1);
816 } else switch (wParam) {
817 case VK_CLEAR: return JvNewStringLatin1("clear");
818 case VK_SHIFT: return JvNewStringLatin1("shift");
819 case VK_CONTROL: return JvNewStringLatin1("control");
820 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
821 case VK_MENU: return JvNewStringLatin1("alt");
822 case VK_PAUSE: return JvNewStringLatin1("pause");
823 case VK_PRIOR: return JvNewStringLatin1("page_up");
824 case VK_NEXT: return JvNewStringLatin1("page_down");
825 case VK_END: return JvNewStringLatin1("end");
826 case VK_HOME: return JvNewStringLatin1("home");
827 case VK_LEFT: return JvNewStringLatin1("left");
828 case VK_UP: return JvNewStringLatin1("up");
829 case VK_RIGHT: return JvNewStringLatin1("right");
830 case VK_DOWN: return JvNewStringLatin1("down");
831 case VK_INSERT: return JvNewStringLatin1("insert");
832 case VK_DELETE: return JvNewStringLatin1("delete");
833 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
834 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
835 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
836 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
837 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
838 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
839 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
840 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
841 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
842 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
843 case VK_F1: return JvNewStringLatin1("f1");
844 case VK_F2: return JvNewStringLatin1("f2");
845 case VK_F3: return JvNewStringLatin1("f3");
846 case VK_F4: return JvNewStringLatin1("f4");
847 case VK_F5: return JvNewStringLatin1("f5");
848 case VK_F6: return JvNewStringLatin1("f6");
849 case VK_F7: return JvNewStringLatin1("f7");
850 case VK_F8: return JvNewStringLatin1("f8");
851 case VK_F9: return JvNewStringLatin1("f9");
852 case VK_F10: return JvNewStringLatin1("f10");
853 case VK_F11: return JvNewStringLatin1("f11");
854 case VK_F12: return JvNewStringLatin1("f12");
855 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
856 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
857 case VK_LSHIFT: return JvNewStringLatin1("shift");
858 case VK_RSHIFT: return JvNewStringLatin1("shift");
859 case VK_LCONTROL: return JvNewStringLatin1("control");
860 case VK_RCONTROL: return JvNewStringLatin1("control");
868 ///////////////////////////////////////////////////////////////////////////////////////
869 ///////////////////////////////////////////////////////////////////////////////////////
870 ///////////////////////////////////////////////////////////////////////////////////////
872 #else /* COMPILE_DLL */
876 // A simple DLL to invoke xwt.exe and pass it any arguments found in the <object/> tag
880 #include <initguid.h>
887 // Globals ////////////////////////////////////////////////////////////////////////
891 #define CLSID_STRING_SIZE 39
893 const char XWT_friendlyName[] = "XWT ActiveX Control (build " BUILDID ")";
894 const char XWT_versionIndependantProgramID[] = "XWT.ActiveX";
895 const char XWT_programID[] = "XWT.ActiveX (build " BUILDID ")";
896 extern "C" const CLSID XWT_clsid = CLSID_STRUCT;
897 static HMODULE g_hModule = NULL; //DLL handle
902 // Superclasses ////////////////////////////////////////////////////////////////////////
904 // Option bit definitions for IObjectSafety:
905 #define INTERFACESAFE_FOR_UNTRUSTED_CALLER 0x00000001 // Caller of interface may be untrusted
906 #define INTERFACESAFE_FOR_UNTRUSTED_DATA 0x00000002 // Data passed into interface may be untrusted
908 // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
909 DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);
911 interface IObjectSafety : public IUnknown {
913 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) = 0;
914 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) = 0;
917 interface IShoeHorn : IPersistPropertyBag, IObjectSafety { };
921 // Entry Points ////////////////////////////////////////////////////////////////////////
923 // to get mingw to stop nagging me
924 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { }
926 // determines whether or not the DLL can be unloaded; always allow this since we don't do too much
927 STDAPI __declspec(dllexport) DllCanUnloadNow(void) { return S_OK; }
929 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID /*lpReserved*/) {
930 if (dwReason == DLL_PROCESS_ATTACH) g_hModule = (HINSTANCE)hModule;
936 // Other ///////////////////////////////////////////////////////////////////////////////////
938 // simple assert() replacement that pops open a message box if there are errors
939 void check(int val, char* message) {
941 MessageBox (NULL, message, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
946 void clsidToString(const CLSID& clsid, char* str, int length) {
947 check(length >= CLSID_STRING_SIZE, "clsidToString(): string too short");
948 LPOLESTR wide_str = NULL;
949 HRESULT hr = StringFromCLSID(clsid, &wide_str);
950 check(SUCCEEDED(hr), "StringFromCLSID() failed in clsidToString()");
951 wcstombs(str, wide_str, length);
952 CoTaskMemFree(wide_str);
955 void setRegistryKey(const char* key, const char* subkey, const char* value) {
959 if (subkey != NULL) {
960 strcat(keyBuf, "\\");
961 strcat(keyBuf, subkey );
963 long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
965 check(RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, strlen(value) + 1) == ERROR_SUCCESS,
966 "RegSetValueEx() failed in setRegistryKey()");
970 void deleteRegistryKey(HKEY parent, const char* target) {
972 RegOpenKeyEx(parent, target, 0, KEY_ALL_ACCESS, &hKeyChild);
974 // Iterate over children, deleting them
978 while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) {
979 deleteRegistryKey(hKeyChild, szBuffer);
983 RegCloseKey(hKeyChild);
984 RegDeleteKey(parent, target);
987 STDAPI __declspec(dllexport) DllRegisterServer(void) {
988 char moduleName[512];
989 HRESULT result = GetModuleFileName(g_hModule, moduleName, sizeof(moduleName)/sizeof(char));
990 check(result, "GetModuleFileName() failed in RegisterServer()");
992 char clsidString[CLSID_STRING_SIZE];
993 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
997 strcpy(key, "CLSID\\");
998 strcat(key, clsidString);
1000 setRegistryKey(key, NULL, XWT_friendlyName);
1001 setRegistryKey(key, "InprocServer32", moduleName);
1002 setRegistryKey(key, "ProgID", XWT_programID);
1003 setRegistryKey(key, "VersionIndependentProgID", XWT_versionIndependantProgramID);
1004 setRegistryKey(XWT_versionIndependantProgramID, NULL, XWT_friendlyName);
1005 setRegistryKey(XWT_versionIndependantProgramID, "CLSID", clsidString);
1006 setRegistryKey(XWT_versionIndependantProgramID, "CurVer", XWT_programID);
1007 setRegistryKey(XWT_programID, NULL, XWT_friendlyName);
1008 setRegistryKey(XWT_programID, "CLSID", clsidString);
1012 STDAPI __declspec(dllexport) DllUnregisterServer(void) {
1013 char clsidString[CLSID_STRING_SIZE];
1014 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
1018 strcpy(key, "CLSID\\");
1019 strcat(key, clsidString);
1021 deleteRegistryKey(HKEY_CLASSES_ROOT, key);
1022 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_versionIndependantProgramID);
1023 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_programID);
1029 // ShoeHorn //////////////////////////////////////////////////////////////////////////////////
1031 class ShoeHorn : public IShoeHorn {
1033 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
1034 if(iid == IID_IUnknown) *ppv = static_cast<IShoeHorn*>(this);
1035 else if(iid == XWT_clsid) *ppv = static_cast<IShoeHorn*>(this);
1036 else if(iid == IID_IPersistPropertyBag) *ppv = static_cast<IPersistPropertyBag*>(this);
1037 else if(iid == IID_IObjectSafety) *ppv = static_cast<IObjectSafety*>(this);
1038 else { *ppv = NULL; return E_NOINTERFACE; }
1039 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1042 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1043 virtual ULONG __stdcall Release() {
1044 if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; }
1047 virtual HRESULT __stdcall GetClassID(CLSID*) { return S_OK; }
1048 virtual HRESULT __stdcall InitNew() { return S_OK; }
1049 virtual HRESULT __stdcall Save(IPropertyBag*, int, int) { return S_OK; }
1050 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions) { return S_OK; }
1051 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions) {
1052 if (pdwSupportedOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1053 if (pdwEnabledOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1057 virtual HRESULT __stdcall Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) {
1065 MultiByteToWideChar(CP_ACP, 0, "initial-xwar-url", -1, wc, 100);
1066 pPropBag->Read(wc, &v, pErrorLog);
1067 check(WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, url, 100, NULL, NULL),
1068 "WideCharToMultiByte() failed in ShoeHorn::Load()");
1071 LONG result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache", &hkey);
1072 check(result == ERROR_SUCCESS, "RegOpenKey() failed in ShoeHorn::Load()");
1074 // iterate over all the activex cache locations until we find ourselves
1075 for(int i=0; i<9; i++) {
1084 result = RegQueryValueEx(hkey, which, NULL, &type, (BYTE*)buf, &buflen);
1085 if (result != ERROR_SUCCESS)
1087 check(0, "RegQueryValueEx() failed in ShoeHorn::Load()");
1094 for(int i=0; i<200; i++) cmdline[i] = '\0';
1095 strncpy(cmdline, buf, 200);
1096 strncpy(cmdline + strlen(cmdline), "\\xwt-" BUILDID ".exe", 200 - strlen(cmdline));
1097 strncpy(cmdline + strlen(cmdline), " ", 200 - strlen(cmdline));
1098 strncpy(cmdline + strlen(cmdline), url, 200 - strlen(cmdline));
1100 PROCESS_INFORMATION pInfo;
1102 sInfo.cb = sizeof(STARTUPINFO);
1103 sInfo.lpReserved = NULL;
1104 sInfo.lpReserved2 = NULL;
1105 sInfo.cbReserved2 = 0;
1106 sInfo.lpDesktop = NULL;
1107 sInfo.lpTitle = NULL;
1111 sInfo.dwFillAttribute = 0;
1112 sInfo.wShowWindow = SW_SHOW;
1113 BOOL b = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo);
1117 check(0, "unable to locate xwt-" BUILDID ".exe in ActiveX cache folders");
1120 ShoeHorn() : m_cRef(1) { };
1122 private: long m_cRef;
1128 // ClassFactory //////////////////////////////////////////////////////////////////////////
1130 class ClassFactory : public IClassFactory {
1132 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
1133 if(iid == IID_IUnknown) *ppv = static_cast<IClassFactory*>(this);
1134 else if(iid == IID_IClassFactory) *ppv = static_cast<IClassFactory*>(this);
1137 return E_NOINTERFACE;
1139 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1143 ClassFactory() : m_cRef(1) { }
1145 virtual HRESULT __stdcall LockServer(BOOL bLock) { return S_OK; }
1146 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1147 virtual ULONG __stdcall Release() {
1148 if(InterlockedDecrement(&m_cRef) == 0) {
1155 virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
1156 if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
1157 ShoeHorn* s = new ShoeHorn;
1158 if(s == NULL) return E_OUTOFMEMORY;
1159 HRESULT hr = s->QueryInterface(iid, ppv);
1164 private: long m_cRef;
1168 extern "C" __stdcall HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) {
1169 if(clsid != XWT_clsid) return CLASS_E_CLASSNOTAVAILABLE;
1170 ClassFactory* pFactory = new ClassFactory;
1171 if(pFactory == NULL) return E_OUTOFMEMORY;
1172 HRESULT hr = pFactory->QueryInterface(iid, ppv);
1173 pFactory->Release();