TEST_FIELD(COAUTHINFO, DWORD, dwCapabilities, 24, 4, 4);
}
-static void test_pack_COSERVERINFO(void)
+static void test_pack_DATE(void)
{
- /* COSERVERINFO (pack 4) */
- TEST_TYPE(COSERVERINFO, 16, 4);
- TEST_FIELD(COSERVERINFO, DWORD, dwReserved1, 0, 4, 4);
- TEST_FIELD(COSERVERINFO, LPWSTR, pwszName, 4, 4, 4);
- TEST_FIELD(COSERVERINFO, COAUTHINFO *, pAuthInfo, 8, 4, 4);
- TEST_FIELD(COSERVERINFO, DWORD, dwReserved2, 12, 4, 4);
+ /* DATE */
+ TEST_TYPE(DATE, 8, 8);
+}
+
+static void test_pack_DOUBLE(void)
+{
+ /* DOUBLE */
+ TEST_TYPE(DOUBLE, 8, 8);
}
static void test_pack_DWORD_SIZEDARR(void)
{
/* LPBLOB */
TEST_TYPE(LPBLOB, 4, 4);
- TEST_TYPE_POINTER(LPBLOB, 8, 4);
}
static void test_pack_LPBSTR(void)
{
/* LPBSTRBLOB */
TEST_TYPE(LPBSTRBLOB, 4, 4);
- TEST_TYPE_POINTER(LPBSTRBLOB, 8, 4);
}
static void test_pack_LPCOLESTR(void)
{
/* LPITEMIDLIST */
TEST_TYPE(LPITEMIDLIST, 4, 4);
- TEST_TYPE_POINTER(LPITEMIDLIST, 3, 1);
}
static void test_pack_LPSHELLDETAILS(void)
{
/* LPSHITEMID */
TEST_TYPE(LPSHITEMID, 4, 4);
- TEST_TYPE_POINTER(LPSHITEMID, 3, 1);
}
static void test_pack_LPSTRRET(void)
TEST_FIELD(FILEGROUPDESCRIPTORW, FILEDESCRIPTORW[1], fgd, 4, 592, 1);
}
-static void test_pack_IFileSystemBindData(void)
-{
- /* IFileSystemBindData */
-}
-
-static void test_pack_IFileSystemBindDataVtbl(void)
-{
- /* IFileSystemBindDataVtbl */
-}
-
-static void test_pack_IShellChangeNotify(void)
-{
- /* IShellChangeNotify */
-}
-
-static void test_pack_IShellIcon(void)
-{
- /* IShellIcon */
-}
-
static void test_pack_LPBROWSEINFOA(void)
{
/* LPBROWSEINFOA */
test_pack_CLSID();
test_pack_COAUTHIDENTITY();
test_pack_COAUTHINFO();
- test_pack_COSERVERINFO();
test_pack_CSFV();
+ test_pack_DATE();
+ test_pack_DOUBLE();
test_pack_DRAGINFOA();
test_pack_DRAGINFOW();
test_pack_DROPFILES();
test_pack_GUID();
test_pack_HMETAFILEPICT();
test_pack_HYPER_SIZEDARR();
- test_pack_IFileSystemBindData();
- test_pack_IFileSystemBindDataVtbl();
test_pack_IID();
- test_pack_IShellChangeNotify();
- test_pack_IShellIcon();
test_pack_ITEMIDLIST();
test_pack_LPBLOB();
test_pack_LPBROWSEINFOA();
<module name="shell32_winetest" type="win32cui" installbase="bin" installname="shell32_winetest.exe" allowwarnings="true">
- <include base="shell32_winetest">.</include>
- <define name="__USE_W32API" />
- <library>ntdll</library>
- <library>shell32</library>
- <library>kernel32</library>
- <library>advapi32</library>
- <library>shlwapi</library>
- <library>ole32</library>
- <file>shelllink.c</file>
- <file>shellpath.c</file>
- <file>shlexec.c</file>
- <file>shlfileop.c</file>
- <file>shlfolder.c</file>
- <file>string.c</file>
- <file>testlist.c</file>
+ <include base="shell32_winetest">.</include>
+ <define name="__USE_W32API" />
+ <define name="_WIN32_IE">0x600</define>
+ <define name="_WIN32_WINNT">0x501</define>
+ <define name="WINVER">0x501</define>
+ <library>wine</library>
+ <library>shell32</library>
+ <library>ole32</library>
+ <library>oleaut32</library>
+ <library>shlwapi</library>
+ <library>user32</library>
+ <library>gdi32</library>
+ <library>advapi32</library>
+ <library>kernel32</library>
+ <library>uuid</library>
+ <library>ntdll</library>
+ <file>generated.c</file>
+ <file>shelllink.c</file>
+ <file>shellpath.c</file>
+ <file>shlexec.c</file>
+ <file>shlfileop.c</file>
+ <file>shlfolder.c</file>
+ <file>string.c</file>
+ <file>systray.c</file>
+ <file>testlist.c</file>
</module>
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
* This is a test program for the SHGet{Special}Folder{Path|Location} functions
* of shell32, that get either a filesytem path or a LPITEMIDLIST (shell
* namespace) path for a given folder (CSIDL value).
*
*/
-#define _WIN32_IE 0x0400
-
#define COBJMACROS
-#include <stdarg.h>
-#include <stdio.h>
-#include "windef.h"
-#include "winbase.h"
-#include "basetyps.h"
+#include <windows.h>
#include "shlguid.h"
-//#include "wine/shobjidl.h"
+#include "shobjidl.h"
#include "shlobj.h"
#include "wine/test.h"
#include "shell32_test.h"
-extern BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
-extern HRESULT WINAPI SHILCreateFromPath(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes);
-extern void WINAPI ILFree(LPITEMIDLIST pidl);
+
+typedef void (WINAPI *fnILFree)(LPITEMIDLIST);
+typedef BOOL (WINAPI *fnILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
+typedef HRESULT (WINAPI *fnSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
+
+static fnILFree pILFree;
+static fnILIsEqual pILIsEqual;
+static fnSHILCreateFromPath pSHILCreateFromPath;
+
+static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR, LPSTR, DWORD);
+
+static const GUID _IID_IShellLinkDataList = {
+ 0x45e2b4ae, 0xb1c3, 0x11d0,
+ { 0xb9, 0x2f, 0x00, 0xa0, 0xc9, 0x03, 0x12, 0xe1 }
+};
static const WCHAR lnkfile[]= { 'C',':','\\','t','e','s','t','.','l','n','k',0 };
static const WCHAR notafile[]= { 'C',':','\\','n','o','n','e','x','i','s','t','e','n','t','\\','f','i','l','e',0 };
-#if 0 // FIXME: needed to build. Please update shell32 winetest.
-const GUID IID_IPersistFile = { 0x0000010b, 0x0000, 0x0000, { 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46 } };
-#endif
/* For some reason SHILCreateFromPath does not work on Win98 and
* SHSimpleIDListFromPathA does not work on NT4. But if we call both we
* get what we want on all platforms.
*/
-static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathA)(LPCSTR)=NULL;
+static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
static LPITEMIDLIST path_to_pidl(const char* path)
{
LPITEMIDLIST pidl;
- if (!pSHSimpleIDListFromPathA)
+ if (!pSHSimpleIDListFromPathAW)
{
- HMODULE hdll=LoadLibraryA("shell32.dll");
- pSHSimpleIDListFromPathA=(void*)GetProcAddress(hdll, (char*)162);
- if (!pSHSimpleIDListFromPathA)
- trace("SHSimpleIDListFromPathA not found in shell32.dll\n");
+ HMODULE hdll=GetModuleHandleA("shell32.dll");
+ pSHSimpleIDListFromPathAW=(void*)GetProcAddress(hdll, (char*)162);
+ if (!pSHSimpleIDListFromPathAW)
+ trace("SHSimpleIDListFromPathAW not found in shell32.dll\n");
}
pidl=NULL;
- if (pSHSimpleIDListFromPathA)
- pidl=pSHSimpleIDListFromPathA(path);
+ /* pSHSimpleIDListFromPathAW maps to A on non NT platforms */
+ if (pSHSimpleIDListFromPathAW && (GetVersion() & 0x80000000))
+ pidl=pSHSimpleIDListFromPathAW(path);
if (!pidl)
{
pathW=HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
- r=SHILCreateFromPath(pathW, &pidl, NULL);
+ r=pSHILCreateFromPath(pathW, &pidl, NULL);
todo_wine {
- ok(SUCCEEDED(r), "SHILCreateFromPath failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SHILCreateFromPath failed (0x%08x)\n", r);
}
HeapFree(GetProcessHeap(), 0, pathW);
}
r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
&IID_IShellLinkA, (LPVOID*)&sl);
- ok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08x)\n", r);
if (!SUCCEEDED(r))
return;
/* Test Getting / Setting the description */
strcpy(buffer,"garbage");
r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
- ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetDescription failed (0x%08x)\n", r);
ok(*buffer=='\0', "GetDescription returned '%s'\n", buffer);
str="Some description";
r = IShellLinkA_SetDescription(sl, str);
- ok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetDescription failed (0x%08x)\n", r);
strcpy(buffer,"garbage");
r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
- ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetDescription failed (0x%08x)\n", r);
ok(lstrcmp(buffer,str)==0, "GetDescription returned '%s'\n", buffer);
/* Test Getting / Setting the work directory */
strcpy(buffer,"garbage");
r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
- ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08x)\n", r);
ok(*buffer=='\0', "GetWorkingDirectory returned '%s'\n", buffer);
str="c:\\nonexistent\\directory";
r = IShellLinkA_SetWorkingDirectory(sl, str);
- ok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08x)\n", r);
strcpy(buffer,"garbage");
r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
- ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08x)\n", r);
ok(lstrcmpi(buffer,str)==0, "GetWorkingDirectory returned '%s'\n", buffer);
/* Test Getting / Setting the work directory */
strcpy(buffer,"garbage");
r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
- ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
r = IShellLinkA_SetPath(sl, "");
- ok(r==S_OK, "SetPath failed (0x%08lx)\n", r);
+ ok(r==S_OK, "SetPath failed (0x%08x)\n", r);
strcpy(buffer,"garbage");
r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
- ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
+ /* Win98 returns S_FALSE, but WinXP returns S_OK */
str="c:\\nonexistent\\file";
r = IShellLinkA_SetPath(sl, str);
- ok(r==S_FALSE, "SetPath failed (0x%08lx)\n", r);
+ ok(r==S_FALSE || r==S_OK, "SetPath failed (0x%08x)\n", r);
strcpy(buffer,"garbage");
r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
- ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
ok(lstrcmpi(buffer,str)==0, "GetPath returned '%s'\n", buffer);
/* Get some a real path to play with */
r=GetModuleFileName(NULL, mypath, sizeof(mypath));
- ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\n", r);
+ ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%d)\n", r);
/* Test the interaction of SetPath and SetIDList */
tmp_pidl=NULL;
r = IShellLinkA_GetIDList(sl, &tmp_pidl);
- ok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetIDList failed (0x%08x)\n", r);
if (SUCCEEDED(r))
{
strcpy(buffer,"garbage");
if (pidl)
{
r = IShellLinkA_SetIDList(sl, pidl);
- ok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetIDList failed (0x%08x)\n", r);
tmp_pidl=NULL;
r = IShellLinkA_GetIDList(sl, &tmp_pidl);
- ok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
- ok(tmp_pidl && ILIsEqual(pidl, tmp_pidl),
+ ok(SUCCEEDED(r), "GetIDList failed (0x%08x)\n", r);
+ ok(tmp_pidl && pILIsEqual(pidl, tmp_pidl),
"GetIDList returned an incorrect pidl\n");
/* tmp_pidl is owned by IShellLink so we don't free it */
- ILFree(pidl);
+ pILFree(pidl);
strcpy(buffer,"garbage");
r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
- ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
ok(lstrcmpi(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
}
+ /* test path with quotes (Win98 IShellLinkA_SetPath returns S_FALSE, WinXP returns S_OK) */
+ r = IShellLinkA_SetPath(sl, "\"c:\\nonexistent\\file\"");
+ ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
+ r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
+ ok(r==S_OK, "GetPath failed (0x%08x)\n", r);
+ ok(!lstrcmp(buffer, "C:\\nonexistent\\file"), "case doesn't match\n");
+
+ r = IShellLinkA_SetPath(sl, "\"c:\\foo");
+ ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
+ r = IShellLinkA_SetPath(sl, "\"\"c:\\foo");
+ ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
+ r = IShellLinkA_SetPath(sl, "c:\\foo\"");
+ ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
+ r = IShellLinkA_SetPath(sl, "\"\"c:\\foo\"");
+ ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
+ r = IShellLinkA_SetPath(sl, "\"\"c:\\foo\"\"");
+ ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
/* Test Getting / Setting the arguments */
strcpy(buffer,"garbage");
r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
- ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetArguments failed (0x%08x)\n", r);
ok(*buffer=='\0', "GetArguments returned '%s'\n", buffer);
str="param1 \"spaced param2\"";
r = IShellLinkA_SetArguments(sl, str);
- ok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetArguments failed (0x%08x)\n", r);
strcpy(buffer,"garbage");
r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
- ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetArguments failed (0x%08x)\n", r);
ok(lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
/* Test Getting / Setting showcmd */
i=0xdeadbeef;
r = IShellLinkA_GetShowCmd(sl, &i);
- ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetShowCmd failed (0x%08x)\n", r);
ok(i==SW_SHOWNORMAL, "GetShowCmd returned %d\n", i);
r = IShellLinkA_SetShowCmd(sl, SW_SHOWMAXIMIZED);
- ok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetShowCmd failed (0x%08x)\n", r);
i=0xdeadbeef;
r = IShellLinkA_GetShowCmd(sl, &i);
- ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetShowCmd failed (0x%08x)\n", r);
ok(i==SW_SHOWMAXIMIZED, "GetShowCmd returned %d'\n", i);
/* Test Getting / Setting the icon */
strcpy(buffer,"garbage");
r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
todo_wine {
- ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetIconLocation failed (0x%08x)\n", r);
}
ok(*buffer=='\0', "GetIconLocation returned '%s'\n", buffer);
ok(i==0, "GetIconLocation returned %d\n", i);
str="c:\\nonexistent\\file";
r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
- ok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetIconLocation failed (0x%08x)\n", r);
i=0xdeadbeef;
r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
- ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetIconLocation failed (0x%08x)\n", r);
ok(lstrcmpi(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
ok(i==0xbabecafe, "GetIconLocation returned %d'\n", i);
/* Test Getting / Setting the hot key */
w=0xbeef;
r = IShellLinkA_GetHotkey(sl, &w);
- ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetHotkey failed (0x%08x)\n", r);
ok(w==0, "GetHotkey returned %d\n", w);
r = IShellLinkA_SetHotkey(sl, 0x5678);
- ok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "SetHotkey failed (0x%08x)\n", r);
w=0xbeef;
r = IShellLinkA_GetHotkey(sl, &w);
- ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "GetHotkey failed (0x%08x)\n", r);
ok(w==0x5678, "GetHotkey returned %d'\n", w);
IShellLinkA_Release(sl);
*/
#define lok ok_(__FILE__, line)
-#define check_lnk(a,b) check_lnk_(__LINE__, (a), (b))
+#define lok_todo_4(todo_flag,a,b,c,d) \
+ if ((todo & todo_flag) == 0) lok((a), (b), (c), (d)); \
+ else todo_wine lok((a), (b), (c), (d));
+#define lok_todo_2(todo_flag,a,b) \
+ if ((todo & todo_flag) == 0) lok((a), (b)); \
+ else todo_wine lok((a), (b));
+#define check_lnk(a,b,c) check_lnk_(__LINE__, (a), (b), (c))
void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int save_fails)
{
r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
&IID_IShellLinkA, (LPVOID*)&sl);
- lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08x)\n", r);
if (!SUCCEEDED(r))
return;
if (desc->description)
{
r = IShellLinkA_SetDescription(sl, desc->description);
- lok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetDescription failed (0x%08x)\n", r);
}
if (desc->workdir)
{
r = IShellLinkA_SetWorkingDirectory(sl, desc->workdir);
- lok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08x)\n", r);
}
if (desc->path)
{
r = IShellLinkA_SetPath(sl, desc->path);
- lok(SUCCEEDED(r), "SetPath failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetPath failed (0x%08x)\n", r);
}
if (desc->pidl)
{
r = IShellLinkA_SetIDList(sl, desc->pidl);
- lok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetIDList failed (0x%08x)\n", r);
}
if (desc->arguments)
{
r = IShellLinkA_SetArguments(sl, desc->arguments);
- lok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetArguments failed (0x%08x)\n", r);
}
if (desc->showcmd)
{
r = IShellLinkA_SetShowCmd(sl, desc->showcmd);
- lok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetShowCmd failed (0x%08x)\n", r);
}
if (desc->icon)
{
r = IShellLinkA_SetIconLocation(sl, desc->icon, desc->icon_id);
- lok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetIconLocation failed (0x%08x)\n", r);
}
if (desc->hotkey)
{
r = IShellLinkA_SetHotkey(sl, desc->hotkey);
- lok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "SetHotkey failed (0x%08x)\n", r);
}
r = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
- lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08x)\n", r);
if (SUCCEEDED(r))
{
r = IPersistFile_Save(pf, path, TRUE);
if (save_fails)
{
todo_wine {
- lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "save failed (0x%08x)\n", r);
}
}
else
{
- lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "save failed (0x%08x)\n", r);
}
IPersistFile_Release(pf);
}
IShellLinkA_Release(sl);
}
-static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
+static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo)
{
HRESULT r;
IShellLinkA *sl;
r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
&IID_IShellLinkA, (LPVOID*)&sl);
- lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08x)\n", r);
if (!SUCCEEDED(r))
return;
r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
- lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08x)\n", r);
if (!SUCCEEDED(r))
{
IShellLinkA_Release(sl);
}
r = IPersistFile_Load(pf, path, STGM_READ);
- lok(SUCCEEDED(r), "load failed (0x%08lx)\n", r);
+ lok(SUCCEEDED(r), "load failed (0x%08x)\n", r);
IPersistFile_Release(pf);
if (!SUCCEEDED(r))
{
{
strcpy(buffer,"garbage");
r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
- lok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
- lok(lstrcmp(buffer, desc->description)==0,
+ lok(SUCCEEDED(r), "GetDescription failed (0x%08x)\n", r);
+ lok_todo_4(0x1, lstrcmp(buffer, desc->description)==0,
"GetDescription returned '%s' instead of '%s'\n",
buffer, desc->description);
}
{
strcpy(buffer,"garbage");
r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
- lok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
- lok(lstrcmpi(buffer, desc->workdir)==0,
+ lok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08x)\n", r);
+ lok_todo_4(0x2, lstrcmpi(buffer, desc->workdir)==0,
"GetWorkingDirectory returned '%s' instead of '%s'\n",
buffer, desc->workdir);
}
{
strcpy(buffer,"garbage");
r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
- lok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
- lok(lstrcmpi(buffer, desc->path)==0,
+ lok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
+ lok_todo_4(0x4, lstrcmpi(buffer, desc->path)==0,
"GetPath returned '%s' instead of '%s'\n",
buffer, desc->path);
}
{
LPITEMIDLIST pidl=NULL;
r = IShellLinkA_GetIDList(sl, &pidl);
- lok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
- lok(ILIsEqual(pidl, desc->pidl),
+ lok(SUCCEEDED(r), "GetIDList failed (0x%08x)\n", r);
+ lok_todo_2(0x8, pILIsEqual(pidl, desc->pidl),
"GetIDList returned an incorrect pidl\n");
}
if (desc->showcmd)
{
int i=0xdeadbeef;
r = IShellLinkA_GetShowCmd(sl, &i);
- lok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
- lok(i==desc->showcmd,
+ lok(SUCCEEDED(r), "GetShowCmd failed (0x%08x)\n", r);
+ lok_todo_4(0x10, i==desc->showcmd,
"GetShowCmd returned 0x%0x instead of 0x%0x\n",
i, desc->showcmd);
}
int i=0xdeadbeef;
strcpy(buffer,"garbage");
r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
- lok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
- lok(lstrcmpi(buffer, desc->icon)==0,
+ lok(SUCCEEDED(r), "GetIconLocation failed (0x%08x)\n", r);
+ lok_todo_4(0x20, lstrcmpi(buffer, desc->icon)==0,
"GetIconLocation returned '%s' instead of '%s'\n",
buffer, desc->icon);
- lok(i==desc->icon_id,
+ lok_todo_4(0x20, i==desc->icon_id,
"GetIconLocation returned 0x%0x instead of 0x%0x\n",
i, desc->icon_id);
}
{
WORD i=0xbeef;
r = IShellLinkA_GetHotkey(sl, &i);
- lok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
- lok(i==desc->hotkey,
+ lok(SUCCEEDED(r), "GetHotkey failed (0x%08x)\n", r);
+ lok_todo_4(0x40, i==desc->hotkey,
"GetHotkey returned 0x%04x instead of 0x%04x\n",
i, desc->hotkey);
}
lnk_desc_t desc;
char mypath[MAX_PATH];
char mydir[MAX_PATH];
+ char realpath[MAX_PATH];
char* p;
+ HANDLE hf;
DWORD r;
/* Save an empty .lnk file */
desc.path="";
desc.arguments="";
desc.icon="";
- check_lnk(lnkfile, &desc);
-
+ check_lnk(lnkfile, &desc, 0x0);
/* Point a .lnk file to nonexistent files */
desc.description="";
desc.icon_id=1234;
desc.hotkey=0;
create_lnk(lnkfile, &desc, 0);
- check_lnk(lnkfile, &desc);
+ check_lnk(lnkfile, &desc, 0x0);
r=GetModuleFileName(NULL, mypath, sizeof(mypath));
- ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\n", r);
+ ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%d)\n", r);
strcpy(mydir, mypath);
p=strrchr(mydir, '\\');
if (p)
*p='\0';
-
/* Overwrite the existing lnk file and point it to existing files */
desc.description="test 2";
desc.workdir=mydir;
desc.icon_id=0;
desc.hotkey=0x1234;
create_lnk(lnkfile, &desc, 0);
- check_lnk(lnkfile, &desc);
+ check_lnk(lnkfile, &desc, 0x0);
+
+ /* Overwrite the existing lnk file and test link to a command on the path */
+ desc.description="command on path";
+ desc.workdir=mypath;
+ desc.path="rundll32.exe";
+ desc.pidl=NULL;
+ desc.arguments="/option1 /option2 \"Some string\"";
+ desc.showcmd=SW_SHOWNORMAL;
+ desc.icon=mypath;
+ desc.icon_id=0;
+ desc.hotkey=0x1234;
+ create_lnk(lnkfile, &desc, 0);
+ /* Check that link is created to proper location */
+ SearchPathA( NULL, desc.path, NULL, MAX_PATH, realpath, NULL);
+ desc.path=realpath;
+ check_lnk(lnkfile, &desc, 0x0);
+
+ /* Create a temporary non-executable file */
+ r=GetTempPath(sizeof(mypath), mypath);
+ ok(r>=0 && r<sizeof(mypath), "GetTempPath failed (%d), err %d\n", r, GetLastError());
+ r=pGetLongPathNameA(mypath, mydir, sizeof(mydir));
+ ok(r>=0 && r<sizeof(mydir), "GetLongPathName failed (%d), err %d\n", r, GetLastError());
+ p=strrchr(mydir, '\\');
+ if (p)
+ *p='\0';
+
+ strcpy(mypath, mydir);
+ strcat(mypath, "\\test.txt");
+ hf = CreateFile(mypath, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ CloseHandle(hf);
+
+ /* Overwrite the existing lnk file and test link to an existing non-executable file */
+ desc.description="non-executable file";
+ desc.workdir=mydir;
+ desc.path=mypath;
+ desc.pidl=NULL;
+ desc.arguments="";
+ desc.showcmd=SW_SHOWNORMAL;
+ desc.icon=mypath;
+ desc.icon_id=0;
+ desc.hotkey=0x1234;
+ create_lnk(lnkfile, &desc, 0);
+ check_lnk(lnkfile, &desc, 0x0);
+
+ r = DeleteFileA(mypath);
+ ok(r, "failed to delete file %s (%d)\n", mypath, GetLastError());
/* FIXME: Also test saving a .lnk pointing to a pidl that cannot be
* represented as a path.
/* DeleteFileW is not implemented on Win9x */
r=DeleteFileA("c:\\test.lnk");
- ok(r, "failed to delete link (%ld)\n", GetLastError());
+ ok(r, "failed to delete link (%d)\n", GetLastError());
+}
+
+static void test_datalink(void)
+{
+ static const WCHAR lnk[] = {
+ ':',':','{','9','d','b','1','1','8','6','f','-','4','0','d','f','-','1',
+ '1','d','1','-','a','a','8','c','-','0','0','c','0','4','f','b','6','7',
+ '8','6','3','}',':','{','0','0','0','1','0','4','0','9','-','7','8','E',
+ '1','-','1','1','D','2','-','B','6','0','F','-','0','0','6','0','9','7',
+ 'C','9','9','8','E','7','}',':',':','{','9','d','b','1','1','8','6','e',
+ '-','4','0','d','f','-','1','1','d','1','-','a','a','8','c','-','0','0',
+ 'c','0','4','f','b','6','7','8','6','3','}',':','2','6',',','!','!','g',
+ 'x','s','f','(','N','g',']','q','F','`','H','{','L','s','A','C','C','E',
+ 'S','S','F','i','l','e','s','>','p','l','T',']','j','I','{','j','f','(',
+ '=','1','&','L','[','-','8','1','-',']',':',':',0 };
+ static const WCHAR comp[] = {
+ '2','6',',','!','!','g','x','s','f','(','N','g',']','q','F','`','H','{',
+ 'L','s','A','C','C','E','S','S','F','i','l','e','s','>','p','l','T',']',
+ 'j','I','{','j','f','(','=','1','&','L','[','-','8','1','-',']',0 };
+ IShellLinkDataList *dl = NULL;
+ IShellLinkW *sl = NULL;
+ HRESULT r;
+ DWORD flags = 0;
+ EXP_DARWIN_LINK *dar;
+
+ r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW, (LPVOID*)&sl );
+ ok( r == S_OK || r == E_NOINTERFACE, "CoCreateInstance failed (0x%08x)\n", r);
+ if (!sl)
+ {
+ skip("no shelllink\n");
+ return;
+ }
+
+ r = IShellLinkW_QueryInterface( sl, &_IID_IShellLinkDataList, (LPVOID*) &dl );
+ ok(r == S_OK, "IShellLinkW_QueryInterface failed (0x%08x)\n", r);
+
+ if (!dl)
+ {
+ skip("no datalink interface\n");
+ return;
+ }
+
+ flags = 0;
+ r = dl->lpVtbl->GetFlags( dl, &flags );
+ ok( r == S_OK, "GetFlags failed\n");
+ ok( flags == 0, "GetFlags returned wrong flags\n");
+
+ dar = (void*)-1;
+ r = dl->lpVtbl->CopyDataBlock( dl, EXP_DARWIN_ID_SIG, (LPVOID*) &dar );
+ ok( r == E_FAIL, "CopyDataBlock failed\n");
+ ok( dar == NULL, "should be null\n");
+
+ r = IShellLinkW_SetPath(sl, lnk);
+ ok(r == S_OK, "set path failed\n");
+
+ /*
+ * The following crashes:
+ * r = dl->lpVtbl->GetFlags( dl, NULL );
+ */
+
+ flags = 0;
+ r = dl->lpVtbl->GetFlags( dl, &flags );
+ ok( r == S_OK, "GetFlags failed\n");
+ ok( flags == (SLDF_HAS_DARWINID|SLDF_HAS_LOGO3ID),
+ "GetFlags returned wrong flags\n");
+
+ dar = NULL;
+ r = dl->lpVtbl->CopyDataBlock( dl, EXP_DARWIN_ID_SIG, (LPVOID*) &dar );
+ ok( r == S_OK, "CopyDataBlock failed\n");
+
+ ok( dar && ((DATABLOCK_HEADER*)dar)->dwSignature == EXP_DARWIN_ID_SIG, "signature wrong\n");
+ ok( dar && 0==lstrcmpW(dar->szwDarwinID, comp ), "signature wrong\n");
+
+ LocalFree( dar );
+
+ IUnknown_Release( dl );
+ IShellLinkW_Release( sl );
}
START_TEST(shelllink)
{
HRESULT r;
+ HMODULE hmod = GetModuleHandleA("shell32.dll");
+ HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
+
+ pILFree = (fnILFree) GetProcAddress(hmod, (LPSTR)155);
+ pILIsEqual = (fnILIsEqual) GetProcAddress(hmod, (LPSTR)21);
+ pSHILCreateFromPath = (fnSHILCreateFromPath) GetProcAddress(hmod, (LPSTR)28);
+
+ pGetLongPathNameA = (void *)GetProcAddress(hkernel32, "GetLongPathNameA");
r = CoInitialize(NULL);
- ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "CoInitialize failed (0x%08x)\n", r);
if (!SUCCEEDED(r))
return;
test_get_set();
test_load_save();
+ test_datalink();
CoUninitialize();
}
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* TODO:
#include <stdio.h>
#include <assert.h>
+/* Needed to get SEE_MASK_NOZONECHECKS with the PSDK */
+#define NTDDI_WINXPSP1 0x05010100
+#define NTDDI_VERSION NTDDI_WINXPSP1
+
#include "wtypes.h"
#include "winbase.h"
#include "windef.h"
static int myARGC;
static char** myARGV;
static char tmpdir[MAX_PATH];
+static char child_file[MAX_PATH];
+static DLLVERSIONINFO dllver;
-static const char* testfiles[]=
-{
- "%s\\test file.shlexec",
- "%s\\test file.noassoc",
- "%s\\test file.noassoc.shlexec",
- "%s\\test file.shlexec.noassoc",
- "%s\\test_shortcut_shlexec.lnk",
- NULL
-};
+/***
+ *
+ * ShellExecute wrappers
+ *
+ ***/
+static void dump_child(void);
+
+static HANDLE hEvent;
+static void init_event(const char* child_file)
+{
+ char* event_name;
+ event_name=strrchr(child_file, '\\')+1;
+ hEvent=CreateEvent(NULL, FALSE, FALSE, event_name);
+}
static void strcat_param(char* str, const char* param)
{
static char shell_call[2048]="";
static int shell_execute(LPCSTR operation, LPCSTR file, LPCSTR parameters, LPCSTR directory)
{
+ int rc;
+
strcpy(shell_call, "ShellExecute(");
strcat_param(shell_call, operation);
strcat(shell_call, ", ");
if (winetest_debug > 1)
trace("%s\n", shell_call);
+ DeleteFile(child_file);
SetLastError(0xcafebabe);
+
/* FIXME: We cannot use ShellExecuteEx() here because if there is no
* association it displays the 'Open With' dialog and I could not find
* a flag to prevent this.
*/
- return (int)ShellExecute(NULL, operation, file, parameters, directory,
- SW_SHOWNORMAL);
+ rc=(int)ShellExecute(NULL, operation, file, parameters, directory,
+ SW_SHOWNORMAL);
+
+ if (rc > 32)
+ {
+ int wait_rc;
+ wait_rc=WaitForSingleObject(hEvent, 5000);
+ ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait_rc);
+ }
+ /* The child process may have changed the result file, so let profile
+ * functions know about it
+ */
+ WritePrivateProfileStringA(NULL, NULL, NULL, child_file);
+ if (rc > 32)
+ dump_child();
+
+ return rc;
}
static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file,
trace("%s\n", shell_call);
sei.cbSize=sizeof(sei);
- sei.fMask=mask;
+ sei.fMask=SEE_MASK_NOCLOSEPROCESS | mask;
sei.hwnd=NULL;
sei.lpVerb=operation;
sei.lpFile=file;
sei.lpClass=NULL;
sei.hkeyClass=NULL;
sei.dwHotKey=0;
- sei.hIcon=NULL;
+ U(sei).hIcon=NULL;
+ sei.hProcess=NULL; /* Out */
+ DeleteFile(child_file);
SetLastError(0xcafebabe);
success=ShellExecuteEx(&sei);
rc=(int)sei.hInstApp;
- ok((success && rc >= 32) || (!success && rc < 32),
+ ok((success && rc > 32) || (!success && rc <= 32),
"%s rc=%d and hInstApp=%d is not allowed\n", shell_call, success, rc);
+
+ if (rc > 32)
+ {
+ int wait_rc;
+ if (sei.hProcess!=NULL)
+ {
+ wait_rc=WaitForSingleObject(sei.hProcess, 5000);
+ ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject(hProcess) returned %d\n", wait_rc);
+ }
+ wait_rc=WaitForSingleObject(hEvent, 5000);
+ ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait_rc);
+ }
+ /* The child process may have changed the result file, so let profile
+ * functions know about it
+ */
+ WritePrivateProfileStringA(NULL, NULL, NULL, child_file);
+ if (rc > 32)
+ dump_child();
+
return rc;
}
+
+
+/***
+ *
+ * Functions to create / delete associations wrappers
+ *
+ ***/
+
static void create_test_association(const char* extension)
{
HKEY hkey, hkey_shell;
rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, NULL, 0, KEY_SET_VALUE,
NULL, &hkey, NULL);
assert(rc==ERROR_SUCCESS);
- rc=RegSetValueEx(hkey, NULL, 0, REG_SZ, class, strlen(class)+1);
+ rc=RegSetValueEx(hkey, NULL, 0, REG_SZ, (LPBYTE) class, strlen(class)+1);
assert(rc==ERROR_SUCCESS);
CloseHandle(hkey);
SHDeleteKey(HKEY_CLASSES_ROOT, extension);
}
-static void create_test_verb(const char* extension, const char* verb)
+static void create_test_verb_dde(const char* extension, const char* verb,
+ int rawcmd, const char* cmdtail, const char *ddeexec,
+ const char *application, const char *topic,
+ const char *ifexec)
{
HKEY hkey_shell, hkey_verb, hkey_cmd;
char shell[MAX_PATH];
NULL, &hkey_cmd, NULL);
assert(rc==ERROR_SUCCESS);
- cmd=malloc(strlen(argv0)+13+1);
- sprintf(cmd,"%s shlexec \"%%1\"", argv0);
- rc=RegSetValueEx(hkey_cmd, NULL, 0, REG_SZ, cmd, strlen(cmd)+1);
- assert(rc==ERROR_SUCCESS);
+ if (rawcmd)
+ {
+ rc=RegSetValueEx(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmdtail, strlen(cmdtail)+1);
+ }
+ else
+ {
+ cmd=malloc(strlen(argv0)+10+strlen(child_file)+2+strlen(cmdtail)+1);
+ sprintf(cmd,"%s shlexec \"%s\" %s", argv0, child_file, cmdtail);
+ rc=RegSetValueEx(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmd, strlen(cmd)+1);
+ assert(rc==ERROR_SUCCESS);
+ free(cmd);
+ }
+
+ if (ddeexec)
+ {
+ HKEY hkey_ddeexec, hkey_application, hkey_topic, hkey_ifexec;
+
+ rc=RegCreateKeyEx(hkey_verb, "ddeexec", 0, NULL, 0, KEY_SET_VALUE |
+ KEY_CREATE_SUB_KEY, NULL, &hkey_ddeexec, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegSetValueEx(hkey_ddeexec, NULL, 0, REG_SZ, (LPBYTE)ddeexec,
+ strlen(ddeexec)+1);
+ assert(rc==ERROR_SUCCESS);
+ if (application)
+ {
+ rc=RegCreateKeyEx(hkey_ddeexec, "application", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_application, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegSetValueEx(hkey_application, NULL, 0, REG_SZ, (LPBYTE)application,
+ strlen(application)+1);
+ assert(rc==ERROR_SUCCESS);
+ CloseHandle(hkey_application);
+ }
+ if (topic)
+ {
+ rc=RegCreateKeyEx(hkey_ddeexec, "topic", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_topic, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegSetValueEx(hkey_topic, NULL, 0, REG_SZ, (LPBYTE)topic,
+ strlen(topic)+1);
+ assert(rc==ERROR_SUCCESS);
+ CloseHandle(hkey_topic);
+ }
+ if (ifexec)
+ {
+ rc=RegCreateKeyEx(hkey_ddeexec, "ifexec", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_ifexec, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegSetValueEx(hkey_ifexec, NULL, 0, REG_SZ, (LPBYTE)ifexec,
+ strlen(ifexec)+1);
+ assert(rc==ERROR_SUCCESS);
+ CloseHandle(hkey_ifexec);
+ }
+ CloseHandle(hkey_ddeexec);
+ }
- free(cmd);
CloseHandle(hkey_shell);
CloseHandle(hkey_verb);
CloseHandle(hkey_cmd);
}
+static void create_test_verb(const char* extension, const char* verb,
+ int rawcmd, const char* cmdtail)
+{
+ create_test_verb_dde(extension, verb, rawcmd, cmdtail, NULL, NULL,
+ NULL, NULL);
+}
+
+/***
+ *
+ * Functions to check that the child process was started just right
+ * (borrowed from dlls/kernel32/tests/process.c)
+ *
+ ***/
+
+static const char* encodeA(const char* str)
+{
+ static char encoded[2*1024+1];
+ char* ptr;
+ size_t len,i;
+
+ if (!str) return "";
+ len = strlen(str) + 1;
+ if (len >= sizeof(encoded)/2)
+ {
+ fprintf(stderr, "string is too long!\n");
+ assert(0);
+ }
+ ptr = encoded;
+ for (i = 0; i < len; i++)
+ sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
+ ptr[2 * len] = '\0';
+ return ptr;
+}
+
+static unsigned decode_char(char c)
+{
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+ assert(c >= 'A' && c <= 'F');
+ return c - 'A' + 10;
+}
+
+static char* decodeA(const char* str)
+{
+ static char decoded[1024];
+ char* ptr;
+ size_t len,i;
+
+ len = strlen(str) / 2;
+ if (!len--) return NULL;
+ if (len >= sizeof(decoded))
+ {
+ fprintf(stderr, "string is too long!\n");
+ assert(0);
+ }
+ ptr = decoded;
+ for (i = 0; i < len; i++)
+ ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
+ ptr[len] = '\0';
+ return ptr;
+}
+
+static void childPrintf(HANDLE h, const char* fmt, ...)
+{
+ va_list valist;
+ char buffer[1024];
+ DWORD w;
+
+ va_start(valist, fmt);
+ vsprintf(buffer, fmt, valist);
+ va_end(valist);
+ WriteFile(h, buffer, strlen(buffer), &w, NULL);
+}
+
+static void doChild(int argc, char** argv)
+{
+ char* filename;
+ HANDLE hFile;
+ int i;
+
+ filename=argv[2];
+ hFile=CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return;
+
+ /* Arguments */
+ childPrintf(hFile, "[Arguments]\r\n");
+ if (winetest_debug > 2)
+ trace("argcA=%d\n", argc);
+ childPrintf(hFile, "argcA=%d\r\n", argc);
+ for (i = 0; i < argc; i++)
+ {
+ if (winetest_debug > 2)
+ trace("argvA%d=%s\n", i, argv[i]);
+ childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i]));
+ }
+ CloseHandle(hFile);
+
+ init_event(filename);
+ SetEvent(hEvent);
+ CloseHandle(hEvent);
+}
+
+static char* getChildString(const char* sect, const char* key)
+{
+ char buf[1024];
+ char* ret;
+
+ GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), child_file);
+ if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
+ assert(!(strlen(buf) & 1));
+ ret = decodeA(buf);
+ return ret;
+}
+
+static void dump_child(void)
+{
+ if (winetest_debug > 1)
+ {
+ char key[18];
+ char* str;
+ int i, c;
+
+ c=GetPrivateProfileIntA("Arguments", "argcA", -1, child_file);
+ trace("argcA=%d\n",c);
+ for (i=0;i<c;i++)
+ {
+ sprintf(key, "argvA%d", i);
+ str=getChildString("Arguments", key);
+ trace("%s=%s\n", key, str);
+ }
+ }
+}
+
+static int StrCmpPath(const char* s1, const char* s2)
+{
+ if (!s1 && !s2) return 0;
+ if (!s2) return 1;
+ if (!s1) return -1;
+ while (*s1)
+ {
+ if (!*s2)
+ {
+ if (*s1=='.')
+ s1++;
+ return (*s1-*s2);
+ }
+ if ((*s1=='/' || *s1=='\\') && (*s2=='/' || *s2=='\\'))
+ {
+ while (*s1=='/' || *s1=='\\')
+ s1++;
+ while (*s2=='/' || *s2=='\\')
+ s2++;
+ }
+ else if (toupper(*s1)==toupper(*s2))
+ {
+ s1++;
+ s2++;
+ }
+ else
+ {
+ return (*s1-*s2);
+ }
+ }
+ if (*s2=='.')
+ s2++;
+ if (*s2)
+ return -1;
+ return 0;
+}
+
+static int _okChildString(const char* file, int line, const char* key, const char* expected)
+{
+ char* result;
+ result=getChildString("Arguments", key);
+ return ok_(file, line)(lstrcmpiA(result, expected) == 0,
+ "%s expected '%s', got '%s'\n", key, expected, result);
+}
+
+static int _okChildPath(const char* file, int line, const char* key, const char* expected)
+{
+ char* result;
+ result=getChildString("Arguments", key);
+ return ok_(file, line)(StrCmpPath(result, expected) == 0,
+ "%s expected '%s', got '%s'\n", key, expected, result);
+}
+
+static int _okChildInt(const char* file, int line, const char* key, int expected)
+{
+ INT result;
+ result=GetPrivateProfileIntA("Arguments", key, expected, child_file);
+ return ok_(file, line)(result == expected,
+ "%s expected %d, but got %d\n", key, expected, result);
+}
+
+#define okChildString(key, expected) _okChildString(__FILE__, __LINE__, (key), (expected))
+#define okChildPath(key, expected) _okChildPath(__FILE__, __LINE__, (key), (expected))
+#define okChildInt(key, expected) _okChildInt(__FILE__, __LINE__, (key), (expected))
+
+
+
+/***
+ *
+ * Tests
+ *
+ ***/
+
+static const char* testfiles[]=
+{
+ "%s\\test file.shlexec",
+ "%s\\%%nasty%% $file.shlexec",
+ "%s\\test file.noassoc",
+ "%s\\test file.noassoc.shlexec",
+ "%s\\test file.shlexec.noassoc",
+ "%s\\test_shortcut_shlexec.lnk",
+ "%s\\test_shortcut_exe.lnk",
+ "%s\\test file.shl",
+ "%s\\test file.shlfoo",
+ "%s\\test file.sfe",
+ "%s\\masked file.shlexec",
+ "%s\\masked",
+ "%s\\test file.sde",
+ "%s\\test file.exe",
+ "%s\\test2.exe",
+ NULL
+};
typedef struct
{
- char* basename;
- int rc;
+ const char* verb;
+ const char* basename;
int todo;
+ int rc;
} filename_tests_t;
static filename_tests_t filename_tests[]=
{
/* Test bad / nonexistent filenames */
- {"%s\\nonexistent.shlexec", ERROR_FILE_NOT_FOUND, 1},
- {"%s\\nonexistent.noassoc", ERROR_FILE_NOT_FOUND, 1},
+ {NULL, "%s\\nonexistent.shlexec", 0x11, SE_ERR_FNF},
+ {NULL, "%s\\nonexistent.noassoc", 0x11, SE_ERR_FNF},
/* Standard tests */
- {"%s\\test file.shlexec", 0, 0},
- {"%s\\test file.shlexec.", 0, 0},
- {"%s/test file.shlexec", 0, 0},
+ {NULL, "%s\\test file.shlexec", 0x0, 33},
+ {NULL, "%s\\test file.shlexec.", 0x0, 33},
+ {NULL, "%s\\%%nasty%% $file.shlexec", 0x0, 33},
+ {NULL, "%s/test file.shlexec", 0x0, 33},
/* Test filenames with no association */
- {"%s\\test file.noassoc", SE_ERR_NOASSOC, 0},
+ {NULL, "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC},
/* Test double extensions */
- {"%s\\test file.noassoc.shlexec", 0, 0},
- {"%s\\test file.shlexec.noassoc", SE_ERR_NOASSOC, 0},
+ {NULL, "%s\\test file.noassoc.shlexec", 0x0, 33},
+ {NULL, "%s\\test file.shlexec.noassoc", 0x0, SE_ERR_NOASSOC},
+
+ /* Test alternate verbs */
+ {"LowerL", "%s\\nonexistent.shlexec", 0x11, SE_ERR_FNF},
+ {"LowerL", "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC},
+
+ {"QuotedLowerL", "%s\\test file.shlexec", 0x0, 33},
+ {"QuotedUpperL", "%s\\test file.shlexec", 0x0, 33},
- /* Test shortcuts */
- {"%s\\test_shortcut_shlexec.lnk", 0, 0},
+ /* Test file masked due to space */
+ {NULL, "%s\\masked file.shlexec", 0x1, 33},
+ /* Test if quoting prevents the masking */
+ {NULL, "%s\\masked file.shlexec", 0x40, 33},
- {NULL, 0, 0}
+ {NULL, NULL, 0}
};
-static void test_filename()
+static filename_tests_t noquotes_tests[]=
+{
+ /* Test unquoted '%1' thingies */
+ {"NoQuotes", "%s\\test file.shlexec", 0xa, 33},
+ {"LowerL", "%s\\test file.shlexec", 0xa, 33},
+ {"UpperL", "%s\\test file.shlexec", 0xa, 33},
+
+ {NULL, NULL, 0}
+};
+
+static void test_filename(void)
{
char filename[MAX_PATH];
const filename_tests_t* test;
- HMODULE hdll;
- DLLVERSIONINFO dllver;
- HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO*);
char* c;
int rc;
c++;
}
}
- rc=shell_execute(NULL, filename, NULL, NULL);
- if (test->rc==0)
+ if ((test->todo & 0x40)==0)
+ {
+ rc=shell_execute(test->verb, filename, NULL, NULL);
+ }
+ else
+ {
+ char quoted[MAX_PATH + 2];
+ sprintf(quoted, "\"%s\"", filename);
+ rc=shell_execute(test->verb, quoted, NULL, NULL);
+ }
+ if (rc > 32)
+ rc=33;
+ if ((test->todo & 0x1)==0)
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ else todo_wine
{
- if (test->todo)
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ if (rc == 33)
+ {
+ const char* verb;
+ if ((test->todo & 0x2)==0)
{
- todo_wine
- {
- ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call,
- rc, GetLastError());
- }
+ okChildInt("argcA", 5);
}
- else
+ else todo_wine
+ {
+ okChildInt("argcA", 5);
+ }
+ verb=(test->verb ? test->verb : "Open");
+ if ((test->todo & 0x4)==0)
{
- ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call,
- rc, GetLastError());
+ okChildString("argvA3", verb);
+ }
+ else todo_wine
+ {
+ okChildString("argvA3", verb);
+ }
+ if ((test->todo & 0x8)==0)
+ {
+ okChildPath("argvA4", filename);
+ }
+ else todo_wine
+ {
+ okChildPath("argvA4", filename);
}
}
- else
+ test++;
+ }
+
+ test=noquotes_tests;
+ while (test->basename)
+ {
+ sprintf(filename, test->basename, tmpdir);
+ rc=shell_execute(test->verb, filename, NULL, NULL);
+ if (rc > 32)
+ rc=33;
+ if ((test->todo & 0x1)==0)
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ else todo_wine
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ if (rc==0)
{
- if (test->todo)
+ int count;
+ const char* verb;
+ char* str;
+
+ verb=(test->verb ? test->verb : "Open");
+ if ((test->todo & 0x4)==0)
+ {
+ okChildString("argvA3", verb);
+ }
+ else todo_wine
+ {
+ okChildString("argvA3", verb);
+ }
+
+ count=4;
+ str=filename;
+ while (1)
{
- todo_wine
+ char attrib[18];
+ char* space;
+ space=strchr(str, ' ');
+ if (space)
+ *space='\0';
+ sprintf(attrib, "argvA%d", count);
+ if ((test->todo & 0x8)==0)
+ {
+ okChildPath(attrib, str);
+ }
+ else todo_wine
{
- ok(rc==test->rc, "%s returned %d\n", shell_call, rc);
+ okChildPath(attrib, str);
}
+ count++;
+ if (!space)
+ break;
+ str=space+1;
}
- else
+ if ((test->todo & 0x2)==0)
+ {
+ okChildInt("argcA", count);
+ }
+ else todo_wine
{
- ok(rc==test->rc, "%s returned %d\n", shell_call, rc);
+ okChildInt("argcA", count);
}
}
test++;
}
- hdll=GetModuleHandleA("shell32.dll");
- pDllGetVersion=(void*)GetProcAddress(hdll, "DllGetVersion");
- if (pDllGetVersion)
+ if (dllver.dwMajorVersion != 0)
{
- dllver.cbSize=sizeof(dllver);
- pDllGetVersion(&dllver);
- trace("major=%ld minor=%ld build=%ld platform=%ld\n",
- dllver.dwMajorVersion, dllver.dwMinorVersion,
- dllver.dwBuildNumber, dllver.dwPlatformID);
-
/* The more recent versions of shell32.dll accept quoted filenames
* while older ones (e.g. 4.00) don't. Still we want to test this
* because IE 6 depends on the new behavior.
*/
sprintf(filename, "\"%s\\test file.shlexec\"", tmpdir);
rc=shell_execute(NULL, filename, NULL, NULL);
- ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call, rc,
+ ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc,
GetLastError());
+ okChildInt("argcA", 5);
+ okChildString("argvA3", "Open");
+ sprintf(filename, "%s\\test file.shlexec", tmpdir);
+ okChildPath("argvA4", filename);
+ }
+}
+
+static void test_find_executable(void)
+{
+ char filename[MAX_PATH];
+ char command[MAX_PATH];
+ const filename_tests_t* test;
+ int rc;
+
+ create_test_association(".sfe");
+ create_test_verb(".sfe", "Open", 1, "%1");
+
+ /* Don't test FindExecutable(..., NULL), it always crashes */
+
+ strcpy(command, "your word");
+ rc=(int)FindExecutableA(NULL, NULL, command);
+ ok(rc == SE_ERR_FNF || rc > 32 /* nt4 */, "FindExecutable(NULL) returned %d\n", rc);
+ ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command);
+
+ strcpy(command, "your word");
+ rc=(int)FindExecutableA(tmpdir, NULL, command);
+ ok(rc == SE_ERR_NOASSOC /* >= win2000 */ || rc > 32 /* win98, nt4 */, "FindExecutable(NULL) returned %d\n", rc);
+ ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command);
+
+ sprintf(filename, "%s\\test file.sfe", tmpdir);
+ rc=(int)FindExecutableA(filename, NULL, command);
+ ok(rc > 32, "FindExecutable(%s) returned %d\n", filename, rc);
+ /* Depending on the platform, command could be '%1' or 'test file.sfe' */
+
+ rc=(int)FindExecutableA("test file.sfe", tmpdir, command);
+ ok(rc > 32, "FindExecutable(%s) returned %d\n", filename, rc);
- if (dllver.dwMajorVersion>=6)
+ rc=(int)FindExecutableA("test file.sfe", NULL, command);
+ todo_wine ok(rc == SE_ERR_FNF, "FindExecutable(%s) returned %d\n", filename, rc);
+
+ delete_test_association(".sfe");
+
+ create_test_association(".shl");
+ create_test_verb(".shl", "Open", 0, "Open");
+
+ sprintf(filename, "%s\\test file.shl", tmpdir);
+ rc=(int)FindExecutableA(filename, NULL, command);
+ ok(rc == SE_ERR_FNF /* NT4 */ || rc > 32, "FindExecutable(%s) returned %d\n", filename, rc);
+
+ sprintf(filename, "%s\\test file.shlfoo", tmpdir);
+ rc=(int)FindExecutableA(filename, NULL, command);
+
+ delete_test_association(".shl");
+
+ if (rc > 32)
+ {
+ /* On Windows XP and 2003 FindExecutable() is completely broken.
+ * Probably what it does is convert the filename to 8.3 format,
+ * which as a side effect converts the '.shlfoo' extension to '.shl',
+ * and then tries to find an association for '.shl'. This means it
+ * will normally fail on most extensions with more than 3 characters,
+ * like '.mpeg', etc.
+ * Also it means we cannot do any other test.
+ */
+ trace("FindExecutable() is broken -> skipping 4+ character extension tests\n");
+ return;
+ }
+
+ test=filename_tests;
+ while (test->basename)
+ {
+ sprintf(filename, test->basename, tmpdir);
+ if (strchr(filename, '/'))
{
- /* Recent versions of shell32.dll accept '/'s in shortcut paths.
- * Older versions don't or are quite buggy in this regard.
- */
- sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
+ char* c;
c=filename;
while (*c)
{
*c='/';
c++;
}
- rc=shell_execute(NULL, filename, NULL, NULL);
- todo_wine {
- ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call, rc,
- GetLastError());
+ }
+ /* Win98 does not '\0'-terminate command! */
+ memset(command, '\0', sizeof(command));
+ rc=(int)FindExecutableA(filename, NULL, command);
+ if (rc > 32)
+ rc=33;
+ if ((test->todo & 0x10)==0)
+ {
+ ok(rc==test->rc, "FindExecutable(%s) failed: rc=%d\n", filename, rc);
+ }
+ else todo_wine
+ {
+ ok(rc==test->rc, "FindExecutable(%s) failed: rc=%d\n", filename, rc);
+ }
+ if (rc > 32)
+ {
+ int equal;
+ equal=strcmp(command, argv0) == 0 ||
+ /* NT4 returns an extra 0x8 character! */
+ (strlen(command) == strlen(argv0)+1 && strncmp(command, argv0, strlen(argv0)) == 0);
+ if ((test->todo & 0x20)==0)
+ {
+ ok(equal, "FindExecutable(%s) returned command='%s' instead of '%s'\n",
+ filename, command, argv0);
+ }
+ else todo_wine
+ {
+ ok(equal, "FindExecutable(%s) returned command='%s' instead of '%s'\n",
+ filename, command, argv0);
+ }
+ }
+ test++;
+ }
+}
+
+
+static filename_tests_t lnk_tests[]=
+{
+ /* Pass bad / nonexistent filenames as a parameter */
+ {NULL, "%s\\nonexistent.shlexec", 0xa, 33},
+ {NULL, "%s\\nonexistent.noassoc", 0xa, 33},
+
+ /* Pass regular paths as a parameter */
+ {NULL, "%s\\test file.shlexec", 0xa, 33},
+ {NULL, "%s/%%nasty%% $file.shlexec", 0xa, 33},
+
+ /* Pass filenames with no association as a parameter */
+ {NULL, "%s\\test file.noassoc", 0xa, 33},
+
+ {NULL, NULL, 0}
+};
+
+static void test_lnks(void)
+{
+ char filename[MAX_PATH];
+ char params[MAX_PATH];
+ const filename_tests_t* test;
+ int rc;
+
+ sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL);
+ ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc,
+ GetLastError());
+ okChildInt("argcA", 5);
+ okChildString("argvA3", "Open");
+ sprintf(filename, "%s\\test file.shlexec", tmpdir);
+ okChildPath("argvA4", filename);
+
+ sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL);
+ ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc,
+ GetLastError());
+ okChildInt("argcA", 4);
+ okChildString("argvA3", "Lnk");
+
+ if (dllver.dwMajorVersion>=6)
+ {
+ char* c;
+ /* Recent versions of shell32.dll accept '/'s in shortcut paths.
+ * Older versions don't or are quite buggy in this regard.
+ */
+ sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
+ c=filename;
+ while (*c)
+ {
+ if (*c=='\\')
+ *c='/';
+ c++;
+ }
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL);
+ ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc,
+ GetLastError());
+ okChildInt("argcA", 4);
+ okChildString("argvA3", "Lnk");
+ }
+
+ sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
+ test=lnk_tests;
+ while (test->basename)
+ {
+ params[0]='\"';
+ sprintf(params+1, test->basename, tmpdir);
+ strcat(params,"\"");
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, params,
+ NULL);
+ if (rc > 32)
+ rc=33;
+ if ((test->todo & 0x1)==0)
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ else todo_wine
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ if (rc==0)
+ {
+ if ((test->todo & 0x2)==0)
+ {
+ okChildInt("argcA", 5);
+ }
+ else
+ {
+ okChildInt("argcA", 5);
+ }
+ if ((test->todo & 0x4)==0)
+ {
+ okChildString("argvA3", "Lnk");
+ }
+ else todo_wine
+ {
+ okChildString("argvA3", "Lnk");
+ }
+ sprintf(params, test->basename, tmpdir);
+ if ((test->todo & 0x8)==0)
+ {
+ okChildPath("argvA4", params);
+ }
+ else
+ {
+ okChildPath("argvA4", params);
}
}
+ test++;
}
}
-static void test_exes()
+static void test_exes(void)
+{
+ char filename[MAX_PATH];
+ char params[1024];
+ int rc;
+
+ sprintf(params, "shlexec \"%s\" Exec", child_file);
+
+ /* We need NOZONECHECKS on Win2003 to block a dialog */
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, params,
+ NULL);
+ ok(rc > 32, "%s returned %d\n", shell_call, rc);
+ okChildInt("argcA", 4);
+ okChildString("argvA3", "Exec");
+
+ sprintf(filename, "%s\\test file.noassoc", tmpdir);
+ if (CopyFile(argv0, filename, FALSE))
+ {
+ rc=shell_execute(NULL, filename, params, NULL);
+ todo_wine {
+ ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%d\n", shell_call, rc);
+ }
+ }
+}
+
+static void test_exes_long(void)
{
char filename[MAX_PATH];
+ char params[2024];
+ char longparam[MAX_PATH];
int rc;
+ for (rc = 0; rc < MAX_PATH; rc++)
+ longparam[rc]='a'+rc%26;
+ longparam[MAX_PATH-1]=0;
+
+
+ sprintf(params, "shlexec \"%s\" %s", child_file,longparam);
+
/* We need NOZONECHECKS on Win2003 to block a dialog */
- rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, "shlexec -nop",
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, params,
NULL);
- ok(rc>=32, "%s returned %d\n", shell_call, rc);
+ ok(rc > 32, "%s returned %d\n", shell_call, rc);
+ okChildInt("argcA", 4);
+ okChildString("argvA3", longparam);
sprintf(filename, "%s\\test file.noassoc", tmpdir);
if (CopyFile(argv0, filename, FALSE))
{
- rc=shell_execute(NULL, filename, "shlexec -nop", NULL);
+ rc=shell_execute(NULL, filename, params, NULL);
todo_wine {
ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%d\n", shell_call, rc);
}
}
}
+typedef struct
+{
+ const char* command;
+ const char* ddeexec;
+ const char* application;
+ const char* topic;
+ const char* ifexec;
+ int expectedArgs;
+ const char* expectedDdeExec;
+ int todo;
+ int rc;
+} dde_tests_t;
+
+static dde_tests_t dde_tests[] =
+{
+ /* Test passing and not passing command-line
+ * argument, no DDE */
+ {"", NULL, NULL, NULL, NULL, FALSE, "", 0x0, 33},
+ {"\"%1\"", NULL, NULL, NULL, NULL, TRUE, "", 0x0, 33},
+
+ /* Test passing and not passing command-line
+ * argument, with DDE */
+ {"", "[open(\"%1\")]", "shlexec", "dde", NULL, FALSE, "[open(\"%s\")]", 0x0, 33},
+ {"\"%1\"", "[open(\"%1\")]", "shlexec", "dde", NULL, TRUE, "[open(\"%s\")]", 0x0, 33},
+
+ /* Test unquoted %1 in command and ddeexec
+ * (test filename has space) */
+ {"%1", "[open(%1)]", "shlexec", "dde", NULL, 2, "[open(%s)]", 0x0, 33},
+
+ /* Test ifexec precedence over ddeexec */
+ {"", "[open(\"%1\")]", "shlexec", "dde", "[ifexec(\"%1\")]", FALSE, "[ifexec(\"%s\")]", 0x0, 33},
+
+ /* Test default DDE topic */
+ {"", "[open(\"%1\")]", "shlexec", NULL, NULL, FALSE, "[open(\"%s\")]", 0x0, 33},
+
+ /* Test default DDE application */
+ {"", "[open(\"%1\")]", NULL, "dde", NULL, FALSE, "[open(\"%s\")]", 0x0, 33},
+
+ {NULL, NULL, NULL, NULL, NULL, 0, 0x0, 0}
+};
+
+static DWORD ddeInst;
+static HSZ hszTopic;
+static char ddeExec[MAX_PATH], ddeApplication[MAX_PATH];
+static BOOL denyNextConnection;
+
+static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv,
+ HSZ hsz1, HSZ hsz2, HDDEDATA hData,
+ ULONG_PTR dwData1, ULONG_PTR dwData2)
+{
+ DWORD size = 0;
+
+ if (winetest_debug > 2)
+ trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
+ uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
+
+ switch (uType)
+ {
+ case XTYP_CONNECT:
+ if (!DdeCmpStringHandles(hsz1, hszTopic))
+ {
+ if (denyNextConnection)
+ denyNextConnection = FALSE;
+ else
+ {
+ size = DdeQueryString(ddeInst, hsz2, ddeApplication, MAX_PATH, CP_WINANSI);
+ assert(size < MAX_PATH);
+ return (HDDEDATA)TRUE;
+ }
+ }
+ return (HDDEDATA)FALSE;
+
+ case XTYP_EXECUTE:
+ size = DdeGetData(hData, (LPBYTE)ddeExec, MAX_PATH, 0L);
+ assert(size < MAX_PATH);
+ DdeFreeDataHandle(hData);
+ return (HDDEDATA)DDE_FACK;
+
+ default:
+ return NULL;
+ }
+}
+
+typedef struct
+{
+ char *filename;
+ DWORD threadIdParent;
+} dde_thread_info_t;
-static void init_test()
+static DWORD CALLBACK ddeThread(LPVOID arg)
+{
+ dde_thread_info_t *info = (dde_thread_info_t *)arg;
+ assert(info && info->filename);
+ PostThreadMessage(info->threadIdParent,
+ WM_QUIT,
+ shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, info->filename, NULL, NULL),
+ 0L);
+ ExitThread(0);
+}
+
+/* ShellExecute won't successfully send DDE commands to console applications after starting them,
+ * so we run a DDE server in this application, deny the first connection request to make
+ * ShellExecute start the application, and then process the next DDE connection in this application
+ * to see the execute command that is sent. */
+static void test_dde(void)
+{
+ char filename[MAX_PATH], defApplication[MAX_PATH];
+ HSZ hszApplication;
+ dde_thread_info_t info = { filename, GetCurrentThreadId() };
+ const dde_tests_t* test;
+ char params[1024];
+ DWORD threadId;
+ MSG msg;
+ int rc;
+
+ ddeInst = 0;
+ rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES |
+ CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0L);
+ assert(rc == DMLERR_NO_ERROR);
+
+ sprintf(filename, "%s\\test file.sde", tmpdir);
+
+ /* Default service is application name minus path and extension */
+ strcpy(defApplication, strrchr(argv0, '\\')+1);
+ *strchr(defApplication, '.') = 0;
+
+ test = dde_tests;
+ while (test->command)
+ {
+ create_test_association(".sde");
+ create_test_verb_dde(".sde", "Open", 0, test->command, test->ddeexec,
+ test->application, test->topic, test->ifexec);
+ hszApplication = DdeCreateStringHandleA(ddeInst, test->application ?
+ test->application : defApplication, CP_WINANSI);
+ hszTopic = DdeCreateStringHandleA(ddeInst, test->topic ? test->topic : SZDDESYS_TOPIC,
+ CP_WINANSI);
+ assert(hszApplication && hszTopic);
+ assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_REGISTER));
+ denyNextConnection = TRUE;
+ ddeExec[0] = 0;
+
+ assert(CreateThread(NULL, 0, ddeThread, (LPVOID)&info, 0, &threadId));
+ while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
+ rc = msg.wParam > 32 ? 33 : msg.wParam;
+ if ((test->todo & 0x1)==0)
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ else todo_wine
+ {
+ ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ if (rc == 33)
+ {
+ if ((test->todo & 0x2)==0)
+ {
+ okChildInt("argcA", test->expectedArgs + 3);
+ }
+ else todo_wine
+ {
+ okChildInt("argcA", test->expectedArgs + 3);
+ }
+ if (test->expectedArgs == 1)
+ {
+ if ((test->todo & 0x4) == 0)
+ {
+ okChildPath("argvA3", filename);
+ }
+ else todo_wine
+ {
+ okChildPath("argvA3", filename);
+ }
+ }
+ if ((test->todo & 0x8) == 0)
+ {
+ sprintf(params, test->expectedDdeExec, filename);
+ ok(StrCmpPath(params, ddeExec) == 0,
+ "ddeexec expected '%s', got '%s'\n", params, ddeExec);
+ }
+ else todo_wine
+ {
+ sprintf(params, test->expectedDdeExec, filename);
+ ok(StrCmpPath(params, ddeExec) == 0,
+ "ddeexec expected '%s', got '%s'\n", params, ddeExec);
+ }
+ }
+
+ assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_UNREGISTER));
+ assert(DdeFreeStringHandle(ddeInst, hszTopic));
+ assert(DdeFreeStringHandle(ddeInst, hszApplication));
+ delete_test_association(".sde");
+ test++;
+ }
+
+ assert(DdeUninitialize(ddeInst));
+}
+
+#define DDE_DEFAULT_APP_VARIANTS 2
+typedef struct
+{
+ const char* command;
+ const char* expectedDdeApplication[DDE_DEFAULT_APP_VARIANTS];
+ int todo;
+ int rc[DDE_DEFAULT_APP_VARIANTS];
+} dde_default_app_tests_t;
+
+static dde_default_app_tests_t dde_default_app_tests[] =
+{
+ /* Windows XP and 98 handle default DDE app names in different ways.
+ * The application name we see in the first test determines the pattern
+ * of application names and return codes we will look for. */
+
+ /* Test unquoted existing filename with a space */
+ {"%s\\test file.exe", {"test file", "test"}, 0x0, {33, 33}},
+ {"%s\\test file.exe param", {"test file", "test"}, 0x0, {33, 33}},
+
+ /* Test quoted existing filename with a space */
+ {"\"%s\\test file.exe\"", {"test file", "test file"}, 0x0, {33, 33}},
+ {"\"%s\\test file.exe\" param", {"test file", "test file"}, 0x0, {33, 33}},
+
+ /* Test unquoted filename with a space that doesn't exist, but
+ * test2.exe does */
+ {"%s\\test2 file.exe", {"test2", "test2"}, 0x0, {33, 33}},
+ {"%s\\test2 file.exe param", {"test2", "test2"}, 0x0, {33, 33}},
+
+ /* Test quoted filename with a space that does not exist */
+ {"\"%s\\test2 file.exe\"", {"", "test2 file"}, 0x0, {5, 33}},
+ {"\"%s\\test2 file.exe\" param", {"", "test2 file"}, 0x0, {5, 33}},
+
+ /* Test filename supplied without the extension */
+ {"%s\\test2", {"test2", "test2"}, 0x0, {33, 33}},
+ {"%s\\test2 param", {"test2", "test2"}, 0x0, {33, 33}},
+
+ /* Test an unquoted nonexistent filename */
+ {"%s\\notexist.exe", {"", "notexist"}, 0x0, {5, 33}},
+ {"%s\\notexist.exe param", {"", "notexist"}, 0x0, {5, 33}},
+
+ /* Test an application that will be found on the path */
+ {"cmd", {"cmd", "cmd"}, 0x0, {33, 33}},
+ {"cmd param", {"cmd", "cmd"}, 0x0, {33, 33}},
+
+ /* Test an application that will not be found on the path */
+ {"xyzwxyzwxyz", {"", "xyzwxyzwxyz"}, 0x0, {5, 33}},
+ {"xyzwxyzwxyz param", {"", "xyzwxyzwxyz"}, 0x0, {5, 33}},
+
+ {NULL, {NULL}, 0, {0}}
+};
+
+static void test_dde_default_app(void)
{
+ char filename[MAX_PATH];
+ HSZ hszApplication;
+ dde_thread_info_t info = { filename, GetCurrentThreadId() };
+ const dde_default_app_tests_t* test;
+ char params[1024];
+ DWORD threadId;
+ MSG msg;
+ int rc, which = 0;
+
+ ddeInst = 0;
+ rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES |
+ CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0L);
+ assert(rc == DMLERR_NO_ERROR);
+
+ sprintf(filename, "%s\\test file.sde", tmpdir);
+
+ /* It is strictly not necessary to register an application name here, but wine's
+ * DdeNameService implementation complains if 0L is passed instead of
+ * hszApplication with DNS_FILTEROFF */
+ hszApplication = DdeCreateStringHandleA(ddeInst, "shlexec", CP_WINANSI);
+ hszTopic = DdeCreateStringHandleA(ddeInst, "shlexec", CP_WINANSI);
+ assert(hszApplication && hszTopic);
+ assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_REGISTER | DNS_FILTEROFF));
+
+ test = dde_default_app_tests;
+ while (test->command)
+ {
+ create_test_association(".sde");
+ sprintf(params, test->command, tmpdir);
+ create_test_verb_dde(".sde", "Open", 1, params, "[test]", NULL,
+ "shlexec", NULL);
+ denyNextConnection = FALSE;
+ ddeApplication[0] = 0;
+
+ /* No application will be run as we will respond to the first DDE event,
+ * so don't wait for it */
+ SetEvent(hEvent);
+
+ assert(CreateThread(NULL, 0, ddeThread, (LPVOID)&info, 0, &threadId));
+ while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
+ rc = msg.wParam > 32 ? 33 : msg.wParam;
+
+ /* First test, find which set of test data we expect to see */
+ if (test == dde_default_app_tests)
+ {
+ int i;
+ for (i=0; i<DDE_DEFAULT_APP_VARIANTS; i++)
+ {
+ if (!strcmp(ddeApplication, test->expectedDdeApplication[i]))
+ {
+ which = i;
+ break;
+ }
+ }
+ if (i == DDE_DEFAULT_APP_VARIANTS)
+ skip("Default DDE application test does not match any available results, using first expected data set.\n");
+ }
+
+ if ((test->todo & 0x1)==0)
+ {
+ ok(rc==test->rc[which], "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ else todo_wine
+ {
+ ok(rc==test->rc[which], "%s failed: rc=%d err=%d\n", shell_call,
+ rc, GetLastError());
+ }
+ if (rc == 33)
+ {
+ if ((test->todo & 0x2)==0)
+ {
+ ok(!strcmp(ddeApplication, test->expectedDdeApplication[which]),
+ "Expected application '%s', got '%s'\n",
+ test->expectedDdeApplication[which], ddeApplication);
+ }
+ else todo_wine
+ {
+ ok(!strcmp(ddeApplication, test->expectedDdeApplication[which]),
+ "Expected application '%s', got '%s'\n",
+ test->expectedDdeApplication[which], ddeApplication);
+ }
+ }
+
+ delete_test_association(".sde");
+ test++;
+ }
+
+ assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_UNREGISTER));
+ assert(DdeFreeStringHandle(ddeInst, hszTopic));
+ assert(DdeFreeStringHandle(ddeInst, hszApplication));
+ assert(DdeUninitialize(ddeInst));
+}
+
+static void init_test(void)
+{
+ HMODULE hdll;
+ HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO*);
char filename[MAX_PATH];
WCHAR lnkfile[MAX_PATH];
+ char params[1024];
const char* const * testfile;
lnk_desc_t desc;
DWORD rc;
HRESULT r;
+ hdll=GetModuleHandleA("shell32.dll");
+ pDllGetVersion=(void*)GetProcAddress(hdll, "DllGetVersion");
+ if (pDllGetVersion)
+ {
+ dllver.cbSize=sizeof(dllver);
+ pDllGetVersion(&dllver);
+ trace("major=%d minor=%d build=%d platform=%d\n",
+ dllver.dwMajorVersion, dllver.dwMinorVersion,
+ dllver.dwBuildNumber, dllver.dwPlatformID);
+ }
+ else
+ {
+ memset(&dllver, 0, sizeof(dllver));
+ }
+
r = CoInitialize(NULL);
- ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
+ ok(SUCCEEDED(r), "CoInitialize failed (0x%08x)\n", r);
if (!SUCCEEDED(r))
exit(1);
}
GetTempPathA(sizeof(tmpdir)/sizeof(*tmpdir), tmpdir);
+ assert(GetTempFileNameA(tmpdir, "wt", 0, child_file)!=0);
+ init_event(child_file);
/* Set up the test files */
testfile=testfiles;
FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile==INVALID_HANDLE_VALUE)
{
- trace("unable to create '%s': err=%ld\n", filename, GetLastError());
+ trace("unable to create '%s': err=%d\n", filename, GetLastError());
assert(0);
}
CloseHandle(hfile);
sprintf(filename, "%s\\test file.shlexec", tmpdir);
desc.path=filename;
desc.pidl=NULL;
- desc.arguments="";
+ desc.arguments="ignored";
+ desc.showcmd=0;
+ desc.icon=NULL;
+ desc.icon_id=0;
+ desc.hotkey=0;
+ create_lnk(lnkfile, &desc, 0);
+
+ sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
+ MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, sizeof(lnkfile)/sizeof(*lnkfile));
+ desc.description=NULL;
+ desc.workdir=NULL;
+ desc.path=argv0;
+ desc.pidl=NULL;
+ sprintf(params, "shlexec \"%s\" Lnk", child_file);
+ desc.arguments=params;
desc.showcmd=0;
desc.icon=NULL;
desc.icon_id=0;
/* Create a basic association suitable for most tests */
create_test_association(".shlexec");
- create_test_verb(".shlexec", "Open");
+ create_test_verb(".shlexec", "Open", 0, "Open \"%1\"");
+ create_test_verb(".shlexec", "NoQuotes", 0, "NoQuotes %1");
+ create_test_verb(".shlexec", "LowerL", 0, "LowerL %l");
+ create_test_verb(".shlexec", "QuotedLowerL", 0, "QuotedLowerL \"%l\"");
+ create_test_verb(".shlexec", "UpperL", 0, "UpperL %L");
+ create_test_verb(".shlexec", "QuotedUpperL", 0, "QuotedUpperL \"%L\"");
}
-static void cleanup_test()
+static void cleanup_test(void)
{
char filename[MAX_PATH];
const char* const * testfile;
DeleteFile(filename);
testfile++;
}
+ DeleteFile(child_file);
/* Delete the test association */
delete_test_association(".shlexec");
+ CloseHandle(hEvent);
+
CoUninitialize();
}
{
myARGC = winetest_get_mainargs(&myARGV);
- if (myARGC>=3)
+ if (myARGC >= 3)
{
- /* FIXME: We should dump the parameters we got
- * and have the parent verify them
- */
+ doChild(myARGC, myARGV);
exit(0);
}
init_test();
test_filename();
+ test_find_executable();
+ test_lnks();
test_exes();
+ test_exes_long();
+ test_dde();
+ test_dde_default_app();
cleanup_test();
}
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#define WINE_NOWINSOCK
-#include "windef.h"
-#include "winbase.h"
-#include "wtypes.h"
+#include <windows.h>
#include "shellapi.h"
#include "shlobj.h"
#include "wine/test.h"
-CHAR CURR_DIR[MAX_PATH];
+#ifndef FOF_NORECURSION
+#define FOF_NORECURSION 0x1000
+#endif
+
+static CHAR CURR_DIR[MAX_PATH];
+static const WCHAR UNICODE_PATH[] = {'c',':','\\',0x00c4,'\0','\0'};
+ /* "c:\Ä", or "c:\A" with diaeresis */
+ /* Double-null termination needed for pFrom field of SHFILEOPSTRUCT */
static HMODULE hshell32;
static int (WINAPI *pSHCreateDirectoryExA)(HWND, LPCSTR, LPSECURITY_ATTRIBUTES);
+static int (WINAPI *pSHCreateDirectoryExW)(HWND, LPCWSTR, LPSECURITY_ATTRIBUTES);
static void InitFunctionPointers(void)
{
hshell32 = GetModuleHandleA("shell32.dll");
-
- if(hshell32)
- pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA");
+ pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA");
+ pSHCreateDirectoryExW = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExW");
}
/* creates a file with the specified name for tests */
CloseHandle(file);
}
+static void createTestFileW(const WCHAR *name)
+{
+ HANDLE file;
+
+ file = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ ok(file != INVALID_HANDLE_VALUE, "Failure to open file\n");
+ CloseHandle(file);
+}
+
static BOOL file_exists(const CHAR *name)
{
return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES;
}
+static BOOL file_existsW(LPCWSTR name)
+{
+ return GetFileAttributesW(name) != INVALID_FILE_ATTRIBUTES;
+}
+
+static BOOL file_has_content(const CHAR *name, const CHAR *content)
+{
+ CHAR buf[MAX_PATH];
+ HANDLE file;
+ DWORD read;
+
+ file = CreateFileA(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return FALSE;
+ ReadFile(file, buf, MAX_PATH - 1, &read, NULL);
+ buf[read] = 0;
+ CloseHandle(file);
+ return strcmp(buf, content)==0;
+}
+
/* initializes the tests */
static void init_shfo_tests(void)
{
if(len && (CURR_DIR[len-1] == '\\'))
CURR_DIR[len-1] = 0;
- createTestFile(".\\test1.txt");
- createTestFile(".\\test2.txt");
- createTestFile(".\\test3.txt");
- CreateDirectoryA(".\\test4.txt", NULL);
- CreateDirectoryA(".\\testdir2", NULL);
+ createTestFile("test1.txt");
+ createTestFile("test2.txt");
+ createTestFile("test3.txt");
+ createTestFile("test_5.txt");
+ CreateDirectoryA("test4.txt", NULL);
+ CreateDirectoryA("testdir2", NULL);
+ CreateDirectoryA("testdir2\\nested", NULL);
+ createTestFile("testdir2\\one.txt");
+ createTestFile("testdir2\\nested\\two.txt");
}
/* cleans after tests */
static void clean_after_shfo_tests(void)
{
- DeleteFileA(".\\test1.txt");
- DeleteFileA(".\\test2.txt");
- DeleteFileA(".\\test3.txt");
- DeleteFileA(".\\test4.txt\\test1.txt");
- DeleteFileA(".\\test4.txt\\test2.txt");
- DeleteFileA(".\\test4.txt\\test3.txt");
- RemoveDirectoryA(".\\test4.txt");
- DeleteFileA(".\\testdir2\\test1.txt");
- DeleteFileA(".\\testdir2\\test2.txt");
- DeleteFileA(".\\testdir2\\test3.txt");
- DeleteFileA(".\\testdir2\\test4.txt\\test1.txt");
- RemoveDirectoryA(".\\testdir2\\test4.txt");
- RemoveDirectoryA(".\\testdir2");
+ DeleteFileA("test1.txt");
+ DeleteFileA("test2.txt");
+ DeleteFileA("test3.txt");
+ DeleteFileA("test_5.txt");
+ DeleteFileA("one.txt");
+ DeleteFileA("test4.txt\\test1.txt");
+ DeleteFileA("test4.txt\\test2.txt");
+ DeleteFileA("test4.txt\\test3.txt");
+ RemoveDirectoryA("test4.txt");
+ DeleteFileA("testdir2\\one.txt");
+ DeleteFileA("testdir2\\test1.txt");
+ DeleteFileA("testdir2\\test2.txt");
+ DeleteFileA("testdir2\\test3.txt");
+ DeleteFileA("testdir2\\test4.txt\\test1.txt");
+ DeleteFileA("testdir2\\nested\\two.txt");
+ RemoveDirectoryA("testdir2\\test4.txt");
+ RemoveDirectoryA("testdir2\\nested");
+ RemoveDirectoryA("testdir2");
+ RemoveDirectoryA("c:\\testdir3");
+ DeleteFileA("nonexistent\\notreal\\test2.txt");
+ RemoveDirectoryA("nonexistent\\notreal");
+ RemoveDirectoryA("nonexistent");
}
+
+static void test_get_file_info(void)
+{
+ DWORD rc, rc2;
+ SHFILEINFO shfi, shfi2;
+ char notepad[MAX_PATH];
+
+ /* Test some flag combinations that MSDN claims are not allowed,
+ * but which work anyway
+ */
+ shfi.dwAttributes=0xdeadbeef;
+ rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY,
+ &shfi, sizeof(shfi),
+ SHGFI_ATTRIBUTES | SHGFI_USEFILEATTRIBUTES);
+ todo_wine ok(rc, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) failed\n");
+ if (rc)
+ ok(shfi.dwAttributes != 0xdeadbeef, "dwFileAttributes is not set\n");
+
+ rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY,
+ &shfi, sizeof(shfi),
+ SHGFI_EXETYPE | SHGFI_USEFILEATTRIBUTES);
+ todo_wine ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent | SHGFI_EXETYPE) returned %d\n", rc);
+
+ /* Test SHGFI_USEFILEATTRIBUTES support */
+ strcpy(shfi.szDisplayName, "dummy");
+ shfi.iIcon=0xdeadbeef;
+ rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY,
+ &shfi, sizeof(shfi),
+ SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES);
+ ok(rc, "SHGetFileInfoA(c:\\nonexistent) failed\n");
+ if (rc)
+ {
+ ok(strcpy(shfi.szDisplayName, "dummy") != 0, "SHGetFileInfoA(c:\\nonexistent) displayname is not set\n");
+ ok(shfi.iIcon != 0xdeadbeef, "SHGetFileInfoA(c:\\nonexistent) iIcon is not set\n");
+ }
+
+ /* Wine does not have a default icon for text files, and Windows 98 fails
+ * if we give it an empty executable. So use notepad.exe as the test
+ */
+ if (SearchPath(NULL, "notepad.exe", NULL, sizeof(notepad), notepad, NULL))
+ {
+ strcpy(shfi.szDisplayName, "dummy");
+ shfi.iIcon=0xdeadbeef;
+ rc=SHGetFileInfoA(notepad, GetFileAttributes(notepad),
+ &shfi, sizeof(shfi),
+ SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES);
+ ok(rc, "SHGetFileInfoA(%s, SHGFI_USEFILEATTRIBUTES) failed\n", notepad);
+ strcpy(shfi2.szDisplayName, "dummy");
+ shfi2.iIcon=0xdeadbeef;
+ rc2=SHGetFileInfoA(notepad, 0,
+ &shfi2, sizeof(shfi2),
+ SHGFI_ICONLOCATION);
+ ok(rc2, "SHGetFileInfoA(%s) failed\n", notepad);
+ if (rc && rc2)
+ {
+ ok(lstrcmpi(shfi2.szDisplayName, shfi.szDisplayName) == 0, "wrong display name %s != %s\n", shfi.szDisplayName, shfi2.szDisplayName);
+ ok(shfi2.iIcon == shfi.iIcon, "wrong icon index %d != %d\n", shfi.iIcon, shfi2.iIcon);
+ }
+ }
+
+ /* with a directory now */
+ strcpy(shfi.szDisplayName, "dummy");
+ shfi.iIcon=0xdeadbeef;
+ rc=SHGetFileInfoA("test4.txt", GetFileAttributes("test4.txt"),
+ &shfi, sizeof(shfi),
+ SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES);
+ ok(rc, "SHGetFileInfoA(test4.txt/, SHGFI_USEFILEATTRIBUTES) failed\n");
+ strcpy(shfi2.szDisplayName, "dummy");
+ shfi2.iIcon=0xdeadbeef;
+ rc2=SHGetFileInfoA("test4.txt", 0,
+ &shfi2, sizeof(shfi2),
+ SHGFI_ICONLOCATION);
+ ok(rc2, "SHGetFileInfoA(test4.txt/) failed\n");
+ if (rc && rc2)
+ {
+ ok(lstrcmpi(shfi2.szDisplayName, shfi.szDisplayName) == 0, "wrong display name %s != %s\n", shfi.szDisplayName, shfi2.szDisplayName);
+ ok(shfi2.iIcon == shfi.iIcon, "wrong icon index %d != %d\n", shfi.iIcon, shfi2.iIcon);
+ }
+}
+
+
/*
puts into the specified buffer file names with current directory.
files - string with file names, separated by null characters. Ends on a double
{
SHFILEOPSTRUCTA shfo;
DWORD ret;
- CHAR buf[MAX_PATH];
+ CHAR buf[sizeof(CURR_DIR)+sizeof("/test?.txt")+1];
sprintf(buf, "%s\\%s", CURR_DIR, "test?.txt");
buf[strlen(buf) + 1] = '\0';
shfo.hNameMappings = NULL;
shfo.lpszProgressTitle = NULL;
- ok(!SHFileOperationA(&shfo), "Deletion was successful\n");
- ok(file_exists(".\\test4.txt"), "Directory should not be removed\n");
- ok(!file_exists(".\\test1.txt"), "File should be removed\n");
+ ok(!SHFileOperationA(&shfo), "Deletion was not successful\n");
+ ok(file_exists("test4.txt"), "Directory should not have been removed\n");
+ ok(!file_exists("test1.txt"), "File should have been removed\n");
ret = SHFileOperationA(&shfo);
- ok(!ret, "Directory exists, but is not removed, ret=%ld\n", ret);
- ok(file_exists(".\\test4.txt"), "Directory should not be removed\n");
+ ok(!ret, "Directory exists, but is not removed, ret=%d\n", ret);
+ ok(file_exists("test4.txt"), "Directory should not have been removed\n");
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
- ok(!SHFileOperationA(&shfo), "Directory removed\n");
- ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
+ ok(!SHFileOperationA(&shfo), "Directory is not removed\n");
+ ok(!file_exists("test4.txt"), "Directory should have been removed\n");
ret = SHFileOperationA(&shfo);
- ok(!ret, "The requested file does not exist, ret=%ld\n", ret);
+ ok(!ret, "The requested file does not exist, ret=%d\n", ret);
init_shfo_tests();
sprintf(buf, "%s\\%s", CURR_DIR, "test4.txt");
buf[strlen(buf) + 1] = '\0';
- ok(MoveFileA(".\\test1.txt", ".\\test4.txt\\test1.txt"), "Fill the subdirectory\n");
- ok(!SHFileOperationA(&shfo), "Directory removed\n");
- ok(!file_exists(".\\test4.txt"), "Directory is removed\n");
+ ok(MoveFileA("test1.txt", "test4.txt\\test1.txt"), "Filling the subdirectory failed\n");
+ ok(!SHFileOperationA(&shfo), "Directory is not removed\n");
+ ok(!file_exists("test4.txt"), "Directory is not removed\n");
+
+ init_shfo_tests();
+ shfo.pFrom = "test1.txt\0test4.txt\0";
+ ok(!SHFileOperationA(&shfo), "Directory and a file are not removed\n");
+ ok(!file_exists("test1.txt"), "The file should have been removed\n");
+ ok(!file_exists("test4.txt"), "Directory should have been removed\n");
+ ok(file_exists("test2.txt"), "This file should not have been removed\n");
+
+ /* FOF_FILESONLY does not delete a dir matching a wildcard */
+ init_shfo_tests();
+ shfo.fFlags |= FOF_FILESONLY;
+ shfo.pFrom = "*.txt\0";
+ ok(!SHFileOperation(&shfo), "Failed to delete files\n");
+ ok(!file_exists("test1.txt"), "test1.txt should have been removed\n");
+ ok(!file_exists("test_5.txt"), "test_5.txt should have been removed\n");
+ ok(file_exists("test4.txt"), "test4.txt should not have been removed\n");
+
+ /* FOF_FILESONLY only deletes a dir if explicitly specified */
+ init_shfo_tests();
+ shfo.pFrom = "test_?.txt\0test4.txt\0";
+ ok(!SHFileOperation(&shfo), "Failed to delete files and directory\n");
+ ok(!file_exists("test4.txt"), "test4.txt should have been removed\n");
+ ok(!file_exists("test_5.txt"), "test_5.txt should have been removed\n");
+ ok(file_exists("test1.txt"), "test1.txt should not have been removed\n");
+
+ /* try to delete an invalid filename */
+ init_shfo_tests();
+ shfo.pFrom = "\0";
+ shfo.fFlags &= ~FOF_FILESONLY;
+ shfo.fAnyOperationsAborted = FALSE;
+ ret = SHFileOperation(&shfo);
+ ok(ret == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", ret);
+ ok(!shfo.fAnyOperationsAborted, "Expected no aborted operations\n");
+ ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
+
+ /* try an invalid function */
+ init_shfo_tests();
+ shfo.pFrom = "test1.txt\0";
+ shfo.wFunc = 0;
+ ret = SHFileOperation(&shfo);
+ ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+ ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
+
+ /* try an invalid list, only one null terminator */
+ init_shfo_tests();
+ shfo.pFrom = "";
+ shfo.wFunc = FO_DELETE;
+ ret = SHFileOperation(&shfo);
+ ok(ret == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", ret);
+ ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
+
+ /* delete a dir, and then a file inside the dir, same as
+ * deleting a nonexistent file
+ */
+ init_shfo_tests();
+ shfo.pFrom = "testdir2\0testdir2\\one.txt\0";
+ ret = SHFileOperation(&shfo);
+ ok(ret == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", ret);
+ ok(!file_exists("testdir2"), "Expected testdir2 to not exist\n");
+ ok(!file_exists("testdir2\\one.txt"), "Expected testdir2\\one.txt to not exist\n");
+ /* try the FOF_NORECURSION flag, continues deleting subdirs */
init_shfo_tests();
- shfo.pFrom = ".\\test1.txt\0.\\test4.txt\0";
- ok(!SHFileOperationA(&shfo), "Directory and a file removed\n");
- ok(!file_exists(".\\test1.txt"), "The file should be removed\n");
- ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
- ok(file_exists(".\\test2.txt"), "This file should not be removed\n");
+ shfo.pFrom = "testdir2\0";
+ shfo.fFlags |= FOF_NORECURSION;
+ ret = SHFileOperation(&shfo);
+ ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+ ok(!file_exists("testdir2\\one.txt"), "Expected testdir2\\one.txt to not exist\n");
+ ok(!file_exists("testdir2\\nested"), "Expected testdir2\\nested to exist\n");
}
/* tests the FO_RENAME action */
static void test_rename(void)
{
SHFILEOPSTRUCTA shfo, shfo2;
- CHAR from[MAX_PATH];
- CHAR to[MAX_PATH];
+ CHAR from[5*MAX_PATH];
+ CHAR to[5*MAX_PATH];
DWORD retval;
shfo.hwnd = NULL;
set_curr_dir_path(to, "test4.txt\0");
ok(SHFileOperationA(&shfo), "File is not renamed moving to other directory "
"when specifying directory name only\n");
- ok(file_exists(".\\test1.txt"), "The file is removed\n");
+ ok(file_exists("test1.txt"), "The file is removed\n");
set_curr_dir_path(from, "test3.txt\0");
set_curr_dir_path(to, "test4.txt\\test1.txt\0");
ok(!SHFileOperationA(&shfo), "File is renamed moving to other directory\n");
- ok(file_exists(".\\test4.txt\\test1.txt"), "The file is not renamed\n");
+ ok(file_exists("test4.txt\\test1.txt"), "The file is not renamed\n");
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
retval = SHFileOperationA(&shfo); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE,
- "Can't rename many files, retval = %ld\n", retval);
- ok(file_exists(".\\test1.txt"), "The file is renamed - many files are specified\n");
+ "Can't rename many files, retval = %d\n", retval);
+ ok(file_exists("test1.txt"), "The file is renamed - many files are specified\n");
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
shfo2.fFlags |= FOF_MULTIDESTFILES;
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
retval = SHFileOperationA(&shfo2); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE,
- "Can't rename many files, retval = %ld\n", retval);
- ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified\n");
+ "Can't rename many files, retval = %d\n", retval);
+ ok(file_exists("test1.txt"), "The file is not renamed - many files are specified\n");
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test6.txt\0");
retval = SHFileOperationA(&shfo);
- ok(!retval, "Rename file failed, retval = %ld\n", retval);
- ok(!file_exists(".\\test1.txt"), "The file is not renamed\n");
- ok(file_exists(".\\test6.txt"), "The file is not renamed\n");
+ ok(!retval, "Rename file failed, retval = %d\n", retval);
+ ok(!file_exists("test1.txt"), "The file is not renamed\n");
+ ok(file_exists("test6.txt"), "The file is not renamed\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test1.txt\0");
retval = SHFileOperationA(&shfo);
- ok(!retval, "Rename file back failed, retval = %ld\n", retval);
+ ok(!retval, "Rename file back failed, retval = %d\n", retval);
set_curr_dir_path(from, "test4.txt\0");
set_curr_dir_path(to, "test6.txt\0");
retval = SHFileOperationA(&shfo);
- ok(!retval, "Rename dir failed, retval = %ld\n", retval);
- ok(!file_exists(".\\test4.txt"), "The dir is not renamed\n");
- ok(file_exists(".\\test6.txt"), "The dir is not renamed\n");
+ ok(!retval, "Rename dir failed, retval = %d\n", retval);
+ ok(!file_exists("test4.txt"), "The dir is not renamed\n");
+ ok(file_exists("test6.txt"), "The dir is not renamed\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test4.txt\0");
retval = SHFileOperationA(&shfo);
- ok(!retval, "Rename dir back failed, retval = %ld\n", retval);
+ ok(!retval, "Rename dir back failed, retval = %d\n", retval);
+
+ /* try to rename more than one file to a single file */
+ shfo.pFrom = "test1.txt\0test2.txt\0";
+ shfo.pTo = "a.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_GEN_FAILURE, "Expected ERROR_GEN_FAILURE, got %d\n", retval);
+ ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
+ ok(file_exists("test2.txt"), "Expected test2.txt to exist\n");
+
+ /* pFrom doesn't exist */
+ shfo.pFrom = "idontexist\0";
+ shfo.pTo = "newfile\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == 1026, "Expected 1026, got %d\n", retval);
+ ok(!file_exists("newfile"), "Expected newfile to not exist\n");
+
+ /* pTo already exist */
+ shfo.pFrom = "test1.txt\0";
+ shfo.pTo = "test2.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_ALREADY_EXISTS, "Expected ERROR_ALREADY_EXISTS, got %d\n", retval);
+
+ /* pFrom is valid, but pTo is empty */
+ shfo.pFrom = "test1.txt\0";
+ shfo.pTo = "\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
+
+ /* pFrom is empty */
+ shfo.pFrom = "\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", retval);
+
+ /* pFrom is NULL, commented out because it crashes on nt 4.0 */
+#if 0
+ shfo.pFrom = NULL;
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", retval);
+#endif
}
/* tests the FO_COPY action */
static void test_copy(void)
{
SHFILEOPSTRUCTA shfo, shfo2;
- CHAR from[MAX_PATH];
- CHAR to[MAX_PATH];
+ CHAR from[5*MAX_PATH];
+ CHAR to[5*MAX_PATH];
FILEOP_FLAGS tmp_flags;
DWORD retval;
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(SHFileOperationA(&shfo), "Can't copy many files\n");
- ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
+ ok(!file_exists("test6.txt"), "The file is not copied - many files are "
"specified as a target\n");
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(!SHFileOperationA(&shfo2), "Can't copy many files\n");
- ok(file_exists(".\\test6.txt"), "The file is copied - many files are "
+ ok(file_exists("test6.txt"), "The file is copied - many files are "
"specified as a target\n");
- DeleteFileA(".\\test6.txt");
- DeleteFileA(".\\test7.txt");
- RemoveDirectoryA(".\\test8.txt");
+ DeleteFileA("test6.txt");
+ DeleteFileA("test7.txt");
+ RemoveDirectoryA("test8.txt");
/* number of sources do not correspond to number of targets */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
ok(SHFileOperationA(&shfo2), "Can't copy many files\n");
- ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
+ ok(!file_exists("test6.txt"), "The file is not copied - many files are "
"specified as a target\n");
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test4.txt\0");
ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are copied recursively\n");
- ok(file_exists(".\\test4.txt\\test1.txt"), "The file is copied\n");
+ ok(file_exists("test4.txt\\test1.txt"), "The file is copied\n");
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
- ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
- ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
+ ok(!file_exists("testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists("testdir2\\test4.txt"), "The directory is not copied yet\n");
ok(!SHFileOperationA(&shfo), "Files and directories are copied to directory\n");
- ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
- ok(file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
- ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied\n");
+ ok(file_exists("testdir2\\test1.txt"), "The file is copied\n");
+ ok(file_exists("testdir2\\test4.txt"), "The directory is copied\n");
+ ok(file_exists("testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied\n");
clean_after_shfo_tests();
init_shfo_tests();
shfo.fFlags |= FOF_FILESONLY;
- ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
- ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
+ ok(!file_exists("testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists("testdir2\\test4.txt"), "The directory is not copied yet\n");
ok(!SHFileOperationA(&shfo), "Files are copied to other directory\n");
- ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
- ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
+ ok(file_exists("testdir2\\test1.txt"), "The file is copied\n");
+ ok(!file_exists("testdir2\\test4.txt"), "The directory is copied\n");
clean_after_shfo_tests();
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0");
- ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
- ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
- ok(!SHFileOperationA(&shfo), "Files are copied to other directory \n");
- ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
- ok(file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
+ ok(!file_exists("testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists("testdir2\\test2.txt"), "The file is not copied yet\n");
+ ok(!SHFileOperationA(&shfo), "Files are copied to other directory\n");
+ ok(file_exists("testdir2\\test1.txt"), "The file is copied\n");
+ ok(file_exists("testdir2\\test2.txt"), "The file is copied\n");
clean_after_shfo_tests();
/* Copying multiple files with one not existing as source, fails the
init_shfo_tests();
tmp_flags = shfo.fFlags;
set_curr_dir_path(from, "test1.txt\0test10.txt\0test2.txt\0");
- ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
- ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
+ ok(!file_exists("testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists("testdir2\\test2.txt"), "The file is not copied yet\n");
retval = SHFileOperationA(&shfo);
if (!retval)
- /* Win 95/NT returns success but copies only the files up to the nonexistent source */
- ok(file_exists(".\\testdir2\\test1.txt"), "The file is not copied\n");
+ /* Win 95/NT returns success but copies only the files up to the nonexistent source */
+ ok(file_exists("testdir2\\test1.txt"), "The file is not copied\n");
else
{
- /* Win 98/ME/2K/XP fail the entire operation with return code 1026 if one source file does not exist */
- ok(retval == 1026, "Files are copied to other directory\n");
- ok(!file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
+ /* Win 98/ME/2K/XP fail the entire operation with return code 1026 if one source file does not exist */
+ ok(retval == 1026, "Files are copied to other directory\n");
+ ok(!file_exists("testdir2\\test1.txt"), "The file is copied\n");
}
- ok(!file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
+ ok(!file_exists("testdir2\\test2.txt"), "The file is copied\n");
shfo.fFlags = tmp_flags;
+
+ /* copy into a nonexistent directory */
+ init_shfo_tests();
+ shfo.fFlags = FOF_NOCONFIRMMKDIR;
+ set_curr_dir_path(from, "test1.txt\0");
+ set_curr_dir_path(to, "nonexistent\\notreal\\test2.txt\0");
+ retval= SHFileOperation(&shfo);
+ ok(!retval, "Error copying into nonexistent directory\n");
+ ok(file_exists("nonexistent"), "nonexistent not created\n");
+ ok(file_exists("nonexistent\\notreal"), "nonexistent\\notreal not created\n");
+ ok(file_exists("nonexistent\\notreal\\test2.txt"), "Directory not created\n");
+ ok(!file_exists("nonexistent\\notreal\\test1.txt"), "test1.txt should not exist\n");
+
+ /* a relative dest directory is OK */
+ clean_after_shfo_tests();
+ init_shfo_tests();
+ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0";
+ shfo.pTo = "testdir2\0";
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1 to exist\n");
+
+ /* try to copy files to a file */
+ clean_after_shfo_tests();
+ init_shfo_tests();
+ shfo.pFrom = from;
+ shfo.pTo = to;
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0");
+ set_curr_dir_path(to, "test3.txt\0");
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n");
+ ok(!file_exists("test3.txt\\test2.txt"), "Expected test3.txt\\test2.txt to not exist\n");
+
+ /* try to copy many files to nonexistent directory */
+ DeleteFile(to);
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("test3.txt\\test1.txt"), "Expected test3.txt\\test1.txt to exist\n");
+ ok(DeleteFile("test3.txt\\test2.txt"), "Expected test3.txt\\test1.txt to exist\n");
+ ok(RemoveDirectory(to), "Expected test3.txt to exist\n");
+
+ /* send in FOF_MULTIDESTFILES with too many destination files */
+ init_shfo_tests();
+ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0";
+ shfo.pTo = "testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0testdir2\\d.txt\0";
+ shfo.fFlags |= FOF_NOERRORUI | FOF_MULTIDESTFILES;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n");
+ ok(!file_exists("testdir2\\a.txt"), "Expected testdir2\\a.txt to not exist\n");
+
+ /* send in FOF_MULTIDESTFILES with too many destination files */
+ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0";
+ shfo.pTo = "e.txt\0f.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n");
+ ok(!file_exists("e.txt"), "Expected e.txt to not exist\n");
+
+ /* use FOF_MULTIDESTFILES with files and a source directory */
+ shfo.pFrom = "test1.txt\0test2.txt\0test4.txt\0";
+ shfo.pTo = "testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("testdir2\\a.txt"), "Expected testdir2\\a.txt to exist\n");
+ ok(DeleteFile("testdir2\\b.txt"), "Expected testdir2\\b.txt to exist\n");
+ ok(RemoveDirectory("testdir2\\c.txt"), "Expected testdir2\\c.txt to exist\n");
+
+ /* try many dest files without FOF_MULTIDESTFILES flag */
+ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0";
+ shfo.pTo = "a.txt\0b.txt\0c.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ shfo.fFlags &= ~FOF_MULTIDESTFILES;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(!file_exists("a.txt"), "Expected a.txt to not exist\n");
+
+ /* try a glob */
+ shfo.pFrom = "test?.txt\0";
+ shfo.pTo = "testdir2\0";
+ shfo.fFlags &= ~FOF_MULTIDESTFILES;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n");
+
+ /* try a glob with FOF_FILESONLY */
+ clean_after_shfo_tests();
+ init_shfo_tests();
+ shfo.pFrom = "test?.txt\0";
+ shfo.fFlags |= FOF_FILESONLY;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n");
+ ok(!file_exists("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to not exist\n");
+
+ /* try a glob with FOF_MULTIDESTFILES and the same number
+ * of dest files that we would expect
+ */
+ clean_after_shfo_tests();
+ init_shfo_tests();
+ shfo.pTo = "testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0testdir2\\d.txt\0";
+ shfo.fFlags &= ~FOF_FILESONLY;
+ shfo.fFlags |= FOF_MULTIDESTFILES;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n");
+ ok(!file_exists("testdir2\\a.txt"), "Expected testdir2\\test1.txt to not exist\n");
+ ok(!RemoveDirectory("b.txt"), "b.txt should not exist\n");
+
+ /* copy one file to two others, second is ignored */
+ clean_after_shfo_tests();
+ init_shfo_tests();
+ shfo.pFrom = "test1.txt\0";
+ shfo.pTo = "b.txt\0c.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("b.txt"), "Expected b.txt to exist\n");
+ ok(!DeleteFile("c.txt"), "Expected c.txt to not exist\n");
+
+ /* copy two file to three others, all fail */
+ shfo.pFrom = "test1.txt\0test2.txt\0";
+ shfo.pTo = "b.txt\0c.txt\0d.txt\0";
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected operations to be aborted\n");
+ ok(!DeleteFile("b.txt"), "Expected b.txt to not exist\n");
+
+ /* copy one file and one directory to three others */
+ shfo.pFrom = "test1.txt\0test4.txt\0";
+ shfo.pTo = "b.txt\0c.txt\0d.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected operations to be aborted\n");
+ ok(!DeleteFile("b.txt"), "Expected b.txt to not exist\n");
+ ok(!DeleteFile("c.txt"), "Expected c.txt to not exist\n");
+
+ /* copy a directory with a file beneath it, plus some files */
+ createTestFile("test4.txt\\a.txt");
+ shfo.pFrom = "test4.txt\0test1.txt\0";
+ shfo.pTo = "testdir2\0";
+ shfo.fFlags &= ~FOF_MULTIDESTFILES;
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("testdir2\\test1.txt"), "Expected newdir\\test1.txt to exist\n");
+ ok(DeleteFile("testdir2\\test4.txt\\a.txt"), "Expected a.txt to exist\n");
+ ok(RemoveDirectory("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to exist\n");
+
+ /* copy one directory and a file in that dir to another dir */
+ shfo.pFrom = "test4.txt\0test4.txt\\a.txt\0";
+ shfo.pTo = "testdir2\0";
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("testdir2\\test4.txt\\a.txt"), "Expected a.txt to exist\n");
+ ok(DeleteFile("testdir2\\a.txt"), "Expected testdir2\\a.txt to exist\n");
+
+ /* copy a file in a directory first, and then the directory to a nonexistent dir */
+ shfo.pFrom = "test4.txt\\a.txt\0test4.txt\0";
+ shfo.pTo = "nonexistent\0";
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(shfo.fAnyOperationsAborted, "Expected operations to be aborted\n");
+ ok(!file_exists("nonexistent\\test4.txt"), "Expected nonexistent\\test4.txt to not exist\n");
+ DeleteFile("test4.txt\\a.txt");
+
+ /* destination is same as source file */
+ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0";
+ shfo.pTo = "b.txt\0test2.txt\0c.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ shfo.fFlags = FOF_NOERRORUI | FOF_MULTIDESTFILES;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_NO_MORE_SEARCH_HANDLES,
+ "Expected ERROR_NO_MORE_SEARCH_HANDLES, got %d\n", retval);
+ ok(!shfo.fAnyOperationsAborted, "Expected no operations to be aborted\n");
+ ok(DeleteFile("b.txt"), "Expected b.txt to exist\n");
+ ok(!file_exists("c.txt"), "Expected c.txt to not exist\n");
+
+ /* destination is same as source directory */
+ shfo.pFrom = "test1.txt\0test4.txt\0test3.txt\0";
+ shfo.pTo = "b.txt\0test4.txt\0c.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("b.txt"), "Expected b.txt to exist\n");
+ ok(!file_exists("c.txt"), "Expected c.txt to not exist\n");
+
+ /* copy a directory into itself, error displayed in UI */
+ shfo.pFrom = "test4.txt\0";
+ shfo.pTo = "test4.txt\\newdir\0";
+ shfo.fFlags &= ~FOF_MULTIDESTFILES;
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(!RemoveDirectory("test4.txt\\newdir"), "Expected test4.txt\\newdir to not exist\n");
+
+ /* copy a directory to itself, error displayed in UI */
+ shfo.pFrom = "test4.txt\0";
+ shfo.pTo = "test4.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+
+ /* copy a file into a directory, and the directory into itself */
+ shfo.pFrom = "test1.txt\0test4.txt\0";
+ shfo.pTo = "test4.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ shfo.fFlags |= FOF_NOCONFIRMATION;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(DeleteFile("test4.txt\\test1.txt"), "Expected test4.txt\\test1.txt to exist\n");
+
+ /* copy a file to a file, and the directory into itself */
+ shfo.pFrom = "test1.txt\0test4.txt\0";
+ shfo.pTo = "test4.txt\\a.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(!file_exists("test4.txt\\a.txt"), "Expected test4.txt\\a.txt to not exist\n");
+
+ /* copy a nonexistent file to a nonexistent directory */
+ shfo.pFrom = "e.txt\0";
+ shfo.pTo = "nonexistent\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ retval = SHFileOperation(&shfo);
+ ok(retval == 1026, "Expected 1026, got %d\n", retval);
+ ok(!file_exists("nonexistent\\e.txt"), "Expected nonexistent\\e.txt to not exist\n");
+ ok(!file_exists("nonexistent"), "Expected nonexistent to not exist\n");
+
+ /* Overwrite tests */
+ clean_after_shfo_tests();
+ init_shfo_tests();
+ shfo.fFlags = FOF_NOCONFIRMATION;
+ shfo.pFrom = "test1.txt\0";
+ shfo.pTo = "test2.txt\0";
+ shfo.fAnyOperationsAborted = FALSE;
+ /* without FOF_NOCOFIRMATION the confirmation is Yes/No */
+ retval = SHFileOperation(&shfo);
+ ok(retval == 0, "Expected 0, got %d\n", retval);
+ ok(file_has_content("test2.txt", "test1.txt\n"), "The file was not copied\n");
+
+ shfo.pFrom = "test3.txt\0test1.txt\0";
+ shfo.pTo = "test2.txt\0one.txt\0";
+ shfo.fFlags = FOF_NOCONFIRMATION | FOF_MULTIDESTFILES;
+ /* without FOF_NOCOFIRMATION the confirmation is Yes/Yes to All/No/Cancel */
+ retval = SHFileOperation(&shfo);
+ ok(retval == 0, "Expected 0, got %d\n", retval);
+ ok(file_has_content("test2.txt", "test3.txt\n"), "The file was not copied\n");
+
+ shfo.pFrom = "one.txt\0";
+ shfo.pTo = "testdir2\0";
+ shfo.fFlags = FOF_NOCONFIRMATION;
+ /* without FOF_NOCOFIRMATION the confirmation is Yes/No */
+ retval = SHFileOperation(&shfo);
+ ok(retval == 0, "Expected 0, got %d\n", retval);
+ ok(file_has_content("testdir2\\one.txt", "test1.txt\n"), "The file was not copied\n");
+
+ createTestFile("test4.txt\\test1.txt");
+ shfo.pFrom = "test4.txt\0";
+ shfo.pTo = "testdir2\0";
+ shfo.fFlags = FOF_NOCONFIRMATION;
+ ok(!SHFileOperation(&shfo), "First SHFileOperation failed\n");
+ createTestFile("test4.txt\\.\\test1.txt"); /* modify the content of the file */
+ /* without FOF_NOCOFIRMATION the confirmation is "This folder already contains a folder named ..." */
+ retval = SHFileOperation(&shfo);
+ ok(retval == 0, "Expected 0, got %d\n", retval);
+ ok(file_has_content("testdir2\\test4.txt\\test1.txt", "test4.txt\\.\\test1.txt\n"), "The file was not copied\n");
}
/* tests the FO_MOVE action */
static void test_move(void)
{
SHFILEOPSTRUCTA shfo, shfo2;
- CHAR from[MAX_PATH];
- CHAR to[MAX_PATH];
+ CHAR from[5*MAX_PATH];
+ CHAR to[5*MAX_PATH];
+ DWORD retval;
shfo.hwnd = NULL;
shfo.wFunc = FO_MOVE;
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test4.txt\0");
ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are moved recursively\n");
- ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
+ ok(!file_exists("test1.txt"), "test1.txt should not exist\n");
+ ok(file_exists("test4.txt\\test1.txt"), "The file is not moved\n");
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
- ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not moved yet\n");
- ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not moved yet\n");
+ ok(!file_exists("testdir2\\test2.txt"), "The file is not moved yet\n");
+ ok(!file_exists("testdir2\\test4.txt"), "The directory is not moved yet\n");
ok(!SHFileOperationA(&shfo), "Files and directories are moved to directory\n");
- ok(file_exists(".\\testdir2\\test2.txt"), "The file is moved\n");
- ok(file_exists(".\\testdir2\\test4.txt"), "The directory is moved\n");
- ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved\n");
+ ok(file_exists("testdir2\\test2.txt"), "The file is moved\n");
+ ok(file_exists("testdir2\\test4.txt"), "The directory is moved\n");
+ ok(file_exists("testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved\n");
clean_after_shfo_tests();
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(!SHFileOperationA(&shfo2), "Move many files\n");
- ok(file_exists(".\\test6.txt"), "The file is moved - many files are "
+ ok(file_exists("test6.txt"), "The file is moved - many files are "
"specified as a target\n");
- DeleteFileA(".\\test6.txt");
- DeleteFileA(".\\test7.txt");
- RemoveDirectoryA(".\\test8.txt");
+ DeleteFileA("test6.txt");
+ DeleteFileA("test7.txt");
+ RemoveDirectoryA("test8.txt");
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
ok(SHFileOperationA(&shfo2), "Can't move many files\n");
- ok(!file_exists(".\\test6.txt"), "The file is not moved - many files are "
+ ok(!file_exists("test6.txt"), "The file is not moved - many files are "
"specified as a target\n");
init_shfo_tests();
set_curr_dir_path(from, "test3.txt\0");
set_curr_dir_path(to, "test4.txt\\test1.txt\0");
ok(!SHFileOperationA(&shfo), "File is moved moving to other directory\n");
- ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
+ ok(file_exists("test4.txt\\test1.txt"), "The file is moved\n");
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(SHFileOperationA(&shfo), "Cannot move many files\n");
- ok(file_exists(".\\test1.txt"), "The file is not moved. Many files are specified\n");
- ok(file_exists(".\\test4.txt"), "The directory is not moved. Many files are specified\n");
+ ok(file_exists("test1.txt"), "The file is not moved. Many files are specified\n");
+ ok(file_exists("test4.txt"), "The directory is not moved. Many files are specified\n");
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test6.txt\0");
ok(!SHFileOperationA(&shfo), "Move file\n");
- ok(!file_exists(".\\test1.txt"), "The file is moved\n");
- ok(file_exists(".\\test6.txt"), "The file is moved\n");
+ ok(!file_exists("test1.txt"), "The file is moved\n");
+ ok(file_exists("test6.txt"), "The file is moved\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test1.txt\0");
ok(!SHFileOperationA(&shfo), "Move file back\n");
set_curr_dir_path(from, "test4.txt\0");
set_curr_dir_path(to, "test6.txt\0");
ok(!SHFileOperationA(&shfo), "Move dir\n");
- ok(!file_exists(".\\test4.txt"), "The dir is moved\n");
- ok(file_exists(".\\test6.txt"), "The dir is moved\n");
+ ok(!file_exists("test4.txt"), "The dir is moved\n");
+ ok(file_exists("test6.txt"), "The dir is moved\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test4.txt\0");
ok(!SHFileOperationA(&shfo), "Move dir back\n");
+
+ /* move one file to two others */
+ init_shfo_tests();
+ shfo.pFrom = "test1.txt\0";
+ shfo.pTo = "a.txt\0b.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(!file_exists("test1.txt"), "Expected test1.txt to not exist\n");
+ ok(DeleteFile("a.txt"), "Expected a.txt to exist\n");
+ ok(!file_exists("b.txt"), "Expected b.txt to not exist\n");
+
+ /* move two files to one other */
+ shfo.pFrom = "test2.txt\0test3.txt\0";
+ shfo.pTo = "test1.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(!file_exists("test1.txt"), "Expected test1.txt to not exist\n");
+ ok(file_exists("test2.txt"), "Expected test2.txt to exist\n");
+ ok(file_exists("test3.txt"), "Expected test3.txt to exist\n");
+
+ /* move a directory into itself */
+ shfo.pFrom = "test4.txt\0";
+ shfo.pTo = "test4.txt\\b.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(!RemoveDirectory("test4.txt\\b.txt"), "Expected test4.txt\\b.txt to not exist\n");
+ ok(file_exists("test4.txt"), "Expected test4.txt to exist\n");
+
+ /* move many files without FOF_MULTIDESTFILES */
+ shfo.pFrom = "test2.txt\0test3.txt\0";
+ shfo.pTo = "d.txt\0e.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(!DeleteFile("d.txt"), "Expected d.txt to not exist\n");
+ ok(!DeleteFile("e.txt"), "Expected e.txt to not exist\n");
+
+ /* number of sources != number of targets */
+ shfo.pTo = "d.txt\0";
+ shfo.fFlags |= FOF_MULTIDESTFILES;
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(!DeleteFile("d.txt"), "Expected d.txt to not exist\n");
+
+ /* FO_MOVE does not create dest directories */
+ shfo.pFrom = "test2.txt\0";
+ shfo.pTo = "dir1\\dir2\\test2.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval);
+ ok(!file_exists("dir1"), "Expected dir1 to not exist\n");
+
+ /* try to overwrite an existing file */
+ shfo.pTo = "test3.txt\0";
+ retval = SHFileOperationA(&shfo);
+ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+ ok(!file_exists("test2.txt"), "Expected test2.txt to not exist\n");
+ ok(file_exists("test3.txt"), "Expected test3.txt to exist\n");
}
static void test_sh_create_dir(void)
set_curr_dir_path(path, "testdir2\\test4.txt\0");
ret = pSHCreateDirectoryExA(NULL, path, NULL);
ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory recursively, ret = %d\n", ret);
- ok(file_exists(".\\testdir2"), "The first directory is not created\n");
- ok(file_exists(".\\testdir2\\test4.txt"), "The second directory is not created\n");
+ ok(file_exists("testdir2"), "The first directory is not created\n");
+ ok(file_exists("testdir2\\test4.txt"), "The second directory is not created\n");
ret = pSHCreateDirectoryExA(NULL, path, NULL);
ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
+
+ ret = pSHCreateDirectoryExA(NULL, "c:\\testdir3", NULL);
+ ok(file_exists("c:\\testdir3"), "The directory is not created\n");
+}
+
+static void test_unicode(void)
+{
+ SHFILEOPSTRUCTW shfoW;
+ int ret;
+ HANDLE file;
+
+ shfoW.hwnd = NULL;
+ shfoW.wFunc = FO_DELETE;
+ shfoW.pFrom = UNICODE_PATH;
+ shfoW.pTo = '\0';
+ shfoW.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
+ shfoW.hNameMappings = NULL;
+ shfoW.lpszProgressTitle = NULL;
+
+ /* Clean up before start test */
+ DeleteFileW(UNICODE_PATH);
+ RemoveDirectoryW(UNICODE_PATH);
+
+ /* Make sure we are on a system that supports unicode */
+ SetLastError(0xdeadbeef);
+ file = CreateFileW(UNICODE_PATH, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ skip("Unicode tests skipped on non-unicode system\n");
+ return;
+ }
+ CloseHandle(file);
+
+ /* Try to delete a file with unicode filename */
+ ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
+ ret = SHFileOperationW(&shfoW);
+ ok(!ret, "File is not removed, ErrorCode: %d\n", ret);
+ ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
+
+ /* Try to trash a file with unicode filename */
+ createTestFileW(UNICODE_PATH);
+ shfoW.fFlags |= FOF_ALLOWUNDO;
+ ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
+ ret = SHFileOperationW(&shfoW);
+ ok(!ret, "File is not removed, ErrorCode: %d\n", ret);
+ ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
+
+ if(!pSHCreateDirectoryExW)
+ {
+ skip("Skipping SHCreateDirectoryExW tests\n");
+ return;
+ }
+
+ /* Try to delete a directory with unicode filename */
+ ret = pSHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
+ ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
+ ok(file_existsW(UNICODE_PATH), "The directory is not created\n");
+ shfoW.fFlags &= ~FOF_ALLOWUNDO;
+ ret = SHFileOperationW(&shfoW);
+ ok(!ret, "Directory is not removed, ErrorCode: %d\n", ret);
+ ok(!file_existsW(UNICODE_PATH), "The directory should have been removed\n");
+
+ /* Try to trash a directory with unicode filename */
+ ret = pSHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
+ ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
+ ok(file_existsW(UNICODE_PATH), "The directory was not created\n");
+ shfoW.fFlags |= FOF_ALLOWUNDO;
+ ret = SHFileOperationW(&shfoW);
+ ok(!ret, "Directory is not removed, ErrorCode: %d\n", ret);
+ ok(!file_existsW(UNICODE_PATH), "The directory should have been removed\n");
}
START_TEST(shlfileop)
clean_after_shfo_tests();
+ init_shfo_tests();
+ test_get_file_info();
+ clean_after_shfo_tests();
+
init_shfo_tests();
test_delete();
clean_after_shfo_tests();
test_sh_create_dir();
clean_after_shfo_tests();
+
+ test_unicode();
}
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#define COBJMACROS
+#define CONST_VTABLE
#include "windef.h"
#include "winbase.h"
#include "shlguid.h"
#include "shlobj.h"
-//#include "shobjidl.h"
+#include "shobjidl.h"
#include "shlwapi.h"
+#include "ocidl.h"
+#include "oleauto.h"
-
-#include "wine/unicode.h"
#include "wine/test.h"
static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
+static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
+static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
+static void (WINAPI *pILFree)(LPITEMIDLIST);
+static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
static void init_function_pointers(void)
{
- HMODULE hmod = GetModuleHandleA("shell32.dll");
+ HMODULE hmod;
HRESULT hr;
- if(hmod)
- {
- pSHBindToParent = (void*)GetProcAddress(hmod, "SHBindToParent");
- pSHGetSpecialFolderPathW = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathW");
- }
+ hmod = GetModuleHandleA("shell32.dll");
+ pSHBindToParent = (void*)GetProcAddress(hmod, "SHBindToParent");
+ pSHGetSpecialFolderPathW = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathW");
+ pILFindLastID = (void *)GetProcAddress(hmod, (LPCSTR)16);
+ pILFree = (void*)GetProcAddress(hmod, (LPSTR)155);
+ pILIsEqual = (void*)GetProcAddress(hmod, (LPSTR)21);
+
+ hmod = GetModuleHandleA("shlwapi.dll");
+ pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
hr = SHGetMalloc(&ppM);
- ok(hr == S_OK, "SHGetMalloc failed %08lx\n", hr);
+ ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
}
static void test_ParseDisplayName(void)
DWORD res;
WCHAR cTestDirW [MAX_PATH] = {0};
ITEMIDLIST *newPIDL;
+ BOOL bRes;
hr = SHGetDesktopFolder(&IDesktopFolder);
if(hr != S_OK) return;
hr = IShellFolder_ParseDisplayName(IDesktopFolder,
NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
- "ParseDisplayName returned %08lx, expected 80070002 or E_FAIL\n", hr);
+ "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
res = GetFileAttributesA(cNonExistDir2A);
if(res != INVALID_FILE_ATTRIBUTES) return;
MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
hr = IShellFolder_ParseDisplayName(IDesktopFolder,
NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
- ok((hr == E_FAIL), "ParseDisplayName returned %08lx, expected E_FAIL\n", hr);
+ ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
+ "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
+
+ /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
+ * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
+ * out it doesn't. The magic seems to happen in the file dialogs, then. */
+ if (!pSHGetSpecialFolderPathW || !pILFindLastID) goto finished;
+
+ bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
+ ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
+ if (!bRes) goto finished;
+
+ hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
+ ok(SUCCEEDED(hr), "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
+ if (FAILED(hr)) goto finished;
+
+ ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31, "Last pidl should be of type "
+ "PT_FOLDER, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
+ IMalloc_Free(ppM, newPIDL);
+
+finished:
+ IShellFolder_Release(IDesktopFolder);
}
/* creates a file with the specified name for tests */
{ 1, 1, 1, 1, 0}
};
- /* Just test SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR for now */
+#define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
+ /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
static const ULONG attrs[5] =
{
- SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
- SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
- SFGAO_FILESYSTEM,
- SFGAO_FILESYSTEM,
- SFGAO_FILESYSTEM,
+ SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
+ SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
+ SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
+ SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
+ SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
};
hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
- ok(hr == S_OK, "EnumObjects failed %08lx\n", hr);
+ ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
/* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
* the filesystem shellfolders return S_OK even if less than 'celt' items are
ok (i == 5, "i: %d\n", i);
hr = IEnumIDList_Release(iEnumList);
- ok(hr == S_OK, "IEnumIDList_Release failed %08lx\n", hr);
+ ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
/* Sort them first in case of wrong order from system */
for (i=0;i<5;i++) for (j=0;j<5;j++)
for (i=0;i<5;i++) for (j=0;j<5;j++)
{
hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
- ok(hr == iResults[i][j], "Got %lx expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
+ ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
}
for (i = 0; i < 5; i++)
{
SFGAOF flags;
- flags = SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
+ /* Native returns all flags no matter what we ask for */
+ flags = SFGAO_CANCOPY;
hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
- flags &= SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
- ok(hr == S_OK, "GetAttributesOf returns %08lx\n", hr);
- ok(flags == attrs[i], "GetAttributesOf gets attrs %08lx, expects %08lx\n", flags, attrs[i]);
+ flags &= SFGAO_testfor;
+ ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
+ ok(flags == (attrs[i]), "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
+
+ flags = SFGAO_testfor;
+ hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
+ flags &= SFGAO_testfor;
+ ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
+ ok(flags == attrs[i], "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
}
for (i=0;i<5;i++)
SHITEMID emptyitem = { 0, { 0 } };
LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
WCHAR wszSystemDir[MAX_PATH];
+ char szSystemDir[MAX_PATH];
WCHAR wszMyComputer[] = {
':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
* with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
*/
hr = SHGetDesktopFolder(&psfDesktop);
- ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
if (FAILED(hr)) return;
hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
- ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08lx\n", hr);
+ ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
- ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08lx\n", hr);
+ ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
- ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfDesktop);
return;
}
hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
- ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
IShellFolder_Release(psfDesktop);
IMalloc_Free(ppM, pidlMyComputer);
if (FAILED(hr)) return;
hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
- ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08lx\n", hr);
+ ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
+#if 0
+ /* this call segfaults on 98SE */
hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
- ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08lx\n", hr);
+ ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
+#endif
- cChars = GetSystemDirectoryW(wszSystemDir, MAX_PATH);
- ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryW failed! LastError: %08lx\n", GetLastError());
+ cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
+ ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
if (cChars == 0 || cChars >= MAX_PATH) {
IShellFolder_Release(psfMyComputer);
return;
}
+ MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
- ok (SUCCEEDED(hr), "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfMyComputer);
return;
}
hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
- ok (SUCCEEDED(hr), "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
IShellFolder_Release(psfMyComputer);
IMalloc_Free(ppM, pidlSystemDir);
if (FAILED(hr)) return;
hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
ok (hr == E_INVALIDARG,
- "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08lx\n", hr);
+ "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
+#if 0
+ /* this call segfaults on 98SE */
hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
ok (hr == E_INVALIDARG,
- "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08lx\n", hr);
+ "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
+#endif
IShellFolder_Release(psfSystemDir);
}
HRESULT hr;
HANDLE hTestFile;
WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH], wszTestDir[MAX_PATH];
+ char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
+ DWORD attr;
STRRET strret;
LPSHELLFOLDER psfDesktop, psfPersonal;
IUnknown *psfFile;
- LPITEMIDLIST pidlTestFile;
+ SHITEMID emptyitem = { 0, { 0 } };
+ LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
LPCITEMIDLIST pidlLast;
static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
/* First creating a directory in MyDocuments and a file in this directory. */
result = pSHGetSpecialFolderPathW(NULL, wszTestDir, CSIDL_PERSONAL, FALSE);
- ok(result, "SHGetSpecialFolderPathW failed! Last error: %08lx\n", GetLastError());
+ ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
if (!result) return;
PathAddBackslashW(wszTestDir);
lstrcatW(wszTestDir, wszDirName);
- result = CreateDirectoryW(wszTestDir, NULL);
- ok(result, "CreateDirectoryW failed! Last error: %08lx\n", GetLastError());
- if (!result) return;
+ /* Use ANSI file functions so this works on Windows 9x */
+ WideCharToMultiByte(CP_ACP, 0, wszTestDir, -1, szTestDir, MAX_PATH, 0, 0);
+ CreateDirectoryA(szTestDir, NULL);
+ attr=GetFileAttributesA(szTestDir);
+ if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ ok(0, "unable to create the '%s' directory\n", szTestDir);
+ return;
+ }
lstrcpyW(wszTestFile, wszTestDir);
PathAddBackslashW(wszTestFile);
lstrcatW(wszTestFile, wszFileName);
+ WideCharToMultiByte(CP_ACP, 0, wszTestFile, -1, szTestFile, MAX_PATH, 0, 0);
- hTestFile = CreateFileW(wszTestFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
- ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %08lx\n", GetLastError());
+ hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
if (hTestFile == INVALID_HANDLE_VALUE) return;
CloseHandle(hTestFile);
/* Getting an itemidlist for the file. */
hr = SHGetDesktopFolder(&psfDesktop);
- ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
if (FAILED(hr)) return;
hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
- ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08lx\n", hr);
+ ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfDesktop);
return;
}
+ /* WinXP stores the filenames as both ANSI and UNICODE in the pidls */
+ pidlLast = pILFindLastID(pidlTestFile);
+ ok(pidlLast->mkid.cb >=76, "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
+ if (pidlLast->mkid.cb >= 76) {
+ ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName),
+ "WinXP stores the filename as a wchar-string at this position!\n");
+ }
+
/* It seems as if we cannot bind to regular files on windows, but only directories.
*/
hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
- todo_wine { ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hr = %08lx\n", hr); }
+ todo_wine { ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hr = %08x\n", hr); }
if (SUCCEEDED(hr)) {
IShellFolder_Release(psfFile);
}
-
+
+ /* Some tests for IShellFolder::SetNameOf */
+ hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
+ ok(SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr);
+ if (SUCCEEDED(hr)) {
+ /* It's ok to use this fixed path. Call will fail anyway. */
+ WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
+ LPITEMIDLIST pidlNew;
+
+ /* The pidl returned through the last parameter of SetNameOf is a simple one. */
+ hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
+ ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr);
+ ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
+ "pidl returned from SetNameOf should be simple!\n");
+
+ /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
+ * is implemented on top of SHFileOperation in WinXP. */
+ hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
+ SHGDN_FORPARSING, NULL);
+ ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
+
+ /* Rename the file back to its original name. SetNameOf ignores the fact, that the
+ * SHGDN flags specify an absolute path. */
+ hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
+ ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr);
+
+ pILFree(pidlNew);
+ IShellFolder_Release(psfPersonal);
+ }
+
/* Deleting the file and the directory */
- DeleteFileW(wszTestFile);
- RemoveDirectoryW(wszTestDir);
+ DeleteFileA(szTestFile);
+ RemoveDirectoryA(szTestDir);
/* SHGetPathFromIDListW still works, although the file is not present anymore. */
result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
- ok (result, "SHGetPathFromIDListW failed! Last error: %08lx\n", GetLastError());
+ ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
if(!pSHBindToParent) return;
+ /* SHBindToParent fails, if called with a NULL PIDL. */
+ hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
+ ok (FAILED(hr), "SHBindToParent(NULL) should fail!\n");
+
+ /* But it succeeds with an empty PIDL. */
+ hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
+ ok (SUCCEEDED(hr), "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
+ ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
+ if (SUCCEEDED(hr))
+ IShellFolder_Release(psfPersonal);
+
/* Binding to the folder and querying the display name of the file also works. */
hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
- ok (SUCCEEDED(hr), "SHBindToParent failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfDesktop);
return;
}
+ /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
+ * pidlTestFile (In accordance with MSDN). */
+ ok (pILFindLastID(pidlTestFile) == pidlLast,
+ "SHBindToParent doesn't return the last id of the pidl param!\n");
+
hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
- ok (SUCCEEDED(hr), "Personal->GetDisplayNameOf failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfDesktop);
IShellFolder_Release(psfPersonal);
return;
}
-
- hr = StrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
- ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08lx\n", hr);
- ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
+
+ if (pStrRetToBufW)
+ {
+ hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
+ ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
+ ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
+ }
IShellFolder_Release(psfDesktop);
IShellFolder_Release(psfPersonal);
* on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
*/
hr = SHGetDesktopFolder(&psfDesktop);
- ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
if (FAILED(hr)) return;
hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
&pidlMyDocuments, NULL);
ok (SUCCEEDED(hr),
- "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08lx\n", hr);
+ "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfDesktop);
return;
dwAttributes = 0xffffffff;
hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
(LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
- ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
/* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
- todo_wine{ ok (dwAttributes & SFGAO_FILESYSTEM,
- "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n"); }
+ ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
* key. So the test will return at this point, if run on wine.
*/
lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
- todo_wine { ok (lResult == ERROR_SUCCESS, "RegOpenKeyEx failed! result: %08lx\n", lResult); }
+ ok (lResult == ERROR_SUCCESS, "RegOpenKeyEx failed! result: %08x\n", lResult);
if (lResult != ERROR_SUCCESS) {
IMalloc_Free(ppM, pidlMyDocuments);
IShellFolder_Release(psfDesktop);
/* Query MyDocuments' Attributes value, to be able to restore it later. */
dwSize = sizeof(DWORD);
lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
- ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08lx\n", lResult);
+ ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
if (lResult != ERROR_SUCCESS) {
RegCloseKey(hKey);
IMalloc_Free(ppM, pidlMyDocuments);
dwSize = sizeof(DWORD);
lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
(LPBYTE)&dwOrigCallForAttributes, &dwSize);
- ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08lx\n", lResult);
+ ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
if (lResult != ERROR_SUCCESS) {
RegCloseKey(hKey);
IMalloc_Free(ppM, pidlMyDocuments);
dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
(LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
- ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
if (SUCCEEDED(hr))
ok (dwAttributes == SFGAO_FILESYSTEM,
- "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08lx\n",
+ "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
dwAttributes);
/* Restore MyDocuments' original Attributes and CallForAttributes registry values */
LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
LPITEMIDLIST pidlMyComputer;
DWORD dwFlags;
- const static DWORD dwDesktopFlags = /* As observed on WinXP SP2 */
+ static const DWORD dwDesktopFlags = /* As observed on WinXP SP2 */
SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
- const static DWORD dwMyComputerFlags = /* As observed on WinXP SP2 */
+ static const DWORD dwMyComputerFlags = /* As observed on WinXP SP2 */
SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
WCHAR wszMyComputer[] = {
':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
+ char cCurrDirA [MAX_PATH] = {0};
+ WCHAR cCurrDirW [MAX_PATH];
+ static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
+ static const WCHAR cBackSlash[] = {'\\',0};
+ IShellFolder *IDesktopFolder, *testIShellFolder;
+ ITEMIDLIST *newPIDL;
+ int len;
hr = SHGetDesktopFolder(&psfDesktop);
- ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
if (FAILED(hr)) return;
/* The Desktop attributes can be queried with a single empty itemidlist, .. */
dwFlags = 0xffffffff;
hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
- ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08lx\n", hr);
- ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08lx, expected: %08lx\n",
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
+ ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08x, expected: %08x\n",
dwFlags, dwDesktopFlags);
/* .. or with no itemidlist at all. */
dwFlags = 0xffffffff;
hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
- ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(NULL) failed! hr = %08lx\n", hr);
- ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08lx, expected: %08lx\n",
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
+ ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08x, expected: %08x\n",
dwFlags, dwDesktopFlags);
/* Testing the attributes of the MyComputer shellfolder */
hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
- ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(psfDesktop);
return;
*/
dwFlags = 0xffffffff;
hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
- ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08lx\n", hr);
- todo_wine { ok ((dwFlags & ~(DWORD)SFGAO_CANLINK) == dwMyComputerFlags,
- "Wrong MyComputer attributes: %08lx, expected: %08lx\n", dwFlags, dwMyComputerFlags); }
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
+ ok ((dwFlags & ~(DWORD)SFGAO_CANLINK) == dwMyComputerFlags,
+ "Wrong MyComputer attributes: %08x, expected: %08x\n", dwFlags, dwMyComputerFlags);
hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
- ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
IShellFolder_Release(psfDesktop);
IMalloc_Free(ppM, pidlMyComputer);
if (FAILED(hr)) return;
hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
- todo_wine {ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08lx\n", hr); }
+ todo_wine {ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr); }
dwFlags = 0xffffffff;
hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
- ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
todo_wine { ok (dwFlags == dwMyComputerFlags,
- "Wrong MyComputer attributes: %08lx, expected: %08lx\n", dwFlags, dwMyComputerFlags); }
+ "Wrong MyComputer attributes: %08x, expected: %08x\n", dwFlags, dwMyComputerFlags); }
IShellFolder_Release(psfMyComputer);
+
+ /* create test directory */
+ CreateFilesFolders();
+
+ GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
+ len = lstrlenA(cCurrDirA);
+
+ if (len == 0) {
+ trace("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
+ return;
+ }
+ if(cCurrDirA[len-1] == '\\')
+ cCurrDirA[len-1] = 0;
+
+ MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
+
+ hr = SHGetDesktopFolder(&IDesktopFolder);
+ ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
+
+ hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
+ ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
+
+ hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
+ ok(hr == S_OK, "BindToObject failed %08x\n", hr);
+
+ IMalloc_Free(ppM, newPIDL);
+
+ /* get relative PIDL */
+ hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
+ ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
+
+ /* test the shell attributes of the test directory using the relative PIDL */
+ dwFlags = SFGAO_FOLDER;
+ hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
+ ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
+
+ /* free memory */
+ IMalloc_Free(ppM, newPIDL);
+
+ /* append testdirectory name to path */
+ lstrcatW(cCurrDirW, cBackSlash);
+ lstrcatW(cCurrDirW, cTestDirW);
+
+ hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
+ ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
+
+ /* test the shell attributes of the test directory using the absolute PIDL */
+ dwFlags = SFGAO_FOLDER;
+ hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
+ ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
+
+ /* free memory */
+ IMalloc_Free(ppM, newPIDL);
+
+ IShellFolder_Release(testIShellFolder);
+
+ Cleanup();
+
+ IShellFolder_Release(IDesktopFolder);
}
static void test_SHGetPathFromIDList(void)
WCHAR wszMyComputer[] = {
':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
+ WCHAR wszFileName[MAX_PATH];
+ LPITEMIDLIST pidlTestFile;
+ HANDLE hTestFile;
+ STRRET strret;
+ static WCHAR wszTestFile[] = {
+ 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
+ HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
+ HMODULE hShell32;
+ LPITEMIDLIST pidlPrograms;
if(!pSHGetSpecialFolderPathW) return;
+ /* Calling SHGetPathFromIDList with no pidl should return the empty string */
+ wszPath[0] = 'a';
+ wszPath[1] = '\0';
+ result = SHGetPathFromIDListW(NULL, wszPath);
+ ok(!result, "Expected failure\n");
+ ok(!wszPath[0], "Expected empty string\n");
+
/* Calling SHGetPathFromIDList with an empty pidl should return the desktop folder's path. */
result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
- ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %08lx\n", GetLastError());
+ ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
if (!result) return;
result = SHGetPathFromIDListW(pidlEmpty, wszPath);
- ok(result, "SHGetPathFromIDListW failed! Last error: %08lx\n", GetLastError());
+ ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
if (!result) return;
ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDList didn't return desktop path for empty pidl!\n");
/* MyComputer does not map to a filesystem path. SHGetPathFromIDList should fail. */
hr = SHGetDesktopFolder(&psfDesktop);
- ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
if (FAILED(hr)) return;
hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
- ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08lx\n", hr);
- IShellFolder_Release(psfDesktop);
- if (FAILED(hr)) return;
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
SetLastError(0xdeadbeef);
+ wszPath[0] = 'a';
+ wszPath[1] = '\0';
result = SHGetPathFromIDListW(pidlMyComputer, wszPath);
ok (!result, "SHGetPathFromIDList succeeded where it shouldn't!\n");
- ok (GetLastError()==0xdeadbeef, "SHGetPathFromIDList shouldn't set last error! Last error: %08lx\n", GetLastError());
+ ok (GetLastError()==0xdeadbeef, "SHGetPathFromIDList shouldn't set last error! Last error: %u\n", GetLastError());
+ ok (!wszPath[0], "Expected empty path\n");
+ if (result) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
IMalloc_Free(ppM, pidlMyComputer);
+
+ result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
+ ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
+ if (!result) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+ PathAddBackslashW(wszFileName);
+ lstrcatW(wszFileName, wszTestFile);
+ hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
+ ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
+ if (hTestFile == INVALID_HANDLE_VALUE) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+ CloseHandle(hTestFile);
+
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ DeleteFileW(wszFileName);
+ IMalloc_Free(ppM, pidlTestFile);
+ return;
+ }
+
+ /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
+ * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
+ hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
+ ok (SUCCEEDED(hr), "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
+ IShellFolder_Release(psfDesktop);
+ DeleteFileW(wszFileName);
+ if (FAILED(hr)) {
+ IMalloc_Free(ppM, pidlTestFile);
+ return;
+ }
+ if (pStrRetToBufW)
+ {
+ pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
+ ok(0 == lstrcmpW(wszFileName, wszPath),
+ "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
+ "returned incorrect path for file placed on desktop\n");
+ }
+
+ result = SHGetPathFromIDListW(pidlTestFile, wszPath);
+ ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
+ IMalloc_Free(ppM, pidlTestFile);
+ if (!result) return;
+ ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
+
+
+ /* Test if we can get the path from the start menu "program files" PIDL. */
+ hShell32 = GetModuleHandleA("shell32");
+ pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
+
+ hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
+ ok(SUCCEEDED(hr), "SHGetFolderLocation failed: 0x%08x\n", hr);
+
+ SetLastError(0xdeadbeef);
+ result = SHGetPathFromIDListW(pidlPrograms, wszPath);
+ IMalloc_Free(ppM, pidlPrograms);
+ ok(result, "SHGetPathFromIDList failed\n");
}
static void test_EnumObjects_and_CompareIDs(void)
cCurrDirA[len-1] = 0;
MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
- strcatW(cCurrDirW, cTestDirW);
+ lstrcatW(cCurrDirW, cTestDirW);
hr = SHGetDesktopFolder(&IDesktopFolder);
- ok(hr == S_OK, "SHGetDesktopfolder failed %08lx\n", hr);
+ ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
CreateFilesFolders();
hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
- ok(hr == S_OK, "ParseDisplayName failed %08lx\n", hr);
+ ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
- ok(hr == S_OK, "BindToObject failed %08lx\n", hr);
+ ok(hr == S_OK, "BindToObject failed %08x\n", hr);
test_EnumObjects(testIShellFolder);
- hr = IShellFolder_Release(testIShellFolder);
- ok(hr == S_OK, "IShellFolder_Release failed %08lx\n", hr);
+ IShellFolder_Release(testIShellFolder);
Cleanup();
IMalloc_Free(ppM, newPIDL);
+
+ IShellFolder_Release(IDesktopFolder);
+}
+
+/* A simple implementation of an IPropertyBag, which returns fixed values for
+ * 'Target' and 'Attributes' properties.
+ */
+static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
+ void **ppvObject)
+{
+ if (!ppvObject)
+ return E_INVALIDARG;
+
+ if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
+ *ppvObject = iface;
+ } else {
+ ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
+ return E_NOINTERFACE;
+ }
+
+ IPropertyBag_AddRef(iface);
+ return S_OK;
+}
+
+static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
+ return 2;
+}
+
+static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
+ return 1;
+}
+
+static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
+ VARIANT *pVar, IErrorLog *pErrorLog)
+{
+ static const WCHAR wszTargetSpecialFolder[] = {
+ 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
+ static const WCHAR wszTarget[] = {
+ 'T','a','r','g','e','t',0 };
+ static const WCHAR wszAttributes[] = {
+ 'A','t','t','r','i','b','u','t','e','s',0 };
+ static const WCHAR wszResolveLinkFlags[] = {
+ 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
+
+ if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
+ ok(V_VT(pVar) == VT_I4, "Wrong variant type for 'TargetSpecialFolder' property!\n");
+ return E_INVALIDARG;
+ }
+
+ if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
+ {
+ ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
+ return E_INVALIDARG;
+ }
+
+ if (!lstrcmpW(pszPropName, wszTarget)) {
+ WCHAR wszPath[MAX_PATH];
+ BOOL result;
+
+ ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'Target' property!\n");
+ if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
+
+ result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
+ ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
+ if (!result) return E_INVALIDARG;
+
+ V_BSTR(pVar) = SysAllocString(wszPath);
+ return S_OK;
+ }
+
+ if (!lstrcmpW(pszPropName, wszAttributes)) {
+ ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
+ if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
+ V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
+ SFGAO_CANRENAME|SFGAO_FILESYSTEM;
+ return S_OK;
+ }
+
+ ok(FALSE, "PropertyBag was asked for unknown property (vt=%d)!\n", V_VT(pVar));
+ return E_INVALIDARG;
+}
+
+static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
+ VARIANT *pVar)
+{
+ ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
+ return E_NOTIMPL;
+}
+
+static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
+ InitPropertyBag_IPropertyBag_QueryInterface,
+ InitPropertyBag_IPropertyBag_AddRef,
+ InitPropertyBag_IPropertyBag_Release,
+ InitPropertyBag_IPropertyBag_Read,
+ InitPropertyBag_IPropertyBag_Write
+};
+
+static struct IPropertyBag InitPropertyBag = {
+ &InitPropertyBag_IPropertyBagVtbl
+};
+
+static void test_FolderShortcut(void) {
+ IPersistPropertyBag *pPersistPropertyBag;
+ IShellFolder *pShellFolder, *pDesktopFolder;
+ IPersistFolder3 *pPersistFolder3;
+ HRESULT hr;
+ STRRET strret;
+ WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
+ BOOL result;
+ CLSID clsid;
+ LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
+ HKEY hShellExtKey;
+ WCHAR wszWineTestFolder[] = {
+ ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
+ 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
+ WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
+ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+ 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
+ 'N','a','m','e','S','p','a','c','e','\\',
+ '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
+ 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
+
+ WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
+ static const GUID CLSID_UnixDosFolder =
+ {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
+
+ if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) return;
+
+ /* These tests basically show, that CLSID_FolderShortcuts are initialized
+ * via their IPersistPropertyBag interface. And that the target folder
+ * is taken from the IPropertyBag's 'Target' property.
+ */
+ hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
+ ok (SUCCEEDED(hr), "CoCreateInstance failed! hr = 0x%08x\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
+ ok(SUCCEEDED(hr), "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IPersistPropertyBag_Release(pPersistPropertyBag);
+ return;
+ }
+
+ hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
+ (LPVOID*)&pShellFolder);
+ IPersistPropertyBag_Release(pPersistPropertyBag);
+ ok(SUCCEEDED(hr), "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
+ ok(SUCCEEDED(hr), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(pShellFolder);
+ return;
+ }
+
+ result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
+ ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
+ if (!result) return;
+
+ pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
+ ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
+
+ hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
+ IShellFolder_Release(pShellFolder);
+ ok(SUCCEEDED(hr), "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
+ ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
+ ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
+
+ hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
+ ok(SUCCEEDED(hr), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
+ ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
+
+ /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
+ * shell namespace. The target folder, read from the property bag above, remains untouched.
+ * The following tests show this: The itemidlist for some imaginary shellfolder object
+ * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
+ * itemidlist, but GetDisplayNameOf still returns the path from above.
+ */
+ hr = SHGetDesktopFolder(&pDesktopFolder);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
+ if (FAILED(hr)) return;
+
+ /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
+ * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
+ RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
+ RegCloseKey(hShellExtKey);
+ hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
+ &pidlWineTestFolder, NULL);
+ RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
+ IShellFolder_Release(pDesktopFolder);
+ ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
+ ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IPersistFolder3_Release(pPersistFolder3);
+ pILFree(pidlWineTestFolder);
+ return;
+ }
+
+ hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
+ ok(SUCCEEDED(hr), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
+ ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
+ "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
+ pILFree(pidlCurrentFolder);
+ pILFree(pidlWineTestFolder);
+
+ hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
+ IPersistFolder3_Release(pPersistFolder3);
+ ok(SUCCEEDED(hr), "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
+ ok(SUCCEEDED(hr), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(pShellFolder);
+ return;
+ }
+
+ pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
+ ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
+
+ /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
+ * but ShellFSFolders. */
+ PathAddBackslashW(wszDesktopPath);
+ lstrcatW(wszDesktopPath, wszSomeSubFolder);
+ if (!CreateDirectoryW(wszDesktopPath, NULL)) {
+ IShellFolder_Release(pShellFolder);
+ return;
+ }
+
+ hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
+ &pidlSubFolder, NULL);
+ RemoveDirectoryW(wszDesktopPath);
+ ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(pShellFolder);
+ return;
+ }
+
+ hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
+ (LPVOID*)&pPersistFolder3);
+ IShellFolder_Release(pShellFolder);
+ pILFree(pidlSubFolder);
+ ok (SUCCEEDED(hr), "IShellFolder::BindToObject failed! hr = %08x\n", hr);
+ if (FAILED(hr))
+ return;
+
+ /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
+ * a little bit and also allow CLSID_UnixDosFolder. */
+ hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
+ ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
+ ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
+ "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
+
+ IPersistFolder3_Release(pPersistFolder3);
+}
+
+#include "pshpack1.h"
+struct FileStructA {
+ BYTE type;
+ BYTE dummy;
+ DWORD dwFileSize;
+ WORD uFileDate; /* In our current implementation this is */
+ WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
+ WORD uFileAttribs;
+ CHAR szName[1];
+};
+
+struct FileStructW {
+ WORD cbLen; /* Length of this element. */
+ BYTE abFooBar1[6]; /* Beyond any recognition. */
+ WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
+ WORD uTime; /* (this is currently speculation) */
+ WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
+ WORD uTime2; /* (this is currently speculation) */
+ BYTE abFooBar2[4]; /* Beyond any recognition. */
+ WCHAR wszName[1]; /* The long filename in unicode. */
+ /* Just for documentation: Right after the unicode string: */
+ WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
+ * SHITEMID->cb == uOffset + cbLen */
+};
+#include "poppack.h"
+
+static void test_ITEMIDLIST_format(void) {
+ WCHAR wszPersonal[MAX_PATH];
+ LPSHELLFOLDER psfDesktop, psfPersonal;
+ LPITEMIDLIST pidlPersonal, pidlFile;
+ HANDLE hFile;
+ HRESULT hr;
+ BOOL bResult;
+ WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
+ { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
+ int i;
+
+ if(!pSHGetSpecialFolderPathW) return;
+
+ bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
+ ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
+ if (!bResult) return;
+
+ bResult = SetCurrentDirectoryW(wszPersonal);
+ ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
+ if (!bResult) return;
+
+ hr = SHGetDesktopFolder(&psfDesktop);
+ ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr: %08x\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
+ ok(SUCCEEDED(hr), "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
+ (LPVOID*)&psfPersonal);
+ IShellFolder_Release(psfDesktop);
+ pILFree(pidlPersonal);
+ ok(SUCCEEDED(hr), "psfDesktop->BindToObject failed! hr = %08x\n", hr);
+ if (FAILED(hr)) return;
+
+ for (i=0; i<3; i++) {
+ CHAR szFile[MAX_PATH];
+ struct FileStructA *pFileStructA;
+ WORD cbOffset;
+
+ WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
+
+ hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
+ if (hFile == INVALID_HANDLE_VALUE) {
+ IShellFolder_Release(psfPersonal);
+ return;
+ }
+ CloseHandle(hFile);
+
+ hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
+ DeleteFileW(wszFile[i]);
+ ok(SUCCEEDED(hr), "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfPersonal);
+ return;
+ }
+
+ pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
+ ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
+ ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
+ ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
+
+ if (i < 2) /* First two file names are already in valid 8.3 format */
+ ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
+ else
+ /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
+ * can't implement this correctly, since unix filesystems don't support
+ * this nasty short/long filename stuff. So we'll probably stay with our
+ * current habbit of storing the long filename here, which seems to work
+ * just fine. */
+ todo_wine { ok(pidlFile->mkid.abID[18] == '~', "Should be derived 8.3 name!\n"); }
+
+ if (i == 0) /* First file name has an even number of chars. No need for alignment. */
+ ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0',
+ "Alignment byte, where there shouldn't be!\n");
+
+ if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
+ ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
+ "There should be an alignment byte, but isn't!\n");
+
+ /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
+ cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
+ ok (cbOffset >= sizeof(struct FileStructA) &&
+ cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW),
+ "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
+
+ if (cbOffset >= sizeof(struct FileStructA) &&
+ cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
+ {
+ struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
+
+ ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
+ "FileStructW's offset and length should add up to the PIDL's length!\n");
+
+ if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
+ /* Since we just created the file, time of creation,
+ * time of last access and time of last write access just be the same.
+ * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
+ * after the first run. I do remember something with NTFS keeping the creation time
+ * if a file is deleted and then created again within a couple of seconds or so.
+ * Might be the reason. */
+ ok (pFileStructA->uFileDate == pFileStructW->uDate &&
+ pFileStructA->uFileTime == pFileStructW->uTime,
+ "Last write time should match creation time!\n");
+
+ ok (pFileStructA->uFileDate == pFileStructW->uDate2 &&
+ pFileStructA->uFileTime == pFileStructW->uTime2,
+ "Last write time should match last access time!\n");
+
+ ok (!lstrcmpW(wszFile[i], pFileStructW->wszName),
+ "The filename should be stored in unicode at this position!\n");
+ }
+ }
+
+ pILFree(pidlFile);
+ }
}
START_TEST(shlfolder)
test_GetAttributesOf();
test_SHGetPathFromIDList();
test_CallForAttributes();
+ test_FolderShortcut();
+ test_ITEMIDLIST_format();
OleUninitialize();
}
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
#define WINE_NOWINSOCK
#include "windef.h"
#include "winbase.h"
trace("StrRetToStringNAW is Unicode\n");
strret.uType = STRRET_WSTR;
- strret.u.pOleStr = CoDupStrW("Test");
+ U(strret).pOleStr = CoDupStrW("Test");
memset(buff, 0xff, sizeof(buff));
ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
ok(ret == TRUE && !strcmpW(buff, szTestW),
"STRRET_WSTR: dup failed, ret=%d\n", ret);
strret.uType = STRRET_CSTR;
- lstrcpyA(strret.u.cStr, "Test");
+ lstrcpyA(U(strret).cStr, "Test");
memset(buff, 0xff, sizeof(buff));
ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
ok(ret == TRUE && !strcmpW(buff, szTestW),
"STRRET_CSTR: dup failed, ret=%d\n", ret);
strret.uType = STRRET_OFFSET;
- strret.u.uOffset = 1;
+ U(strret).uOffset = 1;
strcpy((char*)&iidl, " Test");
memset(buff, 0xff, sizeof(buff));
ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, iidl);
#if 0
/* Invalid dest - should return FALSE, except NT4 does not, so we don't check. */
strret.uType = STRRET_WSTR;
- strret.u.pOleStr = CoDupStrW("Test");
+ U(strret).pOleStr = CoDupStrW("Test");
pStrRetToStrNAW(NULL, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
trace("NULL dest: ret=%d\n", ret);
#endif
{
CoInitialize(0);
- hShell32 = LoadLibraryA("shell32.dll");
- if (!hShell32)
- return;
+ hShell32 = GetModuleHandleA("shell32.dll");
pStrRetToStrNAW = (void*)GetProcAddress(hShell32, (LPSTR)96);
if (pStrRetToStrNAW)
--- /dev/null
+/* Unit tests for systray
+ *
+ * Copyright 2007 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#define _WIN32_IE 0x600
+#include <assert.h>
+#include <stdarg.h>
+
+#include <windows.h>
+
+#include "wine/test.h"
+
+
+static HWND hMainWnd;
+
+void test_cbsize()
+{
+ NOTIFYICONDATAW nidW;
+ NOTIFYICONDATAA nidA;
+
+ ZeroMemory(&nidW, sizeof(nidW));
+ nidW.cbSize = NOTIFYICONDATAW_V1_SIZE;
+ nidW.hWnd = hMainWnd;
+ nidW.uID = 1;
+ nidW.uFlags = NIF_ICON|NIF_MESSAGE;
+ nidW.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ nidW.uCallbackMessage = WM_USER+17;
+ ok(Shell_NotifyIconW(NIM_ADD, &nidW), "NIM_ADD failed!\n");
+
+ /* using an invalid cbSize does work */
+ nidW.cbSize = 3;
+ nidW.hWnd = hMainWnd;
+ nidW.uID = 1;
+ ok(Shell_NotifyIconW(NIM_DELETE, &nidW), "NIM_DELETE failed!\n");
+ /* as icon doesn't exist anymore - now there will be an error */
+ nidW.cbSize = sizeof(nidW);
+ /* wine currently doesn't return error code put prints an ERR(...) */
+ todo_wine ok(!Shell_NotifyIconW(NIM_DELETE, &nidW), "The icon was not deleted\n");
+
+ /* same for Shell_NotifyIconA */
+ ZeroMemory(&nidA, sizeof(nidA));
+ nidA.cbSize = NOTIFYICONDATAA_V1_SIZE;
+ nidA.hWnd = hMainWnd;
+ nidA.uID = 1;
+ nidA.uFlags = NIF_ICON|NIF_MESSAGE;
+ nidA.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ nidA.uCallbackMessage = WM_USER+17;
+ ok(Shell_NotifyIconA(NIM_ADD, &nidA), "NIM_ADD failed!\n");
+
+ /* using an invalid cbSize does work */
+ nidA.cbSize = 3;
+ nidA.hWnd = hMainWnd;
+ nidA.uID = 1;
+ ok(Shell_NotifyIconA(NIM_DELETE, &nidA), "NIM_DELETE failed!\n");
+ /* as icon doesn't exist anymore - now there will be an error */
+ nidA.cbSize = sizeof(nidA);
+ /* wine currently doesn't return error code put prints an ERR(...) */
+ todo_wine ok(!Shell_NotifyIconA(NIM_DELETE, &nidA), "The icon was not deleted\n");
+}
+
+START_TEST(systray)
+{
+ WNDCLASSA wc;
+ MSG msg;
+ RECT rc;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandleA(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
+ wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "MyTestWnd";
+ wc.lpfnWndProc = DefWindowProc;
+ RegisterClassA(&wc);
+
+ hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+ GetClientRect(hMainWnd, &rc);
+ ShowWindow(hMainWnd, SW_SHOW);
+
+ test_cbsize();
+
+ PostQuitMessage(0);
+ while(GetMessageA(&msg,0,0,0)) {
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ }
+ DestroyWindow(hMainWnd);
+}
extern void func_shlfileop(void);
extern void func_shlfolder(void);
extern void func_string(void);
+extern void func_systray(void);
const struct test winetest_testlist[] =
{
-// { "generated", func_generated },
+ { "generated", func_generated },
{ "shelllink", func_shelllink },
{ "shellpath", func_shellpath },
{ "shlexec", func_shlexec },
{ "shlfileop", func_shlfileop },
{ "shlfolder", func_shlfolder },
{ "string", func_string },
+ { "systray", func_systray },
{ 0, 0 }
};