Added input queue to server-side console object,
read/write_console_input requests, and use them for Read/WriteConsoleInput.
This commit is contained in:
parent
0b78af7c01
commit
4b461128d6
|
@ -510,6 +510,31 @@ struct get_console_info_reply
|
|||
};
|
||||
|
||||
|
||||
/* Add input records to a console input queue */
|
||||
struct write_console_input_request
|
||||
{
|
||||
int handle; /* handle to the console input */
|
||||
int count; /* number of input records */
|
||||
/* INPUT_RECORD records[0]; */ /* input records */
|
||||
};
|
||||
struct write_console_input_reply
|
||||
{
|
||||
int written; /* number of records written */
|
||||
};
|
||||
|
||||
/* Fetch input records from a console input queue */
|
||||
struct read_console_input_request
|
||||
{
|
||||
int handle; /* handle to the console input */
|
||||
int count; /* max number of records to retrieve */
|
||||
int flush; /* flush the retrieved records from the queue? */
|
||||
};
|
||||
struct read_console_input_reply
|
||||
{
|
||||
/* INPUT_RECORD records[0]; */ /* input records */
|
||||
};
|
||||
|
||||
|
||||
/* Create a change notification */
|
||||
struct create_change_notification_request
|
||||
{
|
||||
|
|
|
@ -203,6 +203,7 @@ extern int create_pipe( struct object *obj[2] );
|
|||
|
||||
/* console functions */
|
||||
|
||||
struct tagINPUT_RECORD;
|
||||
extern int create_console( int fd, struct object *obj[2] );
|
||||
extern int set_console_fd( int handle, int fd, int pid );
|
||||
extern int get_console_mode( int handle, int *mode );
|
||||
|
@ -211,6 +212,8 @@ extern int set_console_info( int handle, struct set_console_info_request *req,
|
|||
const char *title );
|
||||
extern int get_console_info( int handle, struct get_console_info_reply *reply,
|
||||
const char **title );
|
||||
extern int write_console_input( int handle, int count, struct tagINPUT_RECORD *records );
|
||||
extern int read_console_input( int handle, int count, int flush );
|
||||
|
||||
|
||||
/* change notification functions */
|
||||
|
|
|
@ -47,6 +47,8 @@ enum request
|
|||
REQ_SET_CONSOLE_MODE,
|
||||
REQ_SET_CONSOLE_INFO,
|
||||
REQ_GET_CONSOLE_INFO,
|
||||
REQ_WRITE_CONSOLE_INPUT,
|
||||
REQ_READ_CONSOLE_INPUT,
|
||||
REQ_CREATE_CHANGE_NOTIFICATION,
|
||||
REQ_CREATE_MAPPING,
|
||||
REQ_GET_MAPPING_INFO,
|
||||
|
@ -101,6 +103,8 @@ DECL_HANDLER(get_console_mode);
|
|||
DECL_HANDLER(set_console_mode);
|
||||
DECL_HANDLER(set_console_info);
|
||||
DECL_HANDLER(get_console_info);
|
||||
DECL_HANDLER(write_console_input);
|
||||
DECL_HANDLER(read_console_input);
|
||||
DECL_HANDLER(create_change_notification);
|
||||
DECL_HANDLER(create_mapping);
|
||||
DECL_HANDLER(get_mapping_info);
|
||||
|
@ -152,6 +156,8 @@ static const struct handler {
|
|||
{ (void(*)())req_set_console_mode, sizeof(struct set_console_mode_request) },
|
||||
{ (void(*)())req_set_console_info, sizeof(struct set_console_info_request) },
|
||||
{ (void(*)())req_get_console_info, sizeof(struct get_console_info_request) },
|
||||
{ (void(*)())req_write_console_input, sizeof(struct write_console_input_request) },
|
||||
{ (void(*)())req_read_console_input, sizeof(struct read_console_input_request) },
|
||||
{ (void(*)())req_create_change_notification, sizeof(struct create_change_notification_request) },
|
||||
{ (void(*)())req_create_mapping, sizeof(struct create_mapping_request) },
|
||||
{ (void(*)())req_get_mapping_info, sizeof(struct get_mapping_info_request) },
|
||||
|
|
|
@ -1102,8 +1102,7 @@ BOOL16 WINAPI ModuleNext( MODULEENTRY *lpme )
|
|||
lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
|
||||
lpme->hModule = lpme->wNext;
|
||||
lpme->wcUsage = pModule->count;
|
||||
strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
|
||||
lpme->szExePath[MAX_PATH] = '\0';
|
||||
lstrcpyn32A( lpme->szExePath, NE_MODULE_NAME(pModule), sizeof(lpme->szExePath) );
|
||||
lpme->wNext = pModule->next;
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -746,7 +746,7 @@ init MAIN_KernelInit
|
|||
727 stdcall WideCharToMultiByte(long long wstr long ptr long ptr ptr) WideCharToMultiByte
|
||||
728 stdcall WinExec(str long) WinExec32
|
||||
729 stdcall WriteConsoleA(long ptr long ptr ptr) WriteConsole32A
|
||||
730 stub WriteConsoleInputA
|
||||
730 stdcall WriteConsoleInputA(long ptr long ptr) WriteConsoleInput32A
|
||||
731 stub WriteConsoleInputW
|
||||
732 stdcall WriteConsoleOutputA(long ptr long long ptr) WriteConsoleOutput32A
|
||||
733 stub WriteConsoleOutputAttribute
|
||||
|
|
|
@ -33,6 +33,8 @@ struct console_input
|
|||
int fd; /* Unix file descriptor */
|
||||
int mode; /* input mode */
|
||||
struct screen_buffer *output; /* associated screen buffer */
|
||||
int recnum; /* number of input records */
|
||||
INPUT_RECORD *records; /* input records */
|
||||
};
|
||||
|
||||
struct screen_buffer
|
||||
|
@ -135,6 +137,8 @@ int create_console( int fd, struct object *obj[2] )
|
|||
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
|
||||
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
|
||||
console_input->output = screen_buffer;
|
||||
console_input->recnum = 0;
|
||||
console_input->records = NULL;
|
||||
screen_buffer->fd = write_fd;
|
||||
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
|
||||
screen_buffer->input = console_input;
|
||||
|
@ -281,6 +285,60 @@ int get_console_info( int handle, struct get_console_info_reply *reply, const ch
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* add input events to a console input queue */
|
||||
int write_console_input( int handle, int count, INPUT_RECORD *records )
|
||||
{
|
||||
INPUT_RECORD *new_rec;
|
||||
struct console_input *console;
|
||||
|
||||
if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
|
||||
GENERIC_WRITE, &console_input_ops )))
|
||||
return -1;
|
||||
if (!(new_rec = realloc( console->records,
|
||||
(console->recnum + count) * sizeof(INPUT_RECORD) )))
|
||||
{
|
||||
SET_ERROR( ERROR_NOT_ENOUGH_MEMORY );
|
||||
release_object( console );
|
||||
return -1;
|
||||
}
|
||||
console->records = new_rec;
|
||||
memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
|
||||
console->recnum += count;
|
||||
release_object( console );
|
||||
return count;
|
||||
}
|
||||
|
||||
/* retrieve a pointer to the console input records */
|
||||
int read_console_input( int handle, int count, int flush )
|
||||
{
|
||||
struct console_input *console;
|
||||
|
||||
if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
|
||||
GENERIC_READ, &console_input_ops )))
|
||||
return -1;
|
||||
if ((count < 0) || (count > console->recnum)) count = console->recnum;
|
||||
send_reply( current, -1, 1, console->records, count * sizeof(INPUT_RECORD) );
|
||||
if (flush)
|
||||
{
|
||||
int i;
|
||||
for (i = count; i < console->recnum; i++)
|
||||
console->records[i-count] = console->records[i];
|
||||
if ((console->recnum -= count) > 0)
|
||||
{
|
||||
INPUT_RECORD *new_rec = realloc( console->records,
|
||||
console->recnum * sizeof(INPUT_RECORD) );
|
||||
if (new_rec) console->records = new_rec;
|
||||
}
|
||||
else
|
||||
{
|
||||
free( console->records );
|
||||
console->records = NULL;
|
||||
}
|
||||
}
|
||||
release_object( console );
|
||||
return count;
|
||||
}
|
||||
|
||||
static void console_input_dump( struct object *obj, int verbose )
|
||||
{
|
||||
struct console_input *console = (struct console_input *)obj;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "winbase.h"
|
||||
#include "wincon.h"
|
||||
#define WANT_REQUEST_HANDLERS
|
||||
#include "server.h"
|
||||
#include "server/request.h"
|
||||
|
@ -677,6 +678,25 @@ DECL_HANDLER(set_console_mode)
|
|||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* add input records to a console input queue */
|
||||
DECL_HANDLER(write_console_input)
|
||||
{
|
||||
struct write_console_input_reply reply;
|
||||
INPUT_RECORD *records = (INPUT_RECORD *)data;
|
||||
|
||||
if (len != req->count * sizeof(INPUT_RECORD))
|
||||
fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
|
||||
len, req->count );
|
||||
reply.written = write_console_input( req->handle, req->count, records );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* fetch input records from a console input queue */
|
||||
DECL_HANDLER(read_console_input)
|
||||
{
|
||||
read_console_input( req->handle, req->count, req->flush );
|
||||
}
|
||||
|
||||
/* create a change notification */
|
||||
DECL_HANDLER(create_change_notification)
|
||||
{
|
||||
|
|
|
@ -458,6 +458,32 @@ static int dump_get_console_info_reply( struct get_console_info_reply *req, int
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_write_console_input_request( struct write_console_input_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d,", req->handle );
|
||||
fprintf( stderr, " count=%d", req->count );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_write_console_input_reply( struct write_console_input_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " written=%d", req->written );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_read_console_input_request( struct read_console_input_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d,", req->handle );
|
||||
fprintf( stderr, " count=%d,", req->count );
|
||||
fprintf( stderr, " flush=%d", req->flush );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_read_console_input_reply( struct read_console_input_reply *req, int len )
|
||||
{
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_change_notification_request( struct create_change_notification_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " subtree=%d,", req->subtree );
|
||||
|
@ -607,6 +633,10 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] =
|
|||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_get_console_info_request,
|
||||
(void(*)())dump_get_console_info_reply },
|
||||
{ (int(*)(void *,int))dump_write_console_input_request,
|
||||
(void(*)())dump_write_console_input_reply },
|
||||
{ (int(*)(void *,int))dump_read_console_input_request,
|
||||
(void(*)())dump_read_console_input_reply },
|
||||
{ (int(*)(void *,int))dump_create_change_notification_request,
|
||||
(void(*)())dump_create_change_notification_reply },
|
||||
{ (int(*)(void *,int))dump_create_mapping_request,
|
||||
|
@ -661,6 +691,8 @@ static const char * const req_names[REQ_NB_REQUESTS] =
|
|||
"set_console_mode",
|
||||
"set_console_info",
|
||||
"get_console_info",
|
||||
"write_console_input",
|
||||
"read_console_input",
|
||||
"create_change_notification",
|
||||
"create_mapping",
|
||||
"get_mapping_info",
|
||||
|
|
216
win32/console.c
216
win32/console.c
|
@ -1043,44 +1043,122 @@ BOOL32 WINAPI ReadConsoleInput32A(HANDLE32 hConsoleInput,
|
|||
LPINPUT_RECORD lpBuffer,
|
||||
DWORD nLength, LPDWORD lpNumberOfEventsRead)
|
||||
{
|
||||
CONSOLE *console = CONSOLE_GetPtr( hConsoleInput );
|
||||
struct read_console_input_request req;
|
||||
int len;
|
||||
|
||||
TRACE(console, "(%d,%p,%ld,%p)\n",hConsoleInput, lpBuffer, nLength,
|
||||
lpNumberOfEventsRead);
|
||||
if (!console) {
|
||||
FIXME(console, "(%d,%p,%ld,%p), No console handle!\n",hConsoleInput,
|
||||
lpBuffer, nLength, lpNumberOfEventsRead);
|
||||
if ((req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hConsoleInput,
|
||||
K32OBJ_CONSOLE, GENERIC_READ )) == -1)
|
||||
return FALSE;
|
||||
req.count = nLength;
|
||||
req.flush = 1;
|
||||
|
||||
/* Indicate that nothing was read */
|
||||
*lpNumberOfEventsRead = 0;
|
||||
|
||||
return FALSE;
|
||||
/* loop until we get at least one event */
|
||||
for (;;)
|
||||
{
|
||||
CLIENT_SendRequest( REQ_READ_CONSOLE_INPUT, -1, 1, &req, sizeof(req) );
|
||||
if (CLIENT_WaitReply( &len, NULL, 1, lpBuffer, nLength * sizeof(*lpBuffer) ))
|
||||
return FALSE;
|
||||
assert( !(len % sizeof(INPUT_RECORD)) );
|
||||
if (len) break;
|
||||
WaitForSingleObject( hConsoleInput, INFINITE32 );
|
||||
}
|
||||
CONSOLE_get_input(hConsoleInput);
|
||||
/* SDK: return at least 1 input record */
|
||||
while (!console->nrofirs) {
|
||||
DWORD res;
|
||||
|
||||
res=WaitForSingleObject(hConsoleInput,0);
|
||||
switch (res) {
|
||||
case STATUS_TIMEOUT: continue;
|
||||
case 0: break; /*ok*/
|
||||
case WAIT_FAILED: return 0;/*FIXME: SetLastError?*/
|
||||
default: break; /*hmm*/
|
||||
}
|
||||
CONSOLE_get_input(hConsoleInput);
|
||||
}
|
||||
|
||||
if (nLength>console->nrofirs)
|
||||
nLength = console->nrofirs;
|
||||
memcpy(lpBuffer,console->irs,sizeof(INPUT_RECORD)*nLength);
|
||||
if (lpNumberOfEventsRead)
|
||||
*lpNumberOfEventsRead = nLength;
|
||||
CONSOLE_drain_input(console,nLength);
|
||||
K32OBJ_DecCount(&console->header);
|
||||
if (lpNumberOfEventsRead) *lpNumberOfEventsRead = len / sizeof(INPUT_RECORD);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* ReadConsoleInput32W (KERNEL32.570)
|
||||
*/
|
||||
BOOL32 WINAPI ReadConsoleInput32W( HANDLE32 handle, LPINPUT_RECORD buffer,
|
||||
DWORD count, LPDWORD read )
|
||||
{
|
||||
/* FIXME: Fix this if we get UNICODE input. */
|
||||
return ReadConsoleInput32A( handle, buffer, count, read );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FlushConsoleInputBuffer (KERNEL32.132)
|
||||
*/
|
||||
BOOL32 WINAPI FlushConsoleInputBuffer( HANDLE32 handle )
|
||||
{
|
||||
struct read_console_input_request req;
|
||||
int len;
|
||||
|
||||
if ((req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
|
||||
K32OBJ_CONSOLE, GENERIC_READ )) == -1)
|
||||
return FALSE;
|
||||
req.count = -1; /* get all records */
|
||||
req.flush = 1;
|
||||
CLIENT_SendRequest( REQ_READ_CONSOLE_INPUT, -1, 1, &req, sizeof(req) );
|
||||
return !CLIENT_WaitReply( &len, NULL, 0 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* PeekConsoleInputA (KERNEL32.550)
|
||||
*
|
||||
* Gets 'count' first events (or less) from input queue.
|
||||
*
|
||||
* Does not need a complex console.
|
||||
*/
|
||||
BOOL32 WINAPI PeekConsoleInput32A( HANDLE32 handle, LPINPUT_RECORD buffer,
|
||||
DWORD count, LPDWORD read )
|
||||
{
|
||||
struct read_console_input_request req;
|
||||
int len;
|
||||
|
||||
if ((req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
|
||||
K32OBJ_CONSOLE, GENERIC_READ )) == -1)
|
||||
return FALSE;
|
||||
req.count = count;
|
||||
req.flush = 0;
|
||||
|
||||
CLIENT_SendRequest( REQ_READ_CONSOLE_INPUT, -1, 1, &req, sizeof(req) );
|
||||
if (CLIENT_WaitReply( &len, NULL, 1, buffer, count * sizeof(*buffer) ))
|
||||
return FALSE;
|
||||
assert( !(len % sizeof(INPUT_RECORD)) );
|
||||
if (read) *read = len / sizeof(INPUT_RECORD);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* PeekConsoleInputW (KERNEL32.551)
|
||||
*/
|
||||
BOOL32 WINAPI PeekConsoleInput32W(HANDLE32 hConsoleInput,
|
||||
LPINPUT_RECORD pirBuffer,
|
||||
DWORD cInRecords,
|
||||
LPDWORD lpcRead)
|
||||
{
|
||||
/* FIXME: Hmm. Fix this if we get UNICODE input. */
|
||||
return PeekConsoleInput32A(hConsoleInput,pirBuffer,cInRecords,lpcRead);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WriteConsoleInput32A [KERNEL32.730] Write data to a console input buffer
|
||||
*
|
||||
*/
|
||||
BOOL32 WINAPI WriteConsoleInput32A( HANDLE32 handle, INPUT_RECORD *buffer,
|
||||
DWORD count, LPDWORD written )
|
||||
{
|
||||
struct write_console_input_request req;
|
||||
struct write_console_input_reply reply;
|
||||
|
||||
if ((req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
|
||||
K32OBJ_CONSOLE, GENERIC_WRITE )) == -1)
|
||||
return FALSE;
|
||||
req.count = count;
|
||||
CLIENT_SendRequest( REQ_WRITE_CONSOLE_INPUT, -1, 2, &req, sizeof(req),
|
||||
buffer, count * sizeof(*buffer) );
|
||||
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return FALSE;
|
||||
if (written) *written = reply.written;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SetConsoleTitle32A (KERNEL32.476)
|
||||
*
|
||||
|
@ -1185,33 +1263,6 @@ BOOL32 WINAPI SetConsoleTitle32W( LPCWSTR title )
|
|||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* ReadConsoleInput32W (KERNEL32.570)
|
||||
*/
|
||||
BOOL32 WINAPI ReadConsoleInput32W(HANDLE32 hConsoleInput,
|
||||
LPINPUT_RECORD lpBuffer,
|
||||
DWORD nLength, LPDWORD lpNumberOfEventsRead)
|
||||
{
|
||||
FIXME(console, "(%d,%p,%ld,%p): stub\n",hConsoleInput, lpBuffer, nLength,
|
||||
lpNumberOfEventsRead);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FlushConsoleInputBuffer (KERNEL32.132)
|
||||
*/
|
||||
BOOL32 WINAPI FlushConsoleInputBuffer(HANDLE32 hConsoleInput)
|
||||
{
|
||||
CONSOLE *console = CONSOLE_GetPtr( hConsoleInput );
|
||||
|
||||
if (!console)
|
||||
return FALSE;
|
||||
CONSOLE_drain_input(console,console->nrofirs);
|
||||
K32OBJ_DecCount(&console->header);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* SetConsoleCursorPosition [KERNEL32.627]
|
||||
* Sets the cursor position in console
|
||||
|
@ -1271,53 +1322,6 @@ BOOL32 WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* PeekConsoleInputA (KERNEL32.550)
|
||||
*
|
||||
* Gets 'cInRecords' first events (or less) from input queue.
|
||||
*
|
||||
* Does not need a complex console.
|
||||
*/
|
||||
BOOL32 WINAPI PeekConsoleInput32A(HANDLE32 hConsoleInput,
|
||||
LPINPUT_RECORD pirBuffer,
|
||||
DWORD cInRecords,
|
||||
LPDWORD lpcRead)
|
||||
{
|
||||
CONSOLE *console = CONSOLE_GetPtr( hConsoleInput );
|
||||
|
||||
if (!console) {
|
||||
FIXME(console,"(%d,%p,%ld,%p), No console handle passed!\n",hConsoleInput, pirBuffer, cInRecords, lpcRead);
|
||||
|
||||
/* Indicate that nothing was read */
|
||||
*lpcRead = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
TRACE(console,"(%d,%p,%ld,%p)\n",hConsoleInput, pirBuffer, cInRecords, lpcRead);
|
||||
CONSOLE_get_input(hConsoleInput);
|
||||
if (cInRecords>console->nrofirs)
|
||||
cInRecords = console->nrofirs;
|
||||
if (pirBuffer)
|
||||
memcpy(pirBuffer,console->irs,cInRecords*sizeof(INPUT_RECORD));
|
||||
if (lpcRead)
|
||||
*lpcRead = cInRecords;
|
||||
K32OBJ_DecCount(&console->header);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* PeekConsoleInputW (KERNEL32.551)
|
||||
*/
|
||||
BOOL32 WINAPI PeekConsoleInput32W(HANDLE32 hConsoleInput,
|
||||
LPINPUT_RECORD pirBuffer,
|
||||
DWORD cInRecords,
|
||||
LPDWORD lpcRead)
|
||||
{
|
||||
/* FIXME: Hmm. Fix this if we get UNICODE input. */
|
||||
return PeekConsoleInput32A(hConsoleInput,pirBuffer,cInRecords,lpcRead);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* GetConsoleCursorInfo32 [KERNEL32.296] Gets size and visibility of console
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue