mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
In MS Windows all control panel applets are started in single instance. This prevents conflicts of concurrent accesses to the configuration data. Before starting applets, look up the dialog window of the existing instance by checking several atoms, such as the applet path, CPLName, and CPLFlags. If the dialog is found, it's brought to the foreground, and a new applet instance not started. CORE-7921 CORE-17025 Signed-off-by: Raymond Czerny <chip@raymisoft.de> Reviewed-by: Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> Reviewed-by: Joachim Henze <joachim.henze@reactos.org> Reviewed-by: Mark Jansen <mark.jansen@reactos.org>
This commit is contained in:
parent
184b8a30cb
commit
1b5abe8837
1 changed files with 115 additions and 0 deletions
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright 2001 Eric Pouech
|
||||
* Copyright 2008 Owen Rudge
|
||||
* Copyright 2022 Raymond Czerny
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -736,6 +737,75 @@ static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef __REACTOS__
|
||||
|
||||
/** Structure for in and out data when
|
||||
* search for the cpl dialog of first instance
|
||||
*/
|
||||
typedef struct tagAppDlgFindData
|
||||
{
|
||||
PCWSTR szAppFile; /**< Full path to applet library as search parameter */
|
||||
UINT_PTR sAppletNo; /**< Number of applet in a system control library as search parameter */
|
||||
ATOM aCPLName; /**< to read window property 'CPLName' */
|
||||
ATOM aCPLFlags; /**< to read window property 'CPLFlags'*/
|
||||
HWND hRunDLL; /**< to skip self instance */
|
||||
HWND hDlgResult; /**< Returned dialog handle or NULL if not found */
|
||||
} AppDlgFindData;
|
||||
|
||||
/**
|
||||
* Callback function to search applet dialog
|
||||
* @param hwnd A handle to a top-level window.
|
||||
* @param lParam Pointer of AppDlgFindData
|
||||
* @return TRUE: continue enumeration, FALSE: stop enumeration
|
||||
*/
|
||||
static BOOL CALLBACK
|
||||
Control_EnumWinProc(
|
||||
_In_ HWND hwnd,
|
||||
_In_ LPARAM lParam)
|
||||
{
|
||||
AppDlgFindData* pData = (AppDlgFindData*)lParam;
|
||||
WCHAR szClassName[256] = L"";
|
||||
|
||||
if (pData->hRunDLL == hwnd)
|
||||
{
|
||||
// Skip self instance
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GetClassNameW(hwnd, szClassName, _countof(szClassName)))
|
||||
{
|
||||
// Note: A comparison on identical is not possible, the class names are different.
|
||||
// ReactOS: 'rundll32_window'
|
||||
// WinXP: 'RunDLL'
|
||||
// other OS: not checked
|
||||
if (StrStrIW(szClassName, L"rundll32") != NULL)
|
||||
{
|
||||
UINT_PTR sAppletNo;
|
||||
|
||||
sAppletNo = (UINT_PTR)GetPropW(hwnd, (LPTSTR)MAKEINTATOM(pData->aCPLFlags));
|
||||
if (sAppletNo == pData->sAppletNo)
|
||||
{
|
||||
HANDLE hRes;
|
||||
WCHAR szAppFile[MAX_PATH];
|
||||
|
||||
hRes = GetPropW(hwnd, (LPTSTR)MAKEINTATOM(pData->aCPLName));
|
||||
GlobalGetAtomNameW((ATOM)HandleToUlong(hRes), szAppFile, _countof(szAppFile));
|
||||
if (wcscmp(szAppFile, pData->szAppFile) == 0)
|
||||
{
|
||||
HWND hDialog = GetLastActivePopup(hwnd);
|
||||
if (IsWindow(hDialog))
|
||||
{
|
||||
pData->hDlgResult = hDialog;
|
||||
return FALSE; // stop enumeration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE; // continue enumeration
|
||||
}
|
||||
#endif /* __REACTOS__ */
|
||||
|
||||
static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd)
|
||||
/* forms to parse:
|
||||
* foo.cpl,@sp,str
|
||||
|
@ -828,6 +898,10 @@ static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd)
|
|||
#ifdef __REACTOS__
|
||||
ULONG_PTR cookie;
|
||||
BOOL bActivated;
|
||||
ATOM aCPLName;
|
||||
ATOM aCPLFlags;
|
||||
ATOM aCPLPath;
|
||||
AppDlgFindData findData;
|
||||
#endif
|
||||
/* we've been given a textual parameter (or none at all) */
|
||||
if (sp == -1) {
|
||||
|
@ -846,10 +920,51 @@ static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd)
|
|||
|
||||
#ifdef __REACTOS__
|
||||
bActivated = (applet->hActCtx != INVALID_HANDLE_VALUE ? ActivateActCtx(applet->hActCtx, &cookie) : FALSE);
|
||||
|
||||
aCPLPath = GlobalFindAtomW(applet->cmd);
|
||||
if (!aCPLPath)
|
||||
{
|
||||
aCPLPath = GlobalAddAtomW(applet->cmd);
|
||||
}
|
||||
|
||||
aCPLName = GlobalFindAtomW(L"CPLName");
|
||||
if (!aCPLName)
|
||||
{
|
||||
aCPLName = GlobalAddAtomW(L"CPLName");
|
||||
}
|
||||
|
||||
aCPLFlags = GlobalFindAtomW(L"CPLFlags");
|
||||
if (!aCPLFlags)
|
||||
{
|
||||
aCPLFlags = GlobalAddAtomW(L"CPLFlags");
|
||||
}
|
||||
|
||||
findData.szAppFile = applet->cmd;
|
||||
findData.sAppletNo = (UINT_PTR)(sp + 1);
|
||||
findData.aCPLName = aCPLName;
|
||||
findData.aCPLFlags = aCPLFlags;
|
||||
findData.hRunDLL = applet->hWnd;
|
||||
findData.hDlgResult = NULL;
|
||||
// Find the dialog of this applet in the first instance.
|
||||
// Note: The simpler functions "FindWindow" or "FindWindowEx" does not find this type of dialogs.
|
||||
EnumWindows(Control_EnumWinProc, (LPARAM)&findData);
|
||||
if (findData.hDlgResult)
|
||||
{
|
||||
BringWindowToTop(findData.hDlgResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPropW(applet->hWnd, (LPTSTR)MAKEINTATOM(aCPLName), (HANDLE)MAKEINTATOM(aCPLPath));
|
||||
SetPropW(applet->hWnd, (LPTSTR)MAKEINTATOM(aCPLFlags), UlongToHandle(sp + 1));
|
||||
#endif
|
||||
|
||||
if (!applet->proc(applet->hWnd, CPL_STARTWPARMSW, sp, (LPARAM)extraPmts))
|
||||
applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].data);
|
||||
#ifdef __REACTOS__
|
||||
RemovePropW(applet->hWnd, applet->cmd);
|
||||
GlobalDeleteAtom(aCPLPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
Control_UnloadApplet(applet);
|
||||
|
||||
|
|
Loading…
Reference in a new issue