[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / control.cpp
index 74b6261..09dcbd6 100644 (file)
@@ -247,7 +247,7 @@ static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up)
     return 0;
 }
 
-static LRESULT WINAPI    Control_WndProc(HWND hWnd, UINT wMsg,
+static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg,
                     WPARAM lParam1, LPARAM lParam2)
 {
     CPanel*    panel = (CPanel*)GetWindowLongPtrW(hWnd, 0);
@@ -259,16 +259,15 @@ static LRESULT WINAPI    Control_WndProc(HWND hWnd, UINT wMsg,
             case WM_CREATE:
                 Control_WndProc_Create(hWnd, (CREATESTRUCTW*)lParam2);
                 return 0;
-            
             case WM_DESTROY:
             {
-                CPlApplet*    applet = panel->first;
+                CPlApplet *applet = panel->first;
                 while (applet)
                     applet = Control_UnloadApplet(applet);
                 
                 PostQuitMessage(0);
-            }; break;
-            
+                break;
+            }
             case WM_PAINT:
                 return Control_WndProc_Paint(panel, lParam1);
             case WM_LBUTTONUP:
@@ -324,172 +323,127 @@ static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst)
     }
 }
 
-static void Control_DoWindow(CPanelpanel, HWND hWnd, HINSTANCE hInst)
+static void Control_DoWindow(CPanel *panel, HWND hWnd, HINSTANCE hInst)
 {
-    HANDLE        h;
-    WIN32_FIND_DATAW    fd;
-    WCHAR        buffer[MAX_PATH];
-    static const WCHAR wszAllCpl[] = {'*','.','c','p','l',0};
-    WCHAR *p;
-
-    GetSystemDirectoryW( buffer, MAX_PATH );
-    p = buffer + wcslen(buffer);
-    *p++ = '\\';
-    wcscpy(p, wszAllCpl);
-
-    if ((h = FindFirstFileW(buffer, &fd)) != INVALID_HANDLE_VALUE)
+    HANDLE hFind;
+    WIN32_FIND_DATAW wfd;
+    WCHAR wszPath[MAX_PATH];
+    WCHAR *Ptr = wszPath;
+
+    Ptr += GetSystemDirectoryW(wszPath, MAX_PATH);
+    *Ptr++ = '\\';
+    wcscpy(Ptr, L"*.cpl");
+
+    hFind = FindFirstFileW(wszPath, &wfd);
+    if (hFind != INVALID_HANDLE_VALUE)
     {
         do
         {
-            wcscpy(p, fd.cFileName);
-            Control_LoadApplet(hWnd, buffer, panel);
-        } while (FindNextFileW(h, &fd));
-        FindClose(h);
+            wcscpy(Ptr, wfd.cFileName);
+            Control_LoadApplet(hWnd, wszPath, panel);
+        } while (FindNextFileW(hFind, &wfd));
+        FindClose(hFind);
     }
 
     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"
-    */
+static void Control_DoLaunch(CPanel *pPanel, HWND hWnd, LPCWSTR pwszCmd)
 {
-    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++;
-    else
-        ptr = wszCmd;
-
-    Length = (ptr2 - ptr);
-    if (Length >= MAX_PATH)
+    /* Make a pwszCmd copy so we can modify it */
+    LPWSTR pwszCmdCopy = _wcsdup(pwszCmd);
+    if (!pwszCmdCopy)
         return;
 
-    memcpy(szName, (LPVOID)ptr, Length * sizeof(WCHAR));
-    szName[Length] = L'\0';
-    hMutex = CreateMutexW(NULL, TRUE, szName);
+    LPWSTR pwszPath = pwszCmdCopy, pwszArg = NULL, pwszArg2 = NULL;
 
-     if ((!hMutex) || (GetLastError() == ERROR_ALREADY_EXISTS))
-        return;
-    buffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(wszCmd) + 1) * sizeof(*wszCmd));
-    if (!buffer)
+    /* Path can be quoted */
+    if (pwszPath[0] == L'"')
     {
-        CloseHandle(hMutex);
-        return;
+        ++pwszPath;
+        pwszArg = wcschr(pwszPath, L'"');
+        if (pwszArg)
+            *(pwszArg++) = '\0';
     }
+    else
+        pwszArg = pwszCmdCopy;
 
-    TRACE("[shell32, Control_DoLaunch] wszCmd = %ws\n", wszCmd);
-    
-    end = wcscpy(buffer, wszCmd);
-    for (;;)
+    /* First argument starts after space or ','. Note: we ignore characters between '"' and ',' or ' '. */
+    if (pwszArg)
+        pwszArg = wcspbrk(pwszArg, L" ,");
+    if (pwszArg)
     {
-        ch = *end;
-        if (ch == '"')
-            quoted = !quoted;
-
-        if (!quoted && (ch == ',' || ch == '\0'))
+        /* NULL terminate path and find first character of arg */
+        *(pwszArg++) = L'\0';
+        if (pwszArg[0] == L'"')
         {
-            *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++;
+            ++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',');
     }
-    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);
+    TRACE("Launch %ls, arg %ls, arg2 %ls\n", pwszPath, pwszArg, pwszArg2);
 
-    Control_LoadApplet(hWnd, buffer, panel);
-
-    if (panel->first)
+    /* Create a mutex to disallow running multiple instances */
+    HANDLE hMutex = CreateMutexW(NULL, TRUE, PathFindFileNameW(pwszPath));
+    if (!hMutex || GetLastError() == ERROR_ALREADY_EXISTS)
     {
-        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;
-        }
+        TRACE("Next instance disallowed\n");
+        if (hMutex)
+            CloseHandle(hMutex);
+        return;
+    }
 
-        if ((extraPmts) && extraPmts[0] && (!spSet))
+    /* 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])
         {
-            while ((lstrcmpiW(extraPmts, applet->info[sp].szName)) && (sp < applet->count))
-                sp++;
-
-            if (sp >= applet->count)
+            /* If arg begins with '@', number specifies applet index */
+            if (pwszArg[0] == L'@')
+                i = _wtoi(pwszArg + 1);
+            else
             {
-                ReleaseMutex(hMutex);
-                CloseHandle(hMutex);
-                Control_UnloadApplet(applet);
-                HeapFree(GetProcessHeap(), 0, buffer);
-                return;
+                /* Otherwise it's applet name */
+                for (i = 0; i < (INT)pApplet->count; ++i)
+                    if (!wcscmp(pwszArg, pApplet->info[i].szName))
+                        break;
             }
         }
 
-        if (applet->info[sp].dwSize)
+        if (i >= 0 && i < (INT)pApplet->count && pApplet->info[i].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);
+            /* 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_STARTWPARMSW, 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);
 }
 
 /*************************************************************************
@@ -498,22 +452,22 @@ static    void    Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd)
  */
 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);
     }
 }