X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/839f10dbef33ef2982689a05f8305690aba92734..c44bf5bd7bf680c21356864ac5ae72ab29e55ce6:/pageantc.c diff --git a/pageantc.c b/pageantc.c index d7dbfc01..3d5e61f2 100644 --- a/pageantc.c +++ b/pageantc.c @@ -6,17 +6,11 @@ #include #include -#include "puttymem.h" +#include "putty.h" #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ #define AGENT_MAX_MSGLEN 8192 -#ifdef TESTMODE -#define debug(x) (printf x) -#else -#define debug(x) -#endif - #define GET_32BIT(cp) \ (((unsigned long)(unsigned char)(cp)[0] << 24) | \ ((unsigned long)(unsigned char)(cp)[1] << 16) | \ @@ -33,11 +27,48 @@ int agent_exists(void) return TRUE; } +struct agent_query_data { + COPYDATASTRUCT cds; + unsigned char *mapping; + HANDLE handle; + char *mapname; + HWND hwnd; + void (*callback)(void *, void *, int); + void *callback_ctx; +}; + +DWORD WINAPI agent_query_thread(LPVOID param) +{ + struct agent_query_data *data = (struct agent_query_data *)param; + unsigned char *ret; + int id, retlen; + + id = SendMessage(data->hwnd, WM_COPYDATA, (WPARAM) NULL, + (LPARAM) &data->cds); + ret = NULL; + if (id > 0) { + retlen = 4 + GET_32BIT(data->mapping); + ret = snewn(retlen, unsigned char); + if (ret) { + memcpy(ret, data->mapping, retlen); + } + } + if (!ret) + retlen = 0; + UnmapViewOfFile(data->mapping); + CloseHandle(data->handle); + sfree(data->mapname); + + agent_schedule_callback(data->callback, data->callback_ctx, ret, retlen); + + return 0; +} + int agent_query(void *in, int inlen, void **out, int *outlen, void (*callback)(void *, void *, int), void *callback_ctx) { HWND hwnd; - char mapname[64]; + char *mapname; HANDLE filemap; unsigned char *p, *ret; int id, retlen; @@ -47,10 +78,9 @@ int agent_query(void *in, int inlen, void **out, int *outlen, *outlen = 0; hwnd = FindWindow("Pageant", "Pageant"); - debug(("hwnd is %p\n", hwnd)); if (!hwnd) return 1; /* *out == NULL, so failure */ - sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); + mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname); if (!filemap) @@ -60,11 +90,37 @@ int agent_query(void *in, int inlen, void **out, int *outlen, cds.dwData = AGENT_COPYDATA_ID; cds.cbData = 1 + strlen(mapname); cds.lpData = mapname; + if (callback != NULL && !(flags & FLAG_SYNCAGENT)) { + /* + * We need an asynchronous Pageant request. Since I know of + * no way to stop SendMessage from blocking the thread it's + * called in, I see no option but to start a fresh thread. + * When we're done we'll PostMessage the result back to our + * main window, so that the callback is done in the primary + * thread to avoid concurrency. + */ + struct agent_query_data *data = snew(struct agent_query_data); + DWORD threadid; + data->mapping = p; + data->handle = filemap; + data->mapname = mapname; + data->callback = callback; + data->callback_ctx = callback_ctx; + data->cds = cds; /* structure copy */ + data->hwnd = hwnd; + if (CreateThread(NULL, 0, agent_query_thread, data, 0, &threadid)) + return 0; + sfree(data); + } + + /* + * The user either passed a null callback (indicating that the + * query is required to be synchronous) or CreateThread failed. + * Either way, we need a synchronous request. + */ id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) & cds); - debug(("return is %d\n", id)); if (id > 0) { retlen = 4 + GET_32BIT(p); - debug(("len is %d\n", retlen)); ret = snewn(retlen, unsigned char); if (ret) { memcpy(ret, p, retlen); @@ -74,24 +130,5 @@ int agent_query(void *in, int inlen, void **out, int *outlen, } UnmapViewOfFile(p); CloseHandle(filemap); - return 1; } - -#ifdef TESTMODE - -int main(void) -{ - void *msg; - int len; - int i; - - agent_query("\0\0\0\1\1", 5, &msg, &len); - debug(("%d:", len)); - for (i = 0; i < len; i++) - debug((" %02x", ((unsigned char *) msg)[i])); - debug(("\n")); - return 0; -} - -#endif