From 3abb5bd6bb1c8d10bdc07fae088519c84c2c4f9d Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 25 Apr 2005 10:56:29 +0000 Subject: [PATCH] Support for regular files (as opposed to directories). --- dlls/shell32/shell32_De.rc | 77 ++++----- dlls/shell32/shell32_En.rc | 77 ++++----- dlls/shell32/shfldr_unixfs.c | 307 ++++++++++++++++++++++++++--------- dlls/shell32/shresdef.h | 2 + 4 files changed, 291 insertions(+), 172 deletions(-) diff --git a/dlls/shell32/shell32_De.rc b/dlls/shell32/shell32_De.rc index e9955f1d4e7..b14a3c4ccf2 100644 --- a/dlls/shell32/shell32_De.rc +++ b/dlls/shell32/shell32_De.rc @@ -132,43 +132,9 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "&Durchsuchen...", 12288, 170, 63, 50, 14, WS_TABSTOP } -/* - special folders -*/ STRINGTABLE DISCARDABLE { - IDS_DESKTOP "Desktop" - IDS_MYCOMPUTER "Arbeitsplatz" -} - -/* - context menus -*/ -STRINGTABLE DISCARDABLE -{ - IDS_VIEW_LARGE "&Große Symbole" - IDS_VIEW_SMALL "&Kleine Symbole" - IDS_VIEW_LIST "&Liste" - IDS_VIEW_DETAILS "&Details" - IDS_SELECT "Auswählen" - IDS_OPEN "Öffnen" -} - -STRINGTABLE DISCARDABLE -{ - IDS_CREATEFOLDER_DENIED "Es konnte kein neues Verzeichnis erstellt werden: Zugriff verweigert." - IDS_CREATEFOLDER_CAPTION "Es trat ein Fehler beim Erstellen eines neuen Verzeichnisses auf" - IDS_DELETEITEM_CAPTION "Bestätigung: Datei löschen" - IDS_DELETEFOLDER_CAPTION "Bestätigung: Verzeichnis löschen" - IDS_DELETEITEM_TEXT "Sind Sie sich sicher, dass Sie die Datei '%1' löschen möchten ?" - IDS_DELETEMULTIPLE_TEXT "Sind Sie sich sicher, dass Sie diese %1 Dateien löschen möchten ?" - IDS_OVERWRITEFILE_TEXT "Möchten Sie, dass die Datei '%1' überschrieben wird ?" - IDS_OVERWRITEFILE_CAPTION "Bestätigung: Datei überschreiben" -} - -/* columns in the shellview */ -STRINGTABLE -BEGIN + /* columns in the shellview */ IDS_SHV_COLUMN1 "Datei" IDS_SHV_COLUMN2 "Größe" IDS_SHV_COLUMN3 "Typ" @@ -178,20 +144,37 @@ BEGIN IDS_SHV_COLUMN7 "Freier Speicher" IDS_SHV_COLUMN8 "Name" IDS_SHV_COLUMN9 "Kommentar" -END + IDS_SHV_COLUMN10 "Besitzer" + IDS_SHV_COLUMN11 "Gruppe" -/* message box strings */ -STRINGTABLE DISCARDABLE -{ - IDS_RESTART_TITLE "Neustarten" - IDS_RESTART_PROMPT "Möchten Sie, dass ein simulierter Windows Neustart durchgeführt wird ?" - IDS_SHUTDOWN_TITLE "Anhalten" - IDS_SHUTDOWN_PROMPT "Möchten Sie die aktuelle Wine Sitzung beenden ?" -} + /* special folders */ + IDS_DESKTOP "Desktop" + IDS_MYCOMPUTER "Arbeitsplatz" -/* shell folder path default values */ -STRINGTABLE DISCARDABLE -{ + /* context menus */ + IDS_VIEW_LARGE "&Große Symbole" + IDS_VIEW_SMALL "&Kleine Symbole" + IDS_VIEW_LIST "&Liste" + IDS_VIEW_DETAILS "&Details" + IDS_SELECT "Auswählen" + IDS_OPEN "Öffnen" + + IDS_CREATEFOLDER_DENIED "Es konnte kein neues Verzeichnis erstellt werden: Zugriff verweigert." + IDS_CREATEFOLDER_CAPTION "Es trat ein Fehler beim Erstellen eines neuen Verzeichnisses auf" + IDS_DELETEITEM_CAPTION "Bestätigung: Datei löschen" + IDS_DELETEFOLDER_CAPTION "Bestätigung: Verzeichnis löschen" + IDS_DELETEITEM_TEXT "Sind Sie sich sicher, dass Sie die Datei '%1' löschen möchten ?" + IDS_DELETEMULTIPLE_TEXT "Sind Sie sich sicher, dass Sie diese %1 Dateien löschen möchten ?" + IDS_OVERWRITEFILE_TEXT "Möchten Sie, dass die Datei '%1' überschrieben wird ?" + IDS_OVERWRITEFILE_CAPTION "Bestätigung: Datei überschreiben" + + /* message box strings */ + IDS_RESTART_TITLE "Neustarten" + IDS_RESTART_PROMPT "Möchten Sie, dass ein simulierter Windows Neustart durchgeführt wird ?" + IDS_SHUTDOWN_TITLE "Anhalten" + IDS_SHUTDOWN_PROMPT "Möchten Sie die aktuelle Wine Sitzung beenden ?" + + /* shell folder path default values */ IDS_PROGRAMS "Startmenü\\Programme" IDS_PERSONAL "Eigene Dateien" IDS_FAVORITES "Favoriten" diff --git a/dlls/shell32/shell32_En.rc b/dlls/shell32/shell32_En.rc index 66011db29d8..027f3bdb7fb 100644 --- a/dlls/shell32/shell32_En.rc +++ b/dlls/shell32/shell32_En.rc @@ -131,43 +131,9 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "&Browse...", 12288, 170, 63, 50, 14, WS_TABSTOP } -/* - special folders -*/ STRINGTABLE DISCARDABLE { - IDS_DESKTOP "Desktop" - IDS_MYCOMPUTER "My Computer" -} - -/* - context menus -*/ -STRINGTABLE DISCARDABLE -{ - IDS_VIEW_LARGE "Lar&ge Icons" - IDS_VIEW_SMALL "S&mall Icons" - IDS_VIEW_LIST "&List" - IDS_VIEW_DETAILS "&Details" - IDS_SELECT "Select" - IDS_OPEN "Open" -} - -STRINGTABLE DISCARDABLE -{ - IDS_CREATEFOLDER_DENIED "Can not create new Folder: Permission denied." - IDS_CREATEFOLDER_CAPTION "Error during creation of a new folder" - IDS_DELETEITEM_CAPTION "Confirm file delete" - IDS_DELETEFOLDER_CAPTION "Confirm folder delete" - IDS_DELETEITEM_TEXT "Are you sure you want to delete '%1'?" - IDS_DELETEMULTIPLE_TEXT "Are you sure you want to delete these %1 items?" - IDS_OVERWRITEFILE_TEXT "OverWrite File %1?" - IDS_OVERWRITEFILE_CAPTION "Confirm File OverWrite" -} - -/* columns in the shellview */ -STRINGTABLE -BEGIN + /* columns in the shellview */ IDS_SHV_COLUMN1 "File" IDS_SHV_COLUMN2 "Size" IDS_SHV_COLUMN3 "Type" @@ -177,20 +143,37 @@ BEGIN IDS_SHV_COLUMN7 "Size available" IDS_SHV_COLUMN8 "Name" IDS_SHV_COLUMN9 "Comments" -END + IDS_SHV_COLUMN10 "Owner" + IDS_SHV_COLUMN11 "Group" -/* message box strings */ -STRINGTABLE DISCARDABLE -{ - IDS_RESTART_TITLE "Restart" - IDS_RESTART_PROMPT "Do you want to simulate a Windows reboot?" - IDS_SHUTDOWN_TITLE "Shutdown" - IDS_SHUTDOWN_PROMPT "Do you want to shutdown your Wine session?" -} + /* special folders */ + IDS_DESKTOP "Desktop" + IDS_MYCOMPUTER "My Computer" -/* shell folder path default values */ -STRINGTABLE DISCARDABLE -{ + /* context menus */ + IDS_VIEW_LARGE "Lar&ge Icons" + IDS_VIEW_SMALL "S&mall Icons" + IDS_VIEW_LIST "&List" + IDS_VIEW_DETAILS "&Details" + IDS_SELECT "Select" + IDS_OPEN "Open" + + IDS_CREATEFOLDER_DENIED "Can not create new Folder: Permission denied." + IDS_CREATEFOLDER_CAPTION "Error during creation of a new folder" + IDS_DELETEITEM_CAPTION "Confirm file delete" + IDS_DELETEFOLDER_CAPTION "Confirm folder delete" + IDS_DELETEITEM_TEXT "Are you sure you want to delete '%1'?" + IDS_DELETEMULTIPLE_TEXT "Are you sure you want to delete these %1 items?" + IDS_OVERWRITEFILE_TEXT "OverWrite File %1?" + IDS_OVERWRITEFILE_CAPTION "Confirm File OverWrite" + + /* message box strings */ + IDS_RESTART_TITLE "Restart" + IDS_RESTART_PROMPT "Do you want to simulate a Windows reboot?" + IDS_SHUTDOWN_TITLE "Shutdown" + IDS_SHUTDOWN_PROMPT "Do you want to shutdown your Wine session?" + + /* shell folder path default values */ IDS_PROGRAMS "Start Menu\\Programs" IDS_PERSONAL "My Documents" IDS_FAVORITES "Favorites" diff --git a/dlls/shell32/shfldr_unixfs.c b/dlls/shell32/shfldr_unixfs.c index 8dfda05a409..cb8c312b77a 100644 --- a/dlls/shell32/shfldr_unixfs.c +++ b/dlls/shell32/shfldr_unixfs.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #define COBJMACROS #define NONAMELESSUNION @@ -30,6 +33,8 @@ #include "winbase.h" #include "winuser.h" #include "objbase.h" +#include "winreg.h" +#include "winternl.h" #include "wine/debug.h" #include "shell32_main.h" @@ -44,48 +49,101 @@ const GUID CLSID_UnixFolder = {0xcc702eb2, 0x7dc5, 0x11d9, {0xc6, 0x87, 0x00, 0x #define ADJUST_THIS(c,m,p) ((c*)(((long)p)-(long)&(((c*)0)->lp##m##Vtbl))) #define STATIC_CAST(i,p) ((i*)&p->lp##i##Vtbl) -/* FileStruct reserves one byte for szNames, thus we don't need to - * alloc a byte for the terminating '\0' of 'name'. Two of the four +/* FileStruct reserves one byte for szNames, thus we don't have to + * alloc a byte for the terminating '\0' of 'name'. Two of the * additional bytes are for SHITEMID's cb field. One is for IDLDATA's * type field. One is for FileStruct's szNames field, to terminate - * the alternate DOS name, which we don't use here. + * the alternate DOS name, which we don't use here. And then there's + * the additional StatStruct. */ -#define SHITEMID_LEN_FROM_NAME_LEN(n) (sizeof(USHORT)+sizeof(PIDLTYPE)+sizeof(FileStruct)+(n)+sizeof(char)) -#define NAME_LEN_FROM_LPSHITEMID(s) (((LPSHITEMID)s)->cb-sizeof(USHORT)-sizeof(PIDLTYPE)-sizeof(FileStruct)-sizeof(char)) +#define SHITEMID_LEN_FROM_NAME_LEN(n) \ + (sizeof(USHORT)+sizeof(PIDLTYPE)+sizeof(FileStruct)+(n)+sizeof(char)+sizeof(StatStruct)) +#define NAME_LEN_FROM_LPSHITEMID(s) \ + (((LPSHITEMID)s)->cb-sizeof(USHORT)-sizeof(PIDLTYPE)-sizeof(FileStruct)-sizeof(char)-sizeof(StatStruct)) +#define LPSTATSTRUCT_FROM_LPSHITEMID(s) ((StatStruct*)(((LPBYTE)s)+((LPSHITEMID)s)->cb-sizeof(StatStruct))) + +/* This structure is appended to shell32's FileStruct type in IDLs to store unix + * filesystem specific informationen extracted with the stat system call. + */ +typedef struct tagStatStruct { + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; +} StatStruct; + +/****************************************************************************** + * UNIXFS_is_pidl_of_type [INTERNAL] + * + * Checks for the first SHITEMID of an ITEMIDLIST if it passes a filter. + * + * PARAMS + * pIDL [I] The ITEMIDLIST to be checked. + * fFilter [I] Shell condition flags, which specify the filter. + * + * RETURNS + * TRUE, if pIDL is accepted by fFilter + * FALSE, otherwise + */ +static inline BOOL UNIXFS_is_pidl_of_type(LPITEMIDLIST pIDL, SHCONTF fFilter) { + LPSTR pszText = _ILGetTextPointer(pIDL); + if (!pszText) return FALSE; + if (pszText[0] == '.' && !(fFilter & SHCONTF_INCLUDEHIDDEN)) return FALSE; + if (_ILIsFolder(pIDL) && (fFilter & SHCONTF_FOLDERS)) return TRUE; + if (_ILIsValue(pIDL) && (fFilter & SHCONTF_NONFOLDERS)) return TRUE; + return FALSE; +} /****************************************************************************** * UNIXFS_build_shitemid [Internal] * - * Builds a shell item for the given path. Only the part of the path up to the - * next '/' or to the end of the string is considered. Don't forget do append a - * 0 ushort value, if what you need is a ITEMIDLIST with a single entry. + * Constructs a new SHITEMID for a single path item (up to the next '/' or + * '\0') into a buffer. Decorates the SHITEMID with information from a stat + * system call. * - * The signature of this function will change in the future. Better documentation - * to follow. + * PARAMS + * name [I] The name of the next path item. Terminated by either '\0' or '/'. + * pStat [I] A stat struct variable obtained by a stat system call on the file. + * buffer [O] SHITEMID will be constructed here. + * + * RETURNS + * A pointer to the next '/' or '\0' character in name. + * + * NOTES + * Minimum size of buffer is SHITEMID_LEN_FROM_NAME_LEN(strlen(name)). + * If what you need is a PIDLLIST with a single SHITEMID, don't forget to append + * a 0 USHORT value. */ -static const char* UNIXFS_build_shitemid(const char *name, void *buffer) { +static char* UNIXFS_build_shitemid(char *name, struct stat *pStat, void *buffer) { + LARGE_INTEGER time; + FILETIME fileTime; LPPIDLDATA pIDLData; + StatStruct *pStatStruct; int cNameLen; char *pSlash; TRACE("(name=%s, buffer=%p)\n", debugstr_a(name), buffer); - + pSlash = strchr(name, '/'); cNameLen = pSlash ? pSlash - name : strlen(name); memset(buffer, 0, SHITEMID_LEN_FROM_NAME_LEN(cNameLen)); ((LPSHITEMID)buffer)->cb = SHITEMID_LEN_FROM_NAME_LEN(cNameLen) ; - /* Other than the type and the name those are dummy values for now. More to come. - */ pIDLData = _ILGetDataPointer((LPCITEMIDLIST)buffer); - pIDLData->type = PT_FOLDER; - pIDLData->u.file.dwFileSize = 0; - pIDLData->u.file.uFileDate = 0; - pIDLData->u.file.uFileTime = 0; + pIDLData->type = S_ISDIR(pStat->st_mode) ? PT_FOLDER : PT_VALUE; + pIDLData->u.file.dwFileSize = (DWORD)pStat->st_size; + RtlSecondsSince1970ToTime( pStat->st_mtime, &time ); + fileTime.dwLowDateTime = time.u.LowPart; + fileTime.dwHighDateTime = time.u.HighPart; + FileTimeToDosDateTime(&fileTime, &pIDLData->u.file.uFileDate, &pIDLData->u.file.uFileTime); pIDLData->u.file.uFileAttribs = 0; memcpy(pIDLData->u.file.szNames, name, cNameLen); + pStatStruct = LPSTATSTRUCT_FROM_LPSHITEMID(buffer); + pStatStruct->st_mode = pStat->st_mode; + pStatStruct->st_uid = pStat->st_uid; + pStatStruct->st_gid = pStat->st_gid; + return pSlash ? pSlash+1 : (name + cNameLen); } @@ -105,10 +163,11 @@ static const char* UNIXFS_build_shitemid(const char *name, void *buffer) { * ending with a slash ('/'). Currently, only directories (no files) * are accepted. */ -static BOOL UNIXFS_path_to_pidl(const char *path, LPITEMIDLIST *ppidl) { +static BOOL UNIXFS_path_to_pidl(char *path, LPITEMIDLIST *ppidl) { LPITEMIDLIST pidl; + struct stat fileStat; int cSubDirs, cPidlLen; - const char *pSlash; + char *pSlash, swap; TRACE("path=%s, ppidl=%p", debugstr_a(path), ppidl); @@ -130,9 +189,26 @@ static BOOL UNIXFS_path_to_pidl(const char *path, LPITEMIDLIST *ppidl) { if (!pidl) return FALSE; /* Concatenate the SHITEMIDs of the sub-directories. */ + pSlash = path; /* First character of path is guaranteed to be '/' */ while (*path) { - path = UNIXFS_build_shitemid(path, pidl); + if (pSlash) { + /* For the stat call, we temporarily replace the char + * after the next '/' with a '\0'. */ + swap = pSlash[1]; + pSlash[1] = '\0'; + if (stat(path, &fileStat)) { + pSlash[1] = swap; + return FALSE; + } + pSlash[1] = swap; + } else { + /* We are at the last item in path. */ + if (stat(path, &fileStat)) return FALSE; + } + + path = UNIXFS_build_shitemid(path, &fileStat, pidl); pidl = ILGetNext(pidl); + pSlash = strchr(path, '/'); } pidl->mkid.cb = 0; /* Terminate the ITEMIDLIST */ @@ -218,12 +294,14 @@ static BOOL UNIXFS_pidl_to_path(LPCITEMIDLIST pidl, PSZ *path) { */ static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, DWORD *pCount) { + struct dirent *pDirEntry; + struct stat fileStat; DIR *dir; - struct dirent *pSubDir; - DWORD cSubDirs, i; + DWORD cDirEntries, i; USHORT sLen; + char *pszFQPath; - TRACE("(path=%s, apidl=%p, pCount=%p)\n", path, apidl, pCount); + TRACE("(path=%s, apidl=%p, pCount=%p)\n", debugstr_a(path), apidl, pCount); *apidl = NULL; *pCount = 0; @@ -234,8 +312,9 @@ static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, if (!strlen(path)) { LPSHITEMID pid; + if (stat("/", &fileStat)) return FALSE; pid = (LPSHITEMID)SHAlloc(SHITEMID_LEN_FROM_NAME_LEN(0)+sizeof(USHORT)); - UNIXFS_build_shitemid("", pid); + UNIXFS_build_shitemid("", &fileStat, pid); memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT)); *apidl = SHAlloc(sizeof(LPITEMIDLIST)); @@ -255,48 +334,51 @@ static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, return FALSE; } - /* Count number of sub directories. - */ - for (cSubDirs = 0, pSubDir = readdir(dir); pSubDir; pSubDir = readdir(dir)) { - if (strcmp(pSubDir->d_name, ".") && - strcmp(pSubDir->d_name, "..") && - pSubDir->d_type == DT_DIR) - { - cSubDirs++; - } + /* Allocate space for fully qualified paths */ + pszFQPath = SHAlloc(strlen(path) + NAME_MAX); + if (!pszFQPath) { + WARN("SHAlloc failed!\n"); + return FALSE; + } + + /* Count number of directory entries. */ + for (cDirEntries = 0, pDirEntry = readdir(dir); pDirEntry; pDirEntry = readdir(dir)) { + if (!strcmp(pDirEntry->d_name, ".") || !strcmp(pDirEntry->d_name, "..")) continue; + sprintf(pszFQPath, "%s%s", path, pDirEntry->d_name); + if (!stat(pszFQPath, &fileStat) && (S_ISDIR(fileStat.st_mode) || S_ISREG(fileStat.st_mode))) cDirEntries++; } - /* If there are no subdirectories, we are done. */ - if (cSubDirs == 0) { + /* If there are no entries, we are done. */ + if (cDirEntries == 0) { closedir(dir); + SHFree(pszFQPath); return TRUE; } /* Allocate the array of PIDLs */ - *apidl = SHAlloc(cSubDirs * sizeof(LPITEMIDLIST)); + *apidl = SHAlloc(cDirEntries * sizeof(LPITEMIDLIST)); if (!apidl) { WARN("SHAlloc failed!\n"); return FALSE; } - + /* Allocate and initialize one SHITEMID per sub-directory. */ - for (rewinddir(dir), pSubDir = readdir(dir), i = 0; pSubDir; pSubDir = readdir(dir)) { + for (rewinddir(dir), pDirEntry = readdir(dir), i = 0; pDirEntry; pDirEntry = readdir(dir)) { LPSHITEMID pid; - if (!strcmp(pSubDir->d_name, ".") || - !strcmp(pSubDir->d_name, "..") || - pSubDir->d_type != DT_DIR) - { - continue; - } + if (!strcmp(pDirEntry->d_name, ".") || !strcmp(pDirEntry->d_name, "..")) continue; + + sprintf(pszFQPath, "%s%s", path, pDirEntry->d_name); + if (stat(pszFQPath, &fileStat)) continue; + if (!S_ISDIR(fileStat.st_mode) && !S_ISREG(fileStat.st_mode)) continue; - sLen = strlen(pSubDir->d_name); + sLen = strlen(pDirEntry->d_name); pid = (LPSHITEMID)SHAlloc(SHITEMID_LEN_FROM_NAME_LEN(sLen)+sizeof(USHORT)); if (!pid) { WARN("SHAlloc failed!\n"); return FALSE; } - UNIXFS_build_shitemid(pSubDir->d_name, pid); + UNIXFS_build_shitemid(pDirEntry->d_name, &fileStat, pid); memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT)); (*apidl)[i++] = (LPITEMIDLIST)pid; @@ -304,6 +386,7 @@ static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, *pCount = i; closedir(dir); + SHFree(pszFQPath); return TRUE; } @@ -321,6 +404,7 @@ static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, */ typedef struct _UnixFolderIcon { const IExtractIconWVtbl *lpIExtractIconWVtbl; + BOOL bFolder; } UnixFolderIcon; static HRESULT WINAPI UnixFolderIcon_IExtractIconW_QueryInterface(IExtractIconW *iface, REFIID riid, @@ -356,11 +440,17 @@ static ULONG WINAPI UnixFolderIcon_IExtractIconW_Release(IExtractIconW *iface) { static HRESULT WINAPI UnixFolderIcon_IExtractIconW_GetIconLocation(IExtractIconW *iface, UINT uFlags, LPWSTR szIconFile, UINT cchMax, INT* piIndex, UINT* pwFlags) { + UnixFolderIcon *This = ADJUST_THIS(UnixFolderIcon, IExtractIconW, iface); + TRACE("(iface=%p, uFlags=%u, szIconFile=%s, cchMax=%u, piIndex=%p, pwFlags=%p)\n", iface, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags); lstrcpynW(szIconFile, swShell32Name, cchMax); - *piIndex = (uFlags & GIL_OPENICON) ? 4 : 3; + if (This->bFolder) { + *piIndex = (uFlags & GIL_OPENICON) ? -IDI_SHELL_FOLDER_OPEN : -IDI_SHELL_FOLDER; + } else { + *piIndex = -IDI_SHELL_DOCUMENT; + } *pwFlags = 0; return S_OK; @@ -388,7 +478,8 @@ static const IExtractIconWVtbl UnixFolderIcon_IExtractIconW_Vtbl = { /* The singleton instance */ -UnixFolderIcon UnixFolderIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl }; +UnixFolderIcon UnixFolderIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl, TRUE }; +UnixFolderIcon UnixDocumentIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl, FALSE }; /****************************************************************************** * UnixFolder @@ -396,16 +487,6 @@ UnixFolderIcon UnixFolderIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl }; * Class whose heap based instances represent unix filesystem directories. */ -static shvheader GenericSFHeader[] = { - {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, - {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, - {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, - {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12}, - {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5} -}; - -#define GENERICSHELLVIEWCOLUMNS 5 - /* UnixFolder object layout and typedef. */ typedef struct _UnixFolder { @@ -501,7 +582,7 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_ParseDisplayName(IShellFolder2* i return result ? S_OK : E_FAIL; } -static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder); +static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder, SHCONTF fFilter); static HRESULT WINAPI UnixFolder_IShellFolder2_EnumObjects(IShellFolder2* iface, HWND hwndOwner, SHCONTF grfFlags, IEnumIDList** ppEnumIDList) @@ -513,7 +594,7 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_EnumObjects(IShellFolder2* iface, TRACE("(iface=%p, hwndOwner=%p, grfFlags=%08lx, ppEnumIDList=%p)\n", iface, hwndOwner, grfFlags, ppEnumIDList); - newIterator = UnixSubFolderIterator_Construct(This); + newIterator = UnixSubFolderIterator_Construct(This, grfFlags); hr = IUnknown_QueryInterface(newIterator, &IID_IEnumIDList, (void**)ppEnumIDList); IUnknown_Release(newIterator); @@ -571,6 +652,11 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_CompareIDs(IShellFolder2* iface, else if (isEmpty2) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)1); + if (_ILIsFolder(pidl1) && !_ILIsFolder(pidl2)) + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)-1); + if (!_ILIsFolder(pidl1) && _ILIsFolder(pidl2)) + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)1); + compare = CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, _ILGetTextPointer(pidl1), NAME_LEN_FROM_LPSHITEMID(pidl1), _ILGetTextPointer(pidl2), NAME_LEN_FROM_LPSHITEMID(pidl2)); @@ -623,9 +709,19 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_CreateViewObject(IShellFolder2* i static HRESULT WINAPI UnixFolder_IShellFolder2_GetAttributesOf(IShellFolder2* iface, UINT cidl, LPCITEMIDLIST* apidl, SFGAOF* rgfInOut) { + UINT i; + SFGAOF flags= ~(SFGAOF)0; + TRACE("(iface=%p, cidl=%u, apidl=%p, rgfInOut=%p) semi-stub\n", iface, cidl, apidl, rgfInOut); + + for (i=0; itype == PT_FOLDER) flags &= (SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_HASSUBFOLDER); + if (pData->type == PT_VALUE) flags &= SFGAO_FILESYSTEM; + } - *rgfInOut = *rgfInOut & (SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_HASSUBFOLDER); + *rgfInOut = *rgfInOut & flags; return S_OK; } @@ -648,7 +744,11 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_GetUIObjectOf(IShellFolder2* ifac FIXME("IExtractIconA\n"); return E_FAIL; } else if (IsEqualIID(&IID_IExtractIconW, riid)) { - *ppvOut = &UnixFolderIconSingleton; + if (cidl != 1) return E_FAIL; + if (_ILIsFolder(apidl[0])) + *ppvOut = &UnixFolderIconSingleton; + else + *ppvOut = &UnixDocumentIconSingleton; return S_OK; } else if (IsEqualIID(&IID_IDropTarget, riid)) { FIXME("IDropTarget\n"); @@ -760,34 +860,70 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_GetDetailsEx(IShellFolder2* iface return E_NOTIMPL; } +#define SHELLVIEWCOLUMNS 6 + static HRESULT WINAPI UnixFolder_IShellFolder2_GetDetailsOf(IShellFolder2* iface, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) { HRESULT hr = E_FAIL; - + struct passwd *pPasswd; + struct group *pGroup; + static const shvheader SFHeader[SHELLVIEWCOLUMNS] = { + {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, + {IDS_SHV_COLUMN10, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 7}, + {IDS_SHV_COLUMN11, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 7}, + {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 8}, + {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10} + }; + TRACE("(iface=%p, pidl=%p, iColumn=%d, psd=%p) stub\n", iface, pidl, iColumn, psd); - if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS) + if (!psd || iColumn >= SHELLVIEWCOLUMNS) return E_INVALIDARG; if (!pidl) { - psd->fmt = GenericSFHeader[iColumn].fmt; - psd->cxChar = GenericSFHeader[iColumn].cxChar; + psd->fmt = SFHeader[iColumn].fmt; + psd->cxChar = SFHeader[iColumn].cxChar; psd->str.uType = STRRET_CSTR; - LoadStringA(shell32_hInstance, GenericSFHeader[iColumn].colnameid, psd->str.u.cStr, MAX_PATH); + LoadStringA(shell32_hInstance, SFHeader[iColumn].colnameid, psd->str.u.cStr, MAX_PATH); return S_OK; } else { + StatStruct *pStatStruct = LPSTATSTRUCT_FROM_LPSHITEMID(pidl); + psd->str.u.cStr[0] = '\0'; + psd->str.uType = STRRET_CSTR; switch (iColumn) { case 0: hr = IShellFolder2_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL|SHGDN_INFOLDER, &psd->str); break; - case 2: - _ILGetFileType(pidl, psd->str.u.cStr, MAX_PATH); + case 1: + psd->str.u.cStr[0] = S_ISDIR(pStatStruct->st_mode) ? 'd' : '-'; + psd->str.u.cStr[1] = (pStatStruct->st_mode & S_IRUSR) ? 'r' : '-'; + psd->str.u.cStr[2] = (pStatStruct->st_mode & S_IWUSR) ? 'w' : '-'; + psd->str.u.cStr[3] = (pStatStruct->st_mode & S_IXUSR) ? 'x' : '-'; + psd->str.u.cStr[4] = (pStatStruct->st_mode & S_IRGRP) ? 'r' : '-'; + psd->str.u.cStr[5] = (pStatStruct->st_mode & S_IWGRP) ? 'w' : '-'; + psd->str.u.cStr[6] = (pStatStruct->st_mode & S_IXGRP) ? 'x' : '-'; + psd->str.u.cStr[7] = (pStatStruct->st_mode & S_IROTH) ? 'r' : '-'; + psd->str.u.cStr[8] = (pStatStruct->st_mode & S_IWOTH) ? 'w' : '-'; + psd->str.u.cStr[9] = (pStatStruct->st_mode & S_IXOTH) ? 'x' : '-'; + psd->str.u.cStr[10] = '\0'; + break; + case 2: + pPasswd = getpwuid(pStatStruct->st_uid); + if (pPasswd) strcpy(psd->str.u.cStr, pPasswd->pw_name); + break; + case 3: + pGroup = getgrgid(pStatStruct->st_gid); + if (pGroup) strcpy(psd->str.u.cStr, pGroup->gr_name); + break; + case 4: + _ILGetFileSize(pidl, psd->str.u.cStr, MAX_PATH); + break; + case 5: + _ILGetFileDate(pidl, psd->str.u.cStr, MAX_PATH); break; - default: - psd->str.u.cStr[0] = '\0'; } - psd->str.uType = STRRET_CSTR; } return hr; @@ -920,6 +1056,7 @@ typedef struct _UnixSubFolderIterator { ULONG m_cRef; UnixFolder *m_pUnixFolder; ULONG m_cIdx; + SHCONTF m_fFilter; } UnixSubFolderIterator; static void UnixSubFolderIterator_Destroy(UnixSubFolderIterator *iterator) { @@ -979,8 +1116,12 @@ static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Next(IEnumIDList* iface, TRACE("(iface=%p, celt=%ld, rgelt=%p, pceltFetched=%p)\n", iface, celt, rgelt, pceltFetched); - for (i=0; (i < celt) && (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs); i++, This->m_cIdx++) { - rgelt[i] = ILClone(This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx]); + for (i=0; (i < celt) && (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs); This->m_cIdx++) { + LPITEMIDLIST pCurrent = This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx]; + if (UNIXFS_is_pidl_of_type(pCurrent, This->m_fFilter)) { + rgelt[i] = ILClone(pCurrent); + i++; + } } if (pceltFetched) @@ -992,14 +1133,23 @@ static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Next(IEnumIDList* iface, static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Skip(IEnumIDList* iface, ULONG celt) { UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface); + ULONG i; TRACE("(iface=%p, celt=%ld)\n", iface, celt); - if (This->m_cIdx + celt > This->m_pUnixFolder->m_cSubDirs) { + for (i=0; i < celt; i++) { + while (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs && + !UNIXFS_is_pidl_of_type(This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx], This->m_fFilter)) + { + This->m_cIdx++; + } + This->m_cIdx++; + } + + if (This->m_cIdx > This->m_pUnixFolder->m_cSubDirs) { This->m_cIdx = This->m_pUnixFolder->m_cSubDirs; return S_FALSE; } else { - This->m_cIdx += celt; return S_OK; } } @@ -1034,7 +1184,7 @@ static const IEnumIDListVtbl UnixSubFolderIterator_IEnumIDList_Vtbl = { UnixSubFolderIterator_IEnumIDList_Clone }; -static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder) { +static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder, SHCONTF fFilter) { UnixSubFolderIterator *iterator; TRACE("(pUnixFolder=%p)\n", pUnixFolder); @@ -1044,6 +1194,7 @@ static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder) { iterator->m_cRef = 0; iterator->m_cIdx = 0; iterator->m_pUnixFolder = pUnixFolder; + iterator->m_fFilter = fFilter; UnixSubFolderIterator_IEnumIDList_AddRef((IEnumIDList*)iterator); UnixFolder_IShellFolder2_AddRef((IShellFolder2*)pUnixFolder); diff --git a/dlls/shell32/shresdef.h b/dlls/shell32/shresdef.h index 061ce697725..2461c0f4236 100644 --- a/dlls/shell32/shresdef.h +++ b/dlls/shell32/shresdef.h @@ -31,6 +31,8 @@ #define IDS_SHV_COLUMN7 13 #define IDS_SHV_COLUMN8 14 #define IDS_SHV_COLUMN9 15 +#define IDS_SHV_COLUMN10 16 +#define IDS_SHV_COLUMN11 17 #define IDS_DESKTOP 20 #define IDS_MYCOMPUTER 21