2017-06-01 09:39:20 +02:00
|
|
|
/*
|
|
|
|
* Android pseudo-device handling
|
|
|
|
*
|
|
|
|
* Copyright 2014-2017 Alexandre Julliard
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "wine/port.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
|
|
|
#define NONAMELESSUNION
|
|
|
|
#define NONAMELESSSTRUCT
|
|
|
|
|
|
|
|
#include "ntstatus.h"
|
|
|
|
#define WIN32_NO_STATUS
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winternl.h"
|
|
|
|
#include "winioctl.h"
|
|
|
|
#include "ddk/wdm.h"
|
|
|
|
#include "android.h"
|
|
|
|
#include "wine/library.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(android);
|
|
|
|
|
|
|
|
extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
|
|
|
|
static HANDLE stop_event;
|
|
|
|
static HANDLE thread;
|
|
|
|
static JNIEnv *jni_env;
|
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
#define ANDROIDCONTROLTYPE ((ULONG)'A')
|
|
|
|
#define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
|
|
|
|
|
|
|
|
enum android_ioctl
|
|
|
|
{
|
|
|
|
IOCTL_CREATE_WINDOW,
|
|
|
|
IOCTL_DESTROY_WINDOW,
|
2017-06-02 11:34:23 +02:00
|
|
|
IOCTL_WINDOW_POS_CHANGED,
|
2017-06-01 09:42:42 +02:00
|
|
|
NB_IOCTLS
|
|
|
|
};
|
|
|
|
|
2017-06-02 11:37:16 +02:00
|
|
|
/* data about the native window in the context of the Java process */
|
|
|
|
struct native_win_data
|
|
|
|
{
|
|
|
|
struct ANativeWindow *parent;
|
|
|
|
HWND hwnd;
|
|
|
|
};
|
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
struct ioctl_header
|
|
|
|
{
|
|
|
|
int hwnd;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ioctl_android_create_window
|
|
|
|
{
|
|
|
|
struct ioctl_header hdr;
|
|
|
|
int parent;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ioctl_android_destroy_window
|
|
|
|
{
|
|
|
|
struct ioctl_header hdr;
|
|
|
|
};
|
|
|
|
|
2017-06-02 11:34:23 +02:00
|
|
|
struct ioctl_android_window_pos_changed
|
|
|
|
{
|
|
|
|
struct ioctl_header hdr;
|
|
|
|
RECT window_rect;
|
|
|
|
RECT client_rect;
|
|
|
|
RECT visible_rect;
|
|
|
|
int style;
|
|
|
|
int flags;
|
|
|
|
int after;
|
|
|
|
int owner;
|
|
|
|
};
|
2017-06-01 09:42:42 +02:00
|
|
|
|
|
|
|
static inline DWORD current_client_id(void)
|
|
|
|
{
|
|
|
|
return HandleToUlong( PsGetCurrentProcessId() );
|
|
|
|
}
|
|
|
|
|
2017-06-01 09:40:29 +02:00
|
|
|
#ifdef __i386__ /* the Java VM uses %fs for its own purposes, so we need to wrap the calls */
|
2017-06-01 09:39:20 +02:00
|
|
|
static WORD orig_fs, java_fs;
|
2017-06-01 09:40:29 +02:00
|
|
|
static inline void wrap_java_call(void) { wine_set_fs( java_fs ); }
|
|
|
|
static inline void unwrap_java_call(void) { wine_set_fs( orig_fs ); }
|
|
|
|
#else
|
|
|
|
static inline void wrap_java_call(void) { }
|
|
|
|
static inline void unwrap_java_call(void) { }
|
2017-06-01 09:39:20 +02:00
|
|
|
#endif /* __i386__ */
|
|
|
|
|
2017-06-02 11:37:16 +02:00
|
|
|
static struct native_win_data *data_map[65536];
|
|
|
|
|
|
|
|
static unsigned int data_map_idx( HWND hwnd )
|
|
|
|
{
|
|
|
|
return LOWORD(hwnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct native_win_data *get_native_win_data( HWND hwnd )
|
|
|
|
{
|
|
|
|
struct native_win_data *data = data_map[data_map_idx( hwnd )];
|
|
|
|
|
|
|
|
if (data && data->hwnd == hwnd) return data;
|
|
|
|
WARN( "unknown win %p\n", hwnd );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct native_win_data *get_ioctl_native_win_data( const struct ioctl_header *hdr )
|
|
|
|
{
|
|
|
|
return get_native_win_data( LongToHandle(hdr->hwnd) );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void release_native_window( struct native_win_data *data )
|
|
|
|
{
|
|
|
|
if (data->parent) pANativeWindow_release( data->parent );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_native_win_data( struct native_win_data *data )
|
|
|
|
{
|
|
|
|
unsigned int idx = data_map_idx( data->hwnd );
|
|
|
|
|
|
|
|
release_native_window( data );
|
|
|
|
HeapFree( GetProcessHeap(), 0, data );
|
|
|
|
data_map[idx] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct native_win_data *create_native_win_data( HWND hwnd )
|
|
|
|
{
|
|
|
|
unsigned int idx = data_map_idx( hwnd );
|
|
|
|
struct native_win_data *data = data_map[idx];
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
WARN( "data for %p not freed correctly\n", data->hwnd );
|
|
|
|
free_native_win_data( data );
|
|
|
|
}
|
|
|
|
if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return NULL;
|
|
|
|
data->hwnd = hwnd;
|
|
|
|
data_map[idx] = data;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CALLBACK register_native_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
|
|
|
|
{
|
|
|
|
HWND hwnd = (HWND)arg1;
|
|
|
|
struct ANativeWindow *win = (struct ANativeWindow *)arg2;
|
|
|
|
struct native_win_data *data = get_native_win_data( hwnd );
|
|
|
|
|
|
|
|
if (!data || data->parent == win)
|
|
|
|
{
|
|
|
|
if (win) pANativeWindow_release( win );
|
|
|
|
TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_native_window( data );
|
|
|
|
data->parent = win;
|
|
|
|
if (win)
|
|
|
|
{
|
|
|
|
wrap_java_call();
|
|
|
|
win->perform( win, NATIVE_WINDOW_API_CONNECT, NATIVE_WINDOW_API_CPU );
|
|
|
|
unwrap_java_call();
|
|
|
|
}
|
|
|
|
TRACE( "%p -> %p win %p\n", hwnd, data, win );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* register a native window received from the Java side for use in ioctls */
|
|
|
|
void register_native_window( HWND hwnd, struct ANativeWindow *win )
|
|
|
|
{
|
|
|
|
NtQueueApcThread( thread, register_native_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, 0 );
|
|
|
|
}
|
2017-06-01 09:42:42 +02:00
|
|
|
|
|
|
|
static int status_to_android_error( NTSTATUS status )
|
|
|
|
{
|
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
case STATUS_SUCCESS: return 0;
|
|
|
|
case STATUS_NO_MEMORY: return -ENOMEM;
|
|
|
|
case STATUS_NOT_SUPPORTED: return -ENOSYS;
|
|
|
|
case STATUS_INVALID_PARAMETER: return -EINVAL;
|
|
|
|
case STATUS_BUFFER_OVERFLOW: return -EINVAL;
|
|
|
|
case STATUS_INVALID_HANDLE: return -ENOENT;
|
|
|
|
case STATUS_ACCESS_DENIED: return -EPERM;
|
|
|
|
case STATUS_NO_SUCH_DEVICE: return -ENODEV;
|
|
|
|
case STATUS_DUPLICATE_NAME: return -EEXIST;
|
|
|
|
case STATUS_PIPE_DISCONNECTED: return -EPIPE;
|
|
|
|
case STATUS_NO_MORE_FILES: return -ENODATA;
|
|
|
|
case STATUS_IO_TIMEOUT: return -ETIMEDOUT;
|
|
|
|
case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG;
|
|
|
|
case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK;
|
|
|
|
default:
|
|
|
|
FIXME( "unmapped status %08x\n", status );
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-01 09:40:29 +02:00
|
|
|
static jobject load_java_method( jmethodID *method, const char *name, const char *args )
|
|
|
|
{
|
|
|
|
jobject object = wine_get_java_object();
|
|
|
|
|
|
|
|
if (!*method)
|
|
|
|
{
|
|
|
|
jclass class;
|
|
|
|
|
|
|
|
wrap_java_call();
|
|
|
|
class = (*jni_env)->GetObjectClass( jni_env, object );
|
|
|
|
*method = (*jni_env)->GetMethodID( jni_env, class, name, args );
|
|
|
|
unwrap_java_call();
|
|
|
|
if (!*method)
|
|
|
|
{
|
|
|
|
FIXME( "method %s not found\n", name );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void create_desktop_window( HWND hwnd )
|
|
|
|
{
|
|
|
|
static jmethodID method;
|
|
|
|
jobject object;
|
|
|
|
|
|
|
|
if (!(object = load_java_method( &method, "createDesktopWindow", "(I)V" ))) return;
|
|
|
|
|
|
|
|
wrap_java_call();
|
|
|
|
(*jni_env)->CallVoidMethod( jni_env, object, method, HandleToLong( hwnd ));
|
|
|
|
unwrap_java_call();
|
|
|
|
}
|
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
|
|
|
|
{
|
|
|
|
static jmethodID method;
|
|
|
|
jobject object;
|
|
|
|
struct ioctl_android_create_window *res = data;
|
2017-06-02 11:37:16 +02:00
|
|
|
struct native_win_data *win_data;
|
2017-06-01 09:42:42 +02:00
|
|
|
DWORD pid = current_client_id();
|
|
|
|
|
|
|
|
if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
|
|
|
|
|
2017-06-02 11:37:16 +02:00
|
|
|
if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd) )))
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent );
|
|
|
|
|
|
|
|
if (!(object = load_java_method( &method, "createWindow", "(III)V" ))) return STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
wrap_java_call();
|
|
|
|
(*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, pid );
|
|
|
|
unwrap_java_call();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
|
|
|
|
{
|
|
|
|
static jmethodID method;
|
|
|
|
jobject object;
|
|
|
|
struct ioctl_android_destroy_window *res = data;
|
2017-06-02 11:37:16 +02:00
|
|
|
struct native_win_data *win_data;
|
2017-06-01 09:42:42 +02:00
|
|
|
|
|
|
|
if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
|
|
|
|
|
2017-06-02 11:37:16 +02:00
|
|
|
if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
|
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
TRACE( "hwnd %08x\n", res->hdr.hwnd );
|
|
|
|
|
|
|
|
if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
wrap_java_call();
|
|
|
|
(*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd );
|
|
|
|
unwrap_java_call();
|
2017-06-02 11:37:16 +02:00
|
|
|
free_native_win_data( win_data );
|
2017-06-01 09:42:42 +02:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-06-02 11:34:23 +02:00
|
|
|
static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
|
|
|
|
{
|
|
|
|
static jmethodID method;
|
|
|
|
jobject object;
|
|
|
|
struct ioctl_android_window_pos_changed *res = data;
|
|
|
|
|
|
|
|
if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
|
|
|
|
res->hdr.hwnd, wine_dbgstr_rect(&res->window_rect), wine_dbgstr_rect(&res->client_rect),
|
|
|
|
wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner );
|
|
|
|
|
|
|
|
if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
wrap_java_call();
|
|
|
|
(*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style,
|
|
|
|
res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom,
|
|
|
|
res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom,
|
|
|
|
res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom );
|
|
|
|
unwrap_java_call();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size );
|
|
|
|
static const ioctl_func ioctl_funcs[] =
|
|
|
|
{
|
|
|
|
createWindow_ioctl, /* IOCTL_CREATE_WINDOW */
|
|
|
|
destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */
|
2017-06-02 11:34:23 +02:00
|
|
|
windowPosChanged_ioctl, /* IOCTL_WINDOW_POS_CHANGED */
|
2017-06-01 09:42:42 +02:00
|
|
|
};
|
|
|
|
|
2017-06-01 09:39:20 +02:00
|
|
|
static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp )
|
|
|
|
{
|
|
|
|
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
|
2017-06-01 09:42:42 +02:00
|
|
|
DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2;
|
2017-06-01 09:39:20 +02:00
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
if (code < NB_IOCTLS)
|
|
|
|
{
|
|
|
|
struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength;
|
|
|
|
ioctl_func func = ioctl_funcs[code];
|
2017-06-01 09:39:20 +02:00
|
|
|
|
2017-06-01 09:42:42 +02:00
|
|
|
if (in_size >= sizeof(*header))
|
|
|
|
{
|
|
|
|
irp->IoStatus.Information = 0;
|
|
|
|
irp->IoStatus.u.Status = func( irp->AssociatedIrp.SystemBuffer, in_size,
|
|
|
|
irpsp->Parameters.DeviceIoControl.OutputBufferLength,
|
|
|
|
&irp->IoStatus.Information );
|
|
|
|
}
|
|
|
|
else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
|
|
|
|
irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
}
|
2017-06-01 09:39:20 +02:00
|
|
|
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NTSTATUS CALLBACK init_android_driver( DRIVER_OBJECT *driver, UNICODE_STRING *name )
|
|
|
|
{
|
|
|
|
static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
|
|
|
|
static const WCHAR device_linkW[] = {'\\','?','?','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
|
|
|
|
|
|
|
|
UNICODE_STRING nameW, linkW;
|
|
|
|
DEVICE_OBJECT *device;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctl_callback;
|
|
|
|
|
|
|
|
RtlInitUnicodeString( &nameW, device_nameW );
|
|
|
|
RtlInitUnicodeString( &linkW, device_linkW );
|
|
|
|
|
|
|
|
if ((status = IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ))) return status;
|
|
|
|
return IoCreateSymbolicLink( &linkW, &nameW );
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD CALLBACK device_thread( void *arg )
|
|
|
|
{
|
|
|
|
static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
|
|
|
|
|
|
|
|
HANDLE start_event = arg;
|
|
|
|
UNICODE_STRING nameW;
|
|
|
|
NTSTATUS status;
|
|
|
|
JavaVM *java_vm;
|
|
|
|
DWORD ret;
|
|
|
|
|
|
|
|
TRACE( "starting process %x\n", GetCurrentProcessId() );
|
|
|
|
|
|
|
|
if (!(java_vm = wine_get_java_vm())) return 0; /* not running under Java */
|
|
|
|
|
|
|
|
#ifdef __i386__
|
|
|
|
orig_fs = wine_get_fs();
|
|
|
|
(*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
|
|
|
|
java_fs = wine_get_fs();
|
|
|
|
wine_set_fs( orig_fs );
|
|
|
|
if (java_fs != orig_fs) TRACE( "%%fs changed from %04x to %04x by Java VM\n", orig_fs, java_fs );
|
|
|
|
#else
|
|
|
|
(*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 );
|
|
|
|
#endif
|
|
|
|
|
2017-06-01 09:40:29 +02:00
|
|
|
create_desktop_window( GetDesktopWindow() );
|
|
|
|
|
2017-06-01 09:39:20 +02:00
|
|
|
RtlInitUnicodeString( &nameW, driver_nameW );
|
|
|
|
if ((status = IoCreateDriver( &nameW, init_android_driver )))
|
|
|
|
{
|
|
|
|
FIXME( "failed to create driver error %x\n", status );
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
|
|
|
|
SetEvent( start_event );
|
|
|
|
|
|
|
|
ret = wine_ntoskrnl_main_loop( stop_event );
|
|
|
|
|
|
|
|
(*java_vm)->DetachCurrentThread( java_vm );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void start_android_device(void)
|
|
|
|
{
|
|
|
|
HANDLE handles[2];
|
|
|
|
|
|
|
|
handles[0] = CreateEventW( NULL, TRUE, FALSE, NULL );
|
|
|
|
handles[1] = thread = CreateThread( NULL, 0, device_thread, handles[0], 0, NULL );
|
|
|
|
WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
|
|
|
|
CloseHandle( handles[0] );
|
|
|
|
}
|
2017-06-01 09:42:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* Client-side ioctl support */
|
|
|
|
|
|
|
|
|
|
|
|
static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size )
|
|
|
|
{
|
|
|
|
static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
|
|
|
|
static HANDLE device;
|
|
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
if (!device)
|
|
|
|
{
|
|
|
|
HANDLE file = CreateFileW( deviceW, GENERIC_READ,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
|
|
|
|
if (file == INVALID_HANDLE_VALUE) return -ENOENT;
|
|
|
|
if (InterlockedCompareExchangePointer( &device, file, NULL )) CloseHandle( file );
|
|
|
|
}
|
|
|
|
|
|
|
|
status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code),
|
|
|
|
in, in_size, out, out_size ? *out_size : 0 );
|
|
|
|
if (status == STATUS_FILE_DELETED)
|
|
|
|
{
|
|
|
|
WARN( "parent process is gone\n" );
|
|
|
|
ExitProcess( 1 );
|
|
|
|
}
|
|
|
|
if (out_size) *out_size = iosb.Information;
|
|
|
|
return status_to_android_error( status );
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_ioctl_window( HWND hwnd )
|
|
|
|
{
|
|
|
|
struct ioctl_android_create_window req;
|
|
|
|
HWND parent = GetAncestor( hwnd, GA_PARENT );
|
|
|
|
|
|
|
|
req.hdr.hwnd = HandleToLong( hwnd );
|
|
|
|
req.parent = parent == GetDesktopWindow() ? 0 : HandleToLong( parent );
|
|
|
|
android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroy_ioctl_window( HWND hwnd )
|
|
|
|
{
|
|
|
|
struct ioctl_android_destroy_window req;
|
|
|
|
|
|
|
|
req.hdr.hwnd = HandleToLong( hwnd );
|
|
|
|
android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL );
|
|
|
|
}
|
2017-06-02 11:34:23 +02:00
|
|
|
|
|
|
|
int ioctl_window_pos_changed( HWND hwnd, const RECT *window_rect, const RECT *client_rect,
|
|
|
|
const RECT *visible_rect, UINT style, UINT flags, HWND after, HWND owner )
|
|
|
|
{
|
|
|
|
struct ioctl_android_window_pos_changed req;
|
|
|
|
|
|
|
|
req.hdr.hwnd = HandleToLong( hwnd );
|
|
|
|
req.window_rect = *window_rect;
|
|
|
|
req.client_rect = *client_rect;
|
|
|
|
req.visible_rect = *visible_rect;
|
|
|
|
req.style = style;
|
|
|
|
req.flags = flags;
|
|
|
|
req.after = HandleToLong( after );
|
|
|
|
req.owner = HandleToLong( owner );
|
|
|
|
return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL );
|
|
|
|
}
|