mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00
added shell32 tests. Not enabled just yet
svn path=/trunk/; revision=17268
This commit is contained in:
parent
be6f8b5112
commit
877dc5eaf7
10 changed files with 4664 additions and 0 deletions
1414
reactos/regtests/winetests/shell32/generated.c
Executable file
1414
reactos/regtests/winetests/shell32/generated.c
Executable file
File diff suppressed because it is too large
Load diff
16
reactos/regtests/winetests/shell32/shell32.xml
Normal file
16
reactos/regtests/winetests/shell32/shell32.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<module name="shell32_winetest" type="win32cui" installbase="bin" installname="shell32_winetest.exe" warnings="true">
|
||||
<include base="shell32_winetest">.</include>
|
||||
<define name="__USE_W32API" />
|
||||
<library>ntdll</library>
|
||||
<library>shell32</library>
|
||||
<library>shlwapi</library>
|
||||
<library>ole32</library>
|
||||
<library>uuid</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>
|
||||
</module>
|
37
reactos/regtests/winetests/shell32/shell32_test.h
Executable file
37
reactos/regtests/winetests/shell32/shell32_test.h
Executable file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Unit test suite for shell32 functions
|
||||
*
|
||||
* Copyright 2005 Francois Gougett for CodeWeavers
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/* Helper function for creating .lnk files */
|
||||
typedef struct
|
||||
{
|
||||
const char* description;
|
||||
const char* workdir;
|
||||
const char* path;
|
||||
LPITEMIDLIST pidl;
|
||||
const char* arguments;
|
||||
int showcmd;
|
||||
const char* icon;
|
||||
int icon_id;
|
||||
WORD hotkey;
|
||||
} lnk_desc_t;
|
||||
|
||||
#define create_lnk(a,b,c) create_lnk_(__LINE__, (a), (b), (c))
|
||||
void create_lnk_(int,const WCHAR*,lnk_desc_t*,int);
|
533
reactos/regtests/winetests/shell32/shelllink.c
Executable file
533
reactos/regtests/winetests/shell32/shelllink.c
Executable file
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* Unit tests for shelllinks
|
||||
*
|
||||
* Copyright 2004 Mike McCormack
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "shlguid.h"
|
||||
//#include "wine/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);
|
||||
|
||||
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 };
|
||||
|
||||
|
||||
/* 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 path_to_pidl(const char* path)
|
||||
{
|
||||
LPITEMIDLIST pidl;
|
||||
|
||||
if (!pSHSimpleIDListFromPathA)
|
||||
{
|
||||
HMODULE hdll=LoadLibraryA("shell32.dll");
|
||||
pSHSimpleIDListFromPathA=(void*)GetProcAddress(hdll, (char*)162);
|
||||
if (!pSHSimpleIDListFromPathA)
|
||||
trace("SHSimpleIDListFromPathA not found in shell32.dll\n");
|
||||
}
|
||||
|
||||
pidl=NULL;
|
||||
if (pSHSimpleIDListFromPathA)
|
||||
pidl=pSHSimpleIDListFromPathA(path);
|
||||
|
||||
if (!pidl)
|
||||
{
|
||||
WCHAR* pathW;
|
||||
HRESULT r;
|
||||
int len;
|
||||
|
||||
len=MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
|
||||
pathW=HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
|
||||
MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
|
||||
|
||||
r=SHILCreateFromPath(pathW, &pidl, NULL);
|
||||
todo_wine {
|
||||
ok(SUCCEEDED(r), "SHILCreateFromPath failed (0x%08lx)\n", r);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, pathW);
|
||||
}
|
||||
return pidl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test manipulation of an IShellLink's properties.
|
||||
*/
|
||||
|
||||
static void test_get_set(void)
|
||||
{
|
||||
HRESULT r;
|
||||
IShellLinkA *sl;
|
||||
char mypath[MAX_PATH];
|
||||
char buffer[INFOTIPSIZE];
|
||||
LPITEMIDLIST pidl, tmp_pidl;
|
||||
const char * str;
|
||||
int i;
|
||||
WORD w;
|
||||
|
||||
r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IShellLinkA, (LPVOID*)&sl);
|
||||
ok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\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(*buffer=='\0', "GetDescription returned '%s'\n", buffer);
|
||||
|
||||
str="Some description";
|
||||
r = IShellLinkA_SetDescription(sl, str);
|
||||
ok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
|
||||
|
||||
strcpy(buffer,"garbage");
|
||||
r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
|
||||
ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\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(*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);
|
||||
|
||||
strcpy(buffer,"garbage");
|
||||
r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
|
||||
ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\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(*buffer=='\0', "GetPath returned '%s'\n", buffer);
|
||||
|
||||
r = IShellLinkA_SetPath(sl, "");
|
||||
ok(r==S_OK, "SetPath failed (0x%08lx)\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(*buffer=='\0', "GetPath returned '%s'\n", buffer);
|
||||
|
||||
str="c:\\nonexistent\\file";
|
||||
r = IShellLinkA_SetPath(sl, str);
|
||||
ok(r==S_FALSE, "SetPath failed (0x%08lx)\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(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);
|
||||
|
||||
/* 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);
|
||||
if (SUCCEEDED(r))
|
||||
{
|
||||
strcpy(buffer,"garbage");
|
||||
r=SHGetPathFromIDListA(tmp_pidl, buffer);
|
||||
todo_wine {
|
||||
ok(r, "SHGetPathFromIDListA failed\n");
|
||||
}
|
||||
if (r)
|
||||
ok(lstrcmpi(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
|
||||
}
|
||||
|
||||
pidl=path_to_pidl(mypath);
|
||||
todo_wine {
|
||||
ok(pidl!=NULL, "path_to_pidl returned a NULL pidl\n");
|
||||
}
|
||||
|
||||
if (pidl)
|
||||
{
|
||||
r = IShellLinkA_SetIDList(sl, pidl);
|
||||
ok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\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),
|
||||
"GetIDList returned an incorrect pidl\n");
|
||||
|
||||
/* tmp_pidl is owned by IShellLink so we don't free it */
|
||||
ILFree(pidl);
|
||||
|
||||
strcpy(buffer,"garbage");
|
||||
r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
|
||||
ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
|
||||
ok(lstrcmpi(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
|
||||
}
|
||||
|
||||
/* 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(*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);
|
||||
|
||||
strcpy(buffer,"garbage");
|
||||
r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
|
||||
ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\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(i==SW_SHOWNORMAL, "GetShowCmd returned %d\n", i);
|
||||
|
||||
r = IShellLinkA_SetShowCmd(sl, SW_SHOWMAXIMIZED);
|
||||
ok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
|
||||
|
||||
i=0xdeadbeef;
|
||||
r = IShellLinkA_GetShowCmd(sl, &i);
|
||||
ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
|
||||
ok(i==SW_SHOWMAXIMIZED, "GetShowCmd returned %d'\n", i);
|
||||
|
||||
/* Test Getting / Setting the icon */
|
||||
i=0xdeadbeef;
|
||||
strcpy(buffer,"garbage");
|
||||
r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
|
||||
todo_wine {
|
||||
ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\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);
|
||||
|
||||
i=0xdeadbeef;
|
||||
r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
|
||||
ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\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(w==0, "GetHotkey returned %d\n", w);
|
||||
|
||||
r = IShellLinkA_SetHotkey(sl, 0x5678);
|
||||
ok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
|
||||
|
||||
w=0xbeef;
|
||||
r = IShellLinkA_GetHotkey(sl, &w);
|
||||
ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
|
||||
ok(w==0x5678, "GetHotkey returned %d'\n", w);
|
||||
|
||||
IShellLinkA_Release(sl);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test saving and loading .lnk files
|
||||
*/
|
||||
|
||||
#define lok ok_(__FILE__, line)
|
||||
#define check_lnk(a,b) check_lnk_(__LINE__, (a), (b))
|
||||
|
||||
void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int save_fails)
|
||||
{
|
||||
HRESULT r;
|
||||
IShellLinkA *sl;
|
||||
IPersistFile *pf;
|
||||
|
||||
r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IShellLinkA, (LPVOID*)&sl);
|
||||
lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
|
||||
if (!SUCCEEDED(r))
|
||||
return;
|
||||
|
||||
if (desc->description)
|
||||
{
|
||||
r = IShellLinkA_SetDescription(sl, desc->description);
|
||||
lok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->workdir)
|
||||
{
|
||||
r = IShellLinkA_SetWorkingDirectory(sl, desc->workdir);
|
||||
lok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->path)
|
||||
{
|
||||
r = IShellLinkA_SetPath(sl, desc->path);
|
||||
lok(SUCCEEDED(r), "SetPath failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->pidl)
|
||||
{
|
||||
r = IShellLinkA_SetIDList(sl, desc->pidl);
|
||||
lok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->arguments)
|
||||
{
|
||||
r = IShellLinkA_SetArguments(sl, desc->arguments);
|
||||
lok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->showcmd)
|
||||
{
|
||||
r = IShellLinkA_SetShowCmd(sl, desc->showcmd);
|
||||
lok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->icon)
|
||||
{
|
||||
r = IShellLinkA_SetIconLocation(sl, desc->icon, desc->icon_id);
|
||||
lok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
|
||||
}
|
||||
if (desc->hotkey)
|
||||
{
|
||||
r = IShellLinkA_SetHotkey(sl, desc->hotkey);
|
||||
lok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
|
||||
}
|
||||
|
||||
r = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
|
||||
lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
|
||||
}
|
||||
IPersistFile_Release(pf);
|
||||
}
|
||||
|
||||
IShellLinkA_Release(sl);
|
||||
}
|
||||
|
||||
static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
|
||||
{
|
||||
HRESULT r;
|
||||
IShellLinkA *sl;
|
||||
IPersistFile *pf;
|
||||
char buffer[INFOTIPSIZE];
|
||||
|
||||
r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IShellLinkA, (LPVOID*)&sl);
|
||||
lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
|
||||
if (!SUCCEEDED(r))
|
||||
return;
|
||||
|
||||
r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
|
||||
lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
|
||||
if (!SUCCEEDED(r))
|
||||
{
|
||||
IShellLinkA_Release(sl);
|
||||
return;
|
||||
}
|
||||
|
||||
r = IPersistFile_Load(pf, path, STGM_READ);
|
||||
lok(SUCCEEDED(r), "load failed (0x%08lx)\n", r);
|
||||
IPersistFile_Release(pf);
|
||||
if (!SUCCEEDED(r))
|
||||
{
|
||||
IShellLinkA_Release(sl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (desc->description)
|
||||
{
|
||||
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,
|
||||
"GetDescription returned '%s' instead of '%s'\n",
|
||||
buffer, desc->description);
|
||||
}
|
||||
if (desc->workdir)
|
||||
{
|
||||
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,
|
||||
"GetWorkingDirectory returned '%s' instead of '%s'\n",
|
||||
buffer, desc->workdir);
|
||||
}
|
||||
if (desc->path)
|
||||
{
|
||||
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,
|
||||
"GetPath returned '%s' instead of '%s'\n",
|
||||
buffer, desc->path);
|
||||
}
|
||||
if (desc->pidl)
|
||||
{
|
||||
LPITEMIDLIST pidl=NULL;
|
||||
r = IShellLinkA_GetIDList(sl, &pidl);
|
||||
lok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
|
||||
lok(ILIsEqual(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,
|
||||
"GetShowCmd returned 0x%0x instead of 0x%0x\n",
|
||||
i, desc->showcmd);
|
||||
}
|
||||
if (desc->icon)
|
||||
{
|
||||
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,
|
||||
"GetIconLocation returned '%s' instead of '%s'\n",
|
||||
buffer, desc->icon);
|
||||
lok(i==desc->icon_id,
|
||||
"GetIconLocation returned 0x%0x instead of 0x%0x\n",
|
||||
i, desc->icon_id);
|
||||
}
|
||||
if (desc->hotkey)
|
||||
{
|
||||
WORD i=0xbeef;
|
||||
r = IShellLinkA_GetHotkey(sl, &i);
|
||||
lok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
|
||||
lok(i==desc->hotkey,
|
||||
"GetHotkey returned 0x%04x instead of 0x%04x\n",
|
||||
i, desc->hotkey);
|
||||
}
|
||||
|
||||
IShellLinkA_Release(sl);
|
||||
}
|
||||
|
||||
static void test_load_save(void)
|
||||
{
|
||||
lnk_desc_t desc;
|
||||
char mypath[MAX_PATH];
|
||||
char mydir[MAX_PATH];
|
||||
char* p;
|
||||
DWORD r;
|
||||
|
||||
/* Save an empty .lnk file */
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
create_lnk(lnkfile, &desc, 0);
|
||||
|
||||
/* It should come back as a bunch of empty strings */
|
||||
desc.description="";
|
||||
desc.workdir="";
|
||||
desc.path="";
|
||||
desc.arguments="";
|
||||
desc.icon="";
|
||||
check_lnk(lnkfile, &desc);
|
||||
|
||||
|
||||
/* Point a .lnk file to nonexistent files */
|
||||
desc.description="";
|
||||
desc.workdir="c:\\Nonexitent\\work\\directory";
|
||||
desc.path="c:\\nonexistent\\path";
|
||||
desc.pidl=NULL;
|
||||
desc.arguments="";
|
||||
desc.showcmd=0;
|
||||
desc.icon="c:\\nonexistent\\icon\\file";
|
||||
desc.icon_id=1234;
|
||||
desc.hotkey=0;
|
||||
create_lnk(lnkfile, &desc, 0);
|
||||
check_lnk(lnkfile, &desc);
|
||||
|
||||
r=GetModuleFileName(NULL, mypath, sizeof(mypath));
|
||||
ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\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.path=mypath;
|
||||
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_lnk(lnkfile, &desc);
|
||||
|
||||
/* 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());
|
||||
}
|
||||
|
||||
START_TEST(shelllink)
|
||||
{
|
||||
HRESULT r;
|
||||
|
||||
r = CoInitialize(NULL);
|
||||
ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
|
||||
if (!SUCCEEDED(r))
|
||||
return;
|
||||
|
||||
test_get_set();
|
||||
test_load_save();
|
||||
|
||||
CoUninitialize();
|
||||
}
|
906
reactos/regtests/winetests/shell32/shellpath.c
Normal file
906
reactos/regtests/winetests/shell32/shellpath.c
Normal file
|
@ -0,0 +1,906 @@
|
|||
/*
|
||||
* Unit tests for shell32 SHGet{Special}Folder{Path|Location} functions.
|
||||
*
|
||||
* Copyright 2004 Juan Lang
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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).
|
||||
*
|
||||
* FIXME:
|
||||
* - Need to verify on more systems.
|
||||
*/
|
||||
|
||||
#define COBJMACROS
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "initguid.h"
|
||||
#include "shlguid.h"
|
||||
#include "shlobj.h"
|
||||
#include "shlwapi.h"
|
||||
#include "wine/test.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) ( sizeof(x) / sizeof((x)[0]) )
|
||||
#endif
|
||||
|
||||
/* from pidl.h, not included here: */
|
||||
#ifndef PT_GUID
|
||||
#define PT_GUID 0x1f /* no path */
|
||||
#endif
|
||||
#ifndef PT_DRIVE
|
||||
#define PT_DRIVE 0x23 /* has path */
|
||||
#endif
|
||||
#ifndef PT_DRIVE2
|
||||
#define PT_DRIVE2 0x25 /* has path */
|
||||
#endif
|
||||
#ifndef PT_SHELLEXT
|
||||
#define PT_SHELLEXT 0x2e /* no path */
|
||||
#endif
|
||||
#ifndef PT_FOLDER
|
||||
#define PT_FOLDER 0x31 /* has path */
|
||||
#endif
|
||||
#ifndef PT_WORKGRP
|
||||
#define PT_WORKGRP 0x41 /* no path */
|
||||
#endif
|
||||
#ifndef PT_YAGUID
|
||||
#define PT_YAGUID 0x70 /* no path */
|
||||
#endif
|
||||
/* FIXME: this is used for history/favorites folders; what's a better name? */
|
||||
#ifndef PT_IESPECIAL2
|
||||
#define PT_IESPECIAL2 0xb1 /* has path */
|
||||
#endif
|
||||
|
||||
static GUID CLSID_CommonDocuments = { 0x0000000c, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1a } };
|
||||
|
||||
struct shellExpectedValues {
|
||||
int folder;
|
||||
BYTE pidlType;
|
||||
};
|
||||
|
||||
static HMODULE hShell32;
|
||||
static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
|
||||
static HRESULT (WINAPI *pSHGetFolderLocation)(HWND, int, HANDLE, DWORD,
|
||||
LPITEMIDLIST *);
|
||||
static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
|
||||
static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
|
||||
static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
|
||||
static int (WINAPI *pSHFileOperationA)(LPSHFILEOPSTRUCTA);
|
||||
static HRESULT (WINAPI *pSHGetMalloc)(LPMALLOC *);
|
||||
static DLLVERSIONINFO shellVersion = { 0 };
|
||||
static LPMALLOC pMalloc;
|
||||
static const struct shellExpectedValues requiredShellValues[] = {
|
||||
{ CSIDL_BITBUCKET, PT_GUID },
|
||||
{ CSIDL_CONTROLS, PT_SHELLEXT },
|
||||
{ CSIDL_COOKIES, PT_FOLDER },
|
||||
{ CSIDL_DESKTOPDIRECTORY, PT_FOLDER },
|
||||
{ CSIDL_DRIVES, PT_GUID },
|
||||
{ CSIDL_FAVORITES, PT_FOLDER },
|
||||
{ CSIDL_FONTS, PT_FOLDER },
|
||||
/* FIXME: the following fails in Wine, returns type PT_FOLDER
|
||||
{ CSIDL_HISTORY, PT_IESPECIAL2 },
|
||||
*/
|
||||
{ CSIDL_INTERNET, PT_GUID },
|
||||
{ CSIDL_NETHOOD, PT_FOLDER },
|
||||
{ CSIDL_NETWORK, PT_GUID },
|
||||
{ CSIDL_PRINTERS, PT_YAGUID },
|
||||
{ CSIDL_PRINTHOOD, PT_FOLDER },
|
||||
{ CSIDL_PROGRAMS, PT_FOLDER },
|
||||
{ CSIDL_RECENT, PT_FOLDER },
|
||||
{ CSIDL_SENDTO, PT_FOLDER },
|
||||
{ CSIDL_STARTMENU, PT_FOLDER },
|
||||
{ CSIDL_STARTUP, PT_FOLDER },
|
||||
{ CSIDL_TEMPLATES, PT_FOLDER },
|
||||
};
|
||||
static const struct shellExpectedValues optionalShellValues[] = {
|
||||
/* FIXME: the following only semi-succeed; they return NULL PIDLs on XP.. hmm.
|
||||
{ CSIDL_ALTSTARTUP, PT_FOLDER },
|
||||
{ CSIDL_COMMON_ALTSTARTUP, PT_FOLDER },
|
||||
{ CSIDL_COMMON_OEM_LINKS, PT_FOLDER },
|
||||
*/
|
||||
/* Windows NT-only: */
|
||||
{ CSIDL_COMMON_DESKTOPDIRECTORY, PT_FOLDER },
|
||||
{ CSIDL_COMMON_DOCUMENTS, PT_SHELLEXT },
|
||||
{ CSIDL_COMMON_FAVORITES, PT_FOLDER },
|
||||
{ CSIDL_COMMON_PROGRAMS, PT_FOLDER },
|
||||
{ CSIDL_COMMON_STARTMENU, PT_FOLDER },
|
||||
{ CSIDL_COMMON_STARTUP, PT_FOLDER },
|
||||
{ CSIDL_COMMON_TEMPLATES, PT_FOLDER },
|
||||
/* first appearing in shell32 version 4.71: */
|
||||
{ CSIDL_APPDATA, PT_FOLDER },
|
||||
/* first appearing in shell32 version 4.72: */
|
||||
{ CSIDL_INTERNET_CACHE, PT_IESPECIAL2 },
|
||||
/* first appearing in shell32 version 5.0: */
|
||||
{ CSIDL_ADMINTOOLS, PT_FOLDER },
|
||||
{ CSIDL_COMMON_APPDATA, PT_FOLDER },
|
||||
{ CSIDL_LOCAL_APPDATA, PT_FOLDER },
|
||||
{ CSIDL_MYDOCUMENTS, PT_FOLDER },
|
||||
{ CSIDL_MYMUSIC, PT_FOLDER },
|
||||
{ CSIDL_MYPICTURES, PT_FOLDER },
|
||||
{ CSIDL_MYVIDEO, PT_FOLDER },
|
||||
{ CSIDL_PROFILE, PT_FOLDER },
|
||||
{ CSIDL_PROGRAM_FILES, PT_FOLDER },
|
||||
{ CSIDL_PROGRAM_FILESX86, PT_FOLDER },
|
||||
{ CSIDL_PROGRAM_FILES_COMMON, PT_FOLDER },
|
||||
{ CSIDL_PROGRAM_FILES_COMMONX86, PT_FOLDER },
|
||||
{ CSIDL_SYSTEM, PT_FOLDER },
|
||||
{ CSIDL_WINDOWS, PT_FOLDER },
|
||||
/* first appearing in shell32 6.0: */
|
||||
{ CSIDL_CDBURN_AREA, PT_FOLDER },
|
||||
{ CSIDL_COMMON_MUSIC, PT_FOLDER },
|
||||
{ CSIDL_COMMON_PICTURES, PT_FOLDER },
|
||||
{ CSIDL_COMMON_VIDEO, PT_FOLDER },
|
||||
{ CSIDL_COMPUTERSNEARME, PT_WORKGRP },
|
||||
{ CSIDL_RESOURCES, PT_FOLDER },
|
||||
{ CSIDL_RESOURCES_LOCALIZED, PT_FOLDER },
|
||||
};
|
||||
|
||||
static void loadShell32(void)
|
||||
{
|
||||
hShell32 = LoadLibraryA("shell32");
|
||||
if (hShell32)
|
||||
{
|
||||
HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO *);
|
||||
|
||||
pSHGetFolderPathA = (void *)GetProcAddress(hShell32,
|
||||
"SHGetFolderPathA");
|
||||
pSHGetFolderLocation = (void *)GetProcAddress(hShell32,
|
||||
"SHGetFolderLocation");
|
||||
pSHGetSpecialFolderPathA = (void *)GetProcAddress(hShell32,
|
||||
"SHGetSpecialFolderPathA");
|
||||
pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32,
|
||||
"SHGetSpecialFolderLocation");
|
||||
pDllGetVersion = (void *)GetProcAddress(hShell32, "DllGetVersion");
|
||||
pILFindLastID = (void *)GetProcAddress(hShell32, "ILFindLastID");
|
||||
if (!pILFindLastID)
|
||||
pILFindLastID = (void *)GetProcAddress(hShell32, (LPCSTR)16);
|
||||
pSHFileOperationA = (void *)GetProcAddress(hShell32,
|
||||
"SHFileOperationA");
|
||||
pSHGetMalloc = (void *)GetProcAddress(hShell32, "SHGetMalloc");
|
||||
|
||||
ok(pSHGetMalloc != NULL, "shell32 is missing SHGetMalloc\n");
|
||||
if (pSHGetMalloc)
|
||||
{
|
||||
HRESULT hr = pSHGetMalloc(&pMalloc);
|
||||
|
||||
ok(SUCCEEDED(hr), "SHGetMalloc failed: 0x%08lx\n", hr);
|
||||
ok(pMalloc != NULL, "SHGetMalloc returned a NULL IMalloc\n");
|
||||
}
|
||||
|
||||
if (pDllGetVersion)
|
||||
{
|
||||
shellVersion.cbSize = sizeof(shellVersion);
|
||||
pDllGetVersion(&shellVersion);
|
||||
if (winetest_interactive)
|
||||
printf("shell32 version is %ld.%ld\n",
|
||||
shellVersion.dwMajorVersion, shellVersion.dwMinorVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CSIDL_PROFILES
|
||||
#define CSIDL_PROFILES 0x003e
|
||||
#endif
|
||||
|
||||
/* A couple utility printing functions */
|
||||
static const char *getFolderName(int folder)
|
||||
{
|
||||
static char unknown[17];
|
||||
|
||||
#define CSIDL_TO_STR(x) case x: return#x;
|
||||
switch (folder)
|
||||
{
|
||||
CSIDL_TO_STR(CSIDL_DESKTOP);
|
||||
CSIDL_TO_STR(CSIDL_INTERNET);
|
||||
CSIDL_TO_STR(CSIDL_PROGRAMS);
|
||||
CSIDL_TO_STR(CSIDL_CONTROLS);
|
||||
CSIDL_TO_STR(CSIDL_PRINTERS);
|
||||
CSIDL_TO_STR(CSIDL_PERSONAL);
|
||||
CSIDL_TO_STR(CSIDL_FAVORITES);
|
||||
CSIDL_TO_STR(CSIDL_STARTUP);
|
||||
CSIDL_TO_STR(CSIDL_RECENT);
|
||||
CSIDL_TO_STR(CSIDL_SENDTO);
|
||||
CSIDL_TO_STR(CSIDL_BITBUCKET);
|
||||
CSIDL_TO_STR(CSIDL_STARTMENU);
|
||||
CSIDL_TO_STR(CSIDL_MYDOCUMENTS);
|
||||
CSIDL_TO_STR(CSIDL_MYMUSIC);
|
||||
CSIDL_TO_STR(CSIDL_MYVIDEO);
|
||||
CSIDL_TO_STR(CSIDL_DESKTOPDIRECTORY);
|
||||
CSIDL_TO_STR(CSIDL_DRIVES);
|
||||
CSIDL_TO_STR(CSIDL_NETWORK);
|
||||
CSIDL_TO_STR(CSIDL_NETHOOD);
|
||||
CSIDL_TO_STR(CSIDL_FONTS);
|
||||
CSIDL_TO_STR(CSIDL_TEMPLATES);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_STARTMENU);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_PROGRAMS);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_STARTUP);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_DESKTOPDIRECTORY);
|
||||
CSIDL_TO_STR(CSIDL_APPDATA);
|
||||
CSIDL_TO_STR(CSIDL_PRINTHOOD);
|
||||
CSIDL_TO_STR(CSIDL_LOCAL_APPDATA);
|
||||
CSIDL_TO_STR(CSIDL_ALTSTARTUP);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_ALTSTARTUP);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_FAVORITES);
|
||||
CSIDL_TO_STR(CSIDL_INTERNET_CACHE);
|
||||
CSIDL_TO_STR(CSIDL_COOKIES);
|
||||
CSIDL_TO_STR(CSIDL_HISTORY);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_APPDATA);
|
||||
CSIDL_TO_STR(CSIDL_WINDOWS);
|
||||
CSIDL_TO_STR(CSIDL_SYSTEM);
|
||||
CSIDL_TO_STR(CSIDL_PROGRAM_FILES);
|
||||
CSIDL_TO_STR(CSIDL_MYPICTURES);
|
||||
CSIDL_TO_STR(CSIDL_PROFILE);
|
||||
CSIDL_TO_STR(CSIDL_SYSTEMX86);
|
||||
CSIDL_TO_STR(CSIDL_PROGRAM_FILESX86);
|
||||
CSIDL_TO_STR(CSIDL_PROGRAM_FILES_COMMON);
|
||||
CSIDL_TO_STR(CSIDL_PROGRAM_FILES_COMMONX86);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_TEMPLATES);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_DOCUMENTS);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_ADMINTOOLS);
|
||||
CSIDL_TO_STR(CSIDL_ADMINTOOLS);
|
||||
CSIDL_TO_STR(CSIDL_CONNECTIONS);
|
||||
CSIDL_TO_STR(CSIDL_PROFILES);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_MUSIC);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_PICTURES);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_VIDEO);
|
||||
CSIDL_TO_STR(CSIDL_RESOURCES);
|
||||
CSIDL_TO_STR(CSIDL_RESOURCES_LOCALIZED);
|
||||
CSIDL_TO_STR(CSIDL_COMMON_OEM_LINKS);
|
||||
CSIDL_TO_STR(CSIDL_CDBURN_AREA);
|
||||
CSIDL_TO_STR(CSIDL_COMPUTERSNEARME);
|
||||
#undef CSIDL_TO_STR
|
||||
default:
|
||||
wnsprintfA(unknown, sizeof(unknown), "unknown (0x%04x)", folder);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *printGUID(const GUID *guid)
|
||||
{
|
||||
static char guidSTR[39];
|
||||
|
||||
if (!guid) return NULL;
|
||||
|
||||
wnsprintfA(guidSTR, sizeof(guidSTR),
|
||||
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
|
||||
guid->Data1, guid->Data2, guid->Data3,
|
||||
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
|
||||
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
|
||||
return guidSTR;
|
||||
}
|
||||
|
||||
static void testSHGetFolderLocationInvalidArgs(void)
|
||||
{
|
||||
LPITEMIDLIST pidl;
|
||||
HRESULT hr;
|
||||
|
||||
if (!pSHGetFolderLocation) return;
|
||||
|
||||
/* check a bogus CSIDL: */
|
||||
pidl = NULL;
|
||||
hr = pSHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl);
|
||||
ok(hr == E_INVALIDARG,
|
||||
"SHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl)\n"
|
||||
"returned 0x%08lx, expected E_INVALIDARG\n", hr);
|
||||
if (SUCCEEDED(hr))
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
/* check a bogus user token: */
|
||||
pidl = NULL;
|
||||
hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, (HANDLE)2, 0, &pidl);
|
||||
ok(hr == E_FAIL,
|
||||
"SHGetFolderLocation(NULL, CSIDL_FAVORITES, 2, 0, &pidl)\n"
|
||||
"returned 0x%08lx, expected E_FAIL\n", hr);
|
||||
if (SUCCEEDED(hr))
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
/* check reserved is not zero: */
|
||||
pidl = NULL;
|
||||
hr = pSHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 1, &pidl);
|
||||
ok(hr == E_INVALIDARG,
|
||||
"SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 1, &pidl)\n"
|
||||
"returned 0x%08lx, expected E_INVALIDARG\n", hr);
|
||||
if (SUCCEEDED(hr))
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
/* a NULL pidl pointer crashes, so don't test it */
|
||||
}
|
||||
|
||||
static void testSHGetSpecialFolderLocationInvalidArgs(void)
|
||||
{
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
if (!pSHGetSpecialFolderLocation) return;
|
||||
|
||||
/* SHGetSpecialFolderLocation(NULL, 0, NULL) crashes */
|
||||
hr = pSHGetSpecialFolderLocation(NULL, 0xeeee, &pidl);
|
||||
ok(hr == E_INVALIDARG,
|
||||
"SHGetSpecialFolderLocation(NULL, 0xeeee, &pidl) returned 0x%08lx, "
|
||||
"expected E_INVALIDARG\n", hr);
|
||||
}
|
||||
|
||||
static void testSHGetFolderPathInvalidArgs(void)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
HRESULT hr;
|
||||
|
||||
if (!pSHGetFolderPathA) return;
|
||||
|
||||
/* expect 2's a bogus handle, especially since we didn't open it */
|
||||
hr = pSHGetFolderPathA(NULL, CSIDL_DESKTOP, (HANDLE)2,
|
||||
SHGFP_TYPE_DEFAULT, path);
|
||||
ok(hr == E_FAIL,
|
||||
"SHGetFolderPathA(NULL, CSIDL_DESKTOP, 2, SHGFP_TYPE_DEFAULT, path)\n"
|
||||
"returned 0x%08lx, expected E_FAIL\n", hr);
|
||||
hr = pSHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path);
|
||||
ok(hr == E_INVALIDARG,
|
||||
"SHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path)\n"
|
||||
"returned 0x%08lx, expected E_INVALIDARG\n", hr);
|
||||
}
|
||||
|
||||
static void testSHGetSpecialFolderPathInvalidArgs(void)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
BOOL ret;
|
||||
|
||||
if (!pSHGetSpecialFolderPathA) return;
|
||||
|
||||
ret = pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE);
|
||||
ok(!ret,
|
||||
"SHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE)\n"
|
||||
"returned TRUE, expected FALSE\n");
|
||||
/* odd but true: calling with a NULL path still succeeds if it's a real
|
||||
* dir
|
||||
*/
|
||||
ret = pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_PROGRAMS, FALSE);
|
||||
ok(ret,
|
||||
"SHGetSpecialFolderPathA(NULL, NULL, CSIDL_PROGRAMS, FALSE)\n"
|
||||
"returned FALSE, expected TRUE\n");
|
||||
ret = pSHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE);
|
||||
ok(!ret,
|
||||
"SHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE)\n"
|
||||
"returned TRUE, expected FALSE\n");
|
||||
}
|
||||
|
||||
static void testApiParameters(void)
|
||||
{
|
||||
testSHGetFolderLocationInvalidArgs();
|
||||
testSHGetSpecialFolderLocationInvalidArgs();
|
||||
testSHGetFolderPathInvalidArgs();
|
||||
testSHGetSpecialFolderPathInvalidArgs();
|
||||
}
|
||||
|
||||
/* Returns the folder's PIDL type, or 0xff if one can't be found. */
|
||||
static BYTE testSHGetFolderLocation(BOOL optional, int folder)
|
||||
{
|
||||
LPITEMIDLIST pidl;
|
||||
HRESULT hr;
|
||||
BYTE ret = 0xff;
|
||||
|
||||
/* treat absence of function as success */
|
||||
if (!pSHGetFolderLocation) return TRUE;
|
||||
|
||||
pidl = NULL;
|
||||
hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
|
||||
ok(SUCCEEDED(hr) || optional,
|
||||
"SHGetFolderLocation(NULL, %s, NULL, 0, &pidl)\n"
|
||||
"failed: 0x%08lx\n", getFolderName(folder), hr);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ok(pidl != NULL,
|
||||
"SHGetFolderLocation(NULL, %s, NULL, 0, &pidl)\n"
|
||||
"succeeded, but returned pidl is NULL\n", getFolderName(folder));
|
||||
if (pidl)
|
||||
{
|
||||
LPITEMIDLIST pidlLast = pILFindLastID(pidl);
|
||||
|
||||
ok(pidlLast != NULL, "%s: ILFindLastID failed\n",
|
||||
getFolderName(folder));
|
||||
if (pidlLast)
|
||||
ret = pidlLast->mkid.abID[0];
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns the folder's PIDL type, or 0xff if one can't be found. */
|
||||
static BYTE testSHGetSpecialFolderLocation(BOOL optional, int folder)
|
||||
{
|
||||
LPITEMIDLIST pidl;
|
||||
HRESULT hr;
|
||||
BYTE ret = 0xff;
|
||||
|
||||
/* treat absence of function as success */
|
||||
if (!pSHGetSpecialFolderLocation) return TRUE;
|
||||
|
||||
pidl = NULL;
|
||||
hr = pSHGetSpecialFolderLocation(NULL, folder, &pidl);
|
||||
ok(SUCCEEDED(hr) || optional,
|
||||
"SHGetSpecialFolderLocation(NULL, %s, &pidl)\n"
|
||||
"failed: 0x%08lx\n", getFolderName(folder), hr);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ok(pidl != NULL,
|
||||
"SHGetSpecialFolderLocation(NULL, %s, &pidl)\n"
|
||||
"succeeded, but returned pidl is NULL\n", getFolderName(folder));
|
||||
if (pidl)
|
||||
{
|
||||
LPITEMIDLIST pidlLast = pILFindLastID(pidl);
|
||||
|
||||
ok(pidlLast != NULL,
|
||||
"%s: ILFindLastID failed\n", getFolderName(folder));
|
||||
if (pidlLast)
|
||||
ret = pidlLast->mkid.abID[0];
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void testSHGetFolderPath(BOOL optional, int folder)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
HRESULT hr;
|
||||
|
||||
if (!pSHGetFolderPathA) return;
|
||||
|
||||
hr = pSHGetFolderPathA(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path);
|
||||
ok(SUCCEEDED(hr) || optional,
|
||||
"SHGetFolderPathA(NULL, %s, NULL, SHGFP_TYPE_CURRENT, path)\n"
|
||||
"failed: 0x%08lx\n", getFolderName(folder), hr);
|
||||
}
|
||||
|
||||
static void testSHGetSpecialFolderPath(BOOL optional, int folder)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
BOOL ret;
|
||||
|
||||
if (!pSHGetSpecialFolderPathA) return;
|
||||
|
||||
ret = pSHGetSpecialFolderPathA(NULL, path, folder, FALSE);
|
||||
if (ret && winetest_interactive)
|
||||
printf("%s: %s\n", getFolderName(folder), path);
|
||||
ok(ret || optional,
|
||||
"SHGetSpecialFolderPathA(NULL, path, %s, FALSE) failed\n",
|
||||
getFolderName(folder));
|
||||
}
|
||||
|
||||
static void testShellValues(const struct shellExpectedValues testEntries[],
|
||||
int numEntries, BOOL optional)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numEntries; i++)
|
||||
{
|
||||
BYTE type;
|
||||
|
||||
type = testSHGetFolderLocation(optional, testEntries[i].folder);
|
||||
ok(type == testEntries[i].pidlType || optional,
|
||||
"%s has type %d (0x%02x), expected %d (0x%02x)\n",
|
||||
getFolderName(testEntries[i].folder), type, type,
|
||||
testEntries[i].pidlType, testEntries[i].pidlType);
|
||||
type = testSHGetSpecialFolderLocation(optional, testEntries[i].folder);
|
||||
ok(type == testEntries[i].pidlType || optional,
|
||||
"%s has type %d (0x%02x), expected %d (0x%02x)\n",
|
||||
getFolderName(testEntries[i].folder), type, type,
|
||||
testEntries[i].pidlType, testEntries[i].pidlType);
|
||||
switch (type)
|
||||
{
|
||||
case PT_FOLDER:
|
||||
case PT_DRIVE:
|
||||
case PT_DRIVE2:
|
||||
case PT_IESPECIAL2:
|
||||
testSHGetFolderPath(optional, testEntries[i].folder);
|
||||
testSHGetSpecialFolderPath(optional, testEntries[i].folder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempts to verify that the folder path corresponding to the folder CSIDL
|
||||
* value has the same value as the environment variable with name envVar.
|
||||
* Doesn't mind if SHGetSpecialFolderPath fails for folder or if envVar isn't
|
||||
* set in this environment; different OS and shell version behave differently.
|
||||
* However, if both are present, fails if envVar's value is not the same
|
||||
* (byte-for-byte) as what SHGetSpecialFolderPath returns.
|
||||
*/
|
||||
static void matchSpecialFolderPathToEnv(int folder, const char *envVar)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
|
||||
if (!pSHGetSpecialFolderPathA) return;
|
||||
|
||||
if (pSHGetSpecialFolderPathA(NULL, path, folder, FALSE))
|
||||
{
|
||||
char *envVal = getenv(envVar);
|
||||
|
||||
ok(!envVal || !lstrcmpiA(envVal, path),
|
||||
"%%%s%% does not match SHGetSpecialFolderPath:\n"
|
||||
"%%%s%% is %s\nSHGetSpecialFolderPath returns %s\n",
|
||||
envVar, envVar, envVal, path);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempts to match the GUID returned by SHGetFolderLocation for folder with
|
||||
* GUID. Assumes the type of the returned PIDL is in fact a GUID, but doesn't
|
||||
* fail if it isn't--that check should already have been done.
|
||||
* Fails if the returned PIDL is a GUID whose value does not match guid.
|
||||
*/
|
||||
static void matchGUID(int folder, const GUID *guid)
|
||||
{
|
||||
LPITEMIDLIST pidl;
|
||||
HRESULT hr;
|
||||
|
||||
if (!pSHGetFolderLocation) return;
|
||||
if (!guid) return;
|
||||
|
||||
pidl = NULL;
|
||||
hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
LPITEMIDLIST pidlLast = pILFindLastID(pidl);
|
||||
|
||||
if (pidlLast && (pidlLast->mkid.abID[0] == PT_SHELLEXT ||
|
||||
pidlLast->mkid.abID[0] == PT_GUID))
|
||||
{
|
||||
GUID *shellGuid = (GUID *)(pidlLast->mkid.abID + 2);
|
||||
|
||||
ok(IsEqualIID(shellGuid, guid),
|
||||
"%s: got GUID %s, expected %s\n", getFolderName(folder),
|
||||
printGUID(shellGuid), printGUID(guid));
|
||||
}
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
}
|
||||
}
|
||||
|
||||
static void testDesktop(void)
|
||||
{
|
||||
testSHGetFolderPath(FALSE, CSIDL_DESKTOP);
|
||||
testSHGetSpecialFolderPath(FALSE, CSIDL_DESKTOP);
|
||||
/* Test the desktop; even though SHITEMID should always contain abID of at
|
||||
* least one type, when cb is 0 its value is undefined. So don't check
|
||||
* what the returned type is, just make sure it exists.
|
||||
*/
|
||||
testSHGetFolderLocation(FALSE, CSIDL_DESKTOP);
|
||||
testSHGetSpecialFolderLocation(FALSE, CSIDL_DESKTOP);
|
||||
}
|
||||
|
||||
static void testPersonal(void)
|
||||
{
|
||||
BYTE type;
|
||||
|
||||
/* The pidl may be a real folder, or a virtual directory, or a drive if the
|
||||
* home directory is set to the root directory of a drive.
|
||||
*/
|
||||
type = testSHGetFolderLocation(FALSE, CSIDL_PERSONAL);
|
||||
ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE,
|
||||
"CSIDL_PERSONAL returned invalid type 0x%02x, "
|
||||
"expected PT_FOLDER or PT_GUID\n", type);
|
||||
if (type == PT_FOLDER)
|
||||
testSHGetFolderPath(FALSE, CSIDL_PERSONAL);
|
||||
type = testSHGetSpecialFolderLocation(FALSE, CSIDL_PERSONAL);
|
||||
ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE,
|
||||
"CSIDL_PERSONAL returned invalid type 0x%02x, "
|
||||
"expected PT_FOLDER or PT_GUID\n", type);
|
||||
if (type == PT_FOLDER)
|
||||
testSHGetSpecialFolderPath(FALSE, CSIDL_PERSONAL);
|
||||
}
|
||||
|
||||
/* Checks the PIDL type of all the known values. */
|
||||
static void testPidlTypes(void)
|
||||
{
|
||||
testDesktop();
|
||||
testPersonal();
|
||||
testShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues),
|
||||
FALSE);
|
||||
testShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues),
|
||||
TRUE);
|
||||
}
|
||||
|
||||
/* Verifies various shell virtual folders have the correct well-known GUIDs. */
|
||||
static void testGUIDs(void)
|
||||
{
|
||||
matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin);
|
||||
matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel);
|
||||
matchGUID(CSIDL_DRIVES, &CLSID_MyComputer);
|
||||
matchGUID(CSIDL_INTERNET, &CLSID_Internet);
|
||||
matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces);
|
||||
matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments);
|
||||
matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments);
|
||||
}
|
||||
|
||||
/* Verifies various shell paths match the environment variables to which they
|
||||
* correspond.
|
||||
*/
|
||||
static void testEnvVars(void)
|
||||
{
|
||||
matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES, "ProgramFiles");
|
||||
matchSpecialFolderPathToEnv(CSIDL_APPDATA, "APPDATA");
|
||||
matchSpecialFolderPathToEnv(CSIDL_PROFILE, "USERPROFILE");
|
||||
matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "SystemRoot");
|
||||
matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "windir");
|
||||
matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES_COMMON,
|
||||
"CommonProgramFiles");
|
||||
/* this is only set on Wine, but can't hurt to verify it: */
|
||||
matchSpecialFolderPathToEnv(CSIDL_SYSTEM, "winsysdir");
|
||||
}
|
||||
|
||||
/* Verifies the shell path for CSIDL_WINDOWS matches the return from
|
||||
* GetWindowsDirectory. If SHGetSpecialFolderPath fails, no harm, no foul--not
|
||||
* every shell32 version supports CSIDL_WINDOWS.
|
||||
*/
|
||||
static void testWinDir(void)
|
||||
{
|
||||
char windowsShellPath[MAX_PATH], windowsDir[MAX_PATH] = { 0 };
|
||||
|
||||
if (!pSHGetSpecialFolderPathA) return;
|
||||
|
||||
if (pSHGetSpecialFolderPathA(NULL, windowsShellPath, CSIDL_WINDOWS, FALSE))
|
||||
{
|
||||
PathRemoveBackslashA(windowsShellPath);
|
||||
GetWindowsDirectoryA(windowsDir, sizeof(windowsDir));
|
||||
PathRemoveBackslashA(windowsDir);
|
||||
ok(!lstrcmpiA(windowsDir, windowsShellPath),
|
||||
"GetWindowsDirectory does not match SHGetSpecialFolderPath:\n"
|
||||
"GetWindowsDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
|
||||
windowsDir, windowsShellPath);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verifies the shell path for CSIDL_SYSTEM and CSIDL_SYSTEMX86 matches the
|
||||
* return from GetSystemDirectory. If SHGetSpecialFolderPath fails, no harm,
|
||||
* no foul--not every shell32 version supports CSIDL_SYSTEM.
|
||||
*/
|
||||
static void testSystemDir(void)
|
||||
{
|
||||
char systemShellPath[MAX_PATH], systemDir[MAX_PATH] = { 0 };
|
||||
|
||||
if (!pSHGetSpecialFolderPathA) return;
|
||||
|
||||
GetSystemDirectoryA(systemDir, sizeof(systemDir));
|
||||
PathRemoveBackslashA(systemDir);
|
||||
if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEM, FALSE))
|
||||
{
|
||||
PathRemoveBackslashA(systemShellPath);
|
||||
ok(!lstrcmpiA(systemDir, systemShellPath),
|
||||
"GetSystemDirectory does not match SHGetSpecialFolderPath:\n"
|
||||
"GetSystemDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
|
||||
systemDir, systemShellPath);
|
||||
}
|
||||
/* check CSIDL_SYSTEMX86; note that this isn't always present, so don't
|
||||
* worry if it fails
|
||||
*/
|
||||
if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE))
|
||||
{
|
||||
PathRemoveBackslashA(systemShellPath);
|
||||
ok(!lstrcmpiA(systemDir, systemShellPath),
|
||||
"GetSystemDirectory does not match SHGetSpecialFolderPath:\n"
|
||||
"GetSystemDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
|
||||
systemDir, systemShellPath);
|
||||
}
|
||||
}
|
||||
|
||||
/* Globals used by subprocesses */
|
||||
static int myARGC;
|
||||
static char **myARGV;
|
||||
static char base[MAX_PATH];
|
||||
static char selfname[MAX_PATH];
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
myARGC = winetest_get_mainargs(&myARGV);
|
||||
if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
|
||||
strcpy(selfname, myARGV[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Subprocess helper 1: test what happens when CSIDL_FAVORITES is set to a
|
||||
* nonexistent directory.
|
||||
*/
|
||||
static void testNonExistentPath1(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
LPITEMIDLIST pidl;
|
||||
char path[MAX_PATH];
|
||||
|
||||
/* test some failure cases first: */
|
||||
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL,
|
||||
SHGFP_TYPE_CURRENT, NULL);
|
||||
ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
|
||||
"SHGetFolderPath returned 0x%08lx, expected 0x80070002\n", hr);
|
||||
pidl = NULL;
|
||||
hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0,
|
||||
&pidl);
|
||||
ok(hr == E_FAIL,
|
||||
"SHGetFolderLocation returned 0x%08lx, expected E_FAIL\n", hr);
|
||||
if (SUCCEEDED(hr) && pidl)
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE),
|
||||
"SHGetSpecialFolderPath succeeded, expected failure\n");
|
||||
pidl = NULL;
|
||||
hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
|
||||
ok(hr == E_FAIL, "SHGetFolderLocation returned 0x%08lx, expected E_FAIL\n",
|
||||
hr);
|
||||
if (SUCCEEDED(hr) && pidl)
|
||||
IMalloc_Free(pMalloc, pidl);
|
||||
/* now test success: */
|
||||
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
|
||||
SHGFP_TYPE_CURRENT, path);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
if (winetest_interactive)
|
||||
printf("CSIDL_FAVORITES was changed to %s\n", path);
|
||||
ret = CreateDirectoryA(path, NULL);
|
||||
ok(!ret,
|
||||
"CreateDirectoryA succeeded but should have failed "
|
||||
"with ERROR_ALREADY_EXISTS\n");
|
||||
if (!ret)
|
||||
ok(GetLastError() == ERROR_ALREADY_EXISTS,
|
||||
"CreateDirectoryA failed with %ld, "
|
||||
"expected ERROR_ALREADY_EXISTS\n",
|
||||
GetLastError());
|
||||
}
|
||||
ok(SUCCEEDED(hr),
|
||||
"SHGetFolderPath(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, "
|
||||
"NULL, SHGFP_TYPE_CURRENT, path)\nfailed: 0x%08lx\n", hr);
|
||||
}
|
||||
|
||||
/* Subprocess helper 2: make sure SHGetFolderPath still succeeds when the
|
||||
* original value of CSIDL_FAVORITES is restored.
|
||||
*/
|
||||
static void testNonExistentPath2(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
|
||||
SHGFP_TYPE_CURRENT, NULL);
|
||||
ok(SUCCEEDED(hr), "SHGetFolderPath failed: 0x%08lx\n", hr);
|
||||
}
|
||||
|
||||
static void doChild(const char *arg)
|
||||
{
|
||||
if (arg[0] == '1')
|
||||
testNonExistentPath1();
|
||||
else if (arg[0] == '2')
|
||||
testNonExistentPath2();
|
||||
}
|
||||
|
||||
/* Tests the return values from the various shell functions both with and
|
||||
* without the use of the CSIDL_FLAG_CREATE flag. This flag only appeared in
|
||||
* version 5 of the shell, so don't test unless it's at least version 5.
|
||||
* The test reads a value from the registry, modifies it, calls
|
||||
* SHGetFolderPath once with the CSIDL_FLAG_CREATE flag, and immediately
|
||||
* afterward without it. Then it restores the registry and deletes the folder
|
||||
* that was created.
|
||||
* One oddity with respect to restoration: shell32 caches somehow, so it needs
|
||||
* to be reloaded in order to see the correct (restored) value.
|
||||
* Some APIs unrelated to the ones under test may fail, but I expect they're
|
||||
* covered by other unit tests; I just print out something about failure to
|
||||
* help trace what's going on.
|
||||
*/
|
||||
static void testNonExistentPath(void)
|
||||
{
|
||||
static const char userShellFolders[] =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
|
||||
char originalPath[MAX_PATH], modifiedPath[MAX_PATH];
|
||||
HKEY key;
|
||||
|
||||
if (!pSHGetFolderPathA) return;
|
||||
if (!pSHGetFolderLocation) return;
|
||||
if (!pSHGetSpecialFolderPathA) return;
|
||||
if (!pSHGetSpecialFolderLocation) return;
|
||||
if (!pSHFileOperationA) return;
|
||||
if (shellVersion.dwMajorVersion < 5) return;
|
||||
|
||||
if (!RegOpenKeyExA(HKEY_CURRENT_USER, userShellFolders, 0, KEY_ALL_ACCESS,
|
||||
&key))
|
||||
{
|
||||
DWORD len, type;
|
||||
|
||||
len = sizeof(originalPath);
|
||||
if (!RegQueryValueExA(key, "Favorites", NULL, &type,
|
||||
(LPBYTE)&originalPath, &len))
|
||||
{
|
||||
size_t len = strlen(originalPath);
|
||||
|
||||
memcpy(modifiedPath, originalPath, len);
|
||||
modifiedPath[len++] = '2';
|
||||
modifiedPath[len++] = '\0';
|
||||
if (winetest_interactive)
|
||||
printf("Changing CSIDL_FAVORITES to %s\n", modifiedPath);
|
||||
if (!RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) modifiedPath, len))
|
||||
{
|
||||
char buffer[MAX_PATH];
|
||||
STARTUPINFOA startup;
|
||||
PROCESS_INFORMATION info;
|
||||
HRESULT hr;
|
||||
BOOL ret;
|
||||
|
||||
wnsprintfA(buffer, sizeof(buffer), "%s tests/shellpath.c 1",
|
||||
selfname);
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.dwFlags = SW_SHOWNORMAL;
|
||||
CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
|
||||
&startup, &info);
|
||||
ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
|
||||
"child process termination\n");
|
||||
|
||||
/* Query the path to be able to delete it below */
|
||||
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL,
|
||||
SHGFP_TYPE_CURRENT, modifiedPath);
|
||||
ok(SUCCEEDED(hr), "SHGetFolderPathA failed: 0x%08lx\n", hr);
|
||||
|
||||
/* restore original values: */
|
||||
if (winetest_interactive)
|
||||
printf("Restoring CSIDL_FAVORITES to %s\n", originalPath);
|
||||
RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath,
|
||||
strlen(originalPath) + 1);
|
||||
RegFlushKey(key);
|
||||
|
||||
wnsprintfA(buffer, sizeof(buffer), "%s tests/shellpath.c 2",
|
||||
selfname);
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.dwFlags = SW_SHOWNORMAL;
|
||||
CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
|
||||
&startup, &info);
|
||||
ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
|
||||
"child process termination\n");
|
||||
|
||||
ret = RemoveDirectoryA(modifiedPath);
|
||||
ok( ret, "RemoveDirectoryA failed: %ld\n", GetLastError());
|
||||
}
|
||||
}
|
||||
else if (winetest_interactive)
|
||||
printf("RegQueryValueExA(key, Favorites, ...) failed\n");
|
||||
if (key)
|
||||
RegCloseKey(key);
|
||||
}
|
||||
else if (winetest_interactive)
|
||||
printf("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n",
|
||||
userShellFolders);
|
||||
}
|
||||
|
||||
START_TEST(shellpath)
|
||||
{
|
||||
if (!init()) return;
|
||||
|
||||
loadShell32();
|
||||
if (!hShell32) return;
|
||||
|
||||
if (myARGC >= 3)
|
||||
doChild(myARGV[2]);
|
||||
else
|
||||
{
|
||||
/* first test various combinations of parameters: */
|
||||
testApiParameters();
|
||||
|
||||
/* check known values: */
|
||||
testPidlTypes();
|
||||
testGUIDs();
|
||||
testEnvVars();
|
||||
testWinDir();
|
||||
testSystemDir();
|
||||
testNonExistentPath();
|
||||
}
|
||||
}
|
462
reactos/regtests/winetests/shell32/shlexec.c
Executable file
462
reactos/regtests/winetests/shell32/shlexec.c
Executable file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* Unit test of the ShellExecute function.
|
||||
*
|
||||
* Copyright 2005 Francois Gouget for CodeWeavers
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
* - test the default verb selection
|
||||
* - test selection of an alternate class
|
||||
* - try running executables in more ways
|
||||
* - try passing arguments to executables
|
||||
* - ShellExecute("foo.shlexec") with no path should work if foo.shlexec is
|
||||
* in the PATH
|
||||
* - test associations that use %l, %L or "%1" instead of %1
|
||||
* - we may want to test ShellExecuteEx() instead of ShellExecute()
|
||||
* and then we could also check its return value
|
||||
* - ShellExecuteEx() also calls SetLastError() with meaningful values which
|
||||
* we could check
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wtypes.h"
|
||||
#include "winbase.h"
|
||||
#include "windef.h"
|
||||
#include "shellapi.h"
|
||||
#include "shlwapi.h"
|
||||
#include "wine/test.h"
|
||||
|
||||
#include "shell32_test.h"
|
||||
|
||||
|
||||
static char argv0[MAX_PATH];
|
||||
static int myARGC;
|
||||
static char** myARGV;
|
||||
static char tmpdir[MAX_PATH];
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
static void strcat_param(char* str, const char* param)
|
||||
{
|
||||
if (param!=NULL)
|
||||
{
|
||||
strcat(str, "\"");
|
||||
strcat(str, param);
|
||||
strcat(str, "\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(str, "null");
|
||||
}
|
||||
}
|
||||
|
||||
static char shell_call[2048]="";
|
||||
static int shell_execute(LPCSTR operation, LPCSTR file, LPCSTR parameters, LPCSTR directory)
|
||||
{
|
||||
strcpy(shell_call, "ShellExecute(");
|
||||
strcat_param(shell_call, operation);
|
||||
strcat(shell_call, ", ");
|
||||
strcat_param(shell_call, file);
|
||||
strcat(shell_call, ", ");
|
||||
strcat_param(shell_call, parameters);
|
||||
strcat(shell_call, ", ");
|
||||
strcat_param(shell_call, directory);
|
||||
strcat(shell_call, ")");
|
||||
if (winetest_debug > 1)
|
||||
trace("%s\n", shell_call);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file,
|
||||
LPCSTR parameters, LPCSTR directory)
|
||||
{
|
||||
SHELLEXECUTEINFO sei;
|
||||
BOOL success;
|
||||
int rc;
|
||||
|
||||
strcpy(shell_call, "ShellExecuteEx(");
|
||||
strcat_param(shell_call, operation);
|
||||
strcat(shell_call, ", ");
|
||||
strcat_param(shell_call, file);
|
||||
strcat(shell_call, ", ");
|
||||
strcat_param(shell_call, parameters);
|
||||
strcat(shell_call, ", ");
|
||||
strcat_param(shell_call, directory);
|
||||
strcat(shell_call, ")");
|
||||
if (winetest_debug > 1)
|
||||
trace("%s\n", shell_call);
|
||||
|
||||
sei.cbSize=sizeof(sei);
|
||||
sei.fMask=mask;
|
||||
sei.hwnd=NULL;
|
||||
sei.lpVerb=operation;
|
||||
sei.lpFile=file;
|
||||
sei.lpParameters=parameters;
|
||||
sei.lpDirectory=directory;
|
||||
sei.nShow=SW_SHOWNORMAL;
|
||||
sei.hInstApp=NULL; /* Out */
|
||||
sei.lpIDList=NULL;
|
||||
sei.lpClass=NULL;
|
||||
sei.hkeyClass=NULL;
|
||||
sei.dwHotKey=0;
|
||||
sei.hIcon=NULL;
|
||||
|
||||
SetLastError(0xcafebabe);
|
||||
success=ShellExecuteEx(&sei);
|
||||
rc=(int)sei.hInstApp;
|
||||
ok((success && rc >= 32) || (!success && rc < 32),
|
||||
"%s rc=%d and hInstApp=%d is not allowed\n", shell_call, success, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void create_test_association(const char* extension)
|
||||
{
|
||||
HKEY hkey, hkey_shell;
|
||||
char class[MAX_PATH];
|
||||
LONG rc;
|
||||
|
||||
sprintf(class, "shlexec%s", extension);
|
||||
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);
|
||||
assert(rc==ERROR_SUCCESS);
|
||||
CloseHandle(hkey);
|
||||
|
||||
rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, class, 0, NULL, 0,
|
||||
KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS, NULL, &hkey, NULL);
|
||||
assert(rc==ERROR_SUCCESS);
|
||||
rc=RegCreateKeyEx(hkey, "shell", 0, NULL, 0,
|
||||
KEY_CREATE_SUB_KEY, NULL, &hkey_shell, NULL);
|
||||
assert(rc==ERROR_SUCCESS);
|
||||
CloseHandle(hkey);
|
||||
CloseHandle(hkey_shell);
|
||||
}
|
||||
|
||||
static void delete_test_association(const char* extension)
|
||||
{
|
||||
char class[MAX_PATH];
|
||||
|
||||
sprintf(class, "shlexec%s", extension);
|
||||
SHDeleteKey(HKEY_CLASSES_ROOT, class);
|
||||
SHDeleteKey(HKEY_CLASSES_ROOT, extension);
|
||||
}
|
||||
|
||||
static void create_test_verb(const char* extension, const char* verb)
|
||||
{
|
||||
HKEY hkey_shell, hkey_verb, hkey_cmd;
|
||||
char shell[MAX_PATH];
|
||||
char* cmd;
|
||||
LONG rc;
|
||||
|
||||
sprintf(shell, "shlexec%s\\shell", extension);
|
||||
rc=RegOpenKeyEx(HKEY_CLASSES_ROOT, shell, 0,
|
||||
KEY_CREATE_SUB_KEY, &hkey_shell);
|
||||
assert(rc==ERROR_SUCCESS);
|
||||
rc=RegCreateKeyEx(hkey_shell, verb, 0, NULL, 0, KEY_CREATE_SUB_KEY,
|
||||
NULL, &hkey_verb, NULL);
|
||||
assert(rc==ERROR_SUCCESS);
|
||||
rc=RegCreateKeyEx(hkey_verb, "command", 0, NULL, 0, KEY_SET_VALUE,
|
||||
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);
|
||||
|
||||
free(cmd);
|
||||
CloseHandle(hkey_shell);
|
||||
CloseHandle(hkey_verb);
|
||||
CloseHandle(hkey_cmd);
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* basename;
|
||||
int rc;
|
||||
int todo;
|
||||
} 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},
|
||||
|
||||
/* Standard tests */
|
||||
{"%s\\test file.shlexec", 0, 0},
|
||||
{"%s\\test file.shlexec.", 0, 0},
|
||||
{"%s/test file.shlexec", 0, 0},
|
||||
|
||||
/* Test filenames with no association */
|
||||
{"%s\\test file.noassoc", SE_ERR_NOASSOC, 0},
|
||||
|
||||
/* Test double extensions */
|
||||
{"%s\\test file.noassoc.shlexec", 0, 0},
|
||||
{"%s\\test file.shlexec.noassoc", SE_ERR_NOASSOC, 0},
|
||||
|
||||
/* Test shortcuts */
|
||||
{"%s\\test_shortcut_shlexec.lnk", 0, 0},
|
||||
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static void test_filename()
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
const filename_tests_t* test;
|
||||
HMODULE hdll;
|
||||
DLLVERSIONINFO dllver;
|
||||
HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO*);
|
||||
char* c;
|
||||
int rc;
|
||||
|
||||
test=filename_tests;
|
||||
while (test->basename)
|
||||
{
|
||||
sprintf(filename, test->basename, tmpdir);
|
||||
if (strchr(filename, '/'))
|
||||
{
|
||||
c=filename;
|
||||
while (*c)
|
||||
{
|
||||
if (*c=='\\')
|
||||
*c='/';
|
||||
c++;
|
||||
}
|
||||
}
|
||||
rc=shell_execute(NULL, filename, NULL, NULL);
|
||||
if (test->rc==0)
|
||||
{
|
||||
if (test->todo)
|
||||
{
|
||||
todo_wine
|
||||
{
|
||||
ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call,
|
||||
rc, GetLastError());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call,
|
||||
rc, GetLastError());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test->todo)
|
||||
{
|
||||
todo_wine
|
||||
{
|
||||
ok(rc==test->rc, "%s returned %d\n", shell_call, rc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ok(rc==test->rc, "%s returned %d\n", shell_call, rc);
|
||||
}
|
||||
}
|
||||
test++;
|
||||
}
|
||||
|
||||
hdll=GetModuleHandleA("shell32.dll");
|
||||
pDllGetVersion=(void*)GetProcAddress(hdll, "DllGetVersion");
|
||||
if (pDllGetVersion)
|
||||
{
|
||||
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.
|
||||
* One day we may need to check the exact version of the dll but for
|
||||
* now making sure DllGetVersion() is present is sufficient.
|
||||
*/
|
||||
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,
|
||||
GetLastError());
|
||||
|
||||
if (dllver.dwMajorVersion>=6)
|
||||
{
|
||||
/* 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);
|
||||
c=filename;
|
||||
while (*c)
|
||||
{
|
||||
if (*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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_exes()
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
int rc;
|
||||
|
||||
/* We need NOZONECHECKS on Win2003 to block a dialog */
|
||||
rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, "shlexec -nop",
|
||||
NULL);
|
||||
ok(rc>=32, "%s returned %d\n", shell_call, rc);
|
||||
|
||||
sprintf(filename, "%s\\test file.noassoc", tmpdir);
|
||||
if (CopyFile(argv0, filename, FALSE))
|
||||
{
|
||||
rc=shell_execute(NULL, filename, "shlexec -nop", NULL);
|
||||
todo_wine {
|
||||
ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%d\n", shell_call, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void init_test()
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
WCHAR lnkfile[MAX_PATH];
|
||||
const char* const * testfile;
|
||||
lnk_desc_t desc;
|
||||
DWORD rc;
|
||||
HRESULT r;
|
||||
|
||||
r = CoInitialize(NULL);
|
||||
ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
|
||||
if (!SUCCEEDED(r))
|
||||
exit(1);
|
||||
|
||||
rc=GetModuleFileName(NULL, argv0, sizeof(argv0));
|
||||
assert(rc!=0 && rc<sizeof(argv0));
|
||||
if (GetFileAttributes(argv0)==INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
strcat(argv0, ".so");
|
||||
ok(GetFileAttributes(argv0)!=INVALID_FILE_ATTRIBUTES,
|
||||
"unable to find argv0!\n");
|
||||
}
|
||||
|
||||
GetTempPathA(sizeof(tmpdir)/sizeof(*tmpdir), tmpdir);
|
||||
|
||||
/* Set up the test files */
|
||||
testfile=testfiles;
|
||||
while (*testfile)
|
||||
{
|
||||
HANDLE hfile;
|
||||
|
||||
sprintf(filename, *testfile, tmpdir);
|
||||
hfile=CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hfile==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
trace("unable to create '%s': err=%ld\n", filename, GetLastError());
|
||||
assert(0);
|
||||
}
|
||||
CloseHandle(hfile);
|
||||
testfile++;
|
||||
}
|
||||
|
||||
/* Setup the test shortcuts */
|
||||
sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
|
||||
MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, sizeof(lnkfile)/sizeof(*lnkfile));
|
||||
desc.description=NULL;
|
||||
desc.workdir=NULL;
|
||||
sprintf(filename, "%s\\test file.shlexec", tmpdir);
|
||||
desc.path=filename;
|
||||
desc.pidl=NULL;
|
||||
desc.arguments="";
|
||||
desc.showcmd=0;
|
||||
desc.icon=NULL;
|
||||
desc.icon_id=0;
|
||||
desc.hotkey=0;
|
||||
create_lnk(lnkfile, &desc, 0);
|
||||
|
||||
/* Create a basic association suitable for most tests */
|
||||
create_test_association(".shlexec");
|
||||
create_test_verb(".shlexec", "Open");
|
||||
}
|
||||
|
||||
static void cleanup_test()
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
const char* const * testfile;
|
||||
|
||||
/* Delete the test files */
|
||||
testfile=testfiles;
|
||||
while (*testfile)
|
||||
{
|
||||
sprintf(filename, *testfile, tmpdir);
|
||||
DeleteFile(filename);
|
||||
testfile++;
|
||||
}
|
||||
|
||||
/* Delete the test association */
|
||||
delete_test_association(".shlexec");
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
START_TEST(shlexec)
|
||||
{
|
||||
|
||||
myARGC = winetest_get_mainargs(&myARGV);
|
||||
if (myARGC>=3)
|
||||
{
|
||||
/* FIXME: We should dump the parameters we got
|
||||
* and have the parent verify them
|
||||
*/
|
||||
exit(0);
|
||||
}
|
||||
|
||||
init_test();
|
||||
|
||||
test_filename();
|
||||
test_exes();
|
||||
|
||||
cleanup_test();
|
||||
}
|
466
reactos/regtests/winetests/shell32/shlfileop.c
Normal file
466
reactos/regtests/winetests/shell32/shlfileop.c
Normal file
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* Unit test of the SHFileOperation function.
|
||||
*
|
||||
* Copyright 2002 Andriy Palamarchuk
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define WINE_NOWINSOCK
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wtypes.h"
|
||||
#include "shellapi.h"
|
||||
#include "shlobj.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
CHAR CURR_DIR[MAX_PATH];
|
||||
|
||||
static HMODULE hshell32;
|
||||
static int (WINAPI *pSHCreateDirectoryExA)(HWND, LPCSTR, LPSECURITY_ATTRIBUTES);
|
||||
|
||||
static void InitFunctionPointers(void)
|
||||
{
|
||||
hshell32 = GetModuleHandleA("shell32.dll");
|
||||
|
||||
if(hshell32)
|
||||
pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA");
|
||||
}
|
||||
|
||||
/* creates a file with the specified name for tests */
|
||||
static void createTestFile(const CHAR *name)
|
||||
{
|
||||
HANDLE file;
|
||||
DWORD written;
|
||||
|
||||
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
|
||||
WriteFile(file, name, strlen(name), &written, NULL);
|
||||
WriteFile(file, "\n", strlen("\n"), &written, NULL);
|
||||
CloseHandle(file);
|
||||
}
|
||||
|
||||
static BOOL file_exists(const CHAR *name)
|
||||
{
|
||||
return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
/* initializes the tests */
|
||||
static void init_shfo_tests(void)
|
||||
{
|
||||
int len;
|
||||
|
||||
GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
|
||||
len = lstrlenA(CURR_DIR);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
||||
/*
|
||||
puts into the specified buffer file names with current directory.
|
||||
files - string with file names, separated by null characters. Ends on a double
|
||||
null characters
|
||||
*/
|
||||
static void set_curr_dir_path(CHAR *buf, const CHAR* files)
|
||||
{
|
||||
buf[0] = 0;
|
||||
while (files[0])
|
||||
{
|
||||
strcpy(buf, CURR_DIR);
|
||||
buf += strlen(buf);
|
||||
buf[0] = '\\';
|
||||
buf++;
|
||||
strcpy(buf, files);
|
||||
buf += strlen(buf) + 1;
|
||||
files += strlen(files) + 1;
|
||||
}
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* tests the FO_DELETE action */
|
||||
static void test_delete(void)
|
||||
{
|
||||
SHFILEOPSTRUCTA shfo;
|
||||
DWORD ret;
|
||||
CHAR buf[MAX_PATH];
|
||||
|
||||
sprintf(buf, "%s\\%s", CURR_DIR, "test?.txt");
|
||||
buf[strlen(buf) + 1] = '\0';
|
||||
|
||||
shfo.hwnd = NULL;
|
||||
shfo.wFunc = FO_DELETE;
|
||||
shfo.pFrom = buf;
|
||||
shfo.pTo = "\0";
|
||||
shfo.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT;
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
|
||||
|
||||
ok(!SHFileOperationA(&shfo), "Directory removed\n");
|
||||
ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
|
||||
|
||||
ret = SHFileOperationA(&shfo);
|
||||
ok(!ret, "The requested file does not exist, ret=%ld\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");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/* tests the FO_RENAME action */
|
||||
static void test_rename(void)
|
||||
{
|
||||
SHFILEOPSTRUCTA shfo, shfo2;
|
||||
CHAR from[MAX_PATH];
|
||||
CHAR to[MAX_PATH];
|
||||
DWORD retval;
|
||||
|
||||
shfo.hwnd = NULL;
|
||||
shfo.wFunc = FO_RENAME;
|
||||
shfo.pFrom = from;
|
||||
shfo.pTo = to;
|
||||
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
|
||||
shfo.hNameMappings = NULL;
|
||||
shfo.lpszProgressTitle = NULL;
|
||||
|
||||
set_curr_dir_path(from, "test1.txt\0");
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
|
||||
shfo2.fFlags |= FOF_MULTIDESTFILES;
|
||||
|
||||
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(&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");
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* tests the FO_COPY action */
|
||||
static void test_copy(void)
|
||||
{
|
||||
SHFILEOPSTRUCTA shfo, shfo2;
|
||||
CHAR from[MAX_PATH];
|
||||
CHAR to[MAX_PATH];
|
||||
FILEOP_FLAGS tmp_flags;
|
||||
DWORD retval;
|
||||
|
||||
shfo.hwnd = NULL;
|
||||
shfo.wFunc = FO_COPY;
|
||||
shfo.pFrom = from;
|
||||
shfo.pTo = to;
|
||||
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
|
||||
shfo.hNameMappings = NULL;
|
||||
shfo.lpszProgressTitle = NULL;
|
||||
|
||||
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 "
|
||||
"specified as a target\n");
|
||||
|
||||
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
|
||||
shfo2.fFlags |= FOF_MULTIDESTFILES;
|
||||
|
||||
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 "
|
||||
"specified as a target\n");
|
||||
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 "
|
||||
"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");
|
||||
|
||||
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(!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");
|
||||
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(!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");
|
||||
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");
|
||||
clean_after_shfo_tests();
|
||||
|
||||
/* Copying multiple files with one not existing as source, fails the
|
||||
entire operation in Win98/ME/2K/XP, but not in 95/NT */
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
}
|
||||
ok(!file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
|
||||
shfo.fFlags = tmp_flags;
|
||||
}
|
||||
|
||||
/* tests the FO_MOVE action */
|
||||
static void test_move(void)
|
||||
{
|
||||
SHFILEOPSTRUCTA shfo, shfo2;
|
||||
CHAR from[MAX_PATH];
|
||||
CHAR to[MAX_PATH];
|
||||
|
||||
shfo.hwnd = NULL;
|
||||
shfo.wFunc = FO_MOVE;
|
||||
shfo.pFrom = from;
|
||||
shfo.pTo = to;
|
||||
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
|
||||
shfo.hNameMappings = NULL;
|
||||
shfo.lpszProgressTitle = NULL;
|
||||
|
||||
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");
|
||||
|
||||
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(!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");
|
||||
|
||||
clean_after_shfo_tests();
|
||||
init_shfo_tests();
|
||||
|
||||
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
|
||||
shfo2.fFlags |= FOF_MULTIDESTFILES;
|
||||
|
||||
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 "
|
||||
"specified as a target\n");
|
||||
DeleteFileA(".\\test6.txt");
|
||||
DeleteFileA(".\\test7.txt");
|
||||
RemoveDirectoryA(".\\test8.txt");
|
||||
|
||||
init_shfo_tests();
|
||||
|
||||
/* 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 move many files\n");
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
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");
|
||||
set_curr_dir_path(from, "test6.txt\0");
|
||||
set_curr_dir_path(to, "test4.txt\0");
|
||||
ok(!SHFileOperationA(&shfo), "Move dir back\n");
|
||||
}
|
||||
|
||||
static void test_sh_create_dir(void)
|
||||
{
|
||||
CHAR path[MAX_PATH];
|
||||
int ret;
|
||||
|
||||
if(!pSHCreateDirectoryExA)
|
||||
{
|
||||
trace("skipping SHCreateDirectoryExA tests\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
ret = pSHCreateDirectoryExA(NULL, path, NULL);
|
||||
ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
|
||||
}
|
||||
|
||||
START_TEST(shlfileop)
|
||||
{
|
||||
InitFunctionPointers();
|
||||
|
||||
clean_after_shfo_tests();
|
||||
|
||||
init_shfo_tests();
|
||||
test_delete();
|
||||
clean_after_shfo_tests();
|
||||
|
||||
init_shfo_tests();
|
||||
test_rename();
|
||||
clean_after_shfo_tests();
|
||||
|
||||
init_shfo_tests();
|
||||
test_copy();
|
||||
clean_after_shfo_tests();
|
||||
|
||||
init_shfo_tests();
|
||||
test_move();
|
||||
clean_after_shfo_tests();
|
||||
|
||||
test_sh_create_dir();
|
||||
clean_after_shfo_tests();
|
||||
}
|
677
reactos/regtests/winetests/shell32/shlfolder.c
Normal file
677
reactos/regtests/winetests/shell32/shlfolder.c
Normal file
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* Unit test of the IShellFolder functions.
|
||||
*
|
||||
* Copyright 2004 Vitaliy Margolen
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define COBJMACROS
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wtypes.h"
|
||||
#include "shellapi.h"
|
||||
|
||||
|
||||
#include "shlguid.h"
|
||||
#include "shlobj.h"
|
||||
//#include "shobjidl.h"
|
||||
#include "shlwapi.h"
|
||||
|
||||
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/test.h"
|
||||
|
||||
|
||||
static IMalloc *ppM;
|
||||
|
||||
static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
|
||||
static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
|
||||
|
||||
static void init_function_pointers(void)
|
||||
{
|
||||
HMODULE hmod = GetModuleHandleA("shell32.dll");
|
||||
HRESULT hr;
|
||||
|
||||
if(hmod)
|
||||
{
|
||||
pSHBindToParent = (void*)GetProcAddress(hmod, "SHBindToParent");
|
||||
pSHGetSpecialFolderPathW = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathW");
|
||||
}
|
||||
|
||||
hr = SHGetMalloc(&ppM);
|
||||
ok(hr == S_OK, "SHGetMalloc failed %08lx\n", hr);
|
||||
}
|
||||
|
||||
static void test_ParseDisplayName(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
IShellFolder *IDesktopFolder;
|
||||
static const char *cNonExistDir1A = "c:\\nonexist_subdir";
|
||||
static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
|
||||
DWORD res;
|
||||
WCHAR cTestDirW [MAX_PATH] = {0};
|
||||
ITEMIDLIST *newPIDL;
|
||||
|
||||
hr = SHGetDesktopFolder(&IDesktopFolder);
|
||||
if(hr != S_OK) return;
|
||||
|
||||
res = GetFileAttributesA(cNonExistDir1A);
|
||||
if(res != INVALID_FILE_ATTRIBUTES) return;
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* creates a file with the specified name for tests */
|
||||
static void CreateTestFile(const CHAR *name)
|
||||
{
|
||||
HANDLE file;
|
||||
DWORD written;
|
||||
|
||||
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (file != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WriteFile(file, name, strlen(name), &written, NULL);
|
||||
WriteFile(file, "\n", strlen("\n"), &written, NULL);
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* initializes the tests */
|
||||
static void CreateFilesFolders(void)
|
||||
{
|
||||
CreateDirectoryA(".\\testdir", NULL);
|
||||
CreateDirectoryA(".\\testdir\\test.txt", NULL);
|
||||
CreateTestFile (".\\testdir\\test1.txt ");
|
||||
CreateTestFile (".\\testdir\\test2.txt ");
|
||||
CreateTestFile (".\\testdir\\test3.txt ");
|
||||
CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
|
||||
CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
|
||||
}
|
||||
|
||||
/* cleans after tests */
|
||||
static void Cleanup(void)
|
||||
{
|
||||
DeleteFileA(".\\testdir\\test1.txt");
|
||||
DeleteFileA(".\\testdir\\test2.txt");
|
||||
DeleteFileA(".\\testdir\\test3.txt");
|
||||
RemoveDirectoryA(".\\testdir\\test.txt");
|
||||
RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
|
||||
RemoveDirectoryA(".\\testdir\\testdir2");
|
||||
RemoveDirectoryA(".\\testdir");
|
||||
}
|
||||
|
||||
|
||||
/* perform test */
|
||||
static void test_EnumObjects(IShellFolder *iFolder)
|
||||
{
|
||||
IEnumIDList *iEnumList;
|
||||
LPITEMIDLIST newPIDL, idlArr[10];
|
||||
ULONG NumPIDLs;
|
||||
int i=0, j;
|
||||
HRESULT hr;
|
||||
|
||||
static const WORD iResults [5][5] =
|
||||
{
|
||||
{ 0,-1,-1,-1,-1},
|
||||
{ 1, 0,-1,-1,-1},
|
||||
{ 1, 1, 0,-1,-1},
|
||||
{ 1, 1, 1, 0,-1},
|
||||
{ 1, 1, 1, 1, 0}
|
||||
};
|
||||
|
||||
/* Just test SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR for now */
|
||||
static const ULONG attrs[5] =
|
||||
{
|
||||
SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
|
||||
SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
|
||||
SFGAO_FILESYSTEM,
|
||||
SFGAO_FILESYSTEM,
|
||||
SFGAO_FILESYSTEM,
|
||||
};
|
||||
|
||||
hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
|
||||
ok(hr == S_OK, "EnumObjects failed %08lx\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
|
||||
* returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
|
||||
* only ever returns a single entry per call. */
|
||||
while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
|
||||
i += NumPIDLs;
|
||||
ok (i == 5, "i: %d\n", i);
|
||||
|
||||
hr = IEnumIDList_Release(iEnumList);
|
||||
ok(hr == S_OK, "IEnumIDList_Release failed %08lx\n", hr);
|
||||
|
||||
/* Sort them first in case of wrong order from system */
|
||||
for (i=0;i<5;i++) for (j=0;j<5;j++)
|
||||
if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
|
||||
{
|
||||
newPIDL = idlArr[i];
|
||||
idlArr[i] = idlArr[j];
|
||||
idlArr[j] = newPIDL;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
SFGAOF flags;
|
||||
flags = SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
|
||||
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]);
|
||||
}
|
||||
|
||||
for (i=0;i<5;i++)
|
||||
IMalloc_Free(ppM, idlArr[i]);
|
||||
}
|
||||
|
||||
static void test_BindToObject(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT cChars;
|
||||
IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
|
||||
SHITEMID emptyitem = { 0, { 0 } };
|
||||
LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
|
||||
WCHAR wszSystemDir[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 };
|
||||
|
||||
/* The following tests shows that BindToObject should fail with E_INVALIDARG if called
|
||||
* 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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
cChars = GetSystemDirectoryW(wszSystemDir, MAX_PATH);
|
||||
ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryW failed! LastError: %08lx\n", GetLastError());
|
||||
if (cChars == 0 || cChars >= MAX_PATH) {
|
||||
IShellFolder_Release(psfMyComputer);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
IShellFolder_Release(psfSystemDir);
|
||||
}
|
||||
|
||||
static void test_GetDisplayName(void)
|
||||
{
|
||||
BOOL result;
|
||||
HRESULT hr;
|
||||
HANDLE hTestFile;
|
||||
WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH], wszTestDir[MAX_PATH];
|
||||
STRRET strret;
|
||||
LPSHELLFOLDER psfDesktop, psfPersonal;
|
||||
IUnknown *psfFile;
|
||||
LPITEMIDLIST pidlTestFile;
|
||||
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 };
|
||||
|
||||
/* I'm trying to figure if there is a functional difference between calling
|
||||
* SHGetPathFromIDList and calling GetDisplayNameOf(SHGDN_FORPARSING) after
|
||||
* binding to the shellfolder. One thing I thought of was that perhaps
|
||||
* SHGetPathFromIDList would be able to get the path to a file, which does
|
||||
* not exist anymore, while the other method would'nt. It turns out there's
|
||||
* no functional difference in this respect.
|
||||
*/
|
||||
|
||||
if(!pSHGetSpecialFolderPathW) return;
|
||||
|
||||
/* 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());
|
||||
if (!result) return;
|
||||
|
||||
PathAddBackslashW(wszTestDir);
|
||||
lstrcatW(wszTestDir, wszDirName);
|
||||
result = CreateDirectoryW(wszTestDir, NULL);
|
||||
ok(result, "CreateDirectoryW failed! Last error: %08lx\n", GetLastError());
|
||||
if (!result) return;
|
||||
|
||||
lstrcpyW(wszTestFile, wszTestDir);
|
||||
PathAddBackslashW(wszTestFile);
|
||||
lstrcatW(wszTestFile, wszFileName);
|
||||
|
||||
hTestFile = CreateFileW(wszTestFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
|
||||
ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %08lx\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);
|
||||
if (FAILED(hr)) return;
|
||||
|
||||
hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
|
||||
ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08lx\n", hr);
|
||||
if (FAILED(hr)) {
|
||||
IShellFolder_Release(psfDesktop);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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); }
|
||||
if (SUCCEEDED(hr)) {
|
||||
IShellFolder_Release(psfFile);
|
||||
}
|
||||
|
||||
/* Deleting the file and the directory */
|
||||
DeleteFileW(wszTestFile);
|
||||
RemoveDirectoryW(wszTestDir);
|
||||
|
||||
/* SHGetPathFromIDListW still works, although the file is not present anymore. */
|
||||
result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
|
||||
ok (result, "SHGetPathFromIDListW failed! Last error: %08lx\n", GetLastError());
|
||||
ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
|
||||
|
||||
if(!pSHBindToParent) return;
|
||||
|
||||
/* 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);
|
||||
if (FAILED(hr)) {
|
||||
IShellFolder_Release(psfDesktop);
|
||||
return;
|
||||
}
|
||||
|
||||
hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
|
||||
ok (SUCCEEDED(hr), "Personal->GetDisplayNameOf failed! hr = %08lx\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");
|
||||
|
||||
IShellFolder_Release(psfDesktop);
|
||||
IShellFolder_Release(psfPersonal);
|
||||
}
|
||||
|
||||
static void test_CallForAttributes(void)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG lResult;
|
||||
HRESULT hr;
|
||||
DWORD dwSize;
|
||||
LPSHELLFOLDER psfDesktop;
|
||||
LPITEMIDLIST pidlMyDocuments;
|
||||
DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
|
||||
static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
|
||||
static const WCHAR wszCallForAttributes[] = {
|
||||
'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
|
||||
static const WCHAR wszMyDocumentsKey[] = {
|
||||
'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
|
||||
'1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
|
||||
'\\','S','h','e','l','l','F','o','l','d','e','r',0 };
|
||||
WCHAR wszMyDocuments[] = {
|
||||
':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
|
||||
'9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
|
||||
|
||||
/* For the root of a namespace extension, the attributes are not queried by binding
|
||||
* to the object and calling GetAttributesOf. Instead, the attributes are read from
|
||||
* the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
|
||||
*
|
||||
* The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
|
||||
* value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
|
||||
* the shell does bind to the folder object and calls GetAttributesOf. This is not documented
|
||||
* 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);
|
||||
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);
|
||||
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);
|
||||
|
||||
/* 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_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
|
||||
ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
|
||||
|
||||
/* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
|
||||
* 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); }
|
||||
if (lResult != ERROR_SUCCESS) {
|
||||
IMalloc_Free(ppM, pidlMyDocuments);
|
||||
IShellFolder_Release(psfDesktop);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (lResult != ERROR_SUCCESS) {
|
||||
RegCloseKey(hKey);
|
||||
IMalloc_Free(ppM, pidlMyDocuments);
|
||||
IShellFolder_Release(psfDesktop);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
|
||||
dwSize = sizeof(DWORD);
|
||||
lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
|
||||
(LPBYTE)&dwOrigCallForAttributes, &dwSize);
|
||||
ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08lx\n", lResult);
|
||||
if (lResult != ERROR_SUCCESS) {
|
||||
RegCloseKey(hKey);
|
||||
IMalloc_Free(ppM, pidlMyDocuments);
|
||||
IShellFolder_Release(psfDesktop);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
|
||||
* SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
|
||||
* SFGAO_FILESYSTEM attributes. */
|
||||
dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
|
||||
RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
|
||||
dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
|
||||
RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
|
||||
(LPBYTE)&dwCallForAttributes, sizeof(DWORD));
|
||||
|
||||
/* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
|
||||
* GetAttributesOf. It seems that once there is a single attribute queried, for which
|
||||
* CallForAttributes is set, all flags are taken from the GetAttributesOf call and
|
||||
* the flags in Attributes are ignored.
|
||||
*/
|
||||
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);
|
||||
if (SUCCEEDED(hr))
|
||||
ok (dwAttributes == SFGAO_FILESYSTEM,
|
||||
"Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08lx\n",
|
||||
dwAttributes);
|
||||
|
||||
/* Restore MyDocuments' original Attributes and CallForAttributes registry values */
|
||||
RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
|
||||
RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
|
||||
(LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
|
||||
RegCloseKey(hKey);
|
||||
IMalloc_Free(ppM, pidlMyDocuments);
|
||||
IShellFolder_Release(psfDesktop);
|
||||
}
|
||||
|
||||
static void test_GetAttributesOf(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
LPSHELLFOLDER psfDesktop, psfMyComputer;
|
||||
SHITEMID emptyitem = { 0, { 0 } };
|
||||
LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
|
||||
LPITEMIDLIST pidlMyComputer;
|
||||
DWORD dwFlags;
|
||||
const static 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 */
|
||||
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 };
|
||||
|
||||
hr = SHGetDesktopFolder(&psfDesktop);
|
||||
ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\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",
|
||||
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",
|
||||
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);
|
||||
if (FAILED(hr)) {
|
||||
IShellFolder_Release(psfDesktop);
|
||||
return;
|
||||
}
|
||||
|
||||
/* WinXP SP2 sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
|
||||
* folder object. It doesn't do this, if MyComputer is queried directly (see below).
|
||||
* SFGAO_CANLINK is the same as DROPEFFECT_LINK, which MSDN says means: "Drag source
|
||||
* should create a link to the original data". You can't create links on MyComputer on
|
||||
* Windows, so this flag shouldn't be set. Seems like a bug in Windows. As long as nobody
|
||||
* depends on this bug, we probably shouldn't imitate it.
|
||||
*/
|
||||
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); }
|
||||
|
||||
hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
|
||||
ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08lx\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); }
|
||||
|
||||
dwFlags = 0xffffffff;
|
||||
hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
|
||||
ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08lx\n", hr);
|
||||
todo_wine { ok (dwFlags == dwMyComputerFlags,
|
||||
"Wrong MyComputer attributes: %08lx, expected: %08lx\n", dwFlags, dwMyComputerFlags); }
|
||||
|
||||
IShellFolder_Release(psfMyComputer);
|
||||
}
|
||||
|
||||
static void test_SHGetPathFromIDList(void)
|
||||
{
|
||||
SHITEMID emptyitem = { 0, { 0 } };
|
||||
LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
|
||||
LPITEMIDLIST pidlMyComputer;
|
||||
WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
|
||||
BOOL result;
|
||||
HRESULT hr;
|
||||
LPSHELLFOLDER psfDesktop;
|
||||
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 };
|
||||
|
||||
if(!pSHGetSpecialFolderPathW) return;
|
||||
|
||||
/* 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());
|
||||
if (!result) return;
|
||||
|
||||
result = SHGetPathFromIDListW(pidlEmpty, wszPath);
|
||||
ok(result, "SHGetPathFromIDListW failed! Last error: %08lx\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);
|
||||
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;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
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());
|
||||
|
||||
IMalloc_Free(ppM, pidlMyComputer);
|
||||
}
|
||||
|
||||
static void test_EnumObjects_and_CompareIDs(void)
|
||||
{
|
||||
ITEMIDLIST *newPIDL;
|
||||
IShellFolder *IDesktopFolder, *testIShellFolder;
|
||||
char cCurrDirA [MAX_PATH] = {0};
|
||||
WCHAR cCurrDirW [MAX_PATH];
|
||||
static const WCHAR cTestDirW[] = {'\\','t','e','s','t','d','i','r',0};
|
||||
int len;
|
||||
HRESULT hr;
|
||||
|
||||
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);
|
||||
strcatW(cCurrDirW, cTestDirW);
|
||||
|
||||
hr = SHGetDesktopFolder(&IDesktopFolder);
|
||||
ok(hr == S_OK, "SHGetDesktopfolder failed %08lx\n", hr);
|
||||
|
||||
CreateFilesFolders();
|
||||
|
||||
hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
|
||||
ok(hr == S_OK, "ParseDisplayName failed %08lx\n", hr);
|
||||
|
||||
hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
|
||||
ok(hr == S_OK, "BindToObject failed %08lx\n", hr);
|
||||
|
||||
test_EnumObjects(testIShellFolder);
|
||||
|
||||
hr = IShellFolder_Release(testIShellFolder);
|
||||
ok(hr == S_OK, "IShellFolder_Release failed %08lx\n", hr);
|
||||
|
||||
Cleanup();
|
||||
|
||||
IMalloc_Free(ppM, newPIDL);
|
||||
}
|
||||
|
||||
START_TEST(shlfolder)
|
||||
{
|
||||
init_function_pointers();
|
||||
/* if OleInitialize doesn't get called, ParseDisplayName returns
|
||||
CO_E_NOTINITIALIZED for malformed directory names on win2k. */
|
||||
OleInitialize(NULL);
|
||||
|
||||
test_ParseDisplayName();
|
||||
test_BindToObject();
|
||||
test_EnumObjects_and_CompareIDs();
|
||||
test_GetDisplayName();
|
||||
test_GetAttributesOf();
|
||||
test_SHGetPathFromIDList();
|
||||
test_CallForAttributes();
|
||||
|
||||
OleUninitialize();
|
||||
}
|
117
reactos/regtests/winetests/shell32/string.c
Executable file
117
reactos/regtests/winetests/shell32/string.c
Executable file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Unit tests for shell32 string operations
|
||||
*
|
||||
* Copyright 2004 Jon Griffiths
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
#define WINE_NOWINSOCK
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wtypes.h"
|
||||
#include "shellapi.h"
|
||||
#include "shtypes.h"
|
||||
#include "objbase.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static HMODULE hShell32;
|
||||
static HRESULT (WINAPI *pStrRetToStrNAW)(LPVOID,DWORD,LPSTRRET,const ITEMIDLIST *);
|
||||
|
||||
static WCHAR *CoDupStrW(const char* src)
|
||||
{
|
||||
INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
|
||||
WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR));
|
||||
MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
|
||||
return szTemp;
|
||||
}
|
||||
|
||||
static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
|
||||
{
|
||||
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
|
||||
return *str1 - *str2;
|
||||
}
|
||||
|
||||
static void test_StrRetToStringNA(void)
|
||||
{
|
||||
trace("StrRetToStringNAW is Ascii\n");
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static void test_StrRetToStringNW(void)
|
||||
{
|
||||
static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
|
||||
ITEMIDLIST iidl[10];
|
||||
WCHAR buff[128];
|
||||
STRRET strret;
|
||||
BOOL ret;
|
||||
|
||||
trace("StrRetToStringNAW is Unicode\n");
|
||||
|
||||
strret.uType = STRRET_WSTR;
|
||||
strret.u.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");
|
||||
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;
|
||||
strcpy((char*)&iidl, " Test");
|
||||
memset(buff, 0xff, sizeof(buff));
|
||||
ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, iidl);
|
||||
ok(ret == TRUE && !strcmpW(buff, szTestW),
|
||||
"STRRET_OFFSET: dup failed, ret=%d\n", ret);
|
||||
|
||||
/* The next test crashes on W2K, WinXP and W2K3, so we don't test. */
|
||||
#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");
|
||||
pStrRetToStrNAW(NULL, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
|
||||
trace("NULL dest: ret=%d\n", ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
START_TEST(string)
|
||||
{
|
||||
CoInitialize(0);
|
||||
|
||||
hShell32 = LoadLibraryA("shell32.dll");
|
||||
if (!hShell32)
|
||||
return;
|
||||
|
||||
pStrRetToStrNAW = (void*)GetProcAddress(hShell32, (LPSTR)96);
|
||||
if (pStrRetToStrNAW)
|
||||
{
|
||||
if (!(GetVersion() & 0x80000000))
|
||||
test_StrRetToStringNW();
|
||||
else
|
||||
test_StrRetToStringNA();
|
||||
}
|
||||
}
|
36
reactos/regtests/winetests/shell32/testlist.c
Normal file
36
reactos/regtests/winetests/shell32/testlist.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* Automatically generated file; DO NOT EDIT!! */
|
||||
|
||||
/* stdarg.h is needed for Winelib */
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
||||
extern void func_shelllink(void);
|
||||
extern void func_shellpath(void);
|
||||
extern void func_shlexec(void);
|
||||
extern void func_shlfileop(void);
|
||||
extern void func_shlfolder(void);
|
||||
extern void func_string(void);
|
||||
|
||||
struct test
|
||||
{
|
||||
const char *name;
|
||||
void (*func)(void);
|
||||
};
|
||||
|
||||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "shelllink", func_shelllink },
|
||||
{ "shellpath", func_shellpath },
|
||||
{ "shlexec", func_shlexec },
|
||||
{ "shlfileop", func_shlfileop },
|
||||
{ "shlfolder", func_shlfolder },
|
||||
{ "string", func_string },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
#define WINETEST_WANT_MAIN
|
||||
#include "wine/test.h"
|
Loading…
Reference in a new issue