diff --git a/dll/win32/shell32/stubs.cpp b/dll/win32/shell32/stubs.cpp index 1c7996df8a..3be6d2ec3b 100644 --- a/dll/win32/shell32/stubs.cpp +++ b/dll/win32/shell32/stubs.cpp @@ -36,17 +36,6 @@ SHFindComputer(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) return FALSE; } -/* - * Unimplemented - */ -EXTERN_C HRESULT -WINAPI -SHLimitInputEdit(HWND hWnd, IShellFolder *psf) -{ - FIXME("SHLimitInputEdit() stub\n"); - return S_FALSE; -} - /* * Unimplemented */ diff --git a/dll/win32/shell32/wine/shellord.c b/dll/win32/shell32/wine/shellord.c index 71f35e4d86..49d1bf605b 100644 --- a/dll/win32/shell32/wine/shellord.c +++ b/dll/win32/shell32/wine/shellord.c @@ -2147,4 +2147,153 @@ SHTestTokenMembership(HANDLE TokenHandle, ULONG ulRID) BOOL WINAPI IsUserAnAdmin(VOID) { return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS); -} \ No newline at end of file +} + +/************************************************************************* + * SHLimitInputEdit(SHELL32.@) + */ + +typedef struct UxSubclassInfo +{ + WNDPROC fnWndProc; + LPWSTR pwszValidChars; + LPWSTR pwszInvalidChars; +} UxSubclassInfo; + +static LRESULT CALLBACK +LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC fnWndProc; + UxSubclassInfo *pInfo = GetPropW(hwnd, L"UxSubclassInfo"); + if (!pInfo) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + fnWndProc = pInfo->fnWndProc; + + switch (uMsg) + { + case WM_CHAR: + { + if (pInfo->pwszInvalidChars) + { + if (wcschr(pInfo->pwszInvalidChars, (CHAR)wParam) != NULL) + { + MessageBeep(0xFFFFFFFF); + break; + } + } + else if (pInfo->pwszValidChars) + { + if (wcschr(pInfo->pwszValidChars, (CHAR)wParam) == NULL) + { + MessageBeep(0xFFFFFFFF); + break; + } + } + return fnWndProc(hwnd, uMsg, wParam, lParam); + } + + case WM_IME_CHAR: + { + // TODO: DBCS + if (pInfo->pwszInvalidChars) + { + if (wcschr(pInfo->pwszInvalidChars, (WCHAR)wParam) != NULL) + { + MessageBeep(0xFFFFFFFF); + break; + } + } + else if (pInfo->pwszValidChars) + { + if (wcschr(pInfo->pwszValidChars, (WCHAR)wParam) == NULL) + { + MessageBeep(0xFFFFFFFF); + break; + } + } + return fnWndProc(hwnd, uMsg, wParam, lParam); + } + + case WM_NCDESTROY: + { + RemovePropW(hwnd, L"UxSubclassInfo"); + CoTaskMemFree(pInfo->pwszValidChars); + pInfo->pwszValidChars = NULL; + CoTaskMemFree(pInfo->pwszInvalidChars); + pInfo->pwszInvalidChars = NULL; + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)fnWndProc); + HeapFree(GetProcessHeap(), 0, pInfo); + return fnWndProc(hwnd, uMsg, wParam, lParam); + } + + default: + return fnWndProc(hwnd, uMsg, wParam, lParam); + } + + return 0; +} + +HRESULT WINAPI SHLimitInputEdit(HWND hWnd, IShellFolder *psf) +{ + IItemNameLimits *pLimits = NULL; + HRESULT hr; + LPWSTR pwszValidChars = NULL; + LPWSTR pwszInvalidChars = NULL; + UxSubclassInfo *pInfo = NULL; + + hr = psf->lpVtbl->QueryInterface(psf, &IID_IItemNameLimits, (LPVOID *)&pLimits); + if (FAILED(hr) || !pLimits) + { + ERR("hr: %x\n", hr); + return hr; + } + + hr = pLimits->lpVtbl->GetValidCharacters(pLimits, &pwszValidChars, &pwszInvalidChars); + if (SUCCEEDED(hr)) + { + pInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(UxSubclassInfo)); + if (pInfo) + { + if (SetPropW(hWnd, L"UxSubclassInfo", pInfo)) + { + pInfo->fnWndProc = (WNDPROC) + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)LimitEditWindowProc); + + if (pInfo->fnWndProc) + { + pInfo->pwszValidChars = pwszValidChars; + pInfo->pwszInvalidChars = pwszInvalidChars; + + pLimits->lpVtbl->Release(pLimits); + return S_OK; + } + else + { + ERR("SetWindowLongPtr failed\n"); + } + } + else + { + ERR("SetPropW failed\n"); + } + + HeapFree(GetProcessHeap(), 0, pInfo); + } + else + { + ERR("HeapAlloc failed\n"); + } + } + else + { + ERR("hr: %x\n", hr); + } + + pLimits->lpVtbl->Release(pLimits); + + CoTaskMemFree(pwszValidChars); + CoTaskMemFree(pwszInvalidChars); + + return hr; +}