shell32: shellord.c: Implement SHGetNewLinkInfo[AW]. Fixes Bug 8082.
Zac Brown
zac at zacbrown.org
Wed Jul 2 14:20:31 CDT 2008
Zac Brown wrote:
> Implement SHGetNewLinkInfo[AW].
>
> Fixes Bug 8082 (http://bugs.winehq.org/show_bug.cgi?id=8082)
>
> Changes:
> * Implement SHGetNewLinkInfo[AW]
> * Update tests
>
>
> ------------------------------------------------------------------------
>
> ---
> dlls/shell32/shellord.c | 255 ++++++++++++++++++++++++++++++++++++++++-
> dlls/shell32/tests/shellord.c | 40 +++----
> 2 files changed, 269 insertions(+), 26 deletions(-)
>
> diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c
> index 5d1666b..5b1f824 100644
> --- a/dlls/shell32/shellord.c
> +++ b/dlls/shell32/shellord.c
> @@ -4,6 +4,7 @@
> *
> * Copyright 1997 Marcus Meissner
> * 1998 Jürgen Schmied
> + * 2008 Google (Zac Brown)
> *
> * This library is free software; you can redistribute it and/or
> * modify it under the terms of the GNU Lesser General Public
> @@ -1899,22 +1900,270 @@ BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWST
> return TRUE;
> }
>
> +/*************************************************************************
> + * SHGetNewLinkInfoA [SHELL32.179]
> + *
> + * See SHGetNewLinkInfoW
> + */
> BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy,
> UINT uFlags)
> {
> - FIXME("%s, %s, %p, %p, 0x%08x - stub\n", debugstr_a(pszLinkTo), debugstr_a(pszDir),
> + BOOL ret;
> + CHAR pathA[MAX_PATH];
> + WCHAR pszLinkToW[MAX_PATH];
> + WCHAR pszDirW[MAX_PATH];
> + WCHAR pszNameW[MAX_PATH];
> + LPSTR tmp_ptr;
> +
> + TRACE("%s, %s, %p, %p, 0x%08x - stub\n", debugstr_a(pszLinkTo), debugstr_a(pszDir),
> pszName, pfMustCopy, uFlags);
>
> + if (pszLinkTo == NULL || pszName == NULL)
> + return FALSE;
> +
> + if (uFlags & SHGNLI_PIDL)
> + {
> + if (SHGetPathFromIDListA (pszLinkTo, pathA) == FALSE)
> + return FALSE;
> + tmp_ptr = pathA;
> + }
> + else
> + tmp_ptr = pszLinkTo;
> +
> +
> + if (MultiByteToWideChar(CP_ACP, 0, pszName, -1, pszNameW, MAX_PATH) == 0 ||
> + MultiByteToWideChar(CP_ACP, 0, tmp_ptr, -1, pszLinkToW, MAX_PATH) == 0)
> + return FALSE;
> +
> + if (pszDir != NULL)
> + {
> + if (MultiByteToWideChar(CP_ACP, 0, pszDir, -1, pszDirW, MAX_PATH) == 0)
> + return FALSE;
> + ret = SHGetNewLinkInfoW (pszLinkToW, pszDirW, pszNameW, pfMustCopy, uFlags);
> + }
> + else
> + ret = SHGetNewLinkInfoW (pszLinkToW, NULL, pszNameW, pfMustCopy, uFlags);
> +
> + if (WideCharToMultiByte(CP_ACP, 0, pszNameW, -1, pszName, MAX_PATH, 0, 0) && ret == TRUE)
> + return ret;
> +
> return FALSE;
> }
>
> +/*****************************************************************************************
> + * [INTERNAL]
> + * confirm_link_unique: Check if a supplied shortcut name is unique
> + * within a directory and if not, generate one
> + * that is for SHGetNewLinkInfoW.
> + *
> + * PARAMS
> + * directory [I] Directory to check for duplicates in
> + * filename [I] Name of file that a link is being made to
> + * flags [I] Flags passed to SHGetNewLinkInfoW
> + * shortcut_name [I/O] Shortcut name to check for. Could be modified
> + * if needed.
> + * name_updated [O] Set to true when the name of the shortcut has
> + * been updated.
> + *
> + * RETURNS
> + * Success: TRUE - The function successfully completed
> + * Failure: FALSE - The function was unable to complete its task
> + */
> +
> +static BOOL confirm_link_unique(LPCWSTR directory, LPCWSTR filename, UINT flags, LPWSTR shortcut_name)
> +{
> + static const WCHAR search_pattern[] = {'\\','*',0};
> + static const WCHAR prefix_start[] = {'S','h','o','r','t','c','u','t',' ',0};
> + static const WCHAR lnk_extension[] = {'.','l','n','k',0};
> + static const WCHAR prefix_format[] = {'S','h','o','r','t','c','u','t',' ','(','%','d',')',' ','t','o',' ','%','s',0};
> + static const WCHAR no_prefix_format[] = {'%','s',' ','(','%','d',')',0};
> + WCHAR filename_noext[MAX_PATH];
> + WCHAR tmp_buf[MAX_PATH];
> + WCHAR *tmp_ptr, *tmp_ptr2;
> + HANDLE h;
> + WIN32_FIND_DATAW find_data;
> + long shortcut_num = 1;
> +
> + /* Get name of file without the file extension */
> + tmp_ptr = strrchrW (filename, '.');
> + if (tmp_ptr != NULL)
> + {
> + if (lstrcpynW (filename_noext, filename, (tmp_ptr - filename)*sizeof(WCHAR)) == NULL)
> + return FALSE;
> + }
> + else
> + lstrcpyW (filename_noext, filename);
> +
> + if (directory != NULL)
> + {
> + if (lstrcpyW (tmp_buf, directory) == NULL)
> + return FALSE;
> + }
> + else
> + {
> + if (GetCurrentDirectoryW (MAX_PATH, tmp_buf) == 0)
> + return FALSE;
> + }
> +
> + if (lstrcatW (tmp_buf, search_pattern) == NULL)
> + return FALSE;
> +
> + h = FindFirstFileW (tmp_buf, &find_data);
> + if (h == INVALID_HANDLE_VALUE)
> + return FALSE;
> +
> + while (FindNextFileW (h, &find_data))
> + {
> + /* Skip if the filename doesn't even contain our shortcut's
> + target filename */
> + if (StrStrW (find_data.cFileName, filename_noext) == NULL)
> + continue;
> +
> + /* Skip if the prefix name flag is set, but no prefix is found
> + in the file's name. */
> + if (flags & SHGNLI_PREFIXNAME)
> + {
> + if (StrStrW (find_data.cFileName, prefix_start) == NULL)
> + continue;
> + }
> +
> + if(lstrcmpW (find_data.cFileName, shortcut_name) == 0)
> + shortcut_num++;
> + else
> + {
> + tmp_ptr = strchrW (find_data.cFileName, '(');
> + tmp_ptr2 = strchrW (find_data.cFileName, ')');
> + if (tmp_ptr && tmp_ptr2)
> + {
> + tmp_ptr++;
> + tmp_ptr2++;
> + lstrcpynW (tmp_buf, tmp_ptr, tmp_ptr2 - tmp_ptr);
> + shortcut_num = wcstol(tmp_buf, &tmp_buf[lstrlenW(tmp_buf)-1], 0) + 1;
> + }
> + }
> + }
> +
> + FindClose (h);
> +
> + if (shortcut_num > 1)
> + {
> + if (flags & SHGNLI_PREFIXNAME)
> + {
> + sprintfW (shortcut_name, prefix_format, shortcut_num, filename);
> + }
> + else
> + {
> + lstrcpyW (shortcut_name, filename);
> + wsprintfW (shortcut_name, no_prefix_format, filename, shortcut_num);
> + }
> +
> + if ((flags & SHGNLI_NOLNK) == 0)
> + lstrcatW (shortcut_name, lnk_extension);
> + }
> +
> + return TRUE;
> +}
> +
> +/*************************************************************************
> + * SHGetNewLinkInfoW [SHELL32.180]
> + *
> + * Creates the proper name for a new shortcut. This function does not
> + * actually create a shortcut.
> + */
> BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy,
> UINT uFlags)
> {
> - FIXME("%s, %s, %p, %p, 0x%08x - stub\n", debugstr_w(pszLinkTo), debugstr_w(pszDir),
> + static const WCHAR prefix_start[] = {'S', 'h', 'o', 'r', 't', 'c', 'u', 't', ' ', 't', 'o', ' ', 0};
> + static const WCHAR prefix_start_nounique[] =
> + {'S', 'h', 'o', 'r', 't', 'c', 'u', 't', ' ', '(', ')', ' ', 't', 'o', ' ', 0};
> + static const WCHAR link_extension[] = {'.', 'l', 'n', 'k', 0};
> + static const WCHAR back_slash[] = {'\\',0};
> + WCHAR target[MAX_PATH];
> + WCHAR shortcut_name[MAX_PATH];
> + WCHAR file_name[MAX_PATH];
> + LPCWSTR tmp_ptr;
> + SHFILEINFOW file_info;
> + BOOL shortcut_name_updated;
> +
> + TRACE("%s, %s, %p, %p, 0x%08x - stub\n", debugstr_w(pszLinkTo), debugstr_w(pszDir),
> pszName, pfMustCopy, uFlags);
>
> - return FALSE;
> + if (pfMustCopy)
> + *pfMustCopy = FALSE;
> + else
> + return FALSE;
> +
> + if (pszLinkTo == NULL || pszName == NULL)
> + return FALSE;
> +
> + if (uFlags & SHGNLI_PIDL)
> + {
> + if (SHGetPathFromIDListW (pszLinkTo, target) == FALSE)
> + return FALSE;
> + }
> + else
> + {
> + if (lstrcpyW (target, pszLinkTo) == NULL)
> + return FALSE;
> + }
> +
> + /* Determine the file's name. */
> + tmp_ptr = strrchrW (target, '\\');
> + if (tmp_ptr != NULL)
> + tmp_ptr++;
> + else
> + tmp_ptr = target;
> +
> + lstrcpyW (file_name, tmp_ptr);
> +
> + if (uFlags & SHGNLI_NOUNIQUE)
> + tmp_ptr = prefix_start_nounique;
> + else
> + tmp_ptr = prefix_start;
> +
> + /* Begin checking against flags and generating the shortcut name. */
> + if (uFlags & SHGNLI_PREFIXNAME)
> + {
> + lstrcpyW (shortcut_name, tmp_ptr);
> + lstrcatW (shortcut_name, file_name);
> + }
> + else
> + lstrcpyW (shortcut_name, file_name);
> +
> + if ((uFlags & SHGNLI_NOLNK) == 0)
> + lstrcatW (shortcut_name, link_extension);
> +
> + /* Check if we need to generate a unique name. */
> + if (lstrcmpW (shortcut_name, file_name) == 0 && !(uFlags & (SHGNLI_NOLNK | SHGNLI_NOUNIQUE)))
> + {
> + if (confirm_link_unique (pszDir, file_name, uFlags, shortcut_name) == FALSE)
> + return FALSE;
> + }
> +
> + if (!(uFlags & SHGNLI_NOUNIQUE))
> + {
> + if (confirm_link_unique (pszDir, file_name, uFlags, shortcut_name) == FALSE)
> + return FALSE;
> + }
> +
> + if (pszDir != NULL && (uFlags & SHGNLI_NOUNIQUE) == 0)
> + {
> + lstrcpyW (pszName, pszDir);
> + lstrcatW (pszName, back_slash);
> + lstrcatW (pszName, shortcut_name);
> + }
> + else
> + lstrcpyW (pszName, shortcut_name);
> +
> + if (SHGetFileInfoW (target, 0, &file_info, sizeof(file_info), SHGFI_ATTRIBUTES))
> + {
> + if (file_info.dwAttributes & SFGAO_LINK)
> + *pfMustCopy = TRUE;
> + else
> + *pfMustCopy = FALSE;
> + }
> +
> + return TRUE;
> }
>
> HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
> diff --git a/dlls/shell32/tests/shellord.c b/dlls/shell32/tests/shellord.c
> index f5ae1bd..423ed7d 100644
> --- a/dlls/shell32/tests/shellord.c
> +++ b/dlls/shell32/tests/shellord.c
> @@ -57,7 +57,7 @@ static const getlink_test_t getlink_tests[] = {
> "testfile.lnk",
> "testfile.txt.lnk",
> TRUE,
> - TRUE,
> + FALSE,
> FALSE
> },
> {
> @@ -75,7 +75,7 @@ static const getlink_test_t getlink_tests[] = {
> "testfile.lnk",
> "testfile.txt.lnk",
> FALSE,
> - TRUE,
> + FALSE,
> FALSE
> },
> {
> @@ -84,7 +84,7 @@ static const getlink_test_t getlink_tests[] = {
> "Shortcut to testfile.lnk",
> "Shortcut to testfile.txt.lnk",
> TRUE,
> - TRUE,
> + FALSE,
> TRUE
> },
> {
> @@ -93,7 +93,7 @@ static const getlink_test_t getlink_tests[] = {
> "testfile.lnk",
> "testfile.txt (2)",
> TRUE,
> - TRUE,
> + FALSE,
> FALSE
> },
> {
> @@ -129,7 +129,7 @@ static const getlink_test_t getlink_tests[] = {
> "Shortcut () to testfile.lnk",
> "Shortcut () to testfile.txt.lnk",
> FALSE,
> - TRUE,
> + FALSE,
> FALSE
> },
> {
> @@ -138,7 +138,7 @@ static const getlink_test_t getlink_tests[] = {
> "testfile.lnk",
> "testfile.txt",
> FALSE,
> - TRUE,
> + FALSE,
> FALSE
> },
> {
> @@ -147,7 +147,7 @@ static const getlink_test_t getlink_tests[] = {
> "Shortcut to testfile.lnk",
> "Shortcut to testfile.txt",
> TRUE,
> - TRUE,
> + FALSE,
> TRUE
> },
> {
> @@ -174,7 +174,7 @@ static const getlink_test_t getlink_tests[] = {
> "Shortcut () to testfile.lnk",
> "Shortcut () to testfile.txt",
> FALSE,
> - TRUE,
> + FALSE,
> FALSE
> },
> {
> @@ -237,41 +237,38 @@ static void test_SHGetNewLinkInfo (void)
> /* Test with all NULL/0 values except for pfMustCopy */
> ret = SHGetNewLinkInfoA (NULL, NULL, NULL, &pfMustCopy, flags);
> ok (ret == FALSE, "Expected return value of FALSE.\n");
> - todo_wine ok(pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> + ok(pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
>
> /* Test with valid target, NULL shortcut directory and name buffers */
> if (test_ptr->skip_crash == FALSE)
> {
> ret = SHGetNewLinkInfoA (shortcut_ptr, NULL, NULL, &pfMustCopy, flags);
> ok (ret == FALSE, "Expected return value of FALSE.\n");
> - todo_wine ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> + ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> }
>
> /* Test with valid shortcut directory, NULL target and name buffers */
> ret = SHGetNewLinkInfoA (NULL, shortcut_dir, NULL, &pfMustCopy, flags);
> ok (ret == FALSE, "Expected return value of FALSE.\n");
> - todo_wine ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> + ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
>
> /* Test with valid shortcut name and NULL target, shortcut directory buffers */
> ret = SHGetNewLinkInfoA (NULL, NULL, shortcut_name, &pfMustCopy, flags);
> ok (ret == FALSE, "Expected return value of FALSE.\n");
> - todo_wine ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> + ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
>
> /* Test with valid shortcut directory and name, NULL shortcut target buffer */
> ret = SHGetNewLinkInfoA (NULL, shortcut_dir, shortcut_name, &pfMustCopy, flags);
> ok (ret == FALSE, "Expected return value of FALSE.\n");
> - todo_wine ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> + ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
>
> /* Test with valid shortcut target and name, NULL shortcut directory buffer */
> if (test_ptr->skip_crash == FALSE)
> {
> memset (shortcut_name, 0, MAX_PATH);
> ret = SHGetNewLinkInfoA (shortcut_ptr, NULL, shortcut_name, &pfMustCopy, flags);
> - todo_wine
> - {
> - ok (ret == TRUE, "Expected return value of TRUE.\n");
> - ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> - }
> + ok (ret == TRUE, "Expected return value of TRUE.\n");
> + ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
>
> lstrcpyA (tmp_buf1, test_ptr->expected_str_1);
> lstrcpyA (tmp_buf2, test_ptr->expected_str_2);
> @@ -299,11 +296,8 @@ static void test_SHGetNewLinkInfo (void)
> /* Test with valid shortcut directory, target, name buffers */
> memset (shortcut_name, 0, MAX_PATH);
> ret = SHGetNewLinkInfoA (shortcut_ptr, shortcut_dir, shortcut_name, &pfMustCopy, flags);
> - todo_wine
> - {
> - ok (ret == TRUE, "Expected return value of TRUE.\n");
> - ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
> - }
> + ok (ret == TRUE, "Expected return value of TRUE.\n");
> + ok (pfMustCopy == FALSE, "Expected pfMustCopy to be FALSE.\n");
>
> if (test_ptr->use_full_path == TRUE && shortcut_dir != NULL)
> {
>
>
> ------------------------------------------------------------------------
>
>
Ignore this patch, will send a fixed on in a minute.
More information about the wine-devel
mailing list