Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2018
- 68 participants
- 1149 messages
Re: [PATCH vkd3d] libs/vkd3d: Use VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT only if array size is >= 6.
by Henri Verbeet
On 7 June 2018 at 15:52, Józef Kucia <joseph.kucia(a)gmail.com> wrote:
> + if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
> + && desc->Width == desc->Height && desc->DepthOrArraySize >= 6)
> image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
Should that be a multiple of 6? I.e., are partial cubemap arrays a
thing in Direct3D 12?
June 7, 2018
[PATCH vkd3d] libs/vkd3d: Use VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT only if array size is >= 6.
by Józef Kucia
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
libs/vkd3d/resource.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c
index acd3bada63ec..2ccb84797514 100644
--- a/libs/vkd3d/resource.c
+++ b/libs/vkd3d/resource.c
@@ -132,7 +132,8 @@ static HRESULT vkd3d_create_image(struct d3d12_resource *resource, struct d3d12_
image_info.flags = 0;
if (!(desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) && dxgi_format_is_typeless(desc->Format))
image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
- if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc->Width == desc->Height)
+ if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
+ && desc->Width == desc->Height && desc->DepthOrArraySize >= 6)
image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
image_info.imageType = vk_image_type_from_d3d12_resource_dimension(desc->Dimension);
--
2.16.4
June 7, 2018
Re: [PATCH v2 1/4] kernel32: Return BIOS info from GetSystemFirmwareTable on Linux
by Huw Davies
On Mon, May 28, 2018 at 10:05:26PM -0600, Alex Henrie wrote:
> /***********************************************************************
> * GetSystemFirmwareTable (KERNEL32.@)
> */
> UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD size)
> {
> - FIXME("(%d %d %p %d):stub\n", provider, id, buffer, size);
> + FIXME("(%08x %08x %p %d): semi-stub\n", provider, id, buffer, size);
This should probably be forwarded to
NtQuerySystemInformation(SystemFirmwareTableInformation, ...).
Huw.
June 7, 2018
Re: [PATCH] shellpath.c: Fix creation of HOME directory symbolic links
by Huw Davies
On Wed, Jun 06, 2018 at 08:46:49AM +0100, Rob Walker wrote:
> Fixes: https://bugs.winehq.org/show_bug.cgi?id=41668 (1)
> https://bugs.winehq.org/show_bug.cgi?id=28216 (2)
>
> (1) Introduces a "WINESYMLINK" env variable that allows a user to
> control what shell folder links are created to the HOME folder, when
> a WINEPREFIX is initially created.
> The Wineprefix Shell Folders, that Wine symlinks to the user's HOME directory,
> are only (re-)created on each Wine boot if they: do not pre-exist or are broken
> symbolic links.
>
> (2) The XDG Directory specification automatically falls back to the user HOME
> directory for any XDG_*_DIR that does not exist (xdg-user-dirs-update).
> The implemented solution is to block Wine from symlinking directly
> to HOME directory.
Hi Rob,
There's an awful lot going on in this patch which makes it very
difficult to review. Please avoid re-naming and re-indenting
existing functions so that we can actually see the real changes.
Then please split the changes into separate patches. A clue
that you're not doing this is that you have a list of two
items in the commit message. If the patch is doing two
things, it should be two patches.
Huw.
>
> Test on Gentoo GNU/Linux.
>
> Signed-off-by: Rob Walker <bob.mt.wya(a)gmail.com>
> ---
> dlls/shell32/shellpath.c | 554 ++++++++++++++++++++++++---------------
> 1 file changed, 343 insertions(+), 211 deletions(-)
>
> diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
> index a551e93aa8..b8c74273c6 100644
> --- a/dlls/shell32/shellpath.c
> +++ b/dlls/shell32/shellpath.c
> @@ -4326,252 +4326,259 @@ static HRESULT _SHRegisterCommonShellFolders(void)
> }
>
> /******************************************************************************
> - * _SHAppendToUnixPath [Internal]
> + * append_to_unix_path [Internal]
> *
> - * Helper function for _SHCreateSymbolicLinks. Appends pwszSubPath (or the
> - * corresponding resource, if IS_INTRESOURCE) to the unix base path 'szBasePath'
> - * and replaces backslashes with slashes.
> + * Helper function for create_home_subdir_symbolic_link.
> + * Appends 'subpath', or the corresponding resource (if it is a
> + * resource identifier), to the Unix base path 'base_dir'.
> + * Replace backslashes with forward slashes.
> *
> * PARAMS
> - * szBasePath [IO] The unix base path, which will be appended to (CP_UNXICP).
> - * pwszSubPath [I] Sub-path or resource id (use MAKEINTRESOURCEW).
> + * base_dir [IO] The Unix base path, which will be appended to (CP_UNXICP).
> + * subpath [I] Sub-path or resource id (use MAKEINTRESOURCEW, pre-call).
> *
> * RETURNS
> - * Success: TRUE,
> + * Success: TRUE
> * Failure: FALSE
> */
> -static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
> - WCHAR wszSubPath[MAX_PATH];
> - int cLen = strlen(szBasePath);
> - char *pBackslash;
> -
> - if (IS_INTRESOURCE(pwszSubPath)) {
> - if (!LoadStringW(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH)) {
> - /* Fall back to hard coded defaults. */
> - switch (LOWORD(pwszSubPath)) {
> - case IDS_PERSONAL:
> - lstrcpyW(wszSubPath, DocumentsW);
> - break;
> - case IDS_MYMUSIC:
> - lstrcpyW(wszSubPath, My_MusicW);
> - break;
> - case IDS_MYPICTURES:
> - lstrcpyW(wszSubPath, My_PicturesW);
> - break;
> - case IDS_MYVIDEOS:
> - lstrcpyW(wszSubPath, My_VideosW);
> - break;
> - default:
> - ERR("LoadString(%d) failed!\n", LOWORD(pwszSubPath));
> - return FALSE;
> - }
> +static inline BOOL append_to_unix_path(char *base_dir, LPCWSTR subpath)
> +{
> + WCHAR ws_subpath[MAX_PATH];
> + int cLen = strlen(base_dir);
> + char *back_slash;
> +
> + if (!IS_INTRESOURCE(subpath))
> + {
> + lstrcpyW(ws_subpath, subpath);
> + }
> + else if (!LoadStringW(shell32_hInstance, LOWORD(subpath), ws_subpath, MAX_PATH))
> + {
> + /* Fall back to hard coded defaults. */
> + switch (LOWORD(subpath)) {
> + case IDS_PERSONAL:
> + lstrcpyW(ws_subpath, DocumentsW);
> + break;
> + case IDS_MYMUSIC:
> + lstrcpyW(ws_subpath, My_MusicW);
> + break;
> + case IDS_MYPICTURES:
> + lstrcpyW(ws_subpath, My_PicturesW);
> + break;
> + case IDS_MYVIDEOS:
> + lstrcpyW(ws_subpath, My_VideosW);
> + break;
> + case IDS_DESKTOP:
> + lstrcpyW(ws_subpath, DesktopW);
> + break;
> + default:
> + ERR("LoadString(%d) failed!\n", LOWORD(subpath));
> + return FALSE;
> }
> - } else {
> - lstrcpyW(wszSubPath, pwszSubPath);
> }
> -
> - if (szBasePath[cLen-1] != '/') szBasePath[cLen++] = '/';
> -
> - if (!WideCharToMultiByte(CP_UNIXCP, 0, wszSubPath, -1, szBasePath + cLen,
> +
> + if (!cLen || (base_dir[cLen-1] != '/')) base_dir[cLen++] = '/';
> +
> + if (!WideCharToMultiByte(CP_UNIXCP, 0, ws_subpath, -1, base_dir + cLen,
> FILENAME_MAX - cLen, NULL, NULL))
> {
> return FALSE;
> }
> -
> - pBackslash = szBasePath + cLen;
> - while ((pBackslash = strchr(pBackslash, '\\'))) *pBackslash = '/';
> -
> +
> + back_slash = base_dir + cLen;
> + while ((back_slash = strchr(back_slash, '\\'))) *back_slash = '/';
> +
> return TRUE;
> }
>
> /******************************************************************************
> - * _SHCreateSymbolicLinks [Internal]
> + * compare_pathft_to_bootft [Internal]
> *
> - * Sets up symbol links for various shell folders to point into the users home
> - * directory. We do an educated guess about what the user would probably want:
> - * - If there is a 'My Documents' directory in $HOME, the user probably wants
> - * wine's 'My Documents' to point there. Furthermore, we imply that the user
> - * is a Windows lover and has no problem with wine creating 'My Pictures',
> - * 'My Music' and 'My Videos' subfolders under '$HOME/My Documents', if those
> - * do not already exits. We put appropriate symbolic links in place for those,
> - * too.
> - * - If there is no 'My Documents' directory in $HOME, we let 'My Documents'
> - * point directly to $HOME. We assume the user to be a unix hacker who does not
> - * want wine to create anything anywhere besides the .wine directory. So, if
> - * there already is a 'My Music' directory in $HOME, we symlink the 'My Music'
> - * shell folder to it. But if not, then we check XDG_MUSIC_DIR - "well known"
> - * directory, and try to link to that. If that fails, then we symlink to
> - * $HOME directly. The same holds fo 'My Pictures' and 'My Videos'.
> - * - The Desktop shell folder is symlinked to XDG_DESKTOP_DIR. If that does not
> - * exist, then we try '$HOME/Desktop'. If that does not exist, then we leave
> - * it alone.
> - * ('My Music',... above in fact means LoadString(IDS_MYMUSIC))
> + * Function to compare the FILETIME of ws_path (a Windows path) to the (estimated)
> + * Wine System boot time.
> + *
> + * PARAMS
> + * ws_path [I] The Windows path, for which provides the FS write time.
> + * time_difference [O] -1 Windows path last written before time of Wine boot.
> + * 0 Windows path last written at time of Wine boot.
> + * +1 Windows path last written after time of Wine boot.
> + * RETURNS
> + * Success: S_OK
> + * Failure: E_FAIL
> + *
> + * NOTES
> + * Pre-allocate storage for time_difference pointer variable externally.
> */
> -static void _SHCreateSymbolicLinks(void)
> -{
> - UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEOS, IDS_MYMUSIC }, i;
> - const WCHAR* MyOSXStuffW[] = { PicturesW, MoviesW, MusicW };
> - int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC };
> - static const char * const xdg_dirs[] = { "PICTURES", "VIDEOS", "MUSIC", "DOCUMENTS", "DESKTOP" };
> - static const unsigned int num = ARRAY_SIZE(xdg_dirs);
> - WCHAR wszTempPath[MAX_PATH];
> - char szPersonalTarget[FILENAME_MAX], *pszPersonal;
> - char szMyStuffTarget[FILENAME_MAX], *pszMyStuff;
> - char szDesktopTarget[FILENAME_MAX], *pszDesktop;
> - struct stat statFolder;
> - const char *pszHome;
> - HRESULT hr;
> - char ** xdg_results;
> - char * xdg_desktop_dir;
> -
> - /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */
> - hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL,
> - SHGFP_TYPE_DEFAULT, wszTempPath);
> - if (FAILED(hr)) return;
> - pszPersonal = wine_get_unix_file_name(wszTempPath);
> - if (!pszPersonal) return;
> +static HRESULT compare_pathft_to_bootft(const WCHAR * ws_path, int * time_difference)
> +{
> + static ULONG64 time_system_start = 0;
> + SYSTEMTIME system_time_st;
> + FILETIME dummy_ft, system_time_ft, last_write_ft;
> + ULONG64 tick_count, time_last_write;
> + HANDLE fhandle;
> + DWORD ft_errorc = 0;
>
> - hr = XDG_UserDirLookup(xdg_dirs, num, &xdg_results);
> - if (FAILED(hr)) xdg_results = NULL;
> + if (!time_difference) return E_FAIL;
>
> - pszHome = getenv("HOME");
> - if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode))
> + if (!time_system_start)
> {
> - while (1)
> + tick_count = (ULONG64) GetTickCount64();
> + GetSystemTime(&system_time_st);
> + if (!SystemTimeToFileTime( &system_time_st, &system_time_ft))
> {
> - /* Check if there's already a Wine-specific 'My Documents' folder */
> - strcpy(szPersonalTarget, pszHome);
> - if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) &&
> - !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
> - {
> - /* '$HOME/My Documents' exists. Create 'My Pictures',
> - * 'My Videos' and 'My Music' subfolders or fail silently if
> - * they already exist.
> - */
> - for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++)
> - {
> - strcpy(szMyStuffTarget, szPersonalTarget);
> - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])))
> - mkdir(szMyStuffTarget, 0777);
> - }
> - break;
> - }
> -
> - /* Try to point to the XDG Documents folder */
> - if (xdg_results && xdg_results[num-2] &&
> - !stat(xdg_results[num-2], &statFolder) &&
> - S_ISDIR(statFolder.st_mode))
> - {
> - strcpy(szPersonalTarget, xdg_results[num-2]);
> - break;
> - }
> -
> - /* Or the hardcoded / OS X Documents folder */
> - strcpy(szPersonalTarget, pszHome);
> - if (_SHAppendToUnixPath(szPersonalTarget, DocumentsW) &&
> - !stat(szPersonalTarget, &statFolder) &&
> - S_ISDIR(statFolder.st_mode))
> - break;
> -
> - /* As a last resort point to $HOME. */
> - strcpy(szPersonalTarget, pszHome);
> - break;
> + ERR("SystemTimeToFileTime call failed (%d)\n", GetLastError());
> + return E_FAIL;
> }
> -
> - /* Replace 'My Documents' directory with a symlink or fail silently if not empty. */
> - remove(pszPersonal);
> - symlink(szPersonalTarget, pszPersonal);
> + time_system_start = (((ULONG64)system_time_ft.dwHighDateTime) << 32)
> + + system_time_ft.dwLowDateTime
> + - (tick_count * 10000);
> }
> - else
> + fhandle = CreateFileW( ws_path, 0, FILE_SHARE_READ, NULL,
> + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
> + if (fhandle == INVALID_HANDLE_VALUE)
> {
> - /* '$HOME' doesn't exist. Create 'My Pictures', 'My Videos' and 'My Music' subdirs
> - * in '%USERPROFILE%\\My Documents' or fail silently if they already exist. */
> - pszHome = NULL;
> - strcpy(szPersonalTarget, pszPersonal);
> - for (i = 0; i < ARRAY_SIZE(aidsMyStuff); i++) {
> - strcpy(szMyStuffTarget, szPersonalTarget);
> - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])))
> - mkdir(szMyStuffTarget, 0777);
> - }
> + ERR("Open file handle failed for path: %s (%d)\n",
> + debugstr_w(ws_path), GetLastError());
> + return E_FAIL;
> }
> -
> - /* Create symbolic links for 'My Pictures', 'My Videos' and 'My Music'. */
> - for (i=0; i < ARRAY_SIZE(aidsMyStuff); i++)
> + if (!GetFileTime(fhandle, &dummy_ft, &dummy_ft, &last_write_ft))
> + ft_errorc = GetLastError();
> + if (!CloseHandle(fhandle))
> {
> - /* Create the current 'My Whatever' folder and get its unix path. */
> - hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_CREATE, NULL,
> - SHGFP_TYPE_DEFAULT, wszTempPath);
> - if (FAILED(hr)) continue;
> -
> - pszMyStuff = wine_get_unix_file_name(wszTempPath);
> - if (!pszMyStuff) continue;
> -
> - while (1)
> - {
> - /* Check for the Wine-specific '$HOME/My Documents' subfolder */
> - strcpy(szMyStuffTarget, szPersonalTarget);
> - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])) &&
> - !stat(szMyStuffTarget, &statFolder) && S_ISDIR(statFolder.st_mode))
> - break;
> + ERR("Close file handle failed: %p (%d)\n",
> + fhandle, GetLastError());
> + return E_FAIL;
> + }
> + if (ft_errorc)
> + {
> + ERR("Get file time failed: %p (%d)\n",
> + fhandle, ft_errorc);
> + return E_FAIL;
> + }
> + time_last_write = (((ULONG64)last_write_ft.dwHighDateTime) << 32)
> + + last_write_ft.dwLowDateTime;
> + *time_difference = ((time_last_write > time_system_start) ? 1 :
> + ((time_last_write < time_system_start) ? -1 :
> + 0));
>
> - /* Try the XDG_XXX_DIR folder */
> - if (xdg_results && xdg_results[i])
> - {
> - strcpy(szMyStuffTarget, xdg_results[i]);
> - break;
> - }
> + return S_OK;
> +}
>
> - /* Or the OS X folder (these are never localized) */
> - if (pszHome)
> - {
> - strcpy(szMyStuffTarget, pszHome);
> - if (_SHAppendToUnixPath(szMyStuffTarget, MyOSXStuffW[i]) &&
> - !stat(szMyStuffTarget, &statFolder) &&
> - S_ISDIR(statFolder.st_mode))
> - break;
> - }
> +/******************************************************************************
> + * create_homedir_symbolic_link [Internal]
> + *
> + * Creates a symbolic link from the current Wineprefix to an appropriate
> + * HOME subdirectory (if one is found).
> + *
> + * Creates 'XXXX' directory in Wineprefix.
> + * Then create a 'My XXXX' symbolic link in Wineprefix:
> + * 1) If '$HOME/XXXX' (IDS directory) exists then target this.
> + * 2) If '$HOME/XXXX' (XDG_XXXX_DIR) exists then target this.
> + * 3) If '$HOME/XXXX' (MacOS XXXX media directory) exists then target this.
> + *
> + * PARAMS
> + * env_enabled [I]
> + * TRUE The user has enabled this Shell Folder to be symlinked (default).
> + * FALSE The user has chosen to disable symlinking this Shell Folder.
> + * The Shell Folder will be created, in the current Wineprefix (if not pre-existing).
> + * ids_dir [I] Windows Resource Identifier code for current Shell Folder.
> + * csidl_dir [I] Constant Special Item ID List identifier for current Shell Folder.
> + * xdg_dir [I] Full path of external Unix XDG directory corresponding to current Shell Folder.
> + * ws_osx_dir [I] Fallback directory name to use, corresponding to current Shell Folder (OSX specific).
> + *
> + */
> +void create_homedir_symbolic_link(BOOL env_enabled,
> + UINT ids_dir,
> + int csidl_dir,
> + const char * xdg_dir,
> + const WCHAR * ws_osx_dir)
> +{
> + static const char * env_homedir = NULL;
> + WCHAR ws_temp_path[MAX_PATH];
> + char home_target[FILENAME_MAX], * prefix_dir;
> + struct stat stat_folder, stat_home_folder;
> + HRESULT hr;
> + BOOL target_ok;
> + int time_difference;
>
> - /* As a last resort point to the same location as 'My Documents' */
> - strcpy(szMyStuffTarget, szPersonalTarget);
> - break;
> + hr = SHGetFolderPathW(NULL, csidl_dir, NULL,
> + SHGFP_TYPE_DEFAULT, ws_temp_path);
> + if (SUCCEEDED(hr))
> + {
> + if (ids_dir != IDS_DESKTOPDIRECTORY) return;
> +
> + if ((compare_pathft_to_bootft(ws_temp_path, &time_difference) == S_OK)
> + && (time_difference < 0))
> + {
> + TRACE("%s directory created before wineboot\n",
> + debugstr_w(ws_temp_path));
> + return;
> }
> - remove(pszMyStuff);
> - symlink(szMyStuffTarget, pszMyStuff);
> - heap_free(pszMyStuff);
> }
> -
> - /* Last but not least, the Desktop folder */
> - if (pszHome)
> - strcpy(szDesktopTarget, pszHome);
> + else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
> + {
> + hr = SHGetFolderPathW(NULL, csidl_dir|CSIDL_FLAG_CREATE, NULL,
> + SHGFP_TYPE_DEFAULT, ws_temp_path);
> + if (FAILED(hr)) return;
> + }
> else
> - strcpy(szDesktopTarget, pszPersonal);
> - heap_free(pszPersonal);
> + {
> + ERR("Failed to get Wineprefix path corresponding to %d CSIDL\n",
> + csidl_dir);
> + return;
> + }
> + if (!env_enabled) return;
> + prefix_dir = wine_get_unix_file_name(ws_temp_path);
> + if (!prefix_dir)
> + {
> + ERR("Failed to get Unix Wineprefix directory for: %s\n",
> + debugstr_w(ws_temp_path));
> + return;
> + }
> + if (!env_homedir) env_homedir = getenv("HOME");
> + if (!(env_homedir
> + && (stat(env_homedir, &stat_home_folder) != 1)
> + && S_ISDIR(stat_home_folder.st_mode)))
> + {
> + if (prefix_dir) heap_free(prefix_dir);
> + return;
> + }
>
> - xdg_desktop_dir = xdg_results ? xdg_results[num - 1] : NULL;
> - if (xdg_desktop_dir ||
> - (_SHAppendToUnixPath(szDesktopTarget, DesktopW) &&
> - !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode)))
> + /* Check for:
> + * '$HOME/XXXX' (IDS directory)
> + * or '$HOME/XXXX' (XDG directory)
> + * or '$HOME/XXXX' (MacOS directory)
> + */
> + target_ok = FALSE;
> + strcpy(home_target, env_homedir);
> + if (append_to_unix_path(home_target, MAKEINTRESOURCEW(ids_dir))
> + && (stat(home_target, &stat_folder) != -1)
> + && S_ISDIR(stat_folder.st_mode))
> {
> - hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, NULL,
> - SHGFP_TYPE_DEFAULT, wszTempPath);
> - if (SUCCEEDED(hr) && (pszDesktop = wine_get_unix_file_name(wszTempPath)))
> - {
> - remove(pszDesktop);
> - if (xdg_desktop_dir)
> - symlink(xdg_desktop_dir, pszDesktop);
> - else
> - symlink(szDesktopTarget, pszDesktop);
> - heap_free(pszDesktop);
> - }
> + target_ok = TRUE;
> + }
> + else if (xdg_dir && stat(xdg_dir, &stat_folder))
> + {
> + strcpy(home_target, xdg_dir);
> + /* Only link to the XDG directory, if it does not point directly
> + * to the user's HOME directory (XDG specification fallback path). */
> + target_ok = (stat_folder.st_ino != stat_home_folder.st_ino);
> + }
> + else
> + {
> + strcpy(home_target, env_homedir);
> + target_ok = append_to_unix_path(home_target, ws_osx_dir)
> + && (stat(home_target, &stat_folder) != -1)
> + && S_ISDIR(stat_folder.st_mode);
> }
>
> - /* Free resources allocated by XDG_UserDirLookup() */
> - if (xdg_results)
> + if (target_ok)
> {
> - for (i = 0; i < num; i++)
> - heap_free(xdg_results[i]);
> - heap_free(xdg_results);
> + remove(prefix_dir);
> + symlink(home_target, prefix_dir);
> }
> +
> +
> + if (prefix_dir) heap_free(prefix_dir);
> }
>
> /******************************************************************************
> @@ -6126,15 +6133,139 @@ static void register_system_knownfolders(void)
> }
> }
>
> +/******************************************************************************
> + * parse_symlinks_env_variable [Internal]
> + *
> + * PARAMS
> + * xdg_dir [I] Unix XDG directory name (without "XDG_" prefix and "_DIR" suffix).
> + *
> + * RETURNS
> + * TRUE "WINESYMLINK" contains the specified XDG directory string.
> + * FALSE "WINESYMLINK" does not contain the specified XDG directory string.
> + * Any error condition.
> + *
> + * Note: "WINESYMLINK", defaults to "ALL", when unset. This enables all symlinks.
> + * "WINESYMLINK" can also be manually set to "ALL", enabling all symlinks.
> + *
> + */
> +static BOOL parse_symlinks_env_variable(const char * xdg_dir)
> +{
> + static const char * matchall_env_var = "ALL";
> + static char env_var[MAX_PATH+1];
> + static char * env_winesymlink = NULL;
> + char * sstr, * sstr_stop, * tstr, * word_start = NULL;
> + char seperator_ch = '\0';
> + BOOL end_string, in_word = FALSE, matched = FALSE;
> + size_t slength = 0, matchall_length, xdg_dir_slength;
> +
> + if (!xdg_dir) return matched;
> +
> + if (!env_winesymlink)
> + {
> + env_winesymlink = getenv("WINESYMLINK");
> + if (!env_winesymlink) env_winesymlink = (char*) matchall_env_var;
> + tstr = env_var;
> + sstr_stop = env_winesymlink + MAX_PATH;
> + for (sstr = env_winesymlink; *sstr && (sstr != sstr_stop); ++sstr)
> + {
> + if (!seperator_ch && (ispunct(*sstr) || isspace(*sstr)))
> + seperator_ch = *sstr;
> + if (!isalpha(*sstr)) continue;
> +
> + if (seperator_ch && in_word)
> + {
> + *tstr++ = seperator_ch;
> + ++slength;
> + }
> + in_word = TRUE;
> + seperator_ch = '\0';
> + *tstr++ = toupper(*sstr);
> + ++slength;
> + }
> + env_var[slength] = '\0';
> + }
> +
> + TRACE("processed env variable: %s\n", debugstr_a(&env_var[0]));
> + matchall_length = strlen(matchall_env_var);
> + xdg_dir_slength = strlen(xdg_dir);
> + end_string = !(env_var[0]);
> + for (sstr = &env_var[0]; !end_string; ++sstr)
> + {
> + end_string = !(*(sstr+1));
> + in_word = isalpha(*sstr);
> + if (in_word && !word_start) word_start = sstr;
> + in_word = in_word && !end_string;
> + if (in_word || !word_start) continue;
> +
> + slength = ((size_t) (sstr-word_start))+(end_string ? 1 : 0);
> + matched = ( (slength == xdg_dir_slength) && (strncmp(word_start, xdg_dir, slength) == 0) )
> + || ( (slength == matchall_length) && (strncmp(word_start, "ALL", slength) == 0) );
> + if (matched) break;
> +
> + word_start = NULL;
> + }
> + TRACE("%s symlinking for %s\n", matched ? "Enabled" : "Disabled", debugstr_a(xdg_dir));
> +
> + return matched;
> +}
> +
> +/******************************************************************************
> + * create_homedir_symbolic_links [Internal]
> + *
> + * Parse WINESYMLINK env variable, for each XDG directory argument. To test if symlinking is
> + * enabled for that XDG directory / Wine Profile Folder.
> + * Then calls the function create_homedir_symbolic_link to potentially symlink from a Shell Folder,
> + * in the current Wineprefix, to a subdirectory of the current user's HOME directory.
> + *
> + * PARAMS
> + * xdg_dirnames [I] Pointer to an array of Unix XDG directory names
> + * (without "XDG_" prefix and "_DIR" suffix).
> + * xdg_dir_count [I] Item count of array (above).
> + *
> + */
> +static void create_homedir_symbolic_links(const char * const xdg_dirnames[], const UINT xdg_dir_count)
> +{
> + char ** xdg_dirs_array;
> + char * xdg_dir;
> + HRESULT hr;
> + UINT i;
> + BOOL env_enabled;
> +
> + if (!xdg_dirnames) return;
> +
> + hr = XDG_UserDirLookup(xdg_dirnames, xdg_dir_count, &xdg_dirs_array);
> + if (FAILED(hr)) xdg_dirs_array = NULL;
> +
> + for (i = 0; i < xdg_dir_count; ++i)
> + {
> + env_enabled = parse_symlinks_env_variable(xdg_dirnames[i]);
> + xdg_dir = xdg_dirs_array ? xdg_dirs_array[i] : NULL;
> + if (!strcmp(xdg_dirnames[i],"DOCUMENTS"))
> + create_homedir_symbolic_link(env_enabled, IDS_PERSONAL, CSIDL_PERSONAL, xdg_dir, DocumentsW);
> + else if (!strcmp(xdg_dirnames[i],"PICTURES"))
> + create_homedir_symbolic_link(env_enabled, IDS_MYPICTURES, CSIDL_MYPICTURES, xdg_dir, PicturesW);
> + else if (!strcmp(xdg_dirnames[i],"VIDEOS"))
> + create_homedir_symbolic_link(env_enabled, IDS_MYVIDEOS, CSIDL_MYVIDEO, xdg_dir, MoviesW);
> + else if (!strcmp(xdg_dirnames[i],"MUSIC"))
> + create_homedir_symbolic_link(env_enabled, IDS_MYMUSIC, CSIDL_MYMUSIC, xdg_dir, MusicW);
> + else if (!strcmp(xdg_dirnames[i],"DESKTOP"))
> + create_homedir_symbolic_link(env_enabled, IDS_DESKTOPDIRECTORY, CSIDL_DESKTOPDIRECTORY, xdg_dir, DesktopW);
> + else
> + ERR("XDG directory name specifier invalid: %s\n", debugstr_a(xdg_dirnames[i]));
> + if (xdg_dir) heap_free(xdg_dirs_array[i]);
> + }
> + if (xdg_dirs_array) heap_free(xdg_dirs_array);
> +}
> +
> HRESULT SHELL_RegisterShellFolders(void)
> {
> + static const char * const xdg_dirnames[] = { "DOCUMENTS", "PICTURES", "VIDEOS", "MUSIC", "DESKTOP" };
> + const UINT xdg_dir_count = 5;
> HRESULT hr;
>
> - /* Set up '$HOME' targeted symlinks for 'My Documents', 'My Pictures',
> - * 'My Videos', 'My Music' and 'Desktop' in advance, so that the
> - * _SHRegister*ShellFolders() functions will find everything nice and clean
> - * and thus will not attempt to create them in the profile directory. */
> - _SHCreateSymbolicLinks();
> + /* Early setup of symlinks from specific User Shell Folders, in
> + * current Wineprefix, to subdirecties of the user's HOME directory. */
> + create_homedir_symbolic_links(xdg_dirnames, xdg_dir_count);
>
> hr = _SHRegisterUserShellFolders(TRUE);
> if (SUCCEEDED(hr))
> @@ -6147,5 +6278,6 @@ HRESULT SHELL_RegisterShellFolders(void)
> hr = set_folder_attributes();
> if (SUCCEEDED(hr))
> register_system_knownfolders();
> +
> return hr;
> }
> --
> 2.17.1
>
>
>
June 7, 2018
Re: [PATCH] ntoskrnl: Have MmIsAddressValid use IsBadReadPtr.
by Thomas Faber
On 2018-06-06 17:11, Derek Lesho wrote:
> Hi Thomas, in your example, does &Base refer to the base of
> ntoskrnl.exe? If so, why are you allocating a buffer there, wouldn't
> that corrupt the memory of ntoskrnl, or am I misunderstanding what
> your code is doing. On windows, do drivers have access to change the
> memory of ntoskrnl?
My intention was to simply make a user mode memory allocation, so there
should be a "Base = NULL;" before the call to ZwAllocateVirtualMemory.
This function cannot allocate kernel address space (or overwrite loaded
modules), so it wouldn't do anything unexpected. I was just suggesting
it to demonstrate behavior with NOACCESS/READONLY/READWRITE pages.
As for your actual use case, I'd assume ntoskrnl's code is most likely
write-protected on Windows as well, much like you encountered on Wine,
but I haven't verified.
Since your patch was committed I don't know if you're still interested
in adding the test. If you are, I'd suggest to go with the simpler
second version, since like I said the "full test" won't be very useful
in Wine.
> On Wed, Jun 6, 2018 at 3:51 AM, Thomas Faber <thomas.faber(a)reactos.org> wrote:
>> void test_function()
>> {
>> ok(MmIsAddressValid((void*)test_function), ...); // fails in master, succeeds with patch?
>> ptr = ExAllocatePoolWithTag(NonPagedPool, ...)
>> ok(MmIsAddressValid(ptr), ...);
>> ExFreePoolWithTag...
>> ok(!MmIsAddressValid(NULL), ...);
>> }
Perhaps also
ok(MmIsAddressValid((void*)MmIsAddressValid), ...);
to specifically test ntoskrnl instead of the test driver's binary.
-Thomas
June 7, 2018
Re: [PATCH 3/4 v5] riched20: Support external HDC in ME_WrapMarkedParagraphs().
by Huw Davies
On Wed, Jun 06, 2018 at 05:24:31PM +0800, Jactry Zeng wrote:
> Superseded patch 146572.
>
> Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
> ---
> dlls/riched20/editor.c | 13 +++++++------
> dlls/riched20/editor.h | 2 +-
> dlls/riched20/editstr.h | 1 +
> dlls/riched20/paint.c | 10 +++++-----
> dlls/riched20/table.c | 4 ++--
> dlls/riched20/wrap.c | 11 +++++++++--
> 6 files changed, 25 insertions(+), 16 deletions(-)
>
> diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
> index 820b0380c7..82132761f0 100644
> --- a/dlls/riched20/editor.c
> +++ b/dlls/riched20/editor.c
> @@ -3028,6 +3028,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
>
> ed->hWnd = NULL;
> ed->hwndParent = NULL;
> + ed->hdcDraw = NULL;
> ed->sizeWindow.cx = ed->sizeWindow.cy = 0;
> ed->texthost = texthost;
> ed->reOle = NULL;
> @@ -3494,7 +3495,7 @@ static LRESULT ME_WmCreate(ME_TextEditor *editor, LPARAM lParam, BOOL unicode)
> }
>
> ME_CommitUndo(editor);
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_MoveCaret(editor);
> return 0;
> }
> @@ -3645,7 +3646,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
> cf.yHeight = size * 20; /* convert twips to points */
> ME_SetSelectionCharFormat(editor, &cf);
> ME_CommitUndo(editor);
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_UpdateScrollBar(editor);
> ME_Repaint(editor);
>
> @@ -3934,7 +3935,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
> ME_CommitUndo(editor);
> if (bRepaint)
> {
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_UpdateScrollBar(editor);
> ME_Repaint(editor);
> }
> @@ -3959,7 +3960,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
> case EM_SETPARAFORMAT:
> {
> BOOL result = ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_UpdateScrollBar(editor);
> ME_Repaint(editor);
> ME_CommitUndo(editor);
> @@ -4054,7 +4055,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
>
> ME_CommitUndo(editor);
> ME_MarkAllForWrapping(editor);
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_UpdateScrollBar(editor);
> if (bRepaint)
> ME_Repaint(editor);
> @@ -4714,7 +4715,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
> editor->bDefaultFormatRect = TRUE;
> }
> ME_MarkAllForWrapping(editor);
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_UpdateScrollBar(editor);
> if (msg != EM_SETRECTNP)
> ME_Repaint(editor);
> diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h
> index 0f0e56ecd1..425a34f0c2 100644
> --- a/dlls/riched20/editor.h
> +++ b/dlls/riched20/editor.h
> @@ -182,7 +182,7 @@ void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC) DECLSPEC_HIDD
> void ME_DestroyContext(ME_Context *c) DECLSPEC_HIDDEN;
>
> /* wrap.c */
> -BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) DECLSPEC_HIDDEN;
> +BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor, HDC hdc) DECLSPEC_HIDDEN;
> void ME_InvalidateParagraphRange(ME_TextEditor *editor, ME_DisplayItem *start_para, ME_DisplayItem *last_para) DECLSPEC_HIDDEN;
> void ME_SendRequestResize(ME_TextEditor *editor, BOOL force) DECLSPEC_HIDDEN;
>
> diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
> index 206ce85287..1d811e1c2a 100644
> --- a/dlls/riched20/editstr.h
> +++ b/dlls/riched20/editstr.h
> @@ -383,6 +383,7 @@ typedef struct tagME_InStream ME_InStream;
> typedef struct tagME_TextEditor
> {
> HWND hWnd, hwndParent;
> + HDC hdcDraw;
> ITextHost *texthost;
> IRichEditOle *reOle;
> BOOL bEmulateVersion10;
> diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c
> index fcc4e105a3..f2429081fc 100644
> --- a/dlls/riched20/paint.c
> +++ b/dlls/riched20/paint.c
> @@ -105,7 +105,7 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, const RECT *rcUpdate)
>
> void ME_Repaint(ME_TextEditor *editor)
> {
> - if (ME_WrapMarkedParagraphs(editor))
> + if (ME_WrapMarkedParagraphs(editor, NULL))
> {
> ME_UpdateScrollBar(editor);
> FIXME("ME_Repaint had to call ME_WrapMarkedParagraphs\n");
> @@ -118,7 +118,7 @@ void ME_UpdateRepaint(ME_TextEditor *editor, BOOL update_now)
> /* Should be called whenever the contents of the control have changed */
> BOOL wrappedParagraphs;
>
> - wrappedParagraphs = ME_WrapMarkedParagraphs(editor);
> + wrappedParagraphs = ME_WrapMarkedParagraphs(editor, NULL);
> if (wrappedParagraphs)
> ME_UpdateScrollBar(editor);
>
> @@ -145,7 +145,7 @@ ME_RewrapRepaint(ME_TextEditor *editor)
> * looks, but not content. Like resizing. */
>
> ME_MarkAllForWrapping(editor);
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_UpdateScrollBar(editor);
> ME_Repaint(editor);
> }
> @@ -1163,7 +1163,7 @@ void ME_UpdateScrollBar(ME_TextEditor *editor)
> SCROLLINFO si;
> BOOL bScrollBarWasVisible, bScrollBarWillBeVisible;
>
> - if (ME_WrapMarkedParagraphs(editor))
> + if (ME_WrapMarkedParagraphs(editor, NULL))
> FIXME("ME_UpdateScrollBar had to call ME_WrapMarkedParagraphs\n");
>
> si.cbSize = sizeof(si);
> @@ -1336,7 +1336,7 @@ ME_InvalidateSelection(ME_TextEditor *editor)
> there's no (inverted) area to be repainted, neither old nor new */
> if (nStart == nEnd && editor->nLastSelStart == editor->nLastSelEnd)
> return;
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> ME_GetSelectionParas(editor, &sel_start, &sel_end);
> assert(sel_start->type == diParagraph);
> assert(sel_end->type == diParagraph);
> diff --git a/dlls/riched20/table.c b/dlls/riched20/table.c
> index 4cd77eb399..5457935dfa 100644
> --- a/dlls/riched20/table.c
> +++ b/dlls/riched20/table.c
> @@ -499,7 +499,7 @@ static void ME_SelectOrInsertNextCell(ME_TextEditor *editor,
> editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
> editor->pCursors[0].nOffset = 0;
> editor->pCursors[1] = editor->pCursors[0];
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> return;
> }
> }
> @@ -544,7 +544,7 @@ static void ME_SelectOrInsertNextCell(ME_TextEditor *editor,
> editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
> editor->pCursors[0].nOffset = 0;
> editor->pCursors[1] = editor->pCursors[0];
> - ME_WrapMarkedParagraphs(editor);
> + ME_WrapMarkedParagraphs(editor, NULL);
> return;
> }
> }
> diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c
> index e3a70f07d1..4c92252547 100644
> --- a/dlls/riched20/wrap.c
> +++ b/dlls/riched20/wrap.c
> @@ -980,14 +980,21 @@ static void ME_MarkRepaintEnd(ME_DisplayItem *para,
> *repaint_end = para;
> }
>
> -BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor)
> +BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor, HDC hdc)
> {
> ME_DisplayItem *item;
> ME_Context c;
> int totalWidth = 0;
> ME_DisplayItem *repaint_start = NULL, *repaint_end = NULL;
>
> - ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
> + if (!hdc)
> + hdc = ITextHost_TxGetDC(editor->texthost);
> + if (hdc != editor->hdcDraw)
> + {
> + ME_MarkAllForWrapping(editor);
> + editor->hdcDraw = hdc;
> + }
> + ME_InitContext(&c, editor, hdc);
> c.pt.x = 0;
> item = editor->pBuffer->pFirst->next;
> while(item != editor->pBuffer->pLast) {
Unfortunately it's more complicated than this because
the styles cache font metrics and uniscribe data. These
will need to be recalculated for a new hdc.
We'll probably also want to re-think how the windowed and window-less
controls handle hdcs in general.
Huw.
June 7, 2018
Re: [PATCH 1/4 v5] riched20/tests: Rewrite tests for ITextServices_TxGetNaturalSize().
by Huw Davies
On Thu, Jun 07, 2018 at 05:21:25PM +0800, Jactry Zeng wrote:
> Huw Davies <huw(a)codeweavers.com> 于2018年6月7日周四 下午4:54写道:
> >
> > On Wed, Jun 06, 2018 at 05:24:13PM +0800, Jactry Zeng wrote:
> > > Superseded patch 146570.
> > >
>
> > > + LONG expected_width, expected_height;
> > > +
> > > + GetClientRect(WindowFromDC(hdc), &rect);
> > > + DrawTextW(hdc, string, -1, &rect, DT_LEFT | DT_CALCRECT | DT_NOCLIP | DT_EDITCONTROL | DT_WORDBREAK);
> >
> > Why can't you use GetTextExtentPointW() here? This would avoid the
> > GetClientRect() call too.
> >
>
> In 0003 there are some tests about multiline support. It seems that
> using DrawText can make it more simple or we will need to compute
> a max width of it by ourselves.
Ok, then please pass the client rect to CHECK_TXGETNATURALSIZE so that
it doesn't need to be queried from there.
Also, this patch series seems out-of-order. Perhaps move 0001 after
0002 and 0003 (or put 0004 before 0002 and 0003).
Huw.
June 7, 2018
Re: [PATCH 2/4 v5] riched20: Call ITextHost_TxGetCharFormat() for setting default charformat.
by Huw Davies
On Wed, Jun 06, 2018 at 05:24:22PM +0800, Jactry Zeng wrote:
> Superseded patch 146571.
>
> ChangeLog:
> v5:
> - Remove an unnecessary newline.
>
> Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
> ---
> dlls/riched20/para.c | 5 ++++
> dlls/riched20/tests/txtsrv.c | 58 +++++++++++++++++++++++++++++++++++-
> 2 files changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/dlls/riched20/para.c b/dlls/riched20/para.c
> index f2a70e5746..ffb017c123 100644
> --- a/dlls/riched20/para.c
> +++ b/dlls/riched20/para.c
> @@ -36,6 +36,7 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor)
> {
> ME_Context c;
> CHARFORMAT2W cf;
> + const CHARFORMATW *host_cf;
> LOGFONTW lf;
> HFONT hf;
> ME_TextBuffer *text = editor->pBuffer;
> @@ -44,6 +45,7 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor)
> ME_Style *style;
> int eol_len;
> WCHAR cr_lf[] = {'\r','\n',0};
> + HRESULT hr;
>
> ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
>
> @@ -73,6 +75,9 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor)
> cf.bCharSet = lf.lfCharSet;
> cf.lcid = GetSystemDefaultLCID();
>
> + hr = ITextHost_TxGetCharFormat(editor->texthost, (const CHARFORMATW **)&host_cf);
> + if (hr == S_OK && (host_cf->cbSize >= sizeof(CHARFORMATW)))
> + ME_ToCF2W(&cf, (CHARFORMAT2W *)host_cf);
Hmm, you need to use the return value of ME_ToCF2W() is this case.
However, ME_ToCF2W() and ME_ToCFAny() should be cleaned up. They
should both do the copy even if the from argument is of the
correct type (basically what ME_CopyToCFAny() does).
Something like:
BOOL cfany_to_cf2w(CHARFORMAT2W *dst, const *CHARFORMAT2W *src);
BOOL cf2w_to_cfany(CHARFORMAT2W *dst, const *CHARFORMAT2W *src);
> style = ME_MakeStyle(&cf);
> text->pDefaultStyle = style;
>
> diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c
> index 6e61392dc5..ac06aa868e 100644
> --- a/dlls/riched20/tests/txtsrv.c
> +++ b/dlls/riched20/tests/txtsrv.c
> @@ -85,6 +85,7 @@ typedef struct ITextHostTestImpl
> {
> ITextHost ITextHost_iface;
> LONG refCount;
> + CHARFORMATW char_format;
> } ITextHostTestImpl;
>
> static inline ITextHostTestImpl *impl_from_ITextHost(ITextHost *iface)
> @@ -330,7 +331,8 @@ static HRESULT WINAPI ITextHostImpl_TxGetCharFormat(ITextHost *iface,
> {
> ITextHostTestImpl *This = impl_from_ITextHost(iface);
> TRACECALL("Call to TxGetCharFormat(%p, ppCF=%p)\n", This, ppCF);
> - return E_NOTIMPL;
> + *ppCF = &This->char_format;
> + return S_OK;
> }
>
> static HRESULT WINAPI ITextHostImpl_TxGetParaFormat(ITextHost *iface,
> @@ -609,6 +611,8 @@ static BOOL init_texthost(ITextServices **txtserv, ITextHost **ret)
> ITextHostTestImpl *dummyTextHost;
> IUnknown *init;
> HRESULT result;
> + LOGFONTW lf;
> + HFONT hf;
>
> dummyTextHost = CoTaskMemAlloc(sizeof(*dummyTextHost));
> if (dummyTextHost == NULL) {
> @@ -617,6 +621,19 @@ static BOOL init_texthost(ITextServices **txtserv, ITextHost **ret)
> }
> dummyTextHost->ITextHost_iface.lpVtbl = &itextHostVtbl;
> dummyTextHost->refCount = 1;
> + memset(&dummyTextHost->char_format, 0, sizeof(dummyTextHost->char_format));
> + dummyTextHost->char_format.cbSize = sizeof(dummyTextHost->char_format);
> + dummyTextHost->char_format.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT;
> + hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
No cast.
> + GetObjectW(hf, sizeof(LOGFONTW), &lf);
> + lstrcpyW(dummyTextHost->char_format.szFaceName, lf.lfFaceName);
> + dummyTextHost->char_format.yHeight = MulDiv(abs(lf.lfHeight), 1440, GetDeviceCaps(GetDC(NULL), LOGPIXELSY));
> + if (lf.lfWeight > FW_NORMAL) dummyTextHost->char_format.dwEffects |= CFE_BOLD;
> + if (lf.lfItalic) dummyTextHost->char_format.dwEffects |= CFE_ITALIC;
> + if (lf.lfUnderline) dummyTextHost->char_format.dwEffects |= CFE_UNDERLINE;
> + if (lf.lfStrikeOut) dummyTextHost->char_format.dwEffects |= CFE_SUBSCRIPT;
> + dummyTextHost->char_format.bPitchAndFamily = lf.lfPitchAndFamily;
> + dummyTextHost->char_format.bCharSet = lf.lfCharSet;
You do the same thing in the previous patch, so this should be a
helper function.
> /* MSDN states that an IUnknown object is returned by
> CreateTextServices which is then queried to obtain a
> @@ -947,6 +964,44 @@ static void test_QueryInterface(void)
> ITextHost_Release(host);
> }
>
> +static void test_default_format(void)
> +{
> + ITextServices *txtserv;
> + ITextHost *host;
> + HRESULT result;
> + LRESULT lresult;
> + CHARFORMAT2W cf2;
> + HFONT hf;
> + LOGFONTW lf;
> + LONG expected_height;
> +
> + if (!init_texthost(&txtserv, &host))
> + return;
> +
> + cf2.cbSize = sizeof(CHARFORMAT2W);
> + result = ITextServices_TxSendMessage(txtserv, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2, &lresult);
> + ok(result == S_OK, "ITextServices_TxSendMessage failed: 0x%08x.\n", result);
> + hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
> + GetObjectW(hf, sizeof(LOGFONTW), &lf);
Rather than getting the font here, why not call ITextHost_GetCharFormat() ?
> + expected_height = MulDiv(abs(lf.lfHeight), 1440, GetDeviceCaps(GetDC(NULL), LOGPIXELSY));
> + ok(!lstrcmpW(lf.lfFaceName, cf2.szFaceName), "got wrong font name: %s.\n", wine_dbgstr_w(cf2.szFaceName));
> + ok(cf2.yHeight == expected_height, "got wrong yHeight: %d, expetced %d.\n", cf2.yHeight, expected_height);
> + if (lf.lfWeight > FW_NORMAL)
> + ok(cf2.dwEffects & CFE_BOLD, "got dwEffects without CFE_BOLD: %x.\n", cf2.dwEffects);
> + if (lf.lfItalic)
> + ok(cf2.dwEffects & CFE_ITALIC, "got dwEffects without CFE_ITALIC: %x.\n", cf2.dwEffects);
> + if (lf.lfUnderline)
> + ok(cf2.dwEffects & CFE_UNDERLINE, "got dwEffects without CFE_UNDERLINE: %x.\n", cf2.dwEffects);
> + if (lf.lfStrikeOut)
> + ok(cf2.dwEffects & CFE_STRIKEOUT, "got dwEffects without CFE_STRIKEOUT: %x.\n", cf2.dwEffects);
> + ok(cf2.bPitchAndFamily == lf.lfPitchAndFamily, "got wrong bPitchAndFamily: %x, expected %x.\n",
> + cf2.bPitchAndFamily, lf.lfPitchAndFamily);
> + ok(cf2.bCharSet == lf.lfCharSet, "got wrong bCharSet: %x, expected %x.\n", cf2.bCharSet, lf.lfCharSet);
> +
> + ITextServices_Release(txtserv);
> + ITextHost_Release(host);
> +}
> +
> START_TEST( txtsrv )
> {
> ITextServices *txtserv;
> @@ -977,6 +1032,7 @@ START_TEST( txtsrv )
> test_TxGetNaturalSize();
> test_TxDraw();
> test_QueryInterface();
> + test_default_format();
> }
> if (wrapperCodeMem) VirtualFree(wrapperCodeMem, 0, MEM_RELEASE);
> }
> --
> 2.17.1
>
>
>
>
June 7, 2018
Re: [PATCH 1/4 v5] riched20/tests: Rewrite tests for ITextServices_TxGetNaturalSize().
by Jactry Zeng
Jactry Zeng <jactry92(a)gmail.com> 于2018年6月7日周四 下午5:21写道:
>
>
> In 0003 there are some tests about multiline support. It seems that
> using DrawText can make it more simple or we will need to compute
> a max width of it by ourselves.
Sorry, it is in 0004.
> --
> Regards,
> Jactry Zeng
--
Regards,
Jactry Zeng
June 7, 2018
Re: [PATCH 1/4 v5] riched20/tests: Rewrite tests for ITextServices_TxGetNaturalSize().
by Jactry Zeng
Huw Davies <huw(a)codeweavers.com> 于2018年6月7日周四 下午4:54写道:
>
> On Wed, Jun 06, 2018 at 05:24:13PM +0800, Jactry Zeng wrote:
> > Superseded patch 146570.
> >
> > + LONG expected_width, expected_height;
> > +
> > + GetClientRect(WindowFromDC(hdc), &rect);
> > + DrawTextW(hdc, string, -1, &rect, DT_LEFT | DT_CALCRECT | DT_NOCLIP | DT_EDITCONTROL | DT_WORDBREAK);
>
> Why can't you use GetTextExtentPointW() here? This would avoid the
> GetClientRect() call too.
>
In 0003 there are some tests about multiline support. It seems that
using DrawText can make it more simple or we will need to compute
a max width of it by ourselves.
--
Regards,
Jactry Zeng
June 7, 2018