diff --git a/dll/win32/shlwapi/ordinal.c b/dll/win32/shlwapi/ordinal.c index f43408d9479..a151d4dce00 100644 --- a/dll/win32/shlwapi/ordinal.c +++ b/dll/win32/shlwapi/ordinal.c @@ -47,6 +47,9 @@ #include "commdlg.h" #include "mlang.h" #include "mshtmhst.h" +#ifdef __REACTOS__ + #include +#endif #include "wine/unicode.h" #include "wine/debug.h" @@ -3288,6 +3291,37 @@ BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound) DWORD WINAPI SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out, DWORD outLen, LPCWSTR filename) { +#ifdef __REACTOS__ + WCHAR szSection[MAX_PATH + 2]; + WCHAR szWideBuff[MAX_PATH]; + CHAR szUtf7Buff[MAX_PATH]; + + TRACE("(%s,%s,%p,%08x,%s)\n", debugstr_w(appName), debugstr_w(keyName), + out, outLen, debugstr_w(filename)); + + if (outLen == 0) + return 0; + + /* Try ".W"-appended section name. See also SHSetIniStringW. */ + lstrcpynW(szSection, appName, _countof(szSection) - 2); + lstrcatW(szSection, L".W"); + GetPrivateProfileStringW(szSection, keyName, NULL, szWideBuff, _countof(szWideBuff), filename); + if (szWideBuff[0] == UNICODE_NULL) /* It's empty or not found */ + { + /* Try the normal section name */ + return GetPrivateProfileStringW(appName, keyName, NULL, out, outLen, filename); + } + + /* Okay, now ".W" version is valid. Its value is a UTF-7 string in UTF-16 */ + + /* szWideBuff --> szUtf7Buff */ + SHUnicodeToAnsiCP(CP_ACP, szWideBuff, szUtf7Buff, _countof(szUtf7Buff)); + szUtf7Buff[_countof(szUtf7Buff) - 1] = ANSI_NULL; + + /* szUtf7Buff --> out */ + SHAnsiToUnicodeCP(CP_UTF7, szUtf7Buff, out, outLen); + out[outLen - 1] = UNICODE_NULL; +#else INT ret; WCHAR *buf; @@ -3310,10 +3344,27 @@ DWORD WINAPI SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out, *out = 0; HeapFree(GetProcessHeap(), 0, buf); +#endif return strlenW(out); } +#ifdef __REACTOS__ +static BOOL Is7BitClean(LPCWSTR psz) +{ + if (!psz) + return TRUE; + + while (*psz) + { + if (*psz > 0x7F) + return FALSE; + ++psz; + } + return TRUE; +} +#endif + /************************************************************************* * @ [SHLWAPI.295] * @@ -3333,10 +3384,63 @@ DWORD WINAPI SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out, BOOL WINAPI SHSetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPCWSTR str, LPCWSTR filename) { +#ifdef __REACTOS__ + WCHAR szSection[MAX_PATH + 2]; + WCHAR szWideBuff[MAX_PATH]; + CHAR szUtf7Buff[MAX_PATH]; + + TRACE("(%s, %p, %s, %s)\n", debugstr_w(appName), keyName, debugstr_w(str), + debugstr_w(filename)); + + /* Write a normal profile string. If str was NULL, then key will be deleted */ + if (!WritePrivateProfileStringW(appName, keyName, str, filename)) + return FALSE; + + if (Is7BitClean(str)) + { + /* Delete ".A" version */ + lstrcpynW(szSection, appName, _countof(szSection) - 2); + lstrcatW(szSection, L".A"); + WritePrivateProfileStringW(szSection, keyName, NULL, filename); + + /* Delete ".W" version */ + lstrcpynW(szSection, appName, _countof(szSection) - 2); + lstrcatW(szSection, L".W"); + WritePrivateProfileStringW(szSection, keyName, NULL, filename); + + return TRUE; + } + + /* Now str is not 7-bit clean. It needs UTF-7 encoding in UTF-16. + We write ".A" and ".W"-appended sections. */ + + /* str --> szUtf7Buff */ + SHUnicodeToAnsiCP(CP_UTF7, str, szUtf7Buff, _countof(szUtf7Buff)); + szUtf7Buff[_countof(szUtf7Buff) - 1] = ANSI_NULL; + + /* szUtf7Buff --> szWideBuff */ + SHAnsiToUnicodeCP(CP_ACP, szUtf7Buff, szWideBuff, _countof(szWideBuff)); + szWideBuff[_countof(szWideBuff) - 1] = UNICODE_NULL; + + /* Write ".A" version */ + lstrcpynW(szSection, appName, _countof(szSection) - 2); + lstrcatW(szSection, L".A"); + if (!WritePrivateProfileStringW(szSection, keyName, str, filename)) + return FALSE; + + /* Write ".W" version */ + lstrcpynW(szSection, appName, _countof(szSection) - 2); + lstrcatW(szSection, L".W"); + if (!WritePrivateProfileStringW(szSection, keyName, szWideBuff, filename)) + return FALSE; + + return TRUE; +#else TRACE("(%s, %p, %s, %s)\n", debugstr_w(appName), keyName, debugstr_w(str), debugstr_w(filename)); return WritePrivateProfileStringW(appName, keyName, str, filename); +#endif } /************************************************************************* diff --git a/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp b/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp index 365c4478f19..2593cf66c6d 100644 --- a/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp +++ b/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp @@ -638,10 +638,60 @@ static void SHPropertyBag_OnRegKey(void) RegCloseKey(hKey); } +static void SHPropertyBag_SHSetIniStringW(void) +{ + WCHAR szIniFile[MAX_PATH]; + WCHAR szValue[MAX_PATH]; + BOOL bRet; + DWORD dwRet; + + ExpandEnvironmentStringsW(L"%TEMP%\\SHSetIniString.ini", szIniFile, _countof(szIniFile)); + + DeleteFileW(szIniFile); + + trace("%ls\n", szIniFile); + + bRet = SHSetIniStringW(L"TestSection", L"Key", L"Value", szIniFile); + ok_int(bRet, TRUE); + + WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); + + dwRet = SHGetIniStringW(L"TestSection", L"Key", szValue, _countof(szValue), szIniFile); + ok_long(dwRet, 5); + ok_wstr(szValue, L"Value"); + + bRet = SHSetIniStringW(L"TestSection", L"Key", NULL, szIniFile); + ok_int(bRet, TRUE); + + WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); + + dwRet = SHGetIniStringW(L"TestSection", L"Key", szValue, _countof(szValue), szIniFile); + ok_long(dwRet, 0); + ok_wstr(szValue, L""); + + bRet = SHSetIniStringW(L"TestSection", L"Key", L"ABC\x3042\x3044\x3046\x2665", szIniFile); + ok_int(bRet, TRUE); + + WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); + + dwRet = SHGetIniStringW(L"TestSection", L"Key", szValue, _countof(szValue), szIniFile); + ok_long(dwRet, 7); + ok_wstr(szValue, L"ABC\x3042\x3044\x3046\x2665"); + + szValue[0] = 0x3000; + szValue[1] = UNICODE_NULL; + dwRet = SHGetIniStringW(L"TestSection", L"NotExistentKey", szValue, _countof(szValue), szIniFile); + ok_long(dwRet, 0); + ok_wstr(szValue, L""); + + DeleteFileW(szIniFile); +} + START_TEST(SHPropertyBag) { SHPropertyBag_ReadTest(); SHPropertyBag_WriteTest(); SHPropertyBag_OnMemory(); SHPropertyBag_OnRegKey(); + SHPropertyBag_SHSetIniStringW(); } diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h index 29aae083047..a2677a639ce 100644 --- a/sdk/include/reactos/shlwapi_undoc.h +++ b/sdk/include/reactos/shlwapi_undoc.h @@ -179,6 +179,12 @@ HRESULT WINAPI SHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD si #define SHLoadRegUIString SHLoadRegUIStringA #endif +DWORD WINAPI +SHGetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPWSTR out, DWORD outLen, LPCWSTR filename); + +BOOL WINAPI +SHSetIniStringW(LPCWSTR appName, LPCWSTR keyName, LPCWSTR str, LPCWSTR filename); + int WINAPIV ShellMessageBoxWrapW(