[ros-diffs] [rharabien] 54960: [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 st...

rharabien at svn.reactos.org rharabien at svn.reactos.org
Sat Jan 14 17:14:54 UTC 2012


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.cpp?rev=54960&r1=54959&r2=54960&view=diff
==============================================================================
--- 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, at sp,str
-    *    foo.cpl, at 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/cpanel.cpp?rev=54960&r1=54959&r2=54960&view=diff
==============================================================================
--- 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/cpanel.h?rev=54960&r1=54959&r2=54960&view=diff
==============================================================================
--- 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();




More information about the Ros-diffs mailing list