From 6778023999912e0b3f601188bcca9a7971d8193b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 29 Nov 2017 17:00:45 -0600 Subject: [PATCH] shell32: Add a parser for DDE commands. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/shell32/dde.c | 123 ++++++++++++++++++++++++++++++++---- dlls/shell32/shell32_main.h | 13 ++++ 2 files changed, 125 insertions(+), 11 deletions(-) diff --git a/dlls/shell32/dde.c b/dlls/shell32/dde.c index c44f05d3415..ae1143b1708 100644 --- a/dlls/shell32/dde.c +++ b/dlls/shell32/dde.c @@ -26,7 +26,10 @@ #include "ddeml.h" #include "shellapi.h" +#include "shell32_main.h" + #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); @@ -94,21 +97,119 @@ static inline HDDEDATA Dde_OnRequest(UINT uFmt, HCONV hconv, HSZ hszTopic, return NULL; } -static inline DWORD Dde_OnExecute(HCONV hconv, HSZ hszTopic, HDDEDATA hdata) +static DWORD PROGMAN_OnExecute(WCHAR *command, int argc, WCHAR **argv) { - WCHAR * pszCommand; - - pszCommand = (WCHAR *)DdeAccessData(hdata, NULL); - if (!pszCommand) - return DDE_FNOTPROCESSED; - - FIXME("stub: %s %s\n", debugstr_hsz(hszTopic), debugstr_w(pszCommand)); - - DdeUnaccessData(hdata); - + FIXME("unhandled command %s\n", debugstr_w(command)); return DDE_FNOTPROCESSED; } +static DWORD parse_dde_command(HSZ hszTopic, WCHAR *command) +{ + static const WCHAR opcode_end[] = {' ',',','(',')','[',']','"',0}; + static const WCHAR param_end[] = {',','(',')','[',']',0}; + + WCHAR *original = command; + WCHAR *opcode = NULL, **argv = NULL, *p; + int argc = 0, i; + DWORD ret = DDE_FACK; + + while (*command == ' ') command++; + + if (*command != '[') goto error; + while (*command == '[') + { + argc = 0; + argv = HeapAlloc(GetProcessHeap(), 0, sizeof(*argv)); + + command++; + while (*command == ' ') command++; + if (!(p = strpbrkW(command, opcode_end))) goto error; + + opcode = strndupW(command, p - command); + + command = p; + while (*command == ' ') command++; + if (*command == '(') + { + command++; + + while (*command != ')') + { + while (*command == ' ') command++; + if (*command == '"') + { + command++; + if (!(p = strchrW(command, '"'))) goto error; + } + else + { + if (!(p = strpbrkW(command, param_end))) goto error; + while (p[-1] == ' ') p--; + } + + argc++; + argv = HeapReAlloc(GetProcessHeap(), 0, argv, argc * sizeof(*argv)); + argv[argc-1] = strndupW(command, p - command); + + command = p; + if (*command == '"') command++; + while (*command == ' ') command++; + if (*command == ',') command++; + else if (*command != ')') goto error; + } + command++; + + while (*command == ' ') command++; + } + + if (*command != ']') goto error; + command++; + while (*command == ' ') command++; + + if (hszTopic == hszProgmanTopic) + ret = PROGMAN_OnExecute(opcode, argc, argv); + else + { + FIXME("unhandled topic %s, command %s\n", debugstr_hsz(hszTopic), debugstr_w(opcode)); + ret = DDE_FNOTPROCESSED; + } + + HeapFree(GetProcessHeap(), 0, opcode); + for (i = 0; i < argc; i++) HeapFree(GetProcessHeap(), 0, argv[i]); + HeapFree(GetProcessHeap(), 0, argv); + + if (ret == DDE_FNOTPROCESSED) break; + } + + return ret; + +error: + ERR("failed to parse command %s\n", debugstr_w(original)); + HeapFree(GetProcessHeap(), 0, opcode); + for (i = 0; i < argc; i++) HeapFree(GetProcessHeap(), 0, argv[i]); + HeapFree(GetProcessHeap(), 0, argv); + return DDE_FNOTPROCESSED; +} + +static DWORD Dde_OnExecute(HCONV hconv, HSZ hszTopic, HDDEDATA hdata) +{ + WCHAR *command; + DWORD len; + DWORD ret; + + len = DdeGetData(hdata, NULL, 0, 0); + if (!len) return DDE_FNOTPROCESSED; + command = HeapAlloc(GetProcessHeap(), 0, len); + DdeGetData(hdata, (BYTE *)command, len, 0); + + TRACE("conv=%p topic=%s data=%s\n", hconv, debugstr_hsz(hszTopic), debugstr_w(command)); + + ret = parse_dde_command(hszTopic, command); + + HeapFree(GetProcessHeap(), 0, command); + return ret; +} + static inline void Dde_OnDisconnect(HCONV hconv) { TRACE( "%p\n", hconv ); diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 368c0e0da60..b65141f489e 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -238,6 +238,19 @@ static inline WCHAR *strdupW(const WCHAR *src) return dest; } +static inline WCHAR *strndupW(const WCHAR *src, DWORD len) +{ + WCHAR *dest; + if (!src) return NULL; + dest = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(*dest)); + if (dest) + { + memcpy(dest, src, len * sizeof(WCHAR)); + dest[len] = '\0'; + } + return dest; +} + static inline WCHAR *strdupAtoW(const char *str) { WCHAR *ret;