mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Factor out common code from Windows CLI main loops.
There aren't quite as many of these as there are on Unix, but Windows Plink and PSFTP still share some suspiciously similar-looking code. Now they're both clients of wincliloop.c.
This commit is contained in:
parent
586dc96f5f
commit
231e482fd2
6
Recipe
6
Recipe
@ -335,11 +335,11 @@ putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS
|
|||||||
puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS
|
puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS
|
||||||
plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC
|
plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC
|
||||||
+ winx11 plink.res winnojmp sessprep noterm winnohlp winselcli
|
+ winx11 plink.res winnojmp sessprep noterm winnohlp winselcli
|
||||||
+ clicons LIBS
|
+ clicons wincliloop LIBS
|
||||||
pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
||||||
+ pscp.res winnojmp winnohlp winselcli clicons LIBS
|
+ pscp.res winnojmp winnohlp winselcli clicons wincliloop LIBS
|
||||||
psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
||||||
+ psftp.res winnojmp winnohlp winselcli clicons LIBS
|
+ psftp.res winnojmp winnohlp winselcli clicons wincliloop LIBS
|
||||||
|
|
||||||
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
|
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
|
||||||
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
||||||
|
129
windows/wincliloop.c
Normal file
129
windows/wincliloop.c
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include "putty.h"
|
||||||
|
|
||||||
|
void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx)
|
||||||
|
{
|
||||||
|
SOCKET *sklist = NULL;
|
||||||
|
size_t skcount = 0, sksize = 0;
|
||||||
|
unsigned long now, next, then;
|
||||||
|
now = GETTICKCOUNT();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int nhandles;
|
||||||
|
HANDLE *handles;
|
||||||
|
int n;
|
||||||
|
DWORD ticks;
|
||||||
|
|
||||||
|
const HANDLE *extra_handles = NULL;
|
||||||
|
size_t n_extra_handles = 0;
|
||||||
|
if (!pre(ctx, &extra_handles, &n_extra_handles))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (toplevel_callback_pending()) {
|
||||||
|
ticks = 0;
|
||||||
|
next = now;
|
||||||
|
} else if (run_timers(now, &next)) {
|
||||||
|
then = now;
|
||||||
|
now = GETTICKCOUNT();
|
||||||
|
if (now - then > next - then)
|
||||||
|
ticks = 0;
|
||||||
|
else
|
||||||
|
ticks = next - now;
|
||||||
|
} else {
|
||||||
|
ticks = INFINITE;
|
||||||
|
/* no need to initialise next here because we can never
|
||||||
|
* get WAIT_TIMEOUT */
|
||||||
|
}
|
||||||
|
|
||||||
|
handles = handle_get_events(&nhandles);
|
||||||
|
size_t winselcli_index = nhandles;
|
||||||
|
size_t extra_base = winselcli_index + 1;
|
||||||
|
size_t total_handles = extra_base + n_extra_handles;
|
||||||
|
handles = sresize(handles, total_handles, HANDLE);
|
||||||
|
handles[winselcli_index] = winselcli_event;
|
||||||
|
for (size_t i = 0; i < n_extra_handles; i++)
|
||||||
|
handles[extra_base + i] = extra_handles[i];
|
||||||
|
|
||||||
|
n = WaitForMultipleObjects(total_handles, handles, false, ticks);
|
||||||
|
|
||||||
|
size_t extra_handle_index = n_extra_handles;
|
||||||
|
|
||||||
|
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
|
||||||
|
handle_got_event(handles[n - WAIT_OBJECT_0]);
|
||||||
|
} else if (n == WAIT_OBJECT_0 + nhandles) {
|
||||||
|
WSANETWORKEVENTS things;
|
||||||
|
SOCKET socket;
|
||||||
|
int i, socketstate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must not call select_result() for any socket
|
||||||
|
* until we have finished enumerating within the tree.
|
||||||
|
* This is because select_result() may close the socket
|
||||||
|
* and modify the tree.
|
||||||
|
*/
|
||||||
|
/* Count the active sockets. */
|
||||||
|
i = 0;
|
||||||
|
for (socket = first_socket(&socketstate);
|
||||||
|
socket != INVALID_SOCKET;
|
||||||
|
socket = next_socket(&socketstate)) i++;
|
||||||
|
|
||||||
|
/* Expand the buffer if necessary. */
|
||||||
|
sgrowarray(sklist, sksize, i);
|
||||||
|
|
||||||
|
/* Retrieve the sockets into sklist. */
|
||||||
|
skcount = 0;
|
||||||
|
for (socket = first_socket(&socketstate);
|
||||||
|
socket != INVALID_SOCKET;
|
||||||
|
socket = next_socket(&socketstate)) {
|
||||||
|
sklist[skcount++] = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we're done enumerating; go through the list. */
|
||||||
|
for (i = 0; i < skcount; i++) {
|
||||||
|
WPARAM wp;
|
||||||
|
socket = sklist[i];
|
||||||
|
wp = (WPARAM) socket;
|
||||||
|
if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
|
||||||
|
static const struct { int bit, mask; } eventtypes[] = {
|
||||||
|
{FD_CONNECT_BIT, FD_CONNECT},
|
||||||
|
{FD_READ_BIT, FD_READ},
|
||||||
|
{FD_CLOSE_BIT, FD_CLOSE},
|
||||||
|
{FD_OOB_BIT, FD_OOB},
|
||||||
|
{FD_WRITE_BIT, FD_WRITE},
|
||||||
|
{FD_ACCEPT_BIT, FD_ACCEPT},
|
||||||
|
};
|
||||||
|
int e;
|
||||||
|
|
||||||
|
noise_ultralight(NOISE_SOURCE_IOID, socket);
|
||||||
|
|
||||||
|
for (e = 0; e < lenof(eventtypes); e++)
|
||||||
|
if (things.lNetworkEvents & eventtypes[e].mask) {
|
||||||
|
LPARAM lp;
|
||||||
|
int err = things.iErrorCode[eventtypes[e].bit];
|
||||||
|
lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
|
||||||
|
select_result(wp, lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (n >= WAIT_OBJECT_0 + extra_base &&
|
||||||
|
n < WAIT_OBJECT_0 + extra_base + n_extra_handles) {
|
||||||
|
extra_handle_index = n - (WAIT_OBJECT_0 + extra_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
run_toplevel_callbacks();
|
||||||
|
|
||||||
|
if (n == WAIT_TIMEOUT) {
|
||||||
|
now = next;
|
||||||
|
} else {
|
||||||
|
now = GETTICKCOUNT();
|
||||||
|
}
|
||||||
|
|
||||||
|
sfree(handles);
|
||||||
|
|
||||||
|
if (!post(ctx, extra_handle_index))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cliloop_null_pre(void *vctx, const HANDLE **eh, size_t *neh)
|
||||||
|
{ return true; }
|
||||||
|
bool cliloop_null_post(void *vctx, size_t ehi) { return true; }
|
@ -231,23 +231,43 @@ const unsigned cmdline_tooltype =
|
|||||||
TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
|
TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
|
||||||
TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD;
|
TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD;
|
||||||
|
|
||||||
|
static bool sending;
|
||||||
|
|
||||||
|
static bool plink_mainloop_pre(void *vctx, const HANDLE **extra_handles,
|
||||||
|
size_t *n_extra_handles)
|
||||||
|
{
|
||||||
|
if (!sending && backend_sendok(backend)) {
|
||||||
|
stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL,
|
||||||
|
0);
|
||||||
|
sending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool plink_mainloop_post(void *vctx, size_t extra_handle_index)
|
||||||
|
{
|
||||||
|
if (sending)
|
||||||
|
handle_unthrottle(stdin_handle, backend_sendbuffer(backend));
|
||||||
|
|
||||||
|
if (!backend_connected(backend) &&
|
||||||
|
handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0)
|
||||||
|
return false; /* we closed the connection */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
bool sending;
|
|
||||||
SOCKET *sklist;
|
|
||||||
size_t skcount, sksize;
|
|
||||||
int exitcode;
|
int exitcode;
|
||||||
bool errors;
|
bool errors;
|
||||||
bool use_subsystem = false;
|
bool use_subsystem = false;
|
||||||
bool just_test_share_exists = false;
|
bool just_test_share_exists = false;
|
||||||
enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
|
enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
|
||||||
unsigned long now, next, then;
|
|
||||||
const struct BackendVtable *vt;
|
const struct BackendVtable *vt;
|
||||||
|
|
||||||
dll_hijacking_protection();
|
dll_hijacking_protection();
|
||||||
|
|
||||||
sklist = NULL;
|
|
||||||
skcount = sksize = 0;
|
|
||||||
/*
|
/*
|
||||||
* Initialise port and protocol to sensible defaults. (These
|
* Initialise port and protocol to sensible defaults. (These
|
||||||
* will be overridden by more or less anything.)
|
* will be overridden by more or less anything.)
|
||||||
@ -487,116 +507,8 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
sending = false;
|
sending = false;
|
||||||
|
|
||||||
now = GETTICKCOUNT();
|
cli_main_loop(plink_mainloop_pre, plink_mainloop_post, NULL);
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int nhandles;
|
|
||||||
HANDLE *handles;
|
|
||||||
int n;
|
|
||||||
DWORD ticks;
|
|
||||||
|
|
||||||
if (!sending && backend_sendok(backend)) {
|
|
||||||
stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL,
|
|
||||||
0);
|
|
||||||
sending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toplevel_callback_pending()) {
|
|
||||||
ticks = 0;
|
|
||||||
next = now;
|
|
||||||
} else if (run_timers(now, &next)) {
|
|
||||||
then = now;
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
if (now - then > next - then)
|
|
||||||
ticks = 0;
|
|
||||||
else
|
|
||||||
ticks = next - now;
|
|
||||||
} else {
|
|
||||||
ticks = INFINITE;
|
|
||||||
/* no need to initialise next here because we can never
|
|
||||||
* get WAIT_TIMEOUT */
|
|
||||||
}
|
|
||||||
|
|
||||||
handles = handle_get_events(&nhandles);
|
|
||||||
handles = sresize(handles, nhandles+1, HANDLE);
|
|
||||||
handles[nhandles] = winselcli_event;
|
|
||||||
n = WaitForMultipleObjects(nhandles+1, handles, false, ticks);
|
|
||||||
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
|
|
||||||
handle_got_event(handles[n - WAIT_OBJECT_0]);
|
|
||||||
} else if (n == WAIT_OBJECT_0 + nhandles) {
|
|
||||||
WSANETWORKEVENTS things;
|
|
||||||
SOCKET socket;
|
|
||||||
int i, socketstate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We must not call select_result() for any socket
|
|
||||||
* until we have finished enumerating within the tree.
|
|
||||||
* This is because select_result() may close the socket
|
|
||||||
* and modify the tree.
|
|
||||||
*/
|
|
||||||
/* Count the active sockets. */
|
|
||||||
i = 0;
|
|
||||||
for (socket = first_socket(&socketstate);
|
|
||||||
socket != INVALID_SOCKET;
|
|
||||||
socket = next_socket(&socketstate)) i++;
|
|
||||||
|
|
||||||
/* Expand the buffer if necessary. */
|
|
||||||
sgrowarray(sklist, sksize, i);
|
|
||||||
|
|
||||||
/* Retrieve the sockets into sklist. */
|
|
||||||
skcount = 0;
|
|
||||||
for (socket = first_socket(&socketstate);
|
|
||||||
socket != INVALID_SOCKET;
|
|
||||||
socket = next_socket(&socketstate)) {
|
|
||||||
sklist[skcount++] = socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we're done enumerating; go through the list. */
|
|
||||||
for (i = 0; i < skcount; i++) {
|
|
||||||
WPARAM wp;
|
|
||||||
socket = sklist[i];
|
|
||||||
wp = (WPARAM) socket;
|
|
||||||
if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
|
|
||||||
static const struct { int bit, mask; } eventtypes[] = {
|
|
||||||
{FD_CONNECT_BIT, FD_CONNECT},
|
|
||||||
{FD_READ_BIT, FD_READ},
|
|
||||||
{FD_CLOSE_BIT, FD_CLOSE},
|
|
||||||
{FD_OOB_BIT, FD_OOB},
|
|
||||||
{FD_WRITE_BIT, FD_WRITE},
|
|
||||||
{FD_ACCEPT_BIT, FD_ACCEPT},
|
|
||||||
};
|
|
||||||
int e;
|
|
||||||
|
|
||||||
noise_ultralight(NOISE_SOURCE_IOID, socket);
|
|
||||||
|
|
||||||
for (e = 0; e < lenof(eventtypes); e++)
|
|
||||||
if (things.lNetworkEvents & eventtypes[e].mask) {
|
|
||||||
LPARAM lp;
|
|
||||||
int err = things.iErrorCode[eventtypes[e].bit];
|
|
||||||
lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
|
|
||||||
select_result(wp, lp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
|
|
||||||
if (n == WAIT_TIMEOUT) {
|
|
||||||
now = next;
|
|
||||||
} else {
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
}
|
|
||||||
|
|
||||||
sfree(handles);
|
|
||||||
|
|
||||||
if (sending)
|
|
||||||
handle_unthrottle(stdin_handle, backend_sendbuffer(backend));
|
|
||||||
|
|
||||||
if (!backend_connected(backend) &&
|
|
||||||
handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0)
|
|
||||||
break; /* we closed the connection */
|
|
||||||
}
|
|
||||||
exitcode = backend_exitcode(backend);
|
exitcode = backend_exitcode(backend);
|
||||||
if (exitcode < 0) {
|
if (exitcode < 0) {
|
||||||
fprintf(stderr, "Remote process exit code unavailable\n");
|
fprintf(stderr, "Remote process exit code unavailable\n");
|
||||||
|
@ -461,123 +461,39 @@ char *dir_file_cat(const char *dir, const char *file)
|
|||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Platform-specific network handling.
|
* Platform-specific network handling.
|
||||||
*/
|
*/
|
||||||
|
struct winsftp_cliloop_ctx {
|
||||||
|
HANDLE other_event;
|
||||||
|
int toret;
|
||||||
|
};
|
||||||
|
static bool winsftp_cliloop_pre(void *vctx, const HANDLE **extra_handles,
|
||||||
|
size_t *n_extra_handles)
|
||||||
|
{
|
||||||
|
struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx;
|
||||||
|
|
||||||
|
if (ctx->other_event != INVALID_HANDLE_VALUE) {
|
||||||
|
*extra_handles = &ctx->other_event;
|
||||||
|
*n_extra_handles = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static bool winsftp_cliloop_post(void *vctx, size_t extra_handle_index)
|
||||||
|
{
|
||||||
|
struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx;
|
||||||
|
|
||||||
|
if (ctx->other_event != INVALID_HANDLE_VALUE &&
|
||||||
|
extra_handle_index == 0)
|
||||||
|
ctx->toret = 1; /* other_event was set */
|
||||||
|
|
||||||
|
return false; /* always run only one loop iteration */
|
||||||
|
}
|
||||||
int do_eventsel_loop(HANDLE other_event)
|
int do_eventsel_loop(HANDLE other_event)
|
||||||
{
|
{
|
||||||
int n, nhandles, nallhandles, netindex, otherindex;
|
struct winsftp_cliloop_ctx ctx[1];
|
||||||
unsigned long next, then;
|
ctx->other_event = other_event;
|
||||||
long ticks;
|
ctx->toret = 0;
|
||||||
HANDLE *handles;
|
cli_main_loop(winsftp_cliloop_pre, winsftp_cliloop_post, ctx);
|
||||||
SOCKET *sklist;
|
return ctx->toret;
|
||||||
int skcount;
|
|
||||||
unsigned long now = GETTICKCOUNT();
|
|
||||||
|
|
||||||
if (toplevel_callback_pending()) {
|
|
||||||
ticks = 0;
|
|
||||||
next = now;
|
|
||||||
} else if (run_timers(now, &next)) {
|
|
||||||
then = now;
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
if (now - then > next - then)
|
|
||||||
ticks = 0;
|
|
||||||
else
|
|
||||||
ticks = next - now;
|
|
||||||
} else {
|
|
||||||
ticks = INFINITE;
|
|
||||||
/* no need to initialise next here because we can never get
|
|
||||||
* WAIT_TIMEOUT */
|
|
||||||
}
|
|
||||||
|
|
||||||
handles = handle_get_events(&nhandles);
|
|
||||||
handles = sresize(handles, nhandles+2, HANDLE);
|
|
||||||
nallhandles = nhandles;
|
|
||||||
|
|
||||||
if (winselcli_event != INVALID_HANDLE_VALUE)
|
|
||||||
handles[netindex = nallhandles++] = winselcli_event;
|
|
||||||
else
|
|
||||||
netindex = -1;
|
|
||||||
if (other_event != INVALID_HANDLE_VALUE)
|
|
||||||
handles[otherindex = nallhandles++] = other_event;
|
|
||||||
else
|
|
||||||
otherindex = -1;
|
|
||||||
|
|
||||||
n = WaitForMultipleObjects(nallhandles, handles, false, ticks);
|
|
||||||
|
|
||||||
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
|
|
||||||
handle_got_event(handles[n - WAIT_OBJECT_0]);
|
|
||||||
} else if (netindex >= 0 && n == WAIT_OBJECT_0 + netindex) {
|
|
||||||
WSANETWORKEVENTS things;
|
|
||||||
SOCKET socket;
|
|
||||||
int i, socketstate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We must not call select_result() for any socket
|
|
||||||
* until we have finished enumerating within the
|
|
||||||
* tree. This is because select_result() may close
|
|
||||||
* the socket and modify the tree.
|
|
||||||
*/
|
|
||||||
/* Count the active sockets. */
|
|
||||||
i = 0;
|
|
||||||
for (socket = first_socket(&socketstate);
|
|
||||||
socket != INVALID_SOCKET;
|
|
||||||
socket = next_socket(&socketstate)) i++;
|
|
||||||
|
|
||||||
/* Expand the buffer if necessary. */
|
|
||||||
sklist = snewn(i, SOCKET);
|
|
||||||
|
|
||||||
/* Retrieve the sockets into sklist. */
|
|
||||||
skcount = 0;
|
|
||||||
for (socket = first_socket(&socketstate);
|
|
||||||
socket != INVALID_SOCKET;
|
|
||||||
socket = next_socket(&socketstate)) {
|
|
||||||
sklist[skcount++] = socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we're done enumerating; go through the list. */
|
|
||||||
for (i = 0; i < skcount; i++) {
|
|
||||||
WPARAM wp;
|
|
||||||
socket = sklist[i];
|
|
||||||
wp = (WPARAM) socket;
|
|
||||||
if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
|
|
||||||
static const struct { int bit, mask; } eventtypes[] = {
|
|
||||||
{FD_CONNECT_BIT, FD_CONNECT},
|
|
||||||
{FD_READ_BIT, FD_READ},
|
|
||||||
{FD_CLOSE_BIT, FD_CLOSE},
|
|
||||||
{FD_OOB_BIT, FD_OOB},
|
|
||||||
{FD_WRITE_BIT, FD_WRITE},
|
|
||||||
{FD_ACCEPT_BIT, FD_ACCEPT},
|
|
||||||
};
|
|
||||||
int e;
|
|
||||||
|
|
||||||
noise_ultralight(NOISE_SOURCE_IOID, socket);
|
|
||||||
|
|
||||||
for (e = 0; e < lenof(eventtypes); e++)
|
|
||||||
if (things.lNetworkEvents & eventtypes[e].mask) {
|
|
||||||
LPARAM lp;
|
|
||||||
int err = things.iErrorCode[eventtypes[e].bit];
|
|
||||||
lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
|
|
||||||
select_result(wp, lp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sfree(sklist);
|
|
||||||
}
|
|
||||||
|
|
||||||
sfree(handles);
|
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
|
|
||||||
if (n == WAIT_TIMEOUT) {
|
|
||||||
now = next;
|
|
||||||
} else {
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otherindex >= 0 && n == WAIT_OBJECT_0 + otherindex)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -686,4 +686,12 @@ char *get_jumplist_registry_entries(void);
|
|||||||
/* In winmisc.c */
|
/* In winmisc.c */
|
||||||
char *registry_get_string(HKEY root, const char *path, const char *leaf);
|
char *registry_get_string(HKEY root, const char *path, const char *leaf);
|
||||||
|
|
||||||
|
/* In wincliloop.c */
|
||||||
|
typedef bool (*cliloop_pre_t)(void *vctx, const HANDLE **extra_handles,
|
||||||
|
size_t *n_extra_handles);
|
||||||
|
typedef bool (*cliloop_post_t)(void *vctx, size_t extra_handle_index);
|
||||||
|
void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx);
|
||||||
|
bool cliloop_null_pre(void *vctx, const HANDLE **, size_t *);
|
||||||
|
bool cliloop_null_post(void *vctx, size_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user