Hi Michael,
--- Michael Lin mlin@corvu.com.au wrote:
If your target platform is windows, don't define the WINE_UNIX_PATHS flag when you compile and it will all behave the same as before. It's only when you define WINE_UNIX_PATHS flag that GetOpenFileNameW() will be mapped to UnixFSGetOpenFileNameW() for example. Else it will call the same function as before and shouldn't break on Windows. WINE_UNIX_PATHS is currently not defined anywhere in WINE, so no one should see any difference. To see the change, you have to define that flag in your winelib application's makefile.
But your defining UnixFSGetOpenFileNameW in the spec file so the import library will still have that function listed so if I link a dll to that import library its going to fail on Windows even if I am not calling that function. The Windows Linker/Loader is not forgiving like the Unix loader if the symbol is not found in the import table. It seems like Winebuild will need some magic as well if you don't want these function exported all the time.
Thanks Steven
Discover Yahoo! Have fun online with music videos, cool games, IM and more. Check it out! http://discover.yahoo.com/online.html
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,
Hi Michael,
Our work on this topic basically have the same goal but slightly different approach. We both want to extend the file dialog to include unix file path without changing the current behaviour for current user if they don't want unix file path. I believe our patchs should be merged to provide a common solution.
There are only 2 differences in our approach. The major differences being how the modified behaviour should be activated. You chose registry setting while I chose compiler flag. The 2nd difference being converting unix path back to dos path.
As discussed before, I think there are 3 solutions to ask the file dialog to display unix paths.
First solution is use a flag in the registry. I did not implement this approach because it is a global setting. This setting will be for all native Windows application running on Wine as well as all winelib applications. Most likely, windows application running on wine will want to see dos paths such as c:\my document etc. I thought about providing functions that add/remove registry key and let winelib application add the registry key as it starts up and remove it as the application shuts down. But this still won't handle the case when winelib application crash. Also you will run into problem when you want to run Windows application on wine that want dos paths and running a winelib application that wants unix paths at the same time.
Second solution as I suggested before is to pass in an extension flag as an argument. For example, add OFN_UNIX_PATHS to Flags member of OPENFILENAME struct to pass into GetOpenFileName(). This approach is reasonably clean, however we will run into problems if Microsoft extends their flags to have the same value.
The last solution is what Troy Rollo suggested. A separate entry point with compiler flags. I Chose this approach as most likely only winelib application will benefit from true unix file path and it doesn't seens to have any other problems.
As with what path file dialog should return, well .. if you compile with a compiler flag wanting a unix file dialog .. it should return unix paths.
We should expose conversion of unix to dos utility functions for easy conversion.
As for just showing UnixFS shell folder and not showing c and d drive etc .. I agree. I just haven't get there yet.
Michael Lin
Michael Jung wrote:
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);
On Thu, 12 May 2005, Steven Edwards wrote: [...]
But your defining UnixFSGetOpenFileNameW in the spec file so the import library will still have that function listed so if I link a dll to that import library its going to fail on Windows even if I am not calling that function.
No, that should not happen. If an application links with a library that exports funcA() and funcB() but it only calls funcA(), then it will only import funcA() and it will work on a system where that library only exports funcA().
We use this in many conformance tests: the test links normally with the dll and calls the functions that are found on all platforms directly. However for the APIs found on only some platforms it uses GetProcAddress() so the test will not import those. And even if the test is compiled on a platform where the dll has all the APIs, it still works on platforms where the dll is missing some of them because it does not import those APIs.