Author: akhaldi Date: Thu Apr 24 16:07:14 2014 New Revision: 62955
URL: http://svn.reactos.org/svn/reactos?rev=62955&view=rev Log: [SHLWAPI] * Sync with Wine 1.7.17. CORE-8080
Modified: trunk/reactos/dll/win32/shlwapi/istream.c trunk/reactos/dll/win32/shlwapi/ordinal.c trunk/reactos/dll/win32/shlwapi/path.c trunk/reactos/dll/win32/shlwapi/shlwapi.spec trunk/reactos/dll/win32/shlwapi/string.c trunk/reactos/dll/win32/shlwapi/url.c trunk/reactos/dll/win32/shlwapi/wsprintf.c trunk/reactos/media/doc/README.WINE
Modified: trunk/reactos/dll/win32/shlwapi/istream.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/istream.c... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/istream.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/istream.c [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -58,8 +58,8 @@ if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IStream)) { - *ppvObj = This; IStream_AddRef(iface); + *ppvObj = iface; return S_OK; } return E_NOINTERFACE; @@ -216,22 +216,22 @@ ulSize = cb.QuadPart; while (ulSize) { - ULONG ulLeft, ulAmt; + ULONG ulLeft, ulRead, ulWritten;
ulLeft = ulSize > sizeof(copyBuff) ? sizeof(copyBuff) : ulSize;
/* Read */ - hRet = IStream_fnRead(iface, copyBuff, ulLeft, &ulAmt); + hRet = IStream_fnRead(iface, copyBuff, ulLeft, &ulRead); + if (FAILED(hRet) || ulRead == 0) + break; if (pcbRead) - pcbRead->QuadPart += ulAmt; - if (FAILED(hRet) || ulAmt != ulLeft) - break; + pcbRead->QuadPart += ulRead;
/* Write */ - hRet = IStream_fnWrite(pstm, copyBuff, ulLeft, &ulAmt); + hRet = IStream_fnWrite(pstm, copyBuff, ulRead, &ulWritten); if (pcbWritten) - pcbWritten->QuadPart += ulAmt; - if (FAILED(hRet) || ulAmt != ulLeft) + pcbWritten->QuadPart += ulWritten; + if (FAILED(hRet) || ulWritten != ulLeft) break;
ulSize -= ulLeft; @@ -279,16 +279,14 @@ static HRESULT WINAPI IStream_fnStat(IStream *iface, STATSTG* lpStat, DWORD grfStatFlag) { - ISHFileStream *This = impl_from_IStream(iface); - BY_HANDLE_FILE_INFORMATION fi; - HRESULT hRet = S_OK; - - TRACE("(%p,%p,%d)\n", This, lpStat, grfStatFlag); - - if (!grfStatFlag) - hRet = STG_E_INVALIDPOINTER; - else - { + ISHFileStream *This = impl_from_IStream(iface); + BY_HANDLE_FILE_INFORMATION fi; + + TRACE("(%p,%p,%d)\n", This, lpStat, grfStatFlag); + + if (!grfStatFlag) + return STG_E_INVALIDPOINTER; + memset(&fi, 0, sizeof(fi)); GetFileInformationByHandle(This->hFile, &fi);
@@ -307,8 +305,8 @@ memcpy(&lpStat->clsid, &IID_IStream, sizeof(CLSID)); lpStat->grfStateBits = This->grfStateBits; lpStat->reserved = 0; - } - return hRet; + + return S_OK; }
/************************************************************************* @@ -349,22 +347,21 @@ */ static IStream *IStream_Create(LPCWSTR lpszPath, HANDLE hFile, DWORD dwMode) { - ISHFileStream* fileStream; - - fileStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHFileStream)); - - if (fileStream) - { - fileStream->IStream_iface.lpVtbl = &SHLWAPI_fsVTable; - fileStream->ref = 1; - fileStream->hFile = hFile; - fileStream->dwMode = dwMode; - fileStream->lpszPath = StrDupW(lpszPath); - fileStream->type = 0; /* FIXME */ - fileStream->grfStateBits = 0; /* FIXME */ - } - TRACE ("Returning %p\n", fileStream); - return &fileStream->IStream_iface; + ISHFileStream *fileStream; + + fileStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHFileStream)); + if (!fileStream) return NULL; + + fileStream->IStream_iface.lpVtbl = &SHLWAPI_fsVTable; + fileStream->ref = 1; + fileStream->hFile = hFile; + fileStream->dwMode = dwMode; + fileStream->lpszPath = StrDupW(lpszPath); + fileStream->type = 0; /* FIXME */ + fileStream->grfStateBits = 0; /* FIXME */ + + TRACE ("Returning %p\n", fileStream); + return &fileStream->IStream_iface; }
/************************************************************************* @@ -405,12 +402,10 @@ /* Access */ switch (STGM_ACCESS_MODE(dwMode)) { + case STGM_WRITE: case STGM_READWRITE: dwAccess = GENERIC_READ|GENERIC_WRITE; break; - case STGM_WRITE: - dwAccess = GENERIC_WRITE; - break; case STGM_READ: dwAccess = GENERIC_READ; break; @@ -422,6 +417,7 @@ switch (STGM_SHARE_MODE(dwMode)) { case 0: + case STGM_SHARE_DENY_NONE: dwShare = FILE_SHARE_READ|FILE_SHARE_WRITE; break; case STGM_SHARE_DENY_READ: @@ -432,9 +428,6 @@ break; case STGM_SHARE_EXCLUSIVE: dwShare = 0; - break; - case STGM_SHARE_DENY_NONE: - dwShare = FILE_SHARE_READ|FILE_SHARE_WRITE; break; default: return E_INVALIDARG;
Modified: trunk/reactos/dll/win32/shlwapi/ordinal.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/ordinal.c... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/ordinal.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/ordinal.c [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -38,7 +38,7 @@ extern DWORD SHLWAPI_ThreadRef_index;
HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*); -HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,BOOL); +HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,DWORD); BOOL WINAPI SHAboutInfoW(LPWSTR,DWORD);
/* @@ -2911,7 +2911,7 @@ HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl) { TRACE("%p %p %p\n", hWnd, lpFolder, lpApidl); - return SHInvokeCommand(hWnd, lpFolder, lpApidl, FALSE); + return SHInvokeCommand(hWnd, lpFolder, lpApidl, 0); }
/************************************************************************* @@ -3459,19 +3459,19 @@ * hWnd [I] Window displaying the shell folder * lpFolder [I] IShellFolder interface * lpApidl [I] Id for the particular folder desired - * bInvokeDefault [I] Whether to invoke the default menu item + * dwCommandId [I] The command ID to invoke (0=invoke default) * * RETURNS * Success: S_OK. If bInvokeDefault is TRUE, the default menu action was * executed. * Failure: An HRESULT error code indicating the error. */ -HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, BOOL bInvokeDefault) +HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, DWORD dwCommandId) { IContextMenu *iContext; HRESULT hRet;
- TRACE("(%p, %p, %p, %d)\n", hWnd, lpFolder, lpApidl, bInvokeDefault); + TRACE("(%p, %p, %p, %u)\n", hWnd, lpFolder, lpApidl, dwCommandId);
if (!lpFolder) return E_FAIL; @@ -3485,16 +3485,16 @@ if ((hMenu = CreatePopupMenu())) { HRESULT hQuery; - DWORD dwDefaultId = 0;
/* Add the context menu entries to the popup */ hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF, - bInvokeDefault ? CMF_NORMAL : CMF_DEFAULTONLY); + dwCommandId ? CMF_NORMAL : CMF_DEFAULTONLY);
if (SUCCEEDED(hQuery)) { - if (bInvokeDefault && - (dwDefaultId = GetMenuDefaultItem(hMenu, 0, 0)) != (UINT)-1) + if (!dwCommandId) + dwCommandId = GetMenuDefaultItem(hMenu, 0, 0); + if (dwCommandId != (UINT)-1) { CMINVOKECOMMANDINFO cmIci; /* Invoke the default item */ @@ -3502,8 +3502,8 @@ cmIci.cbSize = sizeof(cmIci); cmIci.fMask = CMIC_MASK_ASYNCOK; cmIci.hwnd = hWnd; - cmIci.lpVerb = MAKEINTRESOURCEA(dwDefaultId); - cmIci.nShow = SW_SCROLLCHILDREN; + cmIci.lpVerb = MAKEINTRESOURCEA(dwCommandId); + cmIci.nShow = SW_SHOWNORMAL;
hRet = IContextMenu_InvokeCommand(iContext, &cmIci); }
Modified: trunk/reactos/dll/win32/shlwapi/path.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/path.c?re... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/path.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/path.c [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -39,6 +39,21 @@ static fnpIsNetDrive pIsNetDrive;
HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD); + +static inline WCHAR* heap_strdupAtoW(LPCSTR str) +{ + WCHAR *ret = NULL; + + if (str) + { + DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + if (ret) + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + } + + return ret; +}
/************************************************************************* * PathAppendA [SHLWAPI.@] @@ -3852,16 +3867,14 @@
strcpyW(szSearch + dwLen, szAllFiles); hfind = FindFirstFileW(szSearch, &find_data); - - if (hfind != INVALID_HANDLE_VALUE && - find_data.cFileName[0] == '.' && - find_data.cFileName[1] == '.') - { - /* The only directory entry should be the parent */ - if (!FindNextFileW(hfind, &find_data)) - retVal = TRUE; + if (hfind != INVALID_HANDLE_VALUE) + { + if (find_data.cFileName[0] == '.' && find_data.cFileName[1] == '.') + /* The only directory entry should be the parent */ + retVal = !FindNextFileW(hfind, &find_data); FindClose(hfind); } + return retVal; }
@@ -4022,18 +4035,61 @@ * strings. * * PARAMS - * pszPath [I] Buffer containing the path to unexpand. - * pszBuf [O] Buffer to receive the unexpanded path. - * cchBuf [I] Size of pszBuf in characters. + * path [I] Buffer containing the path to unexpand. + * buffer [O] Buffer to receive the unexpanded path. + * buf_len [I] Size of pszBuf in characters. * * RETURNS * Success: TRUE * Failure: FALSE */ -BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf) -{ - FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf); - return FALSE; +BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR path, LPSTR buffer, UINT buf_len) +{ + WCHAR bufferW[MAX_PATH], *pathW; + DWORD len; + BOOL ret; + + TRACE("(%s, %p, %d)\n", debugstr_a(path), buffer, buf_len); + + pathW = heap_strdupAtoW(path); + if (!pathW) return FALSE; + + ret = PathUnExpandEnvStringsW(pathW, bufferW, MAX_PATH); + HeapFree(GetProcessHeap(), 0, pathW); + if (!ret) return FALSE; + + len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); + if (buf_len < len + 1) return FALSE; + + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buf_len, NULL, NULL); + return TRUE; +} + +static const WCHAR allusersprofileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%',0}; +static const WCHAR appdataW[] = {'%','A','P','P','D','A','T','A','%',0}; +static const WCHAR computernameW[] = {'%','C','O','M','P','U','T','E','R','N','A','M','E','%',0}; +static const WCHAR programfilesW[] = {'%','P','r','o','g','r','a','m','F','i','l','e','s','%',0}; +static const WCHAR systemrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0}; +static const WCHAR systemdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0}; +static const WCHAR userprofileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%',0}; + +struct envvars_map +{ + const WCHAR *var; + UINT varlen; + WCHAR path[MAX_PATH]; + DWORD len; +}; + +static void init_envvars_map(struct envvars_map *map) +{ + while (map->var) + { + map->len = ExpandEnvironmentStringsW(map->var, map->path, sizeof(map->path)/sizeof(WCHAR)); + /* exclude null from length */ + if (map->len) map->len--; + map++; + } }
/************************************************************************* @@ -4041,10 +4097,51 @@ * * Unicode version of PathUnExpandEnvStringsA. */ -BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf) -{ - FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf); - return FALSE; +BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR path, LPWSTR buffer, UINT buf_len) +{ + static struct envvars_map null_var = {NULL, 0, {0}, 0}; + struct envvars_map *match = &null_var, *cur; + struct envvars_map envvars[] = { + { allusersprofileW, sizeof(allusersprofileW)/sizeof(WCHAR) }, + { appdataW, sizeof(appdataW)/sizeof(WCHAR) }, + { computernameW, sizeof(computernameW)/sizeof(WCHAR) }, + { programfilesW, sizeof(programfilesW)/sizeof(WCHAR) }, + { systemrootW, sizeof(systemrootW)/sizeof(WCHAR) }, + { systemdriveW, sizeof(systemdriveW)/sizeof(WCHAR) }, + { userprofileW, sizeof(userprofileW)/sizeof(WCHAR) }, + { NULL } + }; + DWORD pathlen; + UINT needed; + + TRACE("(%s, %p, %d)\n", debugstr_w(path), buffer, buf_len); + + pathlen = strlenW(path); + init_envvars_map(envvars); + cur = envvars; + while (cur->var) + { + /* path can't contain expanded value or value wasn't retrieved */ + if (cur->len == 0 || cur->len > pathlen || strncmpiW(cur->path, path, cur->len)) + { + cur++; + continue; + } + + if (cur->len > match->len) + match = cur; + cur++; + } + + /* 'varlen' includes NULL termination char */ + needed = match->varlen + pathlen - match->len; + if (match->len == 0 || needed > buf_len) return FALSE; + + strcpyW(buffer, match->var); + strcatW(buffer, &path[match->len]); + TRACE("ret %s\n", debugstr_w(buffer)); + + return TRUE; }
/*************************************************************************
Modified: trunk/reactos/dll/win32/shlwapi/shlwapi.spec URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/shlwapi.s... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/shlwapi.spec [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/shlwapi.spec [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -216,7 +216,7 @@ 216 stdcall -noname SHAnsiToUnicodeCP(long str ptr long) 217 stdcall -ordinal SHUnicodeToAnsi(wstr ptr ptr) 218 stdcall -noname SHUnicodeToAnsiCP(long wstr ptr long) -219 stdcall -noname QISearch(long long long long) +219 stdcall QISearch(long long long long) 220 stdcall -noname SHSetDefaultDialogFont(ptr long) 221 stdcall -noname SHRemoveDefaultDialogFont(ptr) 222 stdcall -noname SHGlobalCounterCreate(long) @@ -546,7 +546,7 @@ 550 stub -noname GetTemplateInfoFromHandle 551 stub -noname IShellFolder_CompareIDs
-@ stdcall AssocCreate(double double ptr ptr) +@ stdcall AssocCreate(int128 ptr ptr) @ stdcall AssocGetPerceivedType(wstr ptr ptr ptr) @ stdcall AssocIsDangerous(wstr) @ stdcall AssocQueryKeyA(long long str str ptr)
Modified: trunk/reactos/dll/win32/shlwapi/string.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/string.c?... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/string.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/string.c [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -2800,7 +2800,7 @@ TRACE("returning %s\n", debugstr_w(dst)); end: if(hmod) FreeLibrary(hmod); - HeapFree(GetProcessHeap(), 0, dllname); + LocalFree(dllname); return hr; }
Modified: trunk/reactos/dll/win32/shlwapi/url.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/url.c?rev... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/url.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/url.c [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -650,6 +650,7 @@ DWORD i, len, res1, res2, process_case = 0; LPWSTR work, preliminary, mbase, mrelative; static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'}; + static const WCHAR fragquerystr[] = {'#','?',0}; HRESULT ret;
TRACE("(base %s, Relative %s, Combine size %d, flags %08x)\n", @@ -721,17 +722,19 @@ } }
- /* If there is a '#' and the characters immediately preceding it are - * ".htm[l]", then begin looking for the last leaf starting from - * the '#'. Otherwise the '#' is not meaningful and just start - * looking from the end. */ - if ((work = strchrW(base.pszSuffix + sizeloc, '#'))) { + /* If there is a '?', then the remaining part can only contain a + * query string or fragment, so start looking for the last leaf + * from the '?'. Otherwise, if there is a '#' and the characters + * immediately preceding it are ".htm[l]", then begin looking for + * the last leaf starting from the '#'. Otherwise the '#' is not + * meaningful and just start looking from the end. */ + if ((work = strpbrkW(base.pszSuffix + sizeloc, fragquerystr))) { const WCHAR htmlW[] = {'.','h','t','m','l',0}; const int len_htmlW = 5; const WCHAR htmW[] = {'.','h','t','m',0}; const int len_htmW = 4;
- if (base.nScheme == URL_SCHEME_HTTP || base.nScheme == URL_SCHEME_HTTPS) + if (*work == '?' || base.nScheme == URL_SCHEME_HTTP || base.nScheme == URL_SCHEME_HTTPS) manual_search = TRUE; else if (work - base.pszSuffix > len_htmW) { work -= len_htmW; @@ -968,57 +971,43 @@ #define WINE_URL_STOP_ON_HASH 0x20 #define WINE_URL_STOP_ON_QUESTION 0x40
-static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags) -{ +static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD flags, DWORD int_flags) +{ + if (flags & URL_ESCAPE_SPACES_ONLY) + return ch == ' '; + + if ((flags & URL_ESCAPE_PERCENT) && (ch == '%')) + return TRUE; + + if (ch <= 31 || (ch >= 127 && ch <= 255) ) + return TRUE;
if (isalnumW(ch)) return FALSE;
- if(dwFlags & URL_ESCAPE_SPACES_ONLY) { - if(ch == ' ') - return TRUE; - else - return FALSE; - } - - if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%')) - return TRUE; - - if (ch <= 31 || ch >= 127) - return TRUE; - - else { - switch (ch) { - case ' ': - case '<': - case '>': - case '"': - case '{': - case '}': - case '|': - case '\': - case '^': - case ']': - case '[': - case '`': - case '&': - return TRUE; - - case '/': - if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE; - return FALSE; - - case '?': - if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE; - return FALSE; - - case '#': - if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE; - return FALSE; - - default: - return FALSE; - } + switch (ch) { + case ' ': + case '<': + case '>': + case '"': + case '{': + case '}': + case '|': + case '\': + case '^': + case ']': + case '[': + case '`': + case '&': + return TRUE; + case '/': + return !!(int_flags & WINE_URL_ESCAPE_SLASH); + case '?': + return !!(int_flags & WINE_URL_ESCAPE_QUESTION); + case '#': + return !!(int_flags & WINE_URL_ESCAPE_HASH); + default: + return FALSE; } }
Modified: trunk/reactos/dll/win32/shlwapi/wsprintf.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shlwapi/wsprintf.... ============================================================================== --- trunk/reactos/dll/win32/shlwapi/wsprintf.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shlwapi/wsprintf.c [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -26,6 +26,7 @@ #include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(string); +
#define WPRINTF_LEFTALIGN 0x0001 /* Align output on the left ('-' prefix) */ #define WPRINTF_PREFIX_HEX 0x0002 /* Prefix hex with 0x ('#' prefix) */
Modified: trunk/reactos/media/doc/README.WINE URL: http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=6... ============================================================================== --- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original) +++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Thu Apr 24 16:07:14 2014 @@ -180,7 +180,7 @@ reactos/dll/win32/shdocvw # Synced to Wine-1.7.1 reactos/dll/win32/shell32 # Forked at Wine-20071011 reactos/dll/win32/shfolder # Synced to Wine-1.7.1 -reactos/dll/win32/shlwapi # Synced to Wine-1.7.1 +reactos/dll/win32/shlwapi # Synced to Wine-1.7.17 reactos/dll/win32/slbcsp # Synced to Wine-1.7.1 reactos/dll/win32/snmpapi # Synced to Wine-1.7.1 reactos/dll/win32/softpub # Synced to Wine-1.7.1