Hi Michael,
On Friday 27 May 2005 03:03, Michael Lin wrote:
Just a few things with this approach. As I mentioned before .. with a global flag in the registry. User can't run a winelib application with unix path and a Windows application on Wine with dos path at the same time.
Please consider the configure based global flag only an option. That's actually what I said several times. It could be a per application option as well. And there is no problem in activating it via a wine-specific API, which would override the config on a per process basis.
Ok ... I know your approach is base everything on dos path and the global flag is simply a display mode. But what about the parsing of the file name editbox in the file dialog? The user is browsing unix file system, but does the user enter unix or dos path? I believe I can modify your solution to accept unix file path, but it have to accept dos path as well.
Modifying shfldr_unixfs to parse unix path in addition to dos paths is trivial: Just remove the (pUnixFolder->m_dwPathMode == PATHMODE_UNIX) test in line 339. The real problem is the test for invalid chars in the filedialog, which '/' is one of. The solution is obvious: If wine is configured to display unix paths, then accept '/' as a valid char in paths in comdlg32. You will have to do this for your solution as well, don't you?
Then there is also the issue of having to have the unix root mapped to a dos drive.
That's true.
Actually, we are tackling two slightly different problems here: I would like to have existend applications, for which I don't have the source, to display unix paths instead of dos paths in their file dialogs. So I want MS Office to display unix paths in it's file dialogs. IMHO there is not way to achieve this without the requirement to map one of the dos drives to '/'. At least not if the user should be able to access every file on his filesystem.
This solution can also be applied to winelib applications. If you want to use the native posix file functions (which, frankly, I don't see a reason to do, because the user doesn't care how filenames look in the core dump, but only how they look on the screen) then just map the paths coming out of the file dialog to unix with the wine_nt_to_unix_path function.
I do understand that there are some shortcomings of this approach for winelib applications, which can not possibly be addressed this way. But it seems equaly obvious to me that your approach can never achieve the goal I laid out above (To make native apps display the unix paths in file dialogs).
So perhaps there might be demand for both solutions. Or perhaps I'm totaly off the point and the only person on the planet who likes to see unix paths in his native windows applications on wine. Which would mean your solution might be the only one people are interested in.
What I meant to say is, please fell free to implement your solution the way you like it and let the wine community decide on it. But please don't modify shfldr_unixfs in a way that breaks my solution (Conceptually, that is. Bugs, of course, are unavoidable.)
Troy, Alexandre and I have been discussing other possible solutions to this problem offline.
I don't want to offend, but I think this just isn't fair. I have contributed a lot of my free time working on this stuff, and I think I would have deserved to be informed on discussions and decisions in this matter. Above that, this kind of discussion should take place on wine-devel, so that the community at large can take part in it. To me this gives the impression that you avoided discussing it on wine-devel, because you didn't want to be convinced. Sorry.
Ok, nuff said, going back to the technological stuff.
One solution I have implemented and waiting on Alexandre's verdict is the following.
Create a new library called wineunixfs. All additional entry point should be in that library. All exported function call should be of the same signiture as one in the core library such as GetOpenFileNameA(), GetOpenFileNameW() etc. To use the library, simply let winelib application link it before all the other core libraries.
My Changes to the core libraries are contained within shell32. There is only one extra exported functions SHUnixFSGetDesktopFolder() being added. This function return the desktop folder in unix mode.
Currenlt wineunixfs duplicates filedlg.c, filedlgbrowser.* and their dependent files from commdlg. I have attached the diff file for the rest of the changes that's on the core libraries.
I'm not the one to judge, but in my opinion this is pretty heavy weight.
Ciao,
Hi Michael,
Please consider the configure based global flag only an option. That's actually what I said several times. It could be a per application option as well. And there is no problem in activating it via a wine-specific API, which would override the config on a per process basis.
Please explain on the per process basis. If you mean let winelib application change the global flags via wine API, there will be synchronization and threading issues. Say application A turn on unix path, application B turn on unix path, application B exit and turn off unix path, then application A will now be back in dos path. Or do you mean each application would have their own registry setting and this per application setting is set when application is installed? Then there is problem of how wine get to this application specific settings.
Modifying shfldr_unixfs to parse unix path in addition to dos paths is trivial: Just remove the (pUnixFolder->m_dwPathMode == PATHMODE_UNIX) test in line 339. The real problem is the test for invalid chars in the filedialog, which '/' is one of. The solution is obvious: If wine is configured to display unix paths, then accept '/' as a valid char in paths in comdlg32. You will have to do this for your solution as well, don't you?
What I mean here is when user is browsing unix path and be able to type in dos path seems a bit strange. Just the little things that doesn't make it feel really in unix mode for winlib app.
Actually, we are tackling two slightly different problems here: I would like to have existend applications, for which I don't have the source, to display unix paths instead of dos paths in their file dialogs.
Oh .. ok .. I didn't know that.
I don't want to offend, but I think this just isn't fair. I have contributed a lot of my free time working on this stuff, and I think I would have deserved to be informed on discussions and decisions in this matter.
Sorry if I offended you, that wasn't my intention. Initially it was just a direct email sent to Alexandre to ask the status of the patch I previously sent. If it has been rejected, I would like to know the reason so I can make changes and send in another patch. Should have cc wine-devel, my apologies.
On Monday 30 May 2005 02:12, you wrote:
Please explain on the per process basis. If you mean let winelib application change the global flags via wine API, there will be synchronization and threading issues. Say application A turn on unix path, application B turn on unix path, application B exit and turn off unix path, then application A will now be back in dos path. Or do you mean each application would have their own registry setting and this per application setting is set when application is installed? Then there is problem of how wine get to this application specific settings.
The ShowUnixFilesystem option in the registry could be global or application specific. In the current patch it's global. But it could be something like
[AppDefaults\winword.exe\shell32] "ShowUnixFilesystem" = "1"
which would turn it on only for winword (This syntax is common in wine's config file).
Back to the winelib case. Suppose the user did choose not to display the unix filesystem at all. We could implement an API, say show_unix_filesystem(BOOL on), which would turn the feature on for the current process, no matter what the user chose in the registry. (By setting the option_show_unix_filesystem variable, which currently is in scope only in the show_unix_filesystem function, but valid process-wide).
What I mean here is when user is browsing unix path and be able to type in dos path seems a bit strange. Just the little things that doesn't make it feel really in unix mode for winlib app.
You mean like the user types in "Z:\home\mjung" and thinks: "Gosh, this should work only for unix paths. What did those crazy wine hackers think?". In my opinion, this is really a no-problem. The user should be able to enter unix paths, that's for sure (it doesn't work currently, though, but should be relatively easy to fix). But the possibility that the user enters a dos path by accident and then wonders why this works is pretty low, I think.
Sorry if I offended you, that wasn't my intention. Initially it was just a direct email sent to Alexandre to ask the status of the patch I previously sent. If it has been rejected, I would like to know the reason so I can make changes and send in another patch. Should have cc wine-devel, my apologies.
Never mind. In your last mail you said that you already implemented "rename" and "new folder" functionality. Are those restricted to shfldr_unixfs? Do you think those could be sent as a separate patch already? That would be sweet.
Bye,
Hi Michael,
Never mind. In your last mail you said that you already implemented "rename" and "new folder" functionality. Are those restricted to shfldr_unixfs? Do you think those could be sent as a separate patch already? That would be sweet.
Here it is, I have cleaned it up so it is only restricted to shfldr_unixfs. I think this should work on your build, it might need other bits on my build. See if it works on your build.
One note, rename currently doesn't check for existing file/folder with same name. Haven't got a chance to fix that yet. Feel free to make any changes. I won't be working on this for a while.
Michael
Index: dlls/shell32/shfldr_unixfs.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/shfldr_unixfs.c,v retrieving revision 1.16 diff -u -r1.16 shfldr_unixfs.c --- dlls/shell32/shfldr_unixfs.c 24 May 2005 11:45:47 -0000 1.16 +++ dlls/shell32/shfldr_unixfs.c 1 Jun 2005 02:08:31 -0000 @@ -47,6 +47,7 @@
#include "shell32_main.h" #include "shfldr.h" +#include "shellfolder.h" #include "shresdef.h" #include "pidl.h"
@@ -88,6 +89,7 @@ typedef struct _UnixFolder { const IShellFolder2Vtbl *lpIShellFolder2Vtbl; const IPersistFolder2Vtbl *lpIPersistFolder2Vtbl; + const ISFHelperVtbl *lpISFHelperVtbl; ULONG m_cRef; CHAR *m_pszPath; LPITEMIDLIST m_pidlLocation; @@ -96,6 +98,10 @@ DWORD m_dwPathMode; } UnixFolder;
+static const IShellFolder2Vtbl UnixFolder_IShellFolder2_Vtbl; +static const IPersistFolder2Vtbl UnixFolder_IPersistFolder2_Vtbl; +static const ISFHelperVtbl shvt; + /****************************************************************************** * UNIXFS_is_pidl_of_type [INTERNAL] * @@ -692,6 +698,9 @@ IsEqualIID(&IID_IPersist, riid)) { *ppv = &This->lpIPersistFolder2Vtbl; + } else if (IsEqualIID(&IID_ISFHelper, riid)) + { + *ppv = &This->lpISFHelperVtbl; } else { *ppv = NULL; return E_NOINTERFACE; @@ -738,14 +747,7 @@ if (result && pdwAttributes && *pdwAttributes) { /* need to traverse to the last element for the attribute */ - LPCITEMIDLIST pidl, last_pidl; - pidl = last_pidl = *ppidl; - while(pidl && pidl->mkid.cb) - { - last_pidl = pidl; - pidl = ILGetNext(pidl); - } - SHELL32_GetItemAttributes((IShellFolder*)iface, last_pidl, pdwAttributes); + SHELL32_GetItemAttributes((IShellFolder*)iface, ILFindLastID(*ppidl), pdwAttributes); }
if (!result) TRACE("FAILED!\n"); @@ -830,11 +832,9 @@ 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)); - if ((compare == CSTR_LESS_THAN) || (compare == CSTR_GREATER_THAN)) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD)((compare == CSTR_LESS_THAN)?-1:1));
@@ -891,8 +891,8 @@ for (i=0; i<cidl; i++) { LPPIDLDATA pData = _ILGetDataPointer(apidl[i]); if (!pData) continue; - if (pData->type == PT_FOLDER) flags &= (SFGAO_FILESYSTEM|SFGAO_FILESYSANCESTOR|SFGAO_FOLDER|SFGAO_HASSUBFOLDER); - if (pData->type == PT_VALUE) flags &= SFGAO_FILESYSTEM; + if (pData->type == PT_FOLDER) flags &= (SFGAO_FILESYSTEM|SFGAO_FILESYSANCESTOR|SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_CANRENAME); + if (pData->type == PT_VALUE) flags &= SFGAO_FILESYSTEM|SFGAO_CANRENAME; }
*rgfInOut = *rgfInOut & flags; @@ -979,11 +979,50 @@ return hr; }
-static HRESULT WINAPI UnixFolder_IShellFolder2_SetNameOf(IShellFolder2* This, HWND hwnd, +static HRESULT WINAPI UnixFolder_IShellFolder2_SetNameOf(IShellFolder2* iface, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, SHGDNF uFlags, LPITEMIDLIST* ppidlOut) { - TRACE("stub\n"); - return E_NOTIMPL; + UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface); + char szSrc[MAX_PATH], szDest[MAX_PATH], temp[MAX_PATH]; + char* ptr; + BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl)); + TRACE ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", iface, hwnd, pidl, + debugstr_w (lpszName), uFlags, ppidlOut); + + /* build source path */ + strcpy(szSrc, This->m_pszPath); + ptr = szSrc + lstrlenA(szSrc); + if (ptr) + _ILSimpleGetText(pidl, ptr, MAX_PATH - (ptr - szSrc)); + + WideCharToMultiByte(CP_ACP, 0, lpszName, -1, temp, MAX_PATH, NULL, NULL); + /* build destination path */ + if (uFlags == SHGDN_NORMAL || uFlags & SHGDN_INFOLDER) { + strcpy(szDest, This->m_pszPath); + ptr = szDest + lstrlenA(szDest); + if (ptr) + lstrcpynA(ptr, temp, MAX_PATH - (ptr - szDest)); + } else + lstrcpynA(szDest, temp, MAX_PATH); + + TRACE("src=%s dest=%s\n", szSrc, szDest); + + if (!rename(szSrc, szDest)) { + LPITEMIDLIST src_pidl = 0, dest_pidl = 0, new_name_pidl = 0; + HRESULT hr = S_OK; + hr = UNIXFS_path_to_pidl(This, lpszName, &new_name_pidl); + + src_pidl = ILCombine(This->m_pidlLocation, pidl); + dest_pidl = ILCombine(This->m_pidlLocation, new_name_pidl); + if (ppidlOut) + { + *ppidlOut = ILClone(ILFindLastID(dest_pidl)); + } + SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, + SHCNF_IDLIST, src_pidl, ILClone(dest_pidl)); + return hr; + } + return E_FAIL; }
static HRESULT WINAPI UnixFolder_IShellFolder2_EnumSearches(IShellFolder2* iface, @@ -1209,6 +1248,7 @@ if(pUnixFolder) { pUnixFolder->lpIShellFolder2Vtbl = &UnixFolder_IShellFolder2_Vtbl; pUnixFolder->lpIPersistFolder2Vtbl = &UnixFolder_IPersistFolder2_Vtbl; + pUnixFolder->lpISFHelperVtbl = &shvt; pUnixFolder->m_cRef = 0; pUnixFolder->m_pszPath = NULL; pUnixFolder->m_apidlSubDirs = NULL; @@ -1391,3 +1431,127 @@
return (IUnknown*)iterator; } + +static HRESULT WINAPI ISFHelper_fnQueryInterface (ISFHelper* iface, REFIID riid, void** ppvObject) +{ + return UnixFolder_IShellFolder2_QueryInterface( + (IShellFolder2*)ADJUST_THIS(UnixFolder, ISFHelper, iface), riid, ppvObject); +} + +static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface) +{ + return UnixFolder_IShellFolder2_AddRef( + (IShellFolder2*)ADJUST_THIS(UnixFolder, ISFHelper, iface)); +} + +static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface) +{ + return UnixFolder_IShellFolder2_Release( + (IShellFolder2*)ADJUST_THIS(UnixFolder, ISFHelper, iface)); +} + +static HRESULT WINAPI ISFHelper_fnGetUniqueName (ISFHelper * iface, LPSTR lpName, UINT uLen) +{ + IShellFolder2 *isf = (IShellFolder2*)ADJUST_THIS(UnixFolder, ISFHelper, iface); + IEnumIDList *penum; + HRESULT hr; + char szText[MAX_PATH]; + char *szNewFolder = "NewFolder"; + + if (uLen < strlen (szNewFolder) + 4) + return E_POINTER; + + strcpy (lpName, szNewFolder); + + hr = UnixFolder_IShellFolder2_EnumObjects (isf, 0, + SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum); + if (penum) { + LPITEMIDLIST pidl; + DWORD dwFetched; + int i = 1; + +next: + IEnumIDList_Reset (penum); + while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) && + dwFetched) { + _ILSimpleGetText (pidl, szText, MAX_PATH); + if (0 == strcasecmp (szText, lpName)) { + sprintf (lpName, "%s %d", szNewFolder, i++); + if (i > 99) { + hr = E_FAIL; + break; + } + goto next; + } + } + + IEnumIDList_Release (penum); + } + return hr; +} + +static HRESULT WINAPI ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCSTR lpName, + LPITEMIDLIST * ppidlOut) +{ + UnixFolder *This = ADJUST_THIS(UnixFolder, ISFHelper, iface); + char lpstrNewDir[MAX_PATH]; + DWORD bRes; + HRESULT hres = E_FAIL; + + TRACE ("(%p)(%s %p)\n", This, lpName, ppidlOut); + strcpy (lpstrNewDir, This->m_pszPath); + strcat(lpstrNewDir, lpName); + bRes = mkdir (lpstrNewDir, 755); + if (!bRes) { + LPITEMIDLIST pidl = 0, full_pidl = 0; + WCHAR nameW[MAX_PATH]; + if (!MultiByteToWideChar(CP_ACP, 0, lpName, -1, nameW, MAX_PATH)) + nameW[MAX_PATH-1] = 0; + hres = UNIXFS_path_to_pidl(This, nameW, &pidl); + + if (ppidlOut) + { + *ppidlOut = pidl; + } + full_pidl = ILCombine(This->m_pidlLocation, pidl); + SHChangeNotify (SHCNE_MKDIR, SHCNF_IDLIST, full_pidl, NULL); + SHFree(full_pidl); + } else { + char lpstrText[128 + MAX_PATH]; + char lpstrTempText[128]; + char lpstrCaption[256]; + + /* Cannot Create folder because of permissions */ + LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_DENIED, lpstrTempText, + sizeof (lpstrTempText)); + LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, lpstrCaption, + sizeof (lpstrCaption)); + sprintf (lpstrText, lpstrTempText, lpstrNewDir); + MessageBoxA (hwnd, lpstrText, lpstrCaption, MB_OK | MB_ICONEXCLAMATION); + } + return hres; +} + +static HRESULT WINAPI ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl) +{ + TRACE("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl, + LPCITEMIDLIST * apidl) +{ + TRACE("stub\n"); + return E_NOTIMPL; +} + +static const ISFHelperVtbl shvt = +{ + ISFHelper_fnQueryInterface, + ISFHelper_fnAddRef, + ISFHelper_fnRelease, + ISFHelper_fnGetUniqueName, + ISFHelper_fnAddFolder, + ISFHelper_fnDeleteItems, + ISFHelper_fnCopyItems +};