From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/adsldp/adsldp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/adsldp/adsldp.c b/dlls/adsldp/adsldp.c index dd459f3aa18..4b3be58a4d2 100644 --- a/dlls/adsldp/adsldp.c +++ b/dlls/adsldp/adsldp.c @@ -1299,7 +1299,7 @@ static HRESULT WINAPI search_ExecuteSearch(IDirectorySearch *iface, LPWSTR filte { LDAP_namespace *ldap = impl_from_IDirectorySearch(iface); ULONG err, i; - WCHAR **props; + WCHAR **props, *object; LDAPControlW **ctrls = NULL, *ctrls_a[2], tombstone; struct ldap_search_context *ldap_ctx;
@@ -1347,9 +1347,13 @@ static HRESULT WINAPI search_ExecuteSearch(IDirectorySearch *iface, LPWSTR filte ctrls = ctrls_a; }
+ object = ldap->object; + if (object && !wcsicmp(object, L"rootDSE")) + object = NULL; + if (ldap->search.pagesize) { - ldap_ctx->page = ldap_search_init_pageW(ldap->ld, ldap->object, ldap->search.scope, + ldap_ctx->page = ldap_search_init_pageW(ldap->ld, object, ldap->search.scope, filter, props, ldap->search.attribtypes_only, ctrls, NULL, 0, ldap->search.size_limit, NULL); if (ldap_ctx->page) @@ -1359,7 +1363,7 @@ static HRESULT WINAPI search_ExecuteSearch(IDirectorySearch *iface, LPWSTR filte err = LDAP_NO_MEMORY; } else - err = ldap_search_ext_sW(ldap->ld, ldap->object, ldap->search.scope, filter, props, + err = ldap_search_ext_sW(ldap->ld, object, ldap->search.scope, filter, props, ldap->search.attribtypes_only, ctrls, NULL, NULL, ldap->search.size_limit, &ldap_ctx->res); free(props);
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/adsldp/adsldp.c | 261 ++++++++++++++++++++++++++++--------------- 1 file changed, 173 insertions(+), 88 deletions(-)
diff --git a/dlls/adsldp/adsldp.c b/dlls/adsldp/adsldp.c index 4b3be58a4d2..f95886c655e 100644 --- a/dlls/adsldp/adsldp.c +++ b/dlls/adsldp/adsldp.c @@ -373,12 +373,6 @@ static HRESULT ADSystemInfo_create(REFIID riid, void **obj) return hr; }
-struct ldap_attribute -{ - WCHAR *name; - WCHAR **values; -}; - typedef struct { IADs IADs_iface; @@ -391,7 +385,7 @@ typedef struct BSTR object; ULONG port; ULONG attrs_count, attrs_count_allocated; - struct ldap_attribute *attrs; + ADS_SEARCH_COLUMN *attrs; struct attribute_type *at; ULONG at_single_count, at_multiple_count; struct @@ -477,10 +471,7 @@ static void free_attributes(LDAP_namespace *ldap) if (!ldap->attrs) return;
for (i = 0; i < ldap->attrs_count; i++) - { - ldap_memfreeW(ldap->attrs[i].name); - ldap_value_freeW(ldap->attrs[i].values); - } + IDirectorySearch_FreeColumn(&ldap->IDirectorySearch_iface, &ldap->attrs[i]);
free(ldap->attrs); ldap->attrs = NULL; @@ -591,6 +582,133 @@ static HRESULT WINAPI ldapns_SetInfo(IADs *iface) return E_NOTIMPL; }
+static HRESULT adsvalue_to_variant(const ADSVALUE *value, VARIANT *var) +{ + HRESULT hr = S_OK; + void *val; + + switch (value->dwType) + { + default: + FIXME("no special handling for type %d\n", value->dwType); + /* fall through */ + case ADSTYPE_DN_STRING: + case ADSTYPE_CASE_EXACT_STRING: + case ADSTYPE_CASE_IGNORE_STRING: + case ADSTYPE_PRINTABLE_STRING: + val = SysAllocString(value->CaseIgnoreString); + if (!val) return E_OUTOFMEMORY; + + V_VT(var) = VT_BSTR; + V_BSTR(var) = val; + break; + + case ADSTYPE_BOOLEAN: + V_VT(var) = VT_BOOL; + V_BOOL(var) = value->Boolean ? VARIANT_TRUE : VARIANT_FALSE; + break; + + case ADSTYPE_INTEGER: + V_VT(var) = VT_I4; + V_I4(var) = value->Integer; + break; + + case ADSTYPE_LARGE_INTEGER: + V_VT(var) = VT_I8; + V_I8(var) = value->LargeInteger.QuadPart; + break; + + case ADSTYPE_OCTET_STRING: + case ADSTYPE_NT_SECURITY_DESCRIPTOR: + { + SAFEARRAY *sa; + + sa = SafeArrayCreateVector(VT_UI1, 0, value->OctetString.dwLength); + if (!sa) return E_OUTOFMEMORY; + + memcpy(sa->pvData, value->OctetString.lpValue, value->OctetString.dwLength); + V_VT(var) = VT_ARRAY | VT_UI1; + V_ARRAY(var) = sa; + break; + } + + case ADSTYPE_UTC_TIME: + { + double date; + + if (!SystemTimeToVariantTime((SYSTEMTIME *)&value->UTCTime, &date)) + return E_FAIL; + + V_VT(var) = VT_DATE; + V_DATE(var) = date; + break; + } + + case ADSTYPE_DN_WITH_BINARY: + { + SAFEARRAY *sa; + IADsDNWithBinary *dn = NULL; + VARIANT data; + + sa = SafeArrayCreateVector(VT_UI1, 0, value->pDNWithBinary->dwLength); + if (!sa) return E_OUTOFMEMORY; + memcpy(sa->pvData, value->pDNWithBinary->lpBinaryValue, value->pDNWithBinary->dwLength); + + hr = CoCreateInstance(&CLSID_DNWithBinary, 0, CLSCTX_INPROC_SERVER, &IID_IADsDNWithBinary, (void **)&dn); + if (hr != S_OK) goto fail; + + V_VT(&data) = VT_ARRAY | VT_UI1; + V_ARRAY(&data) = sa; + hr = IADsDNWithBinary_put_BinaryValue(dn, data); + if (hr != S_OK) goto fail; + + hr = IADsDNWithBinary_put_DNString(dn, value->pDNWithBinary->pszDNString); + if (hr != S_OK) goto fail; + + V_VT(var) = VT_DISPATCH; + V_DISPATCH(var) = (IDispatch *)dn; + break; +fail: + SafeArrayDestroy(sa); + if (dn) IADsDNWithBinary_Release(dn); + return hr; + + } + } + + TRACE("=> %s\n", wine_dbgstr_variant(var)); + return hr; +} + +static HRESULT adsvalues_to_array(const ADSVALUE *values, LONG count, VARIANT *var) +{ + HRESULT hr; + SAFEARRAY *sa; + VARIANT item; + LONG i; + + sa = SafeArrayCreateVector(VT_VARIANT, 0, count); + if (!sa) return E_OUTOFMEMORY; + + for (i = 0; i < count; i++) + { + hr = adsvalue_to_variant(&values[i], &item); + if (hr != S_OK) goto fail; + + hr = SafeArrayPutElement(sa, &i, &item); + VariantClear(&item); + if (hr != S_OK) goto fail; + } + + V_VT(var) = VT_ARRAY | VT_VARIANT; + V_ARRAY(var) = sa; + return S_OK; + +fail: + SafeArrayDestroy(sa); + return hr; +} + static HRESULT WINAPI ldapns_Get(IADs *iface, BSTR name, VARIANT *prop) { LDAP_namespace *ldap = impl_from_IADs(iface); @@ -609,58 +727,21 @@ static HRESULT WINAPI ldapns_Get(IADs *iface, BSTR name, VARIANT *prop)
for (i = 0; i < ldap->attrs_count; i++) { - if (!wcsicmp(name, ldap->attrs[i].name)) + if (!wcsicmp(name, ldap->attrs[i].pszAttrName)) { - LONG count = ldap_count_valuesW(ldap->attrs[i].values); - if (!count) + if (!ldap->attrs[i].dwNumValues) { V_BSTR(prop) = NULL; V_VT(prop) = VT_BSTR; return S_OK; }
- if (count > 1) - { - SAFEARRAY *sa; - VARIANT item; - LONG idx; - - TRACE("attr %s has %lu values\n", debugstr_w(ldap->attrs[i].name), count); - - sa = SafeArrayCreateVector(VT_VARIANT, 0, count); - if (!sa) return E_OUTOFMEMORY; + TRACE("attr %s has %lu values\n", debugstr_w(ldap->attrs[i].pszAttrName), ldap->attrs[i].dwNumValues);
- for (idx = 0; idx < count; idx++) - { - TRACE("=> %s\n", debugstr_w(ldap->attrs[i].values[idx])); - V_VT(&item) = VT_BSTR; - V_BSTR(&item) = SysAllocString(ldap->attrs[i].values[idx]); - if (!V_BSTR(&item)) - { - hr = E_OUTOFMEMORY; - goto fail; - } - - hr = SafeArrayPutElement(sa, &idx, &item); - SysFreeString(V_BSTR(&item)); - if (hr != S_OK) goto fail; - } - - V_VT(prop) = VT_ARRAY | VT_VARIANT; - V_ARRAY(prop) = sa; - return S_OK; -fail: - SafeArrayDestroy(sa); - return hr; - } + if (ldap->attrs[i].dwNumValues > 1) + return adsvalues_to_array(ldap->attrs[i].pADsValues, ldap->attrs[i].dwNumValues, prop); else - { - TRACE("=> %s\n", debugstr_w(ldap->attrs[i].values[0])); - V_BSTR(prop) = SysAllocString(ldap->attrs[i].values[0]); - if (!V_BSTR(prop)) return E_OUTOFMEMORY; - V_VT(prop) = VT_BSTR; - return S_OK; - } + return adsvalue_to_variant(&ldap->attrs[i].pADsValues[0], prop); } }
@@ -685,9 +766,9 @@ static HRESULT WINAPI ldapns_PutEx(IADs *iface, LONG code, BSTR name, VARIANT pr return E_NOTIMPL; }
-static HRESULT add_attribute(LDAP_namespace *ldap, WCHAR *name, WCHAR **values) +static HRESULT add_attribute(LDAP_namespace *ldap, ADS_SEARCH_COLUMN *attr) { - struct ldap_attribute *new_attrs; + ADS_SEARCH_COLUMN *new_attrs;
if (!ldap->attrs) { @@ -704,8 +785,7 @@ static HRESULT add_attribute(LDAP_namespace *ldap, WCHAR *name, WCHAR **values) ldap->attrs = new_attrs; }
- ldap->attrs[ldap->attrs_count].name = name; - ldap->attrs[ldap->attrs_count].values = values; + ldap->attrs[ldap->attrs_count] = *attr; ldap->attrs_count++;
return S_OK; @@ -717,10 +797,11 @@ static HRESULT WINAPI ldapns_GetInfoEx(IADs *iface, VARIANT prop, LONG reserved) HRESULT hr; SAFEARRAY *sa; VARIANT *item; - WCHAR **props = NULL, *attr, **values; - DWORD i, count, err; - LDAPMessage *res = NULL, *entry; - BerElement *ber; + WCHAR **props = NULL; + DWORD i, count; + ADS_SEARCHPREF_INFO pref[3]; + ADS_SEARCH_HANDLE sh; + ADS_SEARCH_COLUMN col;
TRACE("%p,%s,%ld\n", iface, wine_dbgstr_variant(&prop), reserved);
@@ -757,45 +838,49 @@ static HRESULT WINAPI ldapns_GetInfoEx(IADs *iface, VARIANT prop, LONG reserved) } props[i] = V_BSTR(&item[i]); } - props[sa->rgsabound[0].cElements] = NULL; } + else + count = ~0;
- err = ldap_search_sW(ldap->ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", props, FALSE, &res); - if (err != LDAP_SUCCESS) + pref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; + pref[0].vValue.dwType = ADSTYPE_INTEGER; + pref[0].vValue.Integer = ADS_SCOPE_BASE; + pref[0].dwStatus = 0; + + pref[1].dwSearchPref = ADS_SEARCHPREF_ATTRIBTYPES_ONLY; + pref[1].vValue.dwType = ADSTYPE_BOOLEAN; + pref[1].vValue.Boolean = FALSE; + pref[1].dwStatus = 0; + + pref[2].dwSearchPref = ADS_SEARCHPREF_SIZE_LIMIT; + pref[2].vValue.dwType = ADSTYPE_INTEGER; + pref[2].vValue.Integer = 20; + pref[2].dwStatus = 0; + + IDirectorySearch_SetSearchPreference(&ldap->IDirectorySearch_iface, pref, ARRAY_SIZE(pref)); + + hr = IDirectorySearch_ExecuteSearch(&ldap->IDirectorySearch_iface, (WCHAR *)L"(objectClass=*)", props, count, &sh); + if (hr != S_OK) { - TRACE("ldap_search_sW error %#lx\n", err); - hr = HRESULT_FROM_WIN32(map_ldap_error(err)); + TRACE("ExecuteSearch error %#lx\n", hr); goto exit; }
- entry = ldap_first_entry(ldap->ld, res); - while (entry) + while (IDirectorySearch_GetNextRow(&ldap->IDirectorySearch_iface, sh) != S_ADS_NOMORE_ROWS) { - attr = ldap_first_attributeW(ldap->ld, entry, &ber); - while (attr) + WCHAR *name; + while (IDirectorySearch_GetNextColumnName(&ldap->IDirectorySearch_iface, sh, &name) != S_ADS_NOMORE_COLUMNS) { - TRACE("attr: %s\n", debugstr_w(attr)); + hr = IDirectorySearch_GetColumn(&ldap->IDirectorySearch_iface, sh, name, &col); + if (hr == S_OK) + add_attribute(ldap, &col);
- values = ldap_get_valuesW(ldap->ld, entry, attr); - - hr = add_attribute(ldap, attr, values); - if (hr != S_OK) - { - ldap_value_freeW(values); - ldap_memfreeW(attr); - ber_free(ber, 0); - goto exit; - } - - attr = ldap_next_attributeW(ldap->ld, entry, ber); + FreeADsMem(name); } - - ber_free(ber, 0); - entry = ldap_next_entry(ldap->ld, res); }
+ IDirectorySearch_CloseSearchHandle(&ldap->IDirectorySearch_iface, sh); exit: - if (res) ldap_msgfree(res); free(props); SafeArrayUnaccessData(sa); return hr;
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/adsldp/adsldp.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/dlls/adsldp/adsldp.c b/dlls/adsldp/adsldp.c index f95886c655e..e54ea02ecdf 100644 --- a/dlls/adsldp/adsldp.c +++ b/dlls/adsldp/adsldp.c @@ -756,8 +756,38 @@ static HRESULT WINAPI ldapns_Put(IADs *iface, BSTR name, VARIANT prop)
static HRESULT WINAPI ldapns_GetEx(IADs *iface, BSTR name, VARIANT *prop) { - FIXME("%p,%s,%p: stub\n", iface, debugstr_w(name), prop); - return E_NOTIMPL; + LDAP_namespace *ldap = impl_from_IADs(iface); + HRESULT hr; + ULONG i; + + TRACE("%p,%s,%p\n", iface, debugstr_w(name), prop); + + if (!name || !prop) return E_ADS_BAD_PARAMETER; + + if (!ldap->attrs_count) + { + hr = IADs_GetInfo(iface); + if (hr != S_OK) return hr; + } + + for (i = 0; i < ldap->attrs_count; i++) + { + if (!wcsicmp(name, ldap->attrs[i].pszAttrName)) + { + if (!ldap->attrs[i].dwNumValues) + { + V_BSTR(prop) = NULL; + V_VT(prop) = VT_BSTR; + return S_OK; + } + + TRACE("attr %s has %lu values\n", debugstr_w(ldap->attrs[i].pszAttrName), ldap->attrs[i].dwNumValues); + + return adsvalues_to_array(ldap->attrs[i].pADsValues, ldap->attrs[i].dwNumValues, prop); + } + } + + return E_ADS_PROPERTY_NOT_FOUND; }
static HRESULT WINAPI ldapns_PutEx(IADs *iface, LONG code, BSTR name, VARIANT prop)
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/adsldp/tests/ldap.c | 159 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+)
diff --git a/dlls/adsldp/tests/ldap.c b/dlls/adsldp/tests/ldap.c index 79d5df6b660..af965000e26 100644 --- a/dlls/adsldp/tests/ldap.c +++ b/dlls/adsldp/tests/ldap.c @@ -37,6 +37,9 @@ DEFINE_GUID(CLSID_LDAP,0x228d9a81,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x DEFINE_GUID(CLSID_LDAPNamespace,0x228d9a82,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91); DEFINE_OLEGUID(CLSID_PointerMoniker,0x306,0,0);
+DEFINE_GUID(CLSID_Computers,0x252831aa,0x8876,0xd111,0xad,0xed,0x00,0xc0,0x4f,0xd8,0xd5,0xcd); +DEFINE_GUID(CLSID_Users,0x15cad1a9,0x8876,0xd111,0xad,0xed,0x00,0xc0,0x4f,0xd8,0xd5,0xcd); + static BOOL server_down;
static const struct @@ -595,6 +598,161 @@ static void test_DirectoryObject(void) IDirectoryObject_Release(dirobj); }
+static void test_IADs_GetEx(void) +{ + HRESULT hr; + IADs *ads; + BSTR bstr; + VARIANT var, item, bin; + LONG start, end, idx, found; + WCHAR path[256]; + IADsDNWithBinary *dn; + + hr = ADsGetObject(L"LDAP://rootDSE", &IID_IADs, (void **)&ads); + if (hr != S_OK) + { + skip("Computer is not part of an Active Directory Domain\n"); + return; + } + + VariantInit(&var); + bstr = SysAllocString(L"defaultNamingContext"); + hr = IADs_Get(ads, bstr, &var); + SysFreeString(bstr); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&var) == VT_BSTR, "got %#x\n", V_VT(&var)); + trace("VT_BSTR => %s\n", wine_dbgstr_w(V_BSTR(&var))); + wcscpy(path, L"LDAP://"); + wcscat(path, V_BSTR(&var)); + VariantClear(&var); + + VariantInit(&var); + bstr = SysAllocString(L"defaultNamingContext"); + hr = IADs_GetEx(ads, bstr, &var); + SysFreeString(bstr); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&var) == (VT_ARRAY | VT_VARIANT), "got %#x\n", V_VT(&var)); + hr = SafeArrayGetLBound(V_ARRAY(&var), 1, &start); + ok(hr == S_OK, "got %#lx\n", hr); + hr = SafeArrayGetUBound(V_ARRAY(&var), 1, &end); + ok(hr == S_OK, "got %#lx\n", hr); + VariantInit(&item); + for (idx = start; idx <= end; idx++) + { + hr = SafeArrayGetElement(V_ARRAY(&var), &idx, &item); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&item) == VT_BSTR, "%ld: got %d\n", idx, V_VT(&item)); + trace("%ld: VT_BSTR => %s\n", idx, wine_dbgstr_w(V_BSTR(&item))); + VariantClear(&item); + } + VariantClear(&var); + + VariantInit(&var); + bstr = SysAllocString(L"wellKnownObjects"); + hr = IADs_Get(ads, bstr, &var); + SysFreeString(bstr); + ok(hr == E_ADS_PROPERTY_NOT_FOUND, "got %#lx\n", hr); + + IADs_Release(ads); + + hr = ADsGetObject(path, &IID_IADs, (void **)&ads); + ok(hr == S_OK, "got %#lx\n", hr); + + /* ::Get() */ + VariantInit(&var); + bstr = SysAllocString(L"wellKnownObjects"); + hr = IADs_Get(ads, bstr, &var); + SysFreeString(bstr); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&var) == (VT_ARRAY | VT_VARIANT), "got %#x\n", V_VT(&var)); + hr = SafeArrayGetLBound(V_ARRAY(&var), 1, &start); + ok(hr == S_OK, "got %#lx\n", hr); + ok(start == 0, "got start %ld\n", start); + hr = SafeArrayGetUBound(V_ARRAY(&var), 1, &end); + ok(hr == S_OK, "got %#lx\n", hr); + trace("wellKnownObjects contains %lu elements\n", end - start + 1); + VariantInit(&item); + found = 0; + for (idx = start; idx <= end; idx++) + { + hr = SafeArrayGetElement(V_ARRAY(&var), &idx, &item); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&item) == VT_DISPATCH, "%ld: got %d\n", idx, V_VT(&item)); + hr = IDispatch_QueryInterface(V_DISPATCH(&item), &IID_IADsDNWithBinary, (void **)&dn); + ok(hr == S_OK, "IID_IADsDNWithBinary: got %#lx\n", hr); + + VariantInit(&bin); + hr = IADsDNWithBinary_get_BinaryValue(dn, &bin); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&bin) == (VT_ARRAY | VT_UI1), "%ld: got %d\n", idx, V_VT(&bin)); + ok(V_ARRAY(&bin)->cDims == 1, "%ld: got cDims %u\n", idx, V_ARRAY(&bin)->cDims); + ok(V_ARRAY(&bin)->cbElements == 1, "%ld: got cDims %lu\n", idx, V_ARRAY(&bin)->cbElements); + ok(V_ARRAY(&bin)->rgsabound[0].cElements == sizeof(CLSID), + "%ld: got cElements %lu\n", idx, V_ARRAY(&bin)->rgsabound[0].cElements); + + if(!memcmp(V_ARRAY(&bin)->pvData, &CLSID_Computers, sizeof(CLSID)) || + !memcmp(V_ARRAY(&bin)->pvData, &CLSID_Users, sizeof(CLSID))) + found++; + + hr = IADsDNWithBinary_get_DNString(dn, &bstr); + ok(hr == S_OK, "got %#lx\n", hr); + trace("%ld: DNString => %s\n", idx, wine_dbgstr_w(bstr)); + + IADsDNWithBinary_Release(dn); + VariantClear(&item); + } + VariantClear(&var); + ok(found == 2, "Users or Computers entry not found\n"); + + /* ::GetEx() */ + VariantInit(&var); + bstr = SysAllocString(L"wellKnownObjects"); + hr = IADs_GetEx(ads, bstr, &var); + SysFreeString(bstr); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&var) == (VT_ARRAY | VT_VARIANT), "got %#x\n", V_VT(&var)); + hr = SafeArrayGetLBound(V_ARRAY(&var), 1, &start); + ok(hr == S_OK, "got %#lx\n", hr); + ok(start == 0, "got start %ld\n", start); + hr = SafeArrayGetUBound(V_ARRAY(&var), 1, &end); + ok(hr == S_OK, "got %#lx\n", hr); + VariantInit(&item); + found = 0; + for (idx = start; idx <= end; idx++) + { + hr = SafeArrayGetElement(V_ARRAY(&var), &idx, &item); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&item) == VT_DISPATCH, "%ld: got %d\n", idx, V_VT(&item)); + hr = IDispatch_QueryInterface(V_DISPATCH(&item), &IID_IADsDNWithBinary, (void **)&dn); + ok(hr == S_OK, "IID_IADsDNWithBinary: got %#lx\n", hr); + + VariantInit(&bin); + hr = IADsDNWithBinary_get_BinaryValue(dn, &bin); + ok(hr == S_OK, "got %#lx\n", hr); + ok(V_VT(&bin) == (VT_ARRAY | VT_UI1), "%ld: got %d\n", idx, V_VT(&bin)); + ok(V_ARRAY(&bin)->cDims == 1, "%ld: got cDims %u\n", idx, V_ARRAY(&bin)->cDims); + ok(V_ARRAY(&bin)->cbElements == 1, "%ld: got cDims %lu\n", idx, V_ARRAY(&bin)->cbElements); + ok(V_ARRAY(&bin)->rgsabound[0].cElements == sizeof(CLSID), + "%ld: got cElements %lu\n", idx, V_ARRAY(&bin)->rgsabound[0].cElements); + + if(!memcmp(V_ARRAY(&bin)->pvData, &CLSID_Computers, sizeof(CLSID)) || + !memcmp(V_ARRAY(&bin)->pvData, &CLSID_Users, sizeof(CLSID))) + found++; + + hr = IADsDNWithBinary_get_DNString(dn, &bstr); + ok(hr == S_OK, "got %#lx\n", hr); + trace("%ld: DNString => %s\n", idx, wine_dbgstr_w(bstr)); + + VariantClear(&bin); + IADsDNWithBinary_Release(dn); + VariantClear(&item); + } + VariantClear(&var); + ok(found == 2, "Users or Computers entry not found\n"); + + IADs_Release(ads); +} + START_TEST(ldap) { HRESULT hr; @@ -602,6 +760,7 @@ START_TEST(ldap) hr = CoInitialize(NULL); ok(hr == S_OK, "got %#lx\n", hr);
+ test_IADs_GetEx(); test_LDAP(); test_ParseDisplayName(); test_DirectorySearch();