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.…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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();