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);
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:
}
}
-static void Control_DoWindow(CPanel* panel, 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);
}
/*************************************************************************
*/
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);
}
}