Implement ldap_count_values*, ldap_get_values*,  ldap_msgfree and
ldap_value_free_len.

diff --git a/dlls/wldap32/Makefile.in b/dlls/wldap32/Makefile.in
index 77d0c8d..d52725f 100644
--- a/dlls/wldap32/Makefile.in
+++ b/dlls/wldap32/Makefile.in
@@ -23,7 +23,8 @@
 	modrdn.c \
 	option.c \
 	rename.c \
-	search.c
+	search.c \
+	value.c
 
 RC_SRCS = wldap32.rc
 
diff --git a/dlls/wldap32/misc.c b/dlls/wldap32/misc.c
index 50ee54d..3837fe0 100644
--- a/dlls/wldap32/misc.c
+++ b/dlls/wldap32/misc.c
@@ -109,6 +109,18 @@
     strfreeW( block );
 }
 
+ULONG WLDAP32_ldap_msgfree( WLDAP32_LDAPMessage *res )
+{
+    ULONG ret = LDAP_SUCCESS;
+#ifdef HAVE_LDAP
+
+    TRACE( "(%p)\n", res );
+    ldap_msgfree( res );
+
+#endif
+    return ret;
+}
+
 ULONG WLDAP32_ldap_result( WLDAP32_LDAP *ld, ULONG msgid, ULONG all,
     struct l_timeval *timeout, WLDAP32_LDAPMessage **res )
 {
@@ -124,22 +136,6 @@
     return ret;
 }
 
-ULONG ldap_value_freeA( PCHAR *vals )
-{
-    TRACE( "(%p)\n", vals );
-
-    strarrayfreeA( vals );
-    return LDAP_SUCCESS;
-}
-
-ULONG ldap_value_freeW( PWCHAR *vals )
-{
-    TRACE( "(%p)\n", vals );
-
-    strarrayfreeW( vals );
-    return LDAP_SUCCESS;
-}
-
 int LdapUnicodeToUTF8( LPCWSTR src, int srclen, LPSTR dst, int dstlen )
 {
     return WideCharToMultiByte( CP_UTF8, 0, src, srclen, dst, dstlen, NULL, NULL );
diff --git a/dlls/wldap32/value.c b/dlls/wldap32/value.c
new file mode 100644
index 0000000..0159bc3
--- /dev/null
+++ b/dlls/wldap32/value.c
@@ -0,0 +1,213 @@
+/*
+ * WLDAP32 - LDAP support for Wine
+ *
+ * Copyright 2005 Hans Leidekker
+ *
+ * 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 "config.h"
+
+#include "wine/port.h"
+#include "wine/debug.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#else
+#define LDAP_SUCCESS        0x00
+#define LDAP_NOT_SUPPORTED  0x5c
+#endif
+
+#include "winldap_private.h"
+#include "wldap32.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wldap32);
+
+ULONG WLDAP32_ldap_count_values_len( struct WLDAP32_berval **vals )
+{
+    ULONG ret = LDAP_NOT_SUPPORTED;
+#ifdef HAVE_LDAP
+
+    TRACE( "(%p)\n", vals );
+    ret = ldap_count_values_len( (struct berval **)vals );
+
+#endif
+    return ret;
+}
+
+ULONG ldap_count_valuesA( PCHAR *vals )
+{
+    ULONG ret = LDAP_NOT_SUPPORTED;
+#ifdef HAVE_LDAP
+    WCHAR **valsW = NULL;
+
+    TRACE( "(%p)\n", vals );
+
+    if (vals) {
+        valsW = strarrayAtoW( vals );
+        if (!valsW) return WLDAP32_LDAP_NO_MEMORY;
+    }
+
+    ret = ldap_count_valuesW( valsW );
+    strarrayfreeW( valsW );
+
+#endif
+    return ret;
+}
+
+ULONG ldap_count_valuesW( PWCHAR *vals )
+{
+    ULONG ret = LDAP_NOT_SUPPORTED;
+#ifdef HAVE_LDAP
+    char **valsU = NULL;
+
+    TRACE( "(%p)\n", vals );
+
+    if (vals) {
+        valsU = strarrayWtoU( vals );
+        if (!valsU) return WLDAP32_LDAP_NO_MEMORY;
+    }
+
+    ret = ldap_count_values( valsU );
+    strarrayfreeU( valsU );
+
+#endif
+    return ret;
+}
+
+PCHAR *ldap_get_valuesA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry, PCHAR attr )
+{
+    PCHAR *ret = NULL;
+#ifdef HAVE_LDAP
+    WCHAR *attrW = NULL, **retW;
+
+    TRACE( "(%p, %p, %s)\n", ld, entry, debugstr_a(attr) );
+
+    if (!ld || !entry || !attr) return NULL;
+
+    attrW = strAtoW( attr );
+    if (!attrW) return NULL;
+
+    retW = ldap_get_valuesW( ld, entry, attrW );
+
+    ret = strarrayWtoA( retW );
+    ldap_value_freeW( retW );
+    strfreeW( attrW );
+
+#endif
+    return ret;
+}
+
+PWCHAR *ldap_get_valuesW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *entry, PWCHAR attr )
+{
+    PWCHAR *ret = NULL;
+#ifdef HAVE_LDAP
+    char *attrU = NULL, **retU;
+
+    TRACE( "(%p, %p, %s)\n", ld, entry, debugstr_w(attr) );
+
+    if (!ld || !entry || !attr) return NULL;
+
+    attrU = strWtoU( attr );
+    if (!attrU) return NULL;
+
+    retU = ldap_get_values( ld, entry, attrU );
+
+    ret = strarrayUtoW( retU );
+    ldap_value_free( retU );
+    strfreeU( attrU );
+
+#endif
+    return ret;
+}
+
+struct WLDAP32_berval **ldap_get_values_lenA( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *message,
+    PCHAR attr )
+{
+#ifdef HAVE_LDAP
+    WCHAR *attrW = NULL;
+    struct WLDAP32_berval **ret;
+
+    TRACE( "(%p, %p, %s)\n", ld, message, debugstr_a(attr) );
+
+    if (!ld || !message || !attr) return NULL;
+
+    attrW = strAtoW( attr );
+    if (!attrW) return NULL;
+
+    ret = ldap_get_values_lenW( ld, message, attrW );
+
+    strfreeW( attrW );
+    return ret;
+
+#endif
+    return NULL;
+}
+
+struct WLDAP32_berval **ldap_get_values_lenW( WLDAP32_LDAP *ld, WLDAP32_LDAPMessage *message,
+    PWCHAR attr )
+{
+#ifdef HAVE_LDAP
+    char *attrU = NULL;
+    struct berval **ret;
+
+    TRACE( "(%p, %p, %s)\n", ld, message, debugstr_w(attr) );
+
+    if (!ld || !message || !attr) return NULL;
+
+    attrU = strWtoU( attr );
+    if (!attrU) return NULL;
+
+    ret = ldap_get_values_len( ld, message, attrU );
+
+    strfreeU( attrU );
+    return (struct WLDAP32_berval **)ret;
+
+#endif
+    return NULL;
+}
+
+ULONG WLDAP32_ldap_value_free_len( struct WLDAP32_berval **vals )
+{
+#ifdef HAVE_LDAP
+
+    TRACE( "(%p)\n", vals );
+    ldap_value_free_len( (struct berval **)vals );
+
+#endif
+    return LDAP_SUCCESS;
+}
+
+ULONG ldap_value_freeA( PCHAR *vals )
+{
+    TRACE( "(%p)\n", vals );
+
+    strarrayfreeA( vals );
+    return LDAP_SUCCESS;
+}
+
+ULONG ldap_value_freeW( PWCHAR *vals )
+{
+    TRACE( "(%p)\n", vals );
+
+    strarrayfreeW( vals );
+    return LDAP_SUCCESS;
+}
diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h
index 1c4c04b..95507c1 100644
--- a/dlls/wldap32/winldap_private.h
+++ b/dlls/wldap32/winldap_private.h
@@ -261,6 +261,9 @@
 ULONG ldap_compare_sW(WLDAP32_LDAP*,PWCHAR,PWCHAR,PWCHAR);
 ULONG ldap_connect(WLDAP32_LDAP*,LDAP_TIMEVAL*);
 WLDAP32_LDAP *ldap_conn_from_msg(WLDAP32_LDAP*,WLDAP32_LDAPMessage*);
+ULONG ldap_count_valuesA(PCHAR*);
+ULONG ldap_count_valuesW(PWCHAR*);
+ULONG WLDAP32_ldap_count_values_len(PBERVAL*);
 ULONG ldap_deleteA(WLDAP32_LDAP*,PCHAR);
 ULONG ldap_deleteW(WLDAP32_LDAP*,PWCHAR);
 ULONG ldap_delete_extA(WLDAP32_LDAP*,PCHAR,PLDAPControlA*,PLDAPControlA*,ULONG*);
@@ -285,6 +288,10 @@
 PWCHAR ldap_get_dnW(WLDAP32_LDAP*,WLDAP32_LDAPMessage*);
 ULONG ldap_get_optionA(WLDAP32_LDAP*,int,void*);
 ULONG ldap_get_optionW(WLDAP32_LDAP*,int,void*);
+PCHAR *ldap_get_valuesA(WLDAP32_LDAP*,WLDAP32_LDAPMessage*,PCHAR);
+PWCHAR *ldap_get_valuesW(WLDAP32_LDAP*,WLDAP32_LDAPMessage*,PWCHAR);
+PBERVAL *ldap_get_values_lenA(WLDAP32_LDAP*,WLDAP32_LDAPMessage*,PCHAR);
+PBERVAL *ldap_get_values_lenW(WLDAP32_LDAP*,WLDAP32_LDAPMessage*,PWCHAR);
 WLDAP32_LDAP *ldap_initA(const PCHAR,ULONG);
 WLDAP32_LDAP *ldap_initW(const PWCHAR,ULONG);
 void ldap_memfreeA(PCHAR);
@@ -305,6 +312,7 @@
 ULONG ldap_modrdn2_sW(WLDAP32_LDAP*,PWCHAR,PWCHAR,INT);
 ULONG ldap_modrdn_sA(WLDAP32_LDAP*,PCHAR,PCHAR);
 ULONG ldap_modrdn_sW(WLDAP32_LDAP*,PWCHAR,PWCHAR);
+ULONG WLDAP32_ldap_msgfree(WLDAP32_LDAPMessage*);
 WLDAP32_LDAP *ldap_openA(PCHAR,ULONG);
 WLDAP32_LDAP *ldap_openW(PWCHAR,ULONG);
 void WLDAP32_ldap_perror(WLDAP32_LDAP*,const PCHAR);
@@ -348,6 +356,7 @@
 ULONG WLDAP32_ldap_unbind_s(WLDAP32_LDAP*);
 ULONG ldap_value_freeA(PCHAR*);
 ULONG ldap_value_freeW(PWCHAR*);
+ULONG WLDAP32_ldap_value_free_len(struct WLDAP32_berval**);
 
 ULONG LdapGetLastError(void);
 ULONG LdapMapErrorToWin32(ULONG);
diff --git a/dlls/wldap32/wldap32.spec b/dlls/wldap32/wldap32.spec
index 9ed572b..8619958 100644
--- a/dlls/wldap32/wldap32.spec
+++ b/dlls/wldap32/wldap32.spec
@@ -63,10 +63,10 @@
 @ stub ldap_controls_freeW
 @ stub ldap_count_entries
 @ stub ldap_count_references
-@ stub ldap_count_values
-@ stub ldap_count_valuesA
-@ stub ldap_count_valuesW
-@ stub ldap_count_values_len
+@ cdecl ldap_count_values(ptr) ldap_count_valuesA
+@ cdecl ldap_count_valuesA(ptr)
+@ cdecl ldap_count_valuesW(ptr)
+@ cdecl ldap_count_values_len(ptr) WLDAP32_ldap_count_values_len
 @ stub ldap_create_page_control
 @ stub ldap_create_page_controlA
 @ stub ldap_create_page_controlW
@@ -123,12 +123,12 @@
 @ cdecl ldap_get_optionA(ptr long ptr)
 @ cdecl ldap_get_optionW(ptr long ptr)
 @ stub ldap_get_paged_count
-@ stub ldap_get_values
-@ stub ldap_get_valuesA
-@ stub ldap_get_valuesW
-@ stub ldap_get_values_len
-@ stub ldap_get_values_lenA
-@ stub ldap_get_values_lenW
+@ cdecl ldap_get_values(ptr ptr str) ldap_get_valuesA
+@ cdecl ldap_get_valuesA(ptr ptr str)
+@ cdecl ldap_get_valuesW(ptr ptr wstr)
+@ cdecl ldap_get_values_len(ptr ptr str) ldap_get_values_lenA
+@ cdecl ldap_get_values_lenA(ptr ptr str)
+@ cdecl ldap_get_values_lenW(ptr ptr wstr)
 @ cdecl ldap_init(str long) ldap_initA
 @ cdecl ldap_initA(str long)
 @ cdecl ldap_initW(wstr long)
@@ -159,7 +159,7 @@
 @ cdecl ldap_modrdn_s(ptr str ptr) ldap_modrdn_sA
 @ cdecl ldap_modrdn_sA(ptr str ptr)
 @ cdecl ldap_modrdn_sW(ptr wstr ptr)
-@ stub ldap_msgfree
+@ cdecl ldap_msgfree(ptr) WLDAP32_ldap_msgfree
 @ stub ldap_next_attribute
 @ stub ldap_next_attributeA
 @ stub ldap_next_attributeW
@@ -242,4 +242,4 @@
 @ cdecl ldap_value_free(ptr) ldap_value_freeA
 @ cdecl ldap_value_freeA(ptr)
 @ cdecl ldap_value_freeW(ptr)
-@ stub ldap_value_free_len
+@ cdecl ldap_value_free_len(ptr) WLDAP32_ldap_value_free_len