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 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);
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) {
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);
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);
83 // Initialization ////////////////////////////////////////////////////////////////////
85 static int window_class_counter = 0;
87 jstring org::xwt::plat::Win32::getTempPath() {
89 DWORD ret = GetTempPath(1024, buf);
90 if (ret == 0) criticalAbort(JvNewStringLatin1("GetTempPath() failed"));
91 return JvNewStringLatin1(buf);
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
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
166 void org::xwt::plat::Win32::natInit() {
168 // grab desktop dc/handle
169 desktop_handle = (jint)GetDesktopWindow();
170 desktop_dc = (jint)GetDC((HWND)desktop_handle);
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);
186 lf.lfCharSet = ANSI_CHARSET;
187 lf.lfFaceName[0] = 0;
188 lf.lfPitchAndFamily = 0;
189 EnumFontFamiliesEx((HDC)desktop_dc, &lf, fontproc, 0, 0);
191 messagePumpThread = (jint)GetCurrentThreadId();
192 messagePumpStarted->release();
195 while(GetMessage(&msg, (HWND)NULL, 0, 0) > 0) {
197 if (msg.message == WM_USER_CREATEWINDOW) {
198 org::xwt::plat::Win32$Win32Surface *surface = (org::xwt::plat::Win32$Win32Surface*)msg.lParam;
200 // we must create a unique window class name for each
201 // window so that minimization icons can be set independantly
203 sprintf(buf, "XWT_WINDOW_CLASS_%i", window_class_counter++);
206 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
207 wc.lpfnWndProc = WndProc;
209 wc.cbSize = sizeof(WNDCLASSEX);
211 wc.hInstance = GetModuleHandle(NULL);
215 wc.hbrBackground = (HBRUSH)(COLOR_SCROLLBAR + 1);
216 wc.lpszMenuName = NULL;
217 wc.lpszClassName = buf;
218 RegisterClassEx(&wc);
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();
226 TranslateMessage(&msg);
227 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) SetFocus(msg.hwnd);
228 DispatchMessage(&msg);
232 java::lang::System::exit(-1);
236 // Platform Methods ///////////////////////////////////////////////////////////////////
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);
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';
259 SetClipboardData(CF_TEXT, hmem);
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);
271 jint org::xwt::plat::Win32::_getScreenWidth() {
273 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
274 return rect.right - rect.left;
277 jint org::xwt::plat::Win32::_getScreenHeight() {
279 SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
280 return rect.bottom - rect.top;
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();
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;
292 JvGetStringUTFRegion(pf->name, 0, min(31, JvGetStringUTFLength(pf->name)), logfont.lfFaceName);
293 logfont.lfFaceName[min(31, JvGetStringUTFLength(pf->name))] = 0;
295 ret->hfont = (jint)CreateFontIndirect(&logfont);
296 SelectObject((HDC)desktop_dc, (HFONT)(ret->hfont));
299 GetTextMetrics((HDC)desktop_dc, &tm);
301 p.x = 0; p.y = tm.tmAscent;
302 LPtoDP((HDC)desktop_dc, &p, 1);
303 ret->maxAscent = p.y;
305 p.x = 0; p.y = tm.tmDescent;
306 LPtoDP((HDC)desktop_dc, &p, 1);
307 ret->maxDescent = p.y;
312 jint org::xwt::plat::Win32::_stringWidth(jstring font, jstring text) {
314 HFONT hfont = (HFONT)(getFont(font)->hfont);
315 SelectObject((HDC)org::xwt::plat::Win32::desktop_dc, hfont);
317 int len = min(1024, JvGetStringUTFLength(text));
320 JvGetStringUTFRegion(text, 0, len, buf);
323 GetTextExtentPoint32((HDC)org::xwt::plat::Win32::desktop_dc, buf, len, &size);
329 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
331 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
332 // Since all drawing operations are single-threaded, it's safe to use a global here.
333 static HBITMAP scratch = NULL;
334 static HDC scratch_dc = NULL;
335 static jint* scratch_bits = NULL;
336 static jint scratch_w = 0;
337 static jint scratch_h = 0;
339 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
340 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
341 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
343 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
345 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
346 jint dx1, jint dy1, jint dx2, jint dy2,
347 jint sx1, jint sy1, jint sx2, jint sy2) {
349 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
351 if (source->hasalpha) {
353 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
354 if (scratch_dc != NULL) DeleteDC(scratch_dc);
355 if (scratch != NULL) DeleteObject(scratch);
356 scratch_w = max(dx2 - dx1, scratch_w);
357 scratch_h = max(dy2 - dy1, scratch_h);
359 BITMAPINFO bitmapinfo;
360 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
361 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
362 bitmapinfo.bmiHeader.biWidth = scratch_w;
363 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
364 bitmapinfo.bmiHeader.biPlanes = 1;
365 bitmapinfo.bmiHeader.biBitCount = 32;
366 bitmapinfo.bmiHeader.biCompression = BI_RGB;
368 // create section DIB
369 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
370 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
371 SelectObject(scratch_dc, scratch);
374 // copy from screen to scratch
375 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
377 // apply alpha-blending to scratch
378 jint* dat = elements(source->data);
380 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
381 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
382 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
383 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
384 jint dst = scratch_bits[y * scratch_w + x];
385 jint src = dat[sy * source->getWidth() + sx];
386 jint alpha = (src & 0xFF000000) >> 24;
387 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
388 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
389 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
390 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
393 // copy back from scratch to screen
394 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
397 if (source->hasmask) {
398 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
399 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
401 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
408 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
410 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
411 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
413 // Platform API passes us the y-pos of the bottom of the text; we need the top
416 int len = min(1024, JvGetStringUTFLength(text));
419 JvGetStringUTFRegion(text, 0, len, buf);
421 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
422 TextOut((HDC)hdc, x, y, buf, len);
425 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
429 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
430 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
432 RECT rect = { x, y, x + w, y + h };
433 FillRect((HDC)hdc, &rect, brush);
437 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
438 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
441 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
442 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
443 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
444 SetBkMode((HDC)hdc, TRANSPARENT);
445 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
448 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
449 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
450 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
451 SelectClipRgn((HDC)hdc, hrgn);
455 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
456 DeleteObject((void*)hdc);
457 DeleteObject((void*)hbitmap);
462 // Win32Picture /////////////////////////////////////////////////////////////////////////
464 void org::xwt::plat::Win32$Win32Picture::natInit() {
466 BITMAPINFO bitmapinfo;
467 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
468 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
469 bitmapinfo.bmiHeader.biWidth = w;
470 bitmapinfo.bmiHeader.biHeight = -1 * h;
471 bitmapinfo.bmiHeader.biPlanes = 1;
472 bitmapinfo.bmiHeader.biBitCount = 32;
473 bitmapinfo.bmiHeader.biCompression = BI_RGB;
475 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
476 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
477 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
478 uint32_t* dat = (uint32_t*)elements(data);
479 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
480 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
482 jint _copy[min(1024, data->length)];
483 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
485 memcpy(copy, elements(data), data->length * 4);
486 for(int i=0; i<data->length; i++)
487 if ((copy[i] & 0xFF000000) == 0x00000000) {
489 copy[i] = 0x00FFFFFF;
490 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
491 copy[i] = 0x00000000;
495 if (data->length > 1024) free(copy);
500 if (data->length > 1024) free(copy);
504 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
505 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
506 maskdc = (jint)CreateCompatibleDC(NULL);
507 SelectObject((HDC)maskdc, (HBITMAP)hmask);
508 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
509 if (data->length > 1024) free(copy);
514 // Win32Surface /////////////////////////////////////////////////////////////////////////////
516 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
518 // Ask the message-handling thread to create a window for us
519 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
520 hwndCreated->block();
522 // turn on incremental GC now that we have a user-visible interface
523 // [[this is causing segfaults; enable it later...]]
524 // GC_enable_incremental();
526 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
527 hdc = (jint)GetDC((HWND)hwnd);
530 void org::xwt::plat::Win32$Win32Surface::finalize() { /* DeleteObject((void*)hwnd); */ }
531 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
532 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
533 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
534 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
535 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
536 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
537 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
539 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
544 ClientToScreen((HWND)hwnd, &point);
545 GetWindowRect((HWND)hwnd, &rect);
546 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
549 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
550 RECT client_rect, window_rect;
551 GetClientRect((HWND)hwnd, &client_rect);
552 GetWindowRect((HWND)hwnd, &window_rect);
553 int addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
554 int addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
555 SetWindowPos((HWND)hwnd, NULL, 0, 0, w + addwidth, h + addheight, SWP_NOZORDER | SWP_NOMOVE);
558 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
559 int len = min(1024, JvGetStringUTFLength(title));
562 JvGetStringUTFRegion(title, 0, len, buf);
563 SetWindowText((HWND)hwnd, buf);
566 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
568 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
569 int icon_width = GetSystemMetrics(SM_CXSMICON);
570 int icon_height = GetSystemMetrics(SM_CYSMICON);
573 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
574 HDC memdc = CreateCompatibleDC((HDC)hdc);
575 SelectObject(memdc, bit);
576 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
579 jint* dat = elements(p->data);
580 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
581 SelectObject(memdc, bit_mask);
582 for(int x=0; x<icon_width; x++)
583 for(int y=0; y<icon_height; y++) {
584 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
585 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
586 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
589 // instantiate the icon and assign it to the window class
592 ici.hbmMask = bit_mask;
594 HICON hicon = CreateIconIndirect(&ici);
595 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
596 if (oldicon != NULL) DestroyIcon(oldicon);
600 static jstring keyToString(WPARAM wParam);
601 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
603 UINT iMsg = (UINT)_iMsg;
604 WPARAM wParam = (WPARAM)_wParam;
605 LPARAM lParam = (LPARAM)_lParam;
606 int oldmousex, oldmousey;
616 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
617 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
618 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
619 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
621 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
623 KeyPressed(keyToString(wParam));
626 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
628 KeyReleased(keyToString(wParam));
631 case WM_SETFOCUS: Focused(true); return 0;
632 case WM_KILLFOCUS: Focused(false); return 0;
633 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
634 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
635 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
636 case WM_LBUTTONDOWN: Press(1); return 0;
637 case WM_RBUTTONDOWN: Press(2); return 0;
638 case WM_MBUTTONDOWN: Press(3); return 0;
639 case WM_CLOSE: Close(); return 0;
640 case WM_ERASEBKGND: return 0;
645 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
646 if (captured && !inside) {
648 SetCursor((HCURSOR)previous_cursor);
653 GetClientRect((HWND)hwnd, &rect);
654 PosChange(rect.left, rect.top);
658 if (wParam == SIZE_MINIMIZED) {
659 if (maximized) Maximized(false);
661 } else if (wParam == SIZE_MAXIMIZED) {
662 if (minimized) Minimized(false);
665 if (minimized) Minimized(false);
666 if (maximized) Maximized(false);
668 // deliberately fall through to WM_SIZING
671 GetClientRect((HWND)hwnd, &rect);
672 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
676 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
678 GetClientRect((HWND)hwnd, &rect);
679 point.x = mouse_x = lParam & 0xFFFF;
680 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
681 ClientToScreen((HWND)hwnd, &point);
682 hwnd2 = WindowFromPoint(point);
684 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
686 Move(mouse_x, mouse_y);
688 if (newinside && !inside) {
690 SetCapture((HWND)hwnd);
692 previous_cursor = (jint)GetCursor();
693 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
695 } else if (!newinside && inside) {
697 if (!button1 && !button2 && !button3) {
700 SetCursor((HCURSOR)previous_cursor);
706 case WM_USER_SETCURSOR:
707 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
708 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
709 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
710 // cursor should be re-set to "current_cursor".
711 SetCursor((HCURSOR)current_cursor);
714 case WM_USER_DISPOSE:
715 // used to signal that we should destroy ourselves
716 DestroyWindow((HWND)hwnd);
719 case WM_GETMINMAXINFO:
720 mmi = (MINMAXINFO*)lParam;
721 mmi->ptMinTrackSize.x = root->dmin(0);
722 mmi->ptMinTrackSize.y = root->dmin(1);
723 mmi->ptMaxTrackSize.x = root->dmax(0);
724 mmi->ptMaxTrackSize.y = root->dmax(1);
729 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
730 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
732 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
738 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
742 // Key Translator Helper /////////////////////////////////////////////////////////////////////
744 static char keyarr [256] = { 0 };
745 static jstring keyToString(WPARAM wParam) {
747 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
748 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
749 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
750 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
752 if (ToAscii(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0) == 1) {
754 case '\t': return JvNewStringLatin1("tab");
755 case 0x1b: return JvNewStringLatin1("escape");
756 case '\n': return JvNewStringLatin1("enter");
757 case '\r': return JvNewStringLatin1("enter");
758 case 0x08: return JvNewStringLatin1("back_space");
759 default: return JvNewStringLatin1(arr, 1);
762 } else switch (wParam) {
763 case VK_CLEAR: return JvNewStringLatin1("clear");
764 case VK_SHIFT: return JvNewStringLatin1("shift");
765 case VK_CONTROL: return JvNewStringLatin1("control");
766 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
767 case VK_MENU: return JvNewStringLatin1("alt");
768 case VK_PAUSE: return JvNewStringLatin1("pause");
769 case VK_PRIOR: return JvNewStringLatin1("page_up");
770 case VK_NEXT: return JvNewStringLatin1("page_down");
771 case VK_END: return JvNewStringLatin1("end");
772 case VK_HOME: return JvNewStringLatin1("home");
773 case VK_LEFT: return JvNewStringLatin1("left");
774 case VK_UP: return JvNewStringLatin1("up");
775 case VK_RIGHT: return JvNewStringLatin1("right");
776 case VK_DOWN: return JvNewStringLatin1("down");
777 case VK_INSERT: return JvNewStringLatin1("insert");
778 case VK_DELETE: return JvNewStringLatin1("delete");
779 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
780 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
781 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
782 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
783 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
784 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
785 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
786 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
787 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
788 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
789 case VK_F1: return JvNewStringLatin1("f1");
790 case VK_F2: return JvNewStringLatin1("f2");
791 case VK_F3: return JvNewStringLatin1("f3");
792 case VK_F4: return JvNewStringLatin1("f4");
793 case VK_F5: return JvNewStringLatin1("f5");
794 case VK_F6: return JvNewStringLatin1("f6");
795 case VK_F7: return JvNewStringLatin1("f7");
796 case VK_F8: return JvNewStringLatin1("f8");
797 case VK_F9: return JvNewStringLatin1("f9");
798 case VK_F10: return JvNewStringLatin1("f10");
799 case VK_F11: return JvNewStringLatin1("f11");
800 case VK_F12: return JvNewStringLatin1("f12");
801 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
802 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
803 case VK_LSHIFT: return JvNewStringLatin1("shift");
804 case VK_RSHIFT: return JvNewStringLatin1("shift");
805 case VK_LCONTROL: return JvNewStringLatin1("control");
806 case VK_RCONTROL: return JvNewStringLatin1("control");
814 ///////////////////////////////////////////////////////////////////////////////////////
815 ///////////////////////////////////////////////////////////////////////////////////////
816 ///////////////////////////////////////////////////////////////////////////////////////
818 #else /* COMPILE_DLL */
822 // A simple DLL to invoke xwt.exe and pass it any arguments found in the <object/> tag
826 #include <initguid.h>
833 // Globals ////////////////////////////////////////////////////////////////////////
837 #define CLSID_STRING_SIZE 39
839 const char XWT_friendlyName[] = "XWT ActiveX Control (build " BUILDID ")";
840 const char XWT_versionIndependantProgramID[] = "XWT.ActiveX";
841 const char XWT_programID[] = "XWT.ActiveX (build " BUILDID ")";
842 extern "C" const CLSID XWT_clsid = CLSID_STRUCT;
843 static HMODULE g_hModule = NULL; //DLL handle
848 // Superclasses ////////////////////////////////////////////////////////////////////////
850 // Option bit definitions for IObjectSafety:
851 #define INTERFACESAFE_FOR_UNTRUSTED_CALLER 0x00000001 // Caller of interface may be untrusted
852 #define INTERFACESAFE_FOR_UNTRUSTED_DATA 0x00000002 // Data passed into interface may be untrusted
854 // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
855 DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);
857 interface IObjectSafety : public IUnknown {
859 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) = 0;
860 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) = 0;
863 interface IShoeHorn : IPersistPropertyBag, IObjectSafety { };
867 // Entry Points ////////////////////////////////////////////////////////////////////////
869 // to get mingw to stop nagging me
870 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { }
872 // determines whether or not the DLL can be unloaded; always allow this since we don't do too much
873 STDAPI __declspec(dllexport) DllCanUnloadNow(void) { return S_OK; }
875 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID /*lpReserved*/) {
876 if (dwReason == DLL_PROCESS_ATTACH) g_hModule = (HINSTANCE)hModule;
882 // Other ///////////////////////////////////////////////////////////////////////////////////
884 // simple assert() replacement that pops open a message box if there are errors
885 void check(int val, char* message) {
887 MessageBox (NULL, message, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
892 void clsidToString(const CLSID& clsid, char* str, int length) {
893 check(length >= CLSID_STRING_SIZE, "clsidToString(): string too short");
894 LPOLESTR wide_str = NULL;
895 HRESULT hr = StringFromCLSID(clsid, &wide_str);
896 check(SUCCEEDED(hr), "StringFromCLSID() failed in clsidToString()");
897 wcstombs(str, wide_str, length);
898 CoTaskMemFree(wide_str);
901 void setRegistryKey(const char* key, const char* subkey, const char* value) {
905 if (subkey != NULL) {
906 strcat(keyBuf, "\\");
907 strcat(keyBuf, subkey );
909 long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
911 check(RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, strlen(value) + 1) == ERROR_SUCCESS,
912 "RegSetValueEx() failed in setRegistryKey()");
916 void deleteRegistryKey(HKEY parent, const char* target) {
918 RegOpenKeyEx(parent, target, 0, KEY_ALL_ACCESS, &hKeyChild);
920 // Iterate over children, deleting them
924 while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) {
925 deleteRegistryKey(hKeyChild, szBuffer);
929 RegCloseKey(hKeyChild);
930 RegDeleteKey(parent, target);
933 STDAPI __declspec(dllexport) DllRegisterServer(void) {
934 char moduleName[512];
935 HRESULT result = GetModuleFileName(g_hModule, moduleName, sizeof(moduleName)/sizeof(char));
936 check(result, "GetModuleFileName() failed in RegisterServer()");
938 char clsidString[CLSID_STRING_SIZE];
939 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
943 strcpy(key, "CLSID\\");
944 strcat(key, clsidString);
946 setRegistryKey(key, NULL, XWT_friendlyName);
947 setRegistryKey(key, "InprocServer32", moduleName);
948 setRegistryKey(key, "ProgID", XWT_programID);
949 setRegistryKey(key, "VersionIndependentProgID", XWT_versionIndependantProgramID);
950 setRegistryKey(XWT_versionIndependantProgramID, NULL, XWT_friendlyName);
951 setRegistryKey(XWT_versionIndependantProgramID, "CLSID", clsidString);
952 setRegistryKey(XWT_versionIndependantProgramID, "CurVer", XWT_programID);
953 setRegistryKey(XWT_programID, NULL, XWT_friendlyName);
954 setRegistryKey(XWT_programID, "CLSID", clsidString);
958 STDAPI __declspec(dllexport) DllUnregisterServer(void) {
959 char clsidString[CLSID_STRING_SIZE];
960 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
964 strcpy(key, "CLSID\\");
965 strcat(key, clsidString);
967 deleteRegistryKey(HKEY_CLASSES_ROOT, key);
968 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_versionIndependantProgramID);
969 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_programID);
975 // ShoeHorn //////////////////////////////////////////////////////////////////////////////////
977 class ShoeHorn : public IShoeHorn {
979 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
980 if(iid == IID_IUnknown) *ppv = static_cast<IShoeHorn*>(this);
981 else if(iid == XWT_clsid) *ppv = static_cast<IShoeHorn*>(this);
982 else if(iid == IID_IPersistPropertyBag) *ppv = static_cast<IPersistPropertyBag*>(this);
983 else if(iid == IID_IObjectSafety) *ppv = static_cast<IObjectSafety*>(this);
984 else { *ppv = NULL; return E_NOINTERFACE; }
985 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
988 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
989 virtual ULONG __stdcall Release() {
990 if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; }
993 virtual HRESULT __stdcall GetClassID(CLSID*) { return S_OK; }
994 virtual HRESULT __stdcall InitNew() { return S_OK; }
995 virtual HRESULT __stdcall Save(IPropertyBag*, int, int) { return S_OK; }
996 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions) { return S_OK; }
997 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions) {
998 if (pdwSupportedOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
999 if (pdwEnabledOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1003 virtual HRESULT __stdcall Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) {
1011 MultiByteToWideChar(CP_ACP, 0, "initial-xwar-url", -1, wc, 100);
1012 pPropBag->Read(wc, &v, pErrorLog);
1013 check(WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, url, 100, NULL, NULL),
1014 "WideCharToMultiByte() failed in ShoeHorn::Load()");
1017 LONG result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache", &hkey);
1018 check(result == ERROR_SUCCESS, "RegOpenKey() failed in ShoeHorn::Load()");
1020 // iterate over all the activex cache locations until we find ourselves
1021 for(int i=0; i<9; i++) {
1030 result = RegQueryValueEx(hkey, which, NULL, &type, (BYTE*)buf, &buflen);
1031 if (result != ERROR_SUCCESS)
1033 check(0, "RegQueryValueEx() failed in ShoeHorn::Load()");
1040 for(int i=0; i<200; i++) cmdline[i] = '\0';
1041 strncpy(cmdline, buf, 200);
1042 strncpy(cmdline + strlen(cmdline), "\\xwt-" BUILDID ".exe", 200 - strlen(cmdline));
1043 strncpy(cmdline + strlen(cmdline), " ", 200 - strlen(cmdline));
1044 strncpy(cmdline + strlen(cmdline), url, 200 - strlen(cmdline));
1046 PROCESS_INFORMATION pInfo;
1048 sInfo.cb = sizeof(STARTUPINFO);
1049 sInfo.lpReserved = NULL;
1050 sInfo.lpReserved2 = NULL;
1051 sInfo.cbReserved2 = 0;
1052 sInfo.lpDesktop = NULL;
1053 sInfo.lpTitle = NULL;
1057 sInfo.dwFillAttribute = 0;
1058 sInfo.wShowWindow = SW_SHOW;
1059 BOOL b = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo);
1063 check(0, "unable to locate xwt-" BUILDID ".exe in ActiveX cache folders");
1066 ShoeHorn() : m_cRef(1) { };
1068 private: long m_cRef;
1074 // ClassFactory //////////////////////////////////////////////////////////////////////////
1076 class ClassFactory : public IClassFactory {
1078 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
1079 if(iid == IID_IUnknown) *ppv = static_cast<IClassFactory*>(this);
1080 else if(iid == IID_IClassFactory) *ppv = static_cast<IClassFactory*>(this);
1083 return E_NOINTERFACE;
1085 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1089 ClassFactory() : m_cRef(1) { }
1091 virtual HRESULT __stdcall LockServer(BOOL bLock) { return S_OK; }
1092 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1093 virtual ULONG __stdcall Release() {
1094 if(InterlockedDecrement(&m_cRef) == 0) {
1101 virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
1102 if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
1103 ShoeHorn* s = new ShoeHorn;
1104 if(s == NULL) return E_OUTOFMEMORY;
1105 HRESULT hr = s->QueryInterface(iid, ppv);
1110 private: long m_cRef;
1114 extern "C" __stdcall HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) {
1115 if(clsid != XWT_clsid) return CLASS_E_CLASSNOTAVAILABLE;
1116 ClassFactory* pFactory = new ClassFactory;
1117 if(pFactory == NULL) return E_OUTOFMEMORY;
1118 HRESULT hr = pFactory->QueryInterface(iid, ppv);
1119 pFactory->Release();