Author: rharabien Date: Sat Jan 14 17:14:54 2012 New Revision: 54960
URL: http://svn.reactos.org/svn/reactos?rev=54960&view=rev Log: [SHELL32] - Rewrite Control_DoLaunch. Now if cpl has only one applet, applet name/id is ignored - When launching control panel applets always execute rundll32 instead of using static handlers from registry
Modified: trunk/reactos/dll/win32/shell32/control.cpp trunk/reactos/dll/win32/shell32/folders/cpanel.cpp trunk/reactos/dll/win32/shell32/folders/cpanel.h
Modified: trunk/reactos/dll/win32/shell32/control.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/control.c... ============================================================================== --- trunk/reactos/dll/win32/shell32/control.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/control.cpp [iso-8859-1] Sat Jan 14 17:14:54 2012 @@ -348,146 +348,102 @@ Control_DoInterface(panel, hWnd, hInst); }
-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" - */ -{ - 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; - - ptr = wcsrchr(wszCmd, L'\'); - ptr2 = wcsrchr(wszCmd, L','); - if (!ptr2) - { - ptr2 = wszCmd + wcslen(wszCmd) + 1; - } - - if (ptr) - ptr++; +static void Control_DoLaunch(CPanel *pPanel, HWND hWnd, LPCWSTR pwszCmd) +{ + /* Make a pwszCmd copy so we can modify it */ + LPWSTR pwszCmdCopy = _wcsdup(pwszCmd); + if (!pwszCmdCopy) + return; + + LPWSTR pwszPath = pwszCmdCopy, pwszArg = NULL, pwszArg2 = NULL; + + /* Path can be quoted */ + if (pwszPath[0] == L'"') + { + ++pwszPath; + pwszArg = wcschr(pwszPath, L'"'); + if (pwszArg) + *(pwszArg++) = '\0'; + } else - ptr = wszCmd; - - Length = (ptr2 - ptr); - if (Length >= MAX_PATH) + pwszArg = pwszCmdCopy; + + /* First argument starts after space or ','. Note: we ignore characters between '"' and ',' or ' '. */ + if (pwszArg) + pwszArg = wcspbrk(pwszArg, L" ,"); + if (pwszArg) + { + /* 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); 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) - { - CloseHandle(hMutex); - return; - } - - TRACE("[shell32, Control_DoLaunch] wszCmd = %ws\n", wszCmd); - - end = wcscpy(buffer, wszCmd); - for (;;) - { - ch = *end; - if (ch == '"') - quoted = !quoted; - - if (!quoted && (ch == ',' || ch == '\0')) - { - *end = '\0'; - if (beg) - { - 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 (applet->info[sp].dwSize) - { - if (!applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData)) - applet->proc(applet->hWnd, CPL_STARTWPARMSA, sp, (LPARAM)extraPmts); - } - - Control_UnloadApplet(applet); - } + } + + /* Load applet cpl */ + TRACE("Load applet %ls\n", pwszPath); + Control_LoadApplet(hWnd, pwszPath, pPanel); + if (pPanel->first) + { + /* First pPanel applet is the new one */ + CPlApplet *pApplet = pPanel->first; + assert(pApplet && pApplet->next == NULL); + TRACE("pApplet->count %d\n", pApplet->count); + + /* Note: if there is only one applet, first argument is ignored */ + INT i = 0; + if (pApplet->count > 1 && pwszArg && pwszArg[0]) + { + /* If arg begins with '@', number specifies applet index */ + if (pwszArg[0] == L'@') + i = _wtoi(pwszArg + 1); + else + { + /* Otherwise it's applet name */ + for (i = 0; i < (INT)pApplet->count; ++i) + if (!wcscmp(pwszArg, pApplet->info[i].szName)) + break; + } + } + + if (i >= 0 && i < (INT)pApplet->count && pApplet->info[i].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"); + + Control_UnloadApplet(pApplet); + } + else + ERR("Failed to load applet %ls\n", pwszPath);
ReleaseMutex(hMutex); CloseHandle(hMutex); - HeapFree(GetProcessHeap(), 0, buffer); + free(pwszCmdCopy); }
/************************************************************************* @@ -496,22 +452,22 @@ */ 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); } }
Modified: trunk/reactos/dll/win32/shell32/folders/cpanel.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/c... ============================================================================== --- trunk/reactos/dll/win32/shell32/folders/cpanel.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/folders/cpanel.cpp [iso-8859-1] Sat Jan 14 17:14:54 2012 @@ -799,29 +799,25 @@ static HRESULT ExecuteAppletFromCLSID(LPOLESTR pOleStr) { - WCHAR szCmd[MAX_PATH]; - WCHAR szExpCmd[MAX_PATH]; + WCHAR wszBuf[128], wszCmd[MAX_PATH]; + DWORD cbCmd = sizeof(wszCmd); + + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"CLSID\%s\shell\open\command", pOleStr); + + if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszCmd, &cbCmd) != ERROR_SUCCESS) + { + ERR("RegGetValueW(%ls) failed with %u\n", wszBuf, GetLastError()); + return E_FAIL; + } + + if (!ExpandEnvironmentStringsW(wszCmd, wszBuf, _countof(wszBuf))) + return E_FAIL; + PROCESS_INFORMATION pi; STARTUPINFOW si; - WCHAR szBuffer[90] = { 'C', 'L', 'S', 'I', 'D', '\', 0 }; - DWORD dwType, dwSize; - - wcscpy(&szBuffer[6], pOleStr); - wcscat(szBuffer, L"\shell\open\command"); - - dwSize = sizeof(szCmd); - if (RegGetValueW(HKEY_CLASSES_ROOT, szBuffer, NULL, RRF_RT_REG_SZ, &dwType, (PVOID)szCmd, &dwSize) != ERROR_SUCCESS) - { - ERR("RegGetValueW(%ls) failed with %u\n", szBuffer, GetLastError()); - return E_FAIL; - } - - if (!ExpandEnvironmentStringsW(szCmd, szExpCmd, sizeof(szExpCmd) / sizeof(WCHAR))) - return E_FAIL; - ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); - if (!CreateProcessW(NULL, szExpCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + if (!CreateProcessW(NULL, wszBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return E_FAIL;
CloseHandle(pi.hProcess); @@ -829,63 +825,65 @@ return S_OK; }
+EXTERN_C void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow); + +HRESULT WINAPI CControlPanelFolder::ExecuteFromIdList(LPCITEMIDLIST pidl) +{ + PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(ILFindLastID(pidl)); + + if (!pCPanel) + { + /* Is it GUID to control panel applet? */ + IID *piid = _ILGetGUIDPointer(ILFindLastID(pidl)); + if (!piid) + return E_INVALIDARG; + + /* Start it */ + LPOLESTR pOleStr; + if (StringFromCLSID(*piid, &pOleStr) == S_OK) + { + HRESULT hr = ExecuteAppletFromCLSID(pOleStr); + CoTaskMemFree(pOleStr); + return hr; + } + + ERR("Cannot open cpanel applet\n"); + return E_INVALIDARG; + } + + /* Build control panel applet cmd + Note: we passes applet name to Control_RunDLL to distinguish between applets in one .cpl file */ + WCHAR wszCmd[2*MAX_PATH]; + StringCbPrintfW(wszCmd, sizeof(wszCmd), L"rundll32 shell32.dll,Control_RunDLL "%hs","%hs"", pCPanel->szName, pCPanel->szName + pCPanel->offsDispName); + + /* Start the applet */ + TRACE("Run cpl %ls\n", wszCmd); + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + if (!CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + return E_FAIL; + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return S_OK; +}
HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOW psei) { - static const WCHAR wCplopen[] = {'c', 'p', 'l', 'o', 'p', 'e', 'n', '\0'}; - SHELLEXECUTEINFOW sei_tmp; - PIDLCPanelStruct* pcpanel; - WCHAR path[MAX_PATH]; - WCHAR params[MAX_PATH]; - BOOL ret; - HRESULT hr; - int l; - TRACE("(%p)->execute(%p)\n", this, psei);
if (!psei) return E_INVALIDARG;
- pcpanel = _ILGetCPanelPointer(ILFindLastID((LPCITEMIDLIST)psei->lpIDList)); - - if (!pcpanel) - { - LPOLESTR pOleStr; - - IID * iid = _ILGetGUIDPointer(ILFindLastID((LPCITEMIDLIST)psei->lpIDList)); - if (!iid) - return E_INVALIDARG; - if (StringFromCLSID(*iid, &pOleStr) == S_OK) - { - hr = ExecuteAppletFromCLSID(pOleStr); - CoTaskMemFree(pOleStr); - return hr; - } - - return E_INVALIDARG; - } - path[0] = '"'; - /* Return value from MultiByteToWideChar includes terminating NUL, which - * compensates for the starting double quote we just put in */ - l = MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, path + 1, MAX_PATH); - - /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */ - path[l++] = '"'; - path[l] = '\0'; - - MultiByteToWideChar(CP_ACP, 0, pcpanel->szName + pcpanel->offsDispName, -1, params, MAX_PATH); - - memcpy(&sei_tmp, psei, sizeof(sei_tmp)); - sei_tmp.lpFile = path; - sei_tmp.lpParameters = params; - sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; - sei_tmp.lpVerb = wCplopen; - - ret = ShellExecuteExW(&sei_tmp); - if (ret) - return S_OK; - else - return S_FALSE; + if (!(psei->fMask & SEE_MASK_IDLIST)) + { + FIXME("no idlist given!\n"); + return E_FAIL; + } + + return ExecuteFromIdList((LPCITEMIDLIST)psei->lpIDList); }
/************************************************************************** @@ -894,37 +892,18 @@
HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOA psei) { - SHELLEXECUTEINFOA sei_tmp; - PIDLCPanelStruct* pcpanel; - char path[MAX_PATH]; - BOOL ret; - TRACE("(%p)->execute(%p)\n", this, psei);
if (!psei) return E_INVALIDARG;
- pcpanel = _ILGetCPanelPointer(ILFindLastID((LPCITEMIDLIST)psei->lpIDList)); - - if (!pcpanel) - return E_INVALIDARG; - - path[0] = '"'; - lstrcpyA(path + 1, pcpanel->szName); - - /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */ - lstrcatA(path, "" "); - lstrcatA(path, pcpanel->szName + pcpanel->offsDispName); - - memcpy(&sei_tmp, psei, sizeof(sei_tmp)); - sei_tmp.lpFile = path; - sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; - - ret = ShellExecuteExA(&sei_tmp); - if (ret) - return S_OK; - else - return S_FALSE; + if (!(psei->fMask & SEE_MASK_IDLIST)) + { + FIXME("no idlist given!\n"); + return E_FAIL; + } + + return ExecuteFromIdList((LPCITEMIDLIST)psei->lpIDList); }
/************************************************************************** @@ -995,9 +974,8 @@ sei.hwnd = lpcmi->hwnd; sei.nShow = SW_SHOWNORMAL; sei.lpVerb = L"open"; - - if (ShellExecuteExW(&sei) == FALSE) - return E_FAIL; +ERR("here\n"); + return Execute(&sei); } else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME {
Modified: trunk/reactos/dll/win32/shell32/folders/cpanel.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/c... ============================================================================== --- trunk/reactos/dll/win32/shell32/folders/cpanel.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/folders/cpanel.h [iso-8859-1] Sat Jan 14 17:14:54 2012 @@ -37,6 +37,9 @@ int dwAttributes; /* attributes returned by GetAttributesOf FIXME: use it */ LPCITEMIDLIST *apidl; UINT cidl; + + HRESULT WINAPI ExecuteFromIdList(LPCITEMIDLIST pidl); + public: CControlPanelFolder(); ~CControlPanelFolder();