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 <org/xwt/util/Hash.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);
327 // Win32DoubleBuffer /////////////////////////////////////////////////////////////////////////
329 // This is a scratch area; when blitting a translucent image, we copy the underlying data here first.
330 // Since all drawing operations are single-threaded, it's safe to use a global here.
331 static HBITMAP scratch = NULL;
332 static HDC scratch_dc = NULL;
333 static jint* scratch_bits = NULL;
334 static jint scratch_w = 0;
335 static jint scratch_h = 0;
337 #define BLT(dest, dx1, dy1, dx2, dy2, src, sx1, sy1, sx2, sy2, op) \
338 if ((dx2 - dx1 == sx2 - sx1) && (dy2 - dy1 == sy2 - sy1)) \
339 BitBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, op); \
341 StretchBlt(dest, dx1, dy1, dx2 - dx1, dy2 - dy1, src, sx1, sy1, sx2 - sx1, sy2 - sy1, op);
343 void org::xwt::plat::Win32$Win32DoubleBuffer::drawPicture(org::xwt::Picture* source0,
344 jint dx1, jint dy1, jint dx2, jint dy2,
345 jint sx1, jint sy1, jint sx2, jint sy2) {
347 org::xwt::plat::Win32$Win32Picture* source = (org::xwt::plat::Win32$Win32Picture*)source0;
349 if (source->hasalpha) {
351 if (scratch == NULL || scratch_w < dx2 - dx1 || scratch_h < dy2 - dy1) {
352 if (scratch_dc != NULL) DeleteDC(scratch_dc);
353 if (scratch != NULL) DeleteObject(scratch);
354 scratch_w = max(dx2 - dx1, scratch_w);
355 scratch_h = max(dy2 - dy1, scratch_h);
357 BITMAPINFO bitmapinfo;
358 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
359 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
360 bitmapinfo.bmiHeader.biWidth = scratch_w;
361 bitmapinfo.bmiHeader.biHeight = -1 * scratch_h;
362 bitmapinfo.bmiHeader.biPlanes = 1;
363 bitmapinfo.bmiHeader.biBitCount = 32;
364 bitmapinfo.bmiHeader.biCompression = BI_RGB;
366 // create section DIB
367 scratch = CreateDIBSection(NULL, &bitmapinfo, DIB_RGB_COLORS, (void**)&scratch_bits, NULL, 0);
368 scratch_dc = CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
369 SelectObject(scratch_dc, scratch);
372 // copy from screen to scratch
373 BitBlt((HDC)scratch_dc, 0, 0, dx2 - dx1, dy2 - dy1, (HDC)hdc, dx1, dy1, SRCCOPY);
375 // apply alpha-blending to scratch
376 jint* dat = elements(source->data);
378 for(int x = max(clipx1, dx1) - dx1; x < min(clipx2, dx2) - dx1; x++)
379 for(int y = max(clipy1, dy1) - dy1; y < min(clipy2, dy2) - dy1; y++) {
380 int sx = (x * (sx2 - sx1)) / (dx2 - dx1) + sx1;
381 int sy = (y * (sy2 - sy1)) / (dy2 - dy1) + sy1;
382 jint dst = scratch_bits[y * scratch_w + x];
383 jint src = dat[sy * source->getWidth() + sx];
384 jint alpha = (src & 0xFF000000) >> 24;
385 jint r = (((src & 0x00FF0000) >> 16) * alpha + ((dst & 0x00FF0000) >> 16) * (0xFF - alpha)) / 0xFF;
386 jint g = (((src & 0x0000FF00) >> 8) * alpha + ((dst & 0x0000FF00) >> 8) * (0xFF - alpha)) / 0xFF;
387 jint b = (((src & 0x000000FF)) * alpha + ((dst & 0x000000FF)) * (0xFF - alpha)) / 0xFF;
388 scratch_bits[y * scratch_w + x] = (r << 16) | (g << 8) | b;
391 // copy back from scratch to screen
392 BitBlt((HDC)hdc, dx1, dy1, dx2 - dx1, dy2 - dy1, (HDC)scratch_dc, 0, 0, SRCCOPY);
395 if (source->hasmask) {
396 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->maskdc, sx1, sy1, sx2, sy2, SRCAND);
397 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCPAINT);
399 BLT((HDC)hdc, dx1, dy1, dx2, dy2, (HDC)source->hdc, sx1, sy1, sx2, sy2, SRCCOPY);
406 void org::xwt::plat::Win32$Win32DoubleBuffer::drawString(jstring font, jstring text, jint x, jint y, jint color) {
408 org::xwt::plat::Win32$Win32Font* wf = org::xwt::plat::Win32::getFont(font);
409 SelectObject((HDC)hdc, (HFONT)(wf->hfont));
411 // Platform API passes us the y-pos of the bottom of the text; we need the top
414 int len = min(1024, JvGetStringUTFLength(text));
417 JvGetStringUTFRegion(text, 0, len, buf);
419 SetTextColor((HDC)hdc, PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
420 TextOut((HDC)hdc, x, y, buf, len);
423 void org::xwt::plat::Win32$Win32DoubleBuffer::fillRect(jint x, jint y, jint x2, jint y2, jint color) {
427 // sadly, the ability to change the color of a brush didn't arrive until Win2k...
428 HBRUSH brush = CreateSolidBrush(PALETTERGB((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF));
430 RECT rect = { x, y, x + w, y + h };
431 FillRect((HDC)hdc, &rect, brush);
435 void org::xwt::plat::Win32$Win32Surface::blit(org::xwt::DoubleBuffer* s, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
436 BitBlt((HDC)hdc, dx, dy, dx2 - dx, dy2 - dy, (HDC)(((org::xwt::plat::Win32$Win32DoubleBuffer*)s)->hdc), sx, sy, SRCCOPY);
439 void org::xwt::plat::Win32$Win32DoubleBuffer::natInit() {
440 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
441 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
442 SetBkMode((HDC)hdc, TRANSPARENT);
443 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
446 void org::xwt::plat::Win32$Win32DoubleBuffer::setClip(jint x, jint y, jint x2, jint y2) {
447 clipx1 = x; clipx2 = x2; clipy1 = y; clipy2 = y2;
448 HRGN hrgn = CreateRectRgn(x, y, x2, y2);
449 SelectClipRgn((HDC)hdc, hrgn);
453 void org::xwt::plat::Win32$Win32DoubleBuffer::finalize() {
454 DeleteObject((void*)hdc);
455 DeleteObject((void*)hbitmap);
460 // Win32Picture /////////////////////////////////////////////////////////////////////////
462 void org::xwt::plat::Win32$Win32Picture::natInit() {
464 BITMAPINFO bitmapinfo;
465 memset(&bitmapinfo, 0, sizeof(BITMAPINFO));
466 bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
467 bitmapinfo.bmiHeader.biWidth = w;
468 bitmapinfo.bmiHeader.biHeight = -1 * h;
469 bitmapinfo.bmiHeader.biPlanes = 1;
470 bitmapinfo.bmiHeader.biBitCount = 32;
471 bitmapinfo.bmiHeader.biCompression = BI_RGB;
473 hbitmap = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
474 hdc = (jint)CreateCompatibleDC((HDC)org::xwt::plat::Win32::desktop_dc);
475 SelectObject((HDC)hdc, (HBITMAP)hbitmap);
476 uint32_t* dat = (uint32_t*)elements(data);
477 for(int i=0; i<data->length; i++) if ((dat[i] & 0xFF000000) == 0x00000000) dat[i] = 0x00000000;
478 StretchDIBits((HDC)hdc, 0, 0, w, h, 0, 0, w, h, elements(data), &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
480 jint _copy[min(1024, data->length)];
481 jint* copy = data->length > 1024 ? (jint*)malloc(data->length * 4) : _copy;
483 memcpy(copy, elements(data), data->length * 4);
484 for(int i=0; i<data->length; i++)
485 if ((copy[i] & 0xFF000000) == 0x00000000) {
487 copy[i] = 0x00FFFFFF;
488 } else if ((copy[i] & 0xFF000000) == 0xFF000000) {
489 copy[i] = 0x00000000;
493 if (data->length > 1024) free(copy);
498 if (data->length > 1024) free(copy);
502 // hmask = (jint)CreateBitmap(w, h, 1, 1, NULL);
503 hmask = (jint)CreateCompatibleBitmap((HDC)org::xwt::plat::Win32::desktop_dc, w, h);
504 maskdc = (jint)CreateCompatibleDC(NULL);
505 SelectObject((HDC)maskdc, (HBITMAP)hmask);
506 StretchDIBits((HDC)maskdc, 0, 0, w, h, 0, 0, w, h, copy, &bitmapinfo, DIB_RGB_COLORS, SRCCOPY);
507 if (data->length > 1024) free(copy);
512 // Win32Surface /////////////////////////////////////////////////////////////////////////////
514 void org::xwt::plat::Win32$Win32Surface::natInit(jboolean framed) {
516 // Ask the message-handling thread to create a window for us
517 PostThreadMessage((DWORD)org::xwt::plat::Win32::messagePumpThread, WM_USER + 2, (WPARAM)framed, (LPARAM)this);
518 hwndCreated->block();
520 // turn on incremental GC now that we have a user-visible interface
521 // [[this is causing segfaults; enable it later...]]
522 // GC_enable_incremental();
524 ShowWindow ((HWND)hwnd, SW_SHOWDEFAULT);
525 hdc = (jint)GetDC((HWND)hwnd);
528 void org::xwt::plat::Win32$Win32Surface::finalize() { DeleteObject((void*)hwnd); }
529 void org::xwt::plat::Win32$Win32Surface::toFront() { BringWindowToTop((HWND)hwnd); }
530 void org::xwt::plat::Win32$Win32Surface::toBack() { SetWindowPos((HWND)hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
531 void org::xwt::plat::Win32$Win32Surface::_dispose() { PostMessage((HWND)hwnd, WM_USER_DISPOSE, 0, 0); }
532 void org::xwt::plat::Win32$Win32Surface::setInvisible(jboolean h) { ShowWindow((HWND)hwnd, h ? SW_HIDE : SW_SHOWNORMAL); }
533 void org::xwt::plat::Win32$Win32Surface::_setMinimized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMINIMIZED : SW_SHOWNORMAL); }
534 void org::xwt::plat::Win32$Win32Surface::_setMaximized(jboolean m) { ShowWindow((HWND)hwnd, m ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); }
535 void org::xwt::plat::Win32$Win32Surface::postCursorChange() { PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0); }
537 void org::xwt::plat::Win32$Win32Surface::setLocation(jint x, jint y) {
542 ClientToScreen((HWND)hwnd, &point);
543 GetWindowRect((HWND)hwnd, &rect);
544 SetWindowPos((HWND)hwnd, NULL, x - (point.x - rect.left), y - (point.y - rect.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
547 void org::xwt::plat::Win32$Win32Surface::setSize(jint w, jint h) {
548 RECT client_rect, window_rect;
549 GetClientRect((HWND)hwnd, &client_rect);
550 GetWindowRect((HWND)hwnd, &window_rect);
551 int addwidth = (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
552 int addheight = (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
553 SetWindowPos((HWND)hwnd, NULL, 0, 0, w + addwidth, h + addheight, SWP_NOZORDER | SWP_NOMOVE);
556 void org::xwt::plat::Win32$Win32Surface::setTitleBarText(java::lang::String* title) {
557 int len = min(1024, JvGetStringUTFLength(title));
560 JvGetStringUTFRegion(title, 0, len, buf);
561 SetWindowText((HWND)hwnd, buf);
564 void org::xwt::plat::Win32$Win32Surface::setIcon(org::xwt::Picture* p0) {
566 org::xwt::plat::Win32$Win32Picture* p = (org::xwt::plat::Win32$Win32Picture*)p0;
567 int icon_width = GetSystemMetrics(SM_CXSMICON);
568 int icon_height = GetSystemMetrics(SM_CYSMICON);
571 HBITMAP bit = CreateCompatibleBitmap((HDC)hdc, icon_width, icon_height);
572 HDC memdc = CreateCompatibleDC((HDC)hdc);
573 SelectObject(memdc, bit);
574 BLT((HDC)memdc, 0, 0, icon_width, icon_height, (HDC)(p->hdc), 0, 0, p->getWidth(), p->getHeight(), SRCCOPY);
577 jint* dat = elements(p->data);
578 HBITMAP bit_mask = CreateBitmap(icon_width, icon_height * 2, 1, 1, NULL);
579 SelectObject(memdc, bit_mask);
580 for(int x=0; x<icon_width; x++)
581 for(int y=0; y<icon_height; y++) {
582 int source = dat[(x * p->getWidth()) / icon_width + ((y * p->getHeight()) / icon_height) * (p->getWidth())];
583 if ((source & 0xFF000000) != 0x00000000) SetPixel(memdc, x, y, PALETTERGB(0, 0, 0));
584 else SetPixel(memdc, x, y, PALETTERGB(255, 255, 255));
587 // instantiate the icon and assign it to the window class
590 ici.hbmMask = bit_mask;
592 HICON hicon = CreateIconIndirect(&ici);
593 HICON oldicon = (HICON)SetClassLong((HWND)hwnd, GCL_HICONSM, (LONG)hicon);
594 if (oldicon != NULL) DestroyIcon(oldicon);
598 static jstring keyToString(WPARAM wParam);
599 jint org::xwt::plat::Win32$Win32Surface::WndProc(jint _hwnd, jint _iMsg, jint _wParam, jint _lParam) {
601 UINT iMsg = (UINT)_iMsg;
602 WPARAM wParam = (WPARAM)_wParam;
603 LPARAM lParam = (LPARAM)_lParam;
604 int oldmousex, oldmousey;
614 case WM_DEVMODECHANGE: break; // FEATURE: color depth changed
615 case WM_DISPLAYCHANGE: break; // FEATURE: screen size changed
616 case WM_FONTCHANGE: break; // FEATURE: set of fonts changed
617 case WM_MOUSEWHEEL: break; // FEATURE: Mouse Wheel
619 case WM_SYSKEYDOWN: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
621 KeyPressed(keyToString(wParam));
624 case WM_SYSKEYUP: if (GetKeyState(VK_MENU) >> (sizeof(SHORT) * 8 - 1) == 0) return 0;
626 KeyReleased(keyToString(wParam));
629 case WM_SETFOCUS: Focused(true); return 0;
630 case WM_KILLFOCUS: Focused(false); return 0;
631 case WM_LBUTTONDBLCLK: DoubleClick(1); return 0;
632 case WM_RBUTTONDBLCLK: DoubleClick(2); return 0;
633 case WM_MBUTTONDBLCLK: DoubleClick(3); return 0;
634 case WM_LBUTTONDOWN: Press(1); return 0;
635 case WM_RBUTTONDOWN: Press(2); return 0;
636 case WM_MBUTTONDOWN: Press(3); return 0;
637 case WM_CLOSE: Close(); return 0;
638 case WM_ERASEBKGND: return 0;
643 Release(iMsg == WM_LBUTTONUP ? 1 : (iMsg == WM_RBUTTONUP ? 2 : 3));
644 if (captured && !inside) {
646 SetCursor((HCURSOR)previous_cursor);
651 GetClientRect((HWND)hwnd, &rect);
652 PosChange(rect.left, rect.top);
656 if (wParam == SIZE_MINIMIZED) {
657 if (maximized) Maximized(false);
659 } else if (wParam == SIZE_MAXIMIZED) {
660 if (minimized) Minimized(false);
663 if (minimized) Minimized(false);
664 if (maximized) Maximized(false);
666 // deliberately fall through to WM_SIZING
669 GetClientRect((HWND)hwnd, &rect);
670 SizeChange(rect.right - rect.left, rect.bottom - rect.top);
674 if (mousex == lParam & 0xFFFF && mousey == (lParam & 0xFFFF0000) >> 16) return 0;
676 GetClientRect((HWND)hwnd, &rect);
677 point.x = mouse_x = lParam & 0xFFFF;
678 point.y = mouse_y = (lParam & 0xFFFF0000) >> 16;
679 ClientToScreen((HWND)hwnd, &point);
680 hwnd2 = WindowFromPoint(point);
682 newinside = hwnd2 == (HWND)hwnd && mouse_x > 0 && mouse_y > 0 && mouse_x < (rect.right - rect.left) && mouse_y < (rect.bottom - rect.top) ? 1 : 0;
684 Move(mouse_x, mouse_y);
686 if (newinside && !inside) {
688 SetCapture((HWND)hwnd);
690 previous_cursor = (jint)GetCursor();
691 PostMessage((HWND)hwnd, WM_USER_SETCURSOR, 0, 0);
693 } else if (!newinside && inside) {
695 if (!button1 && !button2 && !button3) {
698 SetCursor((HCURSOR)previous_cursor);
704 case WM_USER_SETCURSOR:
705 // I can't find documentation of this anywhere, but in my experience, an event must be received between an invocation
706 // of SetCapture() and SetCursor(). Furthermore, it seems that after calling SetCursor(), the cursor will not change until a
707 // return from WndProc (ie the completion of the processing of some event). Hence, we use WM_USER to indicate that the screen
708 // cursor should be re-set to "current_cursor".
709 SetCursor((HCURSOR)current_cursor);
712 case WM_USER_DISPOSE:
713 // used to signal that we should destroy ourselves
714 DestroyWindow((HWND)hwnd);
717 case WM_GETMINMAXINFO:
718 mmi = (MINMAXINFO*)lParam;
719 mmi->ptMinTrackSize.x = root->dmin(0);
720 mmi->ptMinTrackSize.y = root->dmin(1);
721 mmi->ptMaxTrackSize.x = root->dmax(0);
722 mmi->ptMaxTrackSize.y = root->dmax(1);
727 BeginPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
728 Dirty(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
730 EndPaint((HWND)org::xwt::plat::Win32$Win32Surface::hwnd, &ps);
736 return DefWindowProc((HWND)hwnd, iMsg, wParam, lParam);
740 // Key Translator Helper /////////////////////////////////////////////////////////////////////
742 static char keyarr [256] = { 0 };
743 static jstring keyToString(WPARAM wParam) {
745 keyarr[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
746 keyarr[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
747 keyarr[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
748 keyarr[VK_SHIFT] = GetKeyState(VK_SHIFT);
750 if (ToAscii(wParam, 0, (BYTE*)keyarr, (WORD*)arr, 0) == 1) {
752 case '\t': return JvNewStringLatin1("tab");
753 case 0x1b: return JvNewStringLatin1("escape");
754 case '\n': return JvNewStringLatin1("enter");
755 case '\r': return JvNewStringLatin1("enter");
756 case 0x08: return JvNewStringLatin1("back_space");
757 default: return JvNewStringLatin1(arr, 1);
760 } else switch (wParam) {
761 case VK_CLEAR: return JvNewStringLatin1("clear");
762 case VK_SHIFT: return JvNewStringLatin1("shift");
763 case VK_CONTROL: return JvNewStringLatin1("control");
764 case VK_CAPITAL: return JvNewStringLatin1("caps_lock");
765 case VK_MENU: return JvNewStringLatin1("alt");
766 case VK_PAUSE: return JvNewStringLatin1("pause");
767 case VK_PRIOR: return JvNewStringLatin1("page_up");
768 case VK_NEXT: return JvNewStringLatin1("page_down");
769 case VK_END: return JvNewStringLatin1("end");
770 case VK_HOME: return JvNewStringLatin1("home");
771 case VK_LEFT: return JvNewStringLatin1("left");
772 case VK_UP: return JvNewStringLatin1("up");
773 case VK_RIGHT: return JvNewStringLatin1("right");
774 case VK_DOWN: return JvNewStringLatin1("down");
775 case VK_INSERT: return JvNewStringLatin1("insert");
776 case VK_DELETE: return JvNewStringLatin1("delete");
777 case VK_NUMPAD0: return JvNewStringLatin1("numpad0");
778 case VK_NUMPAD1: return JvNewStringLatin1("numpad1");
779 case VK_NUMPAD2: return JvNewStringLatin1("numpad2");
780 case VK_NUMPAD3: return JvNewStringLatin1("numpad3");
781 case VK_NUMPAD4: return JvNewStringLatin1("numpad4");
782 case VK_NUMPAD5: return JvNewStringLatin1("numpad5");
783 case VK_NUMPAD6: return JvNewStringLatin1("numpad6");
784 case VK_NUMPAD7: return JvNewStringLatin1("numpad7");
785 case VK_NUMPAD8: return JvNewStringLatin1("numpad8");
786 case VK_NUMPAD9: return JvNewStringLatin1("numpad9");
787 case VK_F1: return JvNewStringLatin1("f1");
788 case VK_F2: return JvNewStringLatin1("f2");
789 case VK_F3: return JvNewStringLatin1("f3");
790 case VK_F4: return JvNewStringLatin1("f4");
791 case VK_F5: return JvNewStringLatin1("f5");
792 case VK_F6: return JvNewStringLatin1("f6");
793 case VK_F7: return JvNewStringLatin1("f7");
794 case VK_F8: return JvNewStringLatin1("f8");
795 case VK_F9: return JvNewStringLatin1("f9");
796 case VK_F10: return JvNewStringLatin1("f10");
797 case VK_F11: return JvNewStringLatin1("f11");
798 case VK_F12: return JvNewStringLatin1("f12");
799 case VK_NUMLOCK: return JvNewStringLatin1("num_lock");
800 case VK_SCROLL: return JvNewStringLatin1("scroll_lock");
801 case VK_LSHIFT: return JvNewStringLatin1("shift");
802 case VK_RSHIFT: return JvNewStringLatin1("shift");
803 case VK_LCONTROL: return JvNewStringLatin1("control");
804 case VK_RCONTROL: return JvNewStringLatin1("control");
812 ///////////////////////////////////////////////////////////////////////////////////////
813 ///////////////////////////////////////////////////////////////////////////////////////
814 ///////////////////////////////////////////////////////////////////////////////////////
816 #else /* COMPILE_DLL */
820 // A simple DLL to invoke xwt.exe and pass it any arguments found in the <object/> tag
824 #include <initguid.h>
831 // Globals ////////////////////////////////////////////////////////////////////////
835 #define CLSID_STRING_SIZE 39
837 const char XWT_friendlyName[] = "XWT ActiveX Control (Hydrogen)";
838 const char XWT_versionIndependantProgramID[] = "XWT.ActiveX";
839 const char XWT_programID[] = "XWT.ActiveX.Hydrogen";
840 extern "C" const CLSID XWT_clsid = { 0xc60d6d23, 0x3a7d, 0x11d6, { 0x82, 0xf9, 0x0, 0x50, 0x56, 0xca, 0x92, 0x50 } };
842 static HMODULE g_hModule = NULL; //DLL handle
847 // Superclasses ////////////////////////////////////////////////////////////////////////
849 // Option bit definitions for IObjectSafety:
850 #define INTERFACESAFE_FOR_UNTRUSTED_CALLER 0x00000001 // Caller of interface may be untrusted
851 #define INTERFACESAFE_FOR_UNTRUSTED_DATA 0x00000002 // Data passed into interface may be untrusted
853 // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
854 DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);
856 interface IObjectSafety : public IUnknown {
858 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) = 0;
859 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) = 0;
862 interface IShoeHorn : IPersistPropertyBag, IObjectSafety { };
866 // Entry Points ////////////////////////////////////////////////////////////////////////
868 // to get mingw to stop nagging me
869 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { }
871 // determines whether or not the DLL can be unloaded; always allow this since we don't do too much
872 STDAPI __declspec(dllexport) DllCanUnloadNow(void) { return S_OK; }
874 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID /*lpReserved*/) {
875 if (dwReason == DLL_PROCESS_ATTACH) g_hModule = (HINSTANCE)hModule;
881 // Other ///////////////////////////////////////////////////////////////////////////////////
883 // simple assert() replacement that pops open a message box if there are errors
884 void check(int val, char* message) {
886 MessageBox (NULL, message, "XWT Critical Abort", MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND);
891 void clsidToString(const CLSID& clsid, char* str, int length) {
892 check(length >= CLSID_STRING_SIZE, "clsidToString(): string too short");
893 LPOLESTR wide_str = NULL;
894 HRESULT hr = StringFromCLSID(clsid, &wide_str);
895 check(SUCCEEDED(hr), "StringFromCLSID() failed in clsidToString()");
896 wcstombs(str, wide_str, length);
897 CoTaskMemFree(wide_str);
900 void setRegistryKey(const char* key, const char* subkey, const char* value) {
904 if (subkey != NULL) {
905 strcat(keyBuf, "\\");
906 strcat(keyBuf, subkey );
908 long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, keyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
910 check(RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, strlen(value) + 1) == ERROR_SUCCESS,
911 "RegSetValueEx() failed in setRegistryKey()");
915 void deleteRegistryKey(HKEY parent, const char* target) {
917 RegOpenKeyEx(parent, target, 0, KEY_ALL_ACCESS, &hKeyChild);
919 // Iterate over children, deleting them
923 while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) {
924 deleteRegistryKey(hKeyChild, szBuffer);
928 RegCloseKey(hKeyChild);
929 RegDeleteKey(parent, target);
932 STDAPI __declspec(dllexport) DllRegisterServer(void) {
933 char moduleName[512];
934 HRESULT result = GetModuleFileName(g_hModule, moduleName, sizeof(moduleName)/sizeof(char));
935 check(result, "GetModuleFileName() failed in RegisterServer()");
937 char clsidString[CLSID_STRING_SIZE];
938 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
942 strcpy(key, "CLSID\\");
943 strcat(key, clsidString);
945 setRegistryKey(key, NULL, XWT_friendlyName);
946 setRegistryKey(key, "InprocServer32", moduleName);
947 setRegistryKey(key, "ProgID", XWT_programID);
948 setRegistryKey(key, "VersionIndependentProgID", XWT_versionIndependantProgramID);
949 setRegistryKey(XWT_versionIndependantProgramID, NULL, XWT_friendlyName);
950 setRegistryKey(XWT_versionIndependantProgramID, "CLSID", clsidString);
951 setRegistryKey(XWT_versionIndependantProgramID, "CurVer", XWT_programID);
952 setRegistryKey(XWT_programID, NULL, XWT_friendlyName);
953 setRegistryKey(XWT_programID, "CLSID", clsidString);
957 STDAPI __declspec(dllexport) DllUnregisterServer(void) {
958 char clsidString[CLSID_STRING_SIZE];
959 clsidToString(XWT_clsid, clsidString, sizeof(clsidString));
963 strcpy(key, "CLSID\\");
964 strcat(key, clsidString);
966 deleteRegistryKey(HKEY_CLASSES_ROOT, key);
967 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_versionIndependantProgramID);
968 deleteRegistryKey(HKEY_CLASSES_ROOT, XWT_programID);
974 // ShoeHorn //////////////////////////////////////////////////////////////////////////////////
976 class ShoeHorn : public IShoeHorn {
978 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
979 if(iid == IID_IUnknown) *ppv = static_cast<IShoeHorn*>(this);
980 else if(iid == XWT_clsid) *ppv = static_cast<IShoeHorn*>(this);
981 else if(iid == IID_IPersistPropertyBag) *ppv = static_cast<IPersistPropertyBag*>(this);
982 else if(iid == IID_IObjectSafety) *ppv = static_cast<IObjectSafety*>(this);
983 else { *ppv = NULL; return E_NOINTERFACE; }
984 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
987 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
988 virtual ULONG __stdcall Release() {
989 if(InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; }
992 virtual HRESULT __stdcall GetClassID(CLSID*) { return S_OK; }
993 virtual HRESULT __stdcall InitNew() { return S_OK; }
994 virtual HRESULT __stdcall Save(IPropertyBag*, int, int) { return S_OK; }
995 virtual HRESULT __stdcall SetInterfaceSafetyOptions(REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions) { return S_OK; }
996 virtual HRESULT __stdcall GetInterfaceSafetyOptions(REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions) {
997 if (pdwSupportedOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
998 if (pdwEnabledOptions != NULL) *pdwSupportedOptions |= INTERFACESAFE_FOR_UNTRUSTED_DATA;
1002 virtual HRESULT __stdcall Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) {
1010 MultiByteToWideChar(CP_ACP, 0, "initial-xwar-url", -1, wc, 100);
1011 pPropBag->Read(wc, &v, pErrorLog);
1012 check(WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, url, 100, NULL, NULL),
1013 "WideCharToMultiByte() failed in ShoeHorn::Load()");
1016 LONG result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache", &hkey);
1017 check(result == ERROR_SUCCESS, "RegOpenKey() failed in ShoeHorn::Load()");
1019 // iterate over all the activex cache locations until we find ourselves
1020 for(int i=0; i<9; i++) {
1029 result = RegQueryValueEx(hkey, which, NULL, &type, (BYTE*)buf, &buflen);
1030 check(result == ERROR_SUCCESS, "RegQueryValueEx() failed in ShoeHorn::Load()");
1034 for(int i=0; i<200; i++) cmdline[i] = '\0';
1035 strncpy(cmdline, buf, 200);
1036 strncpy(cmdline + strlen(cmdline), "\\xwt.exe", 200 - strlen(cmdline));
1037 strncpy(cmdline + strlen(cmdline), " ", 200 - strlen(cmdline));
1038 strncpy(cmdline + strlen(cmdline), url, 200 - strlen(cmdline));
1040 PROCESS_INFORMATION pInfo;
1042 sInfo.cb = sizeof(STARTUPINFO);
1043 sInfo.lpReserved = NULL;
1044 sInfo.lpReserved2 = NULL;
1045 sInfo.cbReserved2 = 0;
1046 sInfo.lpDesktop = NULL;
1047 sInfo.lpTitle = NULL;
1051 sInfo.dwFillAttribute = 0;
1052 sInfo.wShowWindow = SW_SHOW;
1053 BOOL b = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sInfo, &pInfo);
1057 check(0, "unable to locate xwt.exe in ActiveX cache folders");
1060 ShoeHorn() : m_cRef(1) { };
1062 private: long m_cRef;
1068 // ClassFactory //////////////////////////////////////////////////////////////////////////
1070 class ClassFactory : public IClassFactory {
1072 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) {
1073 if(iid == IID_IUnknown) *ppv = static_cast<IClassFactory*>(this);
1074 else if(iid == IID_IClassFactory) *ppv = static_cast<IClassFactory*>(this);
1077 return E_NOINTERFACE;
1079 reinterpret_cast<IUnknown*>(*ppv)->AddRef();
1083 ClassFactory() : m_cRef(1) { }
1085 virtual HRESULT __stdcall LockServer(BOOL bLock) { return S_OK; }
1086 virtual ULONG __stdcall AddRef() { return InterlockedIncrement(&m_cRef); }
1087 virtual ULONG __stdcall Release() {
1088 if(InterlockedDecrement(&m_cRef) == 0) {
1095 virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
1096 if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
1097 ShoeHorn* s = new ShoeHorn;
1098 if(s == NULL) return E_OUTOFMEMORY;
1099 HRESULT hr = s->QueryInterface(iid, ppv);
1104 private: long m_cRef;
1108 extern "C" __stdcall HRESULT DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) {
1109 if(clsid != XWT_clsid) return CLASS_E_CLASSNOTAVAILABLE;
1110 ClassFactory* pFactory = new ClassFactory;
1111 if(pFactory == NULL) return E_OUTOFMEMORY;
1112 HRESULT hr = pFactory->QueryInterface(iid, ppv);
1113 pFactory->Release();