diff --git a/dlls/mpr/.cvsignore b/dlls/mpr/.cvsignore index cb44b52e60e46c7c089ea70d22d7b26dbeab9d76..58c8018e68017837c0b627bf131224ef2def1cac 100644 --- a/dlls/mpr/.cvsignore +++ b/dlls/mpr/.cvsignore @@ -1,3 +1,5 @@ Makefile mpr.dll.dbg.c +mpr.res mpr.spec.def +version.res diff --git a/dlls/mpr/Makefile.in b/dlls/mpr/Makefile.in index 283759e966cfce7e0321cc735ff3fe9a52a4e45d..96ab0eb6c61e8fb671e13ee6a228d4f974dd7036 100644 --- a/dlls/mpr/Makefile.in +++ b/dlls/mpr/Makefile.in @@ -3,7 +3,8 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = mpr.dll -IMPORTS = advapi32 kernel32 +IMPORTS = user32 advapi32 kernel32 +EXTRALIBS = $(LIBUNICODE) C_SRCS = \ auth.c \ @@ -13,6 +14,11 @@ C_SRCS = \ pwcache.c \ wnet.c +RC_SRCS = \ + mpr.rc \ + version.rc + + @MAKE_DLL_RULES@ ### Dependencies: diff --git a/dlls/mpr/mpr.rc b/dlls/mpr/mpr.rc new file mode 100644 index 0000000000000000000000000000000000000000..3c33a86b8ba798adb5bf279cbb3b84e19627ff15 --- /dev/null +++ b/dlls/mpr/mpr.rc @@ -0,0 +1,24 @@ +/* + * MPR dll resources + * + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "windef.h" +#include "winbase.h" +#include "mprres.h" + +#include "mpr_En.rc" diff --git a/dlls/mpr/mpr_En.rc b/dlls/mpr/mpr_En.rc new file mode 100644 index 0000000000000000000000000000000000000000..225c516b5cf4cd3eb2d1f3b454237f36d9110306 --- /dev/null +++ b/dlls/mpr/mpr_En.rc @@ -0,0 +1,26 @@ +/* + * MPR dll resources + * + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_ENTIRENETWORK "Entire Network" +} diff --git a/dlls/mpr/mpr_main.c b/dlls/mpr/mpr_main.c index 8f5f11dbe16a90629cbbe40966b6f275eeeb3871..a155c94350f75bd93c189186c68f4d007d8759b2 100644 --- a/dlls/mpr/mpr_main.c +++ b/dlls/mpr/mpr_main.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winnetwk.h" #include "wine/debug.h" +#include "wnetpriv.h" WINE_DEFAULT_DEBUG_CHANNEL(mpr); @@ -79,3 +80,18 @@ DWORD WINAPI DllCanUnloadNow(void) FIXME("Stub\n"); return S_OK; } + +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( hinstDLL ); + wnetInit(hinstDLL); + break; + + case DLL_PROCESS_DETACH: + wnetFree(); + break; + } + return TRUE; +} diff --git a/dlls/mpr/mprres.h b/dlls/mpr/mprres.h new file mode 100644 index 0000000000000000000000000000000000000000..c144e557b60f76fb2c88f05a398a04c37d17afcd --- /dev/null +++ b/dlls/mpr/mprres.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_MPRRES_H__ +#define __WINE_MPRRES_H__ + +#define IDS_ENTIRENETWORK 1 + +#endif /* ndef __WINE_MPRRES_H__ */ diff --git a/dlls/mpr/version.rc b/dlls/mpr/version.rc new file mode 100644 index 0000000000000000000000000000000000000000..7f9d96bf125749e65f9d54aacb8cee18f6b41608 --- /dev/null +++ b/dlls/mpr/version.rc @@ -0,0 +1,29 @@ +/* + * MPR dll version resources + * + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define WINE_FILEDESCRIPTION_STR "Wine Multiprotocol Router Library" +#define WINE_FILENAME_STR "mpr.dll" +#define WINE_FILEVERSION 5,0,2195,6611 +#define WINE_FILEVERSION_STR "5.00.2195.6611" +#define WINE_PRODUCTVERSION 5,0,2195,6611 +#define WINE_PRODUCTVERSION_STR "5.00.2195.6611" +#define WINE_PRODUCTNAME_STR "Wine" + +#include "wine/wine_common_ver.rc" diff --git a/dlls/mpr/wnet.c b/dlls/mpr/wnet.c index 935fbb8735a796e955d61cefa1871d4f8c47955e..48dd87327dcc04e2b44e2d9f853ed58ed2042694 100644 --- a/dlls/mpr/wnet.c +++ b/dlls/mpr/wnet.c @@ -2,6 +2,7 @@ * MPR WNet functions * * Copyright 1999 Ulrich Weigand + * Copyright 2004 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,53 +19,794 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "config.h" - -#include <ctype.h> #include <stdarg.h> -#include <string.h> -#include <sys/types.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - #include "windef.h" #include "winbase.h" #include "winnls.h" #include "winnetwk.h" +#include "npapi.h" +#include "winreg.h" +#include "winuser.h" #include "wine/debug.h" +#include "wine/unicode.h" +#include "mprres.h" +#include "wnetpriv.h" WINE_DEFAULT_DEBUG_CHANNEL(mpr); +/* Data structures representing network service providers. Assumes only one + * thread creates them, and that they are constant for the life of the process + * (and therefore doesn't synchronize access). + * FIXME: only basic provider data and enumeration-related data are implemented + * so far, need to implement the rest too. + */ +typedef struct _WNetProvider +{ + HMODULE hLib; + PWSTR name; + PF_NPGetCaps getCaps; + DWORD dwSpecVersion; + DWORD dwNetType; + DWORD dwEnumScopes; + PF_NPOpenEnum openEnum; + PF_NPEnumResource enumResource; + PF_NPCloseEnum closeEnum; +} WNetProvider, *PWNetProvider; + +typedef struct _WNetProviderTable +{ + LPWSTR entireNetwork; + DWORD numAllocated; + DWORD numProviders; + WNetProvider table[1]; +} WNetProviderTable, *PWNetProviderTable; + +#define WNET_ENUMERATOR_TYPE_NULL 0 +#define WNET_ENUMERATOR_TYPE_GLOBAL 1 +#define WNET_ENUMERATOR_TYPE_PROVIDER 2 +#define WNET_ENUMERATOR_TYPE_CONTEXT 3 + +/* An WNet enumerator. Note that the type doesn't correspond to the scope of + * the enumeration; it represents one of the following types: + * - a 'null' enumeration, one that contains no members + * - a global enumeration, one that's executed across all providers + * - a provider-specific enumeration, one that's only executed by a single + * provider + * - a context enumeration. I know this contradicts what I just said about + * there being no correspondence between the scope and the type, but it's + * necessary for the special case that a "Entire Network" entry needs to + * be enumerated in an enumeration of the context scope. Thus an enumeration + * of the context scope results in a context type enumerator, which morphs + * into a global enumeration (so the enumeration continues across all + * providers). + */ +typedef struct _WNetEnumerator +{ + DWORD enumType; + DWORD providerIndex; + HANDLE handle; + BOOL providerDone; + DWORD dwScope; + DWORD dwType; + DWORD dwUsage; + LPNETRESOURCEW lpNet; +} WNetEnumerator, *PWNetEnumerator; + +#define BAD_PROVIDER_INDEX (DWORD)0xffffffff + +/* Returns an index (into the global WNetProviderTable) of the provider with + * the given name, or BAD_PROVIDER_INDEX if not found. + */ +static DWORD _findProviderIndexW(LPCWSTR lpProvider); + +PWNetProviderTable providerTable; + +/* + * Global provider table functions + */ + +static void _tryLoadProvider(PCWSTR provider) +{ + static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'S','e','r','v','i','c','e','s','\\',0 }; + static const WCHAR serviceFmt[] = { '%','s','%','s','\\', + 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 }; + WCHAR serviceName[MAX_PATH]; + HKEY hKey; + + TRACE("%s\n", debugstr_w(provider)); + snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt, + servicePrefix, provider); + serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0'; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) == + ERROR_SUCCESS) + { + static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r', + 'P','a','t','h',0 }; + WCHAR providerPath[MAX_PATH]; + DWORD type, size = sizeof(providerPath); + + if (RegQueryValueExW(hKey, szProviderPath, NULL, &type, + (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ) + { + static const WCHAR szProviderName[] = { 'N','a','m','e',0 }; + PWSTR name = NULL; + + size = 0; + RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size); + if (size) + { + name = (PWSTR)HeapAlloc(GetProcessHeap(), 0, size); + if (RegQueryValueExW(hKey, szProviderName, NULL, &type, + (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ) + { + HeapFree(GetProcessHeap(), 0, name); + name = NULL; + } + } + if (name) + { + HMODULE hLib = LoadLibraryW(providerPath); + + if (hLib) + { + PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib, + "NPGetCaps"); + + TRACE("loaded lib %p\n", hLib); + if (getCaps) + { + PWNetProvider provider = + &providerTable->table[providerTable->numProviders]; + + provider->hLib = hLib; + provider->name = name; + TRACE("name is %s\n", debugstr_w(name)); + provider->getCaps = getCaps; + provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION); + provider->dwNetType = getCaps(WNNC_NET_TYPE); + TRACE("net type is 0x%08lx\n", provider->dwNetType); + provider->dwEnumScopes = getCaps(WNNC_ENUMERATION); + if (provider->dwEnumScopes) + { + TRACE("supports enumeration\n"); + provider->openEnum = (PF_NPOpenEnum) + GetProcAddress(hLib, "NPOpenEnum"); + TRACE("openEnum is %p\n", provider->openEnum); + provider->enumResource = (PF_NPEnumResource) + GetProcAddress(hLib, "NPEnumResource"); + TRACE("enumResource is %p\n", + provider->enumResource); + provider->closeEnum = (PF_NPCloseEnum) + GetProcAddress(hLib, "NPCloseEnum"); + TRACE("closeEnum is %p\n", provider->closeEnum); + if (!provider->openEnum || !provider->enumResource + || !provider->closeEnum) + { + provider->openEnum = NULL; + provider->enumResource = NULL; + provider->closeEnum = NULL; + provider->dwEnumScopes = 0; + WARN("Couldn't load enumeration functions\n"); + } + } + providerTable->numProviders++; + } + else + { + WARN("Provider %s didn't export NPGetCaps\n", + debugstr_w(provider)); + if (name) + HeapFree(GetProcessHeap(), 0, name); + FreeLibrary(hLib); + } + } + else + { + WARN("Couldn't load library %s for provider %s\n", + debugstr_w(providerPath), debugstr_w(provider)); + HeapFree(GetProcessHeap(), 0, name); + } + } + else + { + WARN("Couldn't get provider name for provider %s\n", + debugstr_w(provider)); + } + } + else + WARN("Couldn't open value %s\n", debugstr_w(szProviderPath)); + RegCloseKey(hKey); + } + else + WARN("Couldn't open service key for provider %s\n", + debugstr_w(provider)); +} + +void wnetInit(HINSTANCE hInstDll) +{ + static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\', + 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\', + 'O','r','d','e','r',0 }; + static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r', + 'O','r','d','e','r',0 }; + HKEY hKey; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey) + == ERROR_SUCCESS) + { + DWORD size = 0; + + RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size); + if (size) + { + PWSTR providers = (PWSTR)HeapAlloc(GetProcessHeap(), 0, size); + + if (providers) + { + DWORD type; + + if (RegQueryValueExW(hKey, providerOrder, NULL, &type, + (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ) + { + PWSTR ptr; + DWORD numToAllocate; + + TRACE("provider order is %s\n", debugstr_w(providers)); + /* first count commas as a heuristic for how many to + * allocate space for */ + for (ptr = providers, numToAllocate = 1; ptr; ) + { + ptr = strchrW(ptr, ','); + if (ptr) + numToAllocate++; + } + providerTable = (PWNetProviderTable) + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(WNetProviderTable) + + (numToAllocate - 1) * sizeof(WNetProvider)); + if (providerTable) + { + PWSTR ptrPrev; + int entireNetworkLen; + + entireNetworkLen = LoadStringW(hInstDll, + IDS_ENTIRENETWORK, NULL, 0); + providerTable->entireNetwork = (LPWSTR)HeapAlloc( + GetProcessHeap(), 0, (entireNetworkLen + 1) * + sizeof(WCHAR)); + if (providerTable->entireNetwork) + LoadStringW(hInstDll, IDS_ENTIRENETWORK, + providerTable->entireNetwork, + entireNetworkLen + 1); + providerTable->numAllocated = numToAllocate; + for (ptr = providers; ptr; ) + { + ptrPrev = ptr; + ptr = strchrW(ptr, ','); + if (ptr) + *ptr = '\0'; + _tryLoadProvider(ptrPrev); + } + } + } + HeapFree(GetProcessHeap(), 0, providers); + } + } + RegCloseKey(hKey); + } +} + +void wnetFree(void) +{ + if (providerTable) + { + DWORD i; + + for (i = 0; i < providerTable->numProviders; i++) + { + HeapFree(GetProcessHeap(), 0, providerTable->table[i].name); + FreeModule(providerTable->table[i].hLib); + } + if (providerTable->entireNetwork) + HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork); + HeapFree(GetProcessHeap(), 0, providerTable); + providerTable = NULL; + } +} + +static DWORD _findProviderIndexW(LPCWSTR lpProvider) +{ + DWORD ret = BAD_PROVIDER_INDEX; + + if (providerTable && providerTable->numProviders) + { + DWORD i; + + for (i = 0; i < providerTable->numProviders && + ret == BAD_PROVIDER_INDEX; i++) + if (!strcmpW(lpProvider, providerTable->table[i].name)) + ret = i; + } + return ret; +} /* * Browsing Functions */ +static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet) +{ + LPNETRESOURCEW ret; + + if (lpNet) + { + ret = (LPNETRESOURCEW)HeapAlloc(GetProcessHeap(), 0, + sizeof(NETRESOURCEW)); + if (ret) + { + size_t len; + + memcpy(ret, lpNet, sizeof(ret)); + ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL; + if (lpNet->lpRemoteName) + { + len = strlenW(lpNet->lpRemoteName) + 1; + ret->lpRemoteName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, + len * sizeof(WCHAR)); + if (ret->lpRemoteName) + strcpyW(ret->lpRemoteName, lpNet->lpRemoteName); + } + } + } + else + ret = NULL; + return ret; +} + +static void _freeEnumNetResource(LPNETRESOURCEW lpNet) +{ + if (lpNet) + { + if (lpNet->lpRemoteName) + HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName); + HeapFree(GetProcessHeap(), 0, lpNet); + } +} + +static PWNetEnumerator _createNullEnumerator(void) +{ + PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + + if (ret) + ret->enumType = WNET_ENUMERATOR_TYPE_NULL; + return ret; +} + +static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType, + DWORD dwUsage, LPNETRESOURCEW lpNet) +{ + PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->dwUsage = dwUsage; + ret->lpNet = _copyNetResourceForEnumW(lpNet); + } + return ret; +} + +static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType, + DWORD dwUsage, DWORD index, HANDLE handle) +{ + PWNetEnumerator ret; + + if (!providerTable || index >= providerTable->numProviders) + ret = NULL; + else + { + ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER; + ret->providerIndex = index; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->dwUsage = dwUsage; + ret->handle = handle; + } + } + return ret; +} + +static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType, + DWORD dwUsage) +{ + PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->dwUsage = dwUsage; + } + return ret; +} + +/* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer + * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries + * to start. On return, *lpcCount reflects the number thunked into lpBuffer. + * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA + * if not all members of the array could be thunked, and something else on + * failure. + */ +static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn, + LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD i, numToThunk, totalBytes, ret; + LPSTR strNext; + + if (!lpNetArrayIn) + return WN_BAD_POINTER; + if (!lpcCount) + return WN_BAD_POINTER; + if (*lpcCount == -1) + return WN_BAD_VALUE; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + + for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) + { + LPNETRESOURCEW lpNet = lpNetArrayIn + i; + + totalBytes += sizeof(NETRESOURCEA); + if (lpNet->lpLocalName) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName, + -1, NULL, 0, NULL, NULL); + if (lpNet->lpRemoteName) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName, + -1, NULL, 0, NULL, NULL); + if (lpNet->lpComment) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment, + -1, NULL, 0, NULL, NULL); + if (lpNet->lpProvider) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider, + -1, NULL, 0, NULL, NULL); + if (totalBytes < *lpBufferSize) + numToThunk = i + 1; + } + strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA)); + for (i = 0; i < numToThunk; i++) + { + LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i; + LPNETRESOURCEW lpNetIn = lpNetArrayIn + i; + + memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA)); + /* lie about string lengths, we already verified how many + * we have space for above + */ + if (lpNetIn->lpLocalName) + { + lpNetOut->lpLocalName = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1, + lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL); + } + if (lpNetIn->lpRemoteName) + { + lpNetOut->lpRemoteName = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1, + lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL); + } + if (lpNetIn->lpComment) + { + lpNetOut->lpComment = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1, + lpNetOut->lpComment, *lpBufferSize, NULL, NULL); + } + if (lpNetIn->lpProvider) + { + lpNetOut->lpProvider = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1, + lpNetOut->lpProvider, *lpBufferSize, NULL, NULL); + } + } + ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; + TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk, + *lpcCount, ret); + return ret; +} + +/* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer + * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries + * to start. On return, *lpcCount reflects the number thunked into lpBuffer. + * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA + * if not all members of the array could be thunked, and something else on + * failure. + */ +static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn, + LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD i, numToThunk, totalBytes, ret; + LPWSTR strNext; + + if (!lpNetArrayIn) + return WN_BAD_POINTER; + if (!lpcCount) + return WN_BAD_POINTER; + if (*lpcCount == -1) + return WN_BAD_VALUE; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + + for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) + { + LPNETRESOURCEA lpNet = lpNetArrayIn + i; + + totalBytes += sizeof(NETRESOURCEW); + if (lpNet->lpLocalName) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName, + -1, NULL, 0) * sizeof(WCHAR); + if (lpNet->lpRemoteName) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName, + -1, NULL, 0) * sizeof(WCHAR); + if (lpNet->lpComment) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment, + -1, NULL, 0) * sizeof(WCHAR); + if (lpNet->lpProvider) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider, + -1, NULL, 0) * sizeof(WCHAR); + if (totalBytes < *lpBufferSize) + numToThunk = i + 1; + } + strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW)); + for (i = 0; i < numToThunk; i++) + { + LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i; + LPNETRESOURCEA lpNetIn = lpNetArrayIn + i; + + memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW)); + /* lie about string lengths, we already verified how many + * we have space for above + */ + if (lpNetIn->lpLocalName) + { + lpNetOut->lpLocalName = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName, + -1, lpNetOut->lpLocalName, *lpBufferSize); + } + if (lpNetIn->lpRemoteName) + { + lpNetOut->lpRemoteName = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName, + -1, lpNetOut->lpRemoteName, *lpBufferSize); + } + if (lpNetIn->lpComment) + { + lpNetOut->lpComment = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment, + -1, lpNetOut->lpComment, *lpBufferSize); + } + if (lpNetIn->lpProvider) + { + lpNetOut->lpProvider = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider, + -1, lpNetOut->lpProvider, *lpBufferSize); + } + } + ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; + TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk, + *lpcCount, ret); + return ret; +} + /********************************************************************* * WNetOpenEnumA [MPR.@] + * + * See comments for WNetOpenEnumW. */ DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEA lpNet, LPHANDLE lphEnum ) { - FIXME( "(%08lX, %08lX, %08lX, %p, %p): stub\n", + DWORD ret; + + TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n", dwScope, dwType, dwUsage, lpNet, lphEnum ); - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + if (!lphEnum) + ret = WN_BAD_POINTER; + else if (!providerTable || providerTable->numProviders == 0) + ret = WN_NO_NETWORK; + else + { + if (lpNet) + { + LPNETRESOURCEW lpNetWide = NULL; + BYTE buf[1024]; + DWORD size = sizeof(buf), count = 1; + BOOL allocated = FALSE; + + ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size); + if (ret == WN_MORE_DATA) + { + lpNetWide = (LPNETRESOURCEW)HeapAlloc(GetProcessHeap(), 0, + size); + if (lpNetWide) + { + ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide, + &size); + allocated = TRUE; + } + else + ret = WN_OUT_OF_MEMORY; + } + else if (ret == WN_SUCCESS) + lpNetWide = (LPNETRESOURCEW)buf; + if (ret == WN_SUCCESS) + ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide, + lphEnum); + if (allocated && lpNetWide) + HeapFree(GetProcessHeap(), 0, lpNetWide); + } + else + ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum); + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /********************************************************************* * WNetOpenEnumW [MPR.@] + * + * Network enumeration has way too many parameters, so I'm not positive I got + * them right. What I've got so far: + * + * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed, + * all the network providers should be enumerated. + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and + * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's + * lpProvider is set, all the network providers should be enumerated. + * (This means the enumeration is a list of network providers, not that the + * enumeration is passed on to the providers.) + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the + * resource matches the "Entire Network" resource (no remote name, no + * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET + * enumeration is done on every network provider. + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and + * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through + * only to the given network provider. + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and + * no lpProvider is set, enumeration will be tried on every network provider, + * in the order in which they're loaded. + * + * - The LPNETRESOURCE should be disregarded for scopes besides + * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not + * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL. + * + * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net + * resource in the enumerated list, as well as any machines in your + * workgroup. The machines in your workgroup come from doing a + * RESOURCE_CONTEXT enumeration of every Network Provider. */ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNet, LPHANDLE lphEnum ) { - FIXME( "(%08lX, %08lX, %08lX, %p, %p): stub\n", + DWORD ret; + + TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n", dwScope, dwType, dwUsage, lpNet, lphEnum ); - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + if (!lphEnum) + ret = WN_BAD_POINTER; + else if (!providerTable || providerTable->numProviders == 0) + ret = WN_NO_NETWORK; + else + { + switch (dwScope) + { + case RESOURCE_GLOBALNET: + if (lpNet) + { + if (lpNet->lpProvider) + { + DWORD index = _findProviderIndexW(lpNet->lpProvider); + + if (index != BAD_PROVIDER_INDEX) + { + if (providerTable->table[index].openEnum && + providerTable->table[index].dwEnumScopes & dwScope) + { + HANDLE handle; + + ret = providerTable->table[index].openEnum( + dwScope, dwType, dwUsage, lpNet, &handle); + if (ret == WN_SUCCESS) + { + *lphEnum = + (HANDLE)_createProviderEnumerator( + dwScope, dwType, dwUsage, index, handle); + ret = *lphEnum ? WN_SUCCESS : + WN_OUT_OF_MEMORY; + } + } + else + ret = WN_NOT_SUPPORTED; + } + else + ret = WN_BAD_PROVIDER; + } + else if (lpNet->lpRemoteName) + { + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, + dwType, dwUsage, lpNet); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + else + { + if (lpNet->lpComment && !strcmpW(lpNet->lpComment, + providerTable->entireNetwork)) + { + /* comment matches the "Entire Network", enumerate + * global scope of every provider + */ + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, + dwType, dwUsage, lpNet); + } + else + { + /* this is the same as not having passed lpNet */ + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, + dwType, dwUsage, NULL); + } + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + } + else + { + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType, + dwUsage, lpNet); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + break; + case RESOURCE_CONTEXT: + *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType, + dwUsage); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + break; + case RESOURCE_REMEMBERED: + case RESOURCE_CONNECTED: + *lphEnum = (HANDLE)_createNullEnumerator(); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + break; + default: + WARN("unknown scope 0x%08lx\n", dwScope); + ret = WN_BAD_VALUE; + } + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /********************************************************************* @@ -73,11 +815,364 @@ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage, DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize ) { - FIXME( "(%p, %p, %p, %p): stub\n", - hEnum, lpcCount, lpBuffer, lpBufferSize ); + DWORD ret; + + TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); + + if (!hEnum) + ret = WN_BAD_POINTER; + else if (!lpcCount) + ret = WN_BAD_POINTER; + if (!lpBuffer) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else if (*lpBufferSize < sizeof(NETRESOURCEA)) + { + *lpBufferSize = sizeof(NETRESOURCEA); + ret = WN_MORE_DATA; + } + else + { + DWORD localCount = *lpcCount, localSize = *lpBufferSize; + LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize); - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + if (localBuffer) + { + ret = WNetEnumResourceW(hEnum, &localCount, localBuffer, + &localSize); + if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1)) + { + /* FIXME: this isn't necessarily going to work in the case of + * WN_MORE_DATA, because our enumerator may have moved on to + * the next provider. MSDN states that a large (16KB) buffer + * size is the appropriate usage of this function, so + * hopefully it won't be an issue. + */ + ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer, + &localCount, lpBuffer, lpBufferSize); + *lpcCount = localCount; + } + HeapFree(GetProcessHeap(), 0, localBuffer); + } + else + ret = WN_OUT_OF_MEMORY; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +static DWORD _countProviderBytesW(PWNetProvider provider) +{ + DWORD ret; + + if (provider) + { + ret = sizeof(NETRESOURCEW); + ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR); + } + else + ret = 0; + return ret; +} + +static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (*lpBufferSize < sizeof(NETRESOURCEA)) + return WN_MORE_DATA; + + if (!providerTable || enumerator->providerIndex >= + providerTable->numProviders) + ret = WN_NO_MORE_ENTRIES; + else + { + DWORD bytes = 0, count = 0, countLimit, i; + LPNETRESOURCEW resource; + LPWSTR strNext; + + countLimit = *lpcCount == -1 ? + providerTable->numProviders - enumerator->providerIndex : *lpcCount; + while (count < countLimit && bytes < *lpBufferSize) + { + DWORD bytesNext = _countProviderBytesW( + &providerTable->table[count + enumerator->providerIndex]); + + if (bytes + bytesNext < *lpBufferSize) + { + bytes += bytesNext; + count++; + } + } + strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW)); + for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count; + i++, resource++) + { + resource->dwScope = RESOURCE_GLOBALNET; + resource->dwType = RESOURCETYPE_ANY; + resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK; + resource->dwUsage = RESOURCEUSAGE_CONTAINER | + RESOURCEUSAGE_RESERVED; + resource->lpLocalName = NULL; + resource->lpRemoteName = strNext; + strcpyW(resource->lpRemoteName, + providerTable->table[i + enumerator->providerIndex].name); + strNext += strlenW(resource->lpRemoteName) + 1; + resource->lpComment = NULL; + resource->lpProvider = strNext; + strcpyW(resource->lpProvider, + providerTable->table[i + enumerator->providerIndex].name); + strNext += strlenW(resource->lpProvider) + 1; + } + enumerator->providerIndex += count; + *lpcCount = count; + ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA; + } + TRACE("Returning %ld\n", ret); + return ret; +} + +/* Advances the enumerator (assumed to be a global enumerator) to the next + * provider that supports the enumeration scope passed to WNetOpenEnum. Does + * not open a handle with the next provider. + * If the existing handle is NULL, may leave the enumerator unchanged, since + * the current provider may support the desired scope. + * If the existing handle is not NULL, closes it before moving on. + * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available + * provider, and another error on failure. + */ +static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator) +{ + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!providerTable || enumerator->providerIndex >= + providerTable->numProviders) + return WN_NO_MORE_ENTRIES; + + if (enumerator->providerDone) + { + enumerator->providerDone = FALSE; + if (enumerator->handle) + { + providerTable->table[enumerator->providerIndex].closeEnum( + enumerator->handle); + enumerator->handle = NULL; + enumerator->providerIndex++; + } + for (; enumerator->providerIndex < providerTable->numProviders && + !(enumerator->dwScope & providerTable->table + [enumerator->providerIndex].dwEnumScopes); + enumerator->providerIndex++) + ; + } + return enumerator->providerIndex < providerTable->numProviders ? + WN_SUCCESS : WN_NO_MORE_ENTRIES; +} + +/* "Passes through" call to the next provider that supports the enumeration + * type. + * FIXME: if one call to a provider's enumerator succeeds while there's still + * space in lpBuffer, I don't call to the next provider. The caller may not + * expect that it should call EnumResourceW again with a return value of + * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings + * may have to be moved around a bit, ick. + */ +static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator, + LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (*lpBufferSize < sizeof(NETRESOURCEW)) + return WN_MORE_DATA; + + ret = _globalEnumeratorAdvance(enumerator); + if (ret == WN_SUCCESS) + { + ret = providerTable->table[enumerator->providerIndex]. + openEnum(enumerator->dwScope, enumerator->dwType, + enumerator->dwUsage, enumerator->lpNet, + &enumerator->handle); + if (ret == WN_SUCCESS) + { + ret = providerTable->table[enumerator->providerIndex]. + enumResource(enumerator->handle, lpcCount, lpBuffer, + lpBufferSize); + if (ret != WN_MORE_DATA) + enumerator->providerDone = TRUE; + } + } + TRACE("Returning %ld\n", ret); + return ret; +} + +static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (*lpBufferSize < sizeof(NETRESOURCEW)) + return WN_MORE_DATA; + if (!providerTable) + return WN_NO_NETWORK; + + switch (enumerator->dwScope) + { + case RESOURCE_GLOBALNET: + if (enumerator->lpNet) + ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, + lpBuffer, lpBufferSize); + else + ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + case RESOURCE_CONTEXT: + ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + default: + WARN("unexpected scope 0x%08lx\n", enumerator->dwScope); + ret = WN_NO_MORE_ENTRIES; + } + TRACE("Returning %ld\n", ret); + return ret; +} + +static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER) + return WN_BAD_VALUE; + if (!enumerator->handle) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (!providerTable) + return WN_NO_NETWORK; + if (enumerator->providerIndex >= providerTable->numProviders) + return WN_NO_MORE_ENTRIES; + if (!providerTable->table[enumerator->providerIndex].enumResource) + return WN_BAD_VALUE; + return providerTable->table[enumerator->providerIndex].enumResource( + enumerator->handle, lpcCount, lpBuffer, lpBufferSize); +} + +static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + size_t cchEntireNetworkLen, bytesNeeded; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (!providerTable) + return WN_NO_NETWORK; + + cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1; + bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR); + if (*lpBufferSize < bytesNeeded) + { + *lpBufferSize = bytesNeeded; + ret = WN_MORE_DATA; + } + else + { + LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer; + + lpNet->dwScope = RESOURCE_GLOBALNET; + lpNet->dwType = enumerator->dwType; + lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT; + lpNet->dwUsage = RESOURCEUSAGE_CONTAINER; + lpNet->lpLocalName = NULL; + lpNet->lpRemoteName = NULL; + lpNet->lpProvider = NULL; + /* odd, but correct: put comment at end of buffer, so it won't get + * overwritten by subsequent calls to a provider's enumResource + */ + lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize - + (cchEntireNetworkLen * sizeof(WCHAR))); + strcpyW(lpNet->lpComment, providerTable->entireNetwork); + ret = WN_SUCCESS; + } + if (ret == WN_SUCCESS) + { + DWORD bufferSize = *lpBufferSize - bytesNeeded; + + /* "Entire Network" entry enumerated--morph this into a global + * enumerator. enumerator->lpNet continues to be NULL, since it has + * no meaning when the scope isn't RESOURCE_GLOBALNET. + */ + enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; + ret = _enumerateGlobalW(enumerator, lpcCount, + (LPBYTE)lpBuffer + bytesNeeded, &bufferSize); + if (ret == WN_SUCCESS) + { + /* reflect the fact that we already enumerated "Entire Network" */ + lpcCount++; + *lpBufferSize = bufferSize + bytesNeeded; + } + else + { + /* the provider enumeration failed, but we already succeeded in + * enumerating "Entire Network"--leave type as global to allow a + * retry, but indicate success with a count of one. + */ + ret = WN_SUCCESS; + *lpcCount = 1; + *lpBufferSize = bytesNeeded; + } + } + TRACE("Returning %ld\n", ret); + return ret; } /********************************************************************* @@ -86,11 +1181,53 @@ DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount, DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize ) { - FIXME( "(%p, %p, %p, %p): stub\n", - hEnum, lpcCount, lpBuffer, lpBufferSize ); + DWORD ret; + + TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); + + if (!hEnum) + ret = WN_BAD_POINTER; + else if (!lpcCount) + ret = WN_BAD_POINTER; + else if (!lpBuffer) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else if (*lpBufferSize < sizeof(NETRESOURCEW)) + { + *lpBufferSize = sizeof(NETRESOURCEW); + ret = WN_MORE_DATA; + } + else + { + PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + switch (enumerator->enumType) + { + case WNET_ENUMERATOR_TYPE_NULL: + ret = WN_NO_MORE_ENTRIES; + break; + case WNET_ENUMERATOR_TYPE_GLOBAL: + ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + case WNET_ENUMERATOR_TYPE_PROVIDER: + ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + case WNET_ENUMERATOR_TYPE_CONTEXT: + ret = _enumerateContextW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + default: + WARN("bogus enumerator type!\n"); + ret = WN_NO_NETWORK; + } + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /********************************************************************* @@ -98,10 +1235,45 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, */ DWORD WINAPI WNetCloseEnum( HANDLE hEnum ) { - FIXME( "(%p): stub\n", hEnum ); + DWORD ret; - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + TRACE( "(%p)\n", hEnum ); + + if (hEnum) + { + PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; + + switch (enumerator->enumType) + { + case WNET_ENUMERATOR_TYPE_NULL: + ret = WN_SUCCESS; + break; + case WNET_ENUMERATOR_TYPE_GLOBAL: + if (enumerator->lpNet) + _freeEnumNetResource(enumerator->lpNet); + if (enumerator->handle) + providerTable->table[enumerator->providerIndex]. + closeEnum(enumerator->handle); + ret = WN_SUCCESS; + break; + case WNET_ENUMERATOR_TYPE_PROVIDER: + if (enumerator->handle) + providerTable->table[enumerator->providerIndex]. + closeEnum(enumerator->handle); + ret = WN_SUCCESS; + break; + default: + WARN("bogus enumerator type!\n"); + ret = WN_BAD_HANDLE; + } + HeapFree(GetProcessHeap(), 0, hEnum); + } + else + ret = WN_BAD_HANDLE; + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /********************************************************************* @@ -349,64 +1521,155 @@ DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice ) * - WN_MORE_DATA buffer isn't big enough * - WN_SUCCESS success (net path in buffer) * + * FIXME: need to test return values under different errors */ DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName, LPSTR lpRemoteName, LPDWORD lpBufferSize ) { - char label[40]; - - TRACE( "local %s\n", lpLocalName ); - if (lpLocalName[1] == ':') + DWORD ret; + + if (!lpLocalName) + ret = WN_BAD_POINTER; + else if (!lpRemoteName) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else { - switch(GetDriveTypeA(lpLocalName)) + int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0); + + if (len) { - case DRIVE_REMOTE: - if (!GetVolumeInformationA( lpLocalName, label, sizeof(label), - NULL, NULL, NULL, NULL, 0 )) label[0] = 0; - if (strlen(label) + 1 > *lpBufferSize) + PWSTR wideLocalName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, len); + + if (wideLocalName) { - *lpBufferSize = strlen(label) + 1; - return WN_MORE_DATA; + WCHAR wideRemoteStatic[MAX_PATH]; + DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR); + + /* try once without memory allocation */ + ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic, + &wideRemoteSize); + if (ret == WN_SUCCESS) + { + int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, + -1, NULL, 0, NULL, NULL); + + if (len <= *lpBufferSize) + { + WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1, + lpRemoteName, *lpBufferSize, NULL, NULL); + ret = WN_SUCCESS; + } + else + { + *lpBufferSize = len; + ret = WN_MORE_DATA; + } + } + else if (ret == WN_MORE_DATA) + { + PWSTR wideRemote = (PWSTR)HeapAlloc(GetProcessHeap(), 0, + wideRemoteSize * sizeof(WCHAR)); + + if (wideRemote) + { + ret = WNetGetConnectionW(wideLocalName, wideRemote, + &wideRemoteSize); + if (ret == WN_SUCCESS) + { + if (len <= *lpBufferSize) + { + WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, + -1, lpRemoteName, *lpBufferSize, NULL, NULL); + ret = WN_SUCCESS; + } + else + { + *lpBufferSize = len; + ret = WN_MORE_DATA; + } + } + HeapFree(GetProcessHeap(), 0, wideRemote); + } + else + ret = WN_OUT_OF_MEMORY; + } + HeapFree(GetProcessHeap(), 0, wideLocalName); } - strcpy( lpRemoteName, label ); - *lpBufferSize = strlen(lpRemoteName) + 1; - return WN_SUCCESS; - case DRIVE_REMOVABLE: - case DRIVE_FIXED: - case DRIVE_CDROM: - TRACE("file is local\n"); - return WN_NOT_CONNECTED; - default: - return WN_BAD_LOCALNAME; + else + ret = WN_OUT_OF_MEMORY; } + else + ret = WN_BAD_LOCALNAME; } - return WN_BAD_LOCALNAME; + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /************************************************************************** * WNetGetConnectionW [MPR.@] + * + * FIXME: need to test return values under different errors */ DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpBufferSize ) { - CHAR buf[200]; - DWORD ret, x = sizeof(buf); - INT len = WideCharToMultiByte( CP_ACP, 0, lpLocalName, -1, NULL, 0, NULL, NULL ); - LPSTR lnA = HeapAlloc( GetProcessHeap(), 0, len ); - - WideCharToMultiByte( CP_ACP, 0, lpLocalName, -1, lnA, len, NULL, NULL ); - ret = WNetGetConnectionA( lnA, buf, &x ); - HeapFree( GetProcessHeap(), 0, lnA ); - if (ret == WN_SUCCESS) + DWORD ret; + + TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName, + lpBufferSize); + + if (!lpLocalName) + ret = WN_BAD_POINTER; + else if (!lpRemoteName) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else if (!lpLocalName[0]) + ret = WN_BAD_LOCALNAME; + else { - x = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 ); - if (x > *lpBufferSize) + WCHAR label[40]; + + if (lpLocalName[1] == ':') { - *lpBufferSize = x; - return WN_MORE_DATA; + switch(GetDriveTypeW(lpLocalName)) + { + case DRIVE_REMOTE: + if (!GetVolumeInformationW( lpLocalName, label, sizeof(label), + NULL, NULL, NULL, NULL, 0 )) + label[0] = 0; + if (strlenW(label) + 1 > *lpBufferSize) + { + *lpBufferSize = strlenW(label) + 1; + ret = WN_MORE_DATA; + } + else + { + strcpyW( lpRemoteName, label ); + *lpBufferSize = strlenW(lpRemoteName) + 1; + ret = WN_SUCCESS; + } + break; + case DRIVE_REMOVABLE: + case DRIVE_FIXED: + case DRIVE_CDROM: + TRACE("file is local\n"); + ret = WN_NOT_CONNECTED; + break; + default: + ret = WN_BAD_LOCALNAME; + } } - *lpBufferSize = MultiByteToWideChar( CP_ACP, 0, buf, -1, lpRemoteName, *lpBufferSize ); + else + ret = WN_BAD_LOCALNAME; } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); return ret; } @@ -479,14 +1742,13 @@ DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize ) /***************************************************************** * WNetGetUserW [MPR.@] + * + * FIXME: we should not return ourselves, but the owner of the drive lpName */ DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize ) { - FIXME( "(%s, %p, %p): mostly stub\n", - debugstr_w(lpName), lpUserID, lpBufferSize ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS; + return GetLastError(); } /********************************************************************* @@ -497,7 +1759,7 @@ DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType ) FIXME( "(%p, %08lX): stub\n", hwnd, dwType ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -508,7 +1770,7 @@ DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct ) FIXME( "(%p): stub\n", lpConnDlgStruct ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -519,7 +1781,7 @@ DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct ) FIXME( "(%p): stub\n", lpConnDlgStruct ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -530,7 +1792,7 @@ DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType ) FIXME( "(%p, %08lX): stub\n", hwnd, dwType ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -541,7 +1803,7 @@ DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct ) FIXME( "(%p): stub\n", lpConnDlgStruct ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -552,7 +1814,7 @@ DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct ) FIXME( "(%p): stub\n", lpConnDlgStruct ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -566,7 +1828,7 @@ DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError, lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -580,7 +1842,7 @@ DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError, lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + return WN_NO_NETWORK; } /********************************************************************* @@ -589,10 +1851,39 @@ DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError, DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider, LPNETINFOSTRUCT lpNetInfoStruct ) { - FIXME( "(%s, %p): stub\n", debugstr_a(lpProvider), lpNetInfoStruct ); + DWORD ret; - SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct ); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else + { + int len; + + len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0); + if (len) + { + LPWSTR wideProvider = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, + len * sizeof(WCHAR)); + + if (wideProvider) + { + MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider, + len); + ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct); + HeapFree(GetProcessHeap(), 0, wideProvider); + } + else + ret = WN_OUT_OF_MEMORY; + } + else + ret = GetLastError(); + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /********************************************************************* @@ -601,10 +1892,46 @@ DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider, DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider, LPNETINFOSTRUCT lpNetInfoStruct ) { - FIXME( "(%s, %p): stub\n", debugstr_w(lpProvider), lpNetInfoStruct ); + DWORD ret; - SetLastError(WN_NO_NETWORK); - return ERROR_NO_NETWORK; + TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct ); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else if (!lpNetInfoStruct) + ret = WN_BAD_POINTER; + else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT)) + ret = WN_BAD_VALUE; + else + { + if (providerTable && providerTable->numProviders) + { + DWORD providerIndex = _findProviderIndexW(lpProvider); + + if (providerIndex != BAD_PROVIDER_INDEX) + { + lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT); + lpNetInfoStruct->dwProviderVersion = + providerTable->table[providerIndex].dwSpecVersion; + lpNetInfoStruct->dwStatus = NO_ERROR; + lpNetInfoStruct->dwCharacteristics = 0; + lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL; + lpNetInfoStruct->wNetType = + HIWORD(providerTable->table[providerIndex].dwNetType); + lpNetInfoStruct->dwPrinters = -1; + lpNetInfoStruct->dwDrives = -1; + ret = WN_SUCCESS; + } + else + ret = WN_BAD_PROVIDER; + } + else + ret = WN_NO_NETWORK; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /***************************************************************** @@ -613,10 +1940,53 @@ DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider, DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType, LPSTR lpProvider, LPDWORD lpBufferSize ) { - FIXME( "(%ld, %p, %p): stub\n", dwNetType, lpProvider, lpBufferSize ); + DWORD ret; - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider), + lpBufferSize); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else + { + if (providerTable) + { + DWORD i; + + ret = WN_NO_NETWORK; + for (i = 0; i < providerTable->numProviders && + HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); + i++) + ; + if (i < providerTable->numProviders) + { + DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0, + providerTable->table[i].name, -1, NULL, 0, NULL, NULL); + + if (*lpBufferSize < sizeNeeded) + { + *lpBufferSize = sizeNeeded; + ret = WN_MORE_DATA; + } + else + { + WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name, + -1, lpProvider, *lpBufferSize, NULL, NULL); + ret = WN_SUCCESS; + /* FIXME: is *lpBufferSize set to the number of characters + * copied? */ + } + } + } + else + ret = WN_NO_NETWORK; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } /***************************************************************** @@ -625,8 +1995,49 @@ DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType, DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType, LPWSTR lpProvider, LPDWORD lpBufferSize ) { - FIXME( "(%ld, %p, %p): stub\n", dwNetType, lpProvider, lpBufferSize ); + DWORD ret; - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; + TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider), + lpBufferSize); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else + { + if (providerTable) + { + DWORD i; + + ret = WN_NO_NETWORK; + for (i = 0; i < providerTable->numProviders && + HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); + i++) + ; + if (i < providerTable->numProviders) + { + DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1; + + if (*lpBufferSize < sizeNeeded) + { + *lpBufferSize = sizeNeeded; + ret = WN_MORE_DATA; + } + else + { + strcpyW(lpProvider, providerTable->table[i].name); + ret = WN_SUCCESS; + /* FIXME: is *lpBufferSize set to the number of characters + * copied? */ + } + } + } + else + ret = WN_NO_NETWORK; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; } diff --git a/dlls/mpr/wnetpriv.h b/dlls/mpr/wnetpriv.h new file mode 100644 index 0000000000000000000000000000000000000000..7a275de1445f9192b038761a9498d3c68e028ed7 --- /dev/null +++ b/dlls/mpr/wnetpriv.h @@ -0,0 +1,27 @@ +/* + * WNet private definitions + * + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WNET_PRIV_H__ +#define __WNET_PRIV_H__ + +void wnetInit(HINSTANCE hInstDll); +void wnetFree(void); + +#endif /* ndef __WNET_PRIV_H__ */ diff --git a/include/Makefile.in b/include/Makefile.in index 8a28f1e567f97ab988e11d279b214890431f3d9c..5b02e6914412b0822a052de1b2212e7cd2a56fe0 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -136,6 +136,7 @@ WINDOWS_INCLUDES = \ mswsock.h \ nb30.h \ netspi.h \ + npapi.h \ nspapi.h \ ntddcdrm.h \ ntddscsi.h \ diff --git a/include/npapi.h b/include/npapi.h new file mode 100644 index 0000000000000000000000000000000000000000..d0cdcc0b810db712b2eead671a32b217b8194b77 --- /dev/null +++ b/include/npapi.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_NPAPI_H__ +#define __WINE_NPAPI_H__ + +/* capabilities */ +#define WNNC_SPEC_VERSION 0x00000001 +#define WNNC_SPEC_VERSION51 0x00050001 +#define WNNC_NET_TYPE 0x00000002 +#define WNNC_NET_NONE 0x00000000 + +#define WNNC_DRIVER_VERSION 0x00000003 + +#define WNNC_USER 0x00000004 +#define WNNC_USR_GETUSER 0x00000001 + +#define WNNC_CONNECTION 0x00000006 +#define WNNC_CON_ADDCONNECTION 0x00000001 +#define WNNC_CON_CANCELCONNECTION 0x00000002 +#define WNNC_CON_GETCONNECTIONS 0x00000004 +#define WNNC_CON_ADDCONNECTION3 0x00000008 + +#define WNNC_DIALOG 0x00000008 +#define WNNC_DLG_DEVICEMODE 0x00000001 +#define WNNC_DLG_PROPERTYDIALOG 0x00000020 +#define WNNC_DLG_SEARCHDIALOG 0x00000040 +#define WNNC_DLG_FORMATNETWORKNAME 0x00000080 + +#define WNNC_ADMIN 0x00000009 +#define WNNC_ADM_GETDIRECTORYTYPE 0x00000001 +#define WNNC_ADM_DIRECTORYNOTIFY 0x00000002 + +#define WNNC_ENUMERATION 0x0000000b +#define WNNC_ENUM_GLOBAL 0x00000001 +#define WNNC_ENUM_LOCAL 0x00000002 + +#define WNNC_START 0x0000000c +#define WNNC_WAIT_FOR_START 0x00000001 + +typedef DWORD APIENTRY (*PF_NPGetCaps)(DWORD ndex); + +/* get user */ +typedef DWORD APIENTRY (*PF_NPGetUser)(LPWSTR lpName, LPWSTR lpUserName, + LPDWORD lpnBufferLen); + +/* enumeration-related */ +typedef DWORD APIENTRY (*PF_NPOpenEnum)(DWORD dwScope, DWORD dwType, DWORD dwUsage, + LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum); +typedef DWORD APIENTRY (*PF_NPEnumResource)(HANDLE hEnum, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize); +typedef DWORD APIENTRY (*PF_NPCloseEnum)(HANDLE hEnum); + +/* connection-related */ +typedef DWORD APIENTRY (*PF_NPAddConnection)(LPNETRESOURCEW lpNetResource, + LPWSTR lpPassword, LPWSTR lpUserName); +typedef DWORD APIENTRY (*PF_NPAddConnection3)(HWND hwndOwner, + LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, + DWORD dwFlags); +typedef DWORD APIENTRY (*PF_NPCancelConnection)(LPWSTR lpName, BOOL fForce); +typedef DWORD APIENTRY (*PF_NPGetConnection)(LPWSTR lpLocalName, + LPWSTR lpRemoteName, LPDWORD lpnBufferLen); + +/* network name manipulation */ +typedef DWORD APIENTRY (*PF_NPGetUniversalName)(LPWSTR lpLocalPath, + DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpnBufferSize); +typedef DWORD APIENTRY (*PF_NPFormatNetworkName)(LPWSTR lpRemoteName, + LPWSTR lpFormattedName, LPDWORD lpnLength, DWORD dwFlags, + DWORD dwAveCharPerLine); + +/* dialogs */ +typedef DWORD APIENTRY (*PF_NPDeviceMode)(HWND hParent); + +/* search dialog */ +#define WNSRCH_REFRESH_FIRST_LEVEL 0x00000001 + +typedef DWORD APIENTRY (*PF_NPSearchDialog)(HWND hwndParent, + LPNETRESOURCEW lpNetResource, LPVOID lpBuffer, DWORD cbBuffer, + LPDWORD lpnFlags); + +/* property dialog */ + +#define WNTYPE_DRIVE 1 +#define WNTYPE_FILE 2 +#define WNTYPE_PRINTER 3 +#define WNTYPE_COMM 4 + +#define WNPS_FILE 0 +#define WNPS_DIR 1 +#define WNPS_MULT 2 + +typedef DWORD APIENTRY (*PF_NPGetPropertyText)(DWORD iButton, DWORD nPropSel, + LPWSTR lpName, LPWSTR lpButtonName, DWORD nButtonNameLen, DWORD nType); + +typedef DWORD APIENTRY (*PF_NPPropertyDialog)(HWND hwndParent, DWORD iButtonDlg, + DWORD nPropSel, LPWSTR lpFileName, DWORD nType); + +/* admin */ +#define WNDT_NORMAL 0 +#define WNDT_NETWORK 1 + +#define WNDN_MKDIR 1 +#define WNDN_RMDIR 2 +#define WNDN_MVDIR 3 + +typedef DWORD APIENTRY (*PF_NPGetDirectoryType)(LPWSTR lpName, LPINT lpType, + BOOL bFlushCache); +typedef DWORD APIENTRY (*PF_NPDirectoryNotify)(HWND hwnd, LPWSTR lpDir, + DWORD dwOper); + +/* permission editor dialogs */ +#define WNPERMC_PERM 0x00000001 +#define WNPERMC_AUDIT 0x00000002 +#define WNPERMC_OWNER 0x00000004 + +typedef DWORD APIENTRY (*PF_NPFMXGetPermCaps)(LPWSTR lpDriveName); + +#define WNPERM_DLG_PERM 0 +#define WNPERM_DLG_AUDIT 1 +#define WNPERM_DLG_OWNER 2 + +typedef DWORD APIENTRY (*PF_NPFMXEditPerm)(LPWSTR lpDriveName, HWND hwndFMX, + DWORD nDialogType); + +typedef DWORD APIENTRY (*PF_NPFMXGetPermHelp)(LPWSTR lpDriveName, + DWORD nDialogType, BOOL fDirectory, LPVOID lpFileNameBuffer, + LPDWORD lpBufferSize, LPDWORD lpnHelpContext); + +VOID WINAPI WNetSetLastErrorA(DWORD err, LPSTR lpError, LPSTR lpProviders); +VOID WINAPI WNetSetLastErrorW(DWORD err, LPWSTR lpError, LPWSTR lpProviders); +#define WNetSetLastError WINELIB_NAME_AW(WNetSetLastError) + +/* provider classes */ +#define WN_NETWORK_CLASS 0x00000001 +#define WN_CREDENTIAL_CLASS 0x00000002 +#define WN_PRIMARY_AUTHENT_CLASS 0x00000004 +#define WN_SERVICE_CLASS 0x00000008 + +#define WN_VALID_LOGON_ACCOUNT 0x00000001 +#define WN_NT_PASSWORD_CHANGED 0x00000002 + +/* notifications */ +typedef DWORD APIENTRY (*PF_NPLogonNotify)(PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, LPVOID StationHandle, LPWSTR *lpLogonScript); +typedef DWORD APIENTRY (*PF_NPPasswordChangeNotify)(LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, + DWORD dwChangeInfo); + +#define NOTIFY_PRE 0x00000001 +#define NOTIFY_POST 0x00000002 + +typedef struct _NOTIFYINFO +{ + DWORD dwNotifyStatus; + DWORD dwOperationStatus; + LPVOID lpContext; +} NOTIFYINFO, *LPNOTIFYINFO; + +/* FIXME: NetResource is declared as a NETRESOURCE in psdk, not a NETRESOURCEW, + * but how can the type change in a service provider? Defaulting to wide-char + * for consistency with the rest of the api. + */ +typedef struct _NOTIFYADD +{ + HWND hwndOwner; + NETRESOURCEW NetResource; + DWORD dwAddFlags; +} NOTIFYADD, *LPNOTIFYADD; + +/* FIXME: lpName and lpProvider are declared as LPTSTRs in psdk, but again + * for consistency with rest of api defaulting to LPWSTRs. + */ +typedef struct _NOTIFYCANCEL +{ + LPWSTR lpName; + LPWSTR lpProvider; + DWORD dwFlags; + BOOL fForce; +} NOTIFYCANCEL, *LPNOTIFYCANCEL; + +typedef DWORD APIENTRY (*PF_AddConnectNotify)(LPNOTIFYINFO lpNotifyInfo, + LPNOTIFYADD lpAddInfo); +typedef DWORD APIENTRY (*PF_CancelConnectNotify)(LPNOTIFYINFO lpNotifyInfo, + LPNOTIFYADD lpAddInfo); + +#endif /* ndef __WINE_NPAPI_H__ */