Hi all,
please find attached my current work on this topic. It takes another approach
as Michael Lin's patches and in particular doesn't add any API.
I've already send the smaller of the two patches to wine-patches, so it may
well be that this one is already applied when you try the patches.
The general idea is as follows: If wine is not configured to show the unix
namespace in file dialogs, it behaves just as it does now. Otherwise, The
MyComputer shell folder does not display the FS shell folders (A:, B:, ..),
but the UnixFS shell folder (/) instead. Path names are converted from DOS to
Unix and back in MyComputer (the unix root '/' has to be accessible by some
DOS drive). This means that paths, which go in and out of the file open and
save dialog APIs, are always DOS paths.
My patches are not ready yet for several reasons:
1.) I'm still patching SHGetPathFromIDList, which we probably shouldn't.
There's an article "How To Support Common Dialog Browsing in a Shell
Namespace Extension" on MSDN
(http://support.microsoft.com/default.aspx?scid=kb;en-us;216954), which
basically states that starting from Win2K the file dialogs do no longer use
the SHGetPathFromIDList API, but call ShellFolder::GetDisplayName instead. So
that's probably the way to go.
2.) It's still an open question how this should be configured in wine. In the
current version, I've added a global "ShowUnixFilesystem" key to the config
file (type is REG_SZ, define to "1" to display the unix namespace).
3.) I'm thinking about moving the unix<->dos conversion stuff into the
namespace extension (from MyComputer). So if the unix filesystem namespace
extension would be given a dos path to ParseDisplayName, we would convert to
unix and set a flag in the SHITEMIDs which tells us to convert back to dos in
GetDisplayName: Unix paths in, unix paths out. Dos paths in, dos paths out.
WineLib applications, which would like to call the posix file APIs can simply
call wine_get_unix_path_name on the path provided by the file dialogs.
I tested the current version with regedit, notepad and virtualdub. Seems to
work fine. But I don't feel it's clean enough yet to be included in cvs.
Let me know what you think about it.
Bye,
Index: dlls/shell32/pidl.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/pidl.c,v
retrieving revision 1.130
diff -u -p -r1.130 pidl.c
--- dlls/shell32/pidl.c 10 May 2005 08:27:23 -0000 1.130
+++ dlls/shell32/pidl.c 13 May 2005 07:44:35 -0000
@@ -1328,8 +1328,32 @@ HRESULT SHELL_GetPathFromIDListW(LPCITEM
HRESULT hr = S_OK;
UINT len;
+ IShellFolder *pDesktop;
+ STRRET strPath;
+ WCHAR *pwszPath;
+
pszPath[0]=0;
+
+ /* Push the pidl to path conversion logic into shellfolder */
+ hr = SHGetDesktopFolder(&pDesktop);
+ if (!SUCCEEDED(hr)) return hr;
+ hr = IShellFolder_GetDisplayNameOf(pDesktop, pidl, SHGDN_FORPARSING, &strPath);
+ IShellFolder_Release(pDesktop);
+ if (!SUCCEEDED(hr)) return hr;
+ hr = StrRetToStrW(&strPath, pidl, &pwszPath);
+ if (!SUCCEEDED(hr)) return hr;
+ if (lstrlenW(pwszPath)+1 > uOutSize) {
+ CoTaskMemFree(pszPath);
+ return E_INVALIDARG;
+ }
+ lstrcpyW(pszPath, pwszPath);
+ CoTaskMemFree(pszPath);
+ return S_OK;
+#if 0
+
+ pszPath[0]=0;
+
/* One case is a PIDL rooted at desktop level */
if (_ILIsDesktop(pidl) ||_ILIsValue(pidl) || _ILIsFolder(pidl))
{
@@ -1401,6 +1425,7 @@ HRESULT SHELL_GetPathFromIDListW(LPCITEM
TRACE_(shell)("-- %s, 0x%08lx\n", debugstr_w(pszPath), hr);
return hr;
+#endif
}
/*************************************************************************
Index: dlls/shell32/shfldr_mycomp.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shfldr_mycomp.c,v
retrieving revision 1.36
diff -u -p -r1.36 shfldr_mycomp.c
--- dlls/shell32/shfldr_mycomp.c 10 May 2005 08:28:11 -0000 1.36
+++ dlls/shell32/shfldr_mycomp.c 13 May 2005 07:44:35 -0000
@@ -50,6 +50,32 @@
WINE_DEFAULT_DEBUG_CHANNEL (shell);
+static int show_unix_filesystem() {
+ static int option_show_unix_filesystem = -1;
+
+ if (option_show_unix_filesystem == -1) {
+ static const WCHAR wszWineConfigKeyW[] = {
+ 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
+ 'W','i','n','e','\\','C','o','n','f','i','g','\\','W','i','n','e',0 };
+ static const WCHAR wszShowUnixFilesystemValueW[] = {
+ 'S','h','o','w','U','n','i','x','F','i','l','e','s','y','s','t','e','m',0 };
+ HKEY hConfigKey;
+ LONG result;
+ DWORD dwValueType, dwLen = 2 * sizeof(WCHAR);
+ WCHAR wszValueW[2];
+
+ option_show_unix_filesystem = 0;
+ result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszWineConfigKeyW, 0, KEY_READ, &hConfigKey);
+ if (result != ERROR_SUCCESS) return option_show_unix_filesystem;
+ result = RegQueryValueExW(hConfigKey, wszShowUnixFilesystemValueW, 0, &dwValueType,
+ (LPBYTE)wszValueW, &dwLen);
+ if (result == ERROR_SUCCESS && dwValueType == REG_SZ && dwLen >= 2 && wszValueW[0] == '1')
+ option_show_unix_filesystem = 1;
+ RegCloseKey(hConfigKey);
+ }
+ return option_show_unix_filesystem;
+}
+
/***********************************************************************
* IShellFolder implementation
*/
@@ -225,10 +251,31 @@ static HRESULT WINAPI ISF_MyComputer_fnP
else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
lpszDisplayName[2] == (WCHAR) '\\')
{
- szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
- /* make drive letter uppercase to enable PIDL comparison */
- szElement[0] = toupper(szElement[0]);
- pidlTemp = _ILCreateDrive (szElement);
+ if (show_unix_filesystem()) {
+ WCHAR wszDrive[] = { 'A', ':', '\\', 0 };
+ char *pszDriveSymlink, szUnixFileName[MAX_PATH];
+ int cLen;
+
+ wszDrive[0] = lpszDisplayName[0];
+ pszDriveSymlink = wine_get_unix_file_name(wszDrive);
+ cLen = strlen(pszDriveSymlink);
+ if (pszDriveSymlink[cLen-1]=='/') pszDriveSymlink[cLen-1]='\0';
+ cLen = readlink(pszDriveSymlink, szUnixFileName, MAX_PATH);
+ if (cLen < 0) {
+ ERR("%s readlink failed!\n", pszDriveSymlink);
+ return E_FAIL;
+ }
+ MultiByteToWideChar(CP_ACP, 0, szUnixFileName, cLen, szElement, MAX_PATH);
+ lstrcpynW(szElement+cLen, lpszDisplayName+2, MAX_PATH-cLen);
+ szNext = szElement;
+ pidlTemp = _ILCreateGuid(PT_GUID, &CLSID_UnixFolder);
+
+ } else {
+ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
+ /* make drive letter uppercase to enable PIDL comparison */
+ szElement[0] = toupper(szElement[0]);
+ pidlTemp = _ILCreateDrive (szElement);
+ }
}
if (szNext && *szNext)
@@ -269,17 +316,22 @@ static BOOL CreateMyCompEnumList(IEnumID
/* enumerate the folders */
if (dwFlags & SHCONTF_FOLDERS)
{
- WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
- DWORD dwDrivemap = GetLogicalDrives();
HKEY hkey;
- while (ret && wszDriveName[0]<='Z')
- {
- if(dwDrivemap & 0x00000001L)
- ret = AddToEnumList(list, _ILCreateDrive(wszDriveName));
- wszDriveName[0]++;
- dwDrivemap = dwDrivemap >> 1;
- }
+ if (show_unix_filesystem()) {
+ ret = AddToEnumList(list, _ILCreateGuid(PT_GUID, &CLSID_UnixFolder));
+ } else {
+ WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
+ DWORD dwDrivemap = GetLogicalDrives();
+
+ while (ret && wszDriveName[0]<='Z')
+ {
+ if(dwDrivemap & 0x00000001L)
+ ret = AddToEnumList(list, _ILCreateDrive(wszDriveName));
+ wszDriveName[0]++;
+ dwDrivemap = dwDrivemap >> 1;
+ }
+ }
TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",list);
if (ret && !RegOpenKeyExW(HKEY_LOCAL_MACHINE, MyComputer_NameSpaceW,
@@ -670,7 +722,10 @@ static HRESULT WINAPI ISF_MyComputer_fnG
if (SUCCEEDED (hr))
{
strRet->uType = STRRET_CSTR;
- lstrcpynA (strRet->u.cStr, szPath, MAX_PATH);
+ if (show_unix_filesystem() && szPath[0]=='/' && GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING)
+ GetFullPathNameA(szPath, MAX_PATH, strRet->u.cStr, NULL);
+ else
+ lstrcpynA (strRet->u.cStr, szPath, MAX_PATH);
}
TRACE ("-- (%p)->(%s)\n", This, szPath);
Index: dlls/shell32/shfldr_unixfs.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shfldr_unixfs.c,v
retrieving revision 1.13
diff -u -p -r1.13 shfldr_unixfs.c
--- dlls/shell32/shfldr_unixfs.c 12 May 2005 09:56:04 -0000 1.13
+++ dlls/shell32/shfldr_unixfs.c 12 May 2005 11:29:42 -0000
@@ -567,7 +567,7 @@ static HRESULT WINAPI UnixFolder_IShellF
{
UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
int cPathLen;
- char *pszAnsiPath;
+ char *pszAnsiPath, *pBackslash;
BOOL result;
TRACE("(iface=%p, hwndOwner=%p, pbcReserved=%p, lpszDisplayName=%s, pchEaten=%p, ppidl=%p, "
@@ -578,18 +578,21 @@ static HRESULT WINAPI UnixFolder_IShellF
pszAnsiPath = (char*)SHAlloc(cPathLen+1);
WideCharToMultiByte(CP_ACP, 0, lpszDisplayName, -1, pszAnsiPath, cPathLen+1, NULL, NULL);
+ for (pBackslash = strchr(pszAnsiPath, '\\'); pBackslash; pBackslash = strchr(pBackslash, '\\'))
+ *pBackslash = '/';
+
result = UNIXFS_path_to_pidl(This->m_pszPath, pszAnsiPath, ppidl);
- if (result && pdwAttributes)
+ 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);
+ /* 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);
}
SHFree(pszAnsiPath);