diff --git a/reactos/dll/win32/shell32/cpanel.h b/reactos/dll/win32/shell32/cpanel.h deleted file mode 100644 index 074a900aa26..00000000000 --- a/reactos/dll/win32/shell32/cpanel.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Control Panel management - * - * Copyright 2001 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef __WINE_SHELL_CPANEL_H -#define __WINE_SHELL_CPANEL_H - -#include - -typedef struct CPlApplet -{ - struct CPlApplet *next; /* linked list */ - HWND hWnd; - LPWSTR cmd; /* path to applet */ - unsigned count; /* number of subprograms */ - HMODULE hModule; /* module of loaded applet */ - APPLET_PROC proc; /* entry point address */ - NEWCPLINFOW info[1]; /* array of count information. - * dwSize field is 0 if entry is invalid */ -} CPlApplet; - -typedef struct CPanel -{ - CPlApplet *first; /* linked list */ - HWND hWnd; - unsigned status; - CPlApplet *clkApplet; - unsigned clkSP; -} CPanel; - - -EXTERN_C CPlApplet *Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel); -EXTERN_C CPlApplet *Control_UnloadApplet(CPlApplet* applet); - -#endif /* __WINE_SHELL_CPANEL_H */ diff --git a/reactos/dll/win32/shell32/folders/CControlPanelFolder.cpp b/reactos/dll/win32/shell32/folders/CControlPanelFolder.cpp index 4a7fc7f9963..5793d765077 100644 --- a/reactos/dll/win32/shell32/folders/CControlPanelFolder.cpp +++ b/reactos/dll/win32/shell32/folders/CControlPanelFolder.cpp @@ -19,12 +19,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -/* -TODO: -1. The selected items list should not be stored in CControlPanelFolder, it should - be a result returned by an internal method. -*/ - #include WINE_DEFAULT_DEBUG_CHANNEL(shell); @@ -40,9 +34,9 @@ class CControlPanelEnum : CControlPanelEnum(); ~CControlPanelEnum(); HRESULT WINAPI Initialize(DWORD dwFlags); - BOOL RegisterCPanelApp(LPCSTR path); - int RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath); - int RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath); + BOOL RegisterCPanelApp(LPCWSTR path); + int RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath); + int RegisterCPanelFolders(HKEY hkey_root, LPCWSTR szRepPath); BOOL CreateCPanelEnumList(DWORD dwFlags); BEGIN_COM_MAP(CControlPanelEnum) @@ -76,7 +70,7 @@ HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags) return S_OK; } -static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName, LPCSTR pszComment, int iIconIdx) +static LPITEMIDLIST _ILCreateCPanelApplet(LPCWSTR pszName, LPCWSTR pszDisplayName, LPCWSTR pszComment, int iIconIdx) { PIDLCPanelStruct *pCP; LPITEMIDLIST pidl; @@ -84,13 +78,13 @@ static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName, int cchName, cchDisplayName, cchComment, cbData; /* Calculate lengths of given strings */ - cchName = strlen(pszName); - cchDisplayName = strlen(pszDisplayName); - cchComment = strlen(pszComment); + cchName = wcslen(pszName); + cchDisplayName = wcslen(pszDisplayName); + cchComment = wcslen(pszComment); /* Allocate PIDL */ cbData = sizeof(pidl->mkid.cb) + sizeof(pData->type) + sizeof(pData->u.cpanel) - sizeof(pData->u.cpanel.szName) - + cchName + cchDisplayName + cchComment + 3; + + (cchName + cchDisplayName + cchComment + 3) * sizeof(WCHAR); pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD)); if (!pidl) return NULL; @@ -103,11 +97,11 @@ static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName, pCP = &pData->u.cpanel; pCP->dummy = 0; pCP->iconIdx = iIconIdx; - strcpy(pCP->szName, pszName); + wcscpy(pCP->szName, pszName); pCP->offsDispName = cchName + 1; - strcpy(pCP->szName + pCP->offsDispName, pszDisplayName); + wcscpy(pCP->szName + pCP->offsDispName, pszDisplayName); pCP->offsComment = pCP->offsDispName + cchDisplayName + 1; - strcpy(pCP->szName + pCP->offsComment, pszComment); + wcscpy(pCP->szName + pCP->offsComment, pszComment); /* Add PIDL NULL terminator */ *(WORD*)(pCP->szName + pCP->offsComment + cchComment + 1) = 0; @@ -131,40 +125,24 @@ static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl) return NULL; } -BOOL CControlPanelEnum::RegisterCPanelApp(LPCSTR path) +BOOL CControlPanelEnum::RegisterCPanelApp(LPCWSTR wpath) { - LPITEMIDLIST pidl; - CPlApplet* applet; - CPanel panel; - CPLINFO info; - unsigned i; + CPlApplet* applet = Control_LoadApplet(0, wpath, NULL); int iconIdx; - char displayName[MAX_PATH]; - char comment[MAX_PATH]; - - WCHAR wpath[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH); - - panel.first = NULL; - applet = Control_LoadApplet(0, wpath, &panel); - if (applet) { - for (i = 0; i < applet->count; ++i) + for (UINT i = 0; i < applet->count; ++i) { - applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info); - - LoadStringA(applet->hModule, info.idName, displayName, MAX_PATH); - LoadStringA(applet->hModule, info.idInfo, comment, MAX_PATH); - - if (info.idIcon > 0) - iconIdx = -info.idIcon; /* negative icon index instead of icon number */ + if (applet->info[i].idIcon > 0) + iconIdx = -applet->info[i].idIcon; /* negative icon index instead of icon number */ else iconIdx = 0; - pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx); + LPITEMIDLIST pidl = _ILCreateCPanelApplet(wpath, + applet->info[i].name, + applet->info[i].info, + iconIdx); if (pidl) AddToEnumList(pidl); @@ -174,15 +152,15 @@ BOOL CControlPanelEnum::RegisterCPanelApp(LPCSTR path) return TRUE; } -int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath) +int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath) { - char name[MAX_PATH]; - char value[MAX_PATH]; + WCHAR name[MAX_PATH]; + WCHAR value[MAX_PATH]; HKEY hkey; int cnt = 0; - if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) + if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) { int idx = 0; @@ -190,14 +168,14 @@ int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPa { DWORD nameLen = MAX_PATH; DWORD valueLen = MAX_PATH; - char buffer[MAX_PATH]; + WCHAR buffer[MAX_PATH]; - if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS) + if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS) break; - if (ExpandEnvironmentStringsA(value, buffer, MAX_PATH)) + if (ExpandEnvironmentStringsW(value, buffer, MAX_PATH)) { - strcpy(value, buffer); + wcscpy(value, buffer); } if (RegisterCPanelApp(value)) @@ -209,24 +187,23 @@ int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPa return cnt; } -int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath) +int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCWSTR szRepPath) { - char name[MAX_PATH]; + WCHAR name[MAX_PATH]; HKEY hkey; int cnt = 0; - if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) + if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) { - int idx = 0; - for (; ; idx++) + for (int idx = 0; ; idx++) { - if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS) + if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS) break; if (*name == '{') { - LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name); + LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name); if (pidl && AddToEnumList(pidl)) ++cnt; @@ -244,27 +221,26 @@ int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath) */ BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags) { - CHAR szPath[MAX_PATH]; - WIN32_FIND_DATAA wfd; + WCHAR szPath[MAX_PATH]; + WIN32_FIND_DATAW wfd; HANDLE hFile; TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); /* enumerate control panel folders */ if (dwFlags & SHCONTF_FOLDERS) - RegisterCPanelFolders(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace"); + RegisterCPanelFolders(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace"); /* enumerate the control panel applets */ if (dwFlags & SHCONTF_NONFOLDERS) { - LPSTR p; + LPWSTR p; - GetSystemDirectoryA(szPath, MAX_PATH); - p = PathAddBackslashA(szPath); - strcpy(p, "*.cpl"); + GetSystemDirectoryW(szPath, MAX_PATH); + p = PathAddBackslashW(szPath); + wcscpy(p, L"*.cpl"); - TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n", this, debugstr_a(szPath)); - hFile = FindFirstFileA(szPath, &wfd); + hFile = FindFirstFileW(szPath, &wfd); if (hFile != INVALID_HANDLE_VALUE) { @@ -274,16 +250,16 @@ BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags) continue; if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - strcpy(p, wfd.cFileName); - if (strcmp(wfd.cFileName, "ncpa.cpl")) + wcscpy(p, wfd.cFileName); + if (wcscmp(wfd.cFileName, L"ncpa.cpl")) RegisterCPanelApp(szPath); } - } while(FindNextFileA(hFile, &wfd)); + } while(FindNextFileW(hFile, &wfd)); FindClose(hFile); } - RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); - RegisterRegistryCPanelApps(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); + RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); + RegisterRegistryCPanelApps(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); } return TRUE; } @@ -576,10 +552,7 @@ HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD if (pCPanel) { - /* copy display name from pidl - it was retrived from applet before; - SHGDN_FORPARSING does not need special handling */ - strRet->uType = STRRET_CSTR; - lstrcpyA(strRet->cStr, pCPanel->szName + pCPanel->offsDispName); + return SHSetStrRet(strRet, pCPanel->szName + pCPanel->offsDispName); } else if (_ILIsSpecialFolder(pidl)) { @@ -657,12 +630,8 @@ HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iCol if (!pidl) { psd->fmt = ControlPanelSFHeader[iColumn].fmt; psd->cxChar = ControlPanelSFHeader[iColumn].cxChar; - psd->str.uType = STRRET_CSTR; - LoadStringA(shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid, psd->str.cStr, MAX_PATH); - return S_OK; + return SHSetStrRet(&psd->str, shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid); } else { - psd->str.cStr[0] = 0x00; - psd->str.uType = STRRET_CSTR; switch(iColumn) { case 0: /* name */ hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); @@ -671,13 +640,15 @@ HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iCol { PIDLCPanelStruct* pCPanel = _ILGetCPanelPointer(pidl); if (pCPanel) - lstrcpyA(psd->str.cStr, pCPanel->szName + pCPanel->offsComment); + return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsComment); if (_ILIsSpecialFolder(pidl)) { HKEY hKey; GUID *pGuid = _ILGetGUIDPointer(pidl); if (HCR_RegOpenClassIDKey(*pGuid, &hKey)) { + psd->str.cStr[0] = 0x00; + psd->str.uType = STRRET_CSTR; RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL); RegCloseKey(hKey); } @@ -745,7 +716,7 @@ HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl, LPWSTR szIconFile, UINT cchM if (!pcpanel) return E_INVALIDARG; - MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax); + wcsncpy(szIconFile, pcpanel->szName, cchMax); *piIndex = (int)pcpanel->iconIdx != -1 ? pcpanel->iconIdx : 0; return S_OK; @@ -780,47 +751,21 @@ HRESULT WINAPI CCPLItemMenu::QueryContextMenu( UINT idCmdLast, UINT uFlags) { - WCHAR szBuffer[30] = {0}; - ULONG Count = 1; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, MAKEINTRESOURCEW(IDS_OPEN), MFS_DEFAULT); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + 1, MFT_SEPARATOR, NULL, MFS_ENABLED); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED); - TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", - this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); - - if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) - { - szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; - _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, szBuffer, MFS_DEFAULT); //FIXME identifier - Count++; - } - - if (LoadStringW(shell32_hInstance, IDS_CREATELINK, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) - { - if (Count) - { - _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_SEPARATOR, NULL, MFS_ENABLED); - } - szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; - - _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, szBuffer, MFS_ENABLED); //FIXME identifier - Count++; - } - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count); + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2); } EXTERN_C -void WINAPI Control_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow); +void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow); /************************************************************************** * ICPanel_IContextMenu_InvokeCommand() */ HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { - WCHAR szPath[MAX_PATH]; - char szTarget[MAX_PATH]; - WCHAR* pszPath; - INT Length, cLength; - CComPtr ppf; - CComPtr isl; HRESULT hResult; PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(m_apidl[0]); @@ -831,60 +776,38 @@ HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME { - CHAR szParams[MAX_PATH]; + WCHAR wszParams[MAX_PATH]; - strcpy(szParams, pCPanel->szName); - strcat(szParams, ","); - strcat(szParams, pCPanel->szName + pCPanel->offsDispName); + wcscpy(wszParams, pCPanel->szName); + wcscat(wszParams, L","); + wcscat(wszParams, pCPanel->szName + pCPanel->offsDispName); - Control_RunDLLA (NULL, NULL, szParams, SW_NORMAL); + Control_RunDLLW (NULL, NULL, wszParams, SW_NORMAL); } else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME { - if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE)) - return E_FAIL; + CComPtr pDataObj; + LPITEMIDLIST pidl = _ILCreateControlPanel(); - pszPath = PathAddBackslashW(szPath); - if (!pszPath) - return E_FAIL; + hResult = SHCreateDataObject(pidl, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj)); + if (FAILED(hResult)) + return hResult; - CHAR* pszDisplayName = pCPanel->szName + pCPanel->offsDispName; + SHFree(pidl); - Length = MAX_PATH - (pszPath - szPath); - cLength = strlen(pszDisplayName); - if (Length < cLength + 5) - { - FIXME("\n"); - return E_FAIL; - } + //FIXME: Use SHCreateLinks + CComPtr psf; + CComPtr pDT; - if (MultiByteToWideChar(CP_ACP, 0, pszDisplayName, cLength + 1, pszPath, Length)) - { - pszPath += cLength; - Length -= cLength; - } + hResult = SHGetDesktopFolder(&psf); + if (FAILED(hResult)) + return hResult; - if (Length > 10) - { - wcscpy(pszPath, L" - "); - cLength = LoadStringW(shell32_hInstance, IDS_LNK_FILE, &pszPath[3], Length - 4) + 3; - if (cLength + 5 > Length) - cLength = Length - 5; - Length -= cLength; - pszPath += cLength; - } - wcscpy(pszPath, L".lnk"); + hResult = psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT)); + if (FAILED(hResult)) + return hResult; - strncpy(szTarget, pCPanel->szName, MAX_PATH); - - hResult = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkA, &isl)); - if (SUCCEEDED(hResult)) - { - isl->SetPath(szTarget); - if (SUCCEEDED(isl->QueryInterface(IID_PPV_ARG(IPersistFile,&ppf)))) - ppf->Save(szPath, TRUE); - } - return NOERROR; + SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL); } return S_OK; } diff --git a/reactos/dll/win32/shell32/precomp.h b/reactos/dll/win32/shell32/precomp.h index 714158e23ca..86ff1c988f3 100644 --- a/reactos/dll/win32/shell32/precomp.h +++ b/reactos/dll/win32/shell32/precomp.h @@ -42,7 +42,7 @@ #include "debughlp.h" #include "wine/shell32_main.h" #include "shresdef.h" -#include "cpanel.h" +#include "wine/cpanel.h" #include "CEnumIDListBase.h" #include "shfldr.h" #include "shellfolder.h" diff --git a/reactos/dll/win32/shell32/wine/control.c b/reactos/dll/win32/shell32/wine/control.c index ff862c67ae0..97464f9bf0e 100644 --- a/reactos/dll/win32/shell32/wine/control.c +++ b/reactos/dll/win32/shell32/wine/control.c @@ -27,42 +27,39 @@ #include #define NO_SHLWAPI_REG #include +#include #include #include "cpanel.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(shlctrl); -CPlApplet* Control_UnloadApplet(CPlApplet* applet) +void Control_UnloadApplet(CPlApplet* applet) { - unsigned i; - CPlApplet* next; + unsigned i; for (i = 0; i < applet->count; i++) - { - if (!applet->info[i].dwSize) - continue; - applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].lData); - } - if (applet->proc) - applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L); - + applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].data); + + if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L); FreeLibrary(applet->hModule); - next = applet->next; +#ifndef __REACTOS__ + list_remove( &applet->entry ); +#endif HeapFree(GetProcessHeap(), 0, applet->cmd); HeapFree(GetProcessHeap(), 0, applet); - return next; } -CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) +CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) { - CPlApplet* applet; + CPlApplet* applet; DWORD len; - unsigned i; - CPLINFO info; + unsigned i; + CPLINFO info; NEWCPLINFOW newinfo; - if (!(applet = (CPlApplet *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet)))) + if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet)))) return applet; len = ExpandEnvironmentStringsW(cmd, NULL, 0); @@ -83,422 +80,775 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) applet->hWnd = hWnd; - if (!(applet->hModule = LoadLibraryW(applet->cmd))) - { + if (!(applet->hModule = LoadLibraryW(applet->cmd))) { WARN("Cannot load control panel applet %s\n", debugstr_w(applet->cmd)); - goto theError; + goto theError; } - if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) - { + if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) { WARN("Not a valid control panel applet %s\n", debugstr_w(applet->cmd)); - goto theError; + goto theError; } - if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) - { + if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) { WARN("Init of applet has failed\n"); - goto theError; + goto theError; } - if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) - { + if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) { WARN("No subprogram in applet\n"); - goto theError; + applet->proc(applet->hWnd, CPL_EXIT, 0, 0); + goto theError; } - applet = (CPlApplet *)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet, - sizeof(*applet) + (applet->count - 1) * sizeof(NEWCPLINFOW)); + applet = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet, + FIELD_OFFSET( CPlApplet, info[applet->count] )); - for (i = 0; i < applet->count; i++) - { - ZeroMemory(&newinfo, sizeof(newinfo)); - newinfo.dwSize = sizeof(NEWCPLINFOW); - applet->info[i].dwSize = sizeof(NEWCPLINFOW); + for (i = 0; i < applet->count; i++) { + ZeroMemory(&newinfo, sizeof(newinfo)); + newinfo.dwSize = sizeof(NEWCPLINFOA); + applet->info[i].helpfile[0] = 0; /* proc is supposed to return a null value upon success for - * CPL_INQUIRE and CPL_NEWINQUIRE - * However, real drivers don't seem to behave like this - * So, use introspection rather than return value - */ - applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&newinfo); - if (newinfo.hIcon == 0) - { - applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info); - if (info.idIcon == 0 || info.idName == 0) - { - WARN("Couldn't get info from sp %u\n", i); - applet->info[i].dwSize = 0; - } - else - { - /* convert the old data into the new structure */ - applet->info[i].dwFlags = 0; - applet->info[i].dwHelpContext = 0; - applet->info[i].lData = info.lData; - applet->info[i].hIcon = LoadIconW(applet->hModule, - MAKEINTRESOURCEW(info.idIcon)); - LoadStringW(applet->hModule, info.idName, - applet->info[i].szName, sizeof(applet->info[i].szName) / sizeof(WCHAR)); - LoadStringW(applet->hModule, info.idInfo, - applet->info[i].szInfo, sizeof(applet->info[i].szInfo) / sizeof(WCHAR)); - applet->info[i].szHelpFile[0] = '\0'; - } - } - else - { - CopyMemory(&applet->info[i], &newinfo, newinfo.dwSize); - if (newinfo.dwSize != sizeof(NEWCPLINFOW)) - { - applet->info[i].dwSize = sizeof(NEWCPLINFOW); - lstrcpyW(applet->info[i].szName, newinfo.szName); - lstrcpyW(applet->info[i].szInfo, newinfo.szInfo); - lstrcpyW(applet->info[i].szHelpFile, newinfo.szHelpFile); - } - } + * CPL_INQUIRE and CPL_NEWINQUIRE + * However, real drivers don't seem to behave like this + * So, use introspection rather than return value + */ + applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info); + applet->info[i].data = info.lData; +#if __REACTOS__ + applet->info[i].idIcon = info.idIcon; +#endif + + if (info.idIcon != CPL_DYNAMIC_RES) + applet->info[i].icon = LoadIconW(applet->hModule, MAKEINTRESOURCEW(info.idIcon)); + if (info.idName != CPL_DYNAMIC_RES) + LoadStringW(applet->hModule, info.idName, + applet->info[i].name, sizeof(applet->info[i].name) / sizeof(WCHAR)); + if (info.idInfo != CPL_DYNAMIC_RES) + LoadStringW(applet->hModule, info.idInfo, + applet->info[i].info, sizeof(applet->info[i].info) / sizeof(WCHAR)); + + /* some broken control panels seem to return incorrect values in CPL_INQUIRE, + but proper data in CPL_NEWINQUIRE. if we get an empty string or a null + icon, see what we can get from CPL_NEWINQUIRE */ + + if (!applet->info[i].name[0]) info.idName = CPL_DYNAMIC_RES; + + /* zero-length szInfo may not be a buggy applet, but it doesn't hurt for us + to check anyway */ + + if (!applet->info[i].info[0]) info.idInfo = CPL_DYNAMIC_RES; + + if (applet->info[i].icon == NULL) + info.idIcon = CPL_DYNAMIC_RES; + + if ((info.idIcon == CPL_DYNAMIC_RES) || (info.idName == CPL_DYNAMIC_RES) || + (info.idInfo == CPL_DYNAMIC_RES)) { + applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&newinfo); + + applet->info[i].data = newinfo.lData; + if (info.idIcon == CPL_DYNAMIC_RES) { + if (!newinfo.hIcon) WARN("couldn't get icon for applet %u\n", i); + applet->info[i].icon = newinfo.hIcon; + } + if (newinfo.dwSize == sizeof(NEWCPLINFOW)) { + if (info.idName == CPL_DYNAMIC_RES) + memcpy(applet->info[i].name, newinfo.szName, sizeof(newinfo.szName)); + if (info.idInfo == CPL_DYNAMIC_RES) + memcpy(applet->info[i].info, newinfo.szInfo, sizeof(newinfo.szInfo)); + memcpy(applet->info[i].helpfile, newinfo.szHelpFile, sizeof(newinfo.szHelpFile)); + } else { + if (info.idName == CPL_DYNAMIC_RES) + MultiByteToWideChar(CP_ACP, 0, ((LPNEWCPLINFOA)&newinfo)->szName, + sizeof(((LPNEWCPLINFOA)&newinfo)->szName) / sizeof(CHAR), + applet->info[i].name, sizeof(applet->info[i].name) / sizeof(WCHAR)); + if (info.idInfo == CPL_DYNAMIC_RES) + MultiByteToWideChar(CP_ACP, 0, ((LPNEWCPLINFOA)&newinfo)->szInfo, + sizeof(((LPNEWCPLINFOA)&newinfo)->szInfo) / sizeof(CHAR), + applet->info[i].info, sizeof(applet->info[i].info) / sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, ((LPNEWCPLINFOA)&newinfo)->szHelpFile, + sizeof(((LPNEWCPLINFOA)&newinfo)->szHelpFile) / sizeof(CHAR), + applet->info[i].helpfile, + sizeof(applet->info[i].helpfile) / sizeof(WCHAR)); + } + } } - applet->next = panel->first; - panel->first = applet; +#ifndef __REACTOS__ + list_add_head( &panel->applets, &applet->entry ); +#endif return applet; theError: - Control_UnloadApplet(applet); + FreeLibrary(applet->hModule); + HeapFree(GetProcessHeap(), 0, applet->cmd); + HeapFree(GetProcessHeap(), 0, applet); return NULL; } -static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTW* cs) +#ifndef __REACTOS__ + +#define IDC_LISTVIEW 1000 +#define IDC_STATUSBAR 1001 + +#define NUM_COLUMNS 2 +#define LISTVIEW_DEFSTYLE (WS_CHILD | WS_VISIBLE | WS_TABSTOP |\ + LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_SINGLESEL) + +static BOOL Control_CreateListView (CPanel *panel) { - CPanel* panel = (CPanel*)cs->lpCreateParams; + RECT ws, sb; + WCHAR empty_string[] = {0}; + WCHAR buf[MAX_STRING_LEN]; + LVCOLUMNW lvc; + + /* Create list view */ + GetClientRect(panel->hWndStatusBar, &sb); + GetClientRect(panel->hWnd, &ws); + + panel->hWndListView = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, + empty_string, LISTVIEW_DEFSTYLE | LVS_ICON, + 0, 0, ws.right - ws.left, ws.bottom - ws.top - + (sb.bottom - sb.top), panel->hWnd, + (HMENU) IDC_LISTVIEW, panel->hInst, NULL); + + if (!panel->hWndListView) + return FALSE; + + /* Create image lists for list view */ + panel->hImageListSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 1, 1); + panel->hImageListLarge = ImageList_Create(GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 1, 1); + + SendMessageW(panel->hWndListView, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)panel->hImageListSmall); + SendMessageW(panel->hWndListView, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)panel->hImageListLarge); + + /* Create columns for list view */ + lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; + lvc.pszText = buf; + lvc.fmt = LVCFMT_LEFT; + + /* Name column */ + lvc.iSubItem = 0; + lvc.cx = (ws.right - ws.left) / 3; + LoadStringW(shell32_hInstance, IDS_CPANEL_NAME, buf, sizeof(buf) / sizeof(buf[0])); + + if (ListView_InsertColumnW(panel->hWndListView, 0, &lvc) == -1) + return FALSE; + + /* Description column */ + lvc.iSubItem = 1; + lvc.cx = ((ws.right - ws.left) / 3) * 2; + LoadStringW(shell32_hInstance, IDS_CPANEL_DESCRIPTION, buf, sizeof(buf) / + sizeof(buf[0])); + + if (ListView_InsertColumnW(panel->hWndListView, 1, &lvc) == -1) + return FALSE; + + return(TRUE); +} + +static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTW* cs) +{ + CPanel* panel = cs->lpCreateParams; + HMENU hMenu, hSubMenu; + CPlApplet* applet; + MENUITEMINFOW mii; + unsigned int i; + int menucount, index; + CPlItem *item; + LVITEMW lvItem; + INITCOMMONCONTROLSEX icex; + INT sb_parts; + int itemidx; SetWindowLongPtrW(hWnd, 0, (LONG_PTR)panel); - panel->status = 0; panel->hWnd = hWnd; + + /* Initialise common control DLL */ + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES; + InitCommonControlsEx(&icex); + + /* create the status bar */ + if (!(panel->hWndStatusBar = CreateStatusWindowW(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, NULL, hWnd, IDC_STATUSBAR))) + return; + + sb_parts = -1; + SendMessageW(panel->hWndStatusBar, SB_SETPARTS, 1, (LPARAM) &sb_parts); + + /* create the list view */ + if (!Control_CreateListView(panel)) + return; + + hMenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_CPANEL)); + + /* insert menu items for applets */ + hSubMenu = GetSubMenu(hMenu, 0); + menucount = 0; + + LIST_FOR_EACH_ENTRY( applet, &panel->applets, CPlApplet, entry ) + { + for (i = 0; i < applet->count; i++) { + /* set up a CPlItem for this particular subprogram */ + item = HeapAlloc(GetProcessHeap(), 0, sizeof(CPlItem)); + + if (!item) + continue; + + item->applet = applet; + item->id = i; + + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA; + mii.dwTypeData = applet->info[i].name; + mii.cch = sizeof(applet->info[i].name) / sizeof(WCHAR); + mii.wID = IDM_CPANEL_APPLET_BASE + menucount; + mii.dwItemData = (ULONG_PTR)item; + + if (InsertMenuItemW(hSubMenu, menucount, TRUE, &mii)) { + /* add the list view item */ + HICON icon = applet->info[i].icon; + if (!icon) icon = LoadImageW( 0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_SHARED ); + index = ImageList_AddIcon(panel->hImageListLarge, icon); + ImageList_AddIcon(panel->hImageListSmall, icon); + + lvItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM; + lvItem.iItem = menucount; + lvItem.iSubItem = 0; + lvItem.pszText = applet->info[i].name; + lvItem.iImage = index; + lvItem.lParam = (LPARAM) item; + + itemidx = ListView_InsertItemW(panel->hWndListView, &lvItem); + + /* add the description */ + ListView_SetItemTextW(panel->hWndListView, itemidx, 1, applet->info[i].info); + + /* update menu bar, increment count */ + DrawMenuBar(hWnd); + menucount++; + } + } + } + + panel->total_subprogs = menucount; + + /* check the "large items" icon in the View menu */ + hSubMenu = GetSubMenu(hMenu, 1); + CheckMenuRadioItem(hSubMenu, FCIDM_SHVIEW_BIGICON, FCIDM_SHVIEW_REPORTVIEW, + FCIDM_SHVIEW_BIGICON, MF_BYCOMMAND); + + SetMenu(hWnd, hMenu); } -#define XICON 32 -#define XSTEP 128 -#define YICON 32 -#define YSTEP 64 - -static BOOL Control_Localize(const CPanel* panel, int cx, int cy, - CPlApplet** papplet, unsigned* psp) +static void Control_FreeCPlItems(HWND hWnd, CPanel *panel) { - unsigned int i; - int x = (XSTEP-XICON)/2, y = 0; - CPlApplet* applet; - RECT rc; + HMENU hMenu, hSubMenu; + MENUITEMINFOW mii; + unsigned int i; - GetClientRect(panel->hWnd, &rc); - for (applet = panel->first; applet; applet = applet->next) + /* get the File menu */ + hMenu = GetMenu(hWnd); + + if (!hMenu) + return; + + hSubMenu = GetSubMenu(hMenu, 0); + + if (!hSubMenu) + return; + + /* loop and free the item data */ + for (i = IDM_CPANEL_APPLET_BASE; i <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs; i++) { - for (i = 0; i < applet->count; i++) - { - if (!applet->info[i].dwSize) - continue; - if (x + XSTEP >= rc.right - rc.left) - { - x = (XSTEP-XICON)/2; - y += YSTEP; - } - if (cx >= x && cx < x + XICON && cy >= y && cy < y + YSTEP) - { - *papplet = applet; - *psp = i; - return TRUE; - } - x += XSTEP; - } + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_DATA; + + if (!GetMenuItemInfoW(hSubMenu, i, FALSE, &mii)) + continue; + + HeapFree(GetProcessHeap(), 0, (LPVOID) mii.dwItemData); } - return FALSE; } -static LRESULT Control_WndProc_Paint(const CPanel* panel, WPARAM wParam) +static void Control_UpdateListViewStyle(CPanel *panel, UINT style, UINT id) { - HDC hdc; - PAINTSTRUCT ps; - RECT rc, txtRect; - unsigned int i; - int x = 0, y = 0; - CPlApplet* applet; - HGDIOBJ hOldFont; + HMENU hMenu, hSubMenu; - hdc = (wParam) ? (HDC)wParam : BeginPaint(panel->hWnd, &ps); - hOldFont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT)); - GetClientRect(panel->hWnd, &rc); - - for (applet = panel->first; applet; applet = applet->next) - { - for (i = 0; i < applet->count; i++) - { - if (x + XSTEP >= rc.right - rc.left) - { - x = 0; - y += YSTEP; - } - if (!applet->info[i].dwSize) - continue; - DrawIcon(hdc, x + (XSTEP-XICON)/2, y, applet->info[i].hIcon); - txtRect.left = x; - txtRect.right = x + XSTEP; - txtRect.top = y + YICON; - txtRect.bottom = y + YSTEP; - DrawTextW(hdc, applet->info[i].szName, -1, &txtRect, - DT_CENTER | DT_VCENTER); - x += XSTEP; - } - } + SetWindowLongW(panel->hWndListView, GWL_STYLE, LISTVIEW_DEFSTYLE | style); - SelectObject(hdc, hOldFont); - if (!wParam) - EndPaint(panel->hWnd, &ps); + /* update the menu */ + hMenu = GetMenu(panel->hWnd); + hSubMenu = GetSubMenu(hMenu, 1); - return 0; + CheckMenuRadioItem(hSubMenu, FCIDM_SHVIEW_BIGICON, FCIDM_SHVIEW_REPORTVIEW, + id, MF_BYCOMMAND); } -static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up) +static CPlItem* Control_GetCPlItem_From_MenuID(HWND hWnd, UINT id) { - unsigned i; - CPlApplet* applet; + HMENU hMenu, hSubMenu; + MENUITEMINFOW mii; - if (Control_Localize(panel, (short)LOWORD(lParam), (short)HIWORD(lParam), &applet, &i)) - { - if (up) - { - if (panel->clkApplet == applet && panel->clkSP == i) - { - applet->proc(applet->hWnd, CPL_DBLCLK, i, applet->info[i].lData); - } - } - else - { - panel->clkApplet = applet; - panel->clkSP = i; - } - } - return 0; + /* retrieve the CPlItem structure from the menu item data */ + hMenu = GetMenu(hWnd); + + if (!hMenu) + return NULL; + + hSubMenu = GetSubMenu(hMenu, 0); + + if (!hSubMenu) + return NULL; + + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_DATA; + + if (!GetMenuItemInfoW(hSubMenu, id, FALSE, &mii)) + return NULL; + + return (CPlItem *) mii.dwItemData; } -static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg, - WPARAM lParam1, LPARAM lParam2) +static CPlItem* Control_GetCPlItem_From_ListView(CPanel *panel) { - CPanel* panel = (CPanel*)GetWindowLongPtrW(hWnd, 0); + LVITEMW lvItem; + int selitem; - if (panel || wMsg == WM_CREATE) + selitem = SendMessageW(panel->hWndListView, LVM_GETNEXTITEM, -1, LVNI_FOCUSED + | LVNI_SELECTED); + + if (selitem != -1) { - switch (wMsg) - { - case WM_CREATE: - Control_WndProc_Create(hWnd, (CREATESTRUCTW*)lParam2); - return 0; - case WM_DESTROY: - { - CPlApplet *applet = panel->first; - while (applet) - applet = Control_UnloadApplet(applet); - - PostQuitMessage(0); - break; - } - case WM_PAINT: - return Control_WndProc_Paint(panel, lParam1); - case WM_LBUTTONUP: - return Control_WndProc_LButton(panel, lParam2, TRUE); - case WM_LBUTTONDOWN: - return Control_WndProc_LButton(panel, lParam2, FALSE); - /* EPP case WM_COMMAND: */ - /* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */ - } + lvItem.iItem = selitem; + lvItem.mask = LVIF_PARAM; + + if (SendMessageW(panel->hWndListView, LVM_GETITEMW, 0, (LPARAM) &lvItem)) + return (CPlItem *) lvItem.lParam; } + return NULL; +} + +static void Control_StartApplet(HWND hWnd, CPlItem *item) +{ + WCHAR verbOpen[] = {'c','p','l','o','p','e','n',0}; + WCHAR format[] = {'@','%','d',0}; + WCHAR param[MAX_PATH]; + + /* execute the applet if item is valid */ + if (item) + { + wsprintfW(param, format, item->id); + ShellExecuteW(hWnd, verbOpen, item->applet->cmd, param, NULL, SW_SHOW); + } +} + +static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg, + WPARAM lParam1, LPARAM lParam2) +{ + CPanel* panel = (CPanel*)GetWindowLongPtrW(hWnd, 0); + + if (panel || wMsg == WM_CREATE) { + switch (wMsg) { + case WM_CREATE: + Control_WndProc_Create(hWnd, (CREATESTRUCTW*)lParam2); + return 0; + case WM_DESTROY: + { + CPlApplet *applet, *next; + LIST_FOR_EACH_ENTRY_SAFE( applet, next, &panel->applets, CPlApplet, entry ) + Control_UnloadApplet(applet); + } + Control_FreeCPlItems(hWnd, panel); + PostQuitMessage(0); + break; + case WM_COMMAND: + switch (LOWORD(lParam1)) + { + case IDM_CPANEL_EXIT: + SendMessageW(hWnd, WM_CLOSE, 0, 0); + return 0; + + case IDM_CPANEL_ABOUT: + { + WCHAR appName[MAX_STRING_LEN]; + HICON icon = LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL), + IMAGE_ICON, 48, 48, LR_SHARED); + + LoadStringW(shell32_hInstance, IDS_CPANEL_TITLE, appName, + sizeof(appName) / sizeof(appName[0])); + ShellAboutW(hWnd, appName, NULL, icon); + + return 0; + } + + case FCIDM_SHVIEW_BIGICON: + Control_UpdateListViewStyle(panel, LVS_ICON, FCIDM_SHVIEW_BIGICON); + return 0; + + case FCIDM_SHVIEW_SMALLICON: + Control_UpdateListViewStyle(panel, LVS_SMALLICON, FCIDM_SHVIEW_SMALLICON); + return 0; + + case FCIDM_SHVIEW_LISTVIEW: + Control_UpdateListViewStyle(panel, LVS_LIST, FCIDM_SHVIEW_LISTVIEW); + return 0; + + case FCIDM_SHVIEW_REPORTVIEW: + Control_UpdateListViewStyle(panel, LVS_REPORT, FCIDM_SHVIEW_REPORTVIEW); + return 0; + + default: + /* check if this is an applet */ + if ((LOWORD(lParam1) >= IDM_CPANEL_APPLET_BASE) && + (LOWORD(lParam1) <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs)) + { + Control_StartApplet(hWnd, Control_GetCPlItem_From_MenuID(hWnd, LOWORD(lParam1))); + return 0; + } + + break; + } + + break; + + case WM_NOTIFY: + { + LPNMHDR nmh = (LPNMHDR) lParam2; + + switch (nmh->idFrom) + { + case IDC_LISTVIEW: + switch (nmh->code) + { + case NM_RETURN: + case NM_DBLCLK: + { + Control_StartApplet(hWnd, Control_GetCPlItem_From_ListView(panel)); + return 0; + } + case LVN_ITEMCHANGED: + { + CPlItem *item = Control_GetCPlItem_From_ListView(panel); + + /* update the status bar if item is valid */ + if (item) + SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].info); + else + SetWindowTextW(panel->hWndStatusBar, NULL); + + return 0; + } + } + + break; + } + + break; + } + + case WM_MENUSELECT: + /* check if this is an applet */ + if ((LOWORD(lParam1) >= IDM_CPANEL_APPLET_BASE) && + (LOWORD(lParam1) <= IDM_CPANEL_APPLET_BASE + panel->total_subprogs)) + { + CPlItem *item = Control_GetCPlItem_From_MenuID(hWnd, LOWORD(lParam1)); + + /* update the status bar if item is valid */ + if (item) + SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].info); + } + else if ((HIWORD(lParam1) == 0xFFFF) && (lParam2 == 0)) + { + /* reset status bar description to that of the selected icon */ + CPlItem *item = Control_GetCPlItem_From_ListView(panel); + + if (item) + SetWindowTextW(panel->hWndStatusBar, item->applet->info[item->id].info); + else + SetWindowTextW(panel->hWndStatusBar, NULL); + + return 0; + } + else + SetWindowTextW(panel->hWndStatusBar, NULL); + + return 0; + + case WM_SIZE: + { + HDWP hdwp; + RECT sb; + + hdwp = BeginDeferWindowPos(2); + + if (hdwp == NULL) + break; + + GetClientRect(panel->hWndStatusBar, &sb); + + hdwp = DeferWindowPos(hdwp, panel->hWndListView, NULL, 0, 0, + LOWORD(lParam2), HIWORD(lParam2) - (sb.bottom - sb.top), + SWP_NOZORDER | SWP_NOMOVE); + + if (hdwp == NULL) + break; + + hdwp = DeferWindowPos(hdwp, panel->hWndStatusBar, NULL, 0, 0, + LOWORD(lParam2), LOWORD(lParam1), SWP_NOZORDER | SWP_NOMOVE); + + if (hdwp != NULL) + EndDeferWindowPos(hdwp); + + return 0; + } + } + } + return DefWindowProcW(hWnd, wMsg, lParam1, lParam2); } -static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst) +static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst) { - WNDCLASSW wc; - MSG msg; - const WCHAR* appName = L"ReactOS Control Panel"; + WNDCLASSEXW wc; + MSG msg; + WCHAR appName[MAX_STRING_LEN]; + const WCHAR className[] = {'S','h','e','l','l','_','C','o','n','t','r','o', + 'l','_','W','n','d','C','l','a','s','s',0}; + + LoadStringW(shell32_hInstance, IDS_CPANEL_TITLE, appName, sizeof(appName) / sizeof(appName[0])); + + wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = Control_WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(CPlApplet*); - wc.hInstance = hInst; - wc.hIcon = 0; - wc.hCursor = 0; - wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wc.hInstance = panel->hInst = hInst; + wc.hIcon = LoadIconW( shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL) ); + wc.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW ); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; - wc.lpszClassName = L"Shell_Control_WndClass"; + wc.lpszClassName = className; + wc.hIconSm = LoadImageW( shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_CONTROL_PANEL), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); - if (!RegisterClassW(&wc)) return; + if (!RegisterClassExW(&wc)) return; CreateWindowExW(0, wc.lpszClassName, appName, - WS_OVERLAPPEDWINDOW | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - hWnd, NULL, hInst, panel); - - if (!panel->hWnd) - return; + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hWnd, NULL, hInst, panel); + if (!panel->hWnd) return; - if (!panel->first) - { - /* FIXME appName & message should be localized */ - MessageBoxW(panel->hWnd, L"Cannot load any applets", appName, MB_OK); - return; - } - - while (GetMessageW(&msg, panel->hWnd, 0, 0)) - { + while (GetMessageW(&msg, panel->hWnd, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } } -static void Control_DoWindow(CPanel *panel, HWND hWnd, HINSTANCE hInst) +static void Control_RegisterRegistryApplets(HWND hWnd, CPanel *panel, HKEY hkey_root, LPCWSTR szRepPath) { - HANDLE hFind; - WIN32_FIND_DATAW wfd; - WCHAR wszPath[MAX_PATH]; - WCHAR *Ptr = wszPath; + WCHAR name[MAX_PATH]; + WCHAR value[MAX_PATH]; + HKEY hkey; - Ptr += GetSystemDirectoryW(wszPath, MAX_PATH); - *Ptr++ = '\\'; - wcscpy(Ptr, L"*.cpl"); - - hFind = FindFirstFileW(wszPath, &wfd); - if (hFind != INVALID_HANDLE_VALUE) + if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) { - do + int idx = 0; + + for(;; ++idx) { - wcscpy(Ptr, wfd.cFileName); - Control_LoadApplet(hWnd, wszPath, panel); - } while (FindNextFileW(hFind, &wfd)); - FindClose(hFind); + DWORD nameLen = MAX_PATH; + DWORD valueLen = MAX_PATH; + + if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)value, &valueLen) != ERROR_SUCCESS) + break; + + Control_LoadApplet(hWnd, value, panel); + } + RegCloseKey(hkey); } +} + +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}; + static const WCHAR wszRegPath[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t', + '\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', + '\\','C','o','n','t','r','o','l',' ','P','a','n','e','l','\\','C','p','l','s',0}; + WCHAR *p; + + /* first add .cpl files in the system directory */ + GetSystemDirectoryW( buffer, MAX_PATH ); + p = buffer + strlenW(buffer); + *p++ = '\\'; + lstrcpyW(p, wszAllCpl); + + if ((h = FindFirstFileW(buffer, &fd)) != INVALID_HANDLE_VALUE) { + do { + lstrcpyW(p, fd.cFileName); + Control_LoadApplet(hWnd, buffer, panel); + } while (FindNextFileW(h, &fd)); + FindClose(h); + } + + /* now check for cpls in the registry */ + Control_RegisterRegistryApplets(hWnd, panel, HKEY_LOCAL_MACHINE, wszRegPath); + Control_RegisterRegistryApplets(hWnd, panel, HKEY_CURRENT_USER, wszRegPath); Control_DoInterface(panel, hWnd, hInst); } -static void Control_DoLaunch(CPanel *pPanel, HWND hWnd, LPCWSTR pwszCmd) +#else +static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst) { - HANDLE hMutex; + ShellExecuteW(NULL, + L"open", + L"explorer.exe", + L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", + NULL, + SW_SHOWDEFAULT); +} +#endif - /* Make a pwszCmd copy so we can modify it */ - LPWSTR pwszCmdCopy = _wcsdup(pwszCmd); +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; + LPWSTR ptr; + signed sp = -1; + LPWSTR extraPmtsBuf = NULL; + LPWSTR extraPmts = NULL; + BOOL quoted = FALSE; + CPlApplet *applet; - LPWSTR pwszPath = pwszCmdCopy, pwszArg = NULL, pwszArg2 = NULL; - if (!pwszCmdCopy) - return; + buffer = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(wszCmd) + 1) * sizeof(*wszCmd)); + if (!buffer) return; - /* Path can be quoted */ - if (pwszPath[0] == L'"') - { - ++pwszPath; - pwszArg = wcschr(pwszPath, L'"'); - if (pwszArg) - *(pwszArg++) = '\0'; + end = lstrcpyW(buffer, wszCmd); + + for (;;) { + ch = *end; + if (ch == '"') quoted = !quoted; + if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) { + *end = '\0'; + if (beg) { + if (*beg == '@') { + sp = atoiW(beg + 1); + } else if (*beg == '\0') { + sp = -1; + } else { + extraPmtsBuf = beg; + } + } + if (ch == '\0') break; + beg = end + 1; + if (ch == ' ') while (end[1] == ' ') end++; + } + end++; } - else - pwszArg = pwszCmdCopy; + while ((ptr = StrChrW(buffer, '"'))) + memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR)); - /* First argument starts after space or ','. Note: we ignore characters between '"' and ',' or ' '. */ - if (pwszArg) - pwszArg = wcspbrk(pwszArg, L" ,"); - if (pwszArg) + /* now check for any quotes in extraPmtsBuf and remove */ + if (extraPmtsBuf != NULL) { - /* 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; + beg = end = extraPmtsBuf; + quoted = FALSE; - /* Second argument always starts with ','. Note: we ignore characters between '"' and ','. */ - if (pwszArg2) - pwszArg2 = wcschr(pwszArg2, L','); + for (;;) { + ch = *end; + if (ch == '"') quoted = !quoted; + if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) { + *end = '\0'; + if (beg) { + if (*beg != '\0') { + extraPmts = beg; + } + } + if (ch == '\0') break; + beg = end + 1; + if (ch == ' ') while (end[1] == ' ') end++; + } + end++; + } + + while ((ptr = StrChrW(extraPmts, '"'))) + memmove(ptr, ptr+1, lstrlenW(ptr)*sizeof(WCHAR)); + + if (extraPmts == NULL) + extraPmts = extraPmtsBuf; } - TRACE("Launch %ls, arg %ls, arg2 %ls\n", pwszPath, pwszArg, pwszArg2); - - /* Create a mutex to disallow running multiple instances */ - hMutex = CreateMutexW(NULL, TRUE, PathFindFileNameW(pwszPath)); - if (!hMutex || GetLastError() == ERROR_ALREADY_EXISTS) - { - TRACE("Next instance disallowed\n"); - if (hMutex) - CloseHandle(hMutex); - return; + /* Now check if there had been a numerical value in the extra params */ + if ((extraPmts) && (*extraPmts == '@') && (sp == -1)) { + sp = atoiW(extraPmts + 1); } - /* Load applet cpl */ - TRACE("Load applet %ls\n", pwszPath); - Control_LoadApplet(hWnd, pwszPath, pPanel); - if (pPanel->first) - { - INT i = 0; - /* First pPanel applet is the new one */ - CPlApplet *pApplet = pPanel->first; - assert(pApplet && pApplet->next == NULL); - TRACE("pApplet->count %d\n", pApplet->count); + TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp); - /* Note: if there is only one applet, first argument is ignored */ - 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; + applet = Control_LoadApplet(hWnd, buffer, panel); + if (applet) + { + /* we've been given a textual parameter (or none at all) */ + if (sp == -1) { + while ((++sp) != applet->count) { + TRACE("sp %d, name %s\n", sp, debugstr_w(applet->info[sp].name)); + + if (StrCmpIW(extraPmts, applet->info[sp].name) == 0) + 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_STARTWPARMSW, i, (LPARAM)pwszArg)) - pApplet->proc(pApplet->hWnd, CPL_DBLCLK, i, pApplet->info[i].lData); - } else - ERR("Applet not found: %ls\n", pwszArg ? pwszArg : L"NULL"); + if (sp >= applet->count) { + WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count); + sp = 0; + } - Control_UnloadApplet(pApplet); + if (!applet->proc(applet->hWnd, CPL_STARTWPARMSW, sp, (LPARAM)extraPmts)) + applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].data); + + Control_UnloadApplet(applet); } - else - ERR("Failed to load applet %ls\n", pwszPath); - ReleaseMutex(hMutex); - CloseHandle(hMutex); - free(pwszCmdCopy); + HeapFree(GetProcessHeap(), 0, buffer); } /************************************************************************* - * Control_RunDLLW [SHELL32.@] + * Control_RunDLLW [SHELL32.@] * */ 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)); +#ifndef __REACTOS__ + memset(&panel, 0, sizeof(panel)); + list_init( &panel.applets ); +#endif - if (!cmd || !*cmd) - { - TRACE("[shell32, Control_RunDLLW] Calling Control_DoWindow\n"); - Control_DoWindow(&Panel, hWnd, hInst); - } - else - { - TRACE("[shell32, Control_RunDLLW] Calling Control_DoLaunch\n"); - Control_DoLaunch(&Panel, hWnd, cmd); + if (!cmd || !*cmd) { + Control_DoWindow(&panel, hWnd, hInst); + } else { + Control_DoLaunch(&panel, hWnd, cmd); } } @@ -537,6 +887,7 @@ HRESULT WINAPI Control_FillCache_RunDLLA(HWND hWnd, HANDLE hModule, DWORD w, DWO } +#ifdef __REACTOS__ /************************************************************************* * RunDll_CallEntry16 [SHELL32.122] * the name is OK (when written with Dll, and not DLL as in Wine!) @@ -544,35 +895,19 @@ HRESULT WINAPI Control_FillCache_RunDLLA(HWND hWnd, HANDLE hModule, DWORD w, DWO void WINAPI RunDll_CallEntry16( DWORD proc, HWND hwnd, HINSTANCE inst, LPCSTR cmdline, INT cmdshow ) { -#if !defined(__CYGWIN__) && !defined (__MINGW32__) && !defined(_MSC_VER) - WORD args[5]; - SEGPTR cmdline_seg; - - TRACE( "proc %x hwnd %p inst %p cmdline %s cmdshow %d\n", - proc, hwnd, inst, debugstr_a(cmdline), cmdshow ); - - cmdline_seg = MapLS( cmdline ); - args[4] = HWND_16(hwnd); - args[3] = MapHModuleLS(inst); - args[2] = SELECTOROF(cmdline_seg); - args[1] = OFFSETOF(cmdline_seg); - args[0] = cmdshow; - WOWCallback16Ex( proc, WCB16_PASCAL, sizeof(args), args, NULL ); - UnMapLS( cmdline_seg ); -#else FIXME( "proc %lx hwnd %p inst %p cmdline %s cmdshow %d\n", proc, hwnd, inst, debugstr_a(cmdline), cmdshow ); -#endif } +#endif /************************************************************************* - * CallCPLEntry16 [SHELL32.166] + * CallCPLEntry16 [SHELL32.166] * * called by desk.cpl on "Advanced" with: * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0 * */ -LRESULT WINAPI CallCPLEntry16(HINSTANCE hMod, FARPROC pFunc, HWND dw3, UINT dw4, LPARAM dw5, LPARAM dw6) +DWORD WINAPI CallCPLEntry16(HMODULE hMod, FARPROC pFunc, DWORD dw3, DWORD dw4, DWORD dw5, DWORD dw6) { FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod, pFunc, dw3, dw4, dw5, dw6); return 0x0deadbee; diff --git a/reactos/dll/win32/shell32/wine/cpanel.h b/reactos/dll/win32/shell32/wine/cpanel.h new file mode 100644 index 00000000000..26fca4a6abf --- /dev/null +++ b/reactos/dll/win32/shell32/wine/cpanel.h @@ -0,0 +1,81 @@ +/* Control Panel management + * + * Copyright 2001 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_SHELL_CPANEL_H +#define __WINE_SHELL_CPANEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct applet_info +{ + LONG_PTR data; +#ifdef __REACTOS__ + int idIcon; +#endif + HICON icon; + WCHAR name[256]; + WCHAR info[256]; + WCHAR helpfile[128]; +}; + +typedef struct CPlApplet { +#ifndef __REACTOS__ + struct list entry; +#endif + HWND hWnd; + LPWSTR cmd; /* path to applet */ + unsigned count; /* number of subprograms */ + HMODULE hModule; /* module of loaded applet */ + APPLET_PROC proc; /* entry point address */ + struct applet_info info[1]; /* array of count information */ +} CPlApplet; + +#ifndef __REACTOS__ +typedef struct CPanel { + struct list applets; + HWND hWnd; + HINSTANCE hInst; + unsigned total_subprogs; + HWND hWndListView; + HIMAGELIST hImageListLarge; + HIMAGELIST hImageListSmall; + HWND hWndStatusBar; +} CPanel; + +/* structure to reference an individual control panel item */ +typedef struct CPlItem { + CPlApplet *applet; + unsigned id; +} CPlItem; +#else +typedef int CPanel; +#endif + +CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) DECLSPEC_HIDDEN; +void Control_UnloadApplet(CPlApplet* applet) DECLSPEC_HIDDEN; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __WINE_SHELL_CPANEL_H */ diff --git a/reactos/dll/win32/shell32/wine/pidl.c b/reactos/dll/win32/shell32/wine/pidl.c index 5e098ca4fb0..6da0037f1e8 100644 --- a/reactos/dll/win32/shell32/wine/pidl.c +++ b/reactos/dll/win32/shell32/wine/pidl.c @@ -2165,6 +2165,12 @@ static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) case PT_VALUEW: return (LPWSTR)pdata->u.file.szNames; + +#ifdef __REACTOS__ /* r54423 */ + case PT_CPLAPPLET: + return pdata->u.cpanel.szName; +#endif + } return NULL; } @@ -2209,11 +2215,6 @@ LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) case PT_NETPROVIDER: case PT_SHARE: return pdata->u.network.szNames; - -#ifdef __REACTOS__ /* r54423 */ - case PT_CPLAPPLET: - return pdata->u.cpanel.szName; -#endif } return NULL; } diff --git a/reactos/dll/win32/shell32/wine/pidl.h b/reactos/dll/win32/shell32/wine/pidl.h index 19275bb1363..8fb148b986d 100644 --- a/reactos/dll/win32/shell32/wine/pidl.h +++ b/reactos/dll/win32/shell32/wine/pidl.h @@ -113,7 +113,7 @@ typedef struct tagPIDLCPanelStruct DWORD iconIdx; /*02 negative icon ID */ WORD offsDispName; /*06*/ WORD offsComment; /*08*/ - CHAR szName[1]; /*10*/ /* terminated by 0x00, followed by display name and comment string */ + WCHAR szName[1]; /*10*/ /* terminated by 0x00, followed by display name and comment string */ } PIDLCPanelStruct; #ifdef __REACTOS__