diff --git a/reactos/dll/win32/shell32/control.cpp b/reactos/dll/win32/shell32/control.cpp index 8f8a688e4e9..59ba59288f1 100644 --- a/reactos/dll/win32/shell32/control.cpp +++ b/reactos/dll/win32/shell32/control.cpp @@ -348,102 +348,146 @@ static void Control_DoWindow(CPanel *panel, HWND hWnd, HINSTANCE hInst) Control_DoInterface(panel, hWnd, hInst); } -static void Control_DoLaunch(CPanel *pPanel, HWND hWnd, LPCWSTR pwszCmd) +static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd) + /* forms to parse: + * foo.cpl,@sp,str + * foo.cpl,@sp + * foo.cpl,,str + * foo.cpl @sp + * foo.cpl str + * "a path\foo.cpl" + */ { - /* Make a pwszCmd copy so we can modify it */ - LPWSTR pwszCmdCopy = _wcsdup(pwszCmd); - if (!pwszCmdCopy) - return; + LPWSTR buffer; + LPWSTR beg = NULL; + LPWSTR end; + WCHAR ch; + LPCWSTR ptr, ptr2; + WCHAR szName[MAX_PATH]; + unsigned sp = 0; + LPWSTR extraPmts = NULL; + int quoted = 0; + BOOL spSet = FALSE; + HANDLE hMutex; + UINT Length; - LPWSTR pwszPath = pwszCmdCopy, pwszArg = NULL, pwszArg2 = NULL; - - /* Path can be quoted */ - if (pwszPath[0] == L'"') + ptr = wcsrchr(wszCmd, L'\\'); + ptr2 = wcsrchr(wszCmd, L','); + if (!ptr2) { - ++pwszPath; - pwszArg = wcschr(pwszPath, L'"'); - if (pwszArg) - *(pwszArg++) = '\0'; + ptr2 = wszCmd + wcslen(wszCmd) + 1; } + + if (ptr) + ptr++; else - pwszArg = pwszCmdCopy; + ptr = wszCmd; - /* First argument starts after space or ','. Note: we ignore characters between '"' and ',' or ' '. */ - if (pwszArg) - pwszArg = wcspbrk(pwszArg, L" ,"); - if (pwszArg) + Length = (ptr2 - ptr); + if (Length >= MAX_PATH) + return; + + memcpy(szName, (LPVOID)ptr, Length * sizeof(WCHAR)); + szName[Length] = L'\0'; + hMutex = CreateMutexW(NULL, TRUE, szName); + + if ((!hMutex) || (GetLastError() == ERROR_ALREADY_EXISTS)) + return; + buffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(wszCmd) + 1) * sizeof(*wszCmd)); + if (!buffer) { - /* NULL terminate path and find first character of arg */ - *(pwszArg++) = L'\0'; - if (pwszArg[0] == L'"') - { - ++pwszArg; - pwszArg2 = wcschr(pwszArg, L'"'); - if (pwszArg2) - *(pwszArg2++) = L'\0'; - } else - pwszArg2 = pwszArg; - - /* Second argument always starts with ','. Note: we ignore characters between '"' and ','. */ - if (pwszArg2) - pwszArg2 = wcschr(pwszArg2, L','); - } - - TRACE("Launch %ls, arg %ls, arg2 %ls\n", pwszPath, pwszArg, pwszArg2); - - /* Create a mutex to disallow running multiple instances */ - HANDLE hMutex = CreateMutexW(NULL, TRUE, PathFindFileNameW(pwszPath)); - if (!hMutex || GetLastError() == ERROR_ALREADY_EXISTS) - { - TRACE("Next instance disallowed\n"); - if (hMutex) - CloseHandle(hMutex); + CloseHandle(hMutex); return; } - /* Load applet cpl */ - TRACE("Load applet %ls\n", pwszPath); - Control_LoadApplet(hWnd, pwszPath, pPanel); - if (pPanel->first) + TRACE("[shell32, Control_DoLaunch] wszCmd = %ws\n", wszCmd); + + end = wcscpy(buffer, wszCmd); + for (;;) { - /* First pPanel applet is the new one */ - CPlApplet *pApplet = pPanel->first; - assert(pApplet && pApplet->next == NULL); - TRACE("pApplet->count %d\n", pApplet->count); + ch = *end; + if (ch == '"') + quoted = !quoted; - /* Note: if there is only one applet, first argument is ignored */ - INT i = 0; - if (pApplet->count > 1 && pwszArg && pwszArg[0]) + if (!quoted && (ch == ',' || ch == '\0')) { - /* If arg begins with '@', number specifies applet index */ - if (pwszArg[0] == L'@') - i = _wtoi(pwszArg + 1); - else + *end = '\0'; + if (beg) { - /* Otherwise it's applet name */ - for (i = 0; i < (INT)pApplet->count; ++i) - if (!wcscmp(pwszArg, pApplet->info[i].szName)) - break; + if (*beg == '@') + { + sp = atoiW(beg + 1); + spSet = TRUE; + } + else if (*beg == '\0') + { + sp = 0; + spSet = TRUE; + } + else + { + extraPmts = beg; + } + } + + if (ch == '\0') break; + beg = end + 1; + if (ch == ' ') + while (end[1] == ' ') + end++; + } + end++; + } + while ((ptr = StrChrW(buffer, '"'))) + memmove((LPVOID)ptr, ptr+1, wcslen(ptr)*sizeof(WCHAR)); + + while ((ptr = StrChrW(extraPmts, '"'))) + memmove((LPVOID)ptr, ptr+1, wcslen(ptr)*sizeof(WCHAR)); + + TRACE("[shell32, Control_DoLaunch] cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp); + + Control_LoadApplet(hWnd, buffer, panel); + + if (panel->first) + { + CPlApplet* applet = panel->first; + + TRACE("[shell32, Control_DoLaunch] applet->count %d, applet->info[sp].szName %ws\n", applet->count, applet->info[sp].szName); + + assert(applet && applet->next == NULL); + if (sp >= applet->count) + { + WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count); + sp = 0; + } + + if ((extraPmts) && extraPmts[0] && (!spSet)) + { + while ((lstrcmpiW(extraPmts, applet->info[sp].szName)) && (sp < applet->count)) + sp++; + + if (sp >= applet->count) + { + ReleaseMutex(hMutex); + CloseHandle(hMutex); + Control_UnloadApplet(applet); + HeapFree(GetProcessHeap(), 0, buffer); + return; } } - if (i >= 0 && i < (INT)pApplet->count && pApplet->info[i].dwSize) + if (applet->info[sp].dwSize) { - /* Start the applet */ - TRACE("Starting applet %d\n", i); - if (!pApplet->proc(pApplet->hWnd, CPL_DBLCLK, i, pApplet->info[i].lData)) - pApplet->proc(pApplet->hWnd, CPL_STARTWPARMSA, i, (LPARAM)pwszArg); - } else - ERR("Applet not found: %ls\n", pwszArg ? pwszArg : L"NULL"); + if (!applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData)) + applet->proc(applet->hWnd, CPL_STARTWPARMSA, sp, (LPARAM)extraPmts); + } - Control_UnloadApplet(pApplet); + Control_UnloadApplet(applet); } - else - ERR("Failed to load applet %ls\n", pwszPath); ReleaseMutex(hMutex); CloseHandle(hMutex); - free(pwszCmdCopy); + HeapFree(GetProcessHeap(), 0, buffer); } /************************************************************************* @@ -452,22 +496,22 @@ static void Control_DoLaunch(CPanel *pPanel, HWND hWnd, LPCWSTR pwszCmd) */ EXTERN_C void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow) { - CPanel Panel; + CPanel panel; TRACE("(%p, %p, %s, 0x%08x)\n", hWnd, hInst, debugstr_w(cmd), nCmdShow); - memset(&Panel, 0, sizeof(Panel)); + memset(&panel, 0, sizeof(panel)); if (!cmd || !*cmd) { TRACE("[shell32, Control_RunDLLW] Calling Control_DoWindow\n"); - Control_DoWindow(&Panel, hWnd, hInst); + Control_DoWindow(&panel, hWnd, hInst); } else { TRACE("[shell32, Control_RunDLLW] Calling Control_DoLaunch\n"); - Control_DoLaunch(&Panel, hWnd, cmd); + Control_DoLaunch(&panel, hWnd, cmd); } }