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.
