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