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>
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>
35 #include <java/lang/System.h>
36 #include <java/io/PrintStream.h>
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)
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*)'
46 // Callbacks ////////////////////////////////////////////////////////////////////
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));
52 if (surface != NULL) {
53 return (LRESULT)surface->WndProc((jint)hwnd, (jint)iMsg, (jint)wParam, (jint)lParam);
56 // this is really lame -- Win32 insists on being able to call your WndProc BEFORE CreateWindow returns...
57 return DefWindowProc(hwnd, iMsg, wParam, lParam);
61 // This function iterates over each family (lparam == 0), and then over each size (lparam == 1)
62 int CALLBACK fontproc(const LOGFONTA* enumlogfont, const TEXTMETRICA* tm, long unsigned int type, LPARAM lparam) {
66 lf.lfCharSet = ANSI_CHARSET;
67 strncpy(lf.lfFaceName, enumlogfont->lfFaceName, 32);
68 lf.lfPitchAndFamily = 0;
69 EnumFontFamiliesEx((HDC)org::xwt::plat::Win32::desktop_dc, &lf, fontproc, 1, 0);
72 org::xwt::plat::Win32::addFont(JvNewStringLatin1(enumlogfont->lfFaceName),
73 ((type & RASTER_FONTTYPE) == 0) ? 0 : tm->tmHeight,
74 tm->tmItalic == 0 ? 0 : 1,
75 tm->tmWeight <= 400 ? 0 : 1);
81 // Initialization ////////////////////////////////////////////////////////////////////
83 static int window_class_counter = 0;
85 jstring org::xwt::plat::Win32::getTempPath() {
87 DWORD ret = GetTempPath(1024, buf);
88 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
89 return JvNewStringLatin1(buf);
92 // XOR mask for the hand cursor
93 static unsigned char hand_cursor_xor[32 * 4] = {
94 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x0C, 0x00, 0x00,
96 0x00, 0x0C, 0x00, 0x00,
97 0x00, 0x0C, 0x00, 0x00,
98 0x00, 0x0C, 0x00, 0x00,
99 0x00, 0x0C, 0x00, 0x00,
100 0x00, 0x0D, 0x80, 0x00,
101 0x00, 0x0D, 0xB0, 0x00,
102 0x00, 0x0D, 0xB4, 0x00,
103 0x00, 0x0D, 0xB6, 0x00,
104 0x00, 0xCF, 0xF6, 0x00,
105 0x00, 0xEF, 0xFE, 0x00,
106 0x00, 0x6F, 0xFE, 0x00,
107 0x00, 0x2F, 0xFE, 0x00,
108 0x00, 0x3F, 0xFE, 0x00,
109 0x00, 0x1F, 0xFE, 0x00,
110 0x00, 0x1F, 0xFC, 0x00,
111 0x00, 0x0F, 0xFC, 0x00,
112 0x00, 0x0F, 0xFC, 0x00,
113 0x00, 0x07, 0xF8, 0x00,
114 0x00, 0x07, 0xF8, 0x00,
115 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 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
128 // AND mask for the hand cursor
129 static unsigned char hand_cursor_and[32 * 4] = {
130 0xFF, 0xF3, 0xFF, 0xFF,
131 0xFF, 0xE1, 0xFF, 0xFF,
132 0xFF, 0xE1, 0xFF, 0xFF,
133 0xFF, 0xE1, 0xFF, 0xFF,
134 0xFF, 0xE1, 0xFF, 0xFF,
135 0xFF, 0xE0, 0x7F, 0xFF,
136 0xFF, 0xE0, 0x0F, 0xFF,
137 0xFF, 0xE0, 0x03, 0xFF,
138 0xFF, 0xE0, 0x01, 0xFF,
139 0xFF, 0x20, 0x00, 0xFF,
140 0xFE, 0x00, 0x00, 0xFF,
141 0xFE, 0x00, 0x00, 0xFF,
142 0xFF, 0x00, 0x00, 0xFF,
143 0xFF, 0x80, 0x00, 0xFF,
144 0xFF, 0x80, 0x00, 0xFF,
145 0xFF, 0xC0, 0x00, 0xFF,
146 0xFF, 0xC0, 0x01, 0xFF,
147 0xFF, 0xE0, 0x01, 0xFF,
148 0xFF, 0xE0, 0x01, 0xFF,
149 0xFF, 0xF0, 0x03, 0xFF,
150 0xFF, 0xF0, 0x03, 0xFF,
151 0xFF, 0xF0, 0x03, 0xFF,
152 0xFF, 0xFF, 0xFF, 0xFF,
153 0xFF, 0xFF, 0xFF, 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
164 void org::xwt::plat::Win32::natInit() {
166 // grab desktop dc/handle
167 desktop_handle = (jint)GetDesktopWindow();
168 desktop_dc = (jint)GetDC((HWND)desktop_handle);
171 org::xwt::plat::Win32::wait_cursor = (jint)LoadCursor(NULL, IDC_WAIT);
172 org::xwt::plat::Win32::default_cursor = (jint)LoadCursor(NULL, IDC_ARROW);
173 org::xwt::plat::Win32::crosshair_cursor = (jint)LoadCursor(NULL, IDC_CROSS);
174 org::xwt::plat::Win32::text_cursor = (jint)LoadCursor(NULL, IDC_IBEAM);
175 org::xwt::plat::Win32::move_cursor = (jint)LoadCursor(NULL, IDC_SIZEALL);
176 org::xwt::plat::Win32::sizenesw_cursor = (jint)LoadCursor(NULL, IDC_SIZENESW);
177 org::xwt::plat::Win32::sizens_cursor = (jint)LoadCursor(NULL, IDC_SIZENS);
178 org::xwt::plat::Win32::sizenwse_cursor = (jint)LoadCursor(NULL, IDC_SIZENWSE);
179 org::xwt::plat::Win32::sizewe_cursor = (jint)LoadCursor(NULL, IDC_SIZEWE);
180 org::xwt::plat::Win32::hand_cursor = (jint)CreateCursor(GetModuleHandle(NULL), 14, 1, 32, 32, hand_cursor_and, hand_cursor_xor);
184 lf.lfCharSet = ANSI_CHARSET;
185 lf.lfFaceName[0] = 0;
186 lf.lfPitchAndFamily = 0;
187 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
189 messagePumpThread = (jint)GetCurrentThreadId();
190 messagePumpStarted->release();
193 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
195 if (msg.message == WM_USER_CREATEWINDOW) {
196 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
198 // we must create a unique window class name for each
199 // window so that minimization icons can be set independantly
201 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
204 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
205 wc.lpfnWndProc = WndProc;
207 wc.cbSize = sizeof(WNDCLASSEX);
209 wc.hInstance = GetModuleHandle(NULL);
213 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
214 wc.lpszMenuName = NULL;
215 wc.lpszClassName = buf;
216 RegisterClassEx(&wc);
218 surface->hwnd = (jint)CreateWindow(wc.lpszClassName, TEXT(""), msg.wParam ? WS_NORMAL : WS_POPUP, 200, 200, 100, 100,
219 (HWND__*)NULL, (HMENU__*)NULL, GetModuleHandle(NULL), (LPVOID)NULL);
220 SetFocus((HWND)surface->hwnd);
221 surface->hwndCreated->release();
224 TranslateMessage(&msg);
225 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
226 DispatchMessage(&msg);
230 java::lang::System::exit(-1);
234 // Platform Methods ///////////////////////////////////////////////////////////////////
236 jstring org::xwt::plat::Win32::_getClipBoard() {
237 OpenClipboard((HWND)desktop_handle);
238 HGLOBAL hmem = GetClipboardData(CF_TEXT);
239 if (hmem == NULL) return NULL;
240 char* buf = (char*)GlobalLock(hmem);
241 if (buf == NULL) return NULL;
242 jstring ret = JvNewStringLatin1(buf);
248 void org::xwt::plat::Win32::_setClipBoard(jstring s) {
249 OpenClipboard((HWND)desktop_handle);
250 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, JvGetStringUTFLength(s) + 1);
251 if (hmem == NULL) return;
252 char* buf = (char*)GlobalLock(hmem);
253 if (buf == NULL) return;
254 JvGetStringUTFRegion(s, 0, JvGetStringUTFLength(s), buf);
255 buf[JvGetStringUTFLength(s)] = '\0';
257 SetClipboardData(CF_TEXT, hmem);
261 void org::xwt::plat::Win32::_criticalAbort(jstring message) {
262 char buf[JvGetStringUTFLength(message) + 1];
263 buf[JvGetStringUTFLength(message)] = '\0';
264 JvGetStringUTFRegion(message, 0, JvGetStringUTFLength(message), buf);
265 MessageBox (NULL, buf, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
266 java::lang::System::exit(-1);
269 jint org::xwt::plat::Win32::_getScreenWidth() {
271 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
272 return rect.right - rect.left;
275 jint org::xwt::plat::Win32::_getScreenHeight() {
277 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
278 return rect.bottom - rect.top;
281 org::xwt::plat::Win32$Win32Font* org::xwt::plat::Win32::mapFont(org::xwt::Platform$ParsedFont* pf) {
282 org::xwt::plat::Win32$Win32Font* ret = new org::xwt::plat::Win32$Win32Font();
284 memset(&logfont, 0, sizeof(LOGFONT));
285 logfont.lfHeight = -MulDiv(pf->size, GetDeviceCaps((HDC)org::xwt::plat::Win32::desktop_dc, LOGPIXELSY), 72);
286 if (pf->italic) logfont.lfItalic = 1;
287 if (pf->bold) logfont.lfWeight = FW_BOLD;
288 logfont.lfCharSet = ANSI_CHARSET;
290 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
291 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
293 ret->hfont = (jint)CreateFontIndirect(&logfont);
294 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
297 GetTextMetrics((HDC)desktop_dc, &tm);
299 p.x = 0; p.y = tm.tmAscent;
300 LPtoDP((HDC)desktop_dc, &p, 1);
301 ret->maxAscent = p.y;
303 p.x = 0; p.y = tm.tmDescent;
304 LPtoDP((HDC)desktop_dc, &p, 1);
305 ret->maxDescent = p.y;
310 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
312 HFONT hfont = (HFONT)(getFont(font)->hfont);
313 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
315 int len = min(1024, JvGetStringUTFLength(text));
318 JvGetStringUTFRegion(text, 0, len, buf);
321 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
325 jboolean org::xwt::plat::Win32::_newBrowserWindow_(jstring url) {
327 int len = min(2048, JvGetStringUTFLength(url));
329 JvGetStringUTFRegion(url, 0, len, buf);
333 memset(&ei, 0, sizeof(ei));
334 ei.cbSize = sizeof(ei);
337 ei.fMask = SEE_MASK_NOCLOSEPROCESS;
338 ei.nShow = SW_SHOWDEFAULT;
339 return (ShellExecuteEx(&ei) == 0);
344 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
346 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
347 // Since all drawing operations are single-threaded, it's safe to use a global here.
348 static HBITMAP scratch = NULL;
349 static HDC scratch_dc = NULL;
350 static jint* scratch_bits = NULL;
351 static jint scratch_w = 0;
352 static jint scratch_h = 0;
354 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
355 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
356 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
358 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
360 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
361 jint dx1, jint dy1, jint dx2, jint dy2,
362 jint sx1, jint sy1, jint sx2, jint sy2) {
364 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
366 if (source->hasalpha) {
368 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
369 if (scratch_dc != NULL) DeleteDC(scratch_dc);
370 if (scratch != NULL) DeleteObject(scratch);
371 scratch_w = max(dx2 - dx1, scratch_w);
372 scratch_h = max(dy2 - dy1, scratch_h);
374 BITMAPINFO bitmapinfo;
375 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
376 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
377 bitmapinfo.bmiHeader.biWidth = scratch_w;
378 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
379 bitmapinfo.bmiHeader.biPlanes = 1;
380 bitmapinfo.bmiHeader.biBitCount = 32;
381 bitmapinfo.bmiHeader.biCompression = BI_RGB;
383 // create section DIB
384 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
385 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
386 SelectObject(scratch_dc, scratch);
389 // copy from screen to scratch
390 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
392 // apply alpha-blending to scratch
393 jint* dat = elements(source->data);
395 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
396 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
397 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
398 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
399 jint dst = scratch_bits[y * scratch_w + x];
400 jint src = dat[sy * source->getWidth() + sx];
401 jint alpha = (src & 0xFF000000) >> 24;
402 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
403 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
404 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
405 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
408 // copy back from scratch to screen
409 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
412 if (source->hasmask) {
413 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
414 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
416 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
423 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
425 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
426 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
428 // Platform API passes us the y-pos of the bottom of the text; we need the top
431 int len = min(1024, JvGetStringUTFLength(text));
434 JvGetStringUTFRegion(text, 0, len, buf);
436 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
437 TextOut((HDC)hdc, x, y, buf, len);
440 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
444 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
445 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
447 RECT rect = { x, y, x + w, y + h };
448 FillRect((HDC)hdc, &rect, brush);
452 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
453 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
456 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
457 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
458 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
459 SetBkMode((HDC)hdc, TRANSPARENT);
460 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
463 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
464 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
465 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
466 SelectClipRgn((HDC)hdc, hrgn);
470 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
471 DeleteObject((void*)hdc);
472 DeleteObject((void*)hbitmap);
477 // Win32Picture /////////////////////////////////////////////////////////////////////////
479 void org::xwt::plat::Win32$Win32Picture::natInit() {
481 BITMAPINFO bitmapinfo;
482 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
483 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
484 bitmapinfo.bmiHeader.biWidth = w;
485 bitmapinfo.bmiHeader.biHeight = -1 * h;
486 bitmapinfo.bmiHeader.biPlanes = 1;
487 bitmapinfo.bmiHeader.biBitCount = 32;
488 bitmapinfo.bmiHeader.biCompression = BI_RGB;
490 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
491 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
492 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
493 uint32_t* dat = (uint32_t*)elements(data);
494 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
495 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
497 jint _copy[min(1024, data->length)];
498 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
500 memcpy(copy, elements(data), data->length * 4);
501 for(int i=0; i<data->length; i++)
502 if ((copy[i] & 0xFF000000) == 0x00000000) {
504 copy[i] = 0x00FFFFFF;
505 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
506 copy[i] = 0x00000000;
510 if (data->length > 1024) free(copy);
515 if (data->length > 1024) free(copy);
519 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
520 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
521 maskdc = (jint)CreateCompatibleDC(NULL);
522 SelectObject((HDC)maskdc, (HBITMAP)hmask);
523 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
524 if (data->length > 1024) free(copy);
529 // Win32Surface /////////////////////////////////////////////////////////////////////////////
531 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
533 // Ask the message-handling thread to create a window for us
534 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
535 hwndCreated->block();
537 // turn on incremental GC now that we have a user-visible interface
538 // [[this is causing segfaults; enable it later...]]
539 // GC_enable_incremental();
541 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
542 hdc = (jint)GetDC((HWND)hwnd);
545 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
546 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
547 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
548 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
549 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
550 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
551 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
552 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
554 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
559 ClientToScreen((HWND)hwnd, &point);
560 GetWindowRect((HWND)hwnd, &rect);
561 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
564 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
565 RECT client_rect, window_rect;
566 GetClientRect((HWND)hwnd, &client_rect);
567 GetWindowRect((HWND)hwnd, &window_rect);
568 int addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
569 int addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
570 SetWindowPos((HWND)hwnd, NULL, 0, 0, w + addwidth, h + addheight, SWP_NOZORDER | SWP_NOMOVE);
573 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
574 int len = min(1024, JvGetStringUTFLength(title));
577 JvGetStringUTFRegion(title, 0, len, buf);
578 SetWindowText((HWND)hwnd, buf);
581 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
583 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
584 int icon_width = GetSystemMetrics(SM_CXSMICON);
585 int icon_height = GetSystemMetrics(SM_CYSMICON);
588 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
589 HDC memdc = CreateCompatibleDC((HDC)hdc);
590 SelectObject(memdc, bit);
591 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
594 jint* dat = elements(p->data);
595 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
596 SelectObject(memdc, bit_mask);
597 for(int x=0; x<icon_width; x++)
598 for(int y=0; y<icon_height; y++) {
599 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
600 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
601 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
604 // instantiate the icon and assign it to the window class
607 ici.hbmMask = bit_mask;
609 HICON hicon = CreateIconIndirect(&ici);
610 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
611 if (oldicon != NULL) DestroyIcon(oldicon);
615 static jstring keyToString(WPARAM wParam);
616 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
618 UINT iMsg = (UINT)_iMsg;
619 WPARAM wParam = (WPARAM)_wParam;
620 LPARAM lParam = (LPARAM)_lParam;
621 int oldmousex, oldmousey;
631 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
632 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
633 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
634 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
636 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
638 KeyPressed(keyToString(wParam));
641 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
643 KeyReleased(keyToString(wParam));
646 case WM_SETFOCUS: Focused(true); return 0;
647 case WM_KILLFOCUS: Focused(false); return 0;
648 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
649 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
650 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
651 case WM_LBUTTONDOWN: Press(1); return 0;
652 case WM_RBUTTONDOWN: Press(2); return 0;
653 case WM_MBUTTONDOWN: Press(3); return 0;
654 case WM_CLOSE: Close(); return 0;
655 case WM_ERASEBKGND: return 0;
660 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
661 if (captured && !inside) {
663 SetCursor((HCURSOR)previous_cursor);
668 GetClientRect((HWND)hwnd, &rect);
669 PosChange(rect.left, rect.top);
673 if (wParam == SIZE_MINIMIZED) {
674 if (maximized) Maximized(false);
676 } else if (wParam == SIZE_MAXIMIZED) {
677 if (minimized) Minimized(false);
680 if (minimized) Minimized(false);
681 if (maximized) Maximized(false);
683 // deliberately fall through to WM_SIZING
686 GetClientRect((HWND)hwnd, &rect);
687 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
691 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
693 GetClientRect((HWND)hwnd, &rect);
694 point.x = mouse_x = lParam & 0xFFFF;
695 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
696 ClientToScreen((HWND)hwnd, &point);
697 hwnd2 = WindowFromPoint(point);
699 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
701 Move(mouse_x, mouse_y);
703 if (newinside && !inside) {
705 SetCapture((HWND)hwnd);
707 previous_cursor = (jint)GetCursor();
708 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
710 } else if (!newinside && inside) {
712 if (!button1 && !button2 && !button3) {
715 SetCursor((HCURSOR)previous_cursor);
721 case WM_USER_SETCURSOR:
722 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
723 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
724 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
725 // cursor should be re-set to "current_cursor".
726 SetCursor((HCURSOR)current_cursor);
729 case WM_USER_DISPOSE:
730 // used to signal that we should destroy ourselves
731 DestroyWindow((HWND)hwnd);
734 case WM_GETMINMAXINFO:
735 mmi = (MINMAXINFO*)lParam;
736 mmi->ptMinTrackSize.x = root->dmin(0);
737 mmi->ptMinTrackSize.y = root->dmin(1);
738 mmi->ptMaxTrackSize.x = root->dmax(0);
739 mmi->ptMaxTrackSize.y = root->dmax(1);
744 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
745 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
746 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
752 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
756 // Key Translator Helper /////////////////////////////////////////////////////////////////////
758 static char keyarr [256] = { 0 };
759 static jstring keyToString(WPARAM wParam) {
761 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
762 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
763 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
764 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
766 if (ToAscii(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0) == 1) {
768 case '\t': return JvNewStringLatin1("tab");
769 case 0x1b: return JvNewStringLatin1("escape");
770 case '\n': return JvNewStringLatin1("enter");
771 case '\r': return JvNewStringLatin1("enter");
772 case 0x08: return JvNewStringLatin1("back_space");
773 default: return JvNewStringLatin1(arr, 1);
776 } else switch (wParam) {
777 case VK_CLEAR: return JvNewStringLatin1("clear");
778 case VK_SHIFT: return JvNewStringLatin1("shift");
779 case VK_CONTROL: return JvNewStringLatin1("control");
780 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
781 case VK_MENU: return JvNewStringLatin1("alt");
782 case VK_PAUSE: return JvNewStringLatin1("pause");
783 case VK_PRIOR: return JvNewStringLatin1("page_up");
784 case VK_NEXT: return JvNewStringLatin1("page_down");
785 case VK_END: return JvNewStringLatin1("end");
786 case VK_HOME: return JvNewStringLatin1("home");
787 case VK_LEFT: return JvNewStringLatin1("left");
788 case VK_UP: return JvNewStringLatin1("up");
789 case VK_RIGHT: return JvNewStringLatin1("right");
790 case VK_DOWN: return JvNewStringLatin1("down");
791 case VK_INSERT: return JvNewStringLatin1("insert");
792 case VK_DELETE: return JvNewStringLatin1("delete");
793 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
794 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
795 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
796 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
797 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
798 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
799 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
800 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
801 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
802 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
803 case VK_F1: return JvNewStringLatin1("f1");
804 case VK_F2: return JvNewStringLatin1("f2");
805 case VK_F3: return JvNewStringLatin1("f3");
806 case VK_F4: return JvNewStringLatin1("f4");
807 case VK_F5: return JvNewStringLatin1("f5");
808 case VK_F6: return JvNewStringLatin1("f6");
809 case VK_F7: return JvNewStringLatin1("f7");
810 case VK_F8: return JvNewStringLatin1("f8");
811 case VK_F9: return JvNewStringLatin1("f9");
812 case VK_F10: return JvNewStringLatin1("f10");
813 case VK_F11: return JvNewStringLatin1("f11");
814 case VK_F12: return JvNewStringLatin1("f12");
815 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
816 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
817 case VK_LSHIFT: return JvNewStringLatin1("shift");
818 case VK_RSHIFT: return JvNewStringLatin1("shift");
819 case VK_LCONTROL: return JvNewStringLatin1("control");
820 case VK_RCONTROL: return JvNewStringLatin1("control");
828 ///////////////////////////////////////////////////////////////////////////////////////
829 ///////////////////////////////////////////////////////////////////////////////////////
830 ///////////////////////////////////////////////////////////////////////////////////////
832 #else /* COMPILE_DLL */
836 // A simple DLL to invoke xwt.exe and pass it any arguments found in the <object/> tag
840 #include <initguid.h>
847 // Globals ////////////////////////////////////////////////////////////////////////
851 #define CLSID_STRING_SIZE 39
853 const char XWT_friendlyName[] = "XWT ActiveX Control (build " BUILDID ")";
854 const char XWT_versionIndependantProgramID[] = "XWT.ActiveX";
855 const char XWT_programID[] = "XWT.ActiveX (build " BUILDID ")";
856 extern "C" const CLSID XWT_clsid = CLSID_STRUCT;
857 static HMODULE g_hModule = NULL; //DLL handle
862 // Superclasses ////////////////////////////////////////////////////////////////////////
864 // Option bit definitions for IObjectSafety:
865 #define INTERFACESAFE_FOR_UNTRUSTED_CALLER 0x00000001 // Caller of interface may be untrusted
866 #define INTERFACESAFE_FOR_UNTRUSTED_DATA 0x00000002 // Data passed into interface may be untrusted
868 // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
869 DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);
871 interface IObjectSafety : public IUnknown {
873 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) = 0;
874 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) = 0;
877 interface IShoeHorn : IPersistPropertyBag, IObjectSafety { };
881 // Entry Points ////////////////////////////////////////////////////////////////////////
883 // to get mingw to stop nagging me
884 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { }
886 // determines whether or not the DLL can be unloaded; always allow this since we don't do too much
887 STDAPI __declspec(dllexport) DllCanUnloadNow(void) { return S_OK; }
889 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID /*lpReserved*/) {
890 if (dwReason == DLL_PROCESS_ATTACH) g_hModule = (HINSTANCE)hModule;
896 // Other ///////////////////////////////////////////////////////////////////////////////////
898 // simple assert() replacement that pops open a message box if there are errors
899 void check(int val, char* message) {
901 MessageBox (NULL, message, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
906 void clsidToString(const CLSID& clsid, char* str, int length) {
907 check(length >= CLSID_STRING_SIZE, "clsidToString(): string too short");
908 LPOLESTR wide_str = NULL;
909 HRESULT hr = StringFromCLSID(clsid, &wide_str);
910 check(SUCCEEDED(hr), "StringFromCLSID() failed in clsidToString()");
911 wcstombs(str, wide_str, length);
912 CoTaskMemFree(wide_str);
915 void setRegistryKey(const char* key, const char* subkey, const char* value) {
919 if (subkey != NULL) {
920 strcat(keyBuf, "\\");
921 strcat(keyBuf, subkey );
923 long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
925 check(RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, strlen(value) + 1) == ERROR_SUCCESS,
926 "RegSetValueEx() failed in setRegistryKey()");
930 void deleteRegistryKey(HKEY parent, const char* target) {
932 RegOpenKeyEx(parent, target, 0, KEY_ALL_ACCESS, &hKeyChild);
934 // Iterate over children, deleting them
938 while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) {
939 deleteRegistryKey(hKeyChild, szBuffer);
943 RegCloseKey(hKeyChild);
944 RegDeleteKey(parent, target);
947 STDAPI __declspec(dllexport) DllRegisterServer(void) {
948 char moduleName[512];
949 HRESULT result = GetModuleFileName(g_hModule, moduleName, sizeof(moduleName)/sizeof(char));
950 check(result, "GetModuleFileName() failed in RegisterServer()");
952 char clsidString[CLSID_STRING_SIZE];
953 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
957 strcpy(key, "CLSID\\");
958 strcat(key, clsidString);
960 setRegistryKey(key, NULL, XWT_friendlyName);
961 setRegistryKey(key, "InprocServer32", moduleName);
962 setRegistryKey(key, "ProgID", XWT_programID);
963 setRegistryKey(key, "VersionIndependentProgID", XWT_versionIndependantProgramID);
964 setRegistryKey(XWT_versionIndependantProgramID, NULL, XWT_friendlyName);
965 setRegistryKey(XWT_versionIndependantProgramID, "CLSID", clsidString);
966 setRegistryKey(XWT_versionIndependantProgramID, "CurVer", XWT_programID);
967 setRegistryKey(XWT_programID, NULL, XWT_friendlyName);
968 setRegistryKey(XWT_programID, "CLSID", clsidString);
972 STDAPI __declspec(dllexport) DllUnregisterServer(void) {
973 char clsidString[CLSID_STRING_SIZE];
974 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
978 strcpy(key, "CLSID\\");
979 strcat(key, clsidString);
981 deleteRegistryKey(HKEY_CLASSES_ROOT, key);
982 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_versionIndependantProgramID);
983 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_programID);
989 // ShoeHorn //////////////////////////////////////////////////////////////////////////////////
991 class ShoeHorn : public IShoeHorn {
993 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
994 if(iid == IID_IUnknown) *ppv = static_cast<IShoeHorn*>(this);
995 else if(iid == XWT_clsid) *ppv = static_cast<IShoeHorn*>(this);
996 else if(iid == IID_IPersistPropertyBag) *ppv = static_cast<IPersistPropertyBag*>(this);
997 else if(iid == IID_IObjectSafety) *ppv = static_cast<IObjectSafety*>(this);
998 else { *ppv = NULL; return E_NOINTERFACE; }
999 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1002 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1003 virtual ULONG __stdcall Release() {
1004 if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; }
1007 virtual HRESULT __stdcall GetClassID(CLSID*) { return S_OK; }
1008 virtual HRESULT __stdcall InitNew() { return S_OK; }
1009 virtual HRESULT __stdcall Save(IPropertyBag*, int, int) { return S_OK; }
1010 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions) { return S_OK; }
1011 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions) {
1012 if (pdwSupportedOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1013 if (pdwEnabledOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1017 virtual HRESULT __stdcall Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) {
1025 MultiByteToWideChar(CP_ACP, 0, "initial-xwar-url", -1, wc, 100);
1026 pPropBag->Read(wc, &v, pErrorLog);
1027 check(WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, url, 100, NULL, NULL),
1028 "WideCharToMultiByte() failed in ShoeHorn::Load()");
1031 LONG result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache", &hkey);
1032 check(result == ERROR_SUCCESS, "RegOpenKey() failed in ShoeHorn::Load()");
1034 // iterate over all the activex cache locations until we find ourselves
1035 for(int i=0; i<9; i++) {
1044 result = RegQueryValueEx(hkey, which, NULL, &type, (BYTE*)buf, &buflen);
1045 if (result != ERROR_SUCCESS)
1047 check(0, "RegQueryValueEx() failed in ShoeHorn::Load()");
1054 for(int i=0; i<200; i++) cmdline[i] = '\0';
1055 strncpy(cmdline, buf, 200);
1056 strncpy(cmdline + strlen(cmdline), "\\xwt-" BUILDID ".exe", 200 - strlen(cmdline));
1057 strncpy(cmdline + strlen(cmdline), " ", 200 - strlen(cmdline));
1058 strncpy(cmdline + strlen(cmdline), url, 200 - strlen(cmdline));
1060 PROCESS_INFORMATION pInfo;
1062 sInfo.cb = sizeof(STARTUPINFO);
1063 sInfo.lpReserved = NULL;
1064 sInfo.lpReserved2 = NULL;
1065 sInfo.cbReserved2 = 0;
1066 sInfo.lpDesktop = NULL;
1067 sInfo.lpTitle = NULL;
1071 sInfo.dwFillAttribute = 0;
1072 sInfo.wShowWindow = SW_SHOW;
1073 BOOL b = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo);
1077 check(0, "unable to locate xwt-" BUILDID ".exe in ActiveX cache folders");
1080 ShoeHorn() : m_cRef(1) { };
1082 private: long m_cRef;
1088 // ClassFactory //////////////////////////////////////////////////////////////////////////
1090 class ClassFactory : public IClassFactory {
1092 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
1093 if(iid == IID_IUnknown) *ppv = static_cast<IClassFactory*>(this);
1094 else if(iid == IID_IClassFactory) *ppv = static_cast<IClassFactory*>(this);
1097 return E_NOINTERFACE;
1099 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1103 ClassFactory() : m_cRef(1) { }
1105 virtual HRESULT __stdcall LockServer(BOOL bLock) { return S_OK; }
1106 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1107 virtual ULONG __stdcall Release() {
1108 if(InterlockedDecrement(&m_cRef) == 0) {
1115 virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
1116 if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
1117 ShoeHorn* s = new ShoeHorn;
1118 if(s == NULL) return E_OUTOFMEMORY;
1119 HRESULT hr = s->QueryInterface(iid, ppv);
1124 private: long m_cRef;
1128 extern "C" __stdcall HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) {
1129 if(clsid != XWT_clsid) return CLASS_E_CLASSNOTAVAILABLE;
1130 ClassFactory* pFactory = new ClassFactory;
1131 if(pFactory == NULL) return E_OUTOFMEMORY;
1132 HRESULT hr = pFactory->QueryInterface(iid, ppv);
1133 pFactory->Release();