From: Alexey Alyaev aalyaev@etersoft.ru
--- dlls/mpr/Makefile.in | 2 +- dlls/mpr/wnet.c | 293 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 249 insertions(+), 46 deletions(-)
diff --git a/dlls/mpr/Makefile.in b/dlls/mpr/Makefile.in index 8a74786cd22..97c762b8070 100644 --- a/dlls/mpr/Makefile.in +++ b/dlls/mpr/Makefile.in @@ -1,6 +1,6 @@ MODULE = mpr.dll IMPORTLIB = mpr -IMPORTS = user32 advapi32 +IMPORTS = user32 advapi32 shlwapi
C_SRCS = \ auth.c \ diff --git a/dlls/mpr/wnet.c b/dlls/mpr/wnet.c index 7c5b576598b..8d58e6d6cb0 100644 --- a/dlls/mpr/wnet.c +++ b/dlls/mpr/wnet.c @@ -34,6 +34,7 @@ #include "ddk/mountmgr.h" #include "wine/debug.h" #include "mprres.h" +#include "shlwapi.h" #include "wnetpriv.h"
WINE_DEFAULT_DEBUG_CHANNEL(mpr); @@ -2530,42 +2531,148 @@ DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel, { DWORD err, size;
- FIXME( "(%s, 0x%08lX, %p, %p): stub\n", - debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); + LPWSTR wLocalPath = NULL;
- switch (dwInfoLevel) + LPVOID wBuffer = NULL; + DWORD wBufferSize = 1024; + + UNIVERSAL_NAME_INFOW *uniInfoW = NULL; + REMOTE_NAME_INFOW *remInfoW = NULL; + + DWORD outSize; + + TRACE("(%s, %ld, %p, %ld)\n", debugstr_a(lpLocalPath), dwInfoLevel, + lpBuffer, *lpBufferSize); + + // Prepare parameters + wLocalPath = strdupAtoW(lpLocalPath); + if (!wLocalPath) { - case UNIVERSAL_NAME_INFO_LEVEL: + err = WN_OUT_OF_MEMORY; + goto out; + } + + // Get wide universal name + wBuffer = HeapAlloc(GetProcessHeap(), 0, wBufferSize); + err = WNetGetUniversalNameW(wLocalPath, dwInfoLevel, wBuffer, &wBufferSize); + if (err == WN_MORE_DATA) { - LPUNIVERSAL_NAME_INFOA info = lpBuffer; + wBuffer = HeapReAlloc(GetProcessHeap(), 0, wBuffer, wBufferSize); + if (!wBuffer) + { + err = WN_OUT_OF_MEMORY; + goto out; + } + + err = WNetGetUniversalNameW(wLocalPath, dwInfoLevel, wBuffer, &wBufferSize); + } + + // Check for errors + if (err != WN_NO_ERROR) + goto out; + + // Estimate size needed to convert result + uniInfoW = wBuffer; + remInfoW = wBuffer;
- if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE) + switch (dwInfoLevel) + { + case UNIVERSAL_NAME_INFO_LEVEL: { - err = ERROR_NOT_CONNECTED; + outSize = sizeof(UNIVERSAL_NAME_INFOA); + outSize += WideCharToMultiByte(CP_ACP, 0, + uniInfoW->lpUniversalName, -1, NULL, 0, NULL, NULL); + break; } + case REMOTE_NAME_INFO_LEVEL: + outSize = sizeof(REMOTE_NAME_INFOA); + outSize += WideCharToMultiByte(CP_ACP, 0, + remInfoW->lpUniversalName, -1, NULL, 0, NULL, NULL); + + outSize += WideCharToMultiByte(CP_ACP, 0, + remInfoW->lpConnectionName, -1, NULL, 0, NULL, NULL); + + outSize += WideCharToMultiByte(CP_ACP, 0, + remInfoW->lpRemainingPath, -1, NULL, 0, NULL, NULL); + + break; + + default: + err = WN_BAD_LEVEL; + goto out; + break; + }
- size = sizeof(*info) + lstrlenA(lpLocalPath) + 1; - if (*lpBufferSize < size) + // Make sure we have enough output buffer space + if (*lpBufferSize < outSize) + { + *lpBufferSize = outSize; + err = WN_MORE_DATA; + goto out; + } + + // Convert result + switch (dwInfoLevel) + { + case UNIVERSAL_NAME_INFO_LEVEL: { - err = WN_MORE_DATA; + UNIVERSAL_NAME_INFOA *out = lpBuffer; + + // Convert universal name + out->lpUniversalName = (LPSTR)(out + 1); + WideCharToMultiByte(CP_ACP, 0, uniInfoW->lpUniversalName, -1, + out->lpUniversalName, (outSize - sizeof(UNIVERSAL_NAME_INFOA)), + NULL, NULL); + break; } - info->lpUniversalName = (char *)info + sizeof(*info); - lstrcpyA(info->lpUniversalName, lpLocalPath); - err = WN_NO_ERROR; - break; - } - case REMOTE_NAME_INFO_LEVEL: - err = WN_NOT_CONNECTED; - break; + case REMOTE_NAME_INFO_LEVEL: + { + REMOTE_NAME_INFOA *out = lpBuffer;
- default: - err = WN_BAD_VALUE; - break; + int wrote = 0; + int remains = outSize - sizeof(REMOTE_NAME_INFOA); + + // Convert universal name + out->lpUniversalName = (LPSTR)(out + 1); + wrote = WideCharToMultiByte(CP_ACP, 0, remInfoW->lpUniversalName, -1, + out->lpUniversalName, remains, NULL, NULL); + + remains -= wrote; + + // Convert connection name + out->lpConnectionName = out->lpUniversalName + wrote; + wrote = WideCharToMultiByte(CP_ACP, 0, remInfoW->lpConnectionName, -1, + out->lpConnectionName, remains, NULL, NULL); + + remains -= wrote; + + // Convert remaining path + out->lpRemainingPath = out->lpConnectionName + wrote; + wrote = WideCharToMultiByte(CP_ACP, 0, remInfoW->lpRemainingPath, -1, + out->lpRemainingPath, remains, NULL, NULL); + + remains -= wrote; + break; + } + default: + err = WN_BAD_LEVEL; + goto out; + break; }
- SetLastError(err); +out: + if (wBuffer) + HeapFree(GetProcessHeap(), 0, wBuffer); + + if (wLocalPath) + HeapFree(GetProcessHeap(), 0, wLocalPath); + + if (err != WN_NO_ERROR) + SetLastError(err); + + TRACE("Returning %ld\n", err); return err; }
@@ -2575,45 +2682,141 @@ DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel, DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize ) { - DWORD err, size; + DWORD err = WN_NO_ERROR;
- FIXME( "(%s, 0x%08lX, %p, %p): stub\n", - debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); + WCHAR drive[3] = {'\0'}; + LPCWSTR remainingPath = NULL;
- switch (dwInfoLevel) + int tries = 2; + + LPWSTR remoteName = NULL; + DWORD remoteNameSize = MAX_PATH; + + DWORD uniNameSize; + DWORD outSize; + + TRACE("(%s, %ld, %p, %ld)\n", debugstr_w(lpLocalPath), dwInfoLevel, + lpBuffer, *lpBufferSize); + + // Extract local path drive letter and remaining path + if (lpLocalPath) { - case UNIVERSAL_NAME_INFO_LEVEL: + drive[0] = lpLocalPath[0]; + drive[1] = lpLocalPath[1]; + + remainingPath = lpLocalPath + 2; + } + + // Try getting remote name for local device + while (tries) { - LPUNIVERSAL_NAME_INFOW info = lpBuffer; + tries--;
- if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE) + remoteName = HeapAlloc(GetProcessHeap(), 0, remoteNameSize); + if (!remoteName) { - err = ERROR_NOT_CONNECTED; + err = WN_OUT_OF_MEMORY; break; }
- size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR); - if (*lpBufferSize < size) + err = WNetGetConnectionW(drive, remoteName, &remoteNameSize); + if (err == WN_MORE_DATA) { - *lpBufferSize = size; - err = WN_MORE_DATA; - break; + HeapFree(GetProcessHeap(), 0, remoteName); + remoteName = NULL; + continue; } - info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info)); - lstrcpyW(info->lpUniversalName, lpLocalPath); - err = WN_NO_ERROR; + break; + }; + + // Check for errors + if (err != WN_NO_ERROR) + goto out; + + // Calculate required size for output + uniNameSize = sizeof(WCHAR) * + (lstrlenW(remoteName) + lstrlenW(remainingPath) + 1 /*NULL*/); + + switch (dwInfoLevel) + { + case UNIVERSAL_NAME_INFO_LEVEL: + outSize = sizeof(UNIVERSAL_NAME_INFOW) + uniNameSize; + break; + + case REMOTE_NAME_INFO_LEVEL: + outSize = sizeof(REMOTE_NAME_INFOW) + uniNameSize; + outSize += sizeof(WCHAR) * (lstrlenW(remoteName) + 1 /*NULL*/); + outSize += sizeof(WCHAR) * (lstrlenW(remainingPath) + 1 /*NULL*/); + break; + + default: + err = WN_BAD_LEVEL; + goto out; + break; } - case REMOTE_NAME_INFO_LEVEL: - err = WN_NO_NETWORK; - break;
- default: - err = WN_BAD_VALUE; - break; + // Check if we have enough result buffer space + if (*lpBufferSize < outSize) + { + *lpBufferSize = outSize; + err = WN_MORE_DATA; + goto out; + } + + // Proceed to copying + switch (dwInfoLevel) + { + case UNIVERSAL_NAME_INFO_LEVEL: + { + UNIVERSAL_NAME_INFOW *out = (UNIVERSAL_NAME_INFOW *)lpBuffer; + + // Copy universal name + out->lpUniversalName = (LPWSTR)(out + 1); + wnsprintfW(out->lpUniversalName, (uniNameSize / sizeof(WCHAR)), + L"%ls%ls", remoteName, remainingPath); + + break; + } + case REMOTE_NAME_INFO_LEVEL: + { + REMOTE_NAME_INFOW *out = (REMOTE_NAME_INFOW *)lpBuffer; + + // Copy universal name + out->lpUniversalName = (LPWSTR)(out + 1); + wnsprintfW(out->lpUniversalName, (uniNameSize / sizeof(WCHAR)), + L"%ls%ls", remoteName, remainingPath); + + // Copy connection name + out->lpConnectionName = + out->lpUniversalName + lstrlenW(out->lpUniversalName) + 1; + + wnsprintfW(out->lpConnectionName, (lstrlenW(remoteName) + 1 /*NULL*/), + L"%ls", remoteName); + + // Copy remaining path + out->lpRemainingPath = + out->lpConnectionName + lstrlenW(out->lpConnectionName) + 1; + + wnsprintfW(out->lpRemainingPath, (lstrlenW(remainingPath) + 1 /*NULL*/), + L"%ls", remainingPath); + + break; + } + default: + err = WN_BAD_LEVEL; + goto out; + break; }
- if (err != WN_NO_ERROR) SetLastError(err); +out: + if (remoteName) + HeapFree(GetProcessHeap(), 0, remoteName); + + if (err != WN_NO_ERROR) + SetLastError(err); + + TRACE("Returning %ld\n", err); return err; }