Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/shell32/dde.c | 115 +++++++++++++++++++++++++++++++++++++++++--- dlls/shell32/shell32_main.h | 13 +++++ 2 files changed, 121 insertions(+), 7 deletions(-)
diff --git a/dlls/shell32/dde.c b/dlls/shell32/dde.c index c44f05d..ae1143b 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; + 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--; + }
- pszCommand = (WCHAR *)DdeAccessData(hdata, NULL); - if (!pszCommand) - return DDE_FNOTPROCESSED; + argc++; + argv = HeapReAlloc(GetProcessHeap(), 0, argv, argc * sizeof(*argv)); + argv[argc-1] = strndupW(command, p - command);
- FIXME("stub: %s %s\n", debugstr_hsz(hszTopic), debugstr_w(pszCommand)); + command = p; + if (*command == '"') command++; + while (*command == ' ') command++; + if (*command == ',') command++; + else if (*command != ')') goto error; + } + command++;
- DdeUnaccessData(hdata); + 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 368c0e0..b65141f 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;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/shell32/dde.c | 43 ++++++++++++++++++++++++++++++++++++++-- dlls/shell32/tests/progman_dde.c | 35 ++++++++++++-------------------- 2 files changed, 54 insertions(+), 24 deletions(-)
diff --git a/dlls/shell32/dde.c b/dlls/shell32/dde.c index ae1143b..3a18d3a 100644 --- a/dlls/shell32/dde.c +++ b/dlls/shell32/dde.c @@ -97,10 +97,49 @@ static inline HDDEDATA Dde_OnRequest(UINT uFmt, HCONV hconv, HSZ hszTopic, return NULL; }
+/* Returned string must be freed by caller */ +static WCHAR *get_programs_path(WCHAR *name) +{ + static const WCHAR slashW[] = {'/',0}; + WCHAR *programs, *path; + int len; + + SHGetKnownFolderPath(&FOLDERID_Programs, 0, NULL, &programs); + + len = lstrlenW(programs) + 1 + lstrlenW(name); + path = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(*path)); + lstrcpyW(path, programs); + lstrcatW(path, slashW); + lstrcatW(path, name); + + CoTaskMemFree(programs); + + return path; +} + static DWORD PROGMAN_OnExecute(WCHAR *command, int argc, WCHAR **argv) { - FIXME("unhandled command %s\n", debugstr_w(command)); - return DDE_FNOTPROCESSED; + static const WCHAR create_groupW[] = {'C','r','e','a','t','e','G','r','o','u','p',0}; + + if (!strcmpiW(command, create_groupW)) + { + WCHAR *path; + + if (argc < 1) return DDE_FNOTPROCESSED; + + path = get_programs_path(argv[0]); + + CreateDirectoryW(path, NULL); + ShellExecuteW(NULL, NULL, path, NULL, NULL, SW_SHOWNORMAL); + + HeapFree(GetProcessHeap(), 0, path); + } + else + { + FIXME("unhandled command %s\n", debugstr_w(command)); + return DDE_FNOTPROCESSED; + } + return DDE_FACK; }
static DWORD parse_dde_command(HSZ hszTopic, WCHAR *command) diff --git a/dlls/shell32/tests/progman_dde.c b/dlls/shell32/tests/progman_dde.c index 35e4b0c..73a79a8 100644 --- a/dlls/shell32/tests/progman_dde.c +++ b/dlls/shell32/tests/progman_dde.c @@ -281,12 +281,9 @@ static void test_progman_dde(DWORD instance, HCONV hConv)
/* CreateGroup Tests (including AddItem, DeleteItem) */ error = dde_execute(instance, hConv, "[CreateGroup(Group1)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(check_exists("Group1"), "directory not created\n"); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(Group1Title), "window not created\n"); - } + ok(check_window_exists(Group1Title), "window not created\n");
sprintf(itemtext, "[AddItem(%s,f1g1Name)]", f1g1); error = dde_execute(instance, hConv, itemtext); @@ -315,21 +312,15 @@ static void test_progman_dde(DWORD instance, HCONV hConv) }
error = dde_execute(instance, hConv, "[CreateGroup(Group2)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(check_exists("Group2"), "directory not created\n"); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(Group2Title), "window not created\n"); - } + ok(check_window_exists(Group2Title), "window not created\n");
/* Create Group that already exists - same instance */ error = dde_execute(instance, hConv, "[CreateGroup(Group1)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(check_exists("Group1"), "directory not created\n"); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(Group1Title), "window not created\n"); - } + ok(check_window_exists(Group1Title), "window not created\n");
/* ShowGroup Tests */ error = dde_execute(instance, hConv, "[ShowGroup(Group1)]"); @@ -356,26 +347,28 @@ static void test_progman_dde(DWORD instance, HCONV hConv)
/* DeleteGroup Test */ error = dde_execute(instance, hConv, "[DeleteGroup(Group1)]"); - todo_wine + todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(!check_exists("Group1"), "directory should not exist\n"); + }
/* Compound Execute String Command */ sprintf(comptext, "[CreateGroup(Group3)][AddItem(%s,f1g3Name)][AddItem(%s,f2g3Name)]", f1g3, f2g3); error = dde_execute(instance, hConv, comptext); - todo_wine { + todo_wine ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(check_exists("Group3"), "directory not created\n"); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(Group3Title), "window not created\n"); + ok(check_window_exists(Group3Title), "window not created\n"); + todo_wine { ok(check_exists("Group3/f1g3Name.lnk"), "link not created\n"); ok(check_exists("Group3/f2g3Name.lnk"), "link not created\n"); }
error = dde_execute(instance, hConv, "[DeleteGroup(Group3)]"); - todo_wine + todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(!check_exists("Group3"), "directory should not exist\n"); + }
/* Full Parameters of Add Item */ /* AddItem(CmdLine[,Name[,IconPath[,IconIndex[,xPos,yPos[,DefDir[,HotKey[,fMinimize[fSeparateSpace]]]]]]]) */ @@ -394,17 +387,15 @@ static void test_progman_dde2(DWORD instance, HCONV hConv)
/* Create Group that already exists on a separate connection */ error = dde_execute(instance, hConv, "[CreateGroup(Group2)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(check_exists("Group2"), "directory not created\n"); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(Group2Title), "window not created\n"); - } + ok(check_window_exists(Group2Title), "window not created\n");
error = dde_execute(instance, hConv, "[DeleteGroup(Group2)]"); - todo_wine + todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(!check_exists("Group2"), "directory should not exist\n"); + } }
START_TEST(progman_dde)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/shell32/dde.c | 26 ++++++++++++++++++++++++++ dlls/shell32/tests/progman_dde.c | 6 ------ 2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/dlls/shell32/dde.c b/dlls/shell32/dde.c index 3a18d3a..a1aac15 100644 --- a/dlls/shell32/dde.c +++ b/dlls/shell32/dde.c @@ -120,6 +120,7 @@ static WCHAR *get_programs_path(WCHAR *name) static DWORD PROGMAN_OnExecute(WCHAR *command, int argc, WCHAR **argv) { static const WCHAR create_groupW[] = {'C','r','e','a','t','e','G','r','o','u','p',0}; + static const WCHAR delete_groupW[] = {'D','e','l','e','t','e','G','r','o','u','p',0};
if (!strcmpiW(command, create_groupW)) { @@ -134,6 +135,31 @@ static DWORD PROGMAN_OnExecute(WCHAR *command, int argc, WCHAR **argv)
HeapFree(GetProcessHeap(), 0, path); } + else if (!strcmpiW(command, delete_groupW)) + { + WCHAR *path, *path2; + SHFILEOPSTRUCTW shfos = {0}; + int ret; + + if (argc < 1) return DDE_FNOTPROCESSED; + + path = get_programs_path(argv[0]); + + path2 = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 2) * sizeof(*path)); + strcpyW(path2, path); + path2[strlenW(path) + 1] = 0; + + shfos.wFunc = FO_DELETE; + shfos.pFrom = path2; + shfos.fFlags = FOF_NOCONFIRMATION; + + ret = SHFileOperationW(&shfos); + + HeapFree(GetProcessHeap(), 0, path2); + HeapFree(GetProcessHeap(), 0, path); + + if (ret || shfos.fAnyOperationsAborted) return DDE_FNOTPROCESSED; + } else { FIXME("unhandled command %s\n", debugstr_w(command)); diff --git a/dlls/shell32/tests/progman_dde.c b/dlls/shell32/tests/progman_dde.c index 73a79a8..c5fd262 100644 --- a/dlls/shell32/tests/progman_dde.c +++ b/dlls/shell32/tests/progman_dde.c @@ -347,10 +347,8 @@ static void test_progman_dde(DWORD instance, HCONV hConv)
/* DeleteGroup Test */ error = dde_execute(instance, hConv, "[DeleteGroup(Group1)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(!check_exists("Group1"), "directory should not exist\n"); - }
/* Compound Execute String Command */ sprintf(comptext, "[CreateGroup(Group3)][AddItem(%s,f1g3Name)][AddItem(%s,f2g3Name)]", f1g3, f2g3); @@ -365,10 +363,8 @@ static void test_progman_dde(DWORD instance, HCONV hConv) }
error = dde_execute(instance, hConv, "[DeleteGroup(Group3)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(!check_exists("Group3"), "directory should not exist\n"); - }
/* Full Parameters of Add Item */ /* AddItem(CmdLine[,Name[,IconPath[,IconIndex[,xPos,yPos[,DefDir[,HotKey[,fMinimize[fSeparateSpace]]]]]]]) */ @@ -392,10 +388,8 @@ static void test_progman_dde2(DWORD instance, HCONV hConv) ok(check_window_exists(Group2Title), "window not created\n");
error = dde_execute(instance, hConv, "[DeleteGroup(Group2)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); ok(!check_exists("Group2"), "directory should not exist\n"); - } }
START_TEST(progman_dde)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/shell32/dde.c | 15 +++++++++++++++ dlls/shell32/tests/progman_dde.c | 10 ++-------- 2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/dlls/shell32/dde.c b/dlls/shell32/dde.c index a1aac15..d04bab8 100644 --- a/dlls/shell32/dde.c +++ b/dlls/shell32/dde.c @@ -121,6 +121,7 @@ static DWORD PROGMAN_OnExecute(WCHAR *command, int argc, WCHAR **argv) { static const WCHAR create_groupW[] = {'C','r','e','a','t','e','G','r','o','u','p',0}; static const WCHAR delete_groupW[] = {'D','e','l','e','t','e','G','r','o','u','p',0}; + static const WCHAR show_groupW[] = {'S','h','o','w','G','r','o','u','p',0};
if (!strcmpiW(command, create_groupW)) { @@ -160,6 +161,20 @@ static DWORD PROGMAN_OnExecute(WCHAR *command, int argc, WCHAR **argv)
if (ret || shfos.fAnyOperationsAborted) return DDE_FNOTPROCESSED; } + else if (!strcmpiW(command, show_groupW)) + { + WCHAR *path; + + /* Win32 requires the second parameter to be present but seems to + * ignore its actual value. */ + if (argc < 2) return DDE_FNOTPROCESSED; + + path = get_programs_path(argv[0]); + + ShellExecuteW(NULL, NULL, path, NULL, NULL, SW_SHOWNORMAL); + + HeapFree(GetProcessHeap(), 0, path); + } else { FIXME("unhandled command %s\n", debugstr_w(command)); diff --git a/dlls/shell32/tests/progman_dde.c b/dlls/shell32/tests/progman_dde.c index c5fd262..b54a72a 100644 --- a/dlls/shell32/tests/progman_dde.c +++ b/dlls/shell32/tests/progman_dde.c @@ -332,18 +332,12 @@ static void test_progman_dde(DWORD instance, HCONV hConv) ok(!check_exists("Group1/f3g1Name.lnk"), "link should not exist\n");
error = dde_execute(instance, hConv, "[ShowGroup(Startup, 0)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(StartupTitle), "window not created\n"); - } + ok(check_window_exists(StartupTitle), "window not created\n");
error = dde_execute(instance, hConv, "[ShowGroup(Group1, 0)]"); - todo_wine { ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error); - if (error == DMLERR_NO_ERROR) - ok(check_window_exists(Group1Title), "window not created\n"); - } + ok(check_window_exists(Group1Title), "window not created\n");
/* DeleteGroup Test */ error = dde_execute(instance, hConv, "[DeleteGroup(Group1)]");