2 * Android driver initialisation functions
4 * Copyright 1996, 2013, 2017 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSSTRUCT
22 #define NONAMELESSUNION
24 #include "wine/port.h"
34 #include "wine/server.h"
35 #include "wine/library.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(android
);
40 unsigned int screen_width
= 0;
41 unsigned int screen_height
= 0;
42 RECT virtual_screen_rect
= { 0, 0, 0, 0 };
44 MONITORINFOEXW default_monitor
=
46 sizeof(default_monitor
), /* cbSize */
47 { 0, 0, 0, 0 }, /* rcMonitor */
48 { 0, 0, 0, 0 }, /* rcWork */
49 MONITORINFOF_PRIMARY
, /* dwFlags */
50 { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */
53 static const unsigned int screen_bpp
= 32; /* we don't support other modes */
55 static int device_init_done
;
59 struct gdi_physdev dev
;
62 static const struct gdi_dc_funcs android_drv_funcs
;
65 /******************************************************************************
68 void init_monitors( int width
, int height
)
70 static const WCHAR trayW
[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
72 HWND hwnd
= FindWindowW( trayW
, NULL
);
74 virtual_screen_rect
.right
= width
;
75 virtual_screen_rect
.bottom
= height
;
76 default_monitor
.rcMonitor
= default_monitor
.rcWork
= virtual_screen_rect
;
78 if (!hwnd
|| !IsWindowVisible( hwnd
)) return;
79 if (!GetWindowRect( hwnd
, &rect
)) return;
80 if (rect
.top
) default_monitor
.rcWork
.bottom
= rect
.top
;
81 else default_monitor
.rcWork
.top
= rect
.bottom
;
82 TRACE( "found tray %p %s work area %s\n", hwnd
,
83 wine_dbgstr_rect( &rect
), wine_dbgstr_rect( &default_monitor
.rcWork
));
87 /******************************************************************************
90 void set_screen_dpi( DWORD dpi
)
92 static const WCHAR dpi_key_name
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
93 static const WCHAR dpi_value_name
[] = {'L','o','g','P','i','x','e','l','s',0};
96 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG
, dpi_key_name
, &hkey
))
98 RegSetValueExW( hkey
, dpi_value_name
, 0, REG_DWORD
, (void *)&dpi
, sizeof(DWORD
) );
103 /**********************************************************************
104 * fetch_display_metrics
106 static void fetch_display_metrics(void)
108 if (wine_get_java_vm()) return; /* for Java threads it will be set when the top view is created */
110 SERVER_START_REQ( get_window_rectangles
)
112 req
->handle
= wine_server_user_handle( GetDesktopWindow() );
113 req
->relative
= COORDS_CLIENT
;
114 if (!wine_server_call( req
))
116 screen_width
= reply
->window
.right
;
117 screen_height
= reply
->window
.bottom
;
122 init_monitors( screen_width
, screen_height
);
123 TRACE( "screen %ux%u\n", screen_width
, screen_height
);
127 /**********************************************************************
130 * Perform initializations needed upon creation of the first device.
132 static void device_init(void)
134 device_init_done
= TRUE
;
135 fetch_display_metrics();
139 /******************************************************************************
140 * create_android_physdev
142 static ANDROID_PDEVICE
*create_android_physdev(void)
144 ANDROID_PDEVICE
*physdev
;
146 if (!device_init_done
) device_init();
148 if (!(physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) ))) return NULL
;
152 /**********************************************************************
155 static BOOL
ANDROID_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
156 LPCWSTR output
, const DEVMODEW
* initData
)
158 ANDROID_PDEVICE
*physdev
= create_android_physdev();
160 if (!physdev
) return FALSE
;
162 push_dc_driver( pdev
, &physdev
->dev
, &android_drv_funcs
);
167 /**********************************************************************
168 * ANDROID_CreateCompatibleDC
170 static BOOL
ANDROID_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
172 ANDROID_PDEVICE
*physdev
= create_android_physdev();
174 if (!physdev
) return FALSE
;
176 push_dc_driver( pdev
, &physdev
->dev
, &android_drv_funcs
);
181 /**********************************************************************
184 static BOOL
ANDROID_DeleteDC( PHYSDEV dev
)
186 HeapFree( GetProcessHeap(), 0, dev
);
191 /***********************************************************************
192 * ANDROID_GetDeviceCaps
194 static INT
ANDROID_GetDeviceCaps( PHYSDEV dev
, INT cap
)
198 case HORZRES
: return screen_width
;
199 case VERTRES
: return screen_height
;
200 case DESKTOPHORZRES
: return virtual_screen_rect
.right
- virtual_screen_rect
.left
;
201 case DESKTOPVERTRES
: return virtual_screen_rect
.bottom
- virtual_screen_rect
.top
;
202 case BITSPIXEL
: return screen_bpp
;
204 dev
= GET_NEXT_PHYSDEV( dev
, pGetDeviceCaps
);
205 return dev
->funcs
->pGetDeviceCaps( dev
, cap
);
210 /***********************************************************************
211 * ANDROID_ChangeDisplaySettingsEx
213 LONG CDECL
ANDROID_ChangeDisplaySettingsEx( LPCWSTR devname
, LPDEVMODEW devmode
,
214 HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
216 FIXME( "(%s,%p,%p,0x%08x,%p)\n", debugstr_w( devname
), devmode
, hwnd
, flags
, lpvoid
);
217 return DISP_CHANGE_SUCCESSFUL
;
221 /***********************************************************************
222 * ANDROID_GetMonitorInfo
224 BOOL CDECL
ANDROID_GetMonitorInfo( HMONITOR handle
, LPMONITORINFO info
)
226 if (handle
!= (HMONITOR
)1)
228 SetLastError( ERROR_INVALID_HANDLE
);
231 info
->rcMonitor
= default_monitor
.rcMonitor
;
232 info
->rcWork
= default_monitor
.rcWork
;
233 info
->dwFlags
= default_monitor
.dwFlags
;
234 if (info
->cbSize
>= sizeof(MONITORINFOEXW
))
235 lstrcpyW( ((MONITORINFOEXW
*)info
)->szDevice
, default_monitor
.szDevice
);
240 /***********************************************************************
241 * ANDROID_EnumDisplayMonitors
243 BOOL CDECL
ANDROID_EnumDisplayMonitors( HDC hdc
, LPRECT rect
, MONITORENUMPROC proc
, LPARAM lp
)
250 if (!GetDCOrgEx( hdc
, &origin
)) return FALSE
;
251 if (GetClipBox( hdc
, &limit
) == ERROR
) return FALSE
;
253 if (rect
&& !IntersectRect( &limit
, &limit
, rect
)) return TRUE
;
255 monrect
= default_monitor
.rcMonitor
;
256 OffsetRect( &monrect
, -origin
.x
, -origin
.y
);
257 if (IntersectRect( &monrect
, &monrect
, &limit
))
258 if (!proc( (HMONITOR
)1, hdc
, &monrect
, lp
))
264 if (!rect
|| IntersectRect( &unused
, &default_monitor
.rcMonitor
, rect
))
265 if (!proc( (HMONITOR
)1, 0, &default_monitor
.rcMonitor
, lp
))
272 /***********************************************************************
273 * ANDROID_EnumDisplaySettingsEx
275 BOOL CDECL
ANDROID_EnumDisplaySettingsEx( LPCWSTR name
, DWORD n
, LPDEVMODEW devmode
, DWORD flags
)
277 static const WCHAR dev_name
[CCHDEVICENAME
] =
278 { 'W','i','n','e',' ','A','n','d','r','o','i','d',' ','d','r','i','v','e','r',0 };
280 devmode
->dmSize
= offsetof( DEVMODEW
, dmICMMethod
);
281 devmode
->dmSpecVersion
= DM_SPECVERSION
;
282 devmode
->dmDriverVersion
= DM_SPECVERSION
;
283 memcpy( devmode
->dmDeviceName
, dev_name
, sizeof(dev_name
) );
284 devmode
->dmDriverExtra
= 0;
285 devmode
->u2
.dmDisplayFlags
= 0;
286 devmode
->dmDisplayFrequency
= 0;
287 devmode
->u1
.s2
.dmPosition
.x
= 0;
288 devmode
->u1
.s2
.dmPosition
.y
= 0;
289 devmode
->u1
.s2
.dmDisplayOrientation
= 0;
290 devmode
->u1
.s2
.dmDisplayFixedOutput
= 0;
292 if (n
== ENUM_CURRENT_SETTINGS
|| n
== ENUM_REGISTRY_SETTINGS
) n
= 0;
295 devmode
->dmPelsWidth
= screen_width
;
296 devmode
->dmPelsHeight
= screen_height
;
297 devmode
->dmBitsPerPel
= screen_bpp
;
298 devmode
->dmDisplayFrequency
= 60;
299 devmode
->dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
;
300 TRACE( "mode %d -- %dx%d %d bpp @%d Hz\n", n
,
301 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
,
302 devmode
->dmBitsPerPel
, devmode
->dmDisplayFrequency
);
305 TRACE( "mode %d -- not present\n", n
);
306 SetLastError( ERROR_NO_MORE_FILES
);
311 /**********************************************************************
312 * ANDROID_wine_get_wgl_driver
314 static struct opengl_funcs
* ANDROID_wine_get_wgl_driver( PHYSDEV dev
, UINT version
)
316 struct opengl_funcs
*ret
;
318 if (!(ret
= get_wgl_driver( version
)))
320 dev
= GET_NEXT_PHYSDEV( dev
, wine_get_wgl_driver
);
321 ret
= dev
->funcs
->wine_get_wgl_driver( dev
, version
);
327 static const struct gdi_dc_funcs android_drv_funcs
=
329 NULL
, /* pAbortDoc */
330 NULL
, /* pAbortPath */
331 NULL
, /* pAlphaBlend */
332 NULL
, /* pAngleArc */
335 NULL
, /* pBeginPath */
336 NULL
, /* pBlendImage */
338 NULL
, /* pCloseFigure */
339 ANDROID_CreateCompatibleDC
, /* pCreateCompatibleDC */
340 ANDROID_CreateDC
, /* pCreateDC */
341 ANDROID_DeleteDC
, /* pDeleteDC */
342 NULL
, /* pDeleteObject */
343 NULL
, /* pDeviceCapabilities */
348 NULL
, /* pEnumFonts */
349 NULL
, /* pEnumICMProfiles */
350 NULL
, /* pExcludeClipRect */
351 NULL
, /* pExtDeviceMode */
352 NULL
, /* pExtEscape */
353 NULL
, /* pExtFloodFill */
354 NULL
, /* pExtSelectClipRgn */
355 NULL
, /* pExtTextOut */
356 NULL
, /* pFillPath */
358 NULL
, /* pFlattenPath */
359 NULL
, /* pFontIsLinked */
360 NULL
, /* pFrameRgn */
361 NULL
, /* pGdiComment */
362 NULL
, /* pGetBoundsRect */
363 NULL
, /* pGetCharABCWidths */
364 NULL
, /* pGetCharABCWidthsI */
365 NULL
, /* pGetCharWidth */
366 ANDROID_GetDeviceCaps
, /* pGetDeviceCaps */
367 NULL
, /* pGetDeviceGammaRamp */
368 NULL
, /* pGetFontData */
369 NULL
, /* pGetFontRealizationInfo */
370 NULL
, /* pGetFontUnicodeRanges */
371 NULL
, /* pGetGlyphIndices */
372 NULL
, /* pGetGlyphOutline */
373 NULL
, /* pGetICMProfile */
374 NULL
, /* pGetImage */
375 NULL
, /* pGetKerningPairs */
376 NULL
, /* pGetNearestColor */
377 NULL
, /* pGetOutlineTextMetrics */
378 NULL
, /* pGetPixel */
379 NULL
, /* pGetSystemPaletteEntries */
380 NULL
, /* pGetTextCharsetInfo */
381 NULL
, /* pGetTextExtentExPoint */
382 NULL
, /* pGetTextExtentExPointI */
383 NULL
, /* pGetTextFace */
384 NULL
, /* pGetTextMetrics */
385 NULL
, /* pGradientFill */
386 NULL
, /* pIntersectClipRect */
387 NULL
, /* pInvertRgn */
389 NULL
, /* pModifyWorldTransform */
391 NULL
, /* pOffsetClipRgn */
392 NULL
, /* pOffsetViewportOrg */
393 NULL
, /* pOffsetWindowOrg */
394 NULL
, /* pPaintRgn */
397 NULL
, /* pPolyBezier */
398 NULL
, /* pPolyBezierTo */
399 NULL
, /* pPolyDraw */
400 NULL
, /* pPolyPolygon */
401 NULL
, /* pPolyPolyline */
403 NULL
, /* pPolyline */
404 NULL
, /* pPolylineTo */
405 NULL
, /* pPutImage */
406 NULL
, /* pRealizeDefaultPalette */
407 NULL
, /* pRealizePalette */
408 NULL
, /* pRectangle */
410 NULL
, /* pRestoreDC */
411 NULL
, /* pRoundRect */
413 NULL
, /* pScaleViewportExt */
414 NULL
, /* pScaleWindowExt */
415 NULL
, /* pSelectBitmap */
416 NULL
, /* pSelectBrush */
417 NULL
, /* pSelectClipPath */
418 NULL
, /* pSelectFont */
419 NULL
, /* pSelectPalette */
420 NULL
, /* pSelectPen */
421 NULL
, /* pSetArcDirection */
422 NULL
, /* pSetBkColor */
423 NULL
, /* pSetBkMode */
424 NULL
, /* pSetBoundsRect */
425 NULL
, /* pSetDCBrushColor */
426 NULL
, /* pSetDCPenColor */
427 NULL
, /* pSetDIBitsToDevice */
428 NULL
, /* pSetDeviceClipping */
429 NULL
, /* pSetDeviceGammaRamp */
430 NULL
, /* pSetLayout */
431 NULL
, /* pSetMapMode */
432 NULL
, /* pSetMapperFlags */
433 NULL
, /* pSetPixel */
434 NULL
, /* pSetPolyFillMode */
436 NULL
, /* pSetRelAbs */
437 NULL
, /* pSetStretchBltMode */
438 NULL
, /* pSetTextAlign */
439 NULL
, /* pSetTextCharacterExtra */
440 NULL
, /* pSetTextColor */
441 NULL
, /* pSetTextJustification */
442 NULL
, /* pSetViewportExt */
443 NULL
, /* pSetViewportOrg */
444 NULL
, /* pSetWindowExt */
445 NULL
, /* pSetWindowOrg */
446 NULL
, /* pSetWorldTransform */
447 NULL
, /* pStartDoc */
448 NULL
, /* pStartPage */
449 NULL
, /* pStretchBlt */
450 NULL
, /* pStretchDIBits */
451 NULL
, /* pStrokeAndFillPath */
452 NULL
, /* pStrokePath */
453 NULL
, /* pUnrealizePalette */
454 NULL
, /* pWidenPath */
455 ANDROID_wine_get_wgl_driver
, /* wine_get_wgl_driver */
456 GDI_PRIORITY_GRAPHICS_DRV
/* priority */
460 /******************************************************************************
461 * ANDROID_get_gdi_driver
463 const struct gdi_dc_funcs
* CDECL
ANDROID_get_gdi_driver( unsigned int version
)
465 if (version
!= WINE_GDI_DRIVER_VERSION
)
467 ERR( "version mismatch, gdi32 wants %u but wineandroid has %u\n", version
, WINE_GDI_DRIVER_VERSION
);
470 return &android_drv_funcs
;
474 static const JNINativeMethod methods
[] =
476 { "wine_desktop_changed", "(II)V", desktop_changed
},
477 { "wine_config_changed", "(I)V", config_changed
},
478 { "wine_surface_changed", "(ILandroid/view/Surface;Z)V", surface_changed
},
479 { "wine_motion_event", "(IIIIII)Z", motion_event
},
480 { "wine_keyboard_event", "(IIII)Z", keyboard_event
},
483 #define DECL_FUNCPTR(f) typeof(f) * p##f = NULL
484 #define LOAD_FUNCPTR(lib, func) do { \
485 if ((p##func = wine_dlsym( lib, #func, NULL, 0 )) == NULL) \
486 { ERR( "can't find symbol %s\n", #func); return; } \
489 DECL_FUNCPTR( __android_log_print
);
490 DECL_FUNCPTR( ANativeWindow_fromSurface
);
491 DECL_FUNCPTR( ANativeWindow_release
);
492 DECL_FUNCPTR( hw_get_module
);
494 struct gralloc_module_t
*gralloc_module
= NULL
;
497 #define DT_GNU_HASH 0x6ffffef5
500 static unsigned int gnu_hash( const char *name
)
502 unsigned int h
= 5381;
503 while (*name
) h
= h
* 33 + (unsigned char)*name
++;
507 static unsigned int hash_symbol( const char *name
)
509 unsigned int hi
, hash
= 0;
512 hash
= (hash
<< 4) + (unsigned char)*name
++;
513 hi
= hash
& 0xf0000000;
520 static void *find_symbol( const struct dl_phdr_info
* info
, const char *var
, int type
)
522 const ElfW(Dyn
) *dyn
= NULL
;
523 const ElfW(Phdr
) *ph
;
524 const ElfW(Sym
) *symtab
= NULL
;
525 const Elf32_Word
*hashtab
= NULL
;
526 const Elf32_Word
*gnu_hashtab
= NULL
;
527 const char *strings
= NULL
;
530 for (ph
= info
->dlpi_phdr
; ph
< &info
->dlpi_phdr
[info
->dlpi_phnum
]; ++ph
)
532 if (PT_DYNAMIC
== ph
->p_type
)
534 dyn
= (const ElfW(Dyn
) *)(info
->dlpi_addr
+ ph
->p_vaddr
);
538 if (!dyn
) return NULL
;
542 if (dyn
->d_tag
== DT_STRTAB
)
543 strings
= (const char*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
544 if (dyn
->d_tag
== DT_SYMTAB
)
545 symtab
= (const ElfW(Sym
) *)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
546 if (dyn
->d_tag
== DT_HASH
)
547 hashtab
= (const Elf32_Word
*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
548 if (dyn
->d_tag
== DT_GNU_HASH
)
549 gnu_hashtab
= (const Elf32_Word
*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
553 if (!symtab
|| !strings
) return NULL
;
555 if (gnu_hashtab
) /* new style hash table */
557 const unsigned int hash
= gnu_hash(var
);
558 const Elf32_Word nbuckets
= gnu_hashtab
[0];
559 const Elf32_Word symbias
= gnu_hashtab
[1];
560 const Elf32_Word nwords
= gnu_hashtab
[2];
561 const ElfW(Addr
) *bitmask
= (const ElfW(Addr
) *)(gnu_hashtab
+ 4);
562 const Elf32_Word
*buckets
= (const Elf32_Word
*)(bitmask
+ nwords
);
563 const Elf32_Word
*chains
= buckets
+ nbuckets
- symbias
;
565 if (!(idx
= buckets
[hash
% nbuckets
])) return NULL
;
568 if ((chains
[idx
] & ~1u) == (hash
& ~1u) &&
569 ELF32_ST_BIND(symtab
[idx
].st_info
) == STB_GLOBAL
&&
570 ELF32_ST_TYPE(symtab
[idx
].st_info
) == type
&&
571 !strcmp( strings
+ symtab
[idx
].st_name
, var
))
572 return (void *)(info
->dlpi_addr
+ symtab
[idx
].st_value
);
573 } while (!(chains
[idx
++] & 1u));
575 else if (hashtab
) /* old style hash table */
577 const unsigned int hash
= hash_symbol( var
);
578 const Elf32_Word nbuckets
= hashtab
[0];
579 const Elf32_Word
*buckets
= hashtab
+ 2;
580 const Elf32_Word
*chains
= buckets
+ nbuckets
;
582 for (idx
= buckets
[hash
% nbuckets
]; idx
; idx
= chains
[idx
])
584 if (ELF32_ST_BIND(symtab
[idx
].st_info
) == STB_GLOBAL
&&
585 ELF32_ST_TYPE(symtab
[idx
].st_info
) == type
&&
586 !strcmp( strings
+ symtab
[idx
].st_name
, var
))
587 return (void *)(info
->dlpi_addr
+ symtab
[idx
].st_value
);
593 static int enum_libs( struct dl_phdr_info
* info
, size_t size
, void* data
)
597 if (!info
->dlpi_name
) return 0;
598 if (!(p
= strrchr( info
->dlpi_name
, '/' ))) return 0;
599 if (strcmp( p
, "/libhardware.so" )) return 0;
600 TRACE( "found libhardware at %p\n", info
->dlpi_phdr
);
601 phw_get_module
= find_symbol( info
, "hw_get_module", STT_FUNC
);
605 static void load_hardware_libs(void)
607 const struct hw_module_t
*module
;
611 if ((libhardware
= wine_dlopen( "libhardware.so", RTLD_GLOBAL
, error
, sizeof(error
) )))
613 LOAD_FUNCPTR( libhardware
, hw_get_module
);
617 /* Android >= N disallows loading libhardware, so we load libandroid (which imports
618 * libhardware), and then we can find libhardware in the list of loaded libraries.
620 if (!wine_dlopen( "libandroid.so", RTLD_GLOBAL
, error
, sizeof(error
) ))
622 ERR( "failed to load libandroid.so: %s\n", error
);
625 dl_iterate_phdr( enum_libs
, 0 );
628 ERR( "failed to find hw_get_module\n" );
633 if (phw_get_module( GRALLOC_HARDWARE_MODULE_ID
, &module
) == 0)
634 gralloc_module
= (struct gralloc_module_t
*)module
;
636 ERR( "failed to load gralloc module\n" );
639 static void load_android_libs(void)
641 void *libandroid
, *liblog
;
644 if (!(libandroid
= wine_dlopen( "libandroid.so", RTLD_GLOBAL
, error
, sizeof(error
) )))
646 ERR( "failed to load libandroid.so: %s\n", error
);
649 if (!(liblog
= wine_dlopen( "liblog.so", RTLD_GLOBAL
, error
, sizeof(error
) )))
651 ERR( "failed to load liblog.so: %s\n", error
);
654 LOAD_FUNCPTR( liblog
, __android_log_print
);
655 LOAD_FUNCPTR( libandroid
, ANativeWindow_fromSurface
);
656 LOAD_FUNCPTR( libandroid
, ANativeWindow_release
);
662 static BOOL
process_attach(void)
665 jobject object
= wine_get_java_object();
669 load_hardware_libs();
671 if ((java_vm
= wine_get_java_vm())) /* running under Java */
674 WORD old_fs
= wine_get_fs();
677 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
678 class = (*jni_env
)->GetObjectClass( jni_env
, object
);
679 (*jni_env
)->RegisterNatives( jni_env
, class, methods
, sizeof(methods
)/sizeof(methods
[0]) );
680 (*jni_env
)->DeleteLocalRef( jni_env
, class );
682 wine_set_fs( old_fs
); /* the Java VM hijacks %fs for its own purposes, restore it */
688 /***********************************************************************
689 * dll initialisation routine
691 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, LPVOID reserved
)
695 case DLL_PROCESS_ATTACH
:
696 DisableThreadLibraryCalls( inst
);
697 return process_attach();