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.